Added ISPE-oriented API for invoking functions.
Added ISPE-oriented API for invoking functions.
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 ¶m, 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),