public HasFeature ( int featureIndex ) : bool | ||
featureIndex | int | feature index to check |
return | bool |
internal static Ref CreateSpecial(Context cx, object @object, string name) { Scriptable target = ScriptRuntime.ToObjectOrNull(cx, @object); if (target == null) { throw ScriptRuntime.UndefReadError(@object, name); } int type; if (name.Equals("__proto__")) { type = SPECIAL_PROTO; } else { if (name.Equals("__parent__")) { type = SPECIAL_PARENT; } else { throw new ArgumentException(name); } } if (!cx.HasFeature(Context.FEATURE_PARENT_PROTO_PROPERTIES)) { // Clear special after checking for valid name! type = SPECIAL_NONE; } return new Rhino.SpecialRef(target, type, name); }
public virtual void InitFromContext(Context cx) { SetErrorReporter(cx.GetErrorReporter()); languageVersion = cx.GetLanguageVersion(); generateDebugInfo = (!cx.IsGeneratingDebugChanged() || cx.IsGeneratingDebug()); reservedKeywordAsIdentifier = cx.HasFeature(Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER); allowMemberExprAsFunctionName = cx.HasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME); strictMode = cx.HasFeature(Context.FEATURE_STRICT_MODE); warningAsError = cx.HasFeature(Context.FEATURE_WARNING_AS_ERROR); xmlAvailable = cx.HasFeature(Context.FEATURE_E4X); optimizationLevel = cx.GetOptimizationLevel(); generatingSource = cx.IsGeneratingSource(); activationNames = cx.activationNames; // Observer code generation in compiled code : generateObserverCount = cx.generateObserverCount; }
public static Scriptable WrapException(Exception t, Scriptable scope, Context cx) { RhinoException re; string errorName; string errorMsg; Exception javaException = null; if (t is EcmaError) { EcmaError ee = (EcmaError)t; re = ee; errorName = ee.GetName(); errorMsg = ee.GetErrorMessage(); } else { if (t is WrappedException) { WrappedException we = (WrappedException)t; re = we; javaException = we.GetWrappedException(); errorName = "JavaException"; errorMsg = javaException.GetType().FullName + ": " + javaException.Message; } else { if (t is EvaluatorException) { // Pure evaluator exception, nor WrappedException instance EvaluatorException ee = (EvaluatorException)t; re = ee; errorName = "InternalError"; errorMsg = ee.Message; } else { if (cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { // With FEATURE_ENHANCED_JAVA_ACCESS, scripts can catch // all exception types re = new WrappedException(t); errorName = "JavaException"; errorMsg = t.ToString(); } else { // Script can catch only instances of JavaScriptException, // EcmaError and EvaluatorException throw Kit.CodeBug(); } } } } string sourceUri = re.SourceName(); if (sourceUri == null) { sourceUri = string.Empty; } int line = re.LineNumber(); object[] args; if (line > 0) { args = new object[] { errorMsg, sourceUri, Sharpen.Extensions.ValueOf(line) }; } else { args = new object[] { errorMsg, sourceUri }; } Scriptable errorObject = cx.NewObject(scope, errorName, args); ScriptableObject.PutProperty(errorObject, "name", errorName); // set exception in Error objects to enable non-ECMA "stack" property if (errorObject is NativeError) { ((NativeError)errorObject).SetStackProvider(re); } if (javaException != null && IsVisible(cx, javaException)) { object wrap = cx.GetWrapFactory().Wrap(cx, scope, javaException, null); ScriptableObject.DefineProperty(errorObject, "javaException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); } if (IsVisible(cx, re)) { object wrap = cx.GetWrapFactory().Wrap(cx, scope, re, null); ScriptableObject.DefineProperty(errorObject, "rhinoException", wrap, ScriptableObject.PERMANENT | ScriptableObject.READONLY); } return errorObject; }
public static object DoTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, object[] args) { if (scope == null) { throw new ArgumentException(); } if (cx.topCallScope != null) { throw new InvalidOperationException(); } object result; cx.topCallScope = ScriptableObject.GetTopLevelScope(scope); cx.useDynamicScope = cx.HasFeature(Context.FEATURE_DYNAMIC_SCOPE); ContextFactory f = cx.GetFactory(); try { result = f.DoTopCall(callable, cx, scope, thisObj, args); } finally { cx.topCallScope = null; // Cleanup cached references cx.cachedXMLLib = null; if (cx.currentActivationCall != null) { // Function should always call exitActivationFunction // if it creates activation record throw new InvalidOperationException(); } } return result; }
/// <summary>The eval function property of the global object.</summary> /// <remarks> /// The eval function property of the global object. /// See ECMA 15.1.2.1 /// </remarks> public static object EvalSpecial(Context cx, Scriptable scope, object thisArg, object[] args, string filename, int lineNumber) { if (args.Length < 1) { return Undefined.instance; } object x = args[0]; if (!(x is CharSequence)) { if (cx.HasFeature(Context.FEATURE_STRICT_MODE) || cx.HasFeature(Context.FEATURE_STRICT_EVAL)) { throw Context.ReportRuntimeError0("msg.eval.nonstring.strict"); } string message = ScriptRuntime.GetMessage0("msg.eval.nonstring"); Context.ReportWarning(message); return x; } if (filename == null) { int[] linep = new int[1]; filename = Context.GetSourcePositionFromStack(linep); if (filename != null) { lineNumber = linep[0]; } else { filename = string.Empty; } } string sourceName = ScriptRuntime.MakeUrlForGeneratedScript(true, filename, lineNumber); ErrorReporter reporter; reporter = DefaultErrorReporter.ForEval(cx.GetErrorReporter()); Evaluator evaluator = Context.CreateInterpreter(); if (evaluator == null) { throw new JavaScriptException("Interpreter not present", filename, lineNumber); } // Compile with explicit interpreter instance to force interpreter // mode. Script script = cx.CompileString(x.ToString(), evaluator, reporter, sourceName, 1, null); evaluator.SetEvalScriptFlag(script); Callable c = (Callable)script; return c.Call(cx, scope, (Scriptable)thisArg, ScriptRuntime.emptyArgs); }
public static object SetName(Scriptable bound, object value, Context cx, Scriptable scope, string id) { if (bound != null) { // TODO: we used to special-case XMLObject here, but putProperty // seems to work for E4X and it's better to optimize the common case ScriptableObject.PutProperty(bound, id, value); } else { // "newname = 7;", where 'newname' has not yet // been defined, creates a new property in the // top scope unless strict mode is specified. if (cx.HasFeature(Context.FEATURE_STRICT_MODE) || cx.HasFeature(Context.FEATURE_STRICT_VARS)) { Context.ReportWarning(ScriptRuntime.GetMessage1("msg.assn.create.strict", id)); } // Find the top scope by walking up the scope chain. bound = ScriptableObject.GetTopLevelScope(scope); if (cx.useDynamicScope) { bound = CheckDynamicScope(cx.topCallScope, bound); } bound.Put(id, bound, value); } return value; }
public static object GetObjectProp(Scriptable obj, string property, Context cx) { object result = ScriptableObject.GetProperty(obj, property); if (result == ScriptableConstants.NOT_FOUND) { if (cx.HasFeature(Context.FEATURE_STRICT_MODE)) { Context.ReportWarning(ScriptRuntime.GetMessage1("msg.ref.undefined.prop", property)); } result = Undefined.instance; } return result; }
public static ScriptableObject InitStandardObjects(Context cx, ScriptableObject scope, bool @sealed) { if (scope == null) { scope = new NativeObject(); } scope.AssociateValue(LIBRARY_SCOPE_KEY, scope); (new ClassCache()).Associate(scope); BaseFunction.Init(scope, @sealed); NativeObject.Init(scope, @sealed); Scriptable objectProto = ScriptableObject.GetObjectPrototype(scope); // Function.prototype.__proto__ should be Object.prototype Scriptable functionProto = ScriptableObject.GetClassPrototype(scope, "Function"); functionProto.SetPrototype(objectProto); // Set the prototype of the object passed in if need be if (scope.GetPrototype() == null) { scope.SetPrototype(objectProto); } // must precede NativeGlobal since it's needed therein NativeError.Init(scope, @sealed); NativeGlobal.Init(cx, scope, @sealed); NativeArray.Init(scope, @sealed); if (cx.GetOptimizationLevel() > 0) { // When optimizing, attempt to fulfill all requests for new Array(N) // with a higher threshold before switching to a sparse // representation NativeArray.SetMaximumInitialCapacity(200000); } NativeString.Init(scope, @sealed); NativeBoolean.Init(scope, @sealed); NativeNumber.Init(scope, @sealed); NativeDate.Init(scope, @sealed); NativeMath.Init(scope, @sealed); NativeJSON.Init(scope, @sealed); NativeWith.Init(scope, @sealed); NativeCall.Init(scope, @sealed); NativeScript.Init(scope, @sealed); NativeIterator.Init(scope, @sealed); // Also initializes NativeGenerator bool withXml = cx.HasFeature(Context.FEATURE_E4X) && cx.GetE4xImplementationFactory() != null; // define lazy-loaded properties using their class name new LazilyLoadedCtor(scope, "RegExp", "org.mozilla.javascript.regexp.NativeRegExp", @sealed, true); new LazilyLoadedCtor(scope, "Packages", "org.mozilla.javascript.NativeJavaTopPackage", @sealed, true); new LazilyLoadedCtor(scope, "getClass", "org.mozilla.javascript.NativeJavaTopPackage", @sealed, true); new LazilyLoadedCtor(scope, "JavaAdapter", "org.mozilla.javascript.JavaAdapter", @sealed, true); new LazilyLoadedCtor(scope, "JavaImporter", "org.mozilla.javascript.ImporterTopLevel", @sealed, true); new LazilyLoadedCtor(scope, "Continuation", "org.mozilla.javascript.NativeContinuation", @sealed, true); foreach (string packageName in GetTopPackageNames()) { new LazilyLoadedCtor(scope, packageName, "org.mozilla.javascript.NativeJavaTopPackage", @sealed, true); } if (withXml) { string xmlImpl = cx.GetE4xImplementationFactory().GetImplementationClassName(); new LazilyLoadedCtor(scope, "XML", xmlImpl, @sealed, true); new LazilyLoadedCtor(scope, "XMLList", xmlImpl, @sealed, true); new LazilyLoadedCtor(scope, "Namespace", xmlImpl, @sealed, true); new LazilyLoadedCtor(scope, "QName", xmlImpl, @sealed, true); } if (scope is TopLevel) { ((TopLevel)scope).CacheBuiltins(); } return scope; }
public override object ExecIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, object[] args) { if (!f.HasTag(DATE_TAG)) { return base.ExecIdCall(f, cx, scope, thisObj, args); } int id = f.MethodId(); switch (id) { case ConstructorId_now: { return ScriptRuntime.WrapNumber(Now()); } case ConstructorId_parse: { string dataStr = ScriptRuntime.ToString(args, 0); return ScriptRuntime.WrapNumber(Date_parseString(dataStr)); } case ConstructorId_UTC: { return ScriptRuntime.WrapNumber(JsStaticFunction_UTC(args)); } case Id_constructor: { // if called as a function, just return a string // representing the current time. if (thisObj != null) { return Date_format(Now(), Id_toString); } return JsConstructor(args); } case Id_toJSON: { if (thisObj is Rhino.NativeDate) { return ((Rhino.NativeDate)thisObj).ToISOString(); } string toISOString = "toISOString"; Scriptable o = ScriptRuntime.ToObject(cx, scope, thisObj); object tv = ScriptRuntime.ToPrimitive(o, ScriptRuntime.NumberClass); if (tv is Number) { double d = System.Convert.ToDouble(((Number)tv)); if (d != d || System.Double.IsInfinity(d)) { return null; } } object toISO = o.Get(toISOString, o); if (toISO == ScriptableConstants.NOT_FOUND) { throw ScriptRuntime.TypeError2("msg.function.not.found.in", toISOString, ScriptRuntime.ToString(o)); } if (!(toISO is Callable)) { throw ScriptRuntime.TypeError3("msg.isnt.function.in", toISOString, ScriptRuntime.ToString(o), ScriptRuntime.ToString(toISO)); } object result = ((Callable)toISO).Call(cx, scope, o, ScriptRuntime.emptyArgs); if (!ScriptRuntime.IsPrimitive(result)) { throw ScriptRuntime.TypeError1("msg.toisostring.must.return.primitive", ScriptRuntime.ToString(result)); } return result; } } // The rest of Date.prototype methods require thisObj to be Date if (!(thisObj is Rhino.NativeDate)) { throw IncompatibleCallError(f); } Rhino.NativeDate realThis = (Rhino.NativeDate)thisObj; double t = realThis.date; switch (id) { case Id_toString: case Id_toTimeString: case Id_toDateString: { if (t == t) { return Date_format(t, id); } return js_NaN_date_str; } case Id_toLocaleString: case Id_toLocaleTimeString: case Id_toLocaleDateString: { if (t == t) { return ToLocale_helper(t, id); } return js_NaN_date_str; } case Id_toUTCString: { if (t == t) { return Js_toUTCString(t); } return js_NaN_date_str; } case Id_toSource: { return "(new Date(" + ScriptRuntime.ToString(t) + "))"; } case Id_valueOf: case Id_getTime: { return ScriptRuntime.WrapNumber(t); } case Id_getYear: case Id_getFullYear: case Id_getUTCFullYear: { if (t == t) { if (id != Id_getUTCFullYear) { t = LocalTime(t); } t = YearFromTime(t); if (id == Id_getYear) { if (cx.HasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) { if (1900 <= t && t < 2000) { t -= 1900; } } else { t -= 1900; } } } return ScriptRuntime.WrapNumber(t); } case Id_getMonth: case Id_getUTCMonth: { if (t == t) { if (id == Id_getMonth) { t = LocalTime(t); } t = MonthFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getDate: case Id_getUTCDate: { if (t == t) { if (id == Id_getDate) { t = LocalTime(t); } t = DateFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getDay: case Id_getUTCDay: { if (t == t) { if (id == Id_getDay) { t = LocalTime(t); } t = WeekDay(t); } return ScriptRuntime.WrapNumber(t); } case Id_getHours: case Id_getUTCHours: { if (t == t) { if (id == Id_getHours) { t = LocalTime(t); } t = HourFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getMinutes: case Id_getUTCMinutes: { if (t == t) { if (id == Id_getMinutes) { t = LocalTime(t); } t = MinFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getSeconds: case Id_getUTCSeconds: { if (t == t) { if (id == Id_getSeconds) { t = LocalTime(t); } t = SecFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getMilliseconds: case Id_getUTCMilliseconds: { if (t == t) { if (id == Id_getMilliseconds) { t = LocalTime(t); } t = MsFromTime(t); } return ScriptRuntime.WrapNumber(t); } case Id_getTimezoneOffset: { if (t == t) { t = (t - LocalTime(t)) / msPerMinute; } return ScriptRuntime.WrapNumber(t); } case Id_setTime: { t = TimeClip(ScriptRuntime.ToNumber(args, 0)); realThis.date = t; return ScriptRuntime.WrapNumber(t); } case Id_setMilliseconds: case Id_setUTCMilliseconds: case Id_setSeconds: case Id_setUTCSeconds: case Id_setMinutes: case Id_setUTCMinutes: case Id_setHours: case Id_setUTCHours: { t = MakeTime(t, args, id); realThis.date = t; return ScriptRuntime.WrapNumber(t); } case Id_setDate: case Id_setUTCDate: case Id_setMonth: case Id_setUTCMonth: case Id_setFullYear: case Id_setUTCFullYear: { t = MakeDate(t, args, id); realThis.date = t; return ScriptRuntime.WrapNumber(t); } case Id_setYear: { double year = ScriptRuntime.ToNumber(args, 0); if (year != year || System.Double.IsInfinity(year)) { t = ScriptRuntime.NaN; } else { if (t != t) { t = 0; } else { t = LocalTime(t); } if (year >= 0 && year <= 99) { year += 1900; } double day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); t = MakeDate(day, TimeWithinDay(t)); t = InternalUTC(t); t = TimeClip(t); } realThis.date = t; return ScriptRuntime.WrapNumber(t); } case Id_toISOString: { return realThis.ToISOString(); } default: { throw new ArgumentException(id.ToString()); } } }
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); }
/// <summary> /// Find the index of the correct function to call given the set of methods /// or constructors and the arguments. /// </summary> /// <remarks> /// Find the index of the correct function to call given the set of methods /// or constructors and the arguments. /// If no function can be found to call, return -1. /// </remarks> internal static int FindFunction(Context cx, MemberBox[] methodsOrCtors, object[] args) { if (methodsOrCtors.Length == 0) { return -1; } else { if (methodsOrCtors.Length == 1) { MemberBox member = methodsOrCtors[0]; Type[] argTypes = member.argTypes; int alength = argTypes.Length; if (member.vararg) { alength--; if (alength > args.Length) { return -1; } } else { if (alength != args.Length) { return -1; } } for (int j = 0; j != alength; ++j) { if (!NativeJavaObject.CanConvert(args[j], argTypes[j])) { return -1; } } return 0; } } int firstBestFit = -1; int[] extraBestFits = null; int extraBestFitsCount = 0; for (int i = 0; i < methodsOrCtors.Length; i++) { MemberBox member = methodsOrCtors[i]; Type[] argTypes = member.argTypes; int alength = argTypes.Length; if (member.vararg) { alength--; if (alength > args.Length) { goto search_continue; } } else { if (alength != args.Length) { goto search_continue; } } for (int j = 0; j < alength; j++) { if (!NativeJavaObject.CanConvert(args[j], argTypes[j])) { goto search_continue; } } if (firstBestFit < 0) { firstBestFit = i; } else { // Compare with all currently fit methods. // The loop starts from -1 denoting firstBestFit and proceed // until extraBestFitsCount to avoid extraBestFits allocation // in the most common case of no ambiguity int betterCount = 0; // number of times member was prefered over // best fits int worseCount = 0; // number of times best fits were prefered // over member for (int j_1 = -1; j_1 != extraBestFitsCount; ++j_1) { int bestFitIndex; if (j_1 == -1) { bestFitIndex = firstBestFit; } else { bestFitIndex = extraBestFits[j_1]; } MemberBox bestFit = methodsOrCtors[bestFitIndex]; if (cx.HasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS) && (bestFit.Member().Attributes & Modifier.PUBLIC) != (member.Member().Attributes & Modifier.PUBLIC)) { // When FEATURE_ENHANCED_JAVA_ACCESS gives us access // to non-public members, continue to prefer public // methods in overloading if ((bestFit.Member().Attributes & Modifier.PUBLIC) == 0) { ++betterCount; } else { ++worseCount; } } else { int preference = PreferSignature(args, argTypes, member.vararg, bestFit.argTypes, bestFit.vararg); if (preference == PREFERENCE_AMBIGUOUS) { break; } else { if (preference == PREFERENCE_FIRST_ARG) { ++betterCount; } else { if (preference == PREFERENCE_SECOND_ARG) { ++worseCount; } else { if (preference != PREFERENCE_EQUAL) { Kit.CodeBug(); } // This should not happen in theory // but on some JVMs, Class.getMethods will return all // static methods of the class hierarchy, even if // a derived class's parameters match exactly. // We want to call the derived class's method. if (bestFit.IsStatic() && bestFit.GetDeclaringClass().IsAssignableFrom(member.GetDeclaringClass())) { // On some JVMs, Class.getMethods will return all // static methods of the class hierarchy, even if // a derived class's parameters match exactly. // We want to call the derived class's method. if (j_1 == -1) { firstBestFit = i; } else { extraBestFits[j_1] = i; } } goto search_continue; } } } } } if (betterCount == 1 + extraBestFitsCount) { // member was prefered over all best fits firstBestFit = i; extraBestFitsCount = 0; } else { if (worseCount == 1 + extraBestFitsCount) { } else { // all best fits were prefered over member, ignore it // some ambiguity was present, add member to best fit set if (extraBestFits == null) { // Allocate maximum possible array extraBestFits = new int[methodsOrCtors.Length - 1]; } extraBestFits[extraBestFitsCount] = i; ++extraBestFitsCount; } } } search_continue: ; } search_break: ; if (firstBestFit < 0) { // Nothing was found return -1; } else { if (extraBestFitsCount == 0) { // single best fit return firstBestFit; } } // report remaining ambiguity StringBuilder buf = new StringBuilder(); for (int j_2 = -1; j_2 != extraBestFitsCount; ++j_2) { int bestFitIndex; if (j_2 == -1) { bestFitIndex = firstBestFit; } else { bestFitIndex = extraBestFits[j_2]; } buf.Append("\n "); buf.Append(methodsOrCtors[bestFitIndex].ToJavaDeclaration()); } MemberBox firstFitMember = methodsOrCtors[firstBestFit]; string memberName = firstFitMember.GetName(); string memberClass = firstFitMember.GetDeclaringClass().FullName; if (methodsOrCtors[0].IsCtor()) { throw Context.ReportRuntimeError3("msg.constructor.ambiguous", memberName, ScriptSignature(args), buf.ToString()); } else { throw Context.ReportRuntimeError4("msg.method.ambiguous", memberClass, memberName, ScriptSignature(args), buf.ToString()); } }
private static void ReportWarning(Context cx, string messageId, string arg) { if (cx.HasFeature(Context.FEATURE_STRICT_MODE)) { string msg = ScriptRuntime.GetMessage1(messageId, arg); Context.ReportWarning(msg); } }