diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 0b435cb9b44..8008f1c6a9f 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -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(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(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(stitcher.back()); ASSERT(ics->stateKind == Try_state); + move(exceptionRegister, exceptionId); } void ICodeGenerator::endCatchStatement() { TryCodeState *ics = static_cast(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(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(stitcher.back()); ASSERT(ics->stateKind == Try_state); + rts(); } /************************************************************************/ diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index 6fee678b85c..3ee746a991e 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -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; }; diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 4b3cfaa8b31..301a9b4beac 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -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 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 catchStack; // <-- later will need to restore scope, other 'global' values + // stack of all catch/finally handlers available for the current activation + std::stack 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(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(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(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 */ diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index 636e0bb912a..2cac515c61d 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -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 */ diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index 3ece4d5d16d..c82464e1cad 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -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 { @@ -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 { 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 { public: /* name, source */ @@ -612,6 +646,7 @@ namespace VM { class Throw : public Instruction_1 { public: + /* exception value */ Throw (Register aOp1) : Instruction_1 (THROW, aOp1) {}; @@ -621,10 +656,16 @@ namespace VM { } }; - class Try : public GenericBranch { + class Try : public Instruction_2 { public: - Try (Label *catchStart) : - GenericBranch(TRY, catchStart) {}; + /* catch target, finally target */ + Try (Label* aOp1, Label* aOp2) : + Instruction_2 + (TRY, aOp1, aOp2) {}; + virtual Formatter& print (Formatter& f) { + f << opcodeNames[TRY] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset; + return f; + } }; } /* namespace VM */ diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 0b435cb9b44..8008f1c6a9f 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -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(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(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(stitcher.back()); ASSERT(ics->stateKind == Try_state); + move(exceptionRegister, exceptionId); } void ICodeGenerator::endCatchStatement() { TryCodeState *ics = static_cast(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(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(stitcher.back()); ASSERT(ics->stateKind == Try_state); + rts(); } /************************************************************************/ diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index 6fee678b85c..3ee746a991e 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -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; }; diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 4b3cfaa8b31..301a9b4beac 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -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 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 catchStack; // <-- later will need to restore scope, other 'global' values + // stack of all catch/finally handlers available for the current activation + std::stack 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(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(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(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 */ diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index 636e0bb912a..2cac515c61d 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -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 */ diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index 3ece4d5d16d..c82464e1cad 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -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 { @@ -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 { 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 { public: /* name, source */ @@ -612,6 +646,7 @@ namespace VM { class Throw : public Instruction_1 { public: + /* exception value */ Throw (Register aOp1) : Instruction_1 (THROW, aOp1) {}; @@ -621,10 +656,16 @@ namespace VM { } }; - class Try : public GenericBranch { + class Try : public Instruction_2 { public: - Try (Label *catchStart) : - GenericBranch(TRY, catchStart) {}; + /* catch target, finally target */ + Try (Label* aOp1, Label* aOp2) : + Instruction_2 + (TRY, aOp1, aOp2) {}; + virtual Formatter& print (Formatter& f) { + f << opcodeNames[TRY] << "\t" << "Offset " << mOp1->mOffset << ", " << "Offset " << mOp2->mOffset; + return f; + } }; } /* namespace VM */