Fix various error reporting bugs related to Invoke.
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/.
20 #include "../include/keima.h"
22 #include "RootScopes.h"
23 #include "CompileContext.h"
26 #include "SemanticAnalysis.h"
27 #include "BytecodeCompiler.h"
29 #include "GlobalRoots.h"
30 #include "Reference.h"
32 #include "Interpreter.h"
35 #include "Spaces-inl.h"
41 Ke::Keima::Initialize()
43 SingleThreadedZone = new Zone();
44 if (!SingleThreadedZone || !SingleThreadedZone->initialize())
52 delete SingleThreadedZone;
53 SingleThreadedZone = NULL;
56 Ke::HandleScope::HandleScope()
58 position_(zone_->rootScopes().position()),
59 prev_(*zone_->rootScopes().scope())
61 *zone_->rootScopes().scope() = this;
64 Ke::HandleScope::~HandleScope()
66 zone_->rootScopes().unwind(position_);
67 *zone_->rootScopes().scope() = prev_;
71 Ke::HandleScope::CreateHandle(ke::Object *obj)
76 return ZONE()->rootScopes().make(obj);
79 template <typename From, typename To> static inline To *
80 Open(Ke::Handle<From> from)
82 return *reinterpret_cast<To **>(*from);
85 template <typename From, typename To> static inline To *
88 return *reinterpret_cast<To **>(from);
91 template <typename From, typename To> static inline Ke::Local<To>
94 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
98 CompileFromSource(CompileContext &cc, const char *path, const char *stream, size_t length)
100 Parser parser(ZONE(), cc, stream, length);
101 ParseTree *tree = parser.parse();
106 if (!Scope::Bind(cc, tree))
109 SemanticAnalysis semantics(ZONE(), cc, tree);
110 if (!semantics.analyze())
113 Scope::Allocate(tree);
115 BytecodeCompiler compiler(ZONE(), tree, NULL);
116 ke::Local<Module> module(ke::ZONE(), compiler.compile());
121 if (!ke::ZONE()->stack().pushModuleFrame(module, args))
123 if (!ke::Interpret(ke::ZONE(), NULL, NULL))
129 Ke::Local<Ke::Module>
130 Ke::Compile(const char *path)
132 RootScope roots(ZONE());
133 CompileContext cc(ZONE(), path);
138 FILE *fp = fopen(path, "rb");
140 cc.reportError(SourcePosition(), Message_CantOpenFile);
141 return Ke::Local<Ke::Module>();
144 if (fseek(fp, 0, SEEK_END)) {
145 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
147 return Ke::Local<Ke::Module>();;
149 long size = ftell(fp);
151 cc.reportError(SourcePosition(), Message_ErrorSeekingFile);
153 return Ke::Local<Ke::Module>();;
156 length = size_t(size);
157 bytes = new char[length + 1];
158 if (fread(bytes, 1, length, fp) != length) {
159 cc.reportError(SourcePosition(), Message_ErrorReadingFile);
162 return Ke::Local<Ke::Module>();;
167 ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
170 return Ke::Local<Ke::Module>();
172 ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
174 return Ke::Local<Ke::Module>();
176 module->setPath(pathstr);
177 return ToLocal<ke::Module, Ke::Module>(module);
181 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
183 ZONE()->installErrorReporter(reporter);
186 class StackFrameIterator : public Ke::IStackFrameIterator
196 virtual bool done() {
200 const char *function() {
201 return iter_.function();
204 const char *source() {
205 return iter_.source();
208 unsigned lineNumber() {
209 return iter_.lineNumber();
217 Ke::IStackFrameIterator *
218 Ke::Keima::NewStackFrameIterator()
220 return new StackFrameIterator();
223 static inline ke::HeapRoot *
224 FromAPI(ke::HeapRoot *from)
226 ke::Address address = reinterpret_cast<ke::Address>(from);
227 address -= offsetof(ke::HeapRoot, obj);
228 return reinterpret_cast<ke::HeapRoot *>(address);
232 Ke::Internals::NewHeapRoot(ke::Object **ptr)
234 ke::Local<ke::Object> obj(ZONE(), *ptr);
235 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create(obj);
239 // Compute an interior pointer, so it looks like a Handle to an object.
240 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
244 Ke::Internals::IncRef(ke::HeapRoot *root)
246 ZONE()->globalRoots()->incref(FromAPI(root));
250 Ke::Internals::DecRef(ke::HeapRoot *root)
252 ZONE()->globalRoots()->decref(FromAPI(root));
256 Ke::Keima::IsInCallStack(Handle<Module> argModule)
258 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
259 return ZONE()->stack().isInCallStack(module);
263 Ke::Keima::CollectGarbage()
265 ke::ZONE()->heap().reclaim();
269 Ke::Keima::ClearPendingException()
271 ke::ZONE()->clearPendingException();
275 Ke::Module::numPublics()
277 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
278 if (!module->publics())
280 return module->publics()->length();
283 Ke::Local<Ke::Function>
284 Ke::Module::getPublic(unsigned index)
286 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
287 ke::Local<ke::Function> fun(ke::ZONE(), ke::Function::cast(module->publics()->at(index)));
288 return ToLocal<ke::Function, Ke::Function>(fun);
292 Ke::Module::numNatives()
294 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
295 if (!module->natives())
297 return module->natives()->length();
300 Ke::Local<Ke::Native>
301 Ke::Module::getNative(unsigned index)
303 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
304 ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
305 return ToLocal<ke::Native, Ke::Native>(fun);
309 Ke::Module::setNativeIdentity(void *identity)
311 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
312 module->setNativeIdentity(identity);
318 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
319 return obj->length();
325 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
329 Ke::Local<Ke::String>
332 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
333 return ToLocal<ke::String, Ke::String>(fun->name());
336 Ke::Local<Ke::String>
339 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
340 return ToLocal<ke::String, Ke::String>(native->name());
344 Ke::Native::bind(void *function)
346 ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
347 native->bind(function);
350 // :TODO: this leaks an interior pointer.
352 GetTypeName(Type *type)
356 if (type->isFunction())
360 if (type->isReference())
361 type = type->contained();
363 return type->tag()->chars();
367 static inline const char *
368 GetInvokeTypeName(Ke::Parameter::Type type)
371 case Ke::Parameter::Array:
373 case Ke::Parameter::CharArray:
375 case Ke::Parameter::Float:
377 case Ke::Parameter::FloatRef:
379 case Ke::Parameter::Int:
381 case Ke::Parameter::IntRef:
389 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
391 switch (param.type()) {
392 case Ke::Parameter::Array:
393 return type->isArray() &&
394 type->levels() == 1 &&
395 type->contained()->isPrimitive() &&
396 (type->contained()->primitive() != PrimitiveType_Char);
397 case Ke::Parameter::CharArray:
398 return type->isCharArray();
399 case Ke::Parameter::Float:
400 return type->isFloat();
401 case Ke::Parameter::FloatRef:
402 return type->isReference() && type->contained()->isFloat();
403 case Ke::Parameter::Int:
404 return type->isInt32();
405 case Ke::Parameter::IntRef:
406 return type->isReference() && type->contained()->isInt32();
413 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
415 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
417 if (fun->nargs() != nparams)
420 for (unsigned i = 0; i < nparams; i++) {
421 if (!CheckInvokeType(params[i], fun->argType(i))) {
422 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
423 GetInvokeTypeName(params[i].type()),
424 GetTypeName(fun->argType(i)));
429 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
430 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
431 if (!returnType->isPrimitive() && !returnType->isVoid()) {
432 ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
440 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
441 bool checkTypes, int *retval)
443 assert(CheckInvokeTypes(argFun, params, nparams));
445 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
447 if (fun->nargs() != nparams) {
448 // :TODO: report error
454 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
457 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
460 for (unsigned i = 0; i < nparams; i++) {
461 ke::LocalSlot &slot = args.arg(i);
462 switch (params[i].type()) {
463 case Ke::Parameter::Int:
464 slot.i32 = params[i].i32();
467 case Ke::Parameter::Float:
468 slot.f = params[i].f();
471 case Ke::Parameter::IntRef:
472 if (params[i].writeback()) {
473 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
476 other.i32 = *params[i].i32p();
477 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
483 case Ke::Parameter::FloatRef:
484 if (params[i].writeback()) {
485 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
488 other.f = *params[i].fp();
489 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
495 case Ke::Parameter::Array:
497 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
498 if (params[i].writeback()) {
499 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
500 params[i].buffer(), Heap::Tenure_Stack);
504 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
507 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
512 case Ke::Parameter::CharArray:
514 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
515 if (params[i].writeback()) {
516 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
517 params[i].buffer(), Heap::Tenure_Stack);
521 Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
524 memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
532 if (!Interpret(ke::ZONE(), NULL, &result))
535 if (fun->type()->returnType()->isVoid())
538 *retval = result.i32;