JSFrame -> JSLinkage, using explicit linked list rather than a stack.
git-svn-id: svn://10.0.0.236/trunk@67165 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -50,289 +50,336 @@ namespace JavaScript {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
JSValue
|
||||
Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
// These classes are private to the JS interpreter.
|
||||
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
// copy arg list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
for (JSValues::const_iterator src = args.begin(),
|
||||
end = args.end(); src != end; ++src, ++dest) {
|
||||
*dest = *src;
|
||||
}
|
||||
}
|
||||
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller,
|
||||
const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1)
|
||||
{
|
||||
// copy caller's parameter list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current
|
||||
* activation is alive and well in locals of the interpreter loop.
|
||||
*/
|
||||
struct JSLinkage : public gc_base {
|
||||
JSLinkage* mPrevious; // previous linkage in linkage stack.
|
||||
InstructionIterator mReturnPC;
|
||||
InstructionIterator mBasePC;
|
||||
JSActivation* mActivation; // caller's activation.
|
||||
Register mResult; // the desired target register for the return value
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
while (true) {
|
||||
try {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation,
|
||||
op1(call)));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
JSLinkage(JSLinkage* previous, InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: mPrevious(previous), mReturnPC(returnPC), mBasePC(basePC),
|
||||
mActivation(activation), mResult(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
while (true) {
|
||||
try {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
mLinkage = new JSLinkage(mLinkage, ++pc, begin_pc, activation,
|
||||
op1(call));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN_VOID:
|
||||
{
|
||||
JSValue result(NotARegister);
|
||||
JSLinkage *linkage = mLinkage;
|
||||
if (!linkage)
|
||||
return result;
|
||||
mLinkage = linkage->mPrevious;
|
||||
activation = linkage->mActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[linkage->mResult] = result;
|
||||
pc = linkage->mReturnPC;
|
||||
begin_pc = linkage->mBasePC;
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result(NotARegister);
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
JSLinkage* linkage = mLinkage;
|
||||
if (!linkage)
|
||||
return result;
|
||||
mLinkage = linkage->mPrevious;
|
||||
activation = linkage->mActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[linkage->mResult] = result;
|
||||
pc = linkage->mReturnPC;
|
||||
begin_pc = linkage->mBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = (*mGlobal)[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
(*mGlobal)[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
continue;
|
||||
|
||||
case RETURN_VOID:
|
||||
{
|
||||
JSValue result(NotARegister);
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result(NotARegister);
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = (*mGlobal)[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
(*mGlobal)[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
}
|
||||
|
||||
case TRY:
|
||||
{ // push the catch handler address onto the try stack
|
||||
// why did Rhino interpreter also have a finally stack?
|
||||
Try* tri = static_cast<Try*>(instruction);
|
||||
catchStack.push_back(begin_pc + ofs(tri));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
}
|
||||
|
||||
case TRY:
|
||||
{ // push the catch handler address onto the try stack
|
||||
// why did Rhino interpreter also have a finally stack?
|
||||
Try* tri = static_cast<Try*>(instruction);
|
||||
catchStack.push_back(begin_pc + ofs(tri));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
} /* interpret */
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
||||
@@ -29,12 +29,16 @@ namespace JavaScript {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
struct JSLinkage;
|
||||
|
||||
class Context : public gc_base {
|
||||
public:
|
||||
explicit Context(World& /*world */, JSObject* aGlobal) :
|
||||
mGlobal(aGlobal) {}
|
||||
explicit Context(World& world, JSObject* aGlobal)
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0)
|
||||
{
|
||||
}
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
JSObject* getGlobalObject() { return mGlobal; }
|
||||
|
||||
JSObject* setGlobalObject(JSObject* aGlobal)
|
||||
{
|
||||
@@ -43,15 +47,12 @@ namespace JavaScript {
|
||||
return t;
|
||||
}
|
||||
|
||||
JSObject* getGlobalObject()
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
|
||||
private:
|
||||
/* World mWorld; */
|
||||
World& mWorld;
|
||||
JSObject* mGlobal;
|
||||
|
||||
JSLinkage* mLinkage;
|
||||
}; /* class Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
||||
@@ -50,289 +50,336 @@ namespace JavaScript {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
JSValue
|
||||
Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
// These classes are private to the JS interpreter.
|
||||
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct JSActivation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
|
||||
JSActivation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1)
|
||||
{
|
||||
// stack of JSFrames.
|
||||
// XXX is a linked list of activation's sufficient?
|
||||
JSFrameStack frames;
|
||||
// copy arg list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
for (JSValues::const_iterator src = args.begin(),
|
||||
end = args.end(); src != end; ++src, ++dest) {
|
||||
*dest = *src;
|
||||
}
|
||||
}
|
||||
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
JSActivation(ICodeModule* iCode, JSActivation* caller,
|
||||
const RegisterList& list)
|
||||
: mRegisters(iCode->itsMaxRegister + 1)
|
||||
{
|
||||
// copy caller's parameter list to initial registers.
|
||||
JSValues::iterator dest = mRegisters.begin();
|
||||
const JSValues& params = caller->mRegisters;
|
||||
for (RegisterList::const_iterator src = list.begin(),
|
||||
end = list.end(); src != end; ++src, ++dest) {
|
||||
*dest = params[*src];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
/**
|
||||
* Stores saved state from the *previous* activation, the current
|
||||
* activation is alive and well in locals of the interpreter loop.
|
||||
*/
|
||||
struct JSLinkage : public gc_base {
|
||||
JSLinkage* mPrevious; // previous linkage in linkage stack.
|
||||
InstructionIterator mReturnPC;
|
||||
InstructionIterator mBasePC;
|
||||
JSActivation* mActivation; // caller's activation.
|
||||
Register mResult; // the desired target register for the return value
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
while (true) {
|
||||
try {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
frames.push(new JSFrame(++pc, begin_pc, activation,
|
||||
op1(call)));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
JSLinkage(JSLinkage* previous, InstructionIterator returnPC, InstructionIterator basePC,
|
||||
JSActivation* activation, Register result)
|
||||
: mPrevious(previous), mReturnPC(returnPC), mBasePC(basePC),
|
||||
mActivation(activation), mResult(result)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
{
|
||||
// initial activation.
|
||||
JSActivation* activation = new JSActivation(iCode, args);
|
||||
JSValues* registers = &activation->mRegisters;
|
||||
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
while (true) {
|
||||
try {
|
||||
Instruction* instruction = *pc;
|
||||
switch (instruction->op()) {
|
||||
case CALL:
|
||||
{
|
||||
Call* call = static_cast<Call*>(instruction);
|
||||
mLinkage = new JSLinkage(mLinkage, ++pc, begin_pc, activation,
|
||||
op1(call));
|
||||
ICodeModule* target =
|
||||
(*registers)[op2(call)].function->getICode();
|
||||
activation = new JSActivation(target, activation, op3(call));
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pc = target->its_iCode->begin();
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN_VOID:
|
||||
{
|
||||
JSValue result(NotARegister);
|
||||
JSLinkage *linkage = mLinkage;
|
||||
if (!linkage)
|
||||
return result;
|
||||
mLinkage = linkage->mPrevious;
|
||||
activation = linkage->mActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[linkage->mResult] = result;
|
||||
pc = linkage->mReturnPC;
|
||||
begin_pc = linkage->mBasePC;
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result(NotARegister);
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
JSLinkage* linkage = mLinkage;
|
||||
if (!linkage)
|
||||
return result;
|
||||
mLinkage = linkage->mPrevious;
|
||||
activation = linkage->mActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[linkage->mResult] = result;
|
||||
pc = linkage->mReturnPC;
|
||||
begin_pc = linkage->mBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = (*mGlobal)[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
(*mGlobal)[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
continue;
|
||||
|
||||
case RETURN_VOID:
|
||||
{
|
||||
JSValue result(NotARegister);
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
|
||||
case RETURN:
|
||||
{
|
||||
Return* ret = static_cast<Return*>(instruction);
|
||||
JSValue result(NotARegister);
|
||||
if (op1(ret) != NotARegister)
|
||||
result = (*registers)[op1(ret)];
|
||||
if (frames.empty())
|
||||
return result;
|
||||
JSFrame *frame = frames.top();
|
||||
frames.pop();
|
||||
activation = frame->itsActivation;
|
||||
registers = &activation->mRegisters;
|
||||
(*registers)[frame->itsResult] = result;
|
||||
pc = frame->itsReturnPC;
|
||||
begin_pc = frame->itsBasePC;
|
||||
}
|
||||
continue;
|
||||
case MOVE:
|
||||
{
|
||||
Move* mov = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(mov)] = (*registers)[src1(mov)];
|
||||
}
|
||||
break;
|
||||
case LOAD_NAME:
|
||||
{
|
||||
LoadName* ln = static_cast<LoadName*>(instruction);
|
||||
(*registers)[dst(ln)] = (*mGlobal)[*src1(ln)];
|
||||
}
|
||||
break;
|
||||
case SAVE_NAME:
|
||||
{
|
||||
SaveName* sn = static_cast<SaveName*>(instruction);
|
||||
(*mGlobal)[*dst(sn)] = (*registers)[src1(sn)];
|
||||
}
|
||||
break;
|
||||
case NEW_OBJECT:
|
||||
{
|
||||
NewObject* no = static_cast<NewObject*>(instruction);
|
||||
(*registers)[dst(no)].object = new JSObject();
|
||||
}
|
||||
break;
|
||||
case NEW_ARRAY:
|
||||
{
|
||||
NewArray* na = static_cast<NewArray*>(instruction);
|
||||
(*registers)[dst(na)].array = new JSArray();
|
||||
}
|
||||
break;
|
||||
case GET_PROP:
|
||||
{
|
||||
GetProp* gp = static_cast<GetProp*>(instruction);
|
||||
JSObject* object = (*registers)[src1(gp)].object;
|
||||
(*registers)[dst(gp)] = (*object)[*src2(gp)];
|
||||
}
|
||||
break;
|
||||
case SET_PROP:
|
||||
{
|
||||
SetProp* sp = static_cast<SetProp*>(instruction);
|
||||
JSObject* object = (*registers)[dst(sp)].object;
|
||||
(*object)[*src1(sp)] = (*registers)[src2(sp)];
|
||||
}
|
||||
break;
|
||||
case GET_ELEMENT:
|
||||
{
|
||||
GetElement* ge = static_cast<GetElement*>(instruction);
|
||||
JSArray* array = (*registers)[src1(ge)].array;
|
||||
(*registers)[dst(ge)] = (*array)[(*registers)[src2(ge)]];
|
||||
}
|
||||
break;
|
||||
case SET_ELEMENT:
|
||||
{
|
||||
SetElement* se = static_cast<SetElement*>(instruction);
|
||||
JSArray* array = (*registers)[dst(se)].array;
|
||||
(*array)[(*registers)[src1(se)]] = (*registers)[src2(se)];
|
||||
}
|
||||
break;
|
||||
case LOAD_IMMEDIATE:
|
||||
{
|
||||
LoadImmediate* li = static_cast<LoadImmediate*>(instruction);
|
||||
(*registers)[dst(li)] = JSValue(src1(li));
|
||||
}
|
||||
break;
|
||||
case BRANCH:
|
||||
{
|
||||
GenericBranch* bra =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
pc = begin_pc + ofs(bra);
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case BRANCH_LT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 < 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
}
|
||||
|
||||
case TRY:
|
||||
{ // push the catch handler address onto the try stack
|
||||
// why did Rhino interpreter also have a finally stack?
|
||||
Try* tri = static_cast<Try*>(instruction);
|
||||
catchStack.push_back(begin_pc + ofs(tri));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
break;
|
||||
case BRANCH_LE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 <= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_EQ:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 == 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_NE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 != 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GE:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 >= 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BRANCH_GT:
|
||||
{
|
||||
GenericBranch* bc =
|
||||
static_cast<GenericBranch*>(instruction);
|
||||
if ((*registers)[src1(bc)].i32 > 0) {
|
||||
pc = begin_pc + ofs(bc);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ADD:
|
||||
{
|
||||
// could get clever here with Functional forms.
|
||||
Arithmetic* add = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(add)] =
|
||||
JSValue((*registers)[src1(add)].f64 +
|
||||
(*registers)[src2(add)].f64);
|
||||
}
|
||||
break;
|
||||
case SUBTRACT:
|
||||
{
|
||||
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(sub)] =
|
||||
JSValue((*registers)[src1(sub)].f64 -
|
||||
(*registers)[src2(sub)].f64);
|
||||
}
|
||||
break;
|
||||
case MULTIPLY:
|
||||
{
|
||||
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(mul)] =
|
||||
JSValue((*registers)[src1(mul)].f64 *
|
||||
(*registers)[src2(mul)].f64);
|
||||
}
|
||||
break;
|
||||
case DIVIDE:
|
||||
{
|
||||
Arithmetic* div = static_cast<Arithmetic*>(instruction);
|
||||
(*registers)[dst(div)] =
|
||||
JSValue((*registers)[src1(div)].f64 /
|
||||
(*registers)[src2(div)].f64);
|
||||
}
|
||||
break;
|
||||
case COMPARE_LT:
|
||||
case COMPARE_LE:
|
||||
case COMPARE_EQ:
|
||||
case COMPARE_NE:
|
||||
case COMPARE_GT:
|
||||
case COMPARE_GE:
|
||||
{
|
||||
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
|
||||
float64 diff =
|
||||
((*registers)[src1(cmp)].f64 -
|
||||
(*registers)[src2(cmp)].f64);
|
||||
(*registers)[dst(cmp)].i32 =
|
||||
(diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1));
|
||||
}
|
||||
break;
|
||||
case NOT:
|
||||
{
|
||||
Not* nt = static_cast<Not*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
}
|
||||
|
||||
case TRY:
|
||||
{ // push the catch handler address onto the try stack
|
||||
// why did Rhino interpreter also have a finally stack?
|
||||
Try* tri = static_cast<Try*>(instruction);
|
||||
catchStack.push_back(begin_pc + ofs(tri));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
} /* interpret */
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
||||
@@ -29,12 +29,16 @@ namespace JavaScript {
|
||||
using namespace ICG;
|
||||
using namespace JSTypes;
|
||||
|
||||
struct JSLinkage;
|
||||
|
||||
class Context : public gc_base {
|
||||
public:
|
||||
explicit Context(World& /*world */, JSObject* aGlobal) :
|
||||
mGlobal(aGlobal) {}
|
||||
explicit Context(World& world, JSObject* aGlobal)
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0)
|
||||
{
|
||||
}
|
||||
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
JSObject* getGlobalObject() { return mGlobal; }
|
||||
|
||||
JSObject* setGlobalObject(JSObject* aGlobal)
|
||||
{
|
||||
@@ -43,15 +47,12 @@ namespace JavaScript {
|
||||
return t;
|
||||
}
|
||||
|
||||
JSObject* getGlobalObject()
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
JSValue interpret(ICodeModule* iCode, const JSValues& args);
|
||||
|
||||
private:
|
||||
/* World mWorld; */
|
||||
World& mWorld;
|
||||
JSObject* mGlobal;
|
||||
|
||||
JSLinkage* mLinkage;
|
||||
}; /* class Interpreter */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user