Re-introduce definite return analysis.
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 "compiler/CompileContext.h"
25 #include "GlobalRoots.h"
26 #include "Reference.h"
28 #include "Interpreter.h"
31 #include "NativeTable.h"
32 #include "Spaces-inl.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 InternalCompile(const char *path)
97 PoolScope poolScope(ZONE()->pool());
98 RootScope roots(ZONE());
99 CompileContext cc(ZONE(), path);
101 TranslationUnit *unit = new (ZONE()->pool()) TranslationUnit();
104 if (!cc.addTranslationUnit(unit))
113 // This is split out from InternalCompile so the RootScope doesn't conflict
114 // with making a return handle.
116 Ke::Compile(const char *path)
118 return InternalCompile(path);
122 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
124 ZONE()->installErrorReporter(reporter);
127 class StackFrameIterator : public Ke::IStackFrameIterator
137 virtual bool done() {
141 const char *function() {
142 return iter_.function();
145 const char *source() {
146 return iter_.source();
149 unsigned lineNumber() {
150 return iter_.lineNumber();
158 Ke::IStackFrameIterator *
159 Ke::Keima::NewStackFrameIterator()
161 return new StackFrameIterator();
164 static inline ke::HeapRoot *
165 FromAPI(ke::HeapRoot *from)
167 ke::Address address = reinterpret_cast<ke::Address>(from);
168 address -= offsetof(ke::HeapRoot, obj);
169 return reinterpret_cast<ke::HeapRoot *>(address);
173 Ke::Internals::NewHeapRoot()
175 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
179 // Compute an interior pointer, so it looks like a Handle to an object.
180 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
184 Ke::Internals::Destroy(ke::HeapRoot *root)
186 ZONE()->globalRoots()->destroy(FromAPI(root));
190 Ke::Keima::IsInCallStack(Handle<Module> argModule)
192 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
193 return ZONE()->stack().isInCallStack(module);
197 Ke::Keima::CollectGarbage()
199 ke::ZONE()->heap().reclaim();
203 Ke::Keima::ClearPendingException()
205 ke::ZONE()->clearPendingException();
209 Ke::Module::setNativeIdentity(void *identity)
211 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
212 module->setNativeIdentity(identity);
218 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
219 return obj->length();
225 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
229 Ke::Local<Ke::String>
232 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
233 return ToLocal<ke::String, Ke::String>(fun->name());
236 static inline const char *
237 GetInvokeTypeName(Ke::Parameter::Type type)
240 case Ke::Parameter::Array:
242 case Ke::Parameter::CharArray:
244 case Ke::Parameter::Float:
246 case Ke::Parameter::FloatRef:
248 case Ke::Parameter::Int:
250 case Ke::Parameter::IntRef:
258 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
260 switch (param.type()) {
261 case Ke::Parameter::Array:
263 if (!type->isArray())
266 ArrayType *atype = ArrayType::cast(type);
267 return atype->levels() == 1 &&
268 (atype->contained()->isPrimitive() || atype->contained()->isEnum()) &&
269 (atype->contained()->primitive() != PrimitiveType_Char);
271 case Ke::Parameter::CharArray:
272 return type->isArray() && ArrayType::cast(type)->isCharArray();
273 case Ke::Parameter::Float:
274 return type->isFloat();
275 case Ke::Parameter::FloatRef:
276 return type->isReference() && ReferenceType::cast(type)->contained()->isFloat();
277 case Ke::Parameter::Int:
278 return type->isInt32() || type->isEnum();
279 case Ke::Parameter::IntRef:
280 return type->isReference() &&
281 (ReferenceType::cast(type)->contained()->isInt32() ||
282 ReferenceType::cast(type)->contained()->isEnum());
289 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
291 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
293 if (fun->nargs() != nparams)
296 for (unsigned i = 0; i < nparams; i++) {
297 if (!CheckInvokeType(params[i], fun->argType(i))) {
298 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
299 GetInvokeTypeName(params[i].type()),
300 GetTypeName(fun->argType(i)));
305 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
306 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
307 if (!returnType->isPrimitive() &&
308 !returnType->isEnum() &&
309 !returnType->isVoid())
311 ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
319 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
320 bool checkTypes, int *retval)
322 assert(CheckInvokeTypes(argFun, params, nparams));
324 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
326 if (fun->nargs() != nparams) {
327 // :TODO: report error
333 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
336 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
339 for (unsigned i = 0; i < nparams; i++) {
340 ke::LocalSlot &slot = args.arg(i);
341 switch (params[i].type()) {
342 case Ke::Parameter::Int:
343 slot.i32 = params[i].i32();
346 case Ke::Parameter::Float:
347 slot.f = params[i].f();
350 case Ke::Parameter::IntRef:
351 if (params[i].writeback()) {
352 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
355 other.i32 = *params[i].i32p();
356 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
362 case Ke::Parameter::FloatRef:
363 if (params[i].writeback()) {
364 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
367 other.f = *params[i].fp();
368 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
374 case Ke::Parameter::Array:
376 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
377 if (params[i].writeback()) {
378 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
379 params[i].length(), Heap::Tenure_Stack);
383 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
386 if (params[i].length())
387 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
392 case Ke::Parameter::CharArray:
394 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
395 if (params[i].writeback()) {
396 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
397 params[i].length(), Heap::Tenure_Stack);
401 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
404 if (params[i].length())
405 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
413 if (!Interpret(ke::ZONE(), NULL, &result))
416 if (fun->type()->returnType()->isVoid())
419 *retval = result.i32;
424 Ke::Keima::BindNative(const char *name, void *address)
426 return ke::ZONE()->nativeTable()->bind(name, address);
430 Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
432 ke::ZONE()->setPublicFunctionListener(listener);
436 Zone::registerPublic(ke::Handle<Function> fun)
438 if (!publicFunctionListener_)
441 Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
442 publicFunctionListener_->registerPublic(local);