зеркало из https://github.com/mozilla/pjs.git
Added a beginning for exception handling.
This commit is contained in:
Родитель
d863195353
Коммит
f516a5722d
|
@ -228,6 +228,12 @@ namespace ICG {
|
|||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginTry(Label *catchLabel)
|
||||
{
|
||||
Try *instr = new Try(catchLabel);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
|
@ -276,15 +282,12 @@ namespace ICG {
|
|||
{
|
||||
resetTopRegister();
|
||||
|
||||
WhileCodeState *ics = new WhileCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
// insert a branch to the while condition, which we're
|
||||
// moving to follow the while block
|
||||
Label *whileConditionTop = getLabel();
|
||||
Label *whileBlockStart = getLabel();
|
||||
branch(whileConditionTop);
|
||||
|
||||
// save off the current stream while we gen code for the condition
|
||||
addStitcher(new WhileCodeState(whileConditionTop,
|
||||
whileBlockStart, this));
|
||||
branch(ics->whileCondition);
|
||||
|
||||
iCode = new InstructionStream();
|
||||
}
|
||||
|
@ -329,17 +332,13 @@ namespace ICG {
|
|||
|
||||
void ICodeGenerator::beginForStatement(uint32)
|
||||
{
|
||||
Label *forCondition = getLabel();
|
||||
|
||||
ForCodeState *ics = new ForCodeState(forCondition, getLabel(), this);
|
||||
|
||||
branch(forCondition);
|
||||
|
||||
ForCodeState *ics = new ForCodeState(this);
|
||||
addStitcher(ics);
|
||||
branch(ics->forCondition);
|
||||
|
||||
// begin the stream for collecting the condition expression
|
||||
iCode = new InstructionStream();
|
||||
setLabel(forCondition);
|
||||
setLabel(ics->forCondition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
@ -397,16 +396,11 @@ namespace ICG {
|
|||
void ICodeGenerator::beginDoStatement(uint32)
|
||||
{
|
||||
resetTopRegister();
|
||||
DoCodeState *ics = new DoCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
// mark the top of the loop body
|
||||
// and reserve a label for the condition
|
||||
Label *doBlock = getLabel();
|
||||
Label *doCondition = getLabel();
|
||||
setLabel(doBlock);
|
||||
|
||||
addStitcher(new DoCodeState(doBlock, doCondition, this));
|
||||
|
||||
iCode = new InstructionStream();
|
||||
setLabel(ics->doBody);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endDoStatement()
|
||||
|
@ -445,6 +439,12 @@ namespace ICG {
|
|||
// stash the control expression value
|
||||
resetTopRegister();
|
||||
Register control = op(MOVE, expression);
|
||||
/*
|
||||
XXXX this register needs to belong to the 'variable' set so that
|
||||
it is preserved across statements. Then we can drop having to
|
||||
keep the registe rbase in the icodestate.
|
||||
|
||||
*/
|
||||
// build an instruction stream for the case statements, the case
|
||||
// expressions are generated into the main stream directly, the
|
||||
// case statements are then added back in afterwards.
|
||||
|
@ -544,11 +544,10 @@ namespace ICG {
|
|||
|
||||
void ICodeGenerator::beginIfStatement(uint32, Register condition)
|
||||
{
|
||||
Label *elseLabel = getLabel();
|
||||
|
||||
addStitcher(new IfCodeState(elseLabel, NULL, this));
|
||||
IfCodeState *ics = new IfCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
branchNotConditional(elseLabel, condition);
|
||||
branchNotConditional(ics->elseLabel, condition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
@ -667,10 +666,65 @@ namespace ICG {
|
|||
}
|
||||
NOT_REACHED("no continue target available");
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
/************************************************************************/
|
||||
void ICodeGenerator::beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally)
|
||||
{
|
||||
addStitcher(new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this));
|
||||
}
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
void ICodeGenerator::endTryBlock()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
|
||||
if (ics->beyondCatch)
|
||||
branch(ics->beyondCatch);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endTryStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
stitcher.pop_back();
|
||||
if (ics->beyondCatch)
|
||||
setLabel(ics->beyondCatch);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginCatchStatement(uint32 pos)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchExpression(Register expression)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginFinallyStatement(uint32 pos)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endFinallyStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
{
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n";
|
||||
for (InstructionIterator i = iCode->begin();
|
||||
|
|
|
@ -57,7 +57,8 @@ namespace ICG {
|
|||
If_state,
|
||||
Do_state,
|
||||
Switch_state,
|
||||
For_state
|
||||
For_state,
|
||||
Try_state
|
||||
};
|
||||
|
||||
class ICodeState {
|
||||
|
@ -118,7 +119,7 @@ namespace ICG {
|
|||
Register topRegister;
|
||||
Register registerBase;
|
||||
uint32 maxRegister;
|
||||
uint32 statementLabelBase;;
|
||||
uint32 statementLabelBase;;
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
@ -127,6 +128,8 @@ namespace ICG {
|
|||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel);
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), registerBase(0), maxRegister(0), statementLabelBase(0)
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
@ -184,7 +187,7 @@ namespace ICG {
|
|||
|
||||
void returnStatement() { iCode->push_back(new ReturnVoid()); }
|
||||
void returnStatement(Register result) \
|
||||
{ iCode->push_back(new Return(result)); }
|
||||
{ iCode->push_back(new Return(result)); }
|
||||
|
||||
void beginWhileStatement(uint32 pos);
|
||||
void endWhileExpression(Register condition);
|
||||
|
@ -230,12 +233,20 @@ namespace ICG {
|
|||
void continueStatement(uint32 pos, const StringAtom &label);
|
||||
void breakStatement(uint32 pos, const StringAtom &label);
|
||||
|
||||
void throwStatement(uint32 pos, Register expression);
|
||||
void throwStatement(uint32 pos, Register expression)
|
||||
{ iCode->push_back(new Throw(expression)); }
|
||||
|
||||
void beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally);
|
||||
void endTryBlock();
|
||||
void endTryStatement();
|
||||
|
||||
void beginCatchStatement(uint32 pos);
|
||||
void endCatchExpression(Register expression);
|
||||
void endCatchStatement();
|
||||
|
||||
void beginFinallyStatement(uint32 pos);
|
||||
void endFinallyStatement();
|
||||
|
||||
};
|
||||
|
||||
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
|
||||
|
@ -246,8 +257,7 @@ namespace ICG {
|
|||
|
||||
class WhileCodeState : public ICodeState {
|
||||
public:
|
||||
WhileCodeState(Label *conditionLabel, Label *bodyLabel,
|
||||
ICodeGenerator *icg); // inline below
|
||||
WhileCodeState(ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream(InstructionStream *iCode) \
|
||||
{ InstructionStream *t = whileExpressionStream; \
|
||||
whileExpressionStream = iCode; return t; }
|
||||
|
@ -265,8 +275,7 @@ namespace ICG {
|
|||
|
||||
class ForCodeState : public ICodeState {
|
||||
public:
|
||||
ForCodeState(Label *conditionLabel, Label *bodyLabel,
|
||||
ICodeGenerator *icg); // inline below
|
||||
ForCodeState(ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream(InstructionStream *iCode) \
|
||||
{ InstructionStream *t = forConditionStream; \
|
||||
forConditionStream = iCode; return t; }
|
||||
|
@ -288,18 +297,17 @@ namespace ICG {
|
|||
|
||||
class IfCodeState : public ICodeState {
|
||||
public:
|
||||
IfCodeState(Label *a, Label *b, ICodeGenerator *icg)
|
||||
: ICodeState(If_state, icg), elseLabel(a), beyondElse(b) { }
|
||||
IfCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(If_state, icg), elseLabel(icg->getLabel()), beyondElse(NULL) { }
|
||||
Label *elseLabel;
|
||||
Label *beyondElse;
|
||||
};
|
||||
|
||||
class DoCodeState : public ICodeState {
|
||||
public:
|
||||
DoCodeState(Label *bodyLabel, Label *conditionLabel,
|
||||
ICodeGenerator *icg)
|
||||
: ICodeState(Do_state, icg), doBody(bodyLabel),
|
||||
doCondition(conditionLabel) { }
|
||||
DoCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(Do_state, icg), doBody(icg->getLabel()),
|
||||
doCondition(icg->getLabel()) { }
|
||||
|
||||
virtual Label *getBreakLabel(ICodeGenerator *icg) \
|
||||
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
|
||||
|
@ -327,6 +335,19 @@ namespace ICG {
|
|||
InstructionStream *caseStatementsStream;
|
||||
};
|
||||
|
||||
class TryCodeState : public ICodeState {
|
||||
public:
|
||||
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(Try_state, icg),
|
||||
catchHandler(catchLabel),
|
||||
finallyHandler(finallyLabel),
|
||||
beyondCatch(NULL)
|
||||
{ if (catchHandler != NULL) beyondCatch = icg->getLabel(); }
|
||||
Label *catchHandler;
|
||||
Label *finallyHandler;
|
||||
Label *beyondCatch;
|
||||
};
|
||||
|
||||
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
|
||||
: stateKind(kind), registerBase(icg->getRegisterBase()),
|
||||
breakLabel(NULL), continueLabel(NULL),
|
||||
|
@ -337,18 +358,16 @@ namespace ICG {
|
|||
: ICodeState(Switch_state, icg), controlExpression(control),
|
||||
defaultLabel(NULL), caseStatementsStream(icg->get_iCode()) {}
|
||||
|
||||
inline WhileCodeState::WhileCodeState(Label *conditionLabel,
|
||||
Label *bodyLabel,
|
||||
ICodeGenerator *icg)
|
||||
: ICodeState(While_state, icg), whileCondition(conditionLabel),
|
||||
whileBody(bodyLabel), whileExpressionStream(icg->get_iCode()) {}
|
||||
inline WhileCodeState::WhileCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(While_state, icg), whileCondition(icg->getLabel()),
|
||||
whileBody(icg->getLabel()), whileExpressionStream(icg->get_iCode()) {}
|
||||
|
||||
inline ForCodeState::ForCodeState(Label *conditionLabel,
|
||||
Label *bodyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(For_state, icg), forCondition(conditionLabel),
|
||||
forBody(bodyLabel), forConditionStream(icg->get_iCode()),
|
||||
inline ForCodeState::ForCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(For_state, icg), forCondition(icg->getLabel()),
|
||||
forBody(icg->getLabel()), forConditionStream(icg->get_iCode()),
|
||||
forIncrementStream(icg->get_iCode()) {}
|
||||
|
||||
|
||||
} /* namespace IGC */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
|
|
@ -64,249 +64,275 @@ namespace JavaScript {
|
|||
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) {
|
||||
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();
|
||||
}
|
||||
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);
|
||||
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();
|
||||
}
|
||||
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:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
|
||||
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);
|
||||
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:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(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();
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -239,6 +239,11 @@ namespace JSTypes {
|
|||
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
|
||||
class JS_Exception : public gc_base {
|
||||
public:
|
||||
JS_Exception() { }
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace VM {
|
|||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ENDTRY, /* there is no try, only do */
|
||||
GET_ELEMENT, /* dest, array, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
|
@ -74,6 +75,8 @@ namespace VM {
|
|||
SET_ELEMENT, /* base, source1, source2 */
|
||||
SET_PROP, /* object, name, source */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
THROW, /* exception object */
|
||||
TRY, /* catch */
|
||||
};
|
||||
|
||||
|
||||
|
@ -96,6 +99,7 @@ namespace VM {
|
|||
"COMPARE_LT ",
|
||||
"COMPARE_NE ",
|
||||
"DIVIDE ",
|
||||
"ENDTRY ",
|
||||
"GET_ELEMENT ",
|
||||
"GET_PROP ",
|
||||
"LOAD_IMMEDIATE",
|
||||
|
@ -112,6 +116,8 @@ namespace VM {
|
|||
"SET_ELEMENT ",
|
||||
"SET_PROP ",
|
||||
"SUBTRACT ",
|
||||
"THROW ",
|
||||
"TRY ",
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
|
@ -408,6 +414,12 @@ namespace VM {
|
|||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class EndTry : public Instruction {
|
||||
public:
|
||||
EndTry () :
|
||||
Instruction(ENDTRY) {};
|
||||
};
|
||||
|
||||
class GetElement : public Instruction_3<Register, Register, Register> {
|
||||
public:
|
||||
/* dest, array, index */
|
||||
|
@ -594,6 +606,23 @@ namespace VM {
|
|||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class Throw : public Instruction_1<Register> {
|
||||
public:
|
||||
Throw (Register aOp1) :
|
||||
Instruction_1<Register>
|
||||
(THROW, aOp1) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[THROW] << "\t" << "R" << mOp1;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class Try : public GenericBranch {
|
||||
public:
|
||||
Try (Label *catchStart) :
|
||||
GenericBranch(TRY, catchStart) {};
|
||||
};
|
||||
|
||||
} /* namespace VM */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -228,6 +228,12 @@ namespace ICG {
|
|||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginTry(Label *catchLabel)
|
||||
{
|
||||
Try *instr = new Try(catchLabel);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
|
@ -276,15 +282,12 @@ namespace ICG {
|
|||
{
|
||||
resetTopRegister();
|
||||
|
||||
WhileCodeState *ics = new WhileCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
// insert a branch to the while condition, which we're
|
||||
// moving to follow the while block
|
||||
Label *whileConditionTop = getLabel();
|
||||
Label *whileBlockStart = getLabel();
|
||||
branch(whileConditionTop);
|
||||
|
||||
// save off the current stream while we gen code for the condition
|
||||
addStitcher(new WhileCodeState(whileConditionTop,
|
||||
whileBlockStart, this));
|
||||
branch(ics->whileCondition);
|
||||
|
||||
iCode = new InstructionStream();
|
||||
}
|
||||
|
@ -329,17 +332,13 @@ namespace ICG {
|
|||
|
||||
void ICodeGenerator::beginForStatement(uint32)
|
||||
{
|
||||
Label *forCondition = getLabel();
|
||||
|
||||
ForCodeState *ics = new ForCodeState(forCondition, getLabel(), this);
|
||||
|
||||
branch(forCondition);
|
||||
|
||||
ForCodeState *ics = new ForCodeState(this);
|
||||
addStitcher(ics);
|
||||
branch(ics->forCondition);
|
||||
|
||||
// begin the stream for collecting the condition expression
|
||||
iCode = new InstructionStream();
|
||||
setLabel(forCondition);
|
||||
setLabel(ics->forCondition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
@ -397,16 +396,11 @@ namespace ICG {
|
|||
void ICodeGenerator::beginDoStatement(uint32)
|
||||
{
|
||||
resetTopRegister();
|
||||
DoCodeState *ics = new DoCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
// mark the top of the loop body
|
||||
// and reserve a label for the condition
|
||||
Label *doBlock = getLabel();
|
||||
Label *doCondition = getLabel();
|
||||
setLabel(doBlock);
|
||||
|
||||
addStitcher(new DoCodeState(doBlock, doCondition, this));
|
||||
|
||||
iCode = new InstructionStream();
|
||||
setLabel(ics->doBody);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endDoStatement()
|
||||
|
@ -445,6 +439,12 @@ namespace ICG {
|
|||
// stash the control expression value
|
||||
resetTopRegister();
|
||||
Register control = op(MOVE, expression);
|
||||
/*
|
||||
XXXX this register needs to belong to the 'variable' set so that
|
||||
it is preserved across statements. Then we can drop having to
|
||||
keep the registe rbase in the icodestate.
|
||||
|
||||
*/
|
||||
// build an instruction stream for the case statements, the case
|
||||
// expressions are generated into the main stream directly, the
|
||||
// case statements are then added back in afterwards.
|
||||
|
@ -544,11 +544,10 @@ namespace ICG {
|
|||
|
||||
void ICodeGenerator::beginIfStatement(uint32, Register condition)
|
||||
{
|
||||
Label *elseLabel = getLabel();
|
||||
|
||||
addStitcher(new IfCodeState(elseLabel, NULL, this));
|
||||
IfCodeState *ics = new IfCodeState(this);
|
||||
addStitcher(ics);
|
||||
|
||||
branchNotConditional(elseLabel, condition);
|
||||
branchNotConditional(ics->elseLabel, condition);
|
||||
|
||||
resetTopRegister();
|
||||
}
|
||||
|
@ -667,10 +666,65 @@ namespace ICG {
|
|||
}
|
||||
NOT_REACHED("no continue target available");
|
||||
}
|
||||
/********************************************************************/
|
||||
|
||||
/************************************************************************/
|
||||
void ICodeGenerator::beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally)
|
||||
{
|
||||
addStitcher(new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this));
|
||||
}
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
void ICodeGenerator::endTryBlock()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
|
||||
if (ics->beyondCatch)
|
||||
branch(ics->beyondCatch);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endTryStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
stitcher.pop_back();
|
||||
if (ics->beyondCatch)
|
||||
setLabel(ics->beyondCatch);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginCatchStatement(uint32 pos)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchExpression(Register expression)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginFinallyStatement(uint32 pos)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endFinallyStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
Formatter& ICodeGenerator::print(Formatter& f)
|
||||
{
|
||||
f << "ICG! " << (uint32)iCode->size() << "\n";
|
||||
for (InstructionIterator i = iCode->begin();
|
||||
|
|
|
@ -57,7 +57,8 @@ namespace ICG {
|
|||
If_state,
|
||||
Do_state,
|
||||
Switch_state,
|
||||
For_state
|
||||
For_state,
|
||||
Try_state
|
||||
};
|
||||
|
||||
class ICodeState {
|
||||
|
@ -118,7 +119,7 @@ namespace ICG {
|
|||
Register topRegister;
|
||||
Register registerBase;
|
||||
uint32 maxRegister;
|
||||
uint32 statementLabelBase;;
|
||||
uint32 statementLabelBase;;
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
@ -127,6 +128,8 @@ namespace ICG {
|
|||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel);
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), registerBase(0), maxRegister(0), statementLabelBase(0)
|
||||
{ iCode = new InstructionStream(); }
|
||||
|
@ -184,7 +187,7 @@ namespace ICG {
|
|||
|
||||
void returnStatement() { iCode->push_back(new ReturnVoid()); }
|
||||
void returnStatement(Register result) \
|
||||
{ iCode->push_back(new Return(result)); }
|
||||
{ iCode->push_back(new Return(result)); }
|
||||
|
||||
void beginWhileStatement(uint32 pos);
|
||||
void endWhileExpression(Register condition);
|
||||
|
@ -230,12 +233,20 @@ namespace ICG {
|
|||
void continueStatement(uint32 pos, const StringAtom &label);
|
||||
void breakStatement(uint32 pos, const StringAtom &label);
|
||||
|
||||
void throwStatement(uint32 pos, Register expression);
|
||||
void throwStatement(uint32 pos, Register expression)
|
||||
{ iCode->push_back(new Throw(expression)); }
|
||||
|
||||
void beginTryStatement(uint32 pos, bool hasCatch, bool hasFinally);
|
||||
void endTryBlock();
|
||||
void endTryStatement();
|
||||
|
||||
void beginCatchStatement(uint32 pos);
|
||||
void endCatchExpression(Register expression);
|
||||
void endCatchStatement();
|
||||
|
||||
void beginFinallyStatement(uint32 pos);
|
||||
void endFinallyStatement();
|
||||
|
||||
};
|
||||
|
||||
Formatter& operator<<(Formatter &f, ICodeGenerator &i);
|
||||
|
@ -246,8 +257,7 @@ namespace ICG {
|
|||
|
||||
class WhileCodeState : public ICodeState {
|
||||
public:
|
||||
WhileCodeState(Label *conditionLabel, Label *bodyLabel,
|
||||
ICodeGenerator *icg); // inline below
|
||||
WhileCodeState(ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream(InstructionStream *iCode) \
|
||||
{ InstructionStream *t = whileExpressionStream; \
|
||||
whileExpressionStream = iCode; return t; }
|
||||
|
@ -265,8 +275,7 @@ namespace ICG {
|
|||
|
||||
class ForCodeState : public ICodeState {
|
||||
public:
|
||||
ForCodeState(Label *conditionLabel, Label *bodyLabel,
|
||||
ICodeGenerator *icg); // inline below
|
||||
ForCodeState(ICodeGenerator *icg); // inline below
|
||||
InstructionStream *swapStream(InstructionStream *iCode) \
|
||||
{ InstructionStream *t = forConditionStream; \
|
||||
forConditionStream = iCode; return t; }
|
||||
|
@ -288,18 +297,17 @@ namespace ICG {
|
|||
|
||||
class IfCodeState : public ICodeState {
|
||||
public:
|
||||
IfCodeState(Label *a, Label *b, ICodeGenerator *icg)
|
||||
: ICodeState(If_state, icg), elseLabel(a), beyondElse(b) { }
|
||||
IfCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(If_state, icg), elseLabel(icg->getLabel()), beyondElse(NULL) { }
|
||||
Label *elseLabel;
|
||||
Label *beyondElse;
|
||||
};
|
||||
|
||||
class DoCodeState : public ICodeState {
|
||||
public:
|
||||
DoCodeState(Label *bodyLabel, Label *conditionLabel,
|
||||
ICodeGenerator *icg)
|
||||
: ICodeState(Do_state, icg), doBody(bodyLabel),
|
||||
doCondition(conditionLabel) { }
|
||||
DoCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(Do_state, icg), doBody(icg->getLabel()),
|
||||
doCondition(icg->getLabel()) { }
|
||||
|
||||
virtual Label *getBreakLabel(ICodeGenerator *icg) \
|
||||
{ if (breakLabel == NULL) breakLabel = icg->getLabel();
|
||||
|
@ -327,6 +335,19 @@ namespace ICG {
|
|||
InstructionStream *caseStatementsStream;
|
||||
};
|
||||
|
||||
class TryCodeState : public ICodeState {
|
||||
public:
|
||||
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(Try_state, icg),
|
||||
catchHandler(catchLabel),
|
||||
finallyHandler(finallyLabel),
|
||||
beyondCatch(NULL)
|
||||
{ if (catchHandler != NULL) beyondCatch = icg->getLabel(); }
|
||||
Label *catchHandler;
|
||||
Label *finallyHandler;
|
||||
Label *beyondCatch;
|
||||
};
|
||||
|
||||
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
|
||||
: stateKind(kind), registerBase(icg->getRegisterBase()),
|
||||
breakLabel(NULL), continueLabel(NULL),
|
||||
|
@ -337,18 +358,16 @@ namespace ICG {
|
|||
: ICodeState(Switch_state, icg), controlExpression(control),
|
||||
defaultLabel(NULL), caseStatementsStream(icg->get_iCode()) {}
|
||||
|
||||
inline WhileCodeState::WhileCodeState(Label *conditionLabel,
|
||||
Label *bodyLabel,
|
||||
ICodeGenerator *icg)
|
||||
: ICodeState(While_state, icg), whileCondition(conditionLabel),
|
||||
whileBody(bodyLabel), whileExpressionStream(icg->get_iCode()) {}
|
||||
inline WhileCodeState::WhileCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(While_state, icg), whileCondition(icg->getLabel()),
|
||||
whileBody(icg->getLabel()), whileExpressionStream(icg->get_iCode()) {}
|
||||
|
||||
inline ForCodeState::ForCodeState(Label *conditionLabel,
|
||||
Label *bodyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(For_state, icg), forCondition(conditionLabel),
|
||||
forBody(bodyLabel), forConditionStream(icg->get_iCode()),
|
||||
inline ForCodeState::ForCodeState(ICodeGenerator *icg)
|
||||
: ICodeState(For_state, icg), forCondition(icg->getLabel()),
|
||||
forBody(icg->getLabel()), forConditionStream(icg->get_iCode()),
|
||||
forIncrementStream(icg->get_iCode()) {}
|
||||
|
||||
|
||||
} /* namespace IGC */
|
||||
} /* namespace JavaScript */
|
||||
|
||||
|
|
|
@ -64,249 +64,275 @@ namespace JavaScript {
|
|||
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) {
|
||||
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();
|
||||
}
|
||||
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);
|
||||
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();
|
||||
}
|
||||
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:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(instruction);
|
||||
(*registers)[dst(nt)].i32 = !(*registers)[src1(nt)].i32;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
|
||||
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);
|
||||
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:
|
||||
{
|
||||
Move* nt = static_cast<Move*>(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();
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -239,6 +239,11 @@ namespace JSTypes {
|
|||
|
||||
// a stack of JSFrames.
|
||||
typedef std::stack<JSFrame*, std::vector<JSFrame*, gc_allocator<JSFrame*> > > JSFrameStack;
|
||||
|
||||
class JS_Exception : public gc_base {
|
||||
public:
|
||||
JS_Exception() { }
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
} /* namespace JavaScript */
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace VM {
|
|||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ENDTRY, /* there is no try, only do */
|
||||
GET_ELEMENT, /* dest, array, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
|
@ -74,6 +75,8 @@ namespace VM {
|
|||
SET_ELEMENT, /* base, source1, source2 */
|
||||
SET_PROP, /* object, name, source */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
THROW, /* exception object */
|
||||
TRY, /* catch */
|
||||
};
|
||||
|
||||
|
||||
|
@ -96,6 +99,7 @@ namespace VM {
|
|||
"COMPARE_LT ",
|
||||
"COMPARE_NE ",
|
||||
"DIVIDE ",
|
||||
"ENDTRY ",
|
||||
"GET_ELEMENT ",
|
||||
"GET_PROP ",
|
||||
"LOAD_IMMEDIATE",
|
||||
|
@ -112,6 +116,8 @@ namespace VM {
|
|||
"SET_ELEMENT ",
|
||||
"SET_PROP ",
|
||||
"SUBTRACT ",
|
||||
"THROW ",
|
||||
"TRY ",
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
|
@ -408,6 +414,12 @@ namespace VM {
|
|||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class EndTry : public Instruction {
|
||||
public:
|
||||
EndTry () :
|
||||
Instruction(ENDTRY) {};
|
||||
};
|
||||
|
||||
class GetElement : public Instruction_3<Register, Register, Register> {
|
||||
public:
|
||||
/* dest, array, index */
|
||||
|
@ -594,6 +606,23 @@ namespace VM {
|
|||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class Throw : public Instruction_1<Register> {
|
||||
public:
|
||||
Throw (Register aOp1) :
|
||||
Instruction_1<Register>
|
||||
(THROW, aOp1) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[THROW] << "\t" << "R" << mOp1;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class Try : public GenericBranch {
|
||||
public:
|
||||
Try (Label *catchStart) :
|
||||
GenericBranch(TRY, catchStart) {};
|
||||
};
|
||||
|
||||
} /* namespace VM */
|
||||
|
||||
} /* namespace JavaScript */
|
||||
|
|
Загрузка…
Ссылка в новой задаче