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"
32 #include "NativeTable.h"
33 #include "Spaces-inl.h"
39 Ke::Keima::Initialize()
41 SingleThreadedZone = new Zone();
42 if (!SingleThreadedZone || !SingleThreadedZone->initialize())
50 delete SingleThreadedZone;
51 SingleThreadedZone = NULL;
54 Ke::HandleScope::HandleScope()
56 position_(zone_->rootScopes().position()),
57 prev_(*zone_->rootScopes().scope())
59 *zone_->rootScopes().scope() = this;
62 Ke::HandleScope::~HandleScope()
64 zone_->rootScopes().unwind(position_);
65 *zone_->rootScopes().scope() = prev_;
69 Ke::HandleScope::CreateHandle(ke::Object *obj)
74 return ZONE()->rootScopes().make(obj);
77 template <typename From, typename To> static inline To *
78 Open(Ke::Handle<From> from)
82 return *reinterpret_cast<To **>(*from);
85 template <typename From, typename To> static inline To *
90 return *reinterpret_cast<To **>(from);
93 template <typename From, typename To> static inline Ke::Local<To>
97 return Ke::Local<To>();
98 return Ke::Local<To>(reinterpret_cast<To *>(Ke::HandleScope::CreateHandle(from)));
102 InternalCompile(ke::Handle<ke::Package> package, const char *name)
104 PoolScope poolScope(ZONE()->pool());
105 RootScope roots(ZONE());
106 CompileContext cc(ZONE());
108 if (!cc.initialize(package, name))
117 // This is split out from InternalCompile so the RootScope doesn't conflict
118 // with making a return handle.
120 Ke::Keima::Compile(Handle<Package> argPackage, const char *name)
122 ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(argPackage));
123 return InternalCompile(package, name);
127 Ke::Keima::InstallMessageReporter(Ke::IMessageReporter *reporter)
129 ZONE()->installErrorReporter(reporter);
132 class StackFrameIterator : public Ke::IStackFrameIterator
142 virtual bool done() {
146 const char *function() {
147 return iter_.function();
150 const char *source() {
151 return iter_.source();
154 unsigned lineNumber() {
155 return iter_.lineNumber();
163 Ke::IStackFrameIterator *
164 Ke::Keima::NewStackFrameIterator()
166 return new StackFrameIterator();
169 static inline ke::HeapRoot *
170 FromAPI(ke::HeapRoot *from)
172 ke::Address address = reinterpret_cast<ke::Address>(from);
173 address -= offsetof(ke::HeapRoot, obj);
174 return reinterpret_cast<ke::HeapRoot *>(address);
178 Ke::Internals::NewHeapRoot()
180 ke::HeapRoot *root = ke::ZONE()->globalRoots()->create();
184 // Compute an interior pointer, so it looks like a Handle to an object.
185 return reinterpret_cast<ke::HeapRoot *>(&root->obj);
189 Ke::Internals::Destroy(ke::HeapRoot *root)
191 ZONE()->globalRoots()->destroy(FromAPI(root));
196 Ke::Keima::IsInCallStack(Handle<Package> package)
198 ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(argModule));
199 return ZONE()->stack().isInCallStack(module);
204 Ke::Keima::CollectGarbage()
206 ke::ZONE()->heap().reclaim();
210 Ke::Keima::ClearPendingException()
212 ke::ZONE()->clearPendingException();
216 Ke::Package::setNativeIdentity(void *identity)
218 ke::Local<ke::Package> package(ke::ZONE(), Open<Ke::Package, ke::Package>(this));
219 package->setNativeIdentity(identity);
225 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
226 return obj->length();
232 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
236 Ke::Local<Ke::String>
239 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
240 return ToLocal<ke::String, Ke::String>(fun->name());
243 Ke::Local<Ke::Package>
244 Ke::Package::New(Handle<Package> argParent,
245 Handle<String> argName,
249 ke::Local<ke::Package> parent(ke::ZONE(), Open<Ke::Package, ke::Package>(argParent));
250 ke::Local<ke::String> name(ke::ZONE(), Open<Ke::String, ke::String>(argName));
251 ke::Local<ke::Package> package(ke::ZONE(), ke::Package::New(ke::ZONE(), parent, path, name, flags));
252 return ToLocal<ke::Package, Ke::Package>(package);
255 static inline const char *
256 GetInvokeTypeName(Ke::Parameter::Type type)
259 case Ke::Parameter::Array:
261 case Ke::Parameter::CharArray:
263 case Ke::Parameter::Float:
265 case Ke::Parameter::FloatRef:
267 case Ke::Parameter::Int:
269 case Ke::Parameter::IntRef:
277 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
279 switch (param.type()) {
280 case Ke::Parameter::Array:
282 if (!type->isArray())
285 ArrayType *atype = ArrayType::cast(type);
286 return atype->levels() == 1 &&
287 (atype->contained()->isPrimitive() || atype->contained()->isEnum()) &&
288 (atype->contained()->primitive() != PrimitiveType_Char);
290 case Ke::Parameter::CharArray:
291 return type->isArray() && ArrayType::cast(type)->isCharArray();
292 case Ke::Parameter::Float:
293 return type->isFloat();
294 case Ke::Parameter::FloatRef:
295 return type->isReference() && ReferenceType::cast(type)->contained()->isFloat();
296 case Ke::Parameter::Int:
297 return type->isInt32() || type->isEnum();
298 case Ke::Parameter::IntRef:
299 return type->isReference() &&
300 (ReferenceType::cast(type)->contained()->isInt32() ||
301 ReferenceType::cast(type)->contained()->isEnum());
308 CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
310 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
312 if (fun->nargs() != nparams)
315 for (unsigned i = 0; i < nparams; i++) {
316 if (!CheckInvokeType(params[i], fun->argType(i))) {
318 ke::ZONE()->reportError(Message_TypeMismatchDuringInvoke,
319 GetInvokeTypeName(params[i].type()),
320 GetTypeName(fun->argType(i), name, sizeof(name)));
325 // Functions can only return tagged cells, for ISPE1-compatible Invoke().
326 ke::Local<ke::Type> returnType(ke::ZONE(), fun->type()->returnType());
327 if (!returnType->isPrimitive() &&
328 !returnType->isEnum() &&
329 !returnType->isVoid())
332 ke::ZONE()->reportError(Message_CannotInvokeReturnType,
333 GetTypeName(returnType, name, sizeof(name)));
341 Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams,
342 bool checkTypes, int *retval)
344 assert(CheckInvokeTypes(argFun, params, nparams));
346 ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
348 if (fun->nargs() != nparams) {
349 // :TODO: report error
355 if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
358 if (checkTypes && !CheckInvokeTypes(argFun, params, nparams))
361 for (unsigned i = 0; i < nparams; i++) {
362 ke::LocalSlot &slot = args.arg(i);
363 switch (params[i].type()) {
364 case Ke::Parameter::Int:
365 slot.i32 = params[i].i32();
368 case Ke::Parameter::Float:
369 slot.f = params[i].f();
372 case Ke::Parameter::IntRef:
373 if (params[i].writeback()) {
374 slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
377 other.i32 = *params[i].i32p();
378 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
384 case Ke::Parameter::FloatRef:
385 if (params[i].writeback()) {
386 slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
389 other.f = *params[i].fp();
390 slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
396 case Ke::Parameter::Array:
398 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalGenericArrayMap());
399 if (params[i].writeback()) {
400 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
401 params[i].length(), Heap::Tenure_Stack);
405 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
408 if (params[i].length())
409 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(int));
414 case Ke::Parameter::CharArray:
416 ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->externalCharArrayMap());
417 if (params[i].writeback()) {
418 slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].buffer(),
419 params[i].length(), Heap::Tenure_Stack);
423 Array *array = Array::New1D(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
426 if (params[i].length())
427 memcpy(array->bytes(), params[i].buffer(), params[i].length() * sizeof(char));
435 if (!Interpret(ke::ZONE(), NULL, &result))
438 if (fun->type()->returnType()->isVoid())
441 *retval = result.i32;
446 Ke::Keima::BindNative(const char *name, void *address)
448 return ke::ZONE()->nativeTable()->bind(name, address);
452 Ke::Keima::SetPublicFunctionListener(IPublicFunctionListener *listener)
454 ke::ZONE()->setPublicFunctionListener(listener);
458 Zone::registerPublic(ke::Handle<Function> fun)
460 if (!publicFunctionListener_)
463 Ke::Local<Ke::Function> local = ToLocal<ke::Function, Ke::Function>(fun);
464 publicFunctionListener_->registerPublic(local);