예제 #1
0
        static object InterpretLoop (Context cx, CallFrame frame, object throwable)
        {
            // throwable holds exception object to rethrow or catch
            // It is also used for continuation restart in which case
            // it holds ContinuationJump

            object DBL_MRK = UniqueTag.DoubleMark;
            object undefined = Undefined.Value;

            bool instructionCounting = (cx.instructionThreshold != 0);
            // arbitrary number to add to instructionCount when calling
            // other functions			
            const int INVOCATION_COST = 100;

            // arbitrary exception cost for instruction counting			
            const int EXCEPTION_COST = 100;

            string stringReg = null;
            int indexReg = -1;

            if (cx.lastInterpreterFrame != null) {
                // save the top frame from the previous interpreterLoop
                // invocation on the stack
                if (cx.previousInterpreterInvocations == null) {
                    cx.previousInterpreterInvocations = new ObjArray ();
                }
                cx.previousInterpreterInvocations.push (cx.lastInterpreterFrame);
            }

            // When restarting continuation throwable is not null and to jump
            // to the code that rewind continuation state indexReg should be set
            // to -1.
            // With the normal call throable == null and indexReg == -1 allows to
            // catch bugs with using indeReg to access array eleemnts before
            // initializing indexReg.

            if (throwable != null) {
                // Assert assumptions
                if (!(throwable is ContinuationJump)) {
                    // It should be continuation
                    Context.CodeBug ();
                }
            }

            object interpreterResult = null;
            double interpreterResultDbl = 0.0;

            for (; ; ) {

                try {

                    if (throwable != null) {
                        // Recovering from exception, indexReg contains
                        // the index of handler

                        if (indexReg >= 0) {
                            // Normal excepton handler, transfer
                            // control appropriately

                            if (frame.frozen) {
                                // TODO: Deal with exceptios!!!
                                frame = frame.cloneFrozen ();
                            }

                            int [] table = frame.idata.itsExceptionTable;

                            frame.pc = table [indexReg + EXCEPTION_HANDLER_SLOT];
                            if (instructionCounting) {
                                frame.pcPrevBranch = frame.pc;
                            }

                            frame.savedStackTop = frame.emptyStackTop;
                            int scopeLocal = frame.localShift + table [indexReg + EXCEPTION_SCOPE_SLOT];
                            int exLocal = frame.localShift + table [indexReg + EXCEPTION_LOCAL_SLOT];
                            frame.scope = (IScriptable)frame.stack [scopeLocal];
                            frame.stack [exLocal] = throwable;

                            throwable = null;
                        }
                        else {
                            // Continuation restoration
                            ContinuationJump cjump = (ContinuationJump)throwable;

                            // Clear throwable to indicate that execptions are OK
                            throwable = null;

                            if (cjump.branchFrame != frame)
                                Context.CodeBug ();

                            // Check that we have at least one frozen frame
                            // in the case of detached continuation restoration:
                            // unwind code ensure that
                            if (cjump.capturedFrame == null)
                                Context.CodeBug ();

                            // Need to rewind branchFrame, capturedFrame
                            // and all frames in between
                            int rewindCount = cjump.capturedFrame.frameIndex + 1;
                            if (cjump.branchFrame != null) {
                                rewindCount -= cjump.branchFrame.frameIndex;
                            }

                            int enterCount = 0;
                            CallFrame [] enterFrames = null;

                            CallFrame x = cjump.capturedFrame;
                            for (int i = 0; i != rewindCount; ++i) {
                                if (!x.frozen)
                                    Context.CodeBug ();
                                if (isFrameEnterExitRequired (x)) {
                                    if (enterFrames == null) {
                                        // Allocate enough space to store the rest
                                        // of rewind frames in case all of them
                                        // would require to enter
                                        enterFrames = new CallFrame [rewindCount - i];
                                    }
                                    enterFrames [enterCount] = x;
                                    ++enterCount;
                                }
                                x = x.parentFrame;
                            }

                            while (enterCount != 0) {
                                // execute enter: walk enterFrames in the reverse
                                // order since they were stored starting from
                                // the capturedFrame, not branchFrame
                                --enterCount;
                                x = enterFrames [enterCount];
                                EnterFrame (cx, x, ScriptRuntime.EmptyArgs);
                            }

                            // Continuation jump is almost done: capturedFrame
                            // points to the call to the function that captured
                            // continuation, so clone capturedFrame and
                            // emulate return that function with the suplied result
                            frame = cjump.capturedFrame.cloneFrozen ();
                            setCallResult (frame, cjump.result, cjump.resultDbl);
                            // restart the execution
                        }

                        // Should be already cleared
                        if (throwable != null)
                            Context.CodeBug ();
                    }
                    else {
                        if (frame.frozen)
                            Context.CodeBug ();
                    }

                    // Use local variables for constant values in frame
                    // for faster access					
                    object [] stack = frame.stack;
                    double [] sDbl = frame.sDbl;
                    object [] vars = frame.varSource.stack;
                    double [] varDbls = frame.varSource.sDbl;

                    sbyte [] iCode = frame.idata.itsICode;
                    string [] strings = frame.idata.itsStringTable;

                    // Use local for stackTop as well. Since execption handlers
                    // can only exist at statement level where stack is empty,
                    // it is necessary to save/restore stackTop only accross
                    // function calls and normal returns.
                    int stackTop = frame.savedStackTop;

                    // Store new frame in cx which is used for error reporting etc.
                    cx.lastInterpreterFrame = frame;

                    for (; ; ) {

                        // Exception handler assumes that PC is already incremented
                        // pass the instruction start when it searches the
                        // exception handler
                        int op = iCode [frame.pc++];                                                
                        {
                            switch (op) {

                                case Token.THROW: {
                                        object value = stack [stackTop];
                                        if (value == DBL_MRK)
                                            value = sDbl [stackTop];
                                        stackTop--;

                                        int sourceLine = GetIndex (iCode, frame.pc);
                                        throwable = new EcmaScriptThrow (
                                            value, frame.idata.itsSourceFile, sourceLine);
                                        goto withoutExceptions_brk;
                                    }

                                case Token.RETHROW: {
                                        indexReg += frame.localShift;
                                        throwable = stack [indexReg];
                                        break;
                                    }

                                case Token.GE:
                                case Token.LE:
                                case Token.GT:
                                case Token.LT: {
                                        --stackTop;
                                        object rhs = stack [stackTop + 1];
                                        object lhs = stack [stackTop];
                                        bool valBln;
                                        {
                                            {
                                                double rDbl, lDbl;
                                                if (rhs == DBL_MRK) {
                                                    rDbl = sDbl [stackTop + 1];
                                                    lDbl = stack_double (frame, stackTop);
                                                }
                                                else if (lhs == DBL_MRK) {
                                                    rDbl = ScriptConvert.ToNumber (rhs);
                                                    lDbl = sDbl [stackTop];
                                                }
                                                else {

                                                    goto number_compare_brk;
                                                }
                                                switch (op) {

                                                    case Token.GE:
                                                        valBln = (lDbl >= rDbl);

                                                        goto object_compare_brk;

                                                    case Token.LE:
                                                        valBln = (lDbl <= rDbl);

                                                        goto object_compare_brk;

                                                    case Token.GT:
                                                        valBln = (lDbl > rDbl);

                                                        goto object_compare_brk;

                                                    case Token.LT:
                                                        valBln = (lDbl < rDbl);

                                                        goto object_compare_brk;

                                                    default:
                                                        throw Context.CodeBug ();

                                                }
                                            }

                                        number_compare_brk:
                                            ;

                                            switch (op) {

                                                case Token.GE:
                                                    valBln = ScriptRuntime.cmp_LE (rhs, lhs);
                                                    break;

                                                case Token.LE:
                                                    valBln = ScriptRuntime.cmp_LE (lhs, rhs);
                                                    break;

                                                case Token.GT:
                                                    valBln = ScriptRuntime.cmp_LT (rhs, lhs);
                                                    break;

                                                case Token.LT:
                                                    valBln = ScriptRuntime.cmp_LT (lhs, rhs);
                                                    break;

                                                default:
                                                    throw Context.CodeBug ();

                                            }
                                        }

                                    object_compare_brk:
                                        ;

                                        stack [stackTop] = valBln;

                                        goto Loop;
                                    }
                                    goto case Token.IN;

                                case Token.IN:
                                case Token.INSTANCEOF: {
                                        object rhs = stack [stackTop];
                                        if (rhs == DBL_MRK)
                                            rhs = sDbl [stackTop];
                                        --stackTop;
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        bool valBln;
                                        if (op == Token.IN) {
                                            valBln = ScriptRuntime.In (lhs, rhs, cx);
                                        }
                                        else {
                                            valBln = ScriptRuntime.InstanceOf (lhs, rhs, cx);
                                        }
                                        stack [stackTop] = valBln;

                                        goto Loop;
                                    }
                                    goto case Token.EQ;

                                case Token.EQ:
                                case Token.NE: {
                                        --stackTop;
                                        bool valBln;
                                        object rhs = stack [stackTop + 1];
                                        object lhs = stack [stackTop];
                                        if (rhs == DBL_MRK) {
                                            if (lhs == DBL_MRK) {
                                                valBln = (sDbl [stackTop] == sDbl [stackTop + 1]);
                                            }
                                            else {
                                                valBln = ScriptRuntime.eqNumber (sDbl [stackTop + 1], lhs);
                                            }
                                        }
                                        else {
                                            if (lhs == DBL_MRK) {
                                                valBln = ScriptRuntime.eqNumber (sDbl [stackTop], rhs);
                                            }
                                            else {
                                                valBln = ScriptRuntime.eq (lhs, rhs);
                                            }
                                        }
                                        valBln ^= (op == Token.NE);
                                        stack [stackTop] = valBln;

                                        goto Loop;
                                    }
                                    goto case Token.SHEQ;

                                case Token.SHEQ:
                                case Token.SHNE: {
                                        --stackTop;
                                        object rhs = stack [stackTop + 1];
                                        object lhs = stack [stackTop];
                                        bool valBln;
                                        {
                                            double rdbl, ldbl;
                                            if (rhs == DBL_MRK) {
                                                rdbl = sDbl [stackTop + 1];
                                                if (lhs == DBL_MRK) {
                                                    ldbl = sDbl [stackTop];
                                                }
                                                else if (CliHelper.IsNumber (lhs)) {
                                                    ldbl = Convert.ToDouble (lhs);
                                                }
                                                else {
                                                    valBln = false;

                                                    goto shallow_compare_brk;
                                                }
                                            }
                                            else if (lhs == DBL_MRK) {
                                                ldbl = sDbl [stackTop];
                                                if (rhs == DBL_MRK) {
                                                    rdbl = sDbl [stackTop + 1];
                                                }
                                                else if (CliHelper.IsNumber (rhs)) {
                                                    rdbl = Convert.ToDouble (rhs);
                                                }
                                                else {
                                                    valBln = false;

                                                    goto shallow_compare_brk;
                                                }
                                            }
                                            else {
                                                valBln = ScriptRuntime.shallowEq (lhs, rhs);

                                                goto shallow_compare_brk;
                                            }
                                            valBln = (ldbl == rdbl);
                                        }

                                    shallow_compare_brk:
                                        ;

                                        valBln ^= (op == Token.SHNE);
                                        stack [stackTop] = valBln;

                                        goto Loop;
                                    }
                                    goto case Token.IFNE;

                                case Token.IFNE:
                                    if (stack_boolean (frame, stackTop--)) {
                                        frame.pc += 2;

                                        goto Loop;
                                    }

                                    goto jumplessRun_brk;

                                case Token.IFEQ:
                                    if (!stack_boolean (frame, stackTop--)) {
                                        frame.pc += 2;

                                        goto Loop;
                                    }

                                    goto jumplessRun_brk;

                                case Icode_IFEQ_POP:
                                    if (!stack_boolean (frame, stackTop--)) {
                                        frame.pc += 2;

                                        goto Loop;
                                    }
                                    stack [stackTop--] = null;

                                    goto jumplessRun_brk;

                                case Token.GOTO:

                                    goto jumplessRun_brk;

                                case Icode_GOSUB:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = frame.pc + 2;

                                    goto jumplessRun_brk;

                                case Icode_STARTSUB:
                                    if (stackTop == frame.emptyStackTop + 1) {
                                        // Call from Icode_GOSUB: store return PC address in the local
                                        indexReg += frame.localShift;
                                        stack [indexReg] = stack [stackTop];
                                        sDbl [indexReg] = sDbl [stackTop];
                                        --stackTop;
                                    }
                                    else {
                                        // Call from exception handler: exception object is already stored
                                        // in the local
                                        if (stackTop != frame.emptyStackTop)
                                            Context.CodeBug ();
                                    }

                                    goto Loop;
                                    goto case Icode_RETSUB;

                                case Icode_RETSUB: {
                                        // indexReg: local to store return address
                                        if (instructionCounting) {
                                            addInstructionCount (cx, frame, 0);
                                        }
                                        indexReg += frame.localShift;
                                        object value = stack [indexReg];
                                        if (value != DBL_MRK) {
                                            // Invocation from exception handler, restore object to rethrow
                                            throwable = value;
                                            goto withoutExceptions_brk;
                                        }
                                        // Normal return from GOSUB									
                                        frame.pc = (int)sDbl [indexReg];
                                        if (instructionCounting) {
                                            frame.pcPrevBranch = frame.pc;
                                        }

                                        goto Loop;
                                    }
                                    goto case Icode_POP;

                                case Icode_POP:
                                    stack [stackTop] = null;
                                    stackTop--;

                                    goto Loop;
                                    goto case Icode_POP_RESULT;

                                case Icode_POP_RESULT:
                                    frame.result = stack [stackTop];
                                    frame.resultDbl = sDbl [stackTop];
                                    stack [stackTop] = null;
                                    --stackTop;

                                    goto Loop;
                                    goto case Icode_DUP;

                                case Icode_DUP:
                                    stack [stackTop + 1] = stack [stackTop];
                                    sDbl [stackTop + 1] = sDbl [stackTop];
                                    stackTop++;

                                    goto Loop;
                                    goto case Icode_DUP2;

                                case Icode_DUP2:
                                    stack [stackTop + 1] = stack [stackTop - 1];
                                    sDbl [stackTop + 1] = sDbl [stackTop - 1];
                                    stack [stackTop + 2] = stack [stackTop];
                                    sDbl [stackTop + 2] = sDbl [stackTop];
                                    stackTop += 2;

                                    goto Loop;
                                    goto case Icode_SWAP;

                                case Icode_SWAP: {
                                        object o = stack [stackTop];
                                        stack [stackTop] = stack [stackTop - 1];
                                        stack [stackTop - 1] = o;
                                        double d = sDbl [stackTop];
                                        sDbl [stackTop] = sDbl [stackTop - 1];
                                        sDbl [stackTop - 1] = d;

                                        goto Loop;
                                    }
                                    goto case Token.RETURN;

                                case Token.RETURN:
                                    frame.result = stack [stackTop];
                                    frame.resultDbl = sDbl [stackTop];
                                    --stackTop;

                                    goto Loop_brk;

                                case Token.RETURN_RESULT:

                                    goto Loop_brk;

                                case Icode_RETUNDEF:
                                    frame.result = undefined;

                                    goto Loop_brk;

                                case Token.BITNOT: {
                                        int rIntValue = stack_int32 (frame, stackTop);
                                        stack [stackTop] = DBL_MRK;
                                        sDbl [stackTop] = ~rIntValue;

                                        goto Loop;
                                    }
                                    goto case Token.BITAND;

                                case Token.BITAND:
                                case Token.BITOR:
                                case Token.BITXOR:
                                case Token.LSH:
                                case Token.RSH: {
                                        int rIntValue = stack_int32 (frame, stackTop);
                                        --stackTop;
                                        int lIntValue = stack_int32 (frame, stackTop);
                                        stack [stackTop] = DBL_MRK;
                                        switch (op) {

                                            case Token.BITAND:
                                                lIntValue &= rIntValue;
                                                break;

                                            case Token.BITOR:
                                                lIntValue |= rIntValue;
                                                break;

                                            case Token.BITXOR:
                                                lIntValue ^= rIntValue;
                                                break;

                                            case Token.LSH:
                                                lIntValue <<= rIntValue;
                                                break;

                                            case Token.RSH:
                                                lIntValue >>= rIntValue;
                                                break;
                                        }
                                        sDbl [stackTop] = lIntValue;

                                        goto Loop;
                                    }
                                    goto case Token.URSH;

                                case Token.URSH: {
                                        int rIntValue = stack_int32 (frame, stackTop) & 0x1F;
                                        --stackTop;
                                        double lDbl = stack_double (frame, stackTop);
                                        stack [stackTop] = DBL_MRK;
                                        uint i = (uint)ScriptConvert.ToUint32 (lDbl);
                                        sDbl [stackTop] = i >> rIntValue;

                                        goto Loop;
                                    }
                                    goto case Token.NEG;

                                case Token.NEG:
                                case Token.POS: {
                                        double rDbl = stack_double (frame, stackTop);
                                        stack [stackTop] = DBL_MRK;
                                        if (op == Token.NEG) {
                                            rDbl = -rDbl;
                                        }
                                        sDbl [stackTop] = rDbl;

                                        goto Loop;
                                    }
                                    goto case Token.ADD;

                                case Token.ADD:
                                    --stackTop;
                                    DoAdd (stack, sDbl, stackTop, cx);

                                    goto Loop;
                                    goto case Token.SUB;

                                case Token.SUB:
                                case Token.MUL:
                                case Token.DIV:
                                case Token.MOD: {
                                        double rDbl = stack_double (frame, stackTop);
                                        --stackTop;
                                        double lDbl = stack_double (frame, stackTop);
                                        stack [stackTop] = DBL_MRK;
                                        switch (op) {

                                            case Token.SUB:
                                                lDbl -= rDbl;
                                                break;

                                            case Token.MUL:
                                                lDbl *= rDbl;
                                                break;

                                            case Token.DIV:
                                                lDbl /= rDbl;
                                                break;

                                            case Token.MOD:
                                                lDbl %= rDbl;
                                                break;
                                        }
                                        sDbl [stackTop] = lDbl;

                                        goto Loop;
                                    }
                                    goto case Token.NOT;

                                case Token.NOT:
                                    stack [stackTop] = !stack_boolean (frame, stackTop);

                                    goto Loop;
                                    goto case Token.BINDNAME;

                                case Token.BINDNAME:
                                    stack [++stackTop] = ScriptRuntime.bind (cx, frame.scope, stringReg);

                                    goto Loop;
                                    goto case Token.SETNAME;

                                case Token.SETNAME: {
                                        object rhs = stack [stackTop];
                                        if (rhs == DBL_MRK)
                                            rhs = sDbl [stackTop];
                                        --stackTop;
                                        IScriptable lhs = (IScriptable)stack [stackTop];
                                        stack [stackTop] = ScriptRuntime.setName (lhs, rhs, cx, frame.scope, stringReg);

                                        goto Loop;
                                    }
                                    goto case Token.DELPROP;

                                case Token.DELPROP: {
                                        object rhs = stack [stackTop];
                                        if (rhs == DBL_MRK)
                                            rhs = sDbl [stackTop];
                                        --stackTop;
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.delete (lhs, rhs, cx);

                                        goto Loop;
                                    }
                                    goto case Token.GETPROP;

                                case Token.GETPROP: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.getObjectProp (lhs, stringReg, cx);

                                        goto Loop;
                                    }
                                    goto case Token.SETPROP;

                                case Token.SETPROP_GETTER:
                                case Token.SETPROP_SETTER:
                                case Token.SETPROP: {
                                        object rhs = stack [stackTop];
                                        if (rhs == DBL_MRK)
                                            rhs = sDbl [stackTop];
                                        --stackTop;
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];

                                        switch (op) {
                                            case Token.SETPROP_GETTER:
                                                ((ScriptableObject)lhs).DefineGetter(stringReg, ((ICallable)rhs));
                                                stack[stackTop] = rhs;
                                                break;

                                            case Token.SETPROP_SETTER:
                                                ((ScriptableObject)lhs).DefineSetter(stringReg, ((ICallable)rhs));
                                                stack[stackTop] = rhs;
                                                break;


                                            default:
                                                stack [stackTop] = ScriptRuntime.setObjectProp (lhs, stringReg, rhs, cx);
                                                break;
                                        }

                                        goto Loop;
                                    }
                                    goto case Icode_PROP_INC_DEC;

                                case Icode_PROP_INC_DEC: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.propIncrDecr (lhs, stringReg, cx, iCode [frame.pc]);
                                        ++frame.pc;

                                        goto Loop;
                                    }
                                    goto case Token.GETELEM;

                                case Token.GETELEM: {
                                        --stackTop;
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK) {
                                            lhs = sDbl [stackTop];
                                        }
                                        object value;
                                        object id = stack [stackTop + 1];
                                        if (id != DBL_MRK) {
                                            value = ScriptRuntime.getObjectElem (lhs, id, cx);
                                        }
                                        else {
                                            double d = sDbl [stackTop + 1];
                                            value = ScriptRuntime.getObjectIndex (lhs, d, cx);
                                        }
                                        stack [stackTop] = value;

                                        goto Loop;
                                    }
                                    goto case Token.SETELEM;

                                case Token.SETELEM: {
                                        stackTop -= 2;
                                        object rhs = stack [stackTop + 2];
                                        if (rhs == DBL_MRK) {
                                            rhs = sDbl [stackTop + 2];
                                        }
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK) {
                                            lhs = sDbl [stackTop];
                                        }
                                        object value;
                                        object id = stack [stackTop + 1];
                                        if (id != DBL_MRK) {
                                            value = ScriptRuntime.setObjectElem (lhs, id, rhs, cx);
                                        }
                                        else {
                                            double d = sDbl [stackTop + 1];
                                            value = ScriptRuntime.setObjectIndex (lhs, d, rhs, cx);
                                        }
                                        stack [stackTop] = value;

                                        goto Loop;
                                    }
                                    goto case Icode_ELEM_INC_DEC;

                                case Icode_ELEM_INC_DEC: {
                                        object rhs = stack [stackTop];
                                        if (rhs == DBL_MRK)
                                            rhs = sDbl [stackTop];
                                        --stackTop;
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.elemIncrDecr (lhs, rhs, cx, iCode [frame.pc]);
                                        ++frame.pc;

                                        goto Loop;
                                    }
                                    goto case Token.GET_REF;

                                case Token.GET_REF: {
                                        IRef rf = (IRef)stack [stackTop];
                                        stack [stackTop] = ScriptRuntime.refGet (rf, cx);

                                        goto Loop;
                                    }
                                    goto case Token.SET_REF;

                                case Token.SET_REF: {
                                        object value = stack [stackTop];
                                        if (value == DBL_MRK)
                                            value = sDbl [stackTop];
                                        --stackTop;
                                        IRef rf = (IRef)stack [stackTop];
                                        stack [stackTop] = ScriptRuntime.refSet (rf, value, cx);

                                        goto Loop;
                                    }
                                    goto case Token.DEL_REF;

                                case Token.DEL_REF: {
                                        IRef rf = (IRef)stack [stackTop];
                                        stack [stackTop] = ScriptRuntime.refDel (rf, cx);

                                        goto Loop;
                                    }
                                    goto case Icode_REF_INC_DEC;

                                case Icode_REF_INC_DEC: {
                                        IRef rf = (IRef)stack [stackTop];
                                        stack [stackTop] = ScriptRuntime.refIncrDecr (rf, cx, iCode [frame.pc]);
                                        ++frame.pc;

                                        goto Loop;
                                    }
                                    goto case Token.LOCAL_LOAD;

                                case Token.LOCAL_LOAD:
                                    ++stackTop;
                                    indexReg += frame.localShift;
                                    stack [stackTop] = stack [indexReg];
                                    sDbl [stackTop] = sDbl [indexReg];

                                    goto Loop;
                                    goto case Icode_LOCAL_CLEAR;

                                case Icode_LOCAL_CLEAR:
                                    indexReg += frame.localShift;
                                    stack [indexReg] = null;

                                    goto Loop;
                                    goto case Icode_NAME_AND_THIS;

                                case Icode_NAME_AND_THIS:
                                    // stringReg: name
                                    ++stackTop;
                                    stack [stackTop] = ScriptRuntime.getNameFunctionAndThis (stringReg, cx, frame.scope);
                                    ++stackTop;
                                    stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);

                                    goto Loop;
                                    goto case Icode_PROP_AND_THIS;

                                case Icode_PROP_AND_THIS: {                                        
                                        object obj = stack [stackTop];                                        
                                        if (obj == DBL_MRK)
                                            obj = sDbl [stackTop];                                        
                                        // stringReg: property
                                        stack [stackTop] = ScriptRuntime.getPropFunctionAndThis (obj, stringReg, cx);
                                        ++stackTop;
                                        stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);

                                        goto Loop;
                                    }
                                    goto case Icode_ELEM_AND_THIS;

                                case Icode_ELEM_AND_THIS: {
                                        object obj = stack [stackTop - 1];
                                        if (obj == DBL_MRK)
                                            obj = sDbl [stackTop - 1];
                                        object id = stack [stackTop];
                                        if (id == DBL_MRK)
                                            id = sDbl [stackTop];
                                        stack [stackTop - 1] = ScriptRuntime.GetElemFunctionAndThis (obj, id, cx);
                                        stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);

                                        goto Loop;
                                    }
                                    goto case Icode_VALUE_AND_THIS;

                                case Icode_VALUE_AND_THIS: {
                                        object value = stack [stackTop];
                                        if (value == DBL_MRK)
                                            value = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.getValueFunctionAndThis (value, cx);
                                        ++stackTop;
                                        stack [stackTop] = ScriptRuntime.lastStoredScriptable (cx);

                                        goto Loop;
                                    }
                                    goto case Icode_CALLSPECIAL;

                                case Icode_CALLSPECIAL: {
                                        if (instructionCounting) {
                                            cx.instructionCount += INVOCATION_COST;
                                        }
                                        int callType = iCode [frame.pc] & 0xFF;
                                        bool isNew = (iCode [frame.pc + 1] != 0);
                                        int sourceLine = GetIndex (iCode, frame.pc + 2);

                                        // indexReg: number of arguments
                                        if (isNew) {
                                            // stack change: function arg0 .. argN -> newResult
                                            stackTop -= indexReg;

                                            object function = stack [stackTop];
                                            if (function == DBL_MRK)
                                                function = sDbl [stackTop];
                                            object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
                                            stack [stackTop] = ScriptRuntime.newSpecial (cx, function, outArgs, frame.scope, callType);
                                        }
                                        else {
                                            // stack change: function thisObj arg0 .. argN -> result
                                            stackTop -= (1 + indexReg);

                                            // Call code generation ensure that stack here
                                            // is ... Callable Scriptable
                                            IScriptable functionThis = (IScriptable)stack [stackTop + 1];
                                            ICallable function = (ICallable)stack [stackTop];
                                            object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
                                            stack [stackTop] = ScriptRuntime.callSpecial (cx, function, functionThis, outArgs, frame.scope, frame.thisObj, callType, frame.idata.itsSourceFile, sourceLine);
                                        }
                                        frame.pc += 4;

                                        goto Loop;
                                    }
                                    goto case Token.CALL;

                                case Token.CALL:
                                case Icode_TAIL_CALL:
                                case Token.REF_CALL: {
                                        if (instructionCounting) {
                                            cx.instructionCount += INVOCATION_COST;
                                        }
                                        // stack change: function thisObj arg0 .. argN -> result
                                        // indexReg: number of arguments
                                        stackTop -= (1 + indexReg);

                                        // CALL generation ensures that fun and funThisObj
                                        // are already Scriptable and Callable objects respectively
                                        ICallable fun = (ICallable)stack [stackTop];
                                        IScriptable funThisObj = (IScriptable)stack [stackTop + 1];
                                        if (op == Token.REF_CALL) {
                                            object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
                                            stack [stackTop] = ScriptRuntime.callRef (fun, funThisObj, outArgs, cx);

                                            goto Loop;
                                        }
                                        IScriptable calleeScope = frame.scope;
                                        if (frame.useActivation) {
                                            calleeScope = ScriptableObject.GetTopLevelScope (frame.scope);
                                        }
                                        if (fun is InterpretedFunction) {
                                            InterpretedFunction ifun = (InterpretedFunction)fun;
                                            if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
                                                CallFrame callParentFrame = frame;
                                                CallFrame calleeFrame = new CallFrame ();
                                                if (op == Icode_TAIL_CALL) {
                                                    // In principle tail call can re-use the current
                                                    // frame and its stack arrays but it is hard to
                                                    // do properly. Any exceptions that can legally
                                                    // happen during frame re-initialization including
                                                    // StackOverflowException during innocent looking
                                                    // System.arraycopy may leave the current frame
                                                    // data corrupted leading to undefined behaviour
                                                    // in the catch code bellow that unwinds JS stack
                                                    // on exceptions. Then there is issue about frame release
                                                    // end exceptions there.
                                                    // To avoid frame allocation a released frame
                                                    // can be cached for re-use which would also benefit
                                                    // non-tail calls but it is not clear that this caching
                                                    // would gain in performance due to potentially
                                                    // bad iteraction with GC.
                                                    callParentFrame = frame.parentFrame;
                                                }
                                                initFrame (cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame);
                                                if (op == Icode_TAIL_CALL) {
                                                    // Release the parent
                                                    ExitFrame (cx, frame, (object)null);
                                                }
                                                else {
                                                    frame.savedStackTop = stackTop;
                                                    frame.savedCallOp = op;
                                                }
                                                frame = calleeFrame;

                                                goto StateLoop;
                                            }
                                        }

                                        if (fun is Continuation) {
                                            // Jump to the captured continuation
                                            ContinuationJump cjump;
                                            cjump = new ContinuationJump ((Continuation)fun, frame);

                                            // continuation result is the first argument if any
                                            // of contination call
                                            if (indexReg == 0) {
                                                cjump.result = undefined;
                                            }
                                            else {
                                                cjump.result = stack [stackTop + 2];
                                                cjump.resultDbl = sDbl [stackTop + 2];
                                            }

                                            // Start the real unwind job
                                            throwable = cjump;
                                            break;
                                        }

                                        if (fun is IdFunctionObject) {
                                            IdFunctionObject ifun = (IdFunctionObject)fun;
                                            if (Continuation.IsContinuationConstructor (ifun)) {
                                                captureContinuation (cx, frame, stackTop);

                                                goto Loop;
                                            }
                                        }

                                        object [] outArgs2 = GetArgsArray (stack, sDbl, stackTop + 2, indexReg);
                                        stack [stackTop] = fun.Call (cx, calleeScope, funThisObj, outArgs2);


                                        goto Loop;
                                    }
                                    goto case Token.NEW;

                                case Token.NEW: {
                                        if (instructionCounting) {
                                            cx.instructionCount += INVOCATION_COST;
                                        }
                                        // stack change: function arg0 .. argN -> newResult
                                        // indexReg: number of arguments
                                        stackTop -= indexReg;

                                        object lhs = stack [stackTop];
                                        if (lhs is InterpretedFunction) {
                                            InterpretedFunction f = (InterpretedFunction)lhs;
                                            if (frame.fnOrScript.securityDomain == f.securityDomain) {
                                                IScriptable newInstance = f.CreateObject (cx, frame.scope);
                                                CallFrame calleeFrame = new CallFrame ();
                                                initFrame (cx, frame.scope, newInstance, stack, sDbl, stackTop + 1, indexReg, f, frame, calleeFrame);

                                                stack [stackTop] = newInstance;
                                                frame.savedStackTop = stackTop;
                                                frame.savedCallOp = op;
                                                frame = calleeFrame;

                                                goto StateLoop;
                                            }
                                        }
                                        if (!(lhs is IFunction)) {
                                            if (lhs == DBL_MRK)
                                                lhs = sDbl [stackTop];
                                            throw ScriptRuntime.NotFunctionError (lhs);
                                        }
                                        IFunction fun = (IFunction)lhs;

                                        if (fun is IdFunctionObject) {
                                            IdFunctionObject ifun = (IdFunctionObject)fun;
                                            if (Continuation.IsContinuationConstructor (ifun)) {
                                                captureContinuation (cx, frame, stackTop);

                                                goto Loop;
                                            }
                                        }

                                        object [] outArgs = GetArgsArray (stack, sDbl, stackTop + 1, indexReg);
                                        stack [stackTop] = fun.Construct (cx, frame.scope, outArgs);

                                        goto Loop;
                                    }
                                    goto case Token.TYPEOF;

                                case Token.TYPEOF: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.Typeof (lhs);

                                        goto Loop;
                                    }
                                    goto case Icode_TYPEOFNAME;

                                case Icode_TYPEOFNAME:
                                    stack [++stackTop] = ScriptRuntime.TypeofName (frame.scope, stringReg);

                                    goto Loop;
                                    goto case Token.STRING;

                                case Token.STRING:
                                    stack [++stackTop] = stringReg;

                                    goto Loop;
                                    goto case Icode_SHORTNUMBER;

                                case Icode_SHORTNUMBER:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = GetShort (iCode, frame.pc);
                                    frame.pc += 2;

                                    goto Loop;
                                    goto case Icode_INTNUMBER;

                                case Icode_INTNUMBER:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = GetInt (iCode, frame.pc);
                                    frame.pc += 4;

                                    goto Loop;
                                    goto case Token.NUMBER;

                                case Token.NUMBER:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = frame.idata.itsDoubleTable [indexReg];

                                    goto Loop;
                                    goto case Token.NAME;

                                case Token.NAME:
                                    stack [++stackTop] = ScriptRuntime.name (cx, frame.scope, stringReg);

                                    goto Loop;
                                    goto case Icode_NAME_INC_DEC;

                                case Icode_NAME_INC_DEC:
                                    stack [++stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, stringReg, iCode [frame.pc]);
                                    ++frame.pc;

                                    goto Loop;
                                    goto case Icode_SETVAR1;

                                case Icode_SETVAR1:
                                    indexReg = iCode [frame.pc++];
                                    // fallthrough
                                    goto case Token.SETVAR;

                                case Token.SETVAR:
                                    if (!frame.useActivation) {
                                        vars [indexReg] = stack [stackTop];
                                        varDbls [indexReg] = sDbl [stackTop];
                                    }
                                    else {
                                        object val = stack [stackTop];
                                        if (val == DBL_MRK)
                                            val = sDbl [stackTop];
                                        stringReg = frame.idata.argNames [indexReg];
                                        frame.scope.Put (stringReg, frame.scope, val);
                                    }

                                    goto Loop;
                                    goto case Icode_GETVAR1;

                                case Icode_GETVAR1:
                                    indexReg = iCode [frame.pc++];
                                    // fallthrough
                                    goto case Token.GETVAR;

                                case Token.GETVAR:
                                    ++stackTop;
                                    if (!frame.useActivation) {
                                        stack [stackTop] = vars [indexReg];
                                        sDbl [stackTop] = varDbls [indexReg];
                                    }
                                    else {
                                        stringReg = frame.idata.argNames [indexReg];
                                        stack [stackTop] = frame.scope.Get (stringReg, frame.scope);
                                    }

                                    goto Loop;
                                    goto case Icode_VAR_INC_DEC;

                                case Icode_VAR_INC_DEC: {
                                        // indexReg : varindex
                                        ++stackTop;
                                        int incrDecrMask = iCode [frame.pc];
                                        if (!frame.useActivation) {
                                            stack [stackTop] = DBL_MRK;
                                            object varValue = vars [indexReg];
                                            double d;
                                            if (varValue == DBL_MRK) {
                                                d = varDbls [indexReg];
                                            }
                                            else {
                                                d = ScriptConvert.ToNumber (varValue);
                                                vars [indexReg] = DBL_MRK;
                                            }
                                            double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0) ? d + 1.0 : d - 1.0;
                                            varDbls [indexReg] = d2;
                                            sDbl [stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
                                        }
                                        else {
                                            string varName = frame.idata.argNames [indexReg];
                                            stack [stackTop] = ScriptRuntime.nameIncrDecr (frame.scope, varName, incrDecrMask);
                                        }
                                        ++frame.pc;

                                        goto Loop;
                                    }
                                    goto case Icode_ZERO;

                                case Icode_ZERO:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = 0;

                                    goto Loop;
                                    goto case Icode_ONE;

                                case Icode_ONE:
                                    ++stackTop;
                                    stack [stackTop] = DBL_MRK;
                                    sDbl [stackTop] = 1;

                                    goto Loop;
                                    goto case Token.NULL;

                                case Token.NULL:
                                    stack [++stackTop] = null;

                                    goto Loop;
                                    goto case Token.THIS;

                                case Token.THIS:
                                    stack [++stackTop] = frame.thisObj;

                                    goto Loop;
                                    goto case Token.THISFN;

                                case Token.THISFN:
                                    stack [++stackTop] = frame.fnOrScript;

                                    goto Loop;
                                    goto case Token.FALSE;

                                case Token.FALSE:
                                    stack [++stackTop] = false;

                                    goto Loop;
                                    goto case Token.TRUE;

                                case Token.TRUE:
                                    stack [++stackTop] = true;

                                    goto Loop;
                                    goto case Icode_UNDEF;

                                case Icode_UNDEF:
                                    stack [++stackTop] = undefined;

                                    goto Loop;
                                    goto case Token.ENTERWITH;

                                case Token.ENTERWITH: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        --stackTop;
                                        frame.scope = ScriptRuntime.enterWith (lhs, cx, frame.scope);

                                        goto Loop;
                                    }
                                    goto case Token.LEAVEWITH;

                                case Token.LEAVEWITH:
                                    frame.scope = ScriptRuntime.leaveWith (frame.scope);

                                    goto Loop;
                                    goto case Token.CATCH_SCOPE;

                                case Token.CATCH_SCOPE: {
                                        // stack top: exception object
                                        // stringReg: name of exception variable
                                        // indexReg: local for exception scope
                                        --stackTop;
                                        indexReg += frame.localShift;

                                        bool afterFirstScope = (frame.idata.itsICode [frame.pc] != 0);

                                        Exception caughtException = (Exception)stack [stackTop + 1];
                                        IScriptable lastCatchScope;
                                        if (!afterFirstScope) {
                                            lastCatchScope = null;
                                        }
                                        else {
                                            lastCatchScope = (IScriptable)stack [indexReg];
                                        }
                                        stack [indexReg] = ScriptRuntime.NewCatchScope (caughtException, lastCatchScope, stringReg, cx, frame.scope);
                                        ++frame.pc;

                                        goto Loop;
                                    }
                                    goto case Token.ENUM_INIT_KEYS;

                                case Token.ENUM_INIT_KEYS:
                                case Token.ENUM_INIT_VALUES: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        --stackTop;
                                        indexReg += frame.localShift;

                                        if (lhs is IIdEnumerable) {
                                            stack [indexReg] = ((IIdEnumerable)lhs).GetEnumeration (cx, (op == Token.ENUM_INIT_VALUES));
                                        }
                                        else {
                                            stack [indexReg] = new IdEnumeration (lhs, cx, (op == Token.ENUM_INIT_VALUES));
                                        }


                                        goto Loop;
                                    }
                                    goto case Token.ENUM_NEXT;

                                case Token.ENUM_NEXT:
                                case Token.ENUM_ID: {
                                        indexReg += frame.localShift;
                                        IdEnumeration val = (IdEnumeration)stack [indexReg];
                                        ++stackTop;
                                        stack [stackTop] = (op == Token.ENUM_NEXT) ? val.MoveNext () : val.Current (cx);

                                        goto Loop;
                                    }
                                    goto case Token.REF_SPECIAL;

                                case Token.REF_SPECIAL: {
                                        //stringReg: name of special property
                                        object obj = stack [stackTop];
                                        if (obj == DBL_MRK)
                                            obj = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.specialRef (obj, stringReg, cx);

                                        goto Loop;
                                    }
                                    goto case Token.REF_MEMBER;

                                case Token.REF_MEMBER: {
                                        //indexReg: flags
                                        object elem = stack [stackTop];
                                        if (elem == DBL_MRK)
                                            elem = sDbl [stackTop];
                                        --stackTop;
                                        object obj = stack [stackTop];
                                        if (obj == DBL_MRK)
                                            obj = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.memberRef (obj, elem, cx, indexReg);

                                        goto Loop;
                                    }
                                    goto case Token.REF_NS_MEMBER;

                                case Token.REF_NS_MEMBER: {
                                        //indexReg: flags
                                        object elem = stack [stackTop];
                                        if (elem == DBL_MRK)
                                            elem = sDbl [stackTop];
                                        --stackTop;
                                        object ns = stack [stackTop];
                                        if (ns == DBL_MRK)
                                            ns = sDbl [stackTop];
                                        --stackTop;
                                        object obj = stack [stackTop];
                                        if (obj == DBL_MRK)
                                            obj = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.memberRef (obj, ns, elem, cx, indexReg);

                                        goto Loop;
                                    }
                                    goto case Token.REF_NAME;

                                case Token.REF_NAME: {
                                        //indexReg: flags
                                        object name = stack [stackTop];
                                        if (name == DBL_MRK)
                                            name = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.nameRef (name, cx, frame.scope, indexReg);

                                        goto Loop;
                                    }
                                    goto case Token.REF_NS_NAME;

                                case Token.REF_NS_NAME: {
                                        //indexReg: flags
                                        object name = stack [stackTop];
                                        if (name == DBL_MRK)
                                            name = sDbl [stackTop];
                                        --stackTop;
                                        object ns = stack [stackTop];
                                        if (ns == DBL_MRK)
                                            ns = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.nameRef (ns, name, cx, frame.scope, indexReg);

                                        goto Loop;
                                    }
                                    goto case Icode_SCOPE_LOAD;

                                case Icode_SCOPE_LOAD:
                                    indexReg += frame.localShift;
                                    frame.scope = (IScriptable)stack [indexReg];

                                    goto Loop;
                                    goto case Icode_SCOPE_SAVE;

                                case Icode_SCOPE_SAVE:
                                    indexReg += frame.localShift;
                                    stack [indexReg] = frame.scope;

                                    goto Loop;
                                    goto case Icode_CLOSURE_EXPR;

                                case Icode_CLOSURE_EXPR: {
                                        InterpretedFunction fun = InterpretedFunction.createFunction (cx, frame.scope, frame.fnOrScript, indexReg);
                                        stack [++stackTop] = fun;
                                    }
                                    goto Loop;
                                    goto case Icode_CLOSURE_STMT;

                                case Icode_CLOSURE_STMT:
                                    initFunction (cx, frame.scope, frame.fnOrScript, indexReg);

                                    goto Loop;
                                    goto case Token.REGEXP;

                                case Token.REGEXP:
                                    stack [++stackTop] = frame.scriptRegExps [indexReg];

                                    goto Loop;
                                    goto case Icode_LITERAL_NEW;

                                case Icode_LITERAL_NEW:
                                    // indexReg: number of values in the literal
                                    ++stackTop;
                                    stack [stackTop] = new object [indexReg];
                                    sDbl [stackTop] = 0;

                                    goto Loop;
                                    goto case Icode_LITERAL_SET;

                                case Icode_LITERAL_SET: {
                                        object value = stack [stackTop];
                                        if (value == DBL_MRK)
                                            value = sDbl [stackTop];
                                        --stackTop;
                                        int i = (int)sDbl [stackTop];
                                        ((object [])stack [stackTop]) [i] = value;
                                        sDbl [stackTop] = i + 1;

                                        goto Loop;
                                    }
                                    goto case Token.ARRAYLIT;

                                case Token.ARRAYLIT:
                                case Icode_SPARE_ARRAYLIT:
                                case Token.OBJECTLIT: {
                                        object [] data = (object [])stack [stackTop];
                                        object val;
                                        if (op == Token.OBJECTLIT) {
                                            object [] ids = (object [])frame.idata.literalIds [indexReg];
                                            val = ScriptRuntime.newObjectLiteral (ids, data, cx, frame.scope);
                                        }
                                        else {
                                            int [] skipIndexces = null;
                                            if (op == Icode_SPARE_ARRAYLIT) {
                                                skipIndexces = (int [])frame.idata.literalIds [indexReg];
                                            }
                                            val = ScriptRuntime.newArrayLiteral (data, skipIndexces, cx, frame.scope);
                                        }
                                        stack [stackTop] = val;

                                        goto Loop;
                                    }
                                    goto case Icode_ENTERDQ;

                                case Icode_ENTERDQ: {
                                        object lhs = stack [stackTop];
                                        if (lhs == DBL_MRK)
                                            lhs = sDbl [stackTop];
                                        --stackTop;
                                        frame.scope = ScriptRuntime.enterDotQuery (lhs, frame.scope);

                                        goto Loop;
                                    }
                                    goto case Icode_LEAVEDQ;

                                case Icode_LEAVEDQ: {
                                        bool valBln = stack_boolean (frame, stackTop);
                                        object x = ScriptRuntime.updateDotQuery (valBln, frame.scope);
                                        if (x != null) {
                                            stack [stackTop] = x;
                                            frame.scope = ScriptRuntime.leaveDotQuery (frame.scope);
                                            frame.pc += 2;

                                            goto Loop;
                                        }
                                        // reset stack and PC to code after ENTERDQ
                                        --stackTop;

                                        goto jumplessRun_brk;
                                    }

                                case Token.DEFAULTNAMESPACE: {
                                        object value = stack [stackTop];
                                        if (value == DBL_MRK)
                                            value = sDbl [stackTop];
                                        stack [stackTop] = ScriptRuntime.setDefaultNamespace (value, cx);

                                        goto Loop;
                                    }
                                    goto case Token.ESCXMLATTR;

                                case Token.ESCXMLATTR: {
                                        object value = stack [stackTop];
                                        if (value != DBL_MRK) {
                                            stack [stackTop] = ScriptRuntime.escapeAttributeValue (value, cx);
                                        }

                                        goto Loop;
                                    }
                                    goto case Token.ESCXMLTEXT;

                                case Token.ESCXMLTEXT: {
                                        object value = stack [stackTop];
                                        if (value != DBL_MRK) {
                                            stack [stackTop] = ScriptRuntime.escapeTextValue (value, cx);
                                        }

                                        goto Loop;
                                    }
                                    goto case Icode_LINE;

                                case Icode_DEBUGGER: {
                                        if (frame.debuggerFrame != null) {
                                            frame.debuggerFrame.OnDebuggerStatement(cx);
                                        }
                                        break;
                                    }

                                case Icode_LINE:
                                    frame.pcSourceLineStart = frame.pc;
                                    if (frame.debuggerFrame != null) {
                                        int line = GetIndex (iCode, frame.pc);
                                        frame.debuggerFrame.OnLineChange (cx, line);
                                    }
                                    frame.pc += 2;

                                    goto Loop;
                                    goto case Icode_REG_IND_C0;

                                case Icode_REG_IND_C0:
                                    indexReg = 0;

                                    goto Loop;
                                    goto case Icode_REG_IND_C1;

                                case Icode_REG_IND_C1:
                                    indexReg = 1;

                                    goto Loop;
                                    goto case Icode_REG_IND_C2;

                                case Icode_REG_IND_C2:
                                    indexReg = 2;

                                    goto Loop;
                                    goto case Icode_REG_IND_C3;

                                case Icode_REG_IND_C3:
                                    indexReg = 3;

                                    goto Loop;
                                    goto case Icode_REG_IND_C4;

                                case Icode_REG_IND_C4:
                                    indexReg = 4;

                                    goto Loop;
                                    goto case Icode_REG_IND_C5;

                                case Icode_REG_IND_C5:
                                    indexReg = 5;

                                    goto Loop;
                                    goto case Icode_REG_IND1;

                                case Icode_REG_IND1:
                                    indexReg = 0xFF & iCode [frame.pc];
                                    ++frame.pc;

                                    goto Loop;
                                    goto case Icode_REG_IND2;

                                case Icode_REG_IND2:
                                    indexReg = GetIndex (iCode, frame.pc);
                                    frame.pc += 2;

                                    goto Loop;
                                    goto case Icode_REG_IND4;

                                case Icode_REG_IND4:
                                    indexReg = GetInt (iCode, frame.pc);
                                    frame.pc += 4;

                                    goto Loop;
                                    goto case Icode_REG_STR_C0;

                                case Icode_REG_STR_C0:
                                    stringReg = strings [0];

                                    goto Loop;
                                    goto case Icode_REG_STR_C1;

                                case Icode_REG_STR_C1:
                                    stringReg = strings [1];

                                    goto Loop;
                                    goto case Icode_REG_STR_C2;

                                case Icode_REG_STR_C2:
                                    stringReg = strings [2];

                                    goto Loop;
                                    goto case Icode_REG_STR_C3;

                                case Icode_REG_STR_C3:
                                    stringReg = strings [3];

                                    goto Loop;
                                    goto case Icode_REG_STR1;

                                case Icode_REG_STR1:
                                    stringReg = strings [0xFF & iCode [frame.pc]];
                                    ++frame.pc;

                                    goto Loop;
                                    goto case Icode_REG_STR2;

                                case Icode_REG_STR2:
                                    stringReg = strings [GetIndex (iCode, frame.pc)];
                                    frame.pc += 2;

                                    goto Loop;
                                    goto case Icode_REG_STR4;

                                case Icode_REG_STR4:
                                    stringReg = strings [GetInt (iCode, frame.pc)];
                                    frame.pc += 4;

                                    goto Loop;
                                    goto default;

                                default:
                                    dumpICode (frame.idata);
                                    throw new ApplicationException ("Unknown icode : " + op + " @ pc : " + (frame.pc - 1));

                            } // end of interpreter switch
                        }

                    jumplessRun_brk:
                        ;
                        // end of jumplessRun label block

                        // This should be reachable only for jump implementation
                        // when pc points to encoded target offset
                        if (instructionCounting) {
                            addInstructionCount (cx, frame, 2);
                        }
                        int offset = GetShort (iCode, frame.pc);
                        if (offset != 0) {
                            // -1 accounts for pc pointing to jump opcode + 1
                            frame.pc += offset - 1;
                        }
                        else {
                            frame.pc = frame.idata.longJumps.getExistingInt (frame.pc);
                        }
                        if (instructionCounting) {
                            frame.pcPrevBranch = frame.pc;
                        }

                        goto Loop;

                    Loop:
                        ;
                    }

                Loop_brk:
                    ;
                    // end of Loop: for

                    ExitFrame (cx, frame, (object)null);
                    interpreterResult = frame.result;
                    interpreterResultDbl = frame.resultDbl;
                    if (frame.parentFrame != null) {
                        frame = frame.parentFrame;
                        if (frame.frozen) {
                            frame = frame.cloneFrozen ();
                        }
                        setCallResult (frame, interpreterResult, interpreterResultDbl);
                        interpreterResult = null; // Help GC

                        goto StateLoop;
                    }

                    goto StateLoop_brk;
                }
                // end of interpreter withoutExceptions: try					
                catch (Exception ex) {
                    if (throwable != null) {
                        // This is serious bug and it is better to track it ASAP
                        throw new ApplicationException ();
                    }
                    throwable = ex;
                }

            withoutExceptions_brk:

                // This should be reachable only after above catch or from
                // finally when it needs to propagate exception or from
                // explicit throw
                if (throwable == null)
                    Context.CodeBug ();

                // Exception type				
                const int EX_CATCH_STATE = 2; // Can execute JS catch				
                const int EX_FINALLY_STATE = 1; // Can execute JS finally				
                const int EX_NO_JS_STATE = 0; // Terminate JS execution

                int exState;
                ContinuationJump cjump2 = null;

                if (throwable is EcmaScriptThrow) {
                    exState = EX_CATCH_STATE;
                }
                else if (throwable is EcmaScriptError) {
                    // an offical ECMA error object,
                    exState = EX_CATCH_STATE;
                }
                else if (throwable is EcmaScriptRuntimeException) {
                    exState = EX_CATCH_STATE;
                }
                else if (throwable is EcmaScriptException) {
                    exState = EX_FINALLY_STATE;
                }
                else if (throwable is Exception) {
                    exState = EX_NO_JS_STATE;
                }
                else {
                    // It must be ContinuationJump
                    exState = EX_FINALLY_STATE;
                    cjump2 = (ContinuationJump)throwable;
                }

                if (instructionCounting) {
                    try {
                        addInstructionCount (cx, frame, EXCEPTION_COST);
                    }
                    catch (ApplicationException ex) {
                        // Error from instruction counting
                        //     => unconditionally terminate JS
                        throwable = ex;
                        cjump2 = null;
                        exState = EX_NO_JS_STATE;
                    }
                }
                if (frame.debuggerFrame != null && throwable is ApplicationException) {
                    // Call debugger only for RuntimeException
                    ApplicationException rex = (ApplicationException)throwable;
                    try {
                        frame.debuggerFrame.OnExceptionThrown (cx, rex);
                    }
                    catch (Exception ex) {
                        // Any exception from debugger
                        //     => unconditionally terminate JS
                        throwable = ex;
                        cjump2 = null;
                        exState = EX_NO_JS_STATE;
                    }
                }

                for (; ; ) {
                    if (exState != EX_NO_JS_STATE) {
                        bool onlyFinally = (exState != EX_CATCH_STATE);
                        indexReg = getExceptionHandler (frame, onlyFinally);
                        if (indexReg >= 0) {
                            // We caught an exception, restart the loop
                            // with exception pending the processing at the loop
                            // start

                            goto StateLoop;
                        }
                    }
                    // No allowed execption handlers in this frame, unwind
                    // to parent and try to look there

                    ExitFrame (cx, frame, throwable);

                    frame = frame.parentFrame;
                    if (frame == null) {
                        break;
                    }
                    if (cjump2 != null && cjump2.branchFrame == frame) {
                        // Continuation branch point was hit,
                        // restart the state loop to reenter continuation
                        indexReg = -1;

                        goto StateLoop;
                    }
                }

                // No more frames, rethrow the exception or deal with continuation
                if (cjump2 != null) {
                    if (cjump2.branchFrame != null) {
                        // The above loop should locate the top frame
                        Context.CodeBug ();
                    }
                    if (cjump2.capturedFrame != null) {
                        // Restarting detached continuation
                        indexReg = -1;

                        goto StateLoop;
                    }
                    // Return continuation result to the caller
                    interpreterResult = cjump2.result;
                    interpreterResultDbl = cjump2.resultDbl;
                    throwable = null;
                }

                goto StateLoop_brk;

            StateLoop:
                ;
            }

        StateLoop_brk:
            ;
            // end of StateLoop: for(;;)

            // Do cleanups/restorations before the final return or throw

            if (cx.previousInterpreterInvocations != null && cx.previousInterpreterInvocations.size () != 0) {
                cx.lastInterpreterFrame = cx.previousInterpreterInvocations.pop ();
            }
            else {
                // It was the last interpreter frame on the stack
                cx.lastInterpreterFrame = null;
                // Force GC of the value cx.previousInterpreterInvocations
                cx.previousInterpreterInvocations = null;
            }

            if (throwable != null) {
                if (throwable is Helpers.StackOverflowVerifierException) {
                    throw Context.ReportRuntimeError (
                        ScriptRuntime.GetMessage ("mag.too.deep.parser.recursion"));
                }
                throw (Exception)throwable;                
            }

            return (interpreterResult != DBL_MRK) ? interpreterResult :
            interpreterResultDbl;
        }
예제 #2
0
        public static object restartContinuation (Continuation c, Context cx, IScriptable scope, object [] args)
        {
            if (!ScriptRuntime.hasTopCall (cx)) {
                return ScriptRuntime.DoTopCall (c, cx, scope, null, args);
            }

            object arg;
            if (args.Length == 0) {
                arg = Undefined.Value;
            }
            else {
                arg = args [0];
            }

            CallFrame capturedFrame = (CallFrame)c.Implementation;
            if (capturedFrame == null) {
                // No frames to restart
                return arg;
            }

            ContinuationJump cjump = new ContinuationJump (c, null);

            cjump.result = arg;
            return InterpretLoop (cx, null, cjump);
        }