Re-add postinc support.
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 ke::Local<ke::Module> module(ZONE(), CompileFromSource(cc, path, bytes, length));
118 ke::Local<ke::String> pathstr(ZONE(), ke::String::New(ZONE(), path, Heap::Tenure_Old));
122 module->setPath(pathstr);
128 // This is split out from InternalCompile so the RootScope doesn't conflict
129 // with making a return handle.
130 Ke::Local<Ke::Module>
131 Ke::Compile(const char *path)
133 ke::Local<ke::Module> module(ZONE(), InternalCompile(path));
134 return ToLocal<ke::Module, Ke::Module>(module);
138 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
140 ZONE()->installErrorReporter(reporter);
143 class StackFrameIterator : public Ke::IStackFrameIterator
153 virtual bool done() {
157 const char *function() {
158 return iter_.function();
161 const char *source() {
162 return iter_.source();
165 unsigned lineNumber() {
166 return iter_.lineNumber();
174 Ke::IStackFrameIterator *
175 Ke::Keima::NewStackFrameIterator()
177 return new StackFrameIterator();
180 static inline ke::HeapRoot *
181 FromAPI(ke::HeapRoot *from)
183 ke::Address address = reinterpret_cast<ke::Address>(from);
184 address -= offsetof(ke::HeapRoot, obj);
185 return reinterpret_cast<ke::HeapRoot *>(address);
189 Ke::Internals::NewHeapRoot()
191 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
195 // Compute an interior pointer, so it looks like a Handle to an object.
196 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
200 Ke::Internals::Destroy(ke::HeapRoot *root)
202 ZONE()->globalRoots()->destroy(FromAPI(root));
206 Ke::Keima::IsInCallStack(Handle<Module> argModule)
208 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
209 return ZONE()->stack().isInCallStack(module);
213 Ke::Keima::CollectGarbage()
215 ke::ZONE()->heap().reclaim();
219 Ke::Keima::ClearPendingException()
221 ke::ZONE()->clearPendingException();
225 Ke::Module::setNativeIdentity(void *identity)
227 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
228 module->setNativeIdentity(identity);
234 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
235 return obj->length();
241 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
245 Ke::Local<Ke::String>
248 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
249 return ToLocal<ke::String, Ke::String>(fun->name());
252 static inline const char *
253 GetInvokeTypeName(Ke::Parameter::Type type)
256 case Ke::Parameter::Array:
258 case Ke::Parameter::CharArray:
260 case Ke::Parameter::Float:
262 case Ke::Parameter::FloatRef:
264 case Ke::Parameter::Int:
266 case Ke::Parameter::IntRef:
274 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
276 switch (param.type()) {
277 case Ke::Parameter::Array:
279 if (!type->isArray())
282 ArrayType *atype = ArrayType::cast(type);
283 return atype->levels() == 1 &&
284 (atype->contained()->isPrimitive() || atype->contained()->isEnum()) &&
285 (atype->contained()->primitive() != PrimitiveType_Char);
287 case Ke::Parameter::CharArray:
288 return type->isArray() && ArrayType::cast(type)->isCharArray();
289 case Ke::Parameter::Float:
290 return type->isFloat();
291 case Ke::Parameter::FloatRef:
292 return type->isReference() && type->contained_ref()->isFloat();
293 case Ke::Parameter::Int:
294 return type->isInt32() || type->isEnum();
295 case Ke::Parameter::IntRef:
296 return type->isReference() && (type->contained_ref()->isInt32() || type->contained_ref()->isEnum());
303 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
305 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
307 if (fun->nargs() != nparams)
310 for (unsigned i = 0; i < nparams; i++) {
311 if (!CheckInvokeType(params[i], fun->argType(i))) {
312 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
313 GetInvokeTypeName(params[i].type()),
314 GetTypeName(fun->argType(i)));
319 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
320 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
321 if (!returnType->isPrimitive() &&
322 !returnType->isEnum() &&
323 !returnType->isVoid())
325 ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
333 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
334 bool checkTypes, int *retval)
336 assert(CheckInvokeTypes(argFun, params, nparams));
338 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
340 if (fun->nargs() != nparams) {
341 // :TODO: report error
347 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
350 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
353 for (unsigned i = 0; i < nparams; i++) {
354 ke::LocalSlot &slot = args.arg(i);
355 switch (params[i].type()) {
356 case Ke::Parameter::Int:
357 slot.i32 = params[i].i32();
360 case Ke::Parameter::Float:
361 slot.f = params[i].f();
364 case Ke::Parameter::IntRef:
365 if (params[i].writeback()) {
366 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
369 other.i32 = *params[i].i32p();
370 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
376 case Ke::Parameter::FloatRef:
377 if (params[i].writeback()) {
378 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
381 other.f = *params[i].fp();
382 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
388 case Ke::Parameter::Array:
390 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
391 if (params[i].writeback()) {
392 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
393 params[i].length(), Heap::Tenure_Stack);
397 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
400 if (params[i].length())
401 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
406 case Ke::Parameter::CharArray:
408 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
409 if (params[i].writeback()) {
410 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
411 params[i].length(), Heap::Tenure_Stack);
415 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
418 if (params[i].length())
419 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
427 if (!Interpret(ke::ZONE(), NULL, &result))
430 if (fun->type()->returnType()->isVoid())
433 *retval = result.i32;
438 Ke::Keima::BindNative(const char *name, void *address)
440 return ke::ZONE()->nativeTable()->bind(name, address);
444 Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
446 ke::ZONE()->setPublicFunctionListener(listener);
450 Zone::registerPublic(ke::Handle<Function> fun)
452 if (!publicFunctionListener_)
455 Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
456 publicFunctionListener_->registerPublic(local);