Add postinc-ref test.
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() && ReferenceType::cast(type)->contained()->isFloat();
293 case Ke::Parameter::Int:
294 return type->isInt32() || type->isEnum();
295 case Ke::Parameter::IntRef:
296 return type->isReference() &&
297 (ReferenceType::cast(type)->contained()->isInt32() ||
298 ReferenceType::cast(type)->contained()->isEnum());
305 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
307 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
309 if (fun->nargs() != nparams)
312 for (unsigned i = 0; i < nparams; i++) {
313 if (!CheckInvokeType(params[i], fun->argType(i))) {
314 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
315 GetInvokeTypeName(params[i].type()),
316 GetTypeName(fun->argType(i)));
321 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
322 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
323 if (!returnType->isPrimitive() &&
324 !returnType->isEnum() &&
325 !returnType->isVoid())
327 ke::ZONE()->reportError(Message_CannotInvokeReturnType, GetTypeName(returnType));
335 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
336 bool checkTypes, int *retval)
338 assert(CheckInvokeTypes(argFun, params, nparams));
340 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
342 if (fun->nargs() != nparams) {
343 // :TODO: report error
349 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
352 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
355 for (unsigned i = 0; i < nparams; i++) {
356 ke::LocalSlot &slot = args.arg(i);
357 switch (params[i].type()) {
358 case Ke::Parameter::Int:
359 slot.i32 = params[i].i32();
362 case Ke::Parameter::Float:
363 slot.f = params[i].f();
366 case Ke::Parameter::IntRef:
367 if (params[i].writeback()) {
368 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
371 other.i32 = *params[i].i32p();
372 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
378 case Ke::Parameter::FloatRef:
379 if (params[i].writeback()) {
380 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
383 other.f = *params[i].fp();
384 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
390 case Ke::Parameter::Array:
392 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
393 if (params[i].writeback()) {
394 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
395 params[i].length(), Heap::Tenure_Stack);
399 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
402 if (params[i].length())
403 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
408 case Ke::Parameter::CharArray:
410 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
411 if (params[i].writeback()) {
412 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
413 params[i].length(), Heap::Tenure_Stack);
417 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
420 if (params[i].length())
421 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
429 if (!Interpret(ke::ZONE(), NULL, &result))
432 if (fun->type()->returnType()->isVoid())
435 *retval = result.i32;
440 Ke::Keima::BindNative(const char *name, void *address)
442 return ke::ZONE()->nativeTable()->bind(name, address);
446 Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
448 ke::ZONE()->setPublicFunctionListener(listener);
452 Zone::registerPublic(ke::Handle<Function> fun)
454 if (!publicFunctionListener_)
457 Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
458 publicFunctionListener_->registerPublic(local);