Fixed reporting of unbound names, and restricted late binding to global functions.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
19 #include "../include/keima.h"
21 #include "RootScopes.h"
22 #include "CompileContext.h"
25 #include "SemanticAnalysis.h"
26 #include "BytecodeCompiler.h"
28 #include "GlobalRoots.h"
29 #include "Reference.h"
31 #include "Interpreter.h"
38 Ke::Keima::Initialize()
40 SingleThreadedZone = new Zone();
41 if (!SingleThreadedZone || !SingleThreadedZone->initialize())
49 delete SingleThreadedZone;
50 SingleThreadedZone = NULL;
53 Ke::HandleScope::HandleScope()
55 position_(zone_->rootScopes().position()),
56 prev_(*zone_->rootScopes().scope())
58 *zone_->rootScopes().scope() = this;
61 Ke::HandleScope::~HandleScope()
63 zone_->rootScopes().unwind(position_);
64 *zone_->rootScopes().scope() = prev_;
68 Ke::HandleScope::CreateHandle(ke::Object *obj)
73 return ZONE()->rootScopes().make(obj);
76 template <typename From, typename To> static inline To *
77 Open(Ke::Handle<From> from)
79 return *reinterpret_cast<To **>(*from);
82 template <typename From, typename To> static inline To *
85 return *reinterpret_cast<To **>(from);
88 template <typename From, typename To> static inline Ke::Local<To>
91 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
95 CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
97 Parser parser(ZONE(), cc, stream, length);
98 ParseTree *tree = parser.parse();
103 if (!Scope::Bind(cc, tree))
106 SemanticAnalysis semantics(ZONE(), cc, tree);
107 if (!semantics.analyze())
110 Scope::Allocate(tree);
112 BytecodeCompiler compiler(ZONE(), tree, NULL);
113 return compiler.compile();
116 Ke::Local<Ke::Module>
117 Ke::Compile(const char *path)
119 RootScope roots(ZONE());
120 CompileContext cc(ZONE(), path);
125 FILE *fp = fopen(path, "rb");
127 cc.reportError(SourcePosition(), Message_CantOpenFile);
128 return Ke::Local<Ke::Module>();
131 if (fseek(fp, 0, SEEK_END)) {
132 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
134 return Ke::Local<Ke::Module>();;
136 long size = ftell(fp);
138 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
140 return Ke::Local<Ke::Module>();;
143 length = size_t(size);
144 bytes = new char[length + 1];
145 if (fread(bytes, 1, length, fp) != length) {
146 cc.reportError(SourcePosition(), Message_ErrorReadingFile);
149 return Ke::Local<Ke::Module>();;
154 ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
157 return Ke::Local<Ke::Module>();
159 ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
161 return Ke::Local<Ke::Module>();
163 module->setPath(pathstr);
164 return ToLocal<ke::Module, Ke::Module>(module);
168 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
170 ZONE()->installErrorReporter(reporter);
173 class StackFrameIterator : public Ke::IStackFrameIterator
183 virtual bool done() {
187 const char *function() {
188 return iter_.function();
191 const char *source() {
192 return iter_.source();
195 unsigned lineNumber() {
196 return iter_.lineNumber();
204 Ke::IStackFrameIterator *
205 Ke::Keima::NewStackFrameIterator()
207 return new StackFrameIterator();
210 static inline ke::HeapRoot *
211 FromAPI(ke::HeapRoot *from)
213 ke::Address address = reinterpret_cast<ke::Address>(from);
214 address -= offsetof(ke::HeapRoot, obj);
215 return reinterpret_cast<ke::HeapRoot *>(address);
219 Ke::Internals::NewHeapRoot(ke::Object **ptr)
221 ke::Local<ke::Object> obj(ZONE(), *ptr);
222 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
226 // Compute an interior pointer, so it looks like a Handle to an object.
227 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
231 Ke::Internals::IncRef(ke::HeapRoot *root)
233 ZONE()->globalRoots()->incref(FromAPI(root));
237 Ke::Internals::DecRef(ke::HeapRoot *root)
239 ZONE()->globalRoots()->decref(FromAPI(root));
243 Ke::Keima::IsInCallStack(Handle<Module> argModule)
245 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
246 return ZONE()->stack().isInCallStack(module);
250 Ke::Keima::CollectGarbage()
252 ke::ZONE()->heap().reclaim();
256 Ke::Module::numPublics()
258 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
259 if (!module->publics())
261 return module->publics()->length();
264 Ke::Local<Ke::Function>
265 Ke::Module::getPublic(unsigned index)
267 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
268 ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
269 return ToLocal<ke::Function, Ke::Function>(fun);
273 Ke::Module::numNatives()
275 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
276 if (!module->natives())
278 return module->natives()->length();
281 Ke::Local<Ke::Native>
282 Ke::Module::getNative(unsigned index)
284 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
285 ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
286 return ToLocal<ke::Native, Ke::Native>(fun);
290 Ke::Module::setNativeIdentity(void *identity)
292 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
293 module->setNativeIdentity(identity);
299 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
300 return obj->length();
306 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
310 Ke::Local<Ke::String>
313 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
314 return ToLocal<ke::String, Ke::String>(fun->name());
317 Ke::Local<Ke::String>
320 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
321 return ToLocal<ke::String, Ke::String>(native->name());
325 Ke::Native::bind(void *function)
327 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
328 native->bind(function);
332 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
334 switch (param.type()) {
335 case Ke::Parameter::Array:
336 return type->isArray() &&
337 type->levels() == 1 &&
338 type->contained()->isPrimitive() &&
339 (type->contained()->primitive() != PrimitiveType_Char);
340 case Ke::Parameter::CharArray:
341 return type->isCharArray();
342 case Ke::Parameter::Float:
343 return type->isFloat();
344 case Ke::Parameter::FloatRef:
345 return type->isReference() && type->contained()->isFloat();
346 case Ke::Parameter::Int:
347 return type->isInt32();
348 case Ke::Parameter::IntRef:
349 return type->isReference() && type->contained()->isInt32();
356 Ke::Keima::CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
358 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
360 if (fun->nargs() != nparams)
363 for (unsigned i = 0; i < nparams; i++) {
364 if (!CheckInvokeType(params[i], fun->argType(i)))
368 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
369 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
370 if ((!returnType->isPrimitive() && !returnType->isVoid()) || returnType->isTraceable())
377 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams, int *retval)
379 assert(CheckInvokeTypes(argFun, params, nparams));
381 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
383 if (fun->nargs() != nparams) {
384 // :TODO: report error
390 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
393 for (unsigned i = 0; i < nparams; i++) {
394 ke::LocalSlot &slot = args.arg(i);
395 switch (params[i].type()) {
396 case Ke::Parameter::Int:
397 slot.i32 = params[i].i32();
400 case Ke::Parameter::Float:
401 slot.f = params[i].f();
404 case Ke::Parameter::IntRef:
405 if (params[i].writeback()) {
406 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
409 other.i32 = *params[i].i32p();
410 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
416 case Ke::Parameter::FloatRef:
417 if (params[i].writeback()) {
418 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
421 other.f = *params[i].fp();
422 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
428 case Ke::Parameter::Array:
430 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
431 if (params[i].writeback()) {
432 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
433 params[i].buffer(), Heap::Tenure_Stack);
437 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
440 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
445 case Ke::Parameter::CharArray:
447 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
448 if (params[i].writeback()) {
449 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
450 params[i].buffer(), Heap::Tenure_Stack);
454 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
457 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
465 if (!Interpret(ke::ZONE(), NULL, &result))
468 if (fun->type()->returnType()->isVoid())
471 *retval = result.i32;