summaryrefslogtreecommitdiffstats
path: root/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java')
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java4643
1 files changed, 0 insertions, 4643 deletions
diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
deleted file mode 100644
index a68c025..0000000
--- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java
+++ /dev/null
@@ -1,4643 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Patrick Beard
- * Norris Boyd
- * Igor Bukanov
- * Ethan Hugg
- * Bob Jervis
- * Terry Lucas
- * Roger Lawrence
- * Milen Nankov
- * Hannes Wallnoefer
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import java.io.PrintStream;
-import java.io.Serializable;
-import java.util.List;
-import java.util.ArrayList;
-
-import org.mozilla.javascript.continuations.Continuation;
-import org.mozilla.javascript.debug.DebugFrame;
-
-public class Interpreter implements Evaluator
-{
-
-// Additional interpreter-specific codes
-
- private static final int
-
- // Stack: ... value1 -> ... value1 value1
- Icode_DUP = -1,
-
- // Stack: ... value2 value1 -> ... value2 value1 value2 value1
- Icode_DUP2 = -2,
-
- // Stack: ... value2 value1 -> ... value1 value2
- Icode_SWAP = -3,
-
- // Stack: ... value1 -> ...
- Icode_POP = -4,
-
- // Store stack top into return register and then pop it
- Icode_POP_RESULT = -5,
-
- // To jump conditionally and pop additional stack value
- Icode_IFEQ_POP = -6,
-
- // various types of ++/--
- Icode_VAR_INC_DEC = -7,
- Icode_NAME_INC_DEC = -8,
- Icode_PROP_INC_DEC = -9,
- Icode_ELEM_INC_DEC = -10,
- Icode_REF_INC_DEC = -11,
-
- // load/save scope from/to local
- Icode_SCOPE_LOAD = -12,
- Icode_SCOPE_SAVE = -13,
-
- Icode_TYPEOFNAME = -14,
-
- // helper for function calls
- Icode_NAME_AND_THIS = -15,
- Icode_PROP_AND_THIS = -16,
- Icode_ELEM_AND_THIS = -17,
- Icode_VALUE_AND_THIS = -18,
-
- // Create closure object for nested functions
- Icode_CLOSURE_EXPR = -19,
- Icode_CLOSURE_STMT = -20,
-
- // Special calls
- Icode_CALLSPECIAL = -21,
-
- // To return undefined value
- Icode_RETUNDEF = -22,
-
- // Exception handling implementation
- Icode_GOSUB = -23,
- Icode_STARTSUB = -24,
- Icode_RETSUB = -25,
-
- // To indicating a line number change in icodes.
- Icode_LINE = -26,
-
- // To store shorts and ints inline
- Icode_SHORTNUMBER = -27,
- Icode_INTNUMBER = -28,
-
- // To create and populate array to hold values for [] and {} literals
- Icode_LITERAL_NEW = -29,
- Icode_LITERAL_SET = -30,
-
- // Array literal with skipped index like [1,,2]
- Icode_SPARE_ARRAYLIT = -31,
-
- // Load index register to prepare for the following index operation
- Icode_REG_IND_C0 = -32,
- Icode_REG_IND_C1 = -33,
- Icode_REG_IND_C2 = -34,
- Icode_REG_IND_C3 = -35,
- Icode_REG_IND_C4 = -36,
- Icode_REG_IND_C5 = -37,
- Icode_REG_IND1 = -38,
- Icode_REG_IND2 = -39,
- Icode_REG_IND4 = -40,
-
- // Load string register to prepare for the following string operation
- Icode_REG_STR_C0 = -41,
- Icode_REG_STR_C1 = -42,
- Icode_REG_STR_C2 = -43,
- Icode_REG_STR_C3 = -44,
- Icode_REG_STR1 = -45,
- Icode_REG_STR2 = -46,
- Icode_REG_STR4 = -47,
-
- // Version of getvar/setvar that read var index directly from bytecode
- Icode_GETVAR1 = -48,
- Icode_SETVAR1 = -49,
-
- // Load unefined
- Icode_UNDEF = -50,
- Icode_ZERO = -51,
- Icode_ONE = -52,
-
- // entrance and exit from .()
- Icode_ENTERDQ = -53,
- Icode_LEAVEDQ = -54,
-
- Icode_TAIL_CALL = -55,
-
- // Clear local to allow GC its context
- Icode_LOCAL_CLEAR = -56,
-
- // Literal get/set
- Icode_LITERAL_GETTER = -57,
- Icode_LITERAL_SETTER = -58,
-
- // const
- Icode_SETCONST = -59,
- Icode_SETCONSTVAR = -60,
- Icode_SETCONSTVAR1 = -61,
-
- // Generator opcodes (along with Token.YIELD)
- Icode_GENERATOR = -62,
- Icode_GENERATOR_END = -63,
-
- Icode_DEBUGGER = -64,
-
- // Last icode
- MIN_ICODE = -64;
-
- // data for parsing
-
- private CompilerEnvirons compilerEnv;
-
- private boolean itsInFunctionFlag;
- private boolean itsInTryFlag;
-
- private InterpreterData itsData;
- private ScriptOrFnNode scriptOrFn;
- private int itsICodeTop;
- private int itsStackDepth;
- private int itsLineNumber;
- private int itsDoubleTableTop;
- private ObjToIntMap itsStrings = new ObjToIntMap(20);
- private int itsLocalTop;
-
- private static final int MIN_LABEL_TABLE_SIZE = 32;
- private static final int MIN_FIXUP_TABLE_SIZE = 40;
- private int[] itsLabelTable;
- private int itsLabelTableTop;
-// itsFixupTable[i] = (label_index << 32) | fixup_site
- private long[] itsFixupTable;
- private int itsFixupTableTop;
- private ObjArray itsLiteralIds = new ObjArray();
-
- private int itsExceptionTableTop;
- private static final int EXCEPTION_TRY_START_SLOT = 0;
- private static final int EXCEPTION_TRY_END_SLOT = 1;
- private static final int EXCEPTION_HANDLER_SLOT = 2;
- private static final int EXCEPTION_TYPE_SLOT = 3;
- private static final int EXCEPTION_LOCAL_SLOT = 4;
- private static final int EXCEPTION_SCOPE_SLOT = 5;
- // SLOT_SIZE: space for try start/end, handler, start, handler type,
- // exception local and scope local
- private static final int EXCEPTION_SLOT_SIZE = 6;
-
-// ECF_ or Expression Context Flags constants: for now only TAIL is available
- private static final int ECF_TAIL = 1 << 0;
-
- /**
- * Class to hold data corresponding to one interpreted call stack frame.
- */
- private static class CallFrame implements Cloneable, Serializable
- {
- static final long serialVersionUID = -2843792508994958978L;
-
- CallFrame parentFrame;
- // amount of stack frames before this one on the interpretation stack
- int frameIndex;
- // If true indicates read-only frame that is a part of continuation
- boolean frozen;
-
- InterpretedFunction fnOrScript;
- InterpreterData idata;
-
-// Stack structure
-// stack[0 <= i < localShift]: arguments and local variables
-// stack[localShift <= i <= emptyStackTop]: used for local temporaries
-// stack[emptyStackTop < i < stack.length]: stack data
-// sDbl[i]: if stack[i] is UniqueTag.DOUBLE_MARK, sDbl[i] holds the number value
-
- Object[] stack;
- int[] stackAttributes;
- double[] sDbl;
- CallFrame varSource; // defaults to this unless continuation frame
- int localShift;
- int emptyStackTop;
-
- DebugFrame debuggerFrame;
- boolean useActivation;
-
- Scriptable thisObj;
- Scriptable[] scriptRegExps;
-
-// The values that change during interpretation
-
- Object result;
- double resultDbl;
- int pc;
- int pcPrevBranch;
- int pcSourceLineStart;
- Scriptable scope;
-
- int savedStackTop;
- int savedCallOp;
- Object throwable;
-
- CallFrame cloneFrozen()
- {
- if (!frozen) Kit.codeBug();
-
- CallFrame copy;
- try {
- copy = (CallFrame)clone();
- } catch (CloneNotSupportedException ex) {
- throw new IllegalStateException();
- }
-
- // clone stack but keep varSource to point to values
- // from this frame to share variables.
-
- copy.stack = stack.clone();
- copy.stackAttributes = stackAttributes.clone();
- copy.sDbl = sDbl.clone();
-
- copy.frozen = false;
- return copy;
- }
- }
-
- private static final class ContinuationJump implements Serializable
- {
- static final long serialVersionUID = 7687739156004308247L;
-
- CallFrame capturedFrame;
- CallFrame branchFrame;
- Object result;
- double resultDbl;
-
- ContinuationJump(Continuation c, CallFrame current)
- {
- this.capturedFrame = (CallFrame)c.getImplementation();
- if (this.capturedFrame == null || current == null) {
- // Continuation and current execution does not share
- // any frames if there is nothing to capture or
- // if there is no currently executed frames
- this.branchFrame = null;
- } else {
- // Search for branch frame where parent frame chains starting
- // from captured and current meet.
- CallFrame chain1 = this.capturedFrame;
- CallFrame chain2 = current;
-
- // First work parents of chain1 or chain2 until the same
- // frame depth.
- int diff = chain1.frameIndex - chain2.frameIndex;
- if (diff != 0) {
- if (diff < 0) {
- // swap to make sure that
- // chain1.frameIndex > chain2.frameIndex and diff > 0
- chain1 = current;
- chain2 = this.capturedFrame;
- diff = -diff;
- }
- do {
- chain1 = chain1.parentFrame;
- } while (--diff != 0);
- if (chain1.frameIndex != chain2.frameIndex) Kit.codeBug();
- }
-
- // Now walk parents in parallel until a shared frame is found
- // or until the root is reached.
- while (chain1 != chain2 && chain1 != null) {
- chain1 = chain1.parentFrame;
- chain2 = chain2.parentFrame;
- }
-
- this.branchFrame = chain1;
- if (this.branchFrame != null && !this.branchFrame.frozen)
- Kit.codeBug();
- }
- }
- }
-
- private static CallFrame captureFrameForGenerator(CallFrame frame) {
- frame.frozen = true;
- CallFrame result = frame.cloneFrozen();
- frame.frozen = false;
-
- // now isolate this frame from its previous context
- result.parentFrame = null;
- result.frameIndex = 0;
-
- return result;
- }
-
- static {
- // Checks for byte code consistencies, good compiler can eliminate them
-
- if (Token.LAST_BYTECODE_TOKEN > 127) {
- String str = "Violation of Token.LAST_BYTECODE_TOKEN <= 127";
- System.err.println(str);
- throw new IllegalStateException(str);
- }
- if (MIN_ICODE < -128) {
- String str = "Violation of Interpreter.MIN_ICODE >= -128";
- System.err.println(str);
- throw new IllegalStateException(str);
- }
- }
-
- private static String bytecodeName(int bytecode)
- {
- if (!validBytecode(bytecode)) {
- throw new IllegalArgumentException(String.valueOf(bytecode));
- }
-
- if (!Token.printICode) {
- return String.valueOf(bytecode);
- }
-
- if (validTokenCode(bytecode)) {
- return Token.name(bytecode);
- }
-
- switch (bytecode) {
- case Icode_DUP: return "DUP";
- case Icode_DUP2: return "DUP2";
- case Icode_SWAP: return "SWAP";
- case Icode_POP: return "POP";
- case Icode_POP_RESULT: return "POP_RESULT";
- case Icode_IFEQ_POP: return "IFEQ_POP";
- case Icode_VAR_INC_DEC: return "VAR_INC_DEC";
- case Icode_NAME_INC_DEC: return "NAME_INC_DEC";
- case Icode_PROP_INC_DEC: return "PROP_INC_DEC";
- case Icode_ELEM_INC_DEC: return "ELEM_INC_DEC";
- case Icode_REF_INC_DEC: return "REF_INC_DEC";
- case Icode_SCOPE_LOAD: return "SCOPE_LOAD";
- case Icode_SCOPE_SAVE: return "SCOPE_SAVE";
- case Icode_TYPEOFNAME: return "TYPEOFNAME";
- case Icode_NAME_AND_THIS: return "NAME_AND_THIS";
- case Icode_PROP_AND_THIS: return "PROP_AND_THIS";
- case Icode_ELEM_AND_THIS: return "ELEM_AND_THIS";
- case Icode_VALUE_AND_THIS: return "VALUE_AND_THIS";
- case Icode_CLOSURE_EXPR: return "CLOSURE_EXPR";
- case Icode_CLOSURE_STMT: return "CLOSURE_STMT";
- case Icode_CALLSPECIAL: return "CALLSPECIAL";
- case Icode_RETUNDEF: return "RETUNDEF";
- case Icode_GOSUB: return "GOSUB";
- case Icode_STARTSUB: return "STARTSUB";
- case Icode_RETSUB: return "RETSUB";
- case Icode_LINE: return "LINE";
- case Icode_SHORTNUMBER: return "SHORTNUMBER";
- case Icode_INTNUMBER: return "INTNUMBER";
- case Icode_LITERAL_NEW: return "LITERAL_NEW";
- case Icode_LITERAL_SET: return "LITERAL_SET";
- case Icode_SPARE_ARRAYLIT: return "SPARE_ARRAYLIT";
- case Icode_REG_IND_C0: return "REG_IND_C0";
- case Icode_REG_IND_C1: return "REG_IND_C1";
- case Icode_REG_IND_C2: return "REG_IND_C2";
- case Icode_REG_IND_C3: return "REG_IND_C3";
- case Icode_REG_IND_C4: return "REG_IND_C4";
- case Icode_REG_IND_C5: return "REG_IND_C5";
- case Icode_REG_IND1: return "LOAD_IND1";
- case Icode_REG_IND2: return "LOAD_IND2";
- case Icode_REG_IND4: return "LOAD_IND4";
- case Icode_REG_STR_C0: return "REG_STR_C0";
- case Icode_REG_STR_C1: return "REG_STR_C1";
- case Icode_REG_STR_C2: return "REG_STR_C2";
- case Icode_REG_STR_C3: return "REG_STR_C3";
- case Icode_REG_STR1: return "LOAD_STR1";
- case Icode_REG_STR2: return "LOAD_STR2";
- case Icode_REG_STR4: return "LOAD_STR4";
- case Icode_GETVAR1: return "GETVAR1";
- case Icode_SETVAR1: return "SETVAR1";
- case Icode_UNDEF: return "UNDEF";
- case Icode_ZERO: return "ZERO";
- case Icode_ONE: return "ONE";
- case Icode_ENTERDQ: return "ENTERDQ";
- case Icode_LEAVEDQ: return "LEAVEDQ";
- case Icode_TAIL_CALL: return "TAIL_CALL";
- case Icode_LOCAL_CLEAR: return "LOCAL_CLEAR";
- case Icode_LITERAL_GETTER: return "LITERAL_GETTER";
- case Icode_LITERAL_SETTER: return "LITERAL_SETTER";
- case Icode_SETCONST: return "SETCONST";
- case Icode_SETCONSTVAR: return "SETCONSTVAR";
- case Icode_SETCONSTVAR1: return "SETCONSTVAR1";
- case Icode_GENERATOR: return "GENERATOR";
- case Icode_GENERATOR_END: return "GENERATOR_END";
- case Icode_DEBUGGER: return "DEBUGGER";
- }
-
- // icode without name
- throw new IllegalStateException(String.valueOf(bytecode));
- }
-
- private static boolean validIcode(int icode)
- {
- return MIN_ICODE <= icode && icode <= -1;
- }
-
- private static boolean validTokenCode(int token)
- {
- return Token.FIRST_BYTECODE_TOKEN <= token
- && token <= Token.LAST_BYTECODE_TOKEN;
- }
-
- private static boolean validBytecode(int bytecode)
- {
- return validIcode(bytecode) || validTokenCode(bytecode);
- }
-
- public Object compile(CompilerEnvirons compilerEnv,
- ScriptOrFnNode tree,
- String encodedSource,
- boolean returnFunction)
- {
- this.compilerEnv = compilerEnv;
- new NodeTransformer().transform(tree);
-
- if (Token.printTrees) {
- /*APPJET*///System.out.println(tree.toStringTree(tree));
- }
-
- if (returnFunction) {
- tree = tree.getFunctionNode(0);
- }
-
- scriptOrFn = tree;
- itsData = new InterpreterData(compilerEnv.getLanguageVersion(),
- scriptOrFn.getSourceName(),
- encodedSource);
- itsData.topLevel = true;
-
- if (returnFunction) {
- generateFunctionICode();
- } else {
- generateICodeFromTree(scriptOrFn);
- }
-
- return itsData;
- }
-
- public Script createScriptObject(Object bytecode, Object staticSecurityDomain)
- {
- if(bytecode != itsData)
- {
- Kit.codeBug();
- }
- return InterpretedFunction.createScript(itsData,
- staticSecurityDomain);
- }
-
- public void setEvalScriptFlag(Script script) {
- ((InterpretedFunction)script).idata.evalScriptFlag = true;
- }
-
-
- public Function createFunctionObject(Context cx, Scriptable scope,
- Object bytecode, Object staticSecurityDomain)
- {
- if(bytecode != itsData)
- {
- Kit.codeBug();
- }
- return InterpretedFunction.createFunction(cx, scope, itsData,
- staticSecurityDomain);
- }
-
- private void generateFunctionICode()
- {
- itsInFunctionFlag = true;
-
- FunctionNode theFunction = (FunctionNode)scriptOrFn;
-
- itsData.itsFunctionType = theFunction.getFunctionType();
- itsData.itsNeedsActivation = theFunction.requiresActivation();
- itsData.itsName = theFunction.getFunctionName();
- if (!theFunction.getIgnoreDynamicScope()) {
- if (compilerEnv.isUseDynamicScope()) {
- itsData.useDynamicScope = true;
- }
- }
- if (theFunction.isGenerator()) {
- addIcode(Icode_GENERATOR);
- addUint16(theFunction.getBaseLineno() & 0xFFFF);
- }
-
- generateICodeFromTree(theFunction.getLastChild());
- }
-
- private void generateICodeFromTree(Node tree)
- {
- generateNestedFunctions();
-
- generateRegExpLiterals();
-
- visitStatement(tree, 0);
- fixLabelGotos();
- // add RETURN_RESULT only to scripts as function always ends with RETURN
- if (itsData.itsFunctionType == 0) {
- addToken(Token.RETURN_RESULT);
- }
-
- if (itsData.itsICode.length != itsICodeTop) {
- // Make itsData.itsICode length exactly itsICodeTop to save memory
- // and catch bugs with jumps beyond icode as early as possible
- byte[] tmp = new byte[itsICodeTop];
- System.arraycopy(itsData.itsICode, 0, tmp, 0, itsICodeTop);
- itsData.itsICode = tmp;
- }
- if (itsStrings.size() == 0) {
- itsData.itsStringTable = null;
- } else {
- itsData.itsStringTable = new String[itsStrings.size()];
- ObjToIntMap.Iterator iter = itsStrings.newIterator();
- for (iter.start(); !iter.done(); iter.next()) {
- String str = (String)iter.getKey();
- int index = iter.getValue();
- if (itsData.itsStringTable[index] != null) Kit.codeBug();
- itsData.itsStringTable[index] = str;
- }
- }
- if (itsDoubleTableTop == 0) {
- itsData.itsDoubleTable = null;
- } else if (itsData.itsDoubleTable.length != itsDoubleTableTop) {
- double[] tmp = new double[itsDoubleTableTop];
- System.arraycopy(itsData.itsDoubleTable, 0, tmp, 0,
- itsDoubleTableTop);
- itsData.itsDoubleTable = tmp;
- }
- if (itsExceptionTableTop != 0
- && itsData.itsExceptionTable.length != itsExceptionTableTop)
- {
- int[] tmp = new int[itsExceptionTableTop];
- System.arraycopy(itsData.itsExceptionTable, 0, tmp, 0,
- itsExceptionTableTop);
- itsData.itsExceptionTable = tmp;
- }
-
- itsData.itsMaxVars = scriptOrFn.getParamAndVarCount();
- // itsMaxFrameArray: interpret method needs this amount for its
- // stack and sDbl arrays
- itsData.itsMaxFrameArray = itsData.itsMaxVars
- + itsData.itsMaxLocals
- + itsData.itsMaxStack;
-
- itsData.argNames = scriptOrFn.getParamAndVarNames();
- itsData.argIsConst = scriptOrFn.getParamAndVarConst();
- itsData.argCount = scriptOrFn.getParamCount();
-
- itsData.encodedSourceStart = scriptOrFn.getEncodedSourceStart();
- itsData.encodedSourceEnd = scriptOrFn.getEncodedSourceEnd();
-
- if (itsLiteralIds.size() != 0) {
- itsData.literalIds = itsLiteralIds.toArray();
- }
-
- if (Token.printICode) dumpICode(itsData);
- }
-
- private void generateNestedFunctions()
- {
- int functionCount = scriptOrFn.getFunctionCount();
- if (functionCount == 0) return;
-
- InterpreterData[] array = new InterpreterData[functionCount];
- for (int i = 0; i != functionCount; i++) {
- FunctionNode def = scriptOrFn.getFunctionNode(i);
- Interpreter jsi = new Interpreter();
- jsi.compilerEnv = compilerEnv;
- jsi.scriptOrFn = def;
- jsi.itsData = new InterpreterData(itsData);
- jsi.generateFunctionICode();
- array[i] = jsi.itsData;
- }
- itsData.itsNestedFunctions = array;
- }
-
- private void generateRegExpLiterals()
- {
- int N = scriptOrFn.getRegexpCount();
- if (N == 0) return;
-
- Context cx = Context.getContext();
- RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx);
- Object[] array = new Object[N];
- for (int i = 0; i != N; i++) {
- String string = scriptOrFn.getRegexpString(i);
- String flags = scriptOrFn.getRegexpFlags(i);
- array[i] = rep.compileRegExp(cx, string, flags);
- }
- itsData.itsRegExpLiterals = array;
- }
-
- private void updateLineNumber(Node node)
- {
- int lineno = node.getLineno();
- if (lineno != itsLineNumber && lineno >= 0) {
- if (itsData.firstLinePC < 0) {
- itsData.firstLinePC = lineno;
- }
- itsLineNumber = lineno;
- addIcode(Icode_LINE);
- addUint16(lineno & 0xFFFF);
- }
- }
-
- private RuntimeException badTree(Node node)
- {
- throw new RuntimeException(node.toString());
- }
-
- private void visitStatement(Node node, int initialStackDepth)
- {
- int type = node.getType();
- Node child = node.getFirstChild();
- switch (type) {
-
- case Token.FUNCTION:
- {
- int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
- int fnType = scriptOrFn.getFunctionNode(fnIndex).
- getFunctionType();
- // Only function expressions or function expression
- // statements need closure code creating new function
- // object on stack as function statements are initialized
- // at script/function start.
- // In addition, function expressions can not be present here
- // at statement level, they must only be present as expressions.
- if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
- addIndexOp(Icode_CLOSURE_STMT, fnIndex);
- } else {
- if (fnType != FunctionNode.FUNCTION_STATEMENT) {
- throw Kit.codeBug();
- }
- }
- // For function statements or function expression statements
- // in scripts, we need to ensure that the result of the script
- // is the function if it is the last statement in the script.
- // For example, eval("function () {}") should return a
- // function, not undefined.
- if (!itsInFunctionFlag) {
- addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
- stackChange(1);
- addIcode(Icode_POP_RESULT);
- stackChange(-1);
- }
- }
- break;
-
- case Token.LABEL:
- case Token.LOOP:
- case Token.BLOCK:
- case Token.EMPTY:
- case Token.WITH:
- updateLineNumber(node);
- case Token.SCRIPT:
- // fall through
- while (child != null) {
- visitStatement(child, initialStackDepth);
- child = child.getNext();
- }
- break;
-
- case Token.ENTERWITH:
- visitExpression(child, 0);
- addToken(Token.ENTERWITH);
- stackChange(-1);
- break;
-
- case Token.LEAVEWITH:
- addToken(Token.LEAVEWITH);
- break;
-
- case Token.LOCAL_BLOCK:
- {
- int local = allocLocal();
- node.putIntProp(Node.LOCAL_PROP, local);
- updateLineNumber(node);
- while (child != null) {
- visitStatement(child, initialStackDepth);
- child = child.getNext();
- }
- addIndexOp(Icode_LOCAL_CLEAR, local);
- releaseLocal(local);
- }
- break;
-
- case Token.DEBUGGER:
- addIcode(Icode_DEBUGGER);
- break;
-
- case Token.SWITCH:
- updateLineNumber(node);
- // See comments in IRFactory.createSwitch() for description
- // of SWITCH node
- {
- visitExpression(child, 0);
- for (Node.Jump caseNode = (Node.Jump)child.getNext();
- caseNode != null;
- caseNode = (Node.Jump)caseNode.getNext())
- {
- if (caseNode.getType() != Token.CASE)
- throw badTree(caseNode);
- Node test = caseNode.getFirstChild();
- addIcode(Icode_DUP);
- stackChange(1);
- visitExpression(test, 0);
- addToken(Token.SHEQ);
- stackChange(-1);
- // If true, Icode_IFEQ_POP will jump and remove case
- // value from stack
- addGoto(caseNode.target, Icode_IFEQ_POP);
- stackChange(-1);
- }
- addIcode(Icode_POP);
- stackChange(-1);
- }
- break;
-
- case Token.TARGET:
- markTargetLabel(node);
- break;
-
- case Token.IFEQ :
- case Token.IFNE :
- {
- Node target = ((Node.Jump)node).target;
- visitExpression(child, 0);
- addGoto(target, type);
- stackChange(-1);
- }
- break;
-
- case Token.GOTO:
- {
- Node target = ((Node.Jump)node).target;
- addGoto(target, type);
- }
- break;
-
- case Token.JSR:
- {
- Node target = ((Node.Jump)node).target;
- addGoto(target, Icode_GOSUB);
- }
- break;
-
- case Token.FINALLY:
- {
- // Account for incomming GOTOSUB address
- stackChange(1);
- int finallyRegister = getLocalBlockRef(node);
- addIndexOp(Icode_STARTSUB, finallyRegister);
- stackChange(-1);
- while (child != null) {
- visitStatement(child, initialStackDepth);
- child = child.getNext();
- }
- addIndexOp(Icode_RETSUB, finallyRegister);
- }
- break;
-
- case Token.EXPR_VOID:
- case Token.EXPR_RESULT:
- updateLineNumber(node);
- visitExpression(child, 0);
- addIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
- stackChange(-1);
- break;
-
- case Token.TRY:
- {
- Node.Jump tryNode = (Node.Jump)node;
- int exceptionObjectLocal = getLocalBlockRef(tryNode);
- int scopeLocal = allocLocal();
-
- addIndexOp(Icode_SCOPE_SAVE, scopeLocal);
-
- int tryStart = itsICodeTop;
- boolean savedFlag = itsInTryFlag;
- itsInTryFlag = true;
- while (child != null) {
- visitStatement(child, initialStackDepth);
- child = child.getNext();
- }
- itsInTryFlag = savedFlag;
-
- Node catchTarget = tryNode.target;
- if (catchTarget != null) {
- int catchStartPC
- = itsLabelTable[getTargetLabel(catchTarget)];
- addExceptionHandler(
- tryStart, catchStartPC, catchStartPC,
- false, exceptionObjectLocal, scopeLocal);
- }
- Node finallyTarget = tryNode.getFinally();
- if (finallyTarget != null) {
- int finallyStartPC
- = itsLabelTable[getTargetLabel(finallyTarget)];
- addExceptionHandler(
- tryStart, finallyStartPC, finallyStartPC,
- true, exceptionObjectLocal, scopeLocal);
- }
-
- addIndexOp(Icode_LOCAL_CLEAR, scopeLocal);
- releaseLocal(scopeLocal);
- }
- break;
-
- case Token.CATCH_SCOPE:
- {
- int localIndex = getLocalBlockRef(node);
- int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
- String name = child.getString();
- child = child.getNext();
- visitExpression(child, 0); // load expression object
- addStringPrefix(name);
- addIndexPrefix(localIndex);
- addToken(Token.CATCH_SCOPE);
- addUint8(scopeIndex != 0 ? 1 : 0);
- stackChange(-1);
- }
- break;
-
- case Token.THROW:
- updateLineNumber(node);
- visitExpression(child, 0);
- addToken(Token.THROW);
- addUint16(itsLineNumber & 0xFFFF);
- stackChange(-1);
- break;
-
- case Token.RETHROW:
- updateLineNumber(node);
- addIndexOp(Token.RETHROW, getLocalBlockRef(node));
- break;
-
- case Token.RETURN:
- updateLineNumber(node);
- if (node.getIntProp(Node.GENERATOR_END_PROP, 0) != 0) {
- // We're in a generator, so change RETURN to GENERATOR_END
- addIcode(Icode_GENERATOR_END);
- addUint16(itsLineNumber & 0xFFFF);
- } else if (child != null) {
- visitExpression(child, ECF_TAIL);
- addToken(Token.RETURN);
- stackChange(-1);
- } else {
- addIcode(Icode_RETUNDEF);
- }
- break;
-
- case Token.RETURN_RESULT:
- updateLineNumber(node);
- addToken(Token.RETURN_RESULT);
- break;
-
- case Token.ENUM_INIT_KEYS:
- case Token.ENUM_INIT_VALUES:
- case Token.ENUM_INIT_ARRAY:
- visitExpression(child, 0);
- addIndexOp(type, getLocalBlockRef(node));
- stackChange(-1);
- break;
-
- case Icode_GENERATOR:
- break;
-
- default:
- throw badTree(node);
- }
-
- if (itsStackDepth != initialStackDepth) {
- throw Kit.codeBug();
- }
- }
-
- private void visitExpression(Node node, int contextFlags)
- {
- int type = node.getType();
- Node child = node.getFirstChild();
- int savedStackDepth = itsStackDepth;
- switch (type) {
-
- case Token.FUNCTION:
- {
- int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
- FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
- // See comments in visitStatement for Token.FUNCTION case
- if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
- throw Kit.codeBug();
- }
- addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
- stackChange(1);
- }
- break;
-
- case Token.LOCAL_LOAD:
- {
- int localIndex = getLocalBlockRef(node);
- addIndexOp(Token.LOCAL_LOAD, localIndex);
- stackChange(1);
- }
- break;
-
- case Token.COMMA:
- {
- Node lastChild = node.getLastChild();
- while (child != lastChild) {
- visitExpression(child, 0);
- addIcode(Icode_POP);
- stackChange(-1);
- child = child.getNext();
- }
- // Preserve tail context flag if any
- visitExpression(child, contextFlags & ECF_TAIL);
- }
- break;
-
- case Token.USE_STACK:
- // Indicates that stack was modified externally,
- // like placed catch object
- stackChange(1);
- break;
-
- case Token.REF_CALL:
- case Token.CALL:
- case Token.NEW:
- {
- if (type == Token.NEW) {
- visitExpression(child, 0);
- } else {
- generateCallFunAndThis(child);
- }
- int argCount = 0;
- while ((child = child.getNext()) != null) {
- visitExpression(child, 0);
- ++argCount;
- }
- int callType = node.getIntProp(Node.SPECIALCALL_PROP,
- Node.NON_SPECIALCALL);
- if (callType != Node.NON_SPECIALCALL) {
- // embed line number and source filename
- addIndexOp(Icode_CALLSPECIAL, argCount);
- addUint8(callType);
- addUint8(type == Token.NEW ? 1 : 0);
- addUint16(itsLineNumber & 0xFFFF);
- } else {
- // Only use the tail call optimization if we're not in a try
- // or we're not generating debug info (since the
- // optimization will confuse the debugger)
- if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 &&
- !compilerEnv.isGenerateDebugInfo() && !itsInTryFlag)
- {
- type = Icode_TAIL_CALL;
- }
- addIndexOp(type, argCount);
- }
- // adjust stack
- if (type == Token.NEW) {
- // new: f, args -> result
- stackChange(-argCount);
- } else {
- // call: f, thisObj, args -> result
- // ref_call: f, thisObj, args -> ref
- stackChange(-1 - argCount);
- }
- if (argCount > itsData.itsMaxCalleeArgs) {
- itsData.itsMaxCalleeArgs = argCount;
- }
- }
- break;
-
- case Token.AND:
- case Token.OR:
- {
- visitExpression(child, 0);
- addIcode(Icode_DUP);
- stackChange(1);
- int afterSecondJumpStart = itsICodeTop;
- int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
- addGotoOp(jump);
- stackChange(-1);
- addIcode(Icode_POP);
- stackChange(-1);
- child = child.getNext();
- // Preserve tail context flag if any
- visitExpression(child, contextFlags & ECF_TAIL);
- resolveForwardGoto(afterSecondJumpStart);
- }
- break;
-
- case Token.HOOK:
- {
- Node ifThen = child.getNext();
- Node ifElse = ifThen.getNext();
- visitExpression(child, 0);
- int elseJumpStart = itsICodeTop;
- addGotoOp(Token.IFNE);
- stackChange(-1);
- // Preserve tail context flag if any
- visitExpression(ifThen, contextFlags & ECF_TAIL);
- int afterElseJumpStart = itsICodeTop;
- addGotoOp(Token.GOTO);
- resolveForwardGoto(elseJumpStart);
- itsStackDepth = savedStackDepth;
- // Preserve tail context flag if any
- visitExpression(ifElse, contextFlags & ECF_TAIL);
- resolveForwardGoto(afterElseJumpStart);
- }
- break;
-
- case Token.GETPROP:
- case Token.GETPROPNOWARN:
- visitExpression(child, 0);
- child = child.getNext();
- addStringOp(type, child.getString());
- break;
-
- case Token.GETELEM:
- case Token.DELPROP:
- case Token.BITAND:
- case Token.BITOR:
- case Token.BITXOR:
- case Token.LSH:
- case Token.RSH:
- case Token.URSH:
- case Token.ADD:
- case Token.SUB:
- case Token.MOD:
- case Token.DIV:
- case Token.MUL:
- case Token.EQ:
- case Token.NE:
- case Token.SHEQ:
- case Token.SHNE:
- case Token.IN:
- case Token.INSTANCEOF:
- case Token.LE:
- case Token.LT:
- case Token.GE:
- case Token.GT:
- visitExpression(child, 0);
- child = child.getNext();
- visitExpression(child, 0);
- addToken(type);
- stackChange(-1);
- break;
-
- case Token.POS:
- case Token.NEG:
- case Token.NOT:
- case Token.BITNOT:
- case Token.TYPEOF:
- case Token.VOID:
- visitExpression(child, 0);
- if (type == Token.VOID) {
- addIcode(Icode_POP);
- addIcode(Icode_UNDEF);
- } else {
- addToken(type);
- }
- break;
-
- case Token.GET_REF:
- case Token.DEL_REF:
- visitExpression(child, 0);
- addToken(type);
- break;
-
- case Token.SETPROP:
- case Token.SETPROP_OP:
- {
- visitExpression(child, 0);
- child = child.getNext();
- String property = child.getString();
- child = child.getNext();
- if (type == Token.SETPROP_OP) {
- addIcode(Icode_DUP);
- stackChange(1);
- addStringOp(Token.GETPROP, property);
- // Compensate for the following USE_STACK
- stackChange(-1);
- }
- visitExpression(child, 0);
- addStringOp(Token.SETPROP, property);
- stackChange(-1);
- }
- break;
-
- case Token.SETELEM:
- case Token.SETELEM_OP:
- visitExpression(child, 0);
- child = child.getNext();
- visitExpression(child, 0);
- child = child.getNext();
- if (type == Token.SETELEM_OP) {
- addIcode(Icode_DUP2);
- stackChange(2);
- addToken(Token.GETELEM);
- stackChange(-1);
- // Compensate for the following USE_STACK
- stackChange(-1);
- }
- visitExpression(child, 0);
- addToken(Token.SETELEM);
- stackChange(-2);
- break;
-
- case Token.SET_REF:
- case Token.SET_REF_OP:
- visitExpression(child, 0);
- child = child.getNext();
- if (type == Token.SET_REF_OP) {
- addIcode(Icode_DUP);
- stackChange(1);
- addToken(Token.GET_REF);
- // Compensate for the following USE_STACK
- stackChange(-1);
- }
- visitExpression(child, 0);
- addToken(Token.SET_REF);
- stackChange(-1);
- break;
-
- case Token.SETNAME:
- {
- String name = child.getString();
- visitExpression(child, 0);
- child = child.getNext();
- visitExpression(child, 0);
- addStringOp(Token.SETNAME, name);
- stackChange(-1);
- }
- break;
-
- case Token.SETCONST:
- {
- String name = child.getString();
- visitExpression(child, 0);
- child = child.getNext();
- visitExpression(child, 0);
- addStringOp(Icode_SETCONST, name);
- stackChange(-1);
- }
- break;
-
- case Token.TYPEOFNAME:
- {
- int index = -1;
- // use typeofname if an activation frame exists
- // since the vars all exist there instead of in jregs
- if (itsInFunctionFlag && !itsData.itsNeedsActivation)
- index = scriptOrFn.getIndexForNameNode(node);
- if (index == -1) {
- addStringOp(Icode_TYPEOFNAME, node.getString());
- stackChange(1);
- } else {
- addVarOp(Token.GETVAR, index);
- stackChange(1);
- addToken(Token.TYPEOF);
- }
- }
- break;
-
- case Token.BINDNAME:
- case Token.NAME:
- case Token.STRING:
- addStringOp(type, node.getString());
- stackChange(1);
- break;
-
- case Token.INC:
- case Token.DEC:
- visitIncDec(node, child);
- break;
-
- case Token.NUMBER:
- {
- double num = node.getDouble();
- int inum = (int)num;
- if (inum == num) {
- if (inum == 0) {
- addIcode(Icode_ZERO);
- // Check for negative zero
- if (1.0 / num < 0.0) {
- addToken(Token.NEG);
- }
- } else if (inum == 1) {
- addIcode(Icode_ONE);
- } else if ((short)inum == inum) {
- addIcode(Icode_SHORTNUMBER);
- // write short as uin16 bit pattern
- addUint16(inum & 0xFFFF);
- } else {
- addIcode(Icode_INTNUMBER);
- addInt(inum);
- }
- } else {
- int index = getDoubleIndex(num);
- addIndexOp(Token.NUMBER, index);
- }
- stackChange(1);
- }
- break;
-
- case Token.GETVAR:
- {
- if (itsData.itsNeedsActivation) Kit.codeBug();
- int index = scriptOrFn.getIndexForNameNode(node);
- addVarOp(Token.GETVAR, index);
- stackChange(1);
- }
- break;
-
- case Token.SETVAR:
- {
- if (itsData.itsNeedsActivation) Kit.codeBug();
- int index = scriptOrFn.getIndexForNameNode(child);
- child = child.getNext();
- visitExpression(child, 0);
- addVarOp(Token.SETVAR, index);
- }
- break;
-
- case Token.SETCONSTVAR:
- {
- if (itsData.itsNeedsActivation) Kit.codeBug();
- int index = scriptOrFn.getIndexForNameNode(child);
- child = child.getNext();
- visitExpression(child, 0);
- addVarOp(Token.SETCONSTVAR, index);
- }
- break;
-
- case Token.NULL:
- case Token.THIS:
- case Token.THISFN:
- case Token.FALSE:
- case Token.TRUE:
- addToken(type);
- stackChange(1);
- break;
-
- case Token.ENUM_NEXT:
- case Token.ENUM_ID:
- addIndexOp(type, getLocalBlockRef(node));
- stackChange(1);
- break;
-
- case Token.REGEXP:
- {
- int index = node.getExistingIntProp(Node.REGEXP_PROP);
- addIndexOp(Token.REGEXP, index);
- stackChange(1);
- }
- break;
-
- case Token.ARRAYLIT:
- case Token.OBJECTLIT:
- visitLiteral(node, child);
- break;
-
- case Token.ARRAYCOMP:
- visitArrayComprehension(node, child, child.getNext());
- break;
-
- case Token.REF_SPECIAL:
- visitExpression(child, 0);
- addStringOp(type, (String)node.getProp(Node.NAME_PROP));
- break;
-
- case Token.REF_MEMBER:
- case Token.REF_NS_MEMBER:
- case Token.REF_NAME:
- case Token.REF_NS_NAME:
- {
- int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0);
- // generate possible target, possible namespace and member
- int childCount = 0;
- do {
- visitExpression(child, 0);
- ++childCount;
- child = child.getNext();
- } while (child != null);
- addIndexOp(type, memberTypeFlags);
- stackChange(1 - childCount);
- }
- break;
-
- case Token.DOTQUERY:
- {
- int queryPC;
- updateLineNumber(node);
- visitExpression(child, 0);
- addIcode(Icode_ENTERDQ);
- stackChange(-1);
- queryPC = itsICodeTop;
- visitExpression(child.getNext(), 0);
- addBackwardGoto(Icode_LEAVEDQ, queryPC);
- }
- break;
-
- case Token.DEFAULTNAMESPACE :
- case Token.ESCXMLATTR :
- case Token.ESCXMLTEXT :
- visitExpression(child, 0);
- addToken(type);
- break;
-
- case Token.YIELD:
- if (child != null) {
- visitExpression(child, 0);
- } else {
- addIcode(Icode_UNDEF);
- stackChange(1);
- }
- addToken(Token.YIELD);
- addUint16(node.getLineno() & 0xFFFF);
- break;
-
- case Token.WITHEXPR: {
- Node enterWith = node.getFirstChild();
- Node with = enterWith.getNext();
- visitExpression(enterWith.getFirstChild(), 0);
- addToken(Token.ENTERWITH);
- stackChange(-1);
- visitExpression(with.getFirstChild(), 0);
- addToken(Token.LEAVEWITH);
- break;
- }
-
- default:
- throw badTree(node);
- }
- if (savedStackDepth + 1 != itsStackDepth) {
- Kit.codeBug();
- }
- }
-
- private void generateCallFunAndThis(Node left)
- {
- // Generate code to place on stack function and thisObj
- int type = left.getType();
- switch (type) {
- case Token.NAME: {
- String name = left.getString();
- // stack: ... -> ... function thisObj
- addStringOp(Icode_NAME_AND_THIS, name);
- stackChange(2);
- break;
- }
- case Token.GETPROP:
- case Token.GETELEM: {
- Node target = left.getFirstChild();
- visitExpression(target, 0);
- Node id = target.getNext();
- if (type == Token.GETPROP) {
- String property = id.getString();
- // stack: ... target -> ... function thisObj
- addStringOp(Icode_PROP_AND_THIS, property);
- stackChange(1);
- } else {
- visitExpression(id, 0);
- // stack: ... target id -> ... function thisObj
- addIcode(Icode_ELEM_AND_THIS);
- }
- break;
- }
- default:
- // Including Token.GETVAR
- visitExpression(left, 0);
- // stack: ... value -> ... function thisObj
- addIcode(Icode_VALUE_AND_THIS);
- stackChange(1);
- break;
- }
- }
-
- private void visitIncDec(Node node, Node child)
- {
- int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
- int childType = child.getType();
- switch (childType) {
- case Token.GETVAR : {
- if (itsData.itsNeedsActivation) Kit.codeBug();
- int i = scriptOrFn.getIndexForNameNode(child);
- addVarOp(Icode_VAR_INC_DEC, i);
- addUint8(incrDecrMask);
- stackChange(1);
- break;
- }
- case Token.NAME : {
- String name = child.getString();
- addStringOp(Icode_NAME_INC_DEC, name);
- addUint8(incrDecrMask);
- stackChange(1);
- break;
- }
- case Token.GETPROP : {
- Node object = child.getFirstChild();
- visitExpression(object, 0);
- String property = object.getNext().getString();
- addStringOp(Icode_PROP_INC_DEC, property);
- addUint8(incrDecrMask);
- break;
- }
- case Token.GETELEM : {
- Node object = child.getFirstChild();
- visitExpression(object, 0);
- Node index = object.getNext();
- visitExpression(index, 0);
- addIcode(Icode_ELEM_INC_DEC);
- addUint8(incrDecrMask);
- stackChange(-1);
- break;
- }
- case Token.GET_REF : {
- Node ref = child.getFirstChild();
- visitExpression(ref, 0);
- addIcode(Icode_REF_INC_DEC);
- addUint8(incrDecrMask);
- break;
- }
- default : {
- throw badTree(node);
- }
- }
- }
-
- private void visitLiteral(Node node, Node child)
- {
- int type = node.getType();
- int count;
- Object[] propertyIds = null;
- if (type == Token.ARRAYLIT) {
- count = 0;
- for (Node n = child; n != null; n = n.getNext()) {
- ++count;
- }
- } else if (type == Token.OBJECTLIT) {
- propertyIds = (Object[])node.getProp(Node.OBJECT_IDS_PROP);
- count = propertyIds.length;
- } else {
- throw badTree(node);
- }
- addIndexOp(Icode_LITERAL_NEW, count);
- stackChange(2);
- while (child != null) {
- int childType = child.getType();
- if (childType == Token.GET) {
- visitExpression(child.getFirstChild(), 0);
- addIcode(Icode_LITERAL_GETTER);
- } else if (childType == Token.SET) {
- visitExpression(child.getFirstChild(), 0);
- addIcode(Icode_LITERAL_SETTER);
- } else {
- visitExpression(child, 0);
- addIcode(Icode_LITERAL_SET);
- }
- stackChange(-1);
- child = child.getNext();
- }
- if (type == Token.ARRAYLIT) {
- int[] skipIndexes = (int[])node.getProp(Node.SKIP_INDEXES_PROP);
- if (skipIndexes == null) {
- addToken(Token.ARRAYLIT);
- } else {
- int index = itsLiteralIds.size();
- itsLiteralIds.add(skipIndexes);
- addIndexOp(Icode_SPARE_ARRAYLIT, index);
- }
- } else {
- int index = itsLiteralIds.size();
- itsLiteralIds.add(propertyIds);
- addIndexOp(Token.OBJECTLIT, index);
- }
- stackChange(-1);
- }
-
- private void visitArrayComprehension(Node node, Node initStmt, Node expr)
- {
- // A bit of a hack: array comprehensions are implemented using
- // statement nodes for the iteration, yet they appear in an
- // expression context. So we pass the current stack depth to
- // visitStatement so it can check that the depth is not altered
- // by statements.
- visitStatement(initStmt, itsStackDepth);
- visitExpression(expr, 0);
- }
-
- private int getLocalBlockRef(Node node)
- {
- Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);
- return localBlock.getExistingIntProp(Node.LOCAL_PROP);
- }
-
- private int getTargetLabel(Node target)
- {
- int label = target.labelId();
- if (label != -1) {
- return label;
- }
- label = itsLabelTableTop;
- if (itsLabelTable == null || label == itsLabelTable.length) {
- if (itsLabelTable == null) {
- itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
- }else {
- int[] tmp = new int[itsLabelTable.length * 2];
- System.arraycopy(itsLabelTable, 0, tmp, 0, label);
- itsLabelTable = tmp;
- }
- }
- itsLabelTableTop = label + 1;
- itsLabelTable[label] = -1;
-
- target.labelId(label);
- return label;
- }
-
- private void markTargetLabel(Node target)
- {
- int label = getTargetLabel(target);
- if (itsLabelTable[label] != -1) {
- // Can mark label only once
- Kit.codeBug();
- }
- itsLabelTable[label] = itsICodeTop;
- }
-
- private void addGoto(Node target, int gotoOp)
- {
- int label = getTargetLabel(target);
- if (!(label < itsLabelTableTop)) Kit.codeBug();
- int targetPC = itsLabelTable[label];
-
- if (targetPC != -1) {
- addBackwardGoto(gotoOp, targetPC);
- } else {
- int gotoPC = itsICodeTop;
- addGotoOp(gotoOp);
- int top = itsFixupTableTop;
- if (itsFixupTable == null || top == itsFixupTable.length) {
- if (itsFixupTable == null) {
- itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
- } else {
- long[] tmp = new long[itsFixupTable.length * 2];
- System.arraycopy(itsFixupTable, 0, tmp, 0, top);
- itsFixupTable = tmp;
- }
- }
- itsFixupTableTop = top + 1;
- itsFixupTable[top] = ((long)label << 32) | gotoPC;
- }
- }
-
- private void fixLabelGotos()
- {
- for (int i = 0; i < itsFixupTableTop; i++) {
- long fixup = itsFixupTable[i];
- int label = (int)(fixup >> 32);
- int jumpSource = (int)fixup;
- int pc = itsLabelTable[label];
- if (pc == -1) {
- // Unlocated label
- throw Kit.codeBug();
- }
- resolveGoto(jumpSource, pc);
- }
- itsFixupTableTop = 0;
- }
-
- private void addBackwardGoto(int gotoOp, int jumpPC)
- {
- int fromPC = itsICodeTop;
- // Ensure that this is a jump backward
- if (fromPC <= jumpPC) throw Kit.codeBug();
- addGotoOp(gotoOp);
- resolveGoto(fromPC, jumpPC);
- }
-
- private void resolveForwardGoto(int fromPC)
- {
- // Ensure that forward jump skips at least self bytecode
- if (itsICodeTop < fromPC + 3) throw Kit.codeBug();
- resolveGoto(fromPC, itsICodeTop);
- }
-
- private void resolveGoto(int fromPC, int jumpPC)
- {
- int offset = jumpPC - fromPC;
- // Ensure that jumps do not overlap
- if (0 <= offset && offset <= 2) throw Kit.codeBug();
- int offsetSite = fromPC + 1;
- if (offset != (short)offset) {
- if (itsData.longJumps == null) {
- itsData.longJumps = new UintMap();
- }
- itsData.longJumps.put(offsetSite, jumpPC);
- offset = 0;
- }
- byte[] array = itsData.itsICode;
- array[offsetSite] = (byte)(offset >> 8);
- array[offsetSite + 1] = (byte)offset;
- }
-
- private void addToken(int token)
- {
- if (!validTokenCode(token)) throw Kit.codeBug();
- addUint8(token);
- }
-
- private void addIcode(int icode)
- {
- if (!validIcode(icode)) throw Kit.codeBug();
- // Write negative icode as uint8 bits
- addUint8(icode & 0xFF);
- }
-
- private void addUint8(int value)
- {
- if ((value & ~0xFF) != 0) throw Kit.codeBug();
- byte[] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top == array.length) {
- array = increaseICodeCapacity(1);
- }
- array[top] = (byte)value;
- itsICodeTop = top + 1;
- }
-
- private void addUint16(int value)
- {
- if ((value & ~0xFFFF) != 0) throw Kit.codeBug();
- byte[] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 2 > array.length) {
- array = increaseICodeCapacity(2);
- }
- array[top] = (byte)(value >>> 8);
- array[top + 1] = (byte)value;
- itsICodeTop = top + 2;
- }
-
- private void addInt(int i)
- {
- byte[] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 4 > array.length) {
- array = increaseICodeCapacity(4);
- }
- array[top] = (byte)(i >>> 24);
- array[top + 1] = (byte)(i >>> 16);
- array[top + 2] = (byte)(i >>> 8);
- array[top + 3] = (byte)i;
- itsICodeTop = top + 4;
- }
-
- private int getDoubleIndex(double num)
- {
- int index = itsDoubleTableTop;
- if (index == 0) {
- itsData.itsDoubleTable = new double[64];
- } else if (itsData.itsDoubleTable.length == index) {
- double[] na = new double[index * 2];
- System.arraycopy(itsData.itsDoubleTable, 0, na, 0, index);
- itsData.itsDoubleTable = na;
- }
- itsData.itsDoubleTable[index] = num;
- itsDoubleTableTop = index + 1;
- return index;
- }
-
- private void addGotoOp(int gotoOp)
- {
- byte[] array = itsData.itsICode;
- int top = itsICodeTop;
- if (top + 3 > array.length) {
- array = increaseICodeCapacity(3);
- }
- array[top] = (byte)gotoOp;
- // Offset would written later
- itsICodeTop = top + 1 + 2;
- }
-
- private void addVarOp(int op, int varIndex)
- {
- switch (op) {
- case Token.SETCONSTVAR:
- if (varIndex < 128) {
- addIcode(Icode_SETCONSTVAR1);
- addUint8(varIndex);
- return;
- }
- addIndexOp(Icode_SETCONSTVAR, varIndex);
- return;
- case Token.GETVAR:
- case Token.SETVAR:
- if (varIndex < 128) {
- addIcode(op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1);
- addUint8(varIndex);
- return;
- }
- // fallthrough
- case Icode_VAR_INC_DEC:
- addIndexOp(op, varIndex);
- return;
- }
- throw Kit.codeBug();
- }
-
- private void addStringOp(int op, String str)
- {
- addStringPrefix(str);
- if (validIcode(op)) {
- addIcode(op);
- } else {
- addToken(op);
- }
- }
-
- private void addIndexOp(int op, int index)
- {
- addIndexPrefix(index);
- if (validIcode(op)) {
- addIcode(op);
- } else {
- addToken(op);
- }
- }
-
- private void addStringPrefix(String str)
- {
- int index = itsStrings.get(str, -1);
- if (index == -1) {
- index = itsStrings.size();
- itsStrings.put(str, index);
- }
- if (index < 4) {
- addIcode(Icode_REG_STR_C0 - index);
- } else if (index <= 0xFF) {
- addIcode(Icode_REG_STR1);
- addUint8(index);
- } else if (index <= 0xFFFF) {
- addIcode(Icode_REG_STR2);
- addUint16(index);
- } else {
- addIcode(Icode_REG_STR4);
- addInt(index);
- }
- }
-
- private void addIndexPrefix(int index)
- {
- if (index < 0) Kit.codeBug();
- if (index < 6) {
- addIcode(Icode_REG_IND_C0 - index);
- } else if (index <= 0xFF) {
- addIcode(Icode_REG_IND1);
- addUint8(index);
- } else if (index <= 0xFFFF) {
- addIcode(Icode_REG_IND2);
- addUint16(index);
- } else {
- addIcode(Icode_REG_IND4);
- addInt(index);
- }
- }
-
- private void addExceptionHandler(int icodeStart, int icodeEnd,
- int handlerStart, boolean isFinally,
- int exceptionObjectLocal, int scopeLocal)
- {
- int top = itsExceptionTableTop;
- int[] table = itsData.itsExceptionTable;
- if (table == null) {
- if (top != 0) Kit.codeBug();
- table = new int[EXCEPTION_SLOT_SIZE * 2];
- itsData.itsExceptionTable = table;
- } else if (table.length == top) {
- table = new int[table.length * 2];
- System.arraycopy(itsData.itsExceptionTable, 0, table, 0, top);
- itsData.itsExceptionTable = table;
- }
- table[top + EXCEPTION_TRY_START_SLOT] = icodeStart;
- table[top + EXCEPTION_TRY_END_SLOT] = icodeEnd;
- table[top + EXCEPTION_HANDLER_SLOT] = handlerStart;
- table[top + EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0;
- table[top + EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal;
- table[top + EXCEPTION_SCOPE_SLOT] = scopeLocal;
-
- itsExceptionTableTop = top + EXCEPTION_SLOT_SIZE;
- }
-
- private byte[] increaseICodeCapacity(int extraSize)
- {
- int capacity = itsData.itsICode.length;
- int top = itsICodeTop;
- if (top + extraSize <= capacity) throw Kit.codeBug();
- capacity *= 2;
- if (top + extraSize > capacity) {
- capacity = top + extraSize;
- }
- byte[] array = new byte[capacity];
- System.arraycopy(itsData.itsICode, 0, array, 0, top);
- itsData.itsICode = array;
- return array;
- }
-
- private void stackChange(int change)
- {
- if (change <= 0) {
- itsStackDepth += change;
- } else {
- int newDepth = itsStackDepth + change;
- if (newDepth > itsData.itsMaxStack) {
- itsData.itsMaxStack = newDepth;
- }
- itsStackDepth = newDepth;
- }
- }
-
- private int allocLocal()
- {
- int localSlot = itsLocalTop;
- ++itsLocalTop;
- if (itsLocalTop > itsData.itsMaxLocals) {
- itsData.itsMaxLocals = itsLocalTop;
- }
- return localSlot;
- }
-
- private void releaseLocal(int localSlot)
- {
- --itsLocalTop;
- if (localSlot != itsLocalTop) Kit.codeBug();
- }
-
- private static int getShort(byte[] iCode, int pc) {
- return (iCode[pc] << 8) | (iCode[pc + 1] & 0xFF);
- }
-
- private static int getIndex(byte[] iCode, int pc) {
- return ((iCode[pc] & 0xFF) << 8) | (iCode[pc + 1] & 0xFF);
- }
-
- private static int getInt(byte[] iCode, int pc) {
- return (iCode[pc] << 24) | ((iCode[pc + 1] & 0xFF) << 16)
- | ((iCode[pc + 2] & 0xFF) << 8) | (iCode[pc + 3] & 0xFF);
- }
-
- private static int getExceptionHandler(CallFrame frame,
- boolean onlyFinally)
- {
- int[] exceptionTable = frame.idata.itsExceptionTable;
- if (exceptionTable == null) {
- // No exception handlers
- return -1;
- }
-
- // Icode switch in the interpreter increments PC immediately
- // and it is necessary to subtract 1 from the saved PC
- // to point it before the start of the next instruction.
- int pc = frame.pc - 1;
-
- // OPT: use binary search
- int best = -1, bestStart = 0, bestEnd = 0;
- for (int i = 0; i != exceptionTable.length; i += EXCEPTION_SLOT_SIZE) {
- int start = exceptionTable[i + EXCEPTION_TRY_START_SLOT];
- int end = exceptionTable[i + EXCEPTION_TRY_END_SLOT];
- if (!(start <= pc && pc < end)) {
- continue;
- }
- if (onlyFinally && exceptionTable[i + EXCEPTION_TYPE_SLOT] != 1) {
- continue;
- }
- if (best >= 0) {
- // Since handlers always nest and they never have shared end
- // although they can share start it is sufficient to compare
- // handlers ends
- if (bestEnd < end) {
- continue;
- }
- // Check the above assumption
- if (bestStart > start) Kit.codeBug(); // should be nested
- if (bestEnd == end) Kit.codeBug(); // no ens sharing
- }
- best = i;
- bestStart = start;
- bestEnd = end;
- }
- return best;
- }
-
- private static void dumpICode(InterpreterData idata)
- {
- if (!Token.printICode) {
- return;
- }
-
- byte iCode[] = idata.itsICode;
- int iCodeLength = iCode.length;
- String[] strings = idata.itsStringTable;
- PrintStream out = System.out;
- out.println("ICode dump, for " + idata.itsName
- + ", length = " + iCodeLength);
- out.println("MaxStack = " + idata.itsMaxStack);
-
- int indexReg = 0;
- for (int pc = 0; pc < iCodeLength; ) {
- out.flush();
- out.print(" [" + pc + "] ");
- int token = iCode[pc];
- int icodeLength = bytecodeSpan(token);
- String tname = bytecodeName(token);
- int old_pc = pc;
- ++pc;
- switch (token) {
- default:
- if (icodeLength != 1) Kit.codeBug();
- out.println(tname);
- break;
-
- case Icode_GOSUB :
- case Token.GOTO :
- case Token.IFEQ :
- case Token.IFNE :
- case Icode_IFEQ_POP :
- case Icode_LEAVEDQ : {
- int newPC = pc + getShort(iCode, pc) - 1;
- out.println(tname + " " + newPC);
- pc += 2;
- break;
- }
- case Icode_VAR_INC_DEC :
- case Icode_NAME_INC_DEC :
- case Icode_PROP_INC_DEC :
- case Icode_ELEM_INC_DEC :
- case Icode_REF_INC_DEC: {
- int incrDecrType = iCode[pc];
- out.println(tname + " " + incrDecrType);
- ++pc;
- break;
- }
-
- case Icode_CALLSPECIAL : {
- int callType = iCode[pc] & 0xFF;
- boolean isNew = (iCode[pc + 1] != 0);
- int line = getIndex(iCode, pc+2);
- out.println(tname+" "+callType+" "+isNew+" "+indexReg+" "+line);
- pc += 4;
- break;
- }
-
- case Token.CATCH_SCOPE:
- {
- boolean afterFisrtFlag = (iCode[pc] != 0);
- out.println(tname+" "+afterFisrtFlag);
- ++pc;
- }
- break;
- case Token.REGEXP :
- out.println(tname+" "+idata.itsRegExpLiterals[indexReg]);
- break;
- case Token.OBJECTLIT :
- case Icode_SPARE_ARRAYLIT :
- out.println(tname+" "+idata.literalIds[indexReg]);
- break;
- case Icode_CLOSURE_EXPR :
- case Icode_CLOSURE_STMT :
- out.println(tname+" "+idata.itsNestedFunctions[indexReg]);
- break;
- case Token.CALL :
- case Icode_TAIL_CALL :
- case Token.REF_CALL :
- case Token.NEW :
- out.println(tname+' '+indexReg);
- break;
- case Token.THROW :
- case Token.YIELD :
- case Icode_GENERATOR :
- case Icode_GENERATOR_END :
- {
- int line = getIndex(iCode, pc);
- out.println(tname + " : " + line);
- pc += 2;
- break;
- }
- case Icode_SHORTNUMBER : {
- int value = getShort(iCode, pc);
- out.println(tname + " " + value);
- pc += 2;
- break;
- }
- case Icode_INTNUMBER : {
- int value = getInt(iCode, pc);
- out.println(tname + " " + value);
- pc += 4;
- break;
- }
- case Token.NUMBER : {
- double value = idata.itsDoubleTable[indexReg];
- out.println(tname + " " + value);
- break;
- }
- case Icode_LINE : {
- int line = getIndex(iCode, pc);
- out.println(tname + " : " + line);
- pc += 2;
- break;
- }
- case Icode_REG_STR1: {
- String str = strings[0xFF & iCode[pc]];
- out.println(tname + " \"" + str + '"');
- ++pc;
- break;
- }
- case Icode_REG_STR2: {
- String str = strings[getIndex(iCode, pc)];
- out.println(tname + " \"" + str + '"');
- pc += 2;
- break;
- }
- case Icode_REG_STR4: {
- String str = strings[getInt(iCode, pc)];
- out.println(tname + " \"" + str + '"');
- pc += 4;
- break;
- }
- case Icode_REG_IND_C0:
- indexReg = 0;
- out.println(tname);
- break;
- case Icode_REG_IND_C1:
- indexReg = 1;
- out.println(tname);
- break;
- case Icode_REG_IND_C2:
- indexReg = 2;
- out.println(tname);
- break;
- case Icode_REG_IND_C3:
- indexReg = 3;
- out.println(tname);
- break;
- case Icode_REG_IND_C4:
- indexReg = 4;
- out.println(tname);
- break;
- case Icode_REG_IND_C5:
- indexReg = 5;
- out.println(tname);
- break;
- case Icode_REG_IND1: {
- indexReg = 0xFF & iCode[pc];
- out.println(tname+" "+indexReg);
- ++pc;
- break;
- }
- case Icode_REG_IND2: {
- indexReg = getIndex(iCode, pc);
- out.println(tname+" "+indexReg);
- pc += 2;
- break;
- }
- case Icode_REG_IND4: {
- indexReg = getInt(iCode, pc);
- out.println(tname+" "+indexReg);
- pc += 4;
- break;
- }
- case Icode_GETVAR1:
- case Icode_SETVAR1:
- case Icode_SETCONSTVAR1:
- indexReg = iCode[pc];
- out.println(tname+" "+indexReg);
- ++pc;
- break;
- }
- if (old_pc + icodeLength != pc) Kit.codeBug();
- }
-
- int[] table = idata.itsExceptionTable;
- if (table != null) {
- out.println("Exception handlers: "
- +table.length / EXCEPTION_SLOT_SIZE);
- for (int i = 0; i != table.length;
- i += EXCEPTION_SLOT_SIZE)
- {
- int tryStart = table[i + EXCEPTION_TRY_START_SLOT];
- int tryEnd = table[i + EXCEPTION_TRY_END_SLOT];
- int handlerStart = table[i + EXCEPTION_HANDLER_SLOT];
- int type = table[i + EXCEPTION_TYPE_SLOT];
- int exceptionLocal = table[i + EXCEPTION_LOCAL_SLOT];
- int scopeLocal = table[i + EXCEPTION_SCOPE_SLOT];
-
- out.println(" tryStart="+tryStart+" tryEnd="+tryEnd
- +" handlerStart="+handlerStart
- +" type="+(type == 0 ? "catch" : "finally")
- +" exceptionLocal="+exceptionLocal);
- }
- }
- out.flush();
- }
-
- private static int bytecodeSpan(int bytecode)
- {
- switch (bytecode) {
- case Token.THROW :
- case Token.YIELD:
- case Icode_GENERATOR:
- case Icode_GENERATOR_END:
- // source line
- return 1 + 2;
-
- case Icode_GOSUB :
- case Token.GOTO :
- case Token.IFEQ :
- case Token.IFNE :
- case Icode_IFEQ_POP :
- case Icode_LEAVEDQ :
- // target pc offset
- return 1 + 2;
-
- case Icode_CALLSPECIAL :
- // call type
- // is new
- // line number
- return 1 + 1 + 1 + 2;
-
- case Token.CATCH_SCOPE:
- // scope flag
- return 1 + 1;
-
- case Icode_VAR_INC_DEC:
- case Icode_NAME_INC_DEC:
- case Icode_PROP_INC_DEC:
- case Icode_ELEM_INC_DEC:
- case Icode_REF_INC_DEC:
- // type of ++/--
- return 1 + 1;
-
- case Icode_SHORTNUMBER :
- // short number
- return 1 + 2;
-
- case Icode_INTNUMBER :
- // int number
- return 1 + 4;
-
- case Icode_REG_IND1:
- // ubyte index
- return 1 + 1;
-
- case Icode_REG_IND2:
- // ushort index
- return 1 + 2;
-
- case Icode_REG_IND4:
- // int index
- return 1 + 4;
-
- case Icode_REG_STR1:
- // ubyte string index
- return 1 + 1;
-
- case Icode_REG_STR2:
- // ushort string index
- return 1 + 2;
-
- case Icode_REG_STR4:
- // int string index
- return 1 + 4;
-
- case Icode_GETVAR1:
- case Icode_SETVAR1:
- case Icode_SETCONSTVAR1:
- // byte var index
- return 1 + 1;
-
- case Icode_LINE :
- // line number
- return 1 + 2;
- }
- if (!validBytecode(bytecode)) throw Kit.codeBug();
- return 1;
- }
-
- static int[] getLineNumbers(InterpreterData data)
- {
- UintMap presentLines = new UintMap();
-
- byte[] iCode = data.itsICode;
- int iCodeLength = iCode.length;
- for (int pc = 0; pc != iCodeLength;) {
- int bytecode = iCode[pc];
- int span = bytecodeSpan(bytecode);
- if (bytecode == Icode_LINE) {
- if (span != 3) Kit.codeBug();
- int line = getIndex(iCode, pc + 1);
- presentLines.put(line, 0);
- }
- pc += span;
- }
-
- return presentLines.getKeys();
- }
-
- public void captureStackInfo(RhinoException ex)
- {
- Context cx = Context.getCurrentContext();
- if (cx == null || cx.lastInterpreterFrame == null) {
- // No interpreter invocations
- ex.interpreterStackInfo = null;
- ex.interpreterLineData = null;
- return;
- }
- // has interpreter frame on the stack
- CallFrame[] array;
- if (cx.previousInterpreterInvocations == null
- || cx.previousInterpreterInvocations.size() == 0)
- {
- array = new CallFrame[1];
- } else {
- int previousCount = cx.previousInterpreterInvocations.size();
- if (cx.previousInterpreterInvocations.peek()
- == cx.lastInterpreterFrame)
- {
- // It can happen if exception was generated after
- // frame was pushed to cx.previousInterpreterInvocations
- // but before assignment to cx.lastInterpreterFrame.
- // In this case frames has to be ignored.
- --previousCount;
- }
- array = new CallFrame[previousCount + 1];
- cx.previousInterpreterInvocations.toArray(array);
- }
- array[array.length - 1] = (CallFrame)cx.lastInterpreterFrame;
-
- int interpreterFrameCount = 0;
- for (int i = 0; i != array.length; ++i) {
- interpreterFrameCount += 1 + array[i].frameIndex;
- }
-
- int[] linePC = new int[interpreterFrameCount];
- // Fill linePC with pc positions from all interpreter frames.
- // Start from the most nested frame
- int linePCIndex = interpreterFrameCount;
- for (int i = array.length; i != 0;) {
- --i;
- CallFrame frame = array[i];
- while (frame != null) {
- --linePCIndex;
- linePC[linePCIndex] = frame.pcSourceLineStart;
- frame = frame.parentFrame;
- }
- }
- if (linePCIndex != 0) Kit.codeBug();
-
- ex.interpreterStackInfo = array;
- ex.interpreterLineData = linePC;
- }
-
- public String getSourcePositionFromStack(Context cx, int[] linep)
- {
- CallFrame frame = (CallFrame)cx.lastInterpreterFrame;
- InterpreterData idata = frame.idata;
- if (frame.pcSourceLineStart >= 0) {
- linep[0] = getIndex(idata.itsICode, frame.pcSourceLineStart);
- } else {
- linep[0] = 0;
- }
- return idata.itsSourceFile;
- }
-
- public String getPatchedStack(RhinoException ex,
- String nativeStackTrace)
- {
- String tag = "org.mozilla.javascript.Interpreter.interpretLoop";
- StringBuffer sb = new StringBuffer(nativeStackTrace.length() + 1000);
- String lineSeparator = SecurityUtilities.getSystemProperty("line.separator");
-
- CallFrame[] array = (CallFrame[])ex.interpreterStackInfo;
- int[] linePC = ex.interpreterLineData;
- int arrayIndex = array.length;
- int linePCIndex = linePC.length;
- int offset = 0;
- while (arrayIndex != 0) {
- --arrayIndex;
- int pos = nativeStackTrace.indexOf(tag, offset);
- if (pos < 0) {
- break;
- }
-
- // Skip tag length
- pos += tag.length();
- // Skip until the end of line
- for (; pos != nativeStackTrace.length(); ++pos) {
- char c = nativeStackTrace.charAt(pos);
- if (c == '\n' || c == '\r') {
- break;
- }
- }
- sb.append(nativeStackTrace.substring(offset, pos));
- offset = pos;
-
- CallFrame frame = array[arrayIndex];
- while (frame != null) {
- if (linePCIndex == 0) Kit.codeBug();
- --linePCIndex;
- InterpreterData idata = frame.idata;
- sb.append(lineSeparator);
- sb.append("\tat script");
- if (idata.itsName != null && idata.itsName.length() != 0) {
- sb.append('.');
- sb.append(idata.itsName);
- }
- sb.append('(');
- sb.append(idata.itsSourceFile);
- int pc = linePC[linePCIndex];
- if (pc >= 0) {
- // Include line info only if available
- sb.append(':');
- sb.append(getIndex(idata.itsICode, pc));
- }
- sb.append(')');
- frame = frame.parentFrame;
- }
- }
- sb.append(nativeStackTrace.substring(offset));
-
- return sb.toString();
- }
-
- public List getScriptStack(RhinoException ex)
- {
- if (ex.interpreterStackInfo == null) {
- return null;
- }
-
- List list = new ArrayList();
- String lineSeparator =
- SecurityUtilities.getSystemProperty("line.separator");
-
- CallFrame[] array = (CallFrame[])ex.interpreterStackInfo;
- int[] linePC = ex.interpreterLineData;
- int arrayIndex = array.length;
- int linePCIndex = linePC.length;
- while (arrayIndex != 0) {
- --arrayIndex;
- StringBuffer sb = new StringBuffer();
- CallFrame frame = array[arrayIndex];
- while (frame != null) {
- if (linePCIndex == 0) Kit.codeBug();
- --linePCIndex;
- InterpreterData idata = frame.idata;
- sb.append("\tat ");
- sb.append(idata.itsSourceFile);
- int pc = linePC[linePCIndex];
- if (pc >= 0) {
- // Include line info only if available
- sb.append(':');
- sb.append(getIndex(idata.itsICode, pc));
- }
- if (idata.itsName != null && idata.itsName.length() != 0) {
- sb.append(" (");
- sb.append(idata.itsName);
- sb.append(')');
- }
- sb.append(lineSeparator);
- frame = frame.parentFrame;
- }
- list.add(sb.toString());
- }
- return list;
- }
-
- static String getEncodedSource(InterpreterData idata)
- {
- if (idata.encodedSource == null) {
- return null;
- }
- return idata.encodedSource.substring(idata.encodedSourceStart,
- idata.encodedSourceEnd);
- }
-
- private static void initFunction(Context cx, Scriptable scope,
- InterpretedFunction parent, int index)
- {
- InterpretedFunction fn;
- fn = InterpretedFunction.createFunction(cx, scope, parent, index);
- ScriptRuntime.initFunction(cx, scope, fn, fn.idata.itsFunctionType,
- parent.idata.evalScriptFlag);
- }
-
- static Object interpret(InterpretedFunction ifun,
- Context cx, Scriptable scope,
- Scriptable thisObj, Object[] args)
- {
- if (!ScriptRuntime.hasTopCall(cx)) Kit.codeBug();
-
- if (cx.interpreterSecurityDomain != ifun.securityDomain) {
- Object savedDomain = cx.interpreterSecurityDomain;
- cx.interpreterSecurityDomain = ifun.securityDomain;
- try {
- return ifun.securityController.callWithDomain(
- ifun.securityDomain, cx, ifun, scope, thisObj, args);
- } finally {
- cx.interpreterSecurityDomain = savedDomain;
- }
- }
-
- CallFrame frame = new CallFrame();
- initFrame(cx, scope, thisObj, args, null, 0, args.length,
- ifun, null, frame);
-
- return interpretLoop(cx, frame, null);
- }
-
- static class GeneratorState {
- GeneratorState(int operation, Object value) {
- this.operation = operation;
- this.value = value;
- }
- int operation;
- Object value;
- RuntimeException returnedException;
- }
-
- public static Object resumeGenerator(Context cx,
- Scriptable scope,
- int operation,
- Object savedState,
- Object value)
- {
- CallFrame frame = (CallFrame) savedState;
- GeneratorState generatorState = new GeneratorState(operation, value);
- if (operation == NativeGenerator.GENERATOR_CLOSE) {
- try {
- return interpretLoop(cx, frame, generatorState);
- } catch (RuntimeException e) {
- // Only propagate exceptions other than closingException
- if (e != value)
- throw e;
- }
- return Undefined.instance;
- }
- Object result = interpretLoop(cx, frame, generatorState);
- if (generatorState.returnedException != null)
- throw generatorState.returnedException;
- return result;
- }
-
- public static Object restartContinuation(Continuation 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];
- }
-
- CallFrame capturedFrame = (CallFrame)c.getImplementation();
- if (capturedFrame == null) {
- // No frames to restart
- return arg;
- }
-
- ContinuationJump cjump = new ContinuationJump(c, null);
-
- cjump.result = arg;
- return interpretLoop(cx, null, cjump);
- }
-
- private static Object interpretLoop(Context cx, CallFrame frame,
- Object throwable)
- {
- // throwable holds exception object to rethrow or catch
- // It is also used for continuation restart in which case
- // it holds ContinuationJump
-
- final Object DBL_MRK = UniqueTag.DOUBLE_MARK;
- final Object undefined = Undefined.instance;
-
- final boolean instructionCounting = (cx.instructionThreshold != 0);
- // arbitrary number to add to instructionCount when calling
- // other functions
- final int INVOCATION_COST = 100;
- // arbitrary exception cost for instruction counting
- final 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 throable == null and indexReg == -1 allows to
- // catch bugs with using indeReg to access array eleemnts before
- // initializing indexReg.
-
- GeneratorState generatorState = null;
- if (throwable != null) {
- if (throwable instanceof GeneratorState) {
- generatorState = (GeneratorState) throwable;
-
- // reestablish this call frame
- enterFrame(cx, frame, ScriptRuntime.emptyArgs, true);
- throwable = null;
- } else if (!(throwable instanceof ContinuationJump)) {
- // It should be continuation
- Kit.codeBug();
- }
- }
-
- Object interpreterResult = null;
- double interpreterResultDbl = 0.0;
-
- StateLoop: for (;;) {
- withoutExceptions: 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;
-
- Loop: for (;;) {
-
- // Exception handler assumes that PC is already incremented
- // pass the instruction start when it searches the
- // exception handler
- int op = iCode[frame.pc++];
- jumplessRun: {
-
- // Back indent to ease implementation reading
-switch (op) {
- case Icode_GENERATOR: {
- 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
- CallFrame generatorFrame = captureFrameForGenerator(frame);
- generatorFrame.frozen = true;
- NativeGenerator generator = new NativeGenerator(frame.scope,
- generatorFrame.fnOrScript, generatorFrame);
- frame.result = generator;
- break Loop;
- } else {
- // We are now resuming execution. Fall through to YIELD case.
- }
- }
- // fall through...
- case Token.YIELD: {
- if (!frame.frozen) {
- return freezeGenerator(cx, frame, stackTop, generatorState);
- } else {
- Object obj = thawGenerator(frame, stackTop, generatorState, op);
- if (obj != Scriptable.NOT_FOUND) {
- throwable = obj;
- break withoutExceptions;
- }
- continue Loop;
- }
- }
- 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);
- break Loop;
- }
- 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);
- break withoutExceptions;
- }
- case Token.RETHROW: {
- indexReg += frame.localShift;
- throwable = stack[indexReg];
- break withoutExceptions;
- }
- case Token.GE :
- case Token.LE :
- case Token.GT :
- case Token.LT : {
- --stackTop;
- Object rhs = stack[stackTop + 1];
- Object lhs = stack[stackTop];
- boolean valBln;
- object_compare:
- {
- number_compare:
- {
- double rDbl, lDbl;
- if (rhs == DBL_MRK) {
- rDbl = sDbl[stackTop + 1];
- lDbl = stack_double(frame, stackTop);
- } else if (lhs == DBL_MRK) {
- rDbl = ScriptRuntime.toNumber(rhs);
- lDbl = sDbl[stackTop];
- } else {
- break number_compare;
- }
- switch (op) {
- case Token.GE:
- valBln = (lDbl >= rDbl);
- break object_compare;
- case Token.LE:
- valBln = (lDbl <= rDbl);
- break object_compare;
- case Token.GT:
- valBln = (lDbl > rDbl);
- break object_compare;
- case Token.LT:
- valBln = (lDbl < rDbl);
- break object_compare;
- default:
- throw Kit.codeBug();
- }
- }
- switch (op) {
- case Token.GE:
- valBln = ScriptRuntime.cmp_LE(rhs, lhs);
- break;
- case Token.LE:
- valBln = ScriptRuntime.cmp_LE(lhs, rhs);
- break;
- case Token.GT:
- valBln = ScriptRuntime.cmp_LT(rhs, lhs);
- break;
- case Token.LT:
- valBln = ScriptRuntime.cmp_LT(lhs, rhs);
- break;
- default:
- throw Kit.codeBug();
- }
- }
- stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
- continue Loop;
- }
- case Token.IN :
- case Token.INSTANCEOF : {
- 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]);
- boolean valBln;
- if (op == Token.IN) {
- valBln = ScriptRuntime.in(lhs, rhs, cx);
- } else {
- valBln = ScriptRuntime.instanceOf(lhs, rhs, cx);
- }
- stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
- continue Loop;
- }
- case Token.EQ :
- case Token.NE : {
- --stackTop;
- boolean valBln;
- Object rhs = stack[stackTop + 1];
- Object lhs = stack[stackTop];
- if (rhs == DBL_MRK) {
- if (lhs == DBL_MRK) {
- valBln = (sDbl[stackTop] == sDbl[stackTop + 1]);
- } else {
- valBln = ScriptRuntime.eqNumber(sDbl[stackTop + 1], lhs);
- }
- } else {
- if (lhs == DBL_MRK) {
- valBln = ScriptRuntime.eqNumber(sDbl[stackTop], rhs);
- } else {
- valBln = ScriptRuntime.eq(lhs, rhs);
- }
- }
- valBln ^= (op == Token.NE);
- stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
- continue Loop;
- }
- case Token.SHEQ :
- case Token.SHNE : {
- --stackTop;
- Object rhs = stack[stackTop + 1];
- Object lhs = stack[stackTop];
- boolean valBln;
- shallow_compare: {
- double rdbl, ldbl;
- if (rhs == DBL_MRK) {
- rdbl = sDbl[stackTop + 1];
- if (lhs == DBL_MRK) {
- ldbl = sDbl[stackTop];
- } else if (lhs instanceof Number) {
- ldbl = ((Number)lhs).doubleValue();
- } else {
- valBln = false;
- break shallow_compare;
- }
- } else if (lhs == DBL_MRK) {
- ldbl = sDbl[stackTop];
- if (rhs == DBL_MRK) {
- rdbl = sDbl[stackTop + 1];
- } else if (rhs instanceof Number) {
- rdbl = ((Number)rhs).doubleValue();
- } else {
- valBln = false;
- break shallow_compare;
- }
- } else {
- valBln = ScriptRuntime.shallowEq(lhs, rhs);
- break shallow_compare;
- }
- valBln = (ldbl == rdbl);
- }
- valBln ^= (op == Token.SHNE);
- stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
- continue Loop;
- }
- case Token.IFNE :
- if (stack_boolean(frame, stackTop--)) {
- frame.pc += 2;
- continue Loop;
- }
- break jumplessRun;
- case Token.IFEQ :
- if (!stack_boolean(frame, stackTop--)) {
- frame.pc += 2;
- continue Loop;
- }
- break jumplessRun;
- case Icode_IFEQ_POP :
- if (!stack_boolean(frame, stackTop--)) {
- frame.pc += 2;
- continue Loop;
- }
- stack[stackTop--] = null;
- break jumplessRun;
- case Token.GOTO :
- break jumplessRun;
- case Icode_GOSUB :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = frame.pc + 2;
- break jumplessRun;
- 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();
- }
- continue Loop;
- 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;
- break withoutExceptions;
- }
- // Normal return from GOSUB
- frame.pc = (int)sDbl[indexReg];
- if (instructionCounting) {
- frame.pcPrevBranch = frame.pc;
- }
- continue Loop;
- }
- case Icode_POP :
- stack[stackTop] = null;
- stackTop--;
- continue Loop;
- case Icode_POP_RESULT :
- frame.result = stack[stackTop];
- frame.resultDbl = sDbl[stackTop];
- stack[stackTop] = null;
- --stackTop;
- continue Loop;
- case Icode_DUP :
- stack[stackTop + 1] = stack[stackTop];
- sDbl[stackTop + 1] = sDbl[stackTop];
- stackTop++;
- continue Loop;
- 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;
- continue Loop;
- 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;
- continue Loop;
- }
- case Token.RETURN :
- frame.result = stack[stackTop];
- frame.resultDbl = sDbl[stackTop];
- --stackTop;
- break Loop;
- case Token.RETURN_RESULT :
- break Loop;
- case Icode_RETUNDEF :
- frame.result = undefined;
- break Loop;
- case Token.BITNOT : {
- int rIntValue = stack_int32(frame, stackTop);
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = ~rIntValue;
- continue Loop;
- }
- case Token.BITAND :
- case Token.BITOR :
- case Token.BITXOR :
- case Token.LSH :
- case Token.RSH : {
- int lIntValue = stack_int32(frame, stackTop-1);
- int rIntValue = stack_int32(frame, stackTop);
- stack[--stackTop] = DBL_MRK;
- switch (op) {
- case Token.BITAND:
- lIntValue &= rIntValue;
- break;
- case Token.BITOR:
- lIntValue |= rIntValue;
- break;
- case Token.BITXOR:
- lIntValue ^= rIntValue;
- break;
- case Token.LSH:
- lIntValue <<= rIntValue;
- break;
- case Token.RSH:
- lIntValue >>= rIntValue;
- break;
- }
- sDbl[stackTop] = lIntValue;
- continue Loop;
- }
- case Token.URSH : {
- double lDbl = stack_double(frame, stackTop-1);
- int rIntValue = stack_int32(frame, stackTop) & 0x1F;
- stack[--stackTop] = DBL_MRK;
- sDbl[stackTop] = ScriptRuntime.toUint32(lDbl) >>> rIntValue;
- continue Loop;
- }
- 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;
- continue Loop;
- }
- case Token.ADD :
- --stackTop;
- do_add(stack, sDbl, stackTop, cx);
- continue Loop;
- case Token.SUB :
- case Token.MUL :
- case Token.DIV :
- case Token.MOD : {
- double rDbl = stack_double(frame, stackTop);
- --stackTop;
- double lDbl = stack_double(frame, stackTop);
- stack[stackTop] = DBL_MRK;
- switch (op) {
- case Token.SUB:
- lDbl -= rDbl;
- break;
- case Token.MUL:
- lDbl *= rDbl;
- break;
- case Token.DIV:
- lDbl /= rDbl;
- break;
- case Token.MOD:
- lDbl %= rDbl;
- break;
- }
- sDbl[stackTop] = lDbl;
- continue Loop;
- }
- case Token.NOT :
- stack[stackTop] = ScriptRuntime.wrapBoolean(
- !stack_boolean(frame, stackTop));
- continue Loop;
- case Token.BINDNAME :
- stack[++stackTop] = ScriptRuntime.bind(cx, frame.scope, stringReg);
- continue Loop;
- case Token.SETNAME : {
- Object rhs = stack[stackTop];
- if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- Scriptable lhs = (Scriptable)stack[stackTop];
- stack[stackTop] = ScriptRuntime.setName(lhs, rhs, cx,
- frame.scope, stringReg);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- case Token.DELPROP : {
- 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.delete(lhs, rhs, cx);
- continue Loop;
- }
- case Token.GETPROPNOWARN : {
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.getObjectPropNoWarn(lhs, stringReg, cx);
- continue Loop;
- }
- case Token.GETPROP : {
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.getObjectProp(lhs, stringReg, cx);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- 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;
- continue Loop;
- }
- case Token.GETELEM : {
- --stackTop;
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) {
- lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- }
- Object value;
- Object id = stack[stackTop + 1];
- if (id != DBL_MRK) {
- value = ScriptRuntime.getObjectElem(lhs, id, cx);
- } else {
- double d = sDbl[stackTop + 1];
- value = ScriptRuntime.getObjectIndex(lhs, d, cx);
- }
- stack[stackTop] = value;
- continue Loop;
- }
- case Token.SETELEM : {
- stackTop -= 2;
- Object rhs = stack[stackTop + 2];
- if (rhs == DBL_MRK) {
- rhs = ScriptRuntime.wrapNumber(sDbl[stackTop + 2]);
- }
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) {
- lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- }
- Object value;
- Object id = stack[stackTop + 1];
- if (id != DBL_MRK) {
- value = ScriptRuntime.setObjectElem(lhs, id, rhs, cx);
- } else {
- double d = sDbl[stackTop + 1];
- value = ScriptRuntime.setObjectIndex(lhs, d, rhs, cx);
- }
- stack[stackTop] = value;
- continue Loop;
- }
- case Icode_ELEM_INC_DEC: {
- 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.elemIncrDecr(lhs, rhs, cx,
- iCode[frame.pc]);
- ++frame.pc;
- continue Loop;
- }
- case Token.GET_REF : {
- Ref ref = (Ref)stack[stackTop];
- stack[stackTop] = ScriptRuntime.refGet(ref, cx);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- case Token.DEL_REF : {
- Ref ref = (Ref)stack[stackTop];
- stack[stackTop] = ScriptRuntime.refDel(ref, cx);
- continue Loop;
- }
- case Icode_REF_INC_DEC : {
- Ref ref = (Ref)stack[stackTop];
- stack[stackTop] = ScriptRuntime.refIncrDecr(ref, cx, iCode[frame.pc]);
- ++frame.pc;
- continue Loop;
- }
- case Token.LOCAL_LOAD :
- ++stackTop;
- indexReg += frame.localShift;
- stack[stackTop] = stack[indexReg];
- sDbl[stackTop] = sDbl[indexReg];
- continue Loop;
- case Icode_LOCAL_CLEAR :
- indexReg += frame.localShift;
- stack[indexReg] = null;
- continue Loop;
- case Icode_NAME_AND_THIS :
- // stringReg: name
- ++stackTop;
- stack[stackTop] = ScriptRuntime.getNameFunctionAndThis(stringReg,
- cx, frame.scope);
- ++stackTop;
- stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
- continue Loop;
- 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);
- ++stackTop;
- stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- case Icode_CALLSPECIAL : {
- if (instructionCounting) {
- cx.instructionCount += INVOCATION_COST;
- }
- int callType = iCode[frame.pc] & 0xFF;
- boolean isNew = (iCode[frame.pc + 1] != 0);
- int sourceLine = getIndex(iCode, frame.pc + 2);
-
- // indexReg: number of arguments
- if (isNew) {
- // stack change: function arg0 .. argN -> newResult
- stackTop -= indexReg;
-
- Object function = stack[stackTop];
- if (function == DBL_MRK)
- function = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- Object[] outArgs = getArgsArray(
- stack, sDbl, stackTop + 1, indexReg);
- stack[stackTop] = ScriptRuntime.newSpecial(
- cx, function, outArgs, frame.scope, callType);
- } else {
- // stack change: function thisObj arg0 .. argN -> result
- stackTop -= 1 + indexReg;
-
- // Call code generation ensure that stack here
- // is ... Callable Scriptable
- Scriptable functionThis = (Scriptable)stack[stackTop + 1];
- Callable function = (Callable)stack[stackTop];
- Object[] outArgs = getArgsArray(
- stack, sDbl, stackTop + 2, indexReg);
- stack[stackTop] = ScriptRuntime.callSpecial(
- cx, function, functionThis, outArgs,
- frame.scope, frame.thisObj, callType,
- frame.idata.itsSourceFile, sourceLine);
- }
- frame.pc += 4;
- continue Loop;
- }
- 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);
- continue Loop;
- }
- Scriptable calleeScope = frame.scope;
- if (frame.useActivation) {
- calleeScope = ScriptableObject.getTopLevelScope(frame.scope);
- }
- if (fun instanceof InterpretedFunction) {
- InterpretedFunction ifun = (InterpretedFunction)fun;
- if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
- CallFrame callParentFrame = frame;
- CallFrame calleeFrame = new CallFrame();
- if (op == Icode_TAIL_CALL) {
- // In principle tail call can re-use the current
- // frame and its stack arrays but it is hard to
- // do properly. Any exceptions that can legally
- // happen during frame re-initialization including
- // StackOverflowException during innocent looking
- // System.arraycopy may leave the current frame
- // data corrupted leading to undefined behaviour
- // in the catch code bellow that unwinds JS stack
- // on exceptions. Then there is issue about frame release
- // end exceptions there.
- // To avoid frame allocation a released frame
- // can be cached for re-use which would also benefit
- // non-tail calls but it is not clear that this caching
- // would gain in performance due to potentially
- // bad 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;
- continue StateLoop;
- }
- }
-
- if (fun instanceof Continuation) {
- // Jump to the captured continuation
- ContinuationJump cjump;
- cjump = new ContinuationJump((Continuation)fun, frame);
-
- // continuation result is the first argument if any
- // of contination call
- if (indexReg == 0) {
- cjump.result = undefined;
- } else {
- cjump.result = stack[stackTop + 2];
- cjump.resultDbl = sDbl[stackTop + 2];
- }
-
- // Start the real unwind job
- throwable = cjump;
- break withoutExceptions;
- }
-
- if (fun instanceof IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject)fun;
- if (Continuation.isContinuationConstructor(ifun)) {
- captureContinuation(cx, frame, stackTop);
- continue Loop;
- }
- // 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 instanceof InterpretedFunction) {
- InterpretedFunction iApplyCallable = (InterpretedFunction)applyCallable;
- if(frame.fnOrScript.securityDomain == iApplyCallable.securityDomain) {
- frame = initFrameForApplyOrCall(cx, frame, indexReg,
- stack, sDbl, stackTop, op, calleeScope, ifun,
- iApplyCallable);
- continue StateLoop;
- }
- }
- }
- }
-
- stack[stackTop] = fun.call(cx, calleeScope, funThisObj,
- getArgsArray(stack, sDbl, stackTop + 2, indexReg));
-
- continue Loop;
- }
- 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 instanceof InterpretedFunction) {
- InterpretedFunction f = (InterpretedFunction)lhs;
- if (frame.fnOrScript.securityDomain == f.securityDomain) {
- Scriptable newInstance = f.createObject(cx, frame.scope);
- CallFrame calleeFrame = new CallFrame();
- initFrame(cx, frame.scope, newInstance, stack, sDbl,
- stackTop + 1, indexReg, f, frame,
- calleeFrame);
-
- stack[stackTop] = newInstance;
- frame.savedStackTop = stackTop;
- frame.savedCallOp = op;
- frame = calleeFrame;
- continue StateLoop;
- }
- }
- if (!(lhs instanceof Function)) {
- if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- throw ScriptRuntime.notFunctionError(lhs);
- }
- Function fun = (Function)lhs;
-
- if (fun instanceof IdFunctionObject) {
- IdFunctionObject ifun = (IdFunctionObject)fun;
- if (Continuation.isContinuationConstructor(ifun)) {
- captureContinuation(cx, frame, stackTop);
- continue Loop;
- }
- }
-
- Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 1, indexReg);
- stack[stackTop] = fun.construct(cx, frame.scope, outArgs);
- continue Loop;
- }
- case Token.TYPEOF : {
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.typeof(lhs);
- continue Loop;
- }
- case Icode_TYPEOFNAME :
- stack[++stackTop] = ScriptRuntime.typeofName(frame.scope, stringReg);
- continue Loop;
- case Token.STRING :
- stack[++stackTop] = stringReg;
- continue Loop;
- case Icode_SHORTNUMBER :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = getShort(iCode, frame.pc);
- frame.pc += 2;
- continue Loop;
- case Icode_INTNUMBER :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = getInt(iCode, frame.pc);
- frame.pc += 4;
- continue Loop;
- case Token.NUMBER :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = frame.idata.itsDoubleTable[indexReg];
- continue Loop;
- case Token.NAME :
- stack[++stackTop] = ScriptRuntime.name(cx, frame.scope, stringReg);
- continue Loop;
- case Icode_NAME_INC_DEC :
- stack[++stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, stringReg,
- cx, iCode[frame.pc]);
- ++frame.pc;
- continue Loop;
- case Icode_SETCONSTVAR1:
- indexReg = iCode[frame.pc++];
- // fallthrough
- case Token.SETCONSTVAR :
- if (!frame.useActivation) {
- if ((varAttributes[indexReg] & ScriptableObject.READONLY) == 0) {
- throw Context.reportRuntimeError1("msg.var.redecl",
- frame.idata.argNames[indexReg]);
- }
- if ((varAttributes[indexReg] & ScriptableObject.UNINITIALIZED_CONST)
- != 0)
- {
- vars[indexReg] = stack[stackTop];
- varAttributes[indexReg] &= ~ScriptableObject.UNINITIALIZED_CONST;
- varDbls[indexReg] = sDbl[stackTop];
- }
- } else {
- Object val = stack[stackTop];
- if (val == DBL_MRK) val = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stringReg = frame.idata.argNames[indexReg];
- if (frame.scope instanceof ConstProperties) {
- ConstProperties cp = (ConstProperties)frame.scope;
- cp.putConst(stringReg, frame.scope, val);
- } else
- throw Kit.codeBug();
- }
- continue Loop;
- case Icode_SETVAR1:
- indexReg = iCode[frame.pc++];
- // fallthrough
- case Token.SETVAR :
- if (!frame.useActivation) {
- if ((varAttributes[indexReg] & ScriptableObject.READONLY) == 0) {
- vars[indexReg] = stack[stackTop];
- varDbls[indexReg] = sDbl[stackTop];
- }
- } else {
- Object val = stack[stackTop];
- if (val == DBL_MRK) val = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stringReg = frame.idata.argNames[indexReg];
- frame.scope.put(stringReg, frame.scope, val);
- }
- continue Loop;
- case Icode_GETVAR1:
- indexReg = iCode[frame.pc++];
- // fallthrough
- case Token.GETVAR :
- ++stackTop;
- if (!frame.useActivation) {
- stack[stackTop] = vars[indexReg];
- sDbl[stackTop] = varDbls[indexReg];
- } else {
- stringReg = frame.idata.argNames[indexReg];
- stack[stackTop] = frame.scope.get(stringReg, frame.scope);
- }
- continue Loop;
- case Icode_VAR_INC_DEC : {
- // indexReg : varindex
- ++stackTop;
- int incrDecrMask = iCode[frame.pc];
- if (!frame.useActivation) {
- stack[stackTop] = DBL_MRK;
- Object varValue = vars[indexReg];
- double d;
- if (varValue == DBL_MRK) {
- d = varDbls[indexReg];
- } else {
- d = ScriptRuntime.toNumber(varValue);
- vars[indexReg] = DBL_MRK;
- }
- double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0)
- ? d + 1.0 : d - 1.0;
- varDbls[indexReg] = d2;
- sDbl[stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
- } else {
- String varName = frame.idata.argNames[indexReg];
- stack[stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, varName,
- cx, incrDecrMask);
- }
- ++frame.pc;
- continue Loop;
- }
- case Icode_ZERO :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = 0;
- continue Loop;
- case Icode_ONE :
- ++stackTop;
- stack[stackTop] = DBL_MRK;
- sDbl[stackTop] = 1;
- continue Loop;
- case Token.NULL :
- stack[++stackTop] = null;
- continue Loop;
- case Token.THIS :
- stack[++stackTop] = frame.thisObj;
- continue Loop;
- case Token.THISFN :
- stack[++stackTop] = frame.fnOrScript;
- continue Loop;
- case Token.FALSE :
- stack[++stackTop] = Boolean.FALSE;
- continue Loop;
- case Token.TRUE :
- stack[++stackTop] = Boolean.TRUE;
- continue Loop;
- case Icode_UNDEF :
- stack[++stackTop] = undefined;
- continue Loop;
- 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);
- continue Loop;
- }
- case Token.LEAVEWITH :
- frame.scope = ScriptRuntime.leaveWith(frame.scope);
- continue Loop;
- case Token.CATCH_SCOPE : {
- // stack top: exception object
- // stringReg: name of exception variable
- // indexReg: local for exception scope
- --stackTop;
- indexReg += frame.localShift;
-
- boolean afterFirstScope = (frame.idata.itsICode[frame.pc] != 0);
- Throwable caughtException = (Throwable)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;
- continue Loop;
- }
- 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);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- case Token.REF_MEMBER: {
- //indexReg: flags
- Object elem = stack[stackTop];
- if (elem == DBL_MRK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- Object obj = stack[stackTop];
- if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.memberRef(obj, elem, cx, indexReg);
- continue Loop;
- }
- case Token.REF_NS_MEMBER: {
- //indexReg: flags
- Object elem = stack[stackTop];
- if (elem == DBL_MRK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- Object ns = stack[stackTop];
- if (ns == DBL_MRK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- Object obj = stack[stackTop];
- if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.memberRef(obj, ns, elem, cx, indexReg);
- continue Loop;
- }
- 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);
- continue Loop;
- }
- case Token.REF_NS_NAME: {
- //indexReg: flags
- Object name = stack[stackTop];
- if (name == DBL_MRK) name = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- Object ns = stack[stackTop];
- if (ns == DBL_MRK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.nameRef(ns, name, cx, frame.scope,
- indexReg);
- continue Loop;
- }
- case Icode_SCOPE_LOAD :
- indexReg += frame.localShift;
- frame.scope = (Scriptable)stack[indexReg];
- continue Loop;
- case Icode_SCOPE_SAVE :
- indexReg += frame.localShift;
- stack[indexReg] = frame.scope;
- continue Loop;
- case Icode_CLOSURE_EXPR :
- stack[++stackTop] = InterpretedFunction.createFunction(cx, frame.scope,
- frame.fnOrScript,
- indexReg);
- continue Loop;
- case Icode_CLOSURE_STMT :
- initFunction(cx, frame.scope, frame.fnOrScript, indexReg);
- continue Loop;
- case Token.REGEXP :
- stack[++stackTop] = frame.scriptRegExps[indexReg];
- continue Loop;
- 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;
- continue Loop;
- 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;
- continue Loop;
- }
- 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;
- continue Loop;
- }
- 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;
- continue Loop;
- }
- 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;
- continue Loop;
- }
- case Icode_ENTERDQ : {
- Object lhs = stack[stackTop];
- if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- --stackTop;
- frame.scope = ScriptRuntime.enterDotQuery(lhs, frame.scope);
- continue Loop;
- }
- case Icode_LEAVEDQ : {
- boolean 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;
- continue Loop;
- }
- // reset stack and PC to code after ENTERDQ
- --stackTop;
- break jumplessRun;
- }
- case Token.DEFAULTNAMESPACE : {
- Object value = stack[stackTop];
- if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
- stack[stackTop] = ScriptRuntime.setDefaultNamespace(value, cx);
- continue Loop;
- }
- case Token.ESCXMLATTR : {
- Object value = stack[stackTop];
- if (value != DBL_MRK) {
- stack[stackTop] = ScriptRuntime.escapeAttributeValue(value, cx);
- }
- continue Loop;
- }
- case Token.ESCXMLTEXT : {
- Object value = stack[stackTop];
- if (value != DBL_MRK) {
- stack[stackTop] = ScriptRuntime.escapeTextValue(value, cx);
- }
- continue Loop;
- }
- case Icode_DEBUGGER:
- if (frame.debuggerFrame != null) {
- frame.debuggerFrame.onDebuggerStatement(cx);
- }
- break Loop;
- 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;
- continue Loop;
- case Icode_REG_IND_C0:
- indexReg = 0;
- continue Loop;
- case Icode_REG_IND_C1:
- indexReg = 1;
- continue Loop;
- case Icode_REG_IND_C2:
- indexReg = 2;
- continue Loop;
- case Icode_REG_IND_C3:
- indexReg = 3;
- continue Loop;
- case Icode_REG_IND_C4:
- indexReg = 4;
- continue Loop;
- case Icode_REG_IND_C5:
- indexReg = 5;
- continue Loop;
- case Icode_REG_IND1:
- indexReg = 0xFF & iCode[frame.pc];
- ++frame.pc;
- continue Loop;
- case Icode_REG_IND2:
- indexReg = getIndex(iCode, frame.pc);
- frame.pc += 2;
- continue Loop;
- case Icode_REG_IND4:
- indexReg = getInt(iCode, frame.pc);
- frame.pc += 4;
- continue Loop;
- case Icode_REG_STR_C0:
- stringReg = strings[0];
- continue Loop;
- case Icode_REG_STR_C1:
- stringReg = strings[1];
- continue Loop;
- case Icode_REG_STR_C2:
- stringReg = strings[2];
- continue Loop;
- case Icode_REG_STR_C3:
- stringReg = strings[3];
- continue Loop;
- case Icode_REG_STR1:
- stringReg = strings[0xFF & iCode[frame.pc]];
- ++frame.pc;
- continue Loop;
- case Icode_REG_STR2:
- stringReg = strings[getIndex(iCode, frame.pc)];
- frame.pc += 2;
- continue Loop;
- case Icode_REG_STR4:
- stringReg = strings[getInt(iCode, frame.pc)];
- frame.pc += 4;
- continue Loop;
- default :
- dumpICode(frame.idata);
- throw new RuntimeException(
- "Unknown icode : "+op+" @ pc : "+(frame.pc-1));
-} // 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;
- }
- continue Loop;
-
- } // 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
- continue StateLoop;
- }
- break StateLoop;
-
- } // end of interpreter withoutExceptions: try
- catch (Throwable ex) {
- if (throwable != null) {
- // This is serious bug and it is better to track it ASAP
- ex.printStackTrace(System.err);
- throw new IllegalStateException();
- }
- throwable = ex;
- }
-
- // 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
- final int EX_CATCH_STATE = 2; // Can execute JS catch
- final int EX_FINALLY_STATE = 1; // Can execute JS finally
- final int EX_NO_JS_STATE = 0; // Terminate JS execution
-
- int exState;
- ContinuationJump cjump = null;
-
- if (generatorState != null &&
- generatorState.operation == NativeGenerator.GENERATOR_CLOSE &&
- throwable == generatorState.value)
- {
- exState = EX_FINALLY_STATE;
- } else if (throwable instanceof JavaScriptException) {
- exState = EX_CATCH_STATE;
- } else if (throwable instanceof EcmaError) {
- // an offical ECMA error object,
- exState = EX_CATCH_STATE;
- } else if (throwable instanceof EvaluatorException) {
- exState = EX_CATCH_STATE;
- } else if (throwable instanceof RuntimeException) {
- exState = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
- ? EX_CATCH_STATE
- : EX_FINALLY_STATE;
- } else if (throwable instanceof Error) {
- exState = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
- ? EX_CATCH_STATE
- : EX_NO_JS_STATE;
- } else if (throwable instanceof ContinuationJump) {
- // It must be ContinuationJump
- exState = EX_FINALLY_STATE;
- cjump = (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 (RuntimeException ex) {
- throwable = ex;
- exState = EX_FINALLY_STATE;
- } catch (Error ex) {
- // Error from instruction counting
- // => unconditionally terminate JS
- throwable = ex;
- cjump = null;
- exState = EX_NO_JS_STATE;
- }
- }
- if (frame.debuggerFrame != null
- && throwable instanceof RuntimeException)
- {
- // Call debugger only for RuntimeException
- RuntimeException rex = (RuntimeException)throwable;
- try {
- frame.debuggerFrame.onExceptionThrown(cx, rex);
- } catch (Throwable ex) {
- // Any exception from debugger
- // => unconditionally terminate JS
- throwable = ex;
- cjump = null;
- exState = EX_NO_JS_STATE;
- }
- }
-
- for (;;) {
- if (exState != EX_NO_JS_STATE) {
- boolean 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
- continue StateLoop;
- }
- }
- // 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 != null && cjump.branchFrame == frame) {
- // Continuation branch point was hit,
- // restart the state loop to reenter continuation
- indexReg = -1;
- continue StateLoop;
- }
- }
-
- // No more frames, rethrow the exception or deal with continuation
- if (cjump != null) {
- if (cjump.branchFrame != null) {
- // The above loop should locate the top frame
- Kit.codeBug();
- }
- if (cjump.capturedFrame != null) {
- // Restarting detached continuation
- indexReg = -1;
- continue StateLoop;
- }
- // Return continuation result to the caller
- interpreterResult = cjump.result;
- interpreterResultDbl = cjump.resultDbl;
- throwable = null;
- }
- break StateLoop;
-
- } // 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 instanceof RuntimeException) {
- throw (RuntimeException)throwable;
- } else {
- // Must be instance of Error or code bug
- throw (Error)throwable;
- }
- }
-
- return (interpreterResult != DBL_MRK)
- ? interpreterResult
- : ScriptRuntime.wrapNumber(interpreterResultDbl);
- }
-
- private static CallFrame processThrowable(Context cx, Object throwable,
- CallFrame frame, int indexReg,
- boolean instructionCounting)
- {
- // Recovering from exception, indexReg contains
- // the index of handler
-
- if (indexReg >= 0) {
- // Normal exception handler, transfer
- // control appropriately
-
- if (frame.frozen) {
- // XXX Deal with exceptios!!!
- frame = frame.cloneFrozen();
- }
-
- int[] table = frame.idata.itsExceptionTable;
-
- frame.pc = table[indexReg + EXCEPTION_HANDLER_SLOT];
- if (instructionCounting) {
- frame.pcPrevBranch = frame.pc;
- }
-
- frame.savedStackTop = frame.emptyStackTop;
- int scopeLocal = frame.localShift
- + table[indexReg
- + EXCEPTION_SCOPE_SLOT];
- int exLocal = frame.localShift
- + table[indexReg
- + EXCEPTION_LOCAL_SLOT];
- frame.scope = (Scriptable)frame.stack[scopeLocal];
- frame.stack[exLocal] = throwable;
-
- throwable = null;
- } else {
- // Continuation restoration
- ContinuationJump cjump = (ContinuationJump)throwable;
-
- // Clear throwable to indicate that exceptions are OK
- throwable = null;
-
- if (cjump.branchFrame != frame) Kit.codeBug();
-
- // Check that we have at least one frozen frame
- // in the case of detached continuation restoration:
- // unwind code ensure that
- if (cjump.capturedFrame == null) Kit.codeBug();
-
- // Need to rewind branchFrame, capturedFrame
- // and all frames in between
- int rewindCount = cjump.capturedFrame.frameIndex + 1;
- if (cjump.branchFrame != null) {
- rewindCount -= cjump.branchFrame.frameIndex;
- }
-
- int enterCount = 0;
- CallFrame[] enterFrames = null;
-
- CallFrame x = cjump.capturedFrame;
- for (int i = 0; i != rewindCount; ++i) {
- if (!x.frozen) Kit.codeBug();
- if (isFrameEnterExitRequired(x)) {
- if (enterFrames == null) {
- // Allocate enough space to store the rest
- // of rewind frames in case all of them
- // would require to enter
- enterFrames = new CallFrame[rewindCount
- - i];
- }
- enterFrames[enterCount] = x;
- ++enterCount;
- }
- x = x.parentFrame;
- }
-
- while (enterCount != 0) {
- // execute enter: walk enterFrames in the reverse
- // order since they were stored starting from
- // the capturedFrame, not branchFrame
- --enterCount;
- x = enterFrames[enterCount];
- enterFrame(cx, x, ScriptRuntime.emptyArgs, true);
- }
-
- // Continuation jump is almost done: capturedFrame
- // points to the call to the function that captured
- // continuation, so clone capturedFrame and
- // emulate return that function with the suplied result
- frame = cjump.capturedFrame.cloneFrozen();
- setCallResult(frame, cjump.result, cjump.resultDbl);
- // restart the execution
- }
- frame.throwable = throwable;
- return frame;
- }
-
- private static Object freezeGenerator(Context cx, CallFrame frame,
- int stackTop,
- GeneratorState generatorState)
- {
- if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
- // Error: no yields when generator is closing
- throw ScriptRuntime.typeError0("msg.yield.closing");
- }
- // return to our caller (which should be a method of NativeGenerator)
- frame.frozen = true;
- frame.result = frame.stack[stackTop];
- frame.resultDbl = frame.sDbl[stackTop];
- frame.savedStackTop = stackTop;
- frame.pc--; // we want to come back here when we resume
- ScriptRuntime.exitActivationFunction(cx);
- return (frame.result != UniqueTag.DOUBLE_MARK)
- ? frame.result
- : ScriptRuntime.wrapNumber(frame.resultDbl);
- }
-
- private static Object thawGenerator(CallFrame frame, int stackTop,
- GeneratorState generatorState, int op)
- {
- // we are resuming execution
- frame.frozen = false;
- int sourceLine = getIndex(frame.idata.itsICode, frame.pc);
- frame.pc += 2; // skip line number data
- if (generatorState.operation == NativeGenerator.GENERATOR_THROW) {
- // processing a call to <generator>.throw(exception): must
- // act as if exception was thrown from resumption point
- return new JavaScriptException(generatorState.value,
- frame.idata.itsSourceFile,
- sourceLine);
- }
- if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
- return generatorState.value;
- }
- if (generatorState.operation != NativeGenerator.GENERATOR_SEND)
- throw Kit.codeBug();
- if (op == Token.YIELD)
- frame.stack[stackTop] = generatorState.value;
- return Scriptable.NOT_FOUND;
- }
-
- private static CallFrame initFrameForApplyOrCall(Context cx, CallFrame frame,
- int indexReg, Object[] stack, double[] sDbl, int stackTop, int op,
- Scriptable calleeScope, IdFunctionObject ifun,
- InterpretedFunction iApplyCallable)
- {
- Scriptable applyThis;
- if (indexReg != 0) {
- applyThis = ScriptRuntime.toObjectOrNull(cx, stack[stackTop + 2]);
- }
- else {
- applyThis = null;
- }
- if (applyThis == null) {
- // This covers the case of args[0] == (null|undefined) as well.
- applyThis = ScriptRuntime.getTopCallScope(cx);
- }
- if(op == Icode_TAIL_CALL) {
- exitFrame(cx, frame, null);
- frame = frame.parentFrame;
- }
- else {
- frame.savedStackTop = stackTop;
- frame.savedCallOp = op;
- }
- CallFrame calleeFrame = new CallFrame();
- if(BaseFunction.isApply(ifun)) {
- Object[] callArgs = indexReg < 2 ? ScriptRuntime.emptyArgs :
- ScriptRuntime.getApplyArguments(cx, stack[stackTop + 3]);
- initFrame(cx, calleeScope, applyThis, callArgs, null, 0,
- callArgs.length, iApplyCallable, frame, calleeFrame);
- }
- else {
- // Shift args left
- for(int i = 1; i < indexReg; ++i) {
- stack[stackTop + 1 + i] = stack[stackTop + 2 + i];
- sDbl[stackTop + 1 + i] = sDbl[stackTop + 2 + i];
- }
- int argCount = indexReg < 2 ? 0 : indexReg - 1;
- initFrame(cx, calleeScope, applyThis, stack, sDbl, stackTop + 2,
- argCount, iApplyCallable, frame, calleeFrame);
- }
-
- frame = calleeFrame;
- return frame;
- }
-
- private static void initFrame(Context cx, Scriptable callerScope,
- Scriptable thisObj,
- Object[] args, double[] argsDbl,
- int argShift, int argCount,
- InterpretedFunction fnOrScript,
- CallFrame parentFrame, CallFrame frame)
- {
- InterpreterData idata = fnOrScript.idata;
-
- boolean useActivation = idata.itsNeedsActivation;
- DebugFrame debuggerFrame = null;
- if (cx.debugger != null) {
- debuggerFrame = cx.debugger.getFrame(cx, idata);
- if (debuggerFrame != null) {
- useActivation = true;
- }
- }
-
- if (useActivation) {
- // Copy args to new array to pass to enterActivationFunction
- // or debuggerFrame.onEnter
- if (argsDbl != null) {
- args = getArgsArray(args, argsDbl, argShift, argCount);
- }
- argShift = 0;
- argsDbl = null;
- }
-
- Scriptable scope;
- if (idata.itsFunctionType != 0) {
- if (!idata.useDynamicScope) {
- scope = fnOrScript.getParentScope();
- } else {
- scope = callerScope;
- }
-
- if (useActivation) {
- scope = ScriptRuntime.createFunctionActivation(
- fnOrScript, scope, args);
- }
- } else {
- scope = callerScope;
- ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
- fnOrScript.idata.evalScriptFlag);
- }
-
- if (idata.itsNestedFunctions != null) {
- if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation)
- Kit.codeBug();
- for (int i = 0; i < idata.itsNestedFunctions.length; i++) {
- InterpreterData fdata = idata.itsNestedFunctions[i];
- if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
- initFunction(cx, scope, fnOrScript, i);
- }
- }
- }
-
- Scriptable[] scriptRegExps = null;
- if (idata.itsRegExpLiterals != null) {
- // Wrapped regexps for functions are stored in
- // InterpretedFunction
- // but for script which should not contain references to scope
- // the regexps re-wrapped during each script execution
- if (idata.itsFunctionType != 0) {
- scriptRegExps = fnOrScript.functionRegExps;
- } else {
- scriptRegExps = fnOrScript.createRegExpWraps(cx, scope);
- }
- }
-
- // Initialize args, vars, locals and stack
-
- int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1;
- int maxFrameArray = idata.itsMaxFrameArray;
- if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1)
- Kit.codeBug();
-
- Object[] stack;
- int[] stackAttributes;
- double[] sDbl;
- boolean stackReuse;
- if (frame.stack != null && maxFrameArray <= frame.stack.length) {
- // Reuse stacks from old frame
- stackReuse = true;
- stack = frame.stack;
- stackAttributes = frame.stackAttributes;
- sDbl = frame.sDbl;
- } else {
- stackReuse = false;
- stack = new Object[maxFrameArray];
- stackAttributes = new int[maxFrameArray];
- sDbl = new double[maxFrameArray];
- }
-
- int varCount = idata.getParamAndVarCount();
- for (int i = 0; i < varCount; i++) {
- if (idata.getParamOrVarConst(i))
- stackAttributes[i] = ScriptableObject.CONST;
- }
- int definedArgs = idata.argCount;
- if (definedArgs > argCount) { definedArgs = argCount; }
-
- // Fill the frame structure
-
- frame.parentFrame = parentFrame;
- frame.frameIndex = (parentFrame == null)
- ? 0 : parentFrame.frameIndex + 1;
- if(frame.frameIndex > cx.getMaximumInterpreterStackDepth())
- {
- throw Context.reportRuntimeError("Exceeded maximum stack depth");
- }
- frame.frozen = false;
-
- frame.fnOrScript = fnOrScript;
- frame.idata = idata;
-
- frame.stack = stack;
- frame.stackAttributes = stackAttributes;
- frame.sDbl = sDbl;
- frame.varSource = frame;
- frame.localShift = idata.itsMaxVars;
- frame.emptyStackTop = emptyStackTop;
-
- frame.debuggerFrame = debuggerFrame;
- frame.useActivation = useActivation;
-
- frame.thisObj = thisObj;
- frame.scriptRegExps = scriptRegExps;
-
- // Initialize initial values of variables that change during
- // interpretation.
- frame.result = Undefined.instance;
- frame.pc = 0;
- frame.pcPrevBranch = 0;
- frame.pcSourceLineStart = idata.firstLinePC;
- frame.scope = scope;
-
- frame.savedStackTop = emptyStackTop;
- frame.savedCallOp = 0;
-
- System.arraycopy(args, argShift, stack, 0, definedArgs);
- if (argsDbl != null) {
- System.arraycopy(argsDbl, argShift, sDbl, 0, definedArgs);
- }
- for (int i = definedArgs; i != idata.itsMaxVars; ++i) {
- stack[i] = Undefined.instance;
- }
- if (stackReuse) {
- // Clean the stack part and space beyond stack if any
- // of the old array to allow to GC objects there
- for (int i = emptyStackTop + 1; i != stack.length; ++i) {
- stack[i] = null;
- }
- }
-
- enterFrame(cx, frame, args, false);
- }
-
- private static boolean isFrameEnterExitRequired(CallFrame frame)
- {
- return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
- }
-
- private static void enterFrame(Context cx, CallFrame frame, Object[] args,
- boolean continuationRestart)
- {
- boolean usesActivation = frame.idata.itsNeedsActivation;
- boolean isDebugged = frame.debuggerFrame != null;
- if(usesActivation || isDebugged) {
- Scriptable scope = frame.scope;
- if(scope == null) {
- Kit.codeBug();
- } else if (continuationRestart) {
- // Walk the parent chain of frame.scope until a NativeCall is
- // found. Normally, frame.scope is a NativeCall when called
- // from initFrame() for a debugged or activatable function.
- // However, when called from interpretLoop() as part of
- // restarting a continuation, it can also be a NativeWith if
- // the continuation was captured within a "with" or "catch"
- // block ("catch" implicitly uses NativeWith to create a scope
- // to expose the exception variable).
- for(;;) {
- if(scope instanceof NativeWith) {
- scope = scope.getParentScope();
- if (scope == null || (frame.parentFrame != null &&
- frame.parentFrame.scope == scope))
- {
- // If we get here, we didn't find a NativeCall in
- // the call chain before reaching parent frame's
- // scope. This should not be possible.
- Kit.codeBug();
- break; // Never reached, but keeps the static analyzer happy about "scope" not being null 5 lines above.
- }
- }
- else {
- break;
- }
- }
- }
- if (isDebugged) {
- frame.debuggerFrame.onEnter(cx, scope, frame.thisObj, args);
- }
- // Enter activation only when itsNeedsActivation true,
- // since debugger should not interfere with activation
- // chaining
- if (usesActivation) {
- ScriptRuntime.enterActivationFunction(cx, scope);
- }
- }
- }
-
- private static void exitFrame(Context cx, CallFrame frame,
- Object throwable)
- {
- if (frame.idata.itsNeedsActivation) {
- ScriptRuntime.exitActivationFunction(cx);
- }
-
- if (frame.debuggerFrame != null) {
- try {
- if (throwable instanceof Throwable) {
- frame.debuggerFrame.onExit(cx, true, throwable);
- } else {
- Object result;
- ContinuationJump cjump = (ContinuationJump)throwable;
- if (cjump == null) {
- result = frame.result;
- } else {
- result = cjump.result;
- }
- if (result == UniqueTag.DOUBLE_MARK) {
- double resultDbl;
- if (cjump == null) {
- resultDbl = frame.resultDbl;
- } else {
- resultDbl = cjump.resultDbl;
- }
- result = ScriptRuntime.wrapNumber(resultDbl);
- }
- frame.debuggerFrame.onExit(cx, false, result);
- }
- } catch (Throwable ex) {
- System.err.println(
-"RHINO USAGE WARNING: onExit terminated with exception");
- ex.printStackTrace(System.err);
- }
- }
- }
-
- private static void setCallResult(CallFrame frame,
- Object callResult,
- double callResultDbl)
- {
- if (frame.savedCallOp == Token.CALL) {
- frame.stack[frame.savedStackTop] = callResult;
- frame.sDbl[frame.savedStackTop] = callResultDbl;
- } else if (frame.savedCallOp == Token.NEW) {
- // If construct returns scriptable,
- // then it replaces on stack top saved original instance
- // of the object.
- if (callResult instanceof Scriptable) {
- frame.stack[frame.savedStackTop] = callResult;
- }
- } else {
- Kit.codeBug();
- }
- frame.savedCallOp = 0;
- }
-
- private static void captureContinuation(Context cx, CallFrame frame,
- int stackTop)
- {
- Continuation c = new Continuation();
- ScriptRuntime.setObjectProtoAndParent(
- c, ScriptRuntime.getTopCallScope(cx));
-
- // Make sure that all frames upstack frames are frozen
- CallFrame x = frame.parentFrame;
- while (x != null && !x.frozen) {
- x.frozen = true;
- // Allow to GC unused stack space
- for (int i = x.savedStackTop + 1; i != x.stack.length; ++i) {
- // Allow to GC unused stack space
- x.stack[i] = null;
- x.stackAttributes[i] = ScriptableObject.EMPTY;
- }
- if (x.savedCallOp == Token.CALL) {
- // the call will always overwrite the stack top with the result
- x.stack[x.savedStackTop] = null;
- } else {
- if (x.savedCallOp != Token.NEW) Kit.codeBug();
- // the new operator uses stack top to store the constructed
- // object so it shall not be cleared: see comments in
- // setCallResult
- }
- x = x.parentFrame;
- }
-
- c.initImplementation(frame.parentFrame);
- frame.stack[stackTop] = c;
- }
-
- private static int stack_int32(CallFrame frame, int i)
- {
- Object x = frame.stack[i];
- double value;
- if (x == UniqueTag.DOUBLE_MARK) {
- value = frame.sDbl[i];
- } else {
- value = ScriptRuntime.toNumber(x);
- }
- return ScriptRuntime.toInt32(value);
- }
-
- private static double stack_double(CallFrame frame, int i)
- {
- Object x = frame.stack[i];
- if (x != UniqueTag.DOUBLE_MARK) {
- return ScriptRuntime.toNumber(x);
- } else {
- return frame.sDbl[i];
- }
- }
-
- private static boolean stack_boolean(CallFrame frame, int i)
- {
- Object x = frame.stack[i];
- if (x == Boolean.TRUE) {
- return true;
- } else if (x == Boolean.FALSE) {
- return false;
- } else if (x == UniqueTag.DOUBLE_MARK) {
- double d = frame.sDbl[i];
- return d == d && d != 0.0;
- } else if (x == null || x == Undefined.instance) {
- return false;
- } else if (x instanceof Number) {
- double d = ((Number)x).doubleValue();
- return (d == d && d != 0.0);
- } else if (x instanceof Boolean) {
- return ((Boolean)x).booleanValue();
- } else {
- return ScriptRuntime.toBoolean(x);
- }
- }
-
- private static void do_add(Object[] stack, double[] sDbl, int stackTop,
- Context cx)
- {
- Object rhs = stack[stackTop + 1];
- Object lhs = stack[stackTop];
- double d;
- boolean leftRightOrder;
- if (rhs == UniqueTag.DOUBLE_MARK) {
- d = sDbl[stackTop + 1];
- if (lhs == UniqueTag.DOUBLE_MARK) {
- sDbl[stackTop] += d;
- return;
- }
- leftRightOrder = true;
- // fallthrough to object + number code
- } else if (lhs == UniqueTag.DOUBLE_MARK) {
- d = sDbl[stackTop];
- lhs = rhs;
- leftRightOrder = false;
- // fallthrough to object + number code
- } else {
- if (lhs instanceof Scriptable || rhs instanceof Scriptable) {
- stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
- } else if (lhs instanceof String) {
- String lstr = (String)lhs;
- String rstr = ScriptRuntime.toString(rhs);
- stack[stackTop] = lstr.concat(rstr);
- } else if (rhs instanceof String) {
- String lstr = ScriptRuntime.toString(lhs);
- String rstr = (String)rhs;
- stack[stackTop] = lstr.concat(rstr);
- } else {
- double lDbl = (lhs instanceof Number)
- ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
- double rDbl = (rhs instanceof Number)
- ? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);
- stack[stackTop] = UniqueTag.DOUBLE_MARK;
- sDbl[stackTop] = lDbl + rDbl;
- }
- return;
- }
-
- // handle object(lhs) + number(d) code
- if (lhs instanceof Scriptable) {
- rhs = ScriptRuntime.wrapNumber(d);
- if (!leftRightOrder) {
- Object tmp = lhs;
- lhs = rhs;
- rhs = tmp;
- }
- stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
- } else if (lhs instanceof String) {
- String lstr = (String)lhs;
- String rstr = ScriptRuntime.toString(d);
- if (leftRightOrder) {
- stack[stackTop] = lstr.concat(rstr);
- } else {
- stack[stackTop] = rstr.concat(lstr);
- }
- } else {
- double lDbl = (lhs instanceof Number)
- ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
- stack[stackTop] = UniqueTag.DOUBLE_MARK;
- sDbl[stackTop] = lDbl + d;
- }
- }
-
- private static Object[] getArgsArray(Object[] stack, double[] sDbl,
- int shift, int count)
- {
- if (count == 0) {
- return ScriptRuntime.emptyArgs;
- }
- Object[] args = new Object[count];
- for (int i = 0; i != count; ++i, ++shift) {
- Object val = stack[shift];
- if (val == UniqueTag.DOUBLE_MARK) {
- val = ScriptRuntime.wrapNumber(sDbl[shift]);
- }
- args[i] = val;
- }
- return args;
- }
-
- private static void addInstructionCount(Context cx, CallFrame frame,
- int extra)
- {
- cx.instructionCount += frame.pc - frame.pcPrevBranch + extra;
- if (cx.instructionCount > cx.instructionThreshold) {
- cx.observeInstructionCount(cx.instructionCount);
- cx.instructionCount = 0;
- }
- }
-}