Added support for ISourcePawnEngine natives.
authorDavid Anderson <dvander@alliedmods.net>
Tue Jul 10 02:11:13 2012 -0700 (2012-07-10)
changeset 68b40b0e18a918
parent 67 b765a6383849
child 69 dfce0539a77d
Added support for ISourcePawnEngine natives.
include/keima.h
jitcraft/API.cpp
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/BytecodeEmitter.h
jitcraft/Functions.cpp
jitcraft/Functions.h
jitcraft/Interpreter.cpp
jitcraft/Messages.tbl
jitcraft/Modules.cpp
jitcraft/Modules.h
jitcraft/NameBinding.cpp
jitcraft/NameBinding.h
jitcraft/ObjectVisitor.h
jitcraft/Objects.h
jitcraft/Opcodes.cpp
jitcraft/Opcodes.tbl
jitcraft/Parser.cpp
jitcraft/Reference.h
jitcraft/Scanner.cpp
jitcraft/Scopes.cpp
jitcraft/Scopes.h
jitcraft/SemanticAnalysis.cpp
jitcraft/Stack.cpp
jitcraft/Stack.h
jitcraft/Token.h
jitcraft/TypeManager.cpp
jitcraft/TypeManager.h
jitcraft/Types.cpp
jitcraft/Types.h
jitcraft/Zone.cpp
jitcraft/main.cpp
     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 &param, 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();