Added a beginning for exception handling.

This commit is contained in:
rogerl%netscape.com 2000-04-21 22:52:52 +00:00
Родитель d863195353
Коммит f516a5722d
10 изменённых файлов: 848 добавлений и 582 удалений

Просмотреть файл

@ -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 */