From 89bda83e0570ab87c6e449f5955613d5385e90b3 Mon Sep 17 00:00:00 2001 From: "alexanders@b2ef00c0-3703-41da-baef-cfe82387ac0c" Date: Wed, 3 Feb 2010 00:50:41 +0000 Subject: removed obsolete svn folder from hg tree --HG-- extra : convert_revision : svn%3Ab2ef00c0-3703-41da-baef-cfe82387ac0c/trunk%408 --- .../src/org/mozilla/javascript/Interpreter.java | 4643 -------------------- 1 file changed, 4643 deletions(-) delete mode 100644 trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java (limited to 'trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java') diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Interpreter.java deleted file mode 100644 index a68c025..0000000 --- a/trunk/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 .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; - } - } -} -- cgit v1.2.3-1-g7c22