dvander@61: /* vim: set ts=4 sw=4 tw=99 et: dvander@61: * dvander@61: * Copyright (C) 2012 David Anderson dvander@61: * dvander@61: * This file is part of JITCraft. dvander@61: * dvander@61: * JITCraft is free software: you can redistribute it and/or modify it under dvander@61: * the terms of the GNU General Public License as published by the Free dvander@61: * Software Foundation, either version 3 of the License, or (at your option) dvander@61: * any later version. dvander@61: * dvander@61: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@61: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@61: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@61: * dvander@61: * You should have received a copy of the GNU General Public License along with dvander@61: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@61: */ dvander@61: #include "../include/keima.h" dvander@61: #include "Zone.h" dvander@61: #include "RootScopes.h" dvander@61: #include "CompileContext.h" dvander@61: #include "Parser.h" dvander@61: #include "Scopes.h" dvander@61: #include "SemanticAnalysis.h" dvander@61: #include "BytecodeCompiler.h" dvander@61: #include "Modules.h" dvander@61: #include "GlobalRoots.h" dvander@61: dvander@61: using namespace ke; dvander@61: dvander@61: bool dvander@62: Ke::Keima::Initialize() dvander@61: { dvander@61: SingleThreadedZone = new Zone(); dvander@61: if (!SingleThreadedZone || !SingleThreadedZone->initialize()) dvander@61: return false; dvander@61: return true; dvander@61: } dvander@61: dvander@61: void dvander@62: Ke::Keima::Shutdown() dvander@61: { dvander@61: delete SingleThreadedZone; dvander@61: SingleThreadedZone = NULL; dvander@61: } dvander@61: dvander@60: Ke::HandleScope::HandleScope() dvander@60: : zone_(ke::ZONE()), dvander@60: position_(zone_->rootScopes().position()), dvander@60: prev_(*zone_->rootScopes().scope()) dvander@60: { dvander@60: *zone_->rootScopes().scope() = this; dvander@60: } dvander@60: dvander@61: Ke::HandleScope::~HandleScope() dvander@61: { dvander@61: zone_->rootScopes().unwind(position_); dvander@61: *zone_->rootScopes().scope() = prev_; dvander@61: } dvander@61: dvander@61: ke::Object ** dvander@61: Ke::HandleScope::CreateHandle(ke::Object *obj) dvander@61: { dvander@61: if (!obj) dvander@61: return NULL; dvander@61: dvander@61: return ZONE()->rootScopes().make(obj); dvander@61: } dvander@61: dvander@62: template static inline To * dvander@62: Open(Ke::Handle from) dvander@62: { dvander@62: return *reinterpret_cast(*from); dvander@62: } dvander@62: dvander@64: template static inline To * dvander@64: Open(From *from) dvander@64: { dvander@64: return *reinterpret_cast(from); dvander@64: } dvander@64: dvander@61: template static inline Ke::Local dvander@64: ToLocal(From *from) dvander@61: { dvander@61: return Ke::Local(reinterpret_cast(Ke::HandleScope::CreateHandle(from))); dvander@61: } dvander@61: dvander@61: static ke::Module * dvander@61: CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length) dvander@61: { dvander@61: Parser parser(ZONE(), cc, stream, length); dvander@61: ParseTree *tree = parser.parse(); dvander@61: if (!tree) dvander@61: return NULL; dvander@61: tree->dump(stdout); dvander@61: dvander@61: if (!Scope::Bind(tree)) dvander@61: return NULL; dvander@61: dvander@61: SemanticAnalysis semantics(ZONE(), cc, tree); dvander@61: if (!semantics.analyze()) dvander@61: return NULL; dvander@61: dvander@61: Scope::Allocate(tree); dvander@61: dvander@61: BytecodeCompiler compiler(ZONE(), tree, NULL); dvander@61: return compiler.compile(); dvander@61: } dvander@61: dvander@61: Ke::Local dvander@61: Ke::Compile(const char *path) dvander@61: { dvander@61: RootScope roots(ZONE()); dvander@61: CompileContext cc(ZONE()); dvander@61: dvander@61: char *bytes = NULL; dvander@61: size_t length; dvander@61: { dvander@61: FILE *fp = fopen(path, "rb"); dvander@61: if (!fp) { dvander@61: cc.reportError(SourcePosition(), Message_CantOpenFile); dvander@61: return Ke::Local(); dvander@61: } dvander@61: dvander@61: if (fseek(fp, 0, SEEK_END)) { dvander@61: cc.reportError(SourcePosition(), Message_ErrorSeekingFile); dvander@61: fclose(fp); dvander@61: return Ke::Local();; dvander@61: } dvander@61: long size = ftell(fp); dvander@61: if (size < 0) { dvander@61: cc.reportError(SourcePosition(), Message_ErrorSeekingFile); dvander@61: fclose(fp); dvander@61: return Ke::Local();; dvander@61: } dvander@61: rewind(fp); dvander@61: length = size_t(size); dvander@61: bytes = new char[length + 1]; dvander@61: if (fread(bytes, 1, length, fp) != length) { dvander@61: cc.reportError(SourcePosition(), Message_ErrorReadingFile); dvander@61: fclose(fp); dvander@61: delete [] bytes; dvander@61: return Ke::Local();; dvander@61: } dvander@61: fclose(fp); dvander@61: } dvander@61: dvander@61: ke::Local module(ZONE(), CompileFromSource(cc, path, bytes, length)); dvander@61: delete [] bytes; dvander@61: if (!module) dvander@61: return Ke::Local(); dvander@61: dvander@61: return ToLocal(module); dvander@61: } dvander@61: dvander@61: static inline ke::HeapRoot * dvander@61: FromAPI(ke::HeapRoot *from) dvander@61: { dvander@61: ke::Address address = reinterpret_cast(from); dvander@61: address -= offsetof(ke::HeapRoot, obj); dvander@61: return reinterpret_cast(address); dvander@61: } dvander@61: dvander@61: ke::HeapRoot * dvander@61: Ke::Internals::NewHeapRoot(ke::Object **ptr) dvander@61: { dvander@61: ke::Local obj(ZONE(), *ptr); dvander@61: ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj); dvander@61: if (!root) dvander@61: return NULL; dvander@61: dvander@61: // Compute an interior pointer, so it looks like a Handle to an object. dvander@61: return reinterpret_cast(&root->obj); dvander@61: } dvander@61: dvander@61: void dvander@61: Ke::Internals::IncRef(ke::HeapRoot *root) dvander@61: { dvander@61: ZONE()->globalRoots()->incref(FromAPI(root)); dvander@61: } dvander@61: dvander@61: void dvander@61: Ke::Internals::DecRef(ke::HeapRoot *root) dvander@61: { dvander@61: ZONE()->globalRoots()->decref(FromAPI(root)); dvander@61: } dvander@62: dvander@62: bool dvander@62: Ke::Keima::IsInCallStack(Handle argModule) dvander@62: { dvander@62: ke::Local module(ke::ZONE(), Open(argModule)); dvander@62: return ZONE()->stack().isInCallStack(module); dvander@62: } dvander@62: dvander@62: void dvander@62: Ke::Keima::CollectGarbage() dvander@62: { dvander@62: ke::ZONE()->heap().reclaim(); dvander@62: } dvander@64: dvander@64: unsigned dvander@64: Ke::Module::numPublics() dvander@64: { dvander@64: ke::Local module(ke::ZONE(), Open(this)); dvander@64: return module->publics()->length(); dvander@64: } dvander@64: dvander@64: Ke::Local dvander@64: Ke::Module::getPublic(unsigned index) dvander@64: { dvander@64: ke::Local module(ke::ZONE(), Open(this)); dvander@64: ke::Local fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index))); dvander@64: return ToLocal(fun); dvander@64: } dvander@64: dvander@64: unsigned dvander@64: Ke::String::length() dvander@64: { dvander@64: ke::Local obj(ke::ZONE(), Open(this)); dvander@64: return obj->length(); dvander@64: } dvander@64: dvander@64: const char * dvander@64: Ke::String::chars() dvander@64: { dvander@64: ke::Local obj(ke::ZONE(), Open(this)); dvander@64: return obj->chars(); dvander@64: } dvander@64: dvander@64: Ke::Local dvander@64: Ke::Function::name() dvander@64: { dvander@64: ke::Local fun(ke::ZONE(), Open(this)); dvander@64: return ToLocal(fun->name()); dvander@64: }