More exception handling handling.

This commit is contained in:
rogerl%netscape.com 2000-04-27 01:27:09 +00:00
parent a7ec34534b
commit d96a9a02a4
10 changed files with 406 additions and 92 deletions

View File

@ -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++) {
@ -85,11 +104,25 @@ namespace ICG {
}
}
*/
markMaxRegister();
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();
}
/************************************************************************/

View File

@ -111,28 +111,34 @@ namespace ICG {
stitcher.back()->registerBase; }
void addStitcher(ICodeState *ics) \
{ stitcher.push_back(ics); statementLabelBase = statementLabels.size(); }
{ stitcher.push_back(ics); statementLabelBase = statementLabels.size(); }
ICodeOp getBranchOp() \
ICodeOp getBranchOp() \
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
Register topRegister;
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;
};

View File

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

View File

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

View File

@ -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,14 +72,14 @@ 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 */
};
/********************************************************************/
@ -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 */

View File

@ -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++) {
@ -85,11 +104,25 @@ namespace ICG {
}
}
*/
markMaxRegister();
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();
}
/************************************************************************/

View File

@ -111,28 +111,34 @@ namespace ICG {
stitcher.back()->registerBase; }
void addStitcher(ICodeState *ics) \
{ stitcher.push_back(ics); statementLabelBase = statementLabels.size(); }
{ stitcher.push_back(ics); statementLabelBase = statementLabels.size(); }
ICodeOp getBranchOp() \
ICodeOp getBranchOp() \
{ return (iCode->empty()) ? NOP : iCode->back()->getBranchOp(); }
Register topRegister;
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;
};

View File

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

View File

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

View File

@ -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,14 +72,14 @@ 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 */
};
/********************************************************************/
@ -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 */