diff -r 11c81eb30246 -r 7c942b5adebc jitcraft/API.cpp --- a/jitcraft/API.cpp Sun Jul 08 17:57:44 2012 -0700 +++ b/jitcraft/API.cpp Mon Jul 09 01:22:03 2012 -0700 @@ -26,6 +26,9 @@ #include "BytecodeCompiler.h" #include "Modules.h" #include "GlobalRoots.h" +#include "Reference.h" +#include "Array.h" +#include "Interpreter.h" using namespace ke; @@ -203,6 +206,8 @@ Ke::Module::numPublics() { ke::Local module(ke::ZONE(), Open(this)); + if (!module->publics()) + return 0; return module->publics()->length(); } @@ -234,3 +239,143 @@ ke::Local fun(ke::ZONE(), Open(this)); return ToLocal(fun->name()); } + +static inline bool +CheckInvokeType(const Ke::Parameter ¶m, Type *type) +{ + switch (param.type()) { + case Ke::Parameter::Array: + return type->isArray() && + type->levels() == 1 && + type->contained()->isPrimitive() && + (type->contained()->primitive() != PrimitiveType_Char); + case Ke::Parameter::CharArray: + return type->isCharArray(); + case Ke::Parameter::Float: + return type->isFloat(); + case Ke::Parameter::FloatRef: + return type->isReference() && type->contained()->isFloat(); + case Ke::Parameter::Int: + return type->isInt32(); + case Ke::Parameter::IntRef: + return type->isReference() && type->contained()->isInt32(); + default: + return false; + } +} + +bool +Ke::Keima::CheckInvokeTypes(Ke::Handle argFun, const Ke::Parameter *params, unsigned nparams) +{ + ke::Local fun(ke::ZONE(), Open(argFun)); + + if (fun->nargs() != nparams) + return false; + + for (unsigned i = 0; i < nparams; i++) { + if (!CheckInvokeType(params[i], fun->argType(i))) + return false; + } + + // Functions can only return tagged cells, for ISPE1-compatible Invoke(). + if (!fun->type()->returnType()->isPrimitive() || fun->type()->returnType()->isTraceable()) + return false; + + return true; +} + +bool +Ke::Keima::Invoke(Handle argFun, const Parameter *params, unsigned nparams, int *retval) +{ + assert(CheckInvokeTypes(argFun, params, nparams)); + + ke::Local fun(ke::ZONE(), Open(argFun)); + + if (fun->nargs() != nparams) { + // :TODO: report error + assert(false); + return false; + } + + ke::InvokeArgs args; + if (!ke::ZONE()->stack().pushInvokeFrame(fun, args)) + return false; + + for (unsigned i = 0; i < nparams; i++) { + ke::LocalSlot &slot = args.arg(i); + switch (params[i].type()) { + case Ke::Parameter::Int: + slot.i32 = params[i].i32(); + break; + + case Ke::Parameter::Float: + slot.f = params[i].f(); + break; + + case Ke::Parameter::IntRef: + if (params[i].writeback()) { + slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack); + } else { + LocalSlot other; + other.i32 = *params[i].i32p(); + slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack); + } + if (!slot.ref) + return false; + break; + + case Ke::Parameter::FloatRef: + if (params[i].writeback()) { + slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack); + } else { + LocalSlot other; + other.f = *params[i].fp(); + slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack); + } + if (!slot.ref) + return false; + break; + + case Ke::Parameter::Array: + { + ke::Local map(ke::ZONE(), ke::ZONE()->genericArrayMap()); + if (params[i].writeback()) { + slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(), + params[i].buffer(), Heap::Tenure_Stack); + if (!slot.obj) + return false; + } else { + Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack); + if (!slot.obj) + return false; + memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int)); + } + break; + } + + case Ke::Parameter::CharArray: + { + ke::Local map(ke::ZONE(), ke::ZONE()->charArrayMap()); + if (params[i].writeback()) { + slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(), + params[i].buffer(), Heap::Tenure_Stack); + if (!slot.obj) + return false; + } else { + Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack); + if (!slot.obj) + return false; + memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char)); + } + break; + } + } + } + + LocalSlot result; + if (!Interpret(ke::ZONE(), NULL, &result)) + return false; + + *retval = result.i32; + return true; +}