Added ISPE-oriented API for invoking functions.
authorDavid Anderson <dvander@alliedmods.net>
Mon Jul 09 01:22:03 2012 -0700 (2012-07-09)
changeset 657c942b5adebc
parent 64 11c81eb30246
child 66 cbba1997dc71
Added ISPE-oriented API for invoking functions.
include/keima.h
jitcraft/API.cpp
jitcraft/Array.cpp
jitcraft/Array.h
jitcraft/BytecodeCompiler.cpp
jitcraft/BytecodeCompiler.h
jitcraft/GlobalRoots.cpp
jitcraft/Interpreter.cpp
jitcraft/Stack.cpp
jitcraft/Stack.h
jitcraft/Zone.cpp
jitcraft/Zone.h
     1.1 --- a/include/keima.h	Sun Jul 08 17:57:44 2012 -0700
     1.2 +++ b/include/keima.h	Mon Jul 09 01:22:03 2012 -0700
     1.3 @@ -18,6 +18,7 @@
     1.4  #ifndef _include_sourcepawn3_api_h_
     1.5  #define _include_sourcepawn3_api_h_
     1.6  
     1.7 +#include <assert.h>
     1.8  #include <stddef.h>
     1.9  #include "../include/keima_util.h"
    1.10  
    1.11 @@ -78,7 +79,7 @@
    1.12          return !!obj_;
    1.13      }
    1.14  
    1.15 -  private:
    1.16 +  protected:
    1.17      T *obj_;
    1.18  };
    1.19  
    1.20 @@ -116,22 +117,21 @@
    1.21  class Root : public Handle<T>
    1.22  {
    1.23    public:
    1.24 -    Root()
    1.25 +    Root<T>()
    1.26        : Handle<T>()
    1.27      {
    1.28      }
    1.29  
    1.30 -    template <typename S> Root(const Root<S> &other)
    1.31 +    Root<T>(const Root<T> &other)
    1.32        : Handle<T>(reinterpret_cast<T *>(*other))
    1.33      {
    1.34 -        typeCheck<S>();
    1.35          incref();
    1.36      }
    1.37  
    1.38      explicit Root(ke::HeapRoot *obj)
    1.39        : Handle<T>(reinterpret_cast<T *>(obj))
    1.40      {
    1.41 -        incref();
    1.42 +		incref();
    1.43      }
    1.44  
    1.45      static inline Root<T> New(Handle<T> other);
    1.46 @@ -140,10 +140,10 @@
    1.47          decref();
    1.48      }
    1.49  
    1.50 -    template <typename S>
    1.51 -    Root<T> &operator =(Root<S> other) {
    1.52 +    Root<T> &operator =(const Root<T> &other) {
    1.53          decref();
    1.54 -        new (this) Root<T>(other);
    1.55 +        obj_ = other.obj_;
    1.56 +		incref();
    1.57          return *this;
    1.58      }
    1.59  
    1.60 @@ -185,6 +185,8 @@
    1.61      void operator delete(void *, size_t);
    1.62  };
    1.63  
    1.64 +class Parameter;
    1.65 +
    1.66  // A string is an immutable UTF8 buffer.
    1.67  class KE_EXPORT String
    1.68  {
    1.69 @@ -247,6 +249,19 @@
    1.70       * Clear any pending exception.
    1.71       */
    1.72      static void ClearPendingException();
    1.73 +
    1.74 +    /*
    1.75 +     * Type checks a function against given parameters.
    1.76 +     */
    1.77 +    static bool CheckInvokeTypes(Handle<Function> fun, const Parameter *params, unsigned nparams);
    1.78 +
    1.79 +    /*
    1.80 +     * Executes a function with the given parameters. This interface is
    1.81 +     * intended for compatibility with SourceMod's ISourcePawnEngine2 and
    1.82 +     * should not be used otherwise, since it is intended to support only
    1.83 +     * a small subset of the core language.
    1.84 +     */
    1.85 +    static bool Invoke(Handle<Function> fun, const Parameter *params, unsigned nparams, int *result);
    1.86  };
    1.87  
    1.88  /*
    1.89 @@ -262,6 +277,103 @@
    1.90      }
    1.91  };
    1.92  
    1.93 +// Argument-passing interface for Invoke().
    1.94 +class Parameter
    1.95 +{
    1.96 +  public:
    1.97 +    enum Type {
    1.98 +        Int,
    1.99 +        Float,
   1.100 +        IntRef,
   1.101 +        FloatRef,
   1.102 +        Array,
   1.103 +        CharArray
   1.104 +    };
   1.105 +
   1.106 +    Parameter()
   1.107 +    {
   1.108 +    }
   1.109 +
   1.110 +    Parameter(int i)
   1.111 +      : type_(Int)
   1.112 +    {
   1.113 +        u.i = i;
   1.114 +    }
   1.115 +
   1.116 +    Parameter(int *i, bool writeback)
   1.117 +      : type_(IntRef),
   1.118 +        writeback_(writeback)
   1.119 +    {
   1.120 +        u.ip = i;
   1.121 +    }
   1.122 +
   1.123 +    Parameter(float f)
   1.124 +      : type_(Float)
   1.125 +    {
   1.126 +        u.f = f;
   1.127 +    }
   1.128 +
   1.129 +    Parameter(float *f, bool writeback)
   1.130 +      : type_(FloatRef),
   1.131 +        writeback_(writeback)
   1.132 +    {
   1.133 +        u.fp = f;
   1.134 +    }
   1.135 +
   1.136 +    Parameter(Type type, void *buffer, size_t length, bool writeback)
   1.137 +      : type_(type),
   1.138 +        writeback_(writeback),
   1.139 +        length_(length)
   1.140 +    {
   1.141 +        assert(type == Array || type == CharArray);
   1.142 +        u.buffer = buffer;
   1.143 +    }
   1.144 +
   1.145 +    Type type() const {
   1.146 +        return type_;
   1.147 +    }
   1.148 +
   1.149 +    int i32() const {
   1.150 +        assert(type() == Int);
   1.151 +        return u.i;
   1.152 +    }
   1.153 +    float f() const {
   1.154 +        assert(type() == Float);
   1.155 +        return u.f;
   1.156 +    }
   1.157 +    int *i32p() const {
   1.158 +        assert(type() == IntRef);
   1.159 +        return u.ip;
   1.160 +    }
   1.161 +    float *fp() const {
   1.162 +        assert(type() == FloatRef);
   1.163 +        return u.fp;
   1.164 +    }
   1.165 +    bool writeback() const {
   1.166 +        assert(type() >= IntRef && type() <= CharArray);
   1.167 +        return writeback_;
   1.168 +    }
   1.169 +    size_t length() const {
   1.170 +        return length_;
   1.171 +    }
   1.172 +    void *buffer() const {
   1.173 +        assert(type() == Array || type() == CharArray);
   1.174 +        return u.buffer;
   1.175 +    }
   1.176 +
   1.177 +  private:
   1.178 +    Type type_;
   1.179 +    bool writeback_;
   1.180 +    size_t length_;
   1.181 +
   1.182 +    union {
   1.183 +        int i;
   1.184 +        float f;
   1.185 +        int *ip;
   1.186 +        float *fp;
   1.187 +        void *buffer;
   1.188 +    } u;
   1.189 +};
   1.190  
   1.191  /*
   1.192   * Compiles a file and returns a Module.
   1.193 @@ -282,7 +394,7 @@
   1.194  Root<T>::New(Handle<T> other)
   1.195  {
   1.196      if (!other)
   1.197 -        return Root<T>(NULL);
   1.198 +        return Root<T>();
   1.199      ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   1.200      return Root<T>(Internals::NewHeapRoot(ptr));
   1.201  }
     2.1 --- a/jitcraft/API.cpp	Sun Jul 08 17:57:44 2012 -0700
     2.2 +++ b/jitcraft/API.cpp	Mon Jul 09 01:22:03 2012 -0700
     2.3 @@ -26,6 +26,9 @@
     2.4  #include "BytecodeCompiler.h"
     2.5  #include "Modules.h"
     2.6  #include "GlobalRoots.h"
     2.7 +#include "Reference.h"
     2.8 +#include "Array.h"
     2.9 +#include "Interpreter.h"
    2.10  
    2.11  using namespace ke;
    2.12  
    2.13 @@ -203,6 +206,8 @@
    2.14  Ke::Module::numPublics()
    2.15  {
    2.16      ke::Local<ke::Module> module(ke::ZONE(), Open<Ke::Module, ke::Module>(this));
    2.17 +    if (!module->publics())
    2.18 +        return 0;
    2.19      return module->publics()->length();
    2.20  }
    2.21  
    2.22 @@ -234,3 +239,143 @@
    2.23      ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(this));
    2.24      return ToLocal<ke::String, Ke::String>(fun->name());
    2.25  }
    2.26 +
    2.27 +static inline bool
    2.28 +CheckInvokeType(const Ke::Parameter &param, Type *type)
    2.29 +{
    2.30 +    switch (param.type()) {
    2.31 +      case Ke::Parameter::Array:
    2.32 +        return type->isArray() &&
    2.33 +               type->levels() == 1 &&
    2.34 +               type->contained()->isPrimitive() &&
    2.35 +               (type->contained()->primitive() != PrimitiveType_Char);
    2.36 +      case Ke::Parameter::CharArray:
    2.37 +        return type->isCharArray();
    2.38 +      case Ke::Parameter::Float:
    2.39 +        return type->isFloat();
    2.40 +      case Ke::Parameter::FloatRef:
    2.41 +        return type->isReference() && type->contained()->isFloat();
    2.42 +      case Ke::Parameter::Int:
    2.43 +        return type->isInt32();
    2.44 +      case Ke::Parameter::IntRef:
    2.45 +       return type->isReference() && type->contained()->isInt32();
    2.46 +      default:
    2.47 +        return false;
    2.48 +    }
    2.49 +}
    2.50 +
    2.51 +bool
    2.52 +Ke::Keima::CheckInvokeTypes(Ke::Handle<Ke::Function> argFun, const Ke::Parameter *params, unsigned nparams)
    2.53 +{
    2.54 +    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
    2.55 +
    2.56 +    if (fun->nargs() != nparams)
    2.57 +        return false;
    2.58 +
    2.59 +    for (unsigned i = 0; i < nparams; i++) {
    2.60 +        if (!CheckInvokeType(params[i], fun->argType(i)))
    2.61 +            return false;
    2.62 +    }
    2.63 +
    2.64 +    // Functions can only return tagged cells, for ISPE1-compatible Invoke().
    2.65 +    if (!fun->type()->returnType()->isPrimitive() || fun->type()->returnType()->isTraceable())
    2.66 +        return false;
    2.67 +
    2.68 +    return true;
    2.69 +}
    2.70 +
    2.71 +bool
    2.72 +Ke::Keima::Invoke(Handle<Function> argFun, const Parameter *params, unsigned nparams, int *retval)
    2.73 +{
    2.74 +    assert(CheckInvokeTypes(argFun, params, nparams));
    2.75 +
    2.76 +    ke::Local<ke::Function> fun(ke::ZONE(), Open<Ke::Function, ke::Function>(argFun));
    2.77 +
    2.78 +    if (fun->nargs() != nparams) {
    2.79 +        // :TODO: report error
    2.80 +        assert(false);
    2.81 +        return false;
    2.82 +    }
    2.83 +
    2.84 +    ke::InvokeArgs args;
    2.85 +    if (!ke::ZONE()->stack().pushInvokeFrame(fun, args))
    2.86 +        return false;
    2.87 +
    2.88 +    for (unsigned i = 0; i < nparams; i++) {
    2.89 +        ke::LocalSlot &slot = args.arg(i);
    2.90 +        switch (params[i].type()) {
    2.91 +          case Ke::Parameter::Int:
    2.92 +            slot.i32 = params[i].i32();
    2.93 +            break;
    2.94 +
    2.95 +          case Ke::Parameter::Float:
    2.96 +            slot.f = params[i].f();
    2.97 +            break;
    2.98 +
    2.99 +          case Ke::Parameter::IntRef:
   2.100 +            if (params[i].writeback()) {
   2.101 +                slot.ref = Reference::NewStack(ke::ZONE(), params[i].i32p(), Heap::Tenure_Stack);
   2.102 +            } else {
   2.103 +                LocalSlot other;
   2.104 +                other.i32 = *params[i].i32p();
   2.105 +                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   2.106 +            }
   2.107 +            if (!slot.ref)
   2.108 +                return false;
   2.109 +            break;
   2.110 +
   2.111 +          case Ke::Parameter::FloatRef:
   2.112 +            if (params[i].writeback()) {
   2.113 +                slot.ref = Reference::NewStack(ke::ZONE(), params[i].fp(), Heap::Tenure_Stack);
   2.114 +            } else {
   2.115 +                LocalSlot other;
   2.116 +                other.f = *params[i].fp();
   2.117 +                slot.ref = Reference::NewStack(ke::ZONE(), other, Heap::Tenure_Stack);
   2.118 +            }
   2.119 +            if (!slot.ref)
   2.120 +                return false;
   2.121 +            break;
   2.122 +
   2.123 +          case Ke::Parameter::Array:
   2.124 +          {
   2.125 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->genericArrayMap());
   2.126 +            if (params[i].writeback()) {
   2.127 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   2.128 +                                              params[i].buffer(), Heap::Tenure_Stack);
   2.129 +                if (!slot.obj)
   2.130 +                    return false;
   2.131 +            } else {
   2.132 +                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   2.133 +                if (!slot.obj)
   2.134 +                    return false;
   2.135 +                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(int));
   2.136 +            }
   2.137 +            break;
   2.138 +          }
   2.139 +
   2.140 +          case Ke::Parameter::CharArray:
   2.141 +          {
   2.142 +            ke::Local<ke::ArrayMap> map(ke::ZONE(), ke::ZONE()->charArrayMap());
   2.143 +            if (params[i].writeback()) {
   2.144 +                slot.obj = Array::NewExternal(ke::ZONE(), map, params[i].length(),
   2.145 +                                              params[i].buffer(), Heap::Tenure_Stack);
   2.146 +                if (!slot.obj)
   2.147 +                    return false;
   2.148 +            } else {
   2.149 +                Array *array = Array::New(ke::ZONE(), map, params[i].length(), Heap::Tenure_Stack);
   2.150 +                if (!slot.obj)
   2.151 +                    return false;
   2.152 +                memcpy(array->vec(), params[i].buffer(), params[i].length() * sizeof(char));
   2.153 +            }
   2.154 +            break;
   2.155 +          }
   2.156 +        }
   2.157 +    }
   2.158 +
   2.159 +    LocalSlot result;
   2.160 +    if (!Interpret(ke::ZONE(), NULL, &result))
   2.161 +        return false;
   2.162 +
   2.163 +    *retval = result.i32;
   2.164 +    return true;
   2.165 +}
     3.1 --- a/jitcraft/Array.cpp	Sun Jul 08 17:57:44 2012 -0700
     3.2 +++ b/jitcraft/Array.cpp	Mon Jul 09 01:22:03 2012 -0700
     3.3 @@ -63,3 +63,15 @@
     3.4      return array;
     3.5  }
     3.6  
     3.7 +Array *
     3.8 +Array::NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements, void *buffer,
     3.9 +                   Heap::Tenure tenure)
    3.10 +{
    3.11 +    Local<Array> array(zone, Array::cast(zone->allocate(map, sizeof(Array), tenure)));
    3.12 +    if (!array)
    3.13 +        return NULL;
    3.14 +
    3.15 +    array->nelements_ = nelements;
    3.16 +    array->elements_ = buffer;
    3.17 +    return array;
    3.18 +}
     4.1 --- a/jitcraft/Array.h	Sun Jul 08 17:57:44 2012 -0700
     4.2 +++ b/jitcraft/Array.h	Mon Jul 09 01:22:03 2012 -0700
     4.3 @@ -36,6 +36,8 @@
     4.4    public:
     4.5      static Array *New(Zone *zone, Handle<ArrayMap> map, uint32 elements,
     4.6                        Heap::Tenure = Heap::Tenure_Default);
     4.7 +    static Array *NewExternal(Zone *zone, Handle<ArrayMap> map, uint32 nelements,
     4.8 +                              void *elements, Heap::Tenure = Heap::Tenure_Default);
     4.9  
    4.10      uint32 nelements() {
    4.11          return nelements_;
    4.12 @@ -86,7 +88,15 @@
    4.13          write(zone, &objVec()[index], ptr);
    4.14      }
    4.15  
    4.16 +    bool isExternal() {
    4.17 +        // Inline arrays always have their elements pointing at the next slot.
    4.18 +        Address buffer = reinterpret_cast<Address>(elements_);
    4.19 +        return buffer != reinterpret_cast<Address>(this + 1);
    4.20 +    }
    4.21 +
    4.22      static inline size_t SizeOf(Array *array) {
    4.23 +        if (array->isExternal())
    4.24 +            return sizeof(Array);
    4.25          return sizeof(Array) + array->nelements() * array->elementSize();
    4.26      }
    4.27  
     5.1 --- a/jitcraft/BytecodeCompiler.cpp	Sun Jul 08 17:57:44 2012 -0700
     5.2 +++ b/jitcraft/BytecodeCompiler.cpp	Mon Jul 09 01:22:03 2012 -0700
     5.3 @@ -31,11 +31,11 @@
     5.4  
     5.5  #define __ emitter_.
     5.6  
     5.7 -BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, Module *module)
     5.8 +BytecodeCompiler::BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module)
     5.9    : zone_(zone),
    5.10      tree_(tree),
    5.11      emitter_(zone->pool()),
    5.12 -    module_(module),
    5.13 +    moduleData_(module),
    5.14      locals_(NULL),
    5.15      scope_(NULL),
    5.16      loop_(NULL)
    5.17 @@ -660,13 +660,13 @@
    5.18          return;
    5.19      }
    5.20  
    5.21 -    BytecodeCompiler child(zone_, tree_, module_);
    5.22 -    Local<Function> fun(zone_, child.compileFunction(module_, node));
    5.23 +    BytecodeCompiler child(zone_, tree_, moduleData_);
    5.24 +    Local<Function> fun(zone_, child.compileFunction(moduleData_, node));
    5.25      if (!fun)
    5.26          return;
    5.27      
    5.28 -    assert(!module_->getFunction(node->fun()->slot()));
    5.29 -    module_->setFunction(zone_, node->fun()->slot(), fun);
    5.30 +    assert(!moduleData_->module->getFunction(node->fun()->slot()));
    5.31 +    moduleData_->module->setFunction(zone_, node->fun()->slot(), fun);
    5.32  }
    5.33  
    5.34  void
    5.35 @@ -676,7 +676,7 @@
    5.36  }
    5.37  
    5.38  Function *
    5.39 -BytecodeCompiler::compileFunction(Module *module, FunctionStatement *node)
    5.40 +BytecodeCompiler::compileFunction(ModuleData *module, FunctionStatement *node)
    5.41  {
    5.42      // Note: No need to record a life slot here, since it's part of the Frame.
    5.43      AutoEnterScope functionScope(this, node->scope());
    5.44 @@ -743,8 +743,8 @@
    5.45          assert(cursor == safepoints->raw() + gcmapSize);
    5.46      }
    5.47  
    5.48 -    Local<Code> code(zone_, Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(), module_,
    5.49 -                     safepoints));
    5.50 +    Local<Code> code(zone_, Code::New(zone_, bytes, locals_, objects, __ maxStackDepth(),
    5.51 +                     moduleData_->module, safepoints));
    5.52      if (!code)
    5.53          return NULL;
    5.54  
    5.55 @@ -760,7 +760,7 @@
    5.56          ScopedRoot<Function> root(fun);
    5.57          if (!root)
    5.58              return NULL;
    5.59 -        if (!publics_.append(root))
    5.60 +        if (!moduleData_->publics.append(root))
    5.61              return NULL;
    5.62      }
    5.63      
    5.64 @@ -770,8 +770,12 @@
    5.65  Module *
    5.66  BytecodeCompiler::compile()
    5.67  {
    5.68 -    module_ = Module::New(zone_, tree_->scope()->numFunctions());
    5.69 -    if (!module_)
    5.70 +    ModuleData moduleData;
    5.71 +
    5.72 +    moduleData_ = &moduleData;
    5.73 +    moduleData_->module = Module::New(zone_, tree_->scope()->numFunctions());
    5.74 +
    5.75 +    if (!moduleData_)
    5.76          return NULL;
    5.77  
    5.78      for (size_t i = 0; i < tree_->statements()->length(); i++) {
    5.79 @@ -781,18 +785,21 @@
    5.80  
    5.81  #ifndef NDEBUG
    5.82      for (size_t i = 0; i < tree_->scope()->numFunctions(); i++)
    5.83 -        assert(module_->getFunction(i));
    5.84 +        assert(moduleData_->module->getFunction(i));
    5.85  #endif
    5.86  
    5.87 -    if (publics_.length()) {
    5.88 +    if (moduleData_->publics.length()) {
    5.89          Local<Function> fun(zone_);
    5.90 -        Local<FixedArray> list(zone_, FixedArray::New(zone_, publics_.length(), Heap::Tenure_Old));
    5.91 +        Local<FixedArray> list(zone_, FixedArray::New(zone_, moduleData_->publics.length(),
    5.92 +                               Heap::Tenure_Old));
    5.93          if (!list)
    5.94              return NULL;
    5.95  
    5.96 -        for (size_t i = 0; i < publics_.length(); i++)
    5.97 -            list->set(zone_, i, publics_[i]);
    5.98 +        for (size_t i = 0; i < moduleData_->publics.length(); i++)
    5.99 +            list->set(zone_, i, moduleData_->publics[i]);
   5.100 +
   5.101 +        moduleData_->module->setPublics(list);
   5.102      }
   5.103  
   5.104 -    return module_;
   5.105 +    return moduleData_->module;
   5.106  }
     6.1 --- a/jitcraft/BytecodeCompiler.h	Sun Jul 08 17:57:44 2012 -0700
     6.2 +++ b/jitcraft/BytecodeCompiler.h	Mon Jul 09 01:22:03 2012 -0700
     6.3 @@ -27,15 +27,20 @@
     6.4  
     6.5  class Module;
     6.6  
     6.7 +struct ModuleData
     6.8 +{
     6.9 +    ScopedRoot<Module> module;
    6.10 +    PoolList<ScopedRoot<Function> > publics;
    6.11 +};
    6.12 +
    6.13  class BytecodeCompiler : public AstVisitor
    6.14  {
    6.15      Zone *zone_;
    6.16      ParseTree *tree_;
    6.17      BytecodeEmitter emitter_;
    6.18 -    ScopedRoot<Module> module_;
    6.19      ScopedRoot<FixedArray> locals_;
    6.20      Scope *scope_;
    6.21 -    PoolList<ScopedRoot<Function> > publics_;
    6.22 +    ModuleData *moduleData_;
    6.23  
    6.24      class LoopScope
    6.25      {
    6.26 @@ -98,11 +103,11 @@
    6.27      void recordLifoSlot(Scope *scope);
    6.28      void unwindTo(Scope *scope);
    6.29      void visitForTest(Expression *expression, BytecodeEmitter::Label *label, bool onTrue);
    6.30 -    Function *compileFunction(Module *module, FunctionStatement *fun);
    6.31 +    Function *compileFunction(ModuleData *module, FunctionStatement *fun);
    6.32      void visitForALU(Type *needed, Expression *node);
    6.33  
    6.34    public:
    6.35 -    BytecodeCompiler(Zone *zone, ParseTree *tree, Module *module);
    6.36 +    BytecodeCompiler(Zone *zone, ParseTree *tree, ModuleData *module);
    6.37  
    6.38      Module *compile();
    6.39  
     7.1 --- a/jitcraft/GlobalRoots.cpp	Sun Jul 08 17:57:44 2012 -0700
     7.2 +++ b/jitcraft/GlobalRoots.cpp	Mon Jul 09 01:22:03 2012 -0700
     7.3 @@ -29,8 +29,9 @@
     7.4  {
     7.5      InlineList<HeapRoot>::iterator iter = roots_.begin();
     7.6      while (iter != roots_.end()) {
     7.7 -        delete *iter;
     7.8 +		HeapRoot *root = *iter;
     7.9          iter = roots_.erase(iter);
    7.10 +		delete root;
    7.11      }
    7.12  }
    7.13  
    7.14 @@ -55,7 +56,7 @@
    7.15          return NULL;
    7.16  
    7.17      root->obj = obj;
    7.18 -    root->refcount = 0;
    7.19 +    root->refcount = 1;
    7.20  
    7.21      roots_.append(root);
    7.22      return root;
     8.1 --- a/jitcraft/Interpreter.cpp	Sun Jul 08 17:57:44 2012 -0700
     8.2 +++ b/jitcraft/Interpreter.cpp	Mon Jul 09 01:22:03 2012 -0700
     8.3 @@ -146,7 +146,7 @@
     8.4      if (!top.fp->prev())
     8.5          return true;
     8.6  
     8.7 -    zone->stack().popFrame();
     8.8 +    zone->stack().popInlineFrame();
     8.9      locals = top.fp->locals();
    8.10      *top.sp++ = *result;
    8.11      top.pc += OpcodeInfo[*top.pc].length;
    8.12 @@ -368,7 +368,7 @@
    8.13      zone->heap().reclaim();
    8.14      unsigned index = READ_UINT32(top.pc);
    8.15      Local<Function> newFun(zone, top.fp->code()->module()->getFunction(index));
    8.16 -    if (!zone->stack().pushFrame(newFun)) {
    8.17 +    if (!zone->stack().pushInlineFrame(newFun)) {
    8.18          assert(false);
    8.19          return false;
    8.20      }
     9.1 --- a/jitcraft/Stack.cpp	Sun Jul 08 17:57:44 2012 -0700
     9.2 +++ b/jitcraft/Stack.cpp	Mon Jul 09 01:22:03 2012 -0700
     9.3 @@ -26,8 +26,7 @@
     9.4  
     9.5  Stack::Stack()
     9.6    : buffer_(NULL),
     9.7 -    end_(NULL),
     9.8 -    top_(NULL)
     9.9 +    end_(NULL)
    9.10  {
    9.11  }
    9.12  
    9.13 @@ -43,57 +42,102 @@
    9.14      if (!buffer_)
    9.15          return false;
    9.16  
    9.17 -    top_ = NULL;
    9.18 +    top_.sp = reinterpret_cast<LocalSlot *>(buffer_);
    9.19 +    top_.pc = NULL;
    9.20 +    top_.fp = NULL;
    9.21      end_ = buffer_ + STACK_SIZE;
    9.22      return true;
    9.23  }
    9.24  
    9.25 +InvokeArgs::~InvokeArgs()
    9.26 +{
    9.27 +    stack_->popInvokeFrame(*this);
    9.28 +}
    9.29 +
    9.30  static inline size_t
    9.31  SizeForCodeFrame(Code *code)
    9.32  {
    9.33      return sizeof(Frame) + sizeof(LocalSlot) * (code->nlocals() + code->maxStackDepth());
    9.34  }
    9.35  
    9.36 +bool
    9.37 +Stack::pushInvokeFrame(Handle<Function> fun, InvokeArgs &args)
    9.38 +{
    9.39 +    size_t nbytes = SizeForCodeFrame(fun->code()) +
    9.40 +                    sizeof(LocalSlot) * fun->nargs();
    9.41 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    9.42 +        assert(false);
    9.43 +        return false;
    9.44 +    }
    9.45 +
    9.46 +    memset(top_.sp, 0, sizeof(LocalSlot) * fun->nargs());
    9.47 +    args.args_ = top_.sp;
    9.48 +    args.nargs_ = fun->nargs();
    9.49 +    args.stack_ = this;
    9.50 +    top_.sp += fun->nargs();
    9.51 +    
    9.52 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
    9.53 +    new (frame) Frame(top_.fp, top_.pc, fun, fun->code(), ZONE()->heap().lifoPosition());
    9.54 +    
    9.55 +    top_.pc = frame->code()->start();
    9.56 +    top_.sp = frame->stackBase();
    9.57 +    top_.fp = frame;
    9.58 +
    9.59 +    return true;
    9.60 +}
    9.61 +
    9.62  Frame *
    9.63 -Stack::pushFrame(Function *fun)
    9.64 +Stack::pushInlineFrame(Handle<Function> fun)
    9.65  {
    9.66      Code *code = fun->code();
    9.67      size_t nbytes = SizeForCodeFrame(code);
    9.68 -    if (reinterpret_cast<char *>(top_->sp) + nbytes >= end_)
    9.69 +    if (reinterpret_cast<char *>(top_.sp) + nbytes >= end_) {
    9.70 +        assert(false);
    9.71          return NULL;
    9.72 +    }
    9.73  
    9.74 -    Frame *frame = reinterpret_cast<Frame *>(top_->sp);
    9.75 -    new (frame) Frame(top_->fp, top_->pc, fun, code, ZONE()->heap().lifoPosition());
    9.76 +    Frame *frame = reinterpret_cast<Frame *>(top_.sp);
    9.77 +    new (frame) Frame(top_.fp, top_.pc, fun, code, ZONE()->heap().lifoPosition());
    9.78      memset(frame->locals(), 0, sizeof(LocalSlot) * code->nlocals());
    9.79  
    9.80 -    top_->pc = frame->code()->start();
    9.81 -    top_->sp = frame->stackBase();
    9.82 -    top_->fp = frame;
    9.83 +    top_.pc = frame->code()->start();
    9.84 +    top_.sp = frame->stackBase();
    9.85 +    top_.fp = frame;
    9.86  
    9.87      return frame;
    9.88  }
    9.89  
    9.90  
    9.91  Frame *
    9.92 -Stack::popFrame()
    9.93 +Stack::popInlineFrame()
    9.94  {
    9.95 -    ZONE()->heap().unwindLifo(top_->fp->lifoPosition());
    9.96 +    ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
    9.97  
    9.98 -    Frame *prev = top_->fp->prev();
    9.99 -    Function *fun = top_->fp->maybeFun();
   9.100 -    Code *code = top_->fp->code();
   9.101 +    Frame *prev = top_.fp->prev();
   9.102 +    Function *fun = top_.fp->maybeFun();
   9.103 +    Code *code = top_.fp->code();
   9.104  
   9.105      size_t nbytes = sizeof(LocalSlot) * code->nlocals() +
   9.106                      sizeof(Frame) +
   9.107                      sizeof(LocalSlot) * (fun ? fun->nargs() : 0);
   9.108  
   9.109 -    top_->pc = top_->fp->prevpc();
   9.110 -    top_->sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<char *>(top_->sp) - nbytes);
   9.111 -    top_->fp = prev;
   9.112 +    top_.pc = top_.fp->prevpc();
   9.113 +    top_.sp = reinterpret_cast<LocalSlot *>(reinterpret_cast<char *>(top_.sp) - nbytes);
   9.114 +    top_.fp = prev;
   9.115      return prev;
   9.116  }
   9.117  
   9.118  void
   9.119 +Stack::popInvokeFrame(InvokeArgs &args)
   9.120 +{
   9.121 +    ZONE()->heap().unwindLifo(top_.fp->lifoPosition());
   9.122 +
   9.123 +    top_.pc = top_.fp->prevpc();
   9.124 +    top_.sp = args.args_;
   9.125 +    top_.fp = top_.fp->prev();
   9.126 +}
   9.127 +
   9.128 +void
   9.129  Frame::accept(VirtualObjectVisitor *visitor)
   9.130  {
   9.131      visitor->visit(reinterpret_cast<Object **>(&fun_));
   9.132 @@ -113,7 +157,9 @@
   9.133              visitor->visit(&slots[i].obj);
   9.134      }
   9.135  
   9.136 -    // Trace arguments, if a function call.
   9.137 +    // Trace arguments, if a function call. Note that this means we usually
   9.138 +    // mark arguments twice, once on the caller side and once on the callee.
   9.139 +    // This makes it easier to deal with invoke frames which have no caller.
   9.140      if (Function *fun = fp->maybeFun()) {
   9.141          for (unsigned i = 0; i < fun->nargs(); i++) {
   9.142              Type *type = fun->argType(i);
   9.143 @@ -140,13 +186,10 @@
   9.144  void
   9.145  Stack::accept(VirtualObjectVisitor *visitor)
   9.146  {
   9.147 -    if (!top_)
   9.148 -        return;
   9.149 +    LocalSlot *sp = top_.sp;
   9.150 +    bytecode *pc = top_.pc;
   9.151  
   9.152 -    LocalSlot *sp = top_->sp;
   9.153 -    bytecode *pc = top_->pc;
   9.154 -
   9.155 -    for (Frame *frame = top_->fp; frame; frame = frame->prev()) {
   9.156 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   9.157          TraceFrame(visitor, frame, sp, pc);
   9.158          sp = reinterpret_cast<LocalSlot *>(frame);
   9.159          pc = frame->prevpc();
   9.160 @@ -156,12 +199,11 @@
   9.161  bool
   9.162  Stack::isInCallStack(Handle<Module> module)
   9.163  {
   9.164 -    if (!top_)
   9.165 -        return false;
   9.166 -
   9.167 -    for (Frame *frame = top_->fp; frame; frame = frame->prev()) {
   9.168 +    for (Frame *frame = top_.fp; frame; frame = frame->prev()) {
   9.169          if (frame->code()->module() == module)
   9.170              return true;
   9.171      }
   9.172      return false;
   9.173  }
   9.174 +
   9.175 +
    10.1 --- a/jitcraft/Stack.h	Sun Jul 08 17:57:44 2012 -0700
    10.2 +++ b/jitcraft/Stack.h	Mon Jul 09 01:22:03 2012 -0700
    10.3 @@ -31,6 +31,7 @@
    10.4  class Array;
    10.5  class Reference;
    10.6  class Frame;
    10.7 +class Stack;
    10.8      
    10.9  union LocalSlot
   10.10  {
   10.11 @@ -47,16 +48,6 @@
   10.12      LocalSlot *sp;
   10.13      bytecode *pc;
   10.14      Frame *fp;
   10.15 -
   10.16 -    Top(LocalSlot *sp, bytecode *pc, Frame *fp)
   10.17 -      : sp(sp), pc(pc), fp(NULL)
   10.18 -    {
   10.19 -    }
   10.20 -
   10.21 -    Top(LocalSlot *sp)
   10.22 -      : sp(sp), pc(NULL), fp(NULL)
   10.23 -    {
   10.24 -    }
   10.25  };
   10.26  
   10.27  class Frame
   10.28 @@ -111,11 +102,34 @@
   10.29      void accept(VirtualObjectVisitor *visitor);
   10.30  };
   10.31  
   10.32 +// RAII object for calling a function from C++.
   10.33 +class InvokeArgs
   10.34 +{
   10.35 +    friend class Stack;
   10.36 +
   10.37 +    Stack *stack_;
   10.38 +    LocalSlot *args_;
   10.39 +    unsigned nargs_;
   10.40 +
   10.41 +  public:
   10.42 +    InvokeArgs()
   10.43 +      : stack_(NULL),
   10.44 +        args_(NULL),
   10.45 +        nargs_(0)
   10.46 +    {
   10.47 +    }
   10.48 +
   10.49 +    ~InvokeArgs();
   10.50 +
   10.51 +    LocalSlot &arg(unsigned index) {
   10.52 +        assert(index < nargs_);
   10.53 +        return args_[nargs_ - index - 1];
   10.54 +    }
   10.55 +};
   10.56 +
   10.57  class Stack
   10.58  {
   10.59 -    char *buffer_;
   10.60 -    char *end_;
   10.61 -    Top *top_;
   10.62 +    friend class InvokeArgs;
   10.63  
   10.64    private:
   10.65      static const size_t STACK_SIZE = 1024 * 1024;
   10.66 @@ -127,20 +141,24 @@
   10.67      bool initialize();
   10.68  
   10.69    public:
   10.70 -    Frame *pushFrame(Function *fun);
   10.71 -    Frame *popFrame();
   10.72 +    Frame *pushInlineFrame(Handle<Function> fun);
   10.73 +    Frame *popInlineFrame();
   10.74 +
   10.75 +    bool pushInvokeFrame(Handle<Function> fun, InvokeArgs &args);
   10.76  
   10.77      Top *top() {
   10.78 -        return top_;
   10.79 -    }
   10.80 -    void setTop(Top *top) {
   10.81 -        top_ = top;
   10.82 -    }
   10.83 -    Top begin() {
   10.84 -        return Top((LocalSlot *)buffer_);
   10.85 +        return &top_;
   10.86      }
   10.87      bool isInCallStack(Handle<Module> module);
   10.88      void accept(VirtualObjectVisitor *visitor);
   10.89 +
   10.90 +  private:
   10.91 +    void popInvokeFrame(InvokeArgs &args);
   10.92 +
   10.93 +  private:
   10.94 +    char *buffer_;
   10.95 +    char *end_;
   10.96 +    Top top_;
   10.97  };
   10.98  
   10.99  }
    11.1 --- a/jitcraft/Zone.cpp	Sun Jul 08 17:57:44 2012 -0700
    11.2 +++ b/jitcraft/Zone.cpp	Mon Jul 09 01:22:03 2012 -0700
    11.3 @@ -21,6 +21,7 @@
    11.4  #include "TypeManager.h"
    11.5  #include "GlobalRoots.h"
    11.6  #include "AllocatorPolicies.h"
    11.7 +#include "Array.h"
    11.8  
    11.9  using namespace ke;
   11.10  
   11.11 @@ -84,6 +85,36 @@
   11.12      if (!types_ || !types_->initialize())
   11.13          return false;
   11.14  
   11.15 +    // Create the cached array maps for generic arrays. This is for the API
   11.16 +    // version of Invoke(), which needs to make arrays very quickly from C++.
   11.17 +    {
   11.18 +        // Generic "cell" array (contents do not matter, just non-gc things).
   11.19 +        Local<Type> type(this, types_->getPrimitive(PrimitiveType_Int32));
   11.20 +        if (!type)
   11.21 +            return false;
   11.22 +
   11.23 +        type = types_->unsafeArray(type, Type::UNKNOWN_SIZE);
   11.24 +        if (!type)
   11.25 +            return false;
   11.26 +
   11.27 +        Local<ArrayMap> contained(this);
   11.28 +        genericArrayMap_ = ArrayMap::New(this, type, contained);
   11.29 +        if (!genericArrayMap_)
   11.30 +            return false;
   11.31 +
   11.32 +        type = types_->getPrimitive(PrimitiveType_Char);
   11.33 +        if (!type)
   11.34 +            return false;
   11.35 +
   11.36 +        type = types_->unsafeArray(type, Type::UNKNOWN_SIZE);
   11.37 +        if (!type)
   11.38 +            return false;
   11.39 +
   11.40 +        charArrayMap_ = ArrayMap::New(this, type, contained);
   11.41 +        if (!charArrayMap_)
   11.42 +            return false;
   11.43 +    }
   11.44 +
   11.45      return true;
   11.46  }
   11.47  
   11.48 @@ -103,6 +134,8 @@
   11.49  {
   11.50      for (unsigned i = 0; i < MapKinds_Total; i++)
   11.51          visitor->visit(maps_[i].address());
   11.52 +    visitor->visit(charArrayMap_.address());
   11.53 +    visitor->visit(genericArrayMap_.address());
   11.54      types()->accept(visitor);
   11.55  
   11.56      Local<Object> *local = lastLocalRoot_;
    12.1 --- a/jitcraft/Zone.h	Sun Jul 08 17:57:44 2012 -0700
    12.2 +++ b/jitcraft/Zone.h	Mon Jul 09 01:22:03 2012 -0700
    12.3 @@ -33,6 +33,7 @@
    12.4  class String;
    12.5  class StringPool;
    12.6  class GlobalRoots;
    12.7 +class ArrayMap;
    12.8  
    12.9  class Zone
   12.10  {
   12.11 @@ -42,6 +43,8 @@
   12.12  
   12.13      // Map cache.
   12.14      Unbarriered<Map> maps_[MapKinds_Total];
   12.15 +    Unbarriered<ArrayMap> genericArrayMap_;
   12.16 +    Unbarriered<ArrayMap> charArrayMap_;
   12.17  
   12.18      TypeManager *types_;
   12.19      StringPool *symbols_;
   12.20 @@ -77,10 +80,17 @@
   12.21          return maps_[kind];
   12.22      }
   12.23      Map *allocateMap(MapKind kind, size_t bytes, MapKind parent = MapKind_Meta);
   12.24 +
   12.25 +    ArrayMap *genericArrayMap() {
   12.26 +        return genericArrayMap_;
   12.27 +    }
   12.28 +    ArrayMap *charArrayMap() {
   12.29 +        return charArrayMap_;
   12.30 +    }
   12.31 +
   12.32      TypeManager *types() const {
   12.33          return types_;
   12.34      }
   12.35 -
   12.36      Local<Object> **lastLocalRoot() {
   12.37          return &lastLocalRoot_;
   12.38      }
   12.39 @@ -112,25 +122,6 @@
   12.40      return SingleThreadedZone;
   12.41  }
   12.42  
   12.43 -class LocalTop
   12.44 -{
   12.45 -    Top &mine_;
   12.46 -    Top *prev_;
   12.47 -
   12.48 -  public:
   12.49 -    LocalTop(Top &mine)
   12.50 -      : mine_(mine),
   12.51 -        prev_(ZONE()->stack().top())
   12.52 -    {
   12.53 -        ZONE()->stack().setTop(&mine_);
   12.54 -    }
   12.55 -
   12.56 -    ~LocalTop()
   12.57 -    {
   12.58 -        ZONE()->stack().setTop(prev_);
   12.59 -    }
   12.60 -};
   12.61 -
   12.62  template <typename T>
   12.63  Local<T>::Local(Zone *zone, T *thing)
   12.64    : zone_(zone),