Added support for ISourcePawnEngine natives.
Added support for ISourcePawnEngine natives.
1.1 --- a/include/keima.h Mon Jul 09 22:25:52 2012 -0700
1.2 +++ b/include/keima.h Tue Jul 10 02:11:13 2012 -0700
1.3 @@ -204,10 +204,25 @@
1.4 {
1.5 public:
1.6 // Returns the name of a function, which may be NULL. If not NULL, the
1.7 - // string is guaranteed to be interned/
1.8 + // string is guaranteed to be interned.
1.9 Local<String> name();
1.10 };
1.11
1.12 +// A native is an ISourcePawnEngine-compatible function provided by C++.
1.13 +class KE_EXPORT Native
1.14 +{
1.15 + public:
1.16 + // Returns the name of a native, which is never NULL. The string is
1.17 + // guaranteed to be interned.
1.18 + Local<String> name();
1.19 +
1.20 + // Returns the function pointer of the native.
1.21 + void *function();
1.22 +
1.23 + // Sets the function pointer of the native.
1.24 + void bind(void *function);
1.25 +};
1.26 +
1.27 // A module represents a single compiled file, and contains functions and
1.28 // global variables for that file (as well as exported types).
1.29 class KE_EXPORT Module
1.30 @@ -216,6 +231,14 @@
1.31 // Returns publics that are based on forwards.
1.32 unsigned numPublics();
1.33 Local<Function> getPublic(unsigned index);
1.34 +
1.35 + // Returns natives.
1.36 + unsigned numNatives();
1.37 + Local<Native> getNative(unsigned index);
1.38 +
1.39 + // Sets the native identity pointer, which is passed as the first argument
1.40 + // to natives.
1.41 + void setNativeIdentity(void *ptr);
1.42 };
1.43
1.44 class Keima
2.1 --- a/jitcraft/API.cpp Mon Jul 09 22:25:52 2012 -0700
2.2 +++ b/jitcraft/API.cpp Tue Jul 10 02:11:13 2012 -0700
2.3 @@ -220,6 +220,30 @@
2.4 }
2.5
2.6 unsigned
2.7 +Ke::Module::numNatives()
2.8 +{
2.9 + ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
2.10 + if (!module->natives())
2.11 + return 0;
2.12 + return module->natives()->length();
2.13 +}
2.14 +
2.15 +Ke::Local<Ke::Native>
2.16 +Ke::Module::getNative(unsigned index)
2.17 +{
2.18 + ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
2.19 + ke::Local<ke::Native> fun(ke::ZONE(), ke::Native::cast(module->natives()->at(index)));
2.20 + return ToLocal<ke::Native, Ke::Native>(fun);
2.21 +}
2.22 +
2.23 +void
2.24 +Ke::Module::setNativeIdentity(void *identity)
2.25 +{
2.26 + ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
2.27 + module->setNativeIdentity(identity);
2.28 +}
2.29 +
2.30 +unsigned
2.31 Ke::String::length()
2.32 {
2.33 ke::Local<ke::String> obj(ke::ZONE(), Open<Ke::String, ke::String>(this));
2.34 @@ -240,6 +264,20 @@
2.35 return ToLocal<ke::String, Ke::String>(fun->name());
2.36 }
2.37
2.38 +Ke::Local<Ke::String>
2.39 +Ke::Native::name()
2.40 +{
2.41 + ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
2.42 + return ToLocal<ke::String, Ke::String>(native->name());
2.43 +}
2.44 +
2.45 +void
2.46 +Ke::Native::bind(void *function)
2.47 +{
2.48 + ke::Local<ke::Native> native(ke::ZONE(), Open<Ke::Native, ke::Native>(this));
2.49 + native->bind(function);
2.50 +}
2.51 +
2.52 static inline bool
2.53 CheckInvokeType(const Ke::Parameter ¶m, Type *type)
2.54 {
3.1 --- a/jitcraft/BytecodeCompiler.cpp Mon Jul 09 22:25:52 2012 -0700
3.2 +++ b/jitcraft/BytecodeCompiler.cpp Tue Jul 10 02:11:13 2012 -0700
3.3 @@ -595,17 +595,29 @@
3.4 {
3.5 Local<Type> funType(zone_, node->callee()->type());
3.6
3.7 - for (size_t i = 0; i < node->arguments()->length(); i++) {
3.8 + for (size_t i = node->arguments()->length() - 1; i < node->arguments()->length(); i--) {
3.9 Expression *arg = node->arguments()->at(i);
3.10
3.11 + // We need to compute a reference if the parameter was in the form:
3.12 + // f(&a)
3.13 + // Note this form does not allow: f({})
3.14 + //
3.15 + // We also need to compute references for all variadic native
3.16 + // arguments, but arrays and references are already in the
3.17 + // appropriate form.
3.18 Local<Type> given(zone_, arg->type());
3.19 - Local<Type> actual(zone_, Type::cast(funType->parameters()->at(i)));
3.20 - if (actual->isReference()) {
3.21 - if (given->isReference()) {
3.22 - // The input type is already a reference, so we're just passing
3.23 - // it on to the callee.
3.24 - arg->accept(this);
3.25 - } else if (arg->isNameProxy()) {
3.26 + if (i >= funType->parameters()->length())
3.27 + assert(funType->isNative() && funType->isNativeVariadic());
3.28 + else
3.29 + assert(!given->isReference() || !funType->parameterAt(i)->isArray());
3.30 +
3.31 + // If a native is passed to a native, it must only be one level deep.
3.32 + assert(!funType->isNative() || !given->isArray() || given->levels() == 1);
3.33 +
3.34 + bool mustPushReference = !given->isArray() && !given->isReference();
3.35 +
3.36 + if (mustPushReference) {
3.37 + if (arg->isNameProxy()) {
3.38 // :TODO: test with functions and globals
3.39 // Compute a reference to the name.
3.40 Variable *var = arg->toNameProxy()->binding()->toVariable();
3.41 @@ -628,7 +640,12 @@
3.42 }
3.43 }
3.44
3.45 - __ callglobal(node->callee()->toNameProxy()->binding()->toNamedFunction()->slot());
3.46 + NamedFunction *fun = node->callee()->toNameProxy()->binding()->toNamedFunction();
3.47 +
3.48 + if (fun->isNative())
3.49 + __ callnative(fun->slot(), node->arguments()->length());
3.50 + else
3.51 + __ callglobal(fun->slot());
3.52 __ drop(node->arguments()->length());
3.53 }
3.54
3.55 @@ -654,6 +671,19 @@
3.56 void
3.57 BytecodeCompiler::visit(FunctionStatement *node)
3.58 {
3.59 + if (node->fun()->isNative()) {
3.60 + assert(!moduleData_->natives->at(node->fun()->slot()));
3.61 +
3.62 + Local<Type> type(zone_, node->fun()->type());
3.63 + Local<String> name(zone_, node->fun()->name());
3.64 + Local<Native> native(zone_, Native::New(zone_, type, name));
3.65 + if (!native)
3.66 + return;
3.67 +
3.68 + moduleData_->natives->set(zone_, node->fun()->slot(), native);
3.69 + return;
3.70 + }
3.71 +
3.72 // If the function has no body, then it's just a declaration.
3.73 if (!node->body()) {
3.74 assert(node->fun()->isForward() || node->fun()->isPublic());
3.75 @@ -779,6 +809,10 @@
3.76
3.77 if (!moduleData_)
3.78 return NULL;
3.79 +
3.80 + moduleData_->natives = FixedArray::New(zone_, tree_->scope()->numNatives(), Heap::Tenure_Old);
3.81 + if (!moduleData_->natives)
3.82 + return NULL;
3.83
3.84 for (size_t i = 0; i < tree_->statements()->length(); i++) {
3.85 Statement *statement = tree_->statements()->at(i);
3.86 @@ -788,6 +822,8 @@
3.87 #ifndef NDEBUG
3.88 for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
3.89 assert(moduleData_->module->getFunction(i));
3.90 + for (size_t i = 0; i < tree_->scope()->numNatives(); i++)
3.91 + assert(moduleData_->natives->at(i));
3.92 #endif
3.93
3.94 if (moduleData_->publics.length()) {
3.95 @@ -803,5 +839,7 @@
3.96 moduleData_->module->setPublics(list);
3.97 }
3.98
3.99 + moduleData_->module->setNatives(moduleData_->natives);
3.100 +
3.101 return moduleData_->module;
3.102 }
4.1 --- a/jitcraft/BytecodeCompiler.h Mon Jul 09 22:25:52 2012 -0700
4.2 +++ b/jitcraft/BytecodeCompiler.h Tue Jul 10 02:11:13 2012 -0700
4.3 @@ -31,6 +31,7 @@
4.4 {
4.5 ScopedRoot<Module> module;
4.6 PoolList<ScopedRoot<Function> > publics;
4.7 + ScopedRoot<FixedArray> natives;
4.8 };
4.9
4.10 class BytecodeCompiler : public AstVisitor
5.1 --- a/jitcraft/BytecodeEmitter.h Mon Jul 09 22:25:52 2012 -0700
5.2 +++ b/jitcraft/BytecodeEmitter.h Tue Jul 10 02:11:13 2012 -0700
5.3 @@ -338,6 +338,13 @@
5.4 writeOp(OP_CALLGLOBAL);
5.5 writeUint32(index);
5.6 }
5.7 + void callnative(unsigned index, unsigned argc) {
5.8 + recordOops();
5.9 + ensure(OP_CALLNATIVE_LENGTH);
5.10 + writeOp(OP_CALLNATIVE);
5.11 + writeUint32(index);
5.12 + writeUint32(argc);
5.13 + }
5.14 void getarray(PrimitiveType type) {
5.15 switch (type) {
5.16 case PrimitiveType_Float:
6.1 --- a/jitcraft/Functions.cpp Mon Jul 09 22:25:52 2012 -0700
6.2 +++ b/jitcraft/Functions.cpp Tue Jul 10 02:11:13 2012 -0700
6.3 @@ -36,3 +36,16 @@
6.4 fun->name_ = name;
6.5 return fun;
6.6 }
6.7 +
6.8 +Native *
6.9 +Native::New(Zone *zone, Handle<Type> type, Handle<String> name)
6.10 +{
6.11 + Native *fun = Native::cast(zone->allocate(MapKind_Native, sizeof(Native), Heap::Tenure_Old));
6.12 + if (!fun)
6.13 + return NULL;
6.14 +
6.15 + fun->type_ = type;
6.16 + fun->name_ = name;
6.17 + fun->function_ = NULL;
6.18 + return fun;
6.19 +}
7.1 --- a/jitcraft/Functions.h Mon Jul 09 22:25:52 2012 -0700
7.2 +++ b/jitcraft/Functions.h Tue Jul 10 02:11:13 2012 -0700
7.3 @@ -67,6 +67,9 @@
7.4 static inline size_t offsetOfType() {
7.5 return offsetof(Function, type_);
7.6 }
7.7 + static inline size_t offsetOfName() {
7.8 + return offsetof(Function, name_);
7.9 + }
7.10 // End GC Descriptor.
7.11
7.12 static inline Function *cast(Object *obj) {
7.13 @@ -75,6 +78,45 @@
7.14 }
7.15 };
7.16
7.17 +// A Native is a function with a very specialized calling convention, intended
7.18 +// for earlier ISourcePawnEngine API compatibility.
7.19 +class Native : public Object
7.20 +{
7.21 + Barriered<Type> type_;
7.22 + Barriered<String> name_;
7.23 + void *function_;
7.24 +
7.25 + public:
7.26 + static Native *New(Zone *zone, Handle<Type> type, Handle<String> name);
7.27 +
7.28 + void *function() {
7.29 + return function_;
7.30 + }
7.31 + Type *type() {
7.32 + return type_;
7.33 + }
7.34 + String *name() {
7.35 + return name_;
7.36 + }
7.37 + void bind(void *function) {
7.38 + function_ = function;
7.39 + }
7.40 +
7.41 + // Begin GC Descriptor.
7.42 + static inline size_t offsetOfType() {
7.43 + return offsetof(Native, type_);
7.44 + }
7.45 + static inline size_t offsetOfName() {
7.46 + return offsetof(Native, name_);
7.47 + }
7.48 + // End GC Descriptor.
7.49 +
7.50 + static inline Native *cast(Object *obj) {
7.51 + assert(!obj || obj->is(MapKind_Native));
7.52 + return reinterpret_cast<Native *>(obj);
7.53 + }
7.54 +};
7.55 +
7.56 }
7.57
7.58 #endif // _include_jitcraft_function_h_
8.1 --- a/jitcraft/Interpreter.cpp Mon Jul 09 22:25:52 2012 -0700
8.2 +++ b/jitcraft/Interpreter.cpp Tue Jul 10 02:11:13 2012 -0700
8.3 @@ -119,6 +119,58 @@
8.4 return true;
8.5 }
8.6
8.7 +static bool
8.8 +InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
8.9 + int *result)
8.10 +{
8.11 + NativeArgs guard;
8.12 +
8.13 + if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
8.14 + return false;
8.15 +
8.16 + intptr_t *cells = guard.args();
8.17 +
8.18 + // params[0] == argc, in ISPE
8.19 + cells[0] = argc;
8.20 +
8.21 + // Pass the formal arguments.
8.22 + Local<Type> type(zone, native->type());
8.23 + Local<Type> param(zone);
8.24 + for (unsigned i = 0; i < type->parameters()->length(); i++) {
8.25 + param = type->parameterAt(i);
8.26 +
8.27 + // For floats, we rely on the aliasing of |i32| and |f|.
8.28 + LocalSlot &arg = args[-int(i) - 1];
8.29 + if (param->isInt32() || param->isFloat()) {
8.30 + cells[i + 1] = arg.i32;
8.31 + } else if (param->isReference()) {
8.32 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
8.33 + } else {
8.34 + assert(param->isArray());
8.35 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
8.36 + }
8.37 + }
8.38 +
8.39 + // For variadic arguments, the compiler left either arrays or references.
8.40 + for (unsigned i = type->parameters()->length(); i < argc; i++) {
8.41 + LocalSlot &arg = args[-int(i) - 1];
8.42 +
8.43 + if (arg.obj->is(MapKind_Reference)) {
8.44 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
8.45 + } else {
8.46 + assert(arg.obj->is(MapKind_Array));
8.47 + cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
8.48 + }
8.49 + }
8.50 +
8.51 + typedef intptr_t (*INVOKE)(void *, intptr_t *);
8.52 + INVOKE invoke = (INVOKE)native->function();
8.53 + *result = invoke(identity, cells);
8.54 +
8.55 + // :TODO: detect errors.
8.56 + return true;
8.57 +}
8.58 +
8.59 bool
8.60 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
8.61 {
8.62 @@ -637,6 +689,30 @@
8.63 break;
8.64 }
8.65
8.66 +case OP_CALLNATIVE:
8.67 +{
8.68 + unsigned index = READ_UINT32(top.pc);
8.69 + unsigned argc = READ_UINT32(top.pc + 4);
8.70 +
8.71 + Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
8.72 + if (!native->function()) {
8.73 + // :TODO: error
8.74 + assert(false);
8.75 + return false;
8.76 + }
8.77 +
8.78 + int result;
8.79 + void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
8.80 + if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result)) {
8.81 + assert(false);
8.82 + return false;
8.83 + }
8.84 +
8.85 + top.sp -= argc;
8.86 + PUSH_I32(top, result);
8.87 + break;
8.88 +}
8.89 +
8.90 default:
8.91 assert(false);
8.92 return false;
9.1 --- a/jitcraft/Messages.tbl Mon Jul 09 22:25:52 2012 -0700
9.2 +++ b/jitcraft/Messages.tbl Tue Jul 10 02:11:13 2012 -0700
9.3 @@ -46,4 +46,7 @@
9.4 MSG(ForwardDeclareMismatches, SyntaxError, "declaration does not match original forward signature")
9.5 MSG(ArrayCantBeReference, SyntaxError, "a parameter cannot be both an array and a reference")
9.6 MSG(ArraySizeMustBeConstant, SyntaxError, "array size must be a constant integer")
9.7 -MSG(ReferenceIsConstant, SyntaxError, "cannot assign to a constant lvalue")
9.8 \ No newline at end of file
9.9 +MSG(ReferenceIsConstant, SyntaxError, "cannot assign to a constant lvalue")
9.10 +MSG(MultiArrayInNative, SyntaxError, "multidimensional arrays cannot be passed to natives")
9.11 +MSG(InvalidVarArgs, SyntaxError, "varargs cannot be const or ref")
9.12 +MSG(VarArgsOutsideNative, SyntaxError, "variadic arguments can only be specified on natives")
10.1 --- a/jitcraft/Modules.cpp Mon Jul 09 22:25:52 2012 -0700
10.2 +++ b/jitcraft/Modules.cpp Tue Jul 10 02:11:13 2012 -0700
10.3 @@ -35,5 +35,7 @@
10.4
10.5 module->functions_ = functions;
10.6 module->publics_ = NULL;
10.7 + module->natives_ = NULL;
10.8 + module->nativeIdentity_ = NULL;
10.9 return module;
10.10 }
11.1 --- a/jitcraft/Modules.h Mon Jul 09 22:25:52 2012 -0700
11.2 +++ b/jitcraft/Modules.h Tue Jul 10 02:11:13 2012 -0700
11.3 @@ -28,6 +28,8 @@
11.4 {
11.5 Barriered<FixedArray> functions_;
11.6 Barriered<FixedArray> publics_;
11.7 + Barriered<FixedArray> natives_;
11.8 + void *nativeIdentity_;
11.9
11.10 public:
11.11 static Module *New(Zone *zone, unsigned nfunctions);
11.12 @@ -44,9 +46,23 @@
11.13 FixedArray *publics() {
11.14 return publics_;
11.15 }
11.16 + FixedArray *natives() {
11.17 + return natives_;
11.18 + }
11.19 +
11.20 void setPublics(Handle<FixedArray> publics) {
11.21 publics_ = publics;
11.22 }
11.23 + void setNatives(Handle<FixedArray> natives) {
11.24 + natives_ = natives;
11.25 + }
11.26 +
11.27 + void *nativeIdentity() {
11.28 + return nativeIdentity_;
11.29 + }
11.30 + void setNativeIdentity(void *identity) {
11.31 + nativeIdentity_ = identity;
11.32 + }
11.33
11.34 // Begin GC Descriptor.
11.35 static inline size_t offsetOfFunctions() {
11.36 @@ -55,6 +71,9 @@
11.37 static inline size_t offsetOfPublics() {
11.38 return offsetof(Module, publics_);
11.39 }
11.40 + static inline size_t offsetOfNatives() {
11.41 + return offsetof(Module, natives_);
11.42 + }
11.43 // End GC Descriptor.
11.44
11.45 static inline Module *cast(Object *obj) {
12.1 --- a/jitcraft/NameBinding.cpp Mon Jul 09 22:25:52 2012 -0700
12.2 +++ b/jitcraft/NameBinding.cpp Tue Jul 10 02:11:13 2012 -0700
12.3 @@ -32,7 +32,8 @@
12.4 NamedFunction::NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos,
12.5 TokenKind token)
12.6 : BoundName(scope, name, pos),
12.7 - token_(token)
12.8 + token_(token),
12.9 + isVariadicNative_(false)
12.10 {
12.11 }
12.12
13.1 --- a/jitcraft/NameBinding.h Mon Jul 09 22:25:52 2012 -0700
13.2 +++ b/jitcraft/NameBinding.h Tue Jul 10 02:11:13 2012 -0700
13.3 @@ -87,6 +87,7 @@
13.4 unsigned slot_;
13.5 TokenKind token_;
13.6 ScopedRoot<Type> forwardType_;
13.7 + bool isVariadicNative_;
13.8
13.9 public:
13.10 NamedFunction(Scope *scope, Handle<String> name, const SourcePosition &pos, TokenKind token);
13.11 @@ -103,6 +104,9 @@
13.12 bool isPublic() const {
13.13 return token_ == TOK_PUBLIC;
13.14 }
13.15 + bool isNative() const {
13.16 + return token_ == TOK_NATIVE;
13.17 + }
13.18 void setForwardType(Handle<Type> type) {
13.19 forwardType_ = type;
13.20 }
13.21 @@ -113,6 +117,14 @@
13.22 token_ = TOK_PUBLIC;
13.23 pos_ = at;
13.24 }
13.25 + void markNativeVariadic() {
13.26 + assert(token_ == TOK_NATIVE);
13.27 + isVariadicNative_ = true;
13.28 + }
13.29 + bool isNativeVariadic() {
13.30 + assert(token_ == TOK_NATIVE);
13.31 + return isVariadicNative_;
13.32 + }
13.33 unsigned slot() const {
13.34 return slot_;
13.35 }
14.1 --- a/jitcraft/ObjectVisitor.h Mon Jul 09 22:25:52 2012 -0700
14.2 +++ b/jitcraft/ObjectVisitor.h Tue Jul 10 02:11:13 2012 -0700
14.3 @@ -79,15 +79,23 @@
14.4 size_t iterateModule(Object *obj) {
14.5 visitField(obj, Module::offsetOfFunctions());
14.6 visitField(obj, Module::offsetOfPublics());
14.7 + visitField(obj, Module::offsetOfNatives());
14.8 return sizeof(Module);
14.9 }
14.10
14.11 size_t iterateFunction(Object *obj) {
14.12 visitField(obj, Function::offsetOfCode());
14.13 visitField(obj, Function::offsetOfType());
14.14 + visitField(obj, Function::offsetOfName());
14.15 return sizeof(Function);
14.16 }
14.17
14.18 + size_t iterateNative(Object *obj) {
14.19 + visitField(obj, Native::offsetOfType());
14.20 + visitField(obj, Native::offsetOfName());
14.21 + return sizeof(Native);
14.22 + }
14.23 +
14.24 size_t iterateString(Object *obj) {
14.25 return String::SizeFor(String::cast(obj)->length());
14.26 }
14.27 @@ -143,6 +151,9 @@
14.28 case MapKind_Array:
14.29 return Align(iterateArray(Array::cast(obj), ArrayMap::cast(map)), kObjectAlignment);
14.30
14.31 + case MapKind_Native:
14.32 + return iterateNative(obj);
14.33 +
14.34 case MapKind_MetaArray:
14.35 return iterateArrayMap(ArrayMap::cast(obj));
14.36
14.37 @@ -181,6 +192,9 @@
14.38 case MapKind_String:
14.39 return String::SizeFor(String::cast(obj)->length());
14.40
14.41 + case MapKind_Native:
14.42 + return sizeof(Native);
14.43 +
14.44 case MapKind_Array:
14.45 return Align(Array::SizeOf(Array::cast(obj)), kObjectAlignment);
14.46
15.1 --- a/jitcraft/Objects.h Mon Jul 09 22:25:52 2012 -0700
15.2 +++ b/jitcraft/Objects.h Tue Jul 10 02:11:13 2012 -0700
15.3 @@ -46,6 +46,7 @@
15.4 MapKind_Module,
15.5 MapKind_Function,
15.6 MapKind_String,
15.7 + MapKind_Native,
15.8 MapKind_FreeRegion, // Special map denoting freed space.
15.9
15.10 // Used to represent Arrays. This does not have a canonical map.
16.1 --- a/jitcraft/Opcodes.cpp Mon Jul 09 22:25:52 2012 -0700
16.2 +++ b/jitcraft/Opcodes.cpp Tue Jul 10 02:11:13 2012 -0700
16.3 @@ -209,6 +209,10 @@
16.4 fprintf(fp, "%u", READ_UINT32(pc));
16.5 break;
16.6
16.7 + case OP_CALLNATIVE:
16.8 + fprintf(fp, "%u %u", READ_UINT32(pc), READ_UINT32(pc + 4));
16.9 + break;
16.10 +
16.11 default:
16.12 // Unknown opcode!
16.13 assert(false);
17.1 --- a/jitcraft/Opcodes.tbl Mon Jul 09 22:25:52 2012 -0700
17.2 +++ b/jitcraft/Opcodes.tbl Tue Jul 10 02:11:13 2012 -0700
17.3 @@ -184,3 +184,14 @@
17.4 // push(sp[-n])
17.5 OPDEF(OP_PICK2, 60, "pick2", 1, 2, 3)
17.6 OPDEF(OP_PICK3, 61, "pick3", 1, 3, 4)
17.7 +
17.8 +// Calls a native function. During the course of calling a native, arguments
17.9 +// on the stack are re-pushed to match the cell-based native calling
17.10 +// convention expected by ISourcePawnEngine.
17.11 +//
17.12 +// Unlike the normal CALL instruction, natives take truly variadic arguments
17.13 +// and so we must specify the number of arguments. The format is:
17.14 +//
17.15 +// [u8 Opcode] [u32 Index] [u32 ArgCount]
17.16 +//
17.17 +OPDEF(OP_CALLNATIVE, 62, "callnative", 9, -1, 1)
17.18 \ No newline at end of file
18.1 --- a/jitcraft/Parser.cpp Mon Jul 09 22:25:52 2012 -0700
18.2 +++ b/jitcraft/Parser.cpp Tue Jul 10 02:11:13 2012 -0700
18.3 @@ -902,6 +902,21 @@
18.4 if (matchName(tag.ref(), TOK_LABEL) && !tag)
18.5 return NULL;
18.6
18.7 + if (match(TOK_ELLIPSES)) {
18.8 + if (isConst || ref) {
18.9 + cc_.reportError(begin, Message_InvalidVarArgs);
18.10 + return NULL;
18.11 + }
18.12 +
18.13 + if (token != TOK_NATIVE) {
18.14 + cc_.reportError(begin, Message_VarArgsOutsideNative);
18.15 + return NULL;
18.16 + }
18.17 +
18.18 + fun->markNativeVariadic();
18.19 + break;
18.20 + }
18.21 +
18.22 Local<String> name(zone_, expectName());
18.23 if (!name)
18.24 return NULL;
18.25 @@ -944,7 +959,7 @@
18.26 }
18.27
18.28 Statement *body = NULL;
18.29 - if (token != TOK_FORWARD) {
18.30 + if (token != TOK_FORWARD && token != TOK_NATIVE) {
18.31 body = block();
18.32 if (!body)
18.33 return NULL;
18.34 @@ -979,11 +994,12 @@
18.35
18.36 case TOK_FORWARD:
18.37 case TOK_PUBLIC:
18.38 + case TOK_NATIVE:
18.39 {
18.40 TokenKind kind = scanner_.scan();
18.41 if ((statement = function(kind)) == NULL)
18.42 return NULL;
18.43 - if (kind == TOK_FORWARD && !matchSemicolon())
18.44 + if ((kind == TOK_FORWARD || kind == TOK_NATIVE) && !matchSemicolon())
18.45 return NULL;
18.46 break;
18.47 }
19.1 --- a/jitcraft/Reference.h Mon Jul 09 22:25:52 2012 -0700
19.2 +++ b/jitcraft/Reference.h Tue Jul 10 02:11:13 2012 -0700
19.3 @@ -51,6 +51,11 @@
19.4 *reinterpret_cast<float *>(location_) = f;
19.5 }
19.6
19.7 + // WARNING! This should only be for Native calls.
19.8 + void *location() {
19.9 + return location_;
19.10 + }
19.11 +
19.12 // Begin GC Descriptor.
19.13 static inline size_t offsetOfBase() {
19.14 return offsetof(Reference, base_);
20.1 --- a/jitcraft/Scanner.cpp Mon Jul 09 22:25:52 2012 -0700
20.2 +++ b/jitcraft/Scanner.cpp Tue Jul 10 02:11:13 2012 -0700
20.3 @@ -371,6 +371,8 @@
20.4 return TOK_PUBLIC;
20.5 if (literal_ == "const")
20.6 return TOK_CONST;
20.7 + if (literal_ == "native")
20.8 + return TOK_NATIVE;
20.9 return (c == ':') ? TOK_LABEL : TOK_NAME;
20.10 }
20.11
20.12 @@ -415,6 +417,16 @@
20.13 case '[': return TOK_LBRACKET;
20.14 case ']': return TOK_RBRACKET;
20.15
20.16 + case '.':
20.17 + c = getChar();
20.18 + if (c == '.') {
20.19 + c = getChar();
20.20 + if (c == '.')
20.21 + return TOK_ELLIPSES;
20.22 + }
20.23 + cc_.reportError(begin_, Message_UnexpectedCharacter, c, uint8(c));
20.24 + return TOK_ERROR;
20.25 +
20.26 case '*':
20.27 c = getChar();
20.28 if (c == '=')
21.1 --- a/jitcraft/Scopes.cpp Mon Jul 09 22:25:52 2012 -0700
21.2 +++ b/jitcraft/Scopes.cpp Tue Jul 10 02:11:13 2012 -0700
21.3 @@ -29,6 +29,7 @@
21.4 locals_(0),
21.5 maxContainedLocals_(0),
21.6 numFunctions_(0),
21.7 + numNatives_(0),
21.8 lifoSlot_(NULL),
21.9 kind_(kind),
21.10 enclosing_(enclosing)
21.11 @@ -155,7 +156,10 @@
21.12
21.13 if (name->kind() == BoundName::FUNCTION) {
21.14 NamedFunction *fun = name->toNamedFunction();
21.15 - fun->allocate(numFunctions_++);
21.16 + if (fun->isNative())
21.17 + fun->allocate(numNatives_++);
21.18 + else
21.19 + fun->allocate(numFunctions_++);
21.20 }
21.21 }
21.22 }
22.1 --- a/jitcraft/Scopes.h Mon Jul 09 22:25:52 2012 -0700
22.2 +++ b/jitcraft/Scopes.h Tue Jul 10 02:11:13 2012 -0700
22.3 @@ -33,6 +33,7 @@
22.4 unsigned locals_;
22.5 unsigned maxContainedLocals_;
22.6 unsigned numFunctions_;
22.7 + unsigned numNatives_;
22.8 Variable *lifoSlot_;
22.9
22.10 bool empty() const {
22.11 @@ -66,6 +67,9 @@
22.12 unsigned numFunctions() const {
22.13 return numFunctions_;
22.14 }
22.15 + unsigned numNatives() const {
22.16 + return numNatives_;
22.17 + }
22.18 unsigned numArguments() const {
22.19 return parameters_.length();
22.20 }
23.1 --- a/jitcraft/SemanticAnalysis.cpp Mon Jul 09 22:25:52 2012 -0700
23.2 +++ b/jitcraft/SemanticAnalysis.cpp Tue Jul 10 02:11:13 2012 -0700
23.3 @@ -546,11 +546,6 @@
23.4 if (!type)
23.5 return false;
23.6
23.7 - if (type->primitive() == PrimitiveType_Char) {
23.8 - cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.9 - return false;
23.10 - }
23.11 -
23.12 if (parameter->reference()) {
23.13 if (parameter->dimensions()) {
23.14 cc_.reportError(parameter->variable()->pos(), Message_ArrayCantBeReference);
23.15 @@ -562,7 +557,12 @@
23.16 return false;
23.17 } else if (parameter->dimensions()) {
23.18 if (parameter->dimensions()->length() > Type::MAX_UNSAFE_ARRAY_DEPTH) {
23.19 - cc_.reportError(node->pos(), Message_MaximumArrayDepth);
23.20 + cc_.reportError(parameter->variable()->pos(), Message_MaximumArrayDepth);
23.21 + return false;
23.22 + }
23.23 +
23.24 + if (node->fun()->isNative() && parameter->dimensions()->length() > 1) {
23.25 + cc_.reportError(parameter->variable()->pos(), Message_MultiArrayInNative);
23.26 return false;
23.27 }
23.28
23.29 @@ -586,6 +586,13 @@
23.30 }
23.31 }
23.32
23.33 + if ((type->isPrimitive() && type->primitive() == PrimitiveType_Char) ||
23.34 + (type->isReference() && type->contained()->primitive() == PrimitiveType_Char))
23.35 + {
23.36 + cc_.reportError(node->pos(), Message_CannotDeclareStringCell);
23.37 + return false;
23.38 + }
23.39 +
23.40 args->set(zone_, i, type);
23.41 parameter->variable()->setType(type);
23.42 }
23.43 @@ -594,7 +601,11 @@
23.44 if (!returnType)
23.45 return false;
23.46
23.47 - Local<Type> funtype(zone_, zone_->types()->newFunction(returnType, args));
23.48 + Local<Type> funtype(zone_);
23.49 + if (node->fun()->isNative())
23.50 + funtype = zone_->types()->newNative(returnType, args, node->fun()->isNativeVariadic());
23.51 + else
23.52 + funtype = zone_->types()->newFunction(returnType, args);
23.53 if (!funtype)
23.54 return false;
23.55
23.56 @@ -737,8 +748,13 @@
23.57 return;
23.58 }
23.59 if (node->arguments()->length() != type->parameters()->length()) {
23.60 - cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
23.61 - return;
23.62 + if (!type->isNative() ||
23.63 + !type->isNativeVariadic() ||
23.64 + node->arguments()->length() < type->parameters()->length())
23.65 + {
23.66 + cc_.reportError(node->pos(), Message_ArgumentCountMismatch);
23.67 + return;
23.68 + }
23.69 }
23.70
23.71 // Currently, only calls from a NameProxy are possible.
23.72 @@ -761,13 +777,23 @@
23.73 if (expression->isIndexExpression())
23.74 given = given->contained();
23.75
23.76 - Local<Type> actual(zone_, type->parameterAt(i));
23.77 - if (!typeCheckParameter(expression, given, actual))
23.78 - return;
23.79 + bool mustComputeReference;
23.80 + if (i >= type->parameters()->length()) {
23.81 + // Special handling for natives. Arguments past the formal must
23.82 + // always have references computed. However, arrays are already
23.83 + // references for natives.
23.84 + assert(type->isNative() && type->isNativeVariadic());
23.85 + mustComputeReference = !given->isReference() && !given->isArray();
23.86 + } else {
23.87 + Local<Type> actual(zone_, type->parameterAt(i));
23.88 + if (!typeCheckParameter(expression, given, actual))
23.89 + return;
23.90 + mustComputeReference = actual->isReference() && !given->isReference();
23.91 + }
23.92
23.93 // If the actual is a reference, and the given is not, we'll need to
23.94 // compute a reference, which may be allocated on the stack.
23.95 - if (actual->isReference() && !given->isReference())
23.96 + if (mustComputeReference)
23.97 scope_->setUsesLifoHeap();
23.98 }
23.99
24.1 --- a/jitcraft/Stack.cpp Mon Jul 09 22:25:52 2012 -0700
24.2 +++ b/jitcraft/Stack.cpp Tue Jul 10 02:11:13 2012 -0700
24.3 @@ -54,6 +54,11 @@
24.4 stack_->popInvokeFrame(*this);
24.5 }
24.6
24.7 +NativeArgs::~NativeArgs()
24.8 +{
24.9 + stack_->popNativeFrame(*this);
24.10 +}
24.11 +
24.12 static inline size_t
24.13 SizeForCodeFrame(Code *code)
24.14 {
24.15 @@ -86,6 +91,30 @@
24.16 return true;
24.17 }
24.18
24.19 +bool
24.20 +Stack::pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc)
24.21 +{
24.22 + size_t nbytes = sizeof(intptr_t) * argc + sizeof(Frame);
24.23 + if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
24.24 + assert(false);
24.25 + return false;
24.26 + }
24.27 +
24.28 + memset(top_.sp, 0, sizeof(intptr_t) * argc);
24.29 + args.argsBase_ = top_.sp;
24.30 + args.stack_ = this;
24.31 + top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<intptr_t *>(top_.sp) + argc);
24.32 +
24.33 + Frame *frame = reinterpret_cast<Frame *>(top_.sp);
24.34 + new (frame) Frame(top_.fp, top_.pc, native, ZONE()->heap().lifoPosition());
24.35 +
24.36 + top_.pc = NULL;
24.37 + top_.sp = reinterpret_cast<LocalSlot *>(frame + 1);
24.38 + top_.fp = frame;
24.39 +
24.40 + return true;
24.41 +}
24.42 +
24.43 Frame *
24.44 Stack::pushInlineFrame(Handle<Function> fun)
24.45 {
24.46 @@ -138,14 +167,24 @@
24.47 }
24.48
24.49 void
24.50 +Stack::popNativeFrame(NativeArgs &args)
24.51 +{
24.52 + ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
24.53 +
24.54 + top_.pc = top_.fp->prevpc();
24.55 + top_.sp = args.argsBase_;
24.56 + top_.fp = top_.fp->prev();
24.57 +}
24.58 +
24.59 +void
24.60 Frame::accept(VirtualObjectVisitor *visitor)
24.61 {
24.62 - visitor->visit(reinterpret_cast<Object **>(&fun_));
24.63 + visitor->visit(reinterpret_cast<Object **>(&callee_));
24.64 visitor->visit(reinterpret_cast<Object **>(&code_));
24.65 }
24.66
24.67 static void
24.68 -TraceFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
24.69 +TraceFunctionFrame(VirtualObjectVisitor *visitor, Frame *fp, LocalSlot *sp, bytecode *pc)
24.70 {
24.71 Code *code = fp->code();
24.72 LocalSlot *slots = fp->locals();
24.73 @@ -190,7 +229,10 @@
24.74 bytecode *pc = top_.pc;
24.75
24.76 for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
24.77 - TraceFrame(visitor, frame, sp, pc);
24.78 + if (!frame->isNative())
24.79 + TraceFunctionFrame(visitor, frame, sp, pc);
24.80 + frame->accept(visitor);
24.81 +
24.82 sp = reinterpret_cast<LocalSlot *>(frame);
24.83 pc = frame->prevpc();
24.84 }
25.1 --- a/jitcraft/Stack.h Mon Jul 09 22:25:52 2012 -0700
25.2 +++ b/jitcraft/Stack.h Tue Jul 10 02:11:13 2012 -0700
25.3 @@ -56,7 +56,11 @@
25.4
25.5 Frame *prev_;
25.6 bytecode *prevpc_;
25.7 - Function *fun_;
25.8 + union {
25.9 + Function *fun_;
25.10 + Native *native_;
25.11 + Object *callee_;
25.12 + };
25.13 Code *code_;
25.14 Address lifoPosition_;
25.15
25.16 @@ -70,6 +74,15 @@
25.17 {
25.18 }
25.19
25.20 + Frame(Frame *prev, bytecode *prevpc, Native *native, Address lifoPosition)
25.21 + : prev_(prev),
25.22 + prevpc_(prevpc),
25.23 + native_(native),
25.24 + code_(NULL),
25.25 + lifoPosition_(lifoPosition)
25.26 + {
25.27 + }
25.28 +
25.29 LocalSlot *locals() {
25.30 return reinterpret_cast<LocalSlot *>(this + 1);
25.31 }
25.32 @@ -77,13 +90,17 @@
25.33 return locals() + code_->nlocals();
25.34 }
25.35 Function *fun() const {
25.36 - assert(fun_);
25.37 + assert(fun_ && callee_->is(MapKind_Function));
25.38 return fun_;
25.39 }
25.40 Function *maybeFun() const {
25.41 - return fun_;
25.42 + return (fun_ && callee_->is(MapKind_Function)) ? fun_ : NULL;
25.43 + }
25.44 + bool isNative() const {
25.45 + return callee_ && callee_->is(MapKind_Native);
25.46 }
25.47 Code *code() const {
25.48 + assert(code_);
25.49 return code_;
25.50 }
25.51 Frame *prev() const {
25.52 @@ -127,9 +144,32 @@
25.53 }
25.54 };
25.55
25.56 +// RAII object for calling a native from C++.
25.57 +class NativeArgs
25.58 +{
25.59 + friend class Stack;
25.60 +
25.61 + Stack *stack_;
25.62 + LocalSlot *argsBase_;
25.63 +
25.64 + public:
25.65 + NativeArgs()
25.66 + : stack_(NULL),
25.67 + argsBase_(NULL)
25.68 + {
25.69 + }
25.70 +
25.71 + ~NativeArgs();
25.72 +
25.73 + intptr_t *args() {
25.74 + return reinterpret_cast<int *>(argsBase_);
25.75 + }
25.76 +};
25.77 +
25.78 class Stack
25.79 {
25.80 friend class InvokeArgs;
25.81 + friend class NativeArgs;
25.82
25.83 private:
25.84 static const size_t STACK_SIZE = 1024 * 1024;
25.85 @@ -145,6 +185,7 @@
25.86 Frame *popInlineFrame();
25.87
25.88 bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
25.89 + bool pushNativeFrame(Handle<Native> native, NativeArgs &args, unsigned argc);
25.90
25.91 Top *top() {
25.92 return &top_;
25.93 @@ -154,6 +195,7 @@
25.94
25.95 private:
25.96 void popInvokeFrame(InvokeArgs &args);
25.97 + void popNativeFrame(NativeArgs &args);
25.98
25.99 private:
25.100 char *buffer_;
26.1 --- a/jitcraft/Token.h Mon Jul 09 22:25:52 2012 -0700
26.2 +++ b/jitcraft/Token.h Tue Jul 10 02:11:13 2012 -0700
26.3 @@ -57,6 +57,8 @@
26.4 _(FORWARD, "<forward>") \
26.5 _(PUBLIC, "<public>") \
26.6 _(CONST, "<const>") \
26.7 + _(NATIVE, "<native>") \
26.8 + _(ELLIPSES, "...") \
26.9 _(PLUS, "+") \
26.10 _(MINUS, "-") \
26.11 _(STAR, "*") \
27.1 --- a/jitcraft/TypeManager.cpp Mon Jul 09 22:25:52 2012 -0700
27.2 +++ b/jitcraft/TypeManager.cpp Tue Jul 10 02:11:13 2012 -0700
27.3 @@ -97,6 +97,13 @@
27.4 return Type::NewFunction(zone_, returnType, args);
27.5 }
27.6
27.7 +Type *
27.8 +TypeManager::newNative(Handle<Type> returnType, Handle<FixedArray> args, bool variadic)
27.9 +{
27.10 + // :TODO: cache this.
27.11 + return Type::NewNative(zone_, returnType, args, variadic);
27.12 +}
27.13 +
27.14 void
27.15 TypeManager::accept(VirtualObjectVisitor *visitor)
27.16 {
28.1 --- a/jitcraft/TypeManager.h Mon Jul 09 22:25:52 2012 -0700
28.2 +++ b/jitcraft/TypeManager.h Tue Jul 10 02:11:13 2012 -0700
28.3 @@ -47,6 +47,7 @@
28.4 Type *getReference(Handle<Type> type, bool isConst);
28.5 Type *unsafeArray(Handle<Type> contained, int elements, bool isConst);
28.6 Type *newFunction(Handle<Type> returnType, Handle<FixedArray> args);
28.7 + Type *newNative(Handle<Type> returnType, Handle<FixedArray> args, bool variadic);
28.8
28.9 void accept(VirtualObjectVisitor *visitor);
28.10 };
29.1 --- a/jitcraft/Types.cpp Mon Jul 09 22:25:52 2012 -0700
29.2 +++ b/jitcraft/Types.cpp Tue Jul 10 02:11:13 2012 -0700
29.3 @@ -111,6 +111,21 @@
29.4 return type;
29.5 }
29.6
29.7 +Type *
29.8 +Type::NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters, bool variadic)
29.9 +{
29.10 + Local<Type> type(zone, Type::cast(zone->allocate(MapKind_Type, sizeof(Type), Heap::Tenure_Old)));
29.11 + if (!type)
29.12 + return NULL;
29.13 +
29.14 + type->kind_ = NATIVE;
29.15 + type->contained_ = NULL;
29.16 + type->returnType_ = returnType;
29.17 + type->parameters_ = parameters;
29.18 + type->variadicNative_ = variadic;
29.19 + return type;
29.20 +}
29.21 +
29.22 bool
29.23 Type::Compare(Type *left, Type *right)
29.24 {
30.1 --- a/jitcraft/Types.h Mon Jul 09 22:25:52 2012 -0700
30.2 +++ b/jitcraft/Types.h Tue Jul 10 02:11:13 2012 -0700
30.3 @@ -42,7 +42,8 @@
30.4 PRIMITIVE,
30.5 ARRAY,
30.6 REFERENCE,
30.7 - FUNCTION
30.8 + FUNCTION,
30.9 + NATIVE
30.10 };
30.11
30.12 private:
30.13 @@ -59,6 +60,7 @@
30.14 static Type *NewArray(Zone *zone, Handle<Type> contained, int elements, bool isConst);
30.15 static Type *NewReference(Zone *zone, Handle<Type> contained, bool isConst);
30.16 static Type *NewFunction(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters);
30.17 + static Type *NewNative(Zone *zone, Handle<Type> returnType, Handle<FixedArray> parameters, bool isVariadic);
30.18
30.19 static bool Compare(Type *left, Type *right);
30.20
30.21 @@ -77,7 +79,14 @@
30.22 return kind() == REFERENCE;
30.23 }
30.24 bool isFunction() {
30.25 - return kind() == FUNCTION;
30.26 + return kind() == FUNCTION || kind() == NATIVE;
30.27 + }
30.28 + bool isNative() {
30.29 + return kind() == NATIVE;
30.30 + }
30.31 + bool isNativeVariadic() {
30.32 + assert(isNative());
30.33 + return variadicNative_;
30.34 }
30.35 PrimitiveType primitive() {
30.36 assert(isPrimitive());
30.37 @@ -169,6 +178,7 @@
30.38 // Functions only.
30.39 Barriered<Type> returnType_;
30.40 Barriered<FixedArray> parameters_;
30.41 + bool variadicNative_;
30.42 };
30.43
30.44 class BoxedPrimitive
31.1 --- a/jitcraft/Zone.cpp Mon Jul 09 22:25:52 2012 -0700
31.2 +++ b/jitcraft/Zone.cpp Tue Jul 10 02:11:13 2012 -0700
31.3 @@ -78,6 +78,8 @@
31.4 return false;
31.5 if ((maps_[MapKind_String] = allocateMap(MapKind_String, sizeof(Map))) == NULL)
31.6 return false;
31.7 + if ((maps_[MapKind_Native] = allocateMap(MapKind_Native, sizeof(Map))) == NULL)
31.8 + return false;
31.9 if ((maps_[MapKind_FreeRegion] = allocateMap(MapKind_FreeRegion, sizeof(Map))) == NULL)
31.10 return false;
31.11
32.1 --- a/jitcraft/main.cpp Mon Jul 09 22:25:52 2012 -0700
32.2 +++ b/jitcraft/main.cpp Tue Jul 10 02:11:13 2012 -0700
32.3 @@ -61,6 +61,16 @@
32.4 }
32.5 #endif
32.6
32.7 +intptr_t PrintToServer(void *blah, intptr_t *params)
32.8 +{
32.9 + assert(params[0] == 3);
32.10 + const char *fmt = reinterpret_cast<const char *>(params[1]);
32.11 + const char *str = reinterpret_cast<const char *>(params[2]);
32.12 + int *d = reinterpret_cast<int *>(params[3]);
32.13 + printf(fmt, str, *d);
32.14 + return 16;
32.15 +}
32.16 +
32.17 int main(int argc, char **argv)
32.18 {
32.19 if (argc < 2) {
32.20 @@ -76,7 +86,14 @@
32.21 if (!module)
32.22 return 1;
32.23
32.24 -
32.25 + Ke::Local<Ke::Native> native = module->getNative(0);
32.26 + native->bind(reinterpret_cast<void *>(PrintToServer));
32.27 + module->setNativeIdentity(reinterpret_cast<void *>(5));
32.28 +
32.29 + int result;
32.30 + Ke::Local<Ke::Function> fun = module->getPublic(0);
32.31 + if (Ke::Keima::Invoke(fun, NULL, 0, &result))
32.32 + printf("%d\n", result);
32.33 }
32.34
32.35 Ke::Keima::Shutdown();