mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-11 12:25:53 +00:00
More exception handling handling.
This commit is contained in:
parent
a7ec34534b
commit
d96a9a02a4
@ -55,6 +55,26 @@ namespace ICG {
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting)
|
||||
: topRegister(0),
|
||||
registerBase(0),
|
||||
maxRegister(0),
|
||||
statementLabelBase(0),
|
||||
exceptionRegister(NotARegister)
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
if (hasTryStatement)
|
||||
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
|
||||
for (int i = 0; i < switchStatementNesting; i++) {
|
||||
String s = widenCString("__switchControlVariable__");
|
||||
char num[8];
|
||||
sprintf(num, "%.2d", i);
|
||||
appendChars(s, num, strlen(num));
|
||||
allocateVariable(world->identifiers[s]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -66,7 +86,6 @@ namespace ICG {
|
||||
ASSERT((*i)->mOffset <= iCode->size());
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
for (InstructionIterator ii = iCode->begin();
|
||||
ii != iCode->end(); ii++) {
|
||||
@ -86,10 +105,24 @@ namespace ICG {
|
||||
}
|
||||
*/
|
||||
markMaxRegister();
|
||||
|
||||
return new ICodeModule(iCode, maxRegister);
|
||||
}
|
||||
|
||||
TryCodeState::TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(Try_state, icg),
|
||||
catchHandler(catchLabel),
|
||||
finallyHandler(finallyLabel),
|
||||
finallyInvoker(NULL),
|
||||
beyondCatch(NULL)
|
||||
{
|
||||
if (catchHandler) {
|
||||
beyondCatch = icg->getLabel();
|
||||
if (finallyLabel)
|
||||
finallyInvoker = icg->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Register ICodeGenerator::loadImmediate(double value)
|
||||
@ -234,12 +267,6 @@ namespace ICG {
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginTry(Label *catchLabel)
|
||||
{
|
||||
Try *instr = new Try(catchLabel);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
@ -679,8 +706,11 @@ namespace ICG {
|
||||
void ICodeGenerator::beginTryStatement(uint32 /* pos */,
|
||||
bool hasCatch, bool hasFinally)
|
||||
{
|
||||
addStitcher(new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this));
|
||||
ASSERT(exceptionRegister != NotARegister);
|
||||
TryCodeState *ics = new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this);
|
||||
addStitcher(ics);
|
||||
beginTry(ics->catchHandler, ics->finallyInvoker);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endTryBlock()
|
||||
@ -688,6 +718,9 @@ namespace ICG {
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
|
||||
endTry();
|
||||
if (ics->finallyHandler)
|
||||
jsr(ics->finallyHandler);
|
||||
if (ics->beyondCatch)
|
||||
branch(ics->beyondCatch);
|
||||
}
|
||||
@ -705,30 +738,44 @@ namespace ICG {
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
ASSERT(ics->catchHandler);
|
||||
setLabel(ics->catchHandler);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchExpression(Register /* expression */)
|
||||
void ICodeGenerator::endCatchExpression(Register exceptionId)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
move(exceptionRegister, exceptionId);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
if (ics->finallyHandler)
|
||||
jsr(ics->finallyHandler);
|
||||
throwStatement(0, exceptionRegister);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginFinallyStatement(uint32 /* pos */)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
ASSERT(ics->finallyHandler);
|
||||
if (ics->finallyInvoker) {
|
||||
setLabel(ics->finallyInvoker);
|
||||
jsr(ics->finallyHandler);
|
||||
throwStatement(0, exceptionRegister);
|
||||
}
|
||||
setLabel(ics->finallyHandler);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endFinallyStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
rts();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -120,19 +120,25 @@ namespace ICG {
|
||||
Register registerBase;
|
||||
uint32 maxRegister;
|
||||
uint32 statementLabelBase;
|
||||
Register exceptionRegister; // reserved to carry the exception object
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
||||
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||
void rts() { iCode->push_back(new Rts()); }
|
||||
void branch(Label *label);
|
||||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel);
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Try(catchLabel, finallyLabel)); }
|
||||
void endTry()
|
||||
{ iCode->push_back(new Endtry()); }
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), registerBase(0), maxRegister(0), statementLabelBase(0)
|
||||
{ iCode = new InstructionStream(); }
|
||||
ICodeGenerator() { ICodeGenerator(NULL, false, 0); }
|
||||
ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting);
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
@ -142,6 +148,8 @@ namespace ICG {
|
||||
|
||||
Register allocateVariable(StringAtom& /*name*/)
|
||||
{ Register result = getRegister(); registerBase = topRegister; return result; }
|
||||
Register allocateVariable(char * /*name*/)
|
||||
{ Register result = getRegister(); registerBase = topRegister; return result; }
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
@ -241,7 +249,7 @@ namespace ICG {
|
||||
void endTryStatement();
|
||||
|
||||
void beginCatchStatement(uint32 pos);
|
||||
void endCatchExpression(Register expression);
|
||||
void endCatchExpression(Register exceptionId);
|
||||
void endCatchStatement();
|
||||
|
||||
void beginFinallyStatement(uint32 pos);
|
||||
@ -337,14 +345,10 @@ namespace ICG {
|
||||
|
||||
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(); }
|
||||
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg);
|
||||
Label *catchHandler;
|
||||
Label *finallyHandler;
|
||||
Label *finallyInvoker;
|
||||
Label *beyondCatch;
|
||||
};
|
||||
|
||||
|
@ -63,12 +63,25 @@ using namespace JSTypes;
|
||||
|
||||
// These classes are private to the JS interpreter.
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
struct Handler: public gc_base {
|
||||
Handler(Label *catchLabel, Label *finallyLabel)
|
||||
: catchTarget(catchLabel), finallyTarget(finallyLabel) {}
|
||||
Label *catchTarget;
|
||||
Label *finallyTarget;
|
||||
};
|
||||
typedef std::vector<Handler *> CatchStack;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct Activation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
ICodeModule* mICode;
|
||||
CatchStack catchStack;
|
||||
|
||||
Activation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
@ -132,7 +145,8 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
// stack of all catch/finally handlers available for the current activation
|
||||
std::stack<InstructionIterator> subroutineStack; // to implement jsr/rts for finally code
|
||||
while (true) {
|
||||
try {
|
||||
// tell any listeners about the current execution state.
|
||||
@ -376,34 +390,84 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
Throw* thrw = static_cast<Throw*>(instruction);
|
||||
throw new JSException((*registers)[op1(thrw)]);
|
||||
}
|
||||
|
||||
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));
|
||||
activation->catchStack.push_back(new Handler(op1(tri), op2(tri)));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
Handler *h = activation->catchStack.back();
|
||||
activation->catchStack.pop_back();
|
||||
delete h;
|
||||
}
|
||||
break;
|
||||
|
||||
case JSR :
|
||||
{
|
||||
subroutineStack.push(++pc);
|
||||
Jsr* jsr = static_cast<Jsr*>(instruction);
|
||||
uint32 offset = ofs(jsr);
|
||||
pc = begin_pc + offset;
|
||||
continue;
|
||||
}
|
||||
case RTS :
|
||||
{
|
||||
ASSERT(!subroutineStack.empty());
|
||||
pc = subroutineStack.top();
|
||||
subroutineStack.pop();
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
catch (JSException x) {
|
||||
if (mLinkage) {
|
||||
if (activation->catchStack.empty()) {
|
||||
Linkage *pLinkage = mLinkage;
|
||||
for (; pLinkage != NULL; pLinkage = pLinkage->mNext) {
|
||||
if (!pLinkage->mActivation->catchStack.empty()) {
|
||||
activation = pLinkage->mActivation;
|
||||
Handler *h = activation->catchStack.back();
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pLinkage->mBasePC;
|
||||
if (h->catchTarget) {
|
||||
pc = begin_pc + h->catchTarget->mOffset;
|
||||
}
|
||||
else {
|
||||
ASSERT(h->finallyTarget);
|
||||
pc = begin_pc + h->finallyTarget->mOffset;
|
||||
}
|
||||
mLinkage = pLinkage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pLinkage)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
Handler *h = activation->catchStack.back();
|
||||
if (h->catchTarget) {
|
||||
pc = begin_pc + h->catchTarget->mOffset;
|
||||
}
|
||||
else {
|
||||
ASSERT(h->finallyTarget);
|
||||
pc = begin_pc + h->finallyTarget->mOffset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return x.value;
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
@ -223,9 +223,10 @@ namespace JSTypes {
|
||||
}
|
||||
};
|
||||
|
||||
class JS_Exception : public gc_base {
|
||||
class JSException : public gc_base {
|
||||
public:
|
||||
JS_Exception() { }
|
||||
JSException(JSValue v) : value(v) { }
|
||||
JSValue value;
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
@ -58,9 +58,10 @@ namespace VM {
|
||||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ENDTRY, /* there is no try, only do */
|
||||
ENDTRY, /* mmm, there is no try, only do */
|
||||
GET_ELEMENT, /* dest, array, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
JSR, /* target */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
LOAD_NAME, /* dest, name */
|
||||
MOVE, /* dest, source */
|
||||
@ -71,15 +72,15 @@ namespace VM {
|
||||
NOT, /* dest, source */
|
||||
RETURN, /* return value */
|
||||
RETURN_VOID, /* Return without a value */
|
||||
RTS, /* Return to sender */
|
||||
SAVE_NAME, /* name, source */
|
||||
SET_ELEMENT, /* base, source1, source2 */
|
||||
SET_PROP, /* object, name, source */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
THROW, /* exception object */
|
||||
TRY /* catch */
|
||||
THROW, /* exception value */
|
||||
TRY, /* catch target, finally target */
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
static char *opcodeNames[] = {
|
||||
@ -102,6 +103,7 @@ namespace VM {
|
||||
"ENDTRY ",
|
||||
"GET_ELEMENT ",
|
||||
"GET_PROP ",
|
||||
"JSR ",
|
||||
"LOAD_IMMEDIATE",
|
||||
"LOAD_NAME ",
|
||||
"MOVE ",
|
||||
@ -112,6 +114,7 @@ namespace VM {
|
||||
"NOT ",
|
||||
"RETURN ",
|
||||
"RETURN_VOID ",
|
||||
"RTS ",
|
||||
"SAVE_NAME ",
|
||||
"SET_ELEMENT ",
|
||||
"SET_PROP ",
|
||||
@ -148,6 +151,7 @@ namespace VM {
|
||||
enum { NotARegister = 0xFFFFFFFF };
|
||||
enum { NotALabel = 0xFFFFFFFF };
|
||||
enum { NotAnOffset = 0xFFFFFFFF };
|
||||
enum { NotABanana = 0xFFFFFFFF };
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
@ -418,10 +422,16 @@ namespace VM {
|
||||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class EndTry : public Instruction {
|
||||
class Endtry : public Instruction {
|
||||
public:
|
||||
EndTry () :
|
||||
Instruction(ENDTRY) {};
|
||||
/* mmm, there is no try, only do */
|
||||
Endtry () :
|
||||
Instruction
|
||||
(ENDTRY) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[ENDTRY];
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class GetElement : public Instruction_3<Register, Register, Register> {
|
||||
@ -448,6 +458,18 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Jsr : public GenericBranch {
|
||||
public:
|
||||
/* target */
|
||||
Jsr (Label* aOp1) :
|
||||
GenericBranch
|
||||
(JSR, aOp1) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << mOp1->mOffset;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class LoadImmediate : public Instruction_2<Register, double> {
|
||||
public:
|
||||
/* dest, immediate value (double) */
|
||||
@ -565,6 +587,18 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Rts : public Instruction {
|
||||
public:
|
||||
/* Return to sender */
|
||||
Rts () :
|
||||
Instruction
|
||||
(RTS) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[RTS];
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class SaveName : public Instruction_2<StringAtom*, Register> {
|
||||
public:
|
||||
/* name, source */
|
||||
@ -612,6 +646,7 @@ namespace VM {
|
||||
|
||||
class Throw : public Instruction_1<Register> {
|
||||
public:
|
||||
/* exception value */
|
||||
Throw (Register aOp1) :
|
||||
Instruction_1<Register>
|
||||
(THROW, aOp1) {};
|
||||
@ -621,10 +656,16 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Try : public GenericBranch {
|
||||
class Try : public Instruction_2<Label*, Label*> {
|
||||
public:
|
||||
Try (Label *catchStart) :
|
||||
GenericBranch(TRY, catchStart) {};
|
||||
/* catch target, finally target */
|
||||
Try (Label* aOp1, Label* aOp2) :
|
||||
Instruction_2<Label*, Label*>
|
||||
(TRY, aOp1, aOp2) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[TRY] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace VM */
|
||||
|
@ -55,6 +55,26 @@ namespace ICG {
|
||||
// ICodeGenerator
|
||||
//
|
||||
|
||||
ICodeGenerator::ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting)
|
||||
: topRegister(0),
|
||||
registerBase(0),
|
||||
maxRegister(0),
|
||||
statementLabelBase(0),
|
||||
exceptionRegister(NotARegister)
|
||||
{
|
||||
iCode = new InstructionStream();
|
||||
if (hasTryStatement)
|
||||
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
|
||||
for (int i = 0; i < switchStatementNesting; i++) {
|
||||
String s = widenCString("__switchControlVariable__");
|
||||
char num[8];
|
||||
sprintf(num, "%.2d", i);
|
||||
appendChars(s, num, strlen(num));
|
||||
allocateVariable(world->identifiers[s]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ICodeModule *ICodeGenerator::complete()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@ -66,7 +86,6 @@ namespace ICG {
|
||||
ASSERT((*i)->mOffset <= iCode->size());
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
for (InstructionIterator ii = iCode->begin();
|
||||
ii != iCode->end(); ii++) {
|
||||
@ -86,10 +105,24 @@ namespace ICG {
|
||||
}
|
||||
*/
|
||||
markMaxRegister();
|
||||
|
||||
return new ICodeModule(iCode, maxRegister);
|
||||
}
|
||||
|
||||
TryCodeState::TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg)
|
||||
: ICodeState(Try_state, icg),
|
||||
catchHandler(catchLabel),
|
||||
finallyHandler(finallyLabel),
|
||||
finallyInvoker(NULL),
|
||||
beyondCatch(NULL)
|
||||
{
|
||||
if (catchHandler) {
|
||||
beyondCatch = icg->getLabel();
|
||||
if (finallyLabel)
|
||||
finallyInvoker = icg->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Register ICodeGenerator::loadImmediate(double value)
|
||||
@ -234,12 +267,6 @@ namespace ICG {
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginTry(Label *catchLabel)
|
||||
{
|
||||
Try *instr = new Try(catchLabel);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
Label *ICodeGenerator::getLabel()
|
||||
@ -679,8 +706,11 @@ namespace ICG {
|
||||
void ICodeGenerator::beginTryStatement(uint32 /* pos */,
|
||||
bool hasCatch, bool hasFinally)
|
||||
{
|
||||
addStitcher(new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this));
|
||||
ASSERT(exceptionRegister != NotARegister);
|
||||
TryCodeState *ics = new TryCodeState((hasCatch) ? getLabel() : NULL,
|
||||
(hasFinally) ? getLabel() : NULL, this);
|
||||
addStitcher(ics);
|
||||
beginTry(ics->catchHandler, ics->finallyInvoker);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endTryBlock()
|
||||
@ -688,6 +718,9 @@ namespace ICG {
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
|
||||
endTry();
|
||||
if (ics->finallyHandler)
|
||||
jsr(ics->finallyHandler);
|
||||
if (ics->beyondCatch)
|
||||
branch(ics->beyondCatch);
|
||||
}
|
||||
@ -705,30 +738,44 @@ namespace ICG {
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
ASSERT(ics->catchHandler);
|
||||
setLabel(ics->catchHandler);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchExpression(Register /* expression */)
|
||||
void ICodeGenerator::endCatchExpression(Register exceptionId)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
move(exceptionRegister, exceptionId);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endCatchStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
if (ics->finallyHandler)
|
||||
jsr(ics->finallyHandler);
|
||||
throwStatement(0, exceptionRegister);
|
||||
}
|
||||
|
||||
void ICodeGenerator::beginFinallyStatement(uint32 /* pos */)
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
ASSERT(ics->finallyHandler);
|
||||
if (ics->finallyInvoker) {
|
||||
setLabel(ics->finallyInvoker);
|
||||
jsr(ics->finallyHandler);
|
||||
throwStatement(0, exceptionRegister);
|
||||
}
|
||||
setLabel(ics->finallyHandler);
|
||||
}
|
||||
|
||||
void ICodeGenerator::endFinallyStatement()
|
||||
{
|
||||
TryCodeState *ics = static_cast<TryCodeState *>(stitcher.back());
|
||||
ASSERT(ics->stateKind == Try_state);
|
||||
rts();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -120,19 +120,25 @@ namespace ICG {
|
||||
Register registerBase;
|
||||
uint32 maxRegister;
|
||||
uint32 statementLabelBase;
|
||||
Register exceptionRegister; // reserved to carry the exception object
|
||||
|
||||
void setLabel(Label *label);
|
||||
void setLabel(InstructionStream *stream, Label *label);
|
||||
|
||||
void jsr(Label *label) { iCode->push_back(new Jsr(label)); }
|
||||
void rts() { iCode->push_back(new Rts()); }
|
||||
void branch(Label *label);
|
||||
void branchConditional(Label *label, Register condition);
|
||||
void branchNotConditional(Label *label, Register condition);
|
||||
|
||||
void beginTry(Label *catchLabel);
|
||||
void beginTry(Label *catchLabel, Label *finallyLabel)
|
||||
{ iCode->push_back(new Try(catchLabel, finallyLabel)); }
|
||||
void endTry()
|
||||
{ iCode->push_back(new Endtry()); }
|
||||
|
||||
public:
|
||||
ICodeGenerator() : topRegister(0), registerBase(0), maxRegister(0), statementLabelBase(0)
|
||||
{ iCode = new InstructionStream(); }
|
||||
ICodeGenerator() { ICodeGenerator(NULL, false, 0); }
|
||||
ICodeGenerator(World *world, bool hasTryStatement, uint32 switchStatementNesting);
|
||||
|
||||
virtual ~ICodeGenerator() { if (iCode) delete iCode; }
|
||||
|
||||
@ -142,6 +148,8 @@ namespace ICG {
|
||||
|
||||
Register allocateVariable(StringAtom& /*name*/)
|
||||
{ Register result = getRegister(); registerBase = topRegister; return result; }
|
||||
Register allocateVariable(char * /*name*/)
|
||||
{ Register result = getRegister(); registerBase = topRegister; return result; }
|
||||
|
||||
Formatter& print(Formatter& f);
|
||||
|
||||
@ -241,7 +249,7 @@ namespace ICG {
|
||||
void endTryStatement();
|
||||
|
||||
void beginCatchStatement(uint32 pos);
|
||||
void endCatchExpression(Register expression);
|
||||
void endCatchExpression(Register exceptionId);
|
||||
void endCatchStatement();
|
||||
|
||||
void beginFinallyStatement(uint32 pos);
|
||||
@ -337,14 +345,10 @@ namespace ICG {
|
||||
|
||||
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(); }
|
||||
TryCodeState(Label *catchLabel, Label *finallyLabel, ICodeGenerator *icg);
|
||||
Label *catchHandler;
|
||||
Label *finallyHandler;
|
||||
Label *finallyInvoker;
|
||||
Label *beyondCatch;
|
||||
};
|
||||
|
||||
|
@ -63,12 +63,25 @@ using namespace JSTypes;
|
||||
|
||||
// These classes are private to the JS interpreter.
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
struct Handler: public gc_base {
|
||||
Handler(Label *catchLabel, Label *finallyLabel)
|
||||
: catchTarget(catchLabel), finallyTarget(finallyLabel) {}
|
||||
Label *catchTarget;
|
||||
Label *finallyTarget;
|
||||
};
|
||||
typedef std::vector<Handler *> CatchStack;
|
||||
|
||||
|
||||
/**
|
||||
* Represents the current function's invocation state.
|
||||
*/
|
||||
struct Activation : public gc_base {
|
||||
JSValues mRegisters;
|
||||
ICodeModule* mICode;
|
||||
CatchStack catchStack;
|
||||
|
||||
Activation(ICodeModule* iCode, const JSValues& args)
|
||||
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
|
||||
@ -132,7 +145,8 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
InstructionIterator begin_pc = iCode->its_iCode->begin();
|
||||
InstructionIterator pc = begin_pc;
|
||||
|
||||
std::vector<InstructionIterator> catchStack; // <-- later will need to restore scope, other 'global' values
|
||||
// stack of all catch/finally handlers available for the current activation
|
||||
std::stack<InstructionIterator> subroutineStack; // to implement jsr/rts for finally code
|
||||
while (true) {
|
||||
try {
|
||||
// tell any listeners about the current execution state.
|
||||
@ -376,34 +390,84 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
|
||||
|
||||
case THROW :
|
||||
{
|
||||
throw new JS_Exception();
|
||||
Throw* thrw = static_cast<Throw*>(instruction);
|
||||
throw new JSException((*registers)[op1(thrw)]);
|
||||
}
|
||||
|
||||
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));
|
||||
activation->catchStack.push_back(new Handler(op1(tri), op2(tri)));
|
||||
}
|
||||
break;
|
||||
case ENDTRY :
|
||||
{
|
||||
catchStack.pop_back();
|
||||
Handler *h = activation->catchStack.back();
|
||||
activation->catchStack.pop_back();
|
||||
delete h;
|
||||
}
|
||||
break;
|
||||
|
||||
case JSR :
|
||||
{
|
||||
subroutineStack.push(++pc);
|
||||
Jsr* jsr = static_cast<Jsr*>(instruction);
|
||||
uint32 offset = ofs(jsr);
|
||||
pc = begin_pc + offset;
|
||||
continue;
|
||||
}
|
||||
case RTS :
|
||||
{
|
||||
ASSERT(!subroutineStack.empty());
|
||||
pc = subroutineStack.top();
|
||||
subroutineStack.pop();
|
||||
continue;
|
||||
}
|
||||
default:
|
||||
NOT_REACHED("bad opcode");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// increment the program counter.
|
||||
++pc;
|
||||
}
|
||||
catch (JS_Exception ) {
|
||||
ASSERT(!catchStack.empty());
|
||||
pc = catchStack.back();
|
||||
catchStack.pop_back();
|
||||
catch (JSException x) {
|
||||
if (mLinkage) {
|
||||
if (activation->catchStack.empty()) {
|
||||
Linkage *pLinkage = mLinkage;
|
||||
for (; pLinkage != NULL; pLinkage = pLinkage->mNext) {
|
||||
if (!pLinkage->mActivation->catchStack.empty()) {
|
||||
activation = pLinkage->mActivation;
|
||||
Handler *h = activation->catchStack.back();
|
||||
registers = &activation->mRegisters;
|
||||
begin_pc = pLinkage->mBasePC;
|
||||
if (h->catchTarget) {
|
||||
pc = begin_pc + h->catchTarget->mOffset;
|
||||
}
|
||||
else {
|
||||
ASSERT(h->finallyTarget);
|
||||
pc = begin_pc + h->finallyTarget->mOffset;
|
||||
}
|
||||
mLinkage = pLinkage;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pLinkage)
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
Handler *h = activation->catchStack.back();
|
||||
if (h->catchTarget) {
|
||||
pc = begin_pc + h->catchTarget->mOffset;
|
||||
}
|
||||
else {
|
||||
ASSERT(h->finallyTarget);
|
||||
pc = begin_pc + h->finallyTarget->mOffset;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return x.value;
|
||||
}
|
||||
}
|
||||
} /* interpret */
|
||||
|
@ -223,9 +223,10 @@ namespace JSTypes {
|
||||
}
|
||||
};
|
||||
|
||||
class JS_Exception : public gc_base {
|
||||
class JSException : public gc_base {
|
||||
public:
|
||||
JS_Exception() { }
|
||||
JSException(JSValue v) : value(v) { }
|
||||
JSValue value;
|
||||
};
|
||||
|
||||
} /* namespace JSTypes */
|
||||
|
@ -58,9 +58,10 @@ namespace VM {
|
||||
COMPARE_LT, /* dest, source */
|
||||
COMPARE_NE, /* dest, source */
|
||||
DIVIDE, /* dest, source1, source2 */
|
||||
ENDTRY, /* there is no try, only do */
|
||||
ENDTRY, /* mmm, there is no try, only do */
|
||||
GET_ELEMENT, /* dest, array, index */
|
||||
GET_PROP, /* dest, object, prop name */
|
||||
JSR, /* target */
|
||||
LOAD_IMMEDIATE, /* dest, immediate value (double) */
|
||||
LOAD_NAME, /* dest, name */
|
||||
MOVE, /* dest, source */
|
||||
@ -71,15 +72,15 @@ namespace VM {
|
||||
NOT, /* dest, source */
|
||||
RETURN, /* return value */
|
||||
RETURN_VOID, /* Return without a value */
|
||||
RTS, /* Return to sender */
|
||||
SAVE_NAME, /* name, source */
|
||||
SET_ELEMENT, /* base, source1, source2 */
|
||||
SET_PROP, /* object, name, source */
|
||||
SUBTRACT, /* dest, source1, source2 */
|
||||
THROW, /* exception object */
|
||||
TRY /* catch */
|
||||
THROW, /* exception value */
|
||||
TRY, /* catch target, finally target */
|
||||
};
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
static char *opcodeNames[] = {
|
||||
@ -102,6 +103,7 @@ namespace VM {
|
||||
"ENDTRY ",
|
||||
"GET_ELEMENT ",
|
||||
"GET_PROP ",
|
||||
"JSR ",
|
||||
"LOAD_IMMEDIATE",
|
||||
"LOAD_NAME ",
|
||||
"MOVE ",
|
||||
@ -112,6 +114,7 @@ namespace VM {
|
||||
"NOT ",
|
||||
"RETURN ",
|
||||
"RETURN_VOID ",
|
||||
"RTS ",
|
||||
"SAVE_NAME ",
|
||||
"SET_ELEMENT ",
|
||||
"SET_PROP ",
|
||||
@ -148,6 +151,7 @@ namespace VM {
|
||||
enum { NotARegister = 0xFFFFFFFF };
|
||||
enum { NotALabel = 0xFFFFFFFF };
|
||||
enum { NotAnOffset = 0xFFFFFFFF };
|
||||
enum { NotABanana = 0xFFFFFFFF };
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
@ -418,10 +422,16 @@ namespace VM {
|
||||
/* print() inherited from Arithmetic */
|
||||
};
|
||||
|
||||
class EndTry : public Instruction {
|
||||
class Endtry : public Instruction {
|
||||
public:
|
||||
EndTry () :
|
||||
Instruction(ENDTRY) {};
|
||||
/* mmm, there is no try, only do */
|
||||
Endtry () :
|
||||
Instruction
|
||||
(ENDTRY) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[ENDTRY];
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class GetElement : public Instruction_3<Register, Register, Register> {
|
||||
@ -448,6 +458,18 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Jsr : public GenericBranch {
|
||||
public:
|
||||
/* target */
|
||||
Jsr (Label* aOp1) :
|
||||
GenericBranch
|
||||
(JSR, aOp1) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[JSR] << "\t" << "Offset " << mOp1->mOffset;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class LoadImmediate : public Instruction_2<Register, double> {
|
||||
public:
|
||||
/* dest, immediate value (double) */
|
||||
@ -565,6 +587,18 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Rts : public Instruction {
|
||||
public:
|
||||
/* Return to sender */
|
||||
Rts () :
|
||||
Instruction
|
||||
(RTS) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[RTS];
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
class SaveName : public Instruction_2<StringAtom*, Register> {
|
||||
public:
|
||||
/* name, source */
|
||||
@ -612,6 +646,7 @@ namespace VM {
|
||||
|
||||
class Throw : public Instruction_1<Register> {
|
||||
public:
|
||||
/* exception value */
|
||||
Throw (Register aOp1) :
|
||||
Instruction_1<Register>
|
||||
(THROW, aOp1) {};
|
||||
@ -621,10 +656,16 @@ namespace VM {
|
||||
}
|
||||
};
|
||||
|
||||
class Try : public GenericBranch {
|
||||
class Try : public Instruction_2<Label*, Label*> {
|
||||
public:
|
||||
Try (Label *catchStart) :
|
||||
GenericBranch(TRY, catchStart) {};
|
||||
/* catch target, finally target */
|
||||
Try (Label* aOp1, Label* aOp2) :
|
||||
Instruction_2<Label*, Label*>
|
||||
(TRY, aOp1, aOp2) {};
|
||||
virtual Formatter& print (Formatter& f) {
|
||||
f << opcodeNames[TRY] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset;
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace VM */
|
||||
|
Loading…
Reference in New Issue
Block a user