Beispiel #1
0
		private static object InterpretLoop(Context cx, Interpreter.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.DOUBLE_MARK;
			object undefined = Undefined.instance;
			bool instructionCounting = (cx.instructionThreshold != 0);
			// arbitrary number to add to instructionCount when calling
			// other functions
			int INVOCATION_COST = 100;
			// arbitrary exception cost for instruction counting
			int EXCEPTION_COST = 100;
			string stringReg = null;
			int indexReg = -1;
			if (cx.lastInterpreterFrame != null)
			{
				// save the top frame from the previous interpretLoop
				// 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 throwable == null and indexReg == -1 allows to
			// catch bugs with using indeReg to access array elements before
			// initializing indexReg.
			Interpreter.GeneratorState generatorState = null;
			if (throwable != null)
			{
				if (throwable is Interpreter.GeneratorState)
				{
					generatorState = (Interpreter.GeneratorState)throwable;
					// reestablish this call frame
					EnterFrame(cx, frame, ScriptRuntime.emptyArgs, true);
					throwable = null;
				}
				else
				{
					if (!(throwable is Interpreter.ContinuationJump))
					{
						// It should be continuation
						Kit.CodeBug();
					}
				}
			}
			object interpreterResult = null;
			double interpreterResultDbl = 0.0;
			for (; ; )
			{
				try
				{
					if (throwable != null)
					{
						// Need to return both 'frame' and 'throwable' from
						// 'processThrowable', so just added a 'throwable'
						// member in 'frame'.
						frame = ProcessThrowable(cx, throwable, frame, indexReg, instructionCounting);
						throwable = frame.throwable;
						frame.throwable = null;
					}
					else
					{
						if (generatorState == null && frame.frozen)
						{
							Kit.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;
					int[] varAttributes = frame.varSource.stackAttributes;
					byte[] 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 across
					// 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 Icode_GENERATOR:
							{
								// Back indent to ease implementation reading
								if (!frame.frozen)
								{
									// First time encountering this opcode: create new generator
									// object and return
									frame.pc--;
									// we want to come back here when we resume
									Interpreter.CallFrame generatorFrame = CaptureFrameForGenerator(frame);
									generatorFrame.frozen = true;
									NativeGenerator generator = new NativeGenerator(frame.scope, generatorFrame.fnOrScript, generatorFrame);
									frame.result = generator;
									goto Loop_break;
								}
								goto case Token.YIELD;
							}

							case Token.YIELD:
							{
								// We are now resuming execution. Fall through to YIELD case.
								// fall through...
								if (!frame.frozen)
								{
									return FreezeGenerator(cx, frame, stackTop, generatorState);
								}
								else
								{
									object obj = ThawGenerator(frame, stackTop, generatorState, op);
									if (obj != ScriptableConstants.NOT_FOUND)
									{
										throwable = obj;
										goto withoutExceptions_break;
									}
									goto Loop_continue;
								}
								goto case Icode_GENERATOR_END;
							}

							case Icode_GENERATOR_END:
							{
								// throw StopIteration
								frame.frozen = true;
								int sourceLine = GetIndex(iCode, frame.pc);
								generatorState.returnedException = new JavaScriptException(NativeIterator.GetStopIterationObject(frame.scope), frame.idata.itsSourceFile, sourceLine);
								goto Loop_break;
							}

							case Token.THROW:
							{
								object value = stack[stackTop];
								if (value == DBL_MRK)
								{
									value = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								int sourceLine = GetIndex(iCode, frame.pc);
								throwable = new JavaScriptException(value, frame.idata.itsSourceFile, sourceLine);
								goto withoutExceptions_break;
							}

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

							case Token.GE:
							case Token.LE:
							case Token.GT:
							case Token.LT:
							{
								stackTop = DoCompare(frame, op, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.IN:
							case Token.INSTANCEOF:
							{
								stackTop = DoInOrInstanceof(cx, op, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.EQ:
							case Token.NE:
							{
								--stackTop;
								bool valBln = DoEquals(stack, sDbl, stackTop);
								valBln ^= (op == Token.NE);
								stack[stackTop] = ScriptRuntime.WrapBoolean(valBln);
								goto Loop_continue;
							}

							case Token.SHEQ:
							case Token.SHNE:
							{
								--stackTop;
								bool valBln = DoShallowEquals(stack, sDbl, stackTop);
								valBln ^= (op == Token.SHNE);
								stack[stackTop] = ScriptRuntime.WrapBoolean(valBln);
								goto Loop_continue;
							}

							case Token.IFNE:
							{
								if (Stack_boolean(frame, stackTop--))
								{
									frame.pc += 2;
									goto Loop_continue;
								}
								goto jumplessRun_break;
							}

							case Token.IFEQ:
							{
								if (!Stack_boolean(frame, stackTop--))
								{
									frame.pc += 2;
									goto Loop_continue;
								}
								goto jumplessRun_break;
							}

							case Icode_IFEQ_POP:
							{
								if (!Stack_boolean(frame, stackTop--))
								{
									frame.pc += 2;
									goto Loop_continue;
								}
								stack[stackTop--] = null;
								goto jumplessRun_break;
							}

							case Token.GOTO:
							{
								goto jumplessRun_break;
							}

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

							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)
									{
										Kit.CodeBug();
									}
								}
								goto Loop_continue;
							}

							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_break;
								}
								// Normal return from GOSUB
								frame.pc = (int)sDbl[indexReg];
								if (instructionCounting)
								{
									frame.pcPrevBranch = frame.pc;
								}
								goto Loop_continue;
							}

							case Icode_POP:
							{
								stack[stackTop] = null;
								stackTop--;
								goto Loop_continue;
							}

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

							case Icode_DUP:
							{
								stack[stackTop + 1] = stack[stackTop];
								sDbl[stackTop + 1] = sDbl[stackTop];
								stackTop++;
								goto Loop_continue;
							}

							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_continue;
							}

							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_continue;
							}

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

							case Token.RETURN_RESULT:
							{
								goto Loop_break;
							}

							case Icode_RETUNDEF:
							{
								frame.result = undefined;
								goto Loop_break;
							}

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

							case Token.BITAND:
							case Token.BITOR:
							case Token.BITXOR:
							case Token.LSH:
							case Token.RSH:
							{
								stackTop = DoBitOp(frame, op, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.URSH:
							{
								double lDbl = Stack_double(frame, stackTop - 1);
								int rIntValue = Stack_int32(frame, stackTop) & unchecked((int)(0x1F));
								stack[--stackTop] = DBL_MRK;
								sDbl[stackTop] = (long)(((ulong)ScriptRuntime.ToUint32(lDbl)) >> rIntValue);
								goto Loop_continue;
							}

							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_continue;
							}

							case Token.ADD:
							{
								--stackTop;
								DoAdd(stack, sDbl, stackTop, cx);
								goto Loop_continue;
							}

							case Token.SUB:
							case Token.MUL:
							case Token.DIV:
							case Token.MOD:
							{
								stackTop = DoArithmetic(frame, op, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.NOT:
							{
								stack[stackTop] = ScriptRuntime.WrapBoolean(!Stack_boolean(frame, stackTop));
								goto Loop_continue;
							}

							case Token.BINDNAME:
							{
								stack[++stackTop] = ScriptRuntime.Bind(cx, frame.scope, stringReg);
								goto Loop_continue;
							}

							case Token.STRICT_SETNAME:
							case Token.SETNAME:
							{
								object rhs = stack[stackTop];
								if (rhs == DBL_MRK)
								{
									rhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								Scriptable lhs = (Scriptable)stack[stackTop];
								stack[stackTop] = op == Token.SETNAME ? ScriptRuntime.SetName(lhs, rhs, cx, frame.scope, stringReg) : ScriptRuntime.StrictSetName(lhs, rhs, cx, frame.scope, stringReg);
								goto Loop_continue;
							}

							case Icode_SETCONST:
							{
								object rhs = stack[stackTop];
								if (rhs == DBL_MRK)
								{
									rhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								Scriptable lhs = (Scriptable)stack[stackTop];
								stack[stackTop] = ScriptRuntime.SetConst(lhs, rhs, cx, stringReg);
								goto Loop_continue;
							}

							case Token.DELPROP:
							case Icode_DELNAME:
							{
								stackTop = DoDelName(cx, op, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.GETPROPNOWARN:
							{
								object lhs = stack[stackTop];
								if (lhs == DBL_MRK)
								{
									lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								stack[stackTop] = ScriptRuntime.GetObjectPropNoWarn(lhs, stringReg, cx);
								goto Loop_continue;
							}

							case Token.GETPROP:
							{
								object lhs = stack[stackTop];
								if (lhs == DBL_MRK)
								{
									lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								stack[stackTop] = ScriptRuntime.GetObjectProp(lhs, stringReg, cx, frame.scope);
								goto Loop_continue;
							}

							case Token.SETPROP:
							{
								object rhs = stack[stackTop];
								if (rhs == DBL_MRK)
								{
									rhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								object lhs = stack[stackTop];
								if (lhs == DBL_MRK)
								{
									lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								stack[stackTop] = ScriptRuntime.SetObjectProp(lhs, stringReg, rhs, cx);
								goto Loop_continue;
							}

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

							case Token.GETELEM:
							{
								stackTop = DoGetElem(cx, frame, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.SETELEM:
							{
								stackTop = DoSetElem(cx, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Icode_ELEM_INC_DEC:
							{
								stackTop = DoElemIncDec(cx, frame, iCode, stack, sDbl, stackTop);
								goto Loop_continue;
							}

							case Token.GET_REF:
							{
								Ref @ref = (Ref)stack[stackTop];
								stack[stackTop] = ScriptRuntime.RefGet(@ref, cx);
								goto Loop_continue;
							}

							case Token.SET_REF:
							{
								object value = stack[stackTop];
								if (value == DBL_MRK)
								{
									value = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								Ref @ref = (Ref)stack[stackTop];
								stack[stackTop] = ScriptRuntime.RefSet(@ref, value, cx);
								goto Loop_continue;
							}

							case Token.DEL_REF:
							{
								Ref @ref = (Ref)stack[stackTop];
								stack[stackTop] = ScriptRuntime.RefDel(@ref, cx);
								goto Loop_continue;
							}

							case Icode_REF_INC_DEC:
							{
								Ref @ref = (Ref)stack[stackTop];
								stack[stackTop] = ScriptRuntime.RefIncrDecr(@ref, cx, iCode[frame.pc]);
								++frame.pc;
								goto Loop_continue;
							}

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

							case Icode_LOCAL_CLEAR:
							{
								indexReg += frame.localShift;
								stack[indexReg] = null;
								goto Loop_continue;
							}

							case Icode_NAME_AND_THIS:
							{
								// stringReg: name
								++stackTop;
								stack[stackTop] = ScriptRuntime.GetNameFunctionAndThis(stringReg, cx, frame.scope);
								++stackTop;
								stack[stackTop] = ScriptRuntime.LastStoredScriptable(cx);
								goto Loop_continue;
							}

							case Icode_PROP_AND_THIS:
							{
								object obj = stack[stackTop];
								if (obj == DBL_MRK)
								{
									obj = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								// stringReg: property
								stack[stackTop] = ScriptRuntime.GetPropFunctionAndThis(obj, stringReg, cx, frame.scope);
								++stackTop;
								stack[stackTop] = ScriptRuntime.LastStoredScriptable(cx);
								goto Loop_continue;
							}

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

							case Icode_VALUE_AND_THIS:
							{
								object value = stack[stackTop];
								if (value == DBL_MRK)
								{
									value = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								stack[stackTop] = ScriptRuntime.GetValueFunctionAndThis(value, cx);
								++stackTop;
								stack[stackTop] = ScriptRuntime.LastStoredScriptable(cx);
								goto Loop_continue;
							}

							case Icode_CALLSPECIAL:
							{
								if (instructionCounting)
								{
									cx.instructionCount += INVOCATION_COST;
								}
								stackTop = DoCallSpecial(cx, frame, stack, sDbl, stackTop, iCode, indexReg);
								goto Loop_continue;
							}

							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
								Callable fun = (Callable)stack[stackTop];
								Scriptable funThisObj = (Scriptable)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_continue;
								}
								Scriptable 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)
									{
										Interpreter.CallFrame callParentFrame = frame;
										Interpreter.CallFrame calleeFrame = new Interpreter.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 interaction with GC.
											callParentFrame = frame.parentFrame;
											// Release the current frame. See Bug #344501 to see why
											// it is being done here.
											ExitFrame(cx, frame, null);
										}
										InitFrame(cx, calleeScope, funThisObj, stack, sDbl, stackTop + 2, indexReg, ifun, callParentFrame, calleeFrame);
										if (op != Icode_TAIL_CALL)
										{
											frame.savedStackTop = stackTop;
											frame.savedCallOp = op;
										}
										frame = calleeFrame;
										goto StateLoop_continue;
									}
								}
								if (fun is NativeContinuation)
								{
									// Jump to the captured continuation
									Interpreter.ContinuationJump cjump;
									cjump = new Interpreter.ContinuationJump((NativeContinuation)fun, frame);
									// continuation result is the first argument if any
									// of continuation 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;
									goto withoutExceptions_break;
								}
								if (fun is IdFunctionObject)
								{
									IdFunctionObject ifun = (IdFunctionObject)fun;
									if (NativeContinuation.IsContinuationConstructor(ifun))
									{
										frame.stack[stackTop] = CaptureContinuation(cx, frame.parentFrame, false);
										goto Loop_continue;
									}
									// Bug 405654 -- make best effort to keep Function.apply and
									// Function.call within this interpreter loop invocation
									if (BaseFunction.IsApplyOrCall(ifun))
									{
										Callable applyCallable = ScriptRuntime.GetCallable(funThisObj);
										if (applyCallable is InterpretedFunction)
										{
											InterpretedFunction iApplyCallable = (InterpretedFunction)applyCallable;
											if (frame.fnOrScript.securityDomain == iApplyCallable.securityDomain)
											{
												frame = InitFrameForApplyOrCall(cx, frame, indexReg, stack, sDbl, stackTop, op, calleeScope, ifun, iApplyCallable);
												goto StateLoop_continue;
											}
										}
									}
								}
								// Bug 447697 -- make best effort to keep __noSuchMethod__ within this
								// interpreter loop invocation
								if (fun is ScriptRuntime.NoSuchMethodShim)
								{
									// get the shim and the actual method
									ScriptRuntime.NoSuchMethodShim noSuchMethodShim = (ScriptRuntime.NoSuchMethodShim)fun;
									Callable noSuchMethodMethod = noSuchMethodShim.noSuchMethodMethod;
									// if the method is in fact an InterpretedFunction
									if (noSuchMethodMethod is InterpretedFunction)
									{
										InterpretedFunction ifun = (InterpretedFunction)noSuchMethodMethod;
										if (frame.fnOrScript.securityDomain == ifun.securityDomain)
										{
											frame = InitFrameForNoSuchMethod(cx, frame, indexReg, stack, sDbl, stackTop, op, funThisObj, calleeScope, noSuchMethodShim, ifun);
											goto StateLoop_continue;
										}
									}
								}
								cx.lastInterpreterFrame = frame;
								frame.savedCallOp = op;
								frame.savedStackTop = stackTop;
								stack[stackTop] = fun.Call(cx, calleeScope, funThisObj, GetArgsArray(stack, sDbl, stackTop + 2, indexReg));
								goto Loop_continue;
							}

							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)
									{
										Scriptable newInstance = f.CreateObject(cx, frame.scope);
										Interpreter.CallFrame calleeFrame = new Interpreter.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_continue;
									}
								}
								if (!(lhs is Function))
								{
									if (lhs == DBL_MRK)
									{
										lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
									}
									throw ScriptRuntime.NotFunctionError(lhs);
								}
								Function fun = (Function)lhs;
								if (fun is IdFunctionObject)
								{
									IdFunctionObject ifun = (IdFunctionObject)fun;
									if (NativeContinuation.IsContinuationConstructor(ifun))
									{
										frame.stack[stackTop] = CaptureContinuation(cx, frame.parentFrame, false);
										goto Loop_continue;
									}
								}
								object[] outArgs = GetArgsArray(stack, sDbl, stackTop + 1, indexReg);
								stack[stackTop] = fun.Construct(cx, frame.scope, outArgs);
								goto Loop_continue;
							}

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

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

							case Token.STRING:
							{
								stack[++stackTop] = stringReg;
								goto Loop_continue;
							}

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

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

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

							case Token.NAME:
							{
								stack[++stackTop] = ScriptRuntime.Name(cx, frame.scope, stringReg);
								goto Loop_continue;
							}

							case Icode_NAME_INC_DEC:
							{
								stack[++stackTop] = ScriptRuntime.NameIncrDecr(frame.scope, stringReg, cx, iCode[frame.pc]);
								++frame.pc;
								goto Loop_continue;
							}

							case Icode_SETCONSTVAR1:
							{
								indexReg = iCode[frame.pc++];
								goto case Token.SETCONSTVAR;
							}

							case Token.SETCONSTVAR:
							{
								// fallthrough
								stackTop = DoSetConstVar(frame, stack, sDbl, stackTop, vars, varDbls, varAttributes, indexReg);
								goto Loop_continue;
							}

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

							case Token.SETVAR:
							{
								// fallthrough
								stackTop = DoSetVar(frame, stack, sDbl, stackTop, vars, varDbls, varAttributes, indexReg);
								goto Loop_continue;
							}

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

							case Token.GETVAR:
							{
								// fallthrough
								stackTop = DoGetVar(frame, stack, sDbl, stackTop, vars, varDbls, indexReg);
								goto Loop_continue;
							}

							case Icode_VAR_INC_DEC:
							{
								stackTop = DoVarIncDec(cx, frame, stack, sDbl, stackTop, vars, varDbls, indexReg);
								goto Loop_continue;
							}

							case Icode_ZERO:
							{
								++stackTop;
								stack[stackTop] = DBL_MRK;
								sDbl[stackTop] = 0;
								goto Loop_continue;
							}

							case Icode_ONE:
							{
								++stackTop;
								stack[stackTop] = DBL_MRK;
								sDbl[stackTop] = 1;
								goto Loop_continue;
							}

							case Token.NULL:
							{
								stack[++stackTop] = null;
								goto Loop_continue;
							}

							case Token.THIS:
							{
								stack[++stackTop] = frame.thisObj;
								goto Loop_continue;
							}

							case Token.THISFN:
							{
								stack[++stackTop] = frame.fnOrScript;
								goto Loop_continue;
							}

							case Token.FALSE:
							{
								stack[++stackTop] = false;
								goto Loop_continue;
							}

							case Token.TRUE:
							{
								stack[++stackTop] = true;
								goto Loop_continue;
							}

							case Icode_UNDEF:
							{
								stack[++stackTop] = undefined;
								goto Loop_continue;
							}

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

							case Token.LEAVEWITH:
							{
								frame.scope = ScriptRuntime.LeaveWith(frame.scope);
								goto Loop_continue;
							}

							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];
								Scriptable lastCatchScope;
								if (!afterFirstScope)
								{
									lastCatchScope = null;
								}
								else
								{
									lastCatchScope = (Scriptable)stack[indexReg];
								}
								stack[indexReg] = ScriptRuntime.NewCatchScope(caughtException, lastCatchScope, stringReg, cx, frame.scope);
								++frame.pc;
								goto Loop_continue;
							}

							case Token.ENUM_INIT_KEYS:
							case Token.ENUM_INIT_VALUES:
							case Token.ENUM_INIT_ARRAY:
							{
								object lhs = stack[stackTop];
								if (lhs == DBL_MRK)
								{
									lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								indexReg += frame.localShift;
								int enumType = op == Token.ENUM_INIT_KEYS ? ScriptRuntime.ENUMERATE_KEYS : op == Token.ENUM_INIT_VALUES ? ScriptRuntime.ENUMERATE_VALUES : ScriptRuntime.ENUMERATE_ARRAY;
								stack[indexReg] = ScriptRuntime.EnumInit(lhs, cx, enumType);
								goto Loop_continue;
							}

							case Token.ENUM_NEXT:
							case Token.ENUM_ID:
							{
								indexReg += frame.localShift;
								object val = stack[indexReg];
								++stackTop;
								stack[stackTop] = (op == Token.ENUM_NEXT) ? (object)ScriptRuntime.EnumNext(val) : (object)ScriptRuntime.EnumId(val, cx);
								goto Loop_continue;
							}

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

							case Token.REF_MEMBER:
							{
								//indexReg: flags
								stackTop = DoRefMember(cx, stack, sDbl, stackTop, indexReg);
								goto Loop_continue;
							}

							case Token.REF_NS_MEMBER:
							{
								//indexReg: flags
								stackTop = DoRefNsMember(cx, stack, sDbl, stackTop, indexReg);
								goto Loop_continue;
							}

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

							case Token.REF_NS_NAME:
							{
								//indexReg: flags
								stackTop = DoRefNsName(cx, frame, stack, sDbl, stackTop, indexReg);
								goto Loop_continue;
							}

							case Icode_SCOPE_LOAD:
							{
								indexReg += frame.localShift;
								frame.scope = (Scriptable)stack[indexReg];
								goto Loop_continue;
							}

							case Icode_SCOPE_SAVE:
							{
								indexReg += frame.localShift;
								stack[indexReg] = frame.scope;
								goto Loop_continue;
							}

							case Icode_CLOSURE_EXPR:
							{
								stack[++stackTop] = InterpretedFunction.CreateFunction(cx, frame.scope, frame.fnOrScript, indexReg);
								goto Loop_continue;
							}

							case Icode_CLOSURE_STMT:
							{
								InitFunction(cx, frame.scope, frame.fnOrScript, indexReg);
								goto Loop_continue;
							}

							case Token.REGEXP:
							{
								object re = frame.idata.itsRegExpLiterals[indexReg];
								stack[++stackTop] = ScriptRuntime.WrapRegExp(cx, frame.scope, re);
								goto Loop_continue;
							}

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

							case Icode_LITERAL_SET:
							{
								object value = stack[stackTop];
								if (value == DBL_MRK)
								{
									value = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								int i = (int)sDbl[stackTop];
								((object[])stack[stackTop])[i] = value;
								sDbl[stackTop] = i + 1;
								goto Loop_continue;
							}

							case Icode_LITERAL_GETTER:
							{
								object value = stack[stackTop];
								--stackTop;
								int i = (int)sDbl[stackTop];
								((object[])stack[stackTop])[i] = value;
								((int[])stack[stackTop - 1])[i] = -1;
								sDbl[stackTop] = i + 1;
								goto Loop_continue;
							}

							case Icode_LITERAL_SETTER:
							{
								object value = stack[stackTop];
								--stackTop;
								int i = (int)sDbl[stackTop];
								((object[])stack[stackTop])[i] = value;
								((int[])stack[stackTop - 1])[i] = +1;
								sDbl[stackTop] = i + 1;
								goto Loop_continue;
							}

							case Token.ARRAYLIT:
							case Icode_SPARE_ARRAYLIT:
							case Token.OBJECTLIT:
							{
								object[] data = (object[])stack[stackTop];
								--stackTop;
								int[] getterSetters = (int[])stack[stackTop];
								object val;
								if (op == Token.OBJECTLIT)
								{
									object[] ids = (object[])frame.idata.literalIds[indexReg];
									val = ScriptRuntime.NewObjectLiteral(ids, data, getterSetters, 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_continue;
							}

							case Icode_ENTERDQ:
							{
								object lhs = stack[stackTop];
								if (lhs == DBL_MRK)
								{
									lhs = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								--stackTop;
								frame.scope = ScriptRuntime.EnterDotQuery(lhs, frame.scope);
								goto Loop_continue;
							}

							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_continue;
								}
								// reset stack and PC to code after ENTERDQ
								--stackTop;
								goto jumplessRun_break;
							}

							case Token.DEFAULTNAMESPACE:
							{
								object value = stack[stackTop];
								if (value == DBL_MRK)
								{
									value = ScriptRuntime.WrapNumber(sDbl[stackTop]);
								}
								stack[stackTop] = ScriptRuntime.SetDefaultNamespace(value, cx);
								goto Loop_continue;
							}

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

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

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

							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_continue;
							}

							case Icode_REG_IND_C0:
							{
								indexReg = 0;
								goto Loop_continue;
							}

							case Icode_REG_IND_C1:
							{
								indexReg = 1;
								goto Loop_continue;
							}

							case Icode_REG_IND_C2:
							{
								indexReg = 2;
								goto Loop_continue;
							}

							case Icode_REG_IND_C3:
							{
								indexReg = 3;
								goto Loop_continue;
							}

							case Icode_REG_IND_C4:
							{
								indexReg = 4;
								goto Loop_continue;
							}

							case Icode_REG_IND_C5:
							{
								indexReg = 5;
								goto Loop_continue;
							}

							case Icode_REG_IND1:
							{
								indexReg = unchecked((int)(0xFF)) & iCode[frame.pc];
								++frame.pc;
								goto Loop_continue;
							}

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

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

							case Icode_REG_STR_C0:
							{
								stringReg = strings[0];
								goto Loop_continue;
							}

							case Icode_REG_STR_C1:
							{
								stringReg = strings[1];
								goto Loop_continue;
							}

							case Icode_REG_STR_C2:
							{
								stringReg = strings[2];
								goto Loop_continue;
							}

							case Icode_REG_STR_C3:
							{
								stringReg = strings[3];
								goto Loop_continue;
							}

							case Icode_REG_STR1:
							{
								stringReg = strings[unchecked((int)(0xFF)) & iCode[frame.pc]];
								++frame.pc;
								goto Loop_continue;
							}

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

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

							default:
							{
								DumpICode(frame.idata);
								throw new Exception("Unknown icode : " + op + " @ pc : " + (frame.pc - 1));
							}
						}
jumplessRun_break: ;
						// end of interpreter switch
						// 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_continue;
Loop_continue: ;
					}
Loop_break: ;
					// end of Loop: for
					ExitFrame(cx, frame, 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_continue;
					}
					goto StateLoop_break;
				}
				catch (Exception ex)
				{
					// end of interpreter withoutExceptions: try
					if (throwable != null)
					{
						// This is serious bug and it is better to track it ASAP
						Sharpen.Runtime.PrintStackTrace(ex, System.Console.Error);
						throw new InvalidOperationException();
					}
					throwable = ex;
				}
withoutExceptions_break: ;
				// This should be reachable only after above catch or from
				// finally when it needs to propagate exception or from
				// explicit throw
				if (throwable == null)
				{
					Kit.CodeBug();
				}
				// Exception type
				int EX_CATCH_STATE = 2;
				// Can execute JS catch
				int EX_FINALLY_STATE = 1;
				// Can execute JS finally
				int EX_NO_JS_STATE = 0;
				// Terminate JS execution
				int exState;
				Interpreter.ContinuationJump cjump_1 = null;
				if (generatorState != null && generatorState.operation == NativeGenerator.GENERATOR_CLOSE && throwable == generatorState.value)
				{
					exState = EX_FINALLY_STATE;
				}
				else
				{
					if (throwable is JavaScriptException)
					{
						exState = EX_CATCH_STATE;
					}
					else
					{
						if (throwable is EcmaError)
						{
							// an offical ECMA error object,
							exState = EX_CATCH_STATE;
						}
						else
						{
							if (throwable is EvaluatorException)
							{
								exState = EX_CATCH_STATE;
							}
							else
							{
								if (throwable is ContinuationPending)
								{
									exState = EX_NO_JS_STATE;
								}
								else
								{
									if (throwable is Exception)
									{
										exState = cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS) ? EX_CATCH_STATE : EX_FINALLY_STATE;
									}
									else
									{
										if (throwable is Exception)
										{
											exState = cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS) ? EX_CATCH_STATE : EX_NO_JS_STATE;
										}
										else
										{
											if (throwable is Interpreter.ContinuationJump)
											{
												// It must be ContinuationJump
												exState = EX_FINALLY_STATE;
												cjump_1 = (Interpreter.ContinuationJump)throwable;
											}
											else
											{
												exState = cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS) ? EX_CATCH_STATE : EX_FINALLY_STATE;
											}
										}
									}
								}
							}
						}
					}
				}
				if (instructionCounting)
				{
					try
					{
						AddInstructionCount(cx, frame, EXCEPTION_COST);
					}
					catch (Exception ex)
					{
						throwable = ex;
						exState = EX_FINALLY_STATE;
					}
					catch (Exception ex)
					{
						// Error from instruction counting
						//     => unconditionally terminate JS
						throwable = ex;
						cjump_1 = null;
						exState = EX_NO_JS_STATE;
					}
				}
				if (frame.debuggerFrame != null && throwable is Exception)
				{
					// Call debugger only for RuntimeException
					Exception rex = (Exception)throwable;
					try
					{
						frame.debuggerFrame.OnExceptionThrown(cx, rex);
					}
					catch (Exception ex)
					{
						// Any exception from debugger
						//     => unconditionally terminate JS
						throwable = ex;
						cjump_1 = 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_continue;
						}
					}
					// No allowed exception handlers in this frame, unwind
					// to parent and try to look there
					ExitFrame(cx, frame, throwable);
					frame = frame.parentFrame;
					if (frame == null)
					{
						break;
					}
					if (cjump_1 != null && cjump_1.branchFrame == frame)
					{
						// Continuation branch point was hit,
						// restart the state loop to reenter continuation
						indexReg = -1;
						goto StateLoop_continue;
					}
				}
				// No more frames, rethrow the exception or deal with continuation
				if (cjump_1 != null)
				{
					if (cjump_1.branchFrame != null)
					{
						// The above loop should locate the top frame
						Kit.CodeBug();
					}
					if (cjump_1.capturedFrame != null)
					{
						// Restarting detached continuation
						indexReg = -1;
						goto StateLoop_continue;
					}
					// Return continuation result to the caller
					interpreterResult = cjump_1.result;
					interpreterResultDbl = cjump_1.resultDbl;
					throwable = null;
				}
				goto StateLoop_break;
StateLoop_continue: ;
			}
StateLoop_break: ;
			// 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 Exception)
				{
					throw (Exception)throwable;
				}
				else
				{
					// Must be instance of Error or code bug
					throw (Exception)throwable;
				}
			}
			return (interpreterResult != DBL_MRK) ? interpreterResult : ScriptRuntime.WrapNumber(interpreterResultDbl);
		}
Beispiel #2
0
		public static object RestartContinuation(NativeContinuation c, Context cx, Scriptable scope, object[] args)
		{
			if (!ScriptRuntime.HasTopCall(cx))
			{
				return ScriptRuntime.DoTopCall(c, cx, scope, null, args);
			}
			object arg;
			if (args.Length == 0)
			{
				arg = Undefined.instance;
			}
			else
			{
				arg = args[0];
			}
			Interpreter.CallFrame capturedFrame = (Interpreter.CallFrame)c.GetImplementation();
			if (capturedFrame == null)
			{
				// No frames to restart
				return arg;
			}
			Interpreter.ContinuationJump cjump = new Interpreter.ContinuationJump(c, null);
			cjump.result = arg;
			return InterpretLoop(cx, null, cjump);
		}