-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
- *\r
- * The contents of this file are subject to the Netscape Public\r
- * License Version 1.1 (the "License"); you may not use this file\r
- * except in compliance with the License. You may obtain a copy of\r
- * the License at http://www.mozilla.org/NPL/\r
- *\r
- * Software distributed under the License is distributed on an "AS\r
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
- * implied. See the License for the specific language governing\r
- * rights and limitations under the License.\r
- *\r
- * The Original Code is Rhino code, released\r
- * May 6, 1999.\r
- *\r
- * The Initial Developer of the Original Code is Netscape\r
- * Communications Corporation. Portions created by Netscape are\r
- * Copyright (C) 1997-2000 Netscape Communications Corporation. All\r
- * Rights Reserved.\r
- *\r
- * Contributor(s): \r
- * Patrick Beard\r
- * Norris Boyd\r
- * Igor Bukanov\r
- * Roger Lawrence\r
- *\r
- * Alternatively, the contents of this file may be used under the\r
- * terms of the GNU Public License (the "GPL"), in which case the\r
- * provisions of the GPL are applicable instead of those above.\r
- * If you wish to allow use of your version of this file only\r
- * under the terms of the GPL and not to allow others to use your\r
- * version of this file under the NPL, indicate your decision by\r
- * deleting the provisions above and replace them with the notice\r
- * and other provisions required by the GPL. If you do not delete\r
- * the provisions above, a recipient may use your version of this\r
- * file under either the NPL or the GPL.\r
- */\r
-\r
-package org.mozilla.javascript;\r
-\r
-import java.io.*;\r
-import java.util.Vector;\r
-import java.util.Enumeration;\r
-\r
-import org.mozilla.javascript.debug.*;\r
-\r
-public class Interpreter extends LabelTable {\r
- \r
- public static final boolean printICode = false;\r
- \r
- public IRFactory createIRFactory(TokenStream ts, \r
- ClassNameHelper nameHelper, Scriptable scope) \r
- {\r
- return new IRFactory(ts, scope);\r
- }\r
- \r
- public Node transform(Node tree, TokenStream ts, Scriptable scope) {\r
- return (new NodeTransformer()).transform(tree, null, ts, scope);\r
- }\r
- \r
- public Object compile(Context cx, Scriptable scope, Node tree, \r
- Object securityDomain,\r
- SecuritySupport securitySupport,\r
- ClassNameHelper nameHelper)\r
- throws IOException\r
- {\r
- version = cx.getLanguageVersion();\r
- itsData = new InterpreterData(0, 0, 0, securityDomain, \r
- cx.hasCompileFunctionsWithDynamicScope(), false);\r
- if (tree instanceof FunctionNode) {\r
- FunctionNode f = (FunctionNode) tree;\r
- InterpretedFunction result = \r
- generateFunctionICode(cx, scope, f, securityDomain);\r
- result.itsData.itsFunctionType = f.getFunctionType();\r
- createFunctionObject(result, scope);\r
- return result;\r
- }\r
- return generateScriptICode(cx, scope, tree, securityDomain);\r
- }\r
- \r
- private void generateICodeFromTree(Node tree, \r
- VariableTable varTable, \r
- boolean needsActivation,\r
- Object securityDomain)\r
- {\r
- int theICodeTop = 0;\r
- itsVariableTable = varTable;\r
- itsData.itsNeedsActivation = needsActivation;\r
- theICodeTop = generateICode(tree, theICodeTop);\r
- itsData.itsICodeTop = theICodeTop;\r
- if (itsEpilogLabel != -1)\r
- markLabel(itsEpilogLabel, theICodeTop);\r
- for (int i = 0; i < itsLabelTableTop; i++)\r
- itsLabelTable[i].fixGotos(itsData.itsICode); \r
- }\r
-\r
- private Object[] generateRegExpLiterals(Context cx,\r
- Scriptable scope,\r
- Vector regexps)\r
- {\r
- Object[] result = new Object[regexps.size()];\r
- RegExpProxy rep = cx.getRegExpProxy();\r
- for (int i = 0; i < regexps.size(); i++) {\r
- Node regexp = (Node) regexps.elementAt(i);\r
- Node left = regexp.getFirstChild();\r
- Node right = regexp.getLastChild();\r
- result[i] = rep.newRegExp(cx, scope, left.getString(), \r
- (left != right) ? right.getString() : null, false);\r
- regexp.putProp(Node.REGEXP_PROP, new Integer(i));\r
- }\r
- return result;\r
- }\r
- \r
- private InterpretedScript generateScriptICode(Context cx, \r
- Scriptable scope, \r
- Node tree,\r
- Object securityDomain)\r
- { \r
- itsSourceFile = (String) tree.getProp(Node.SOURCENAME_PROP);\r
- itsData.itsSourceFile = itsSourceFile;\r
- itsFunctionList = (Vector) tree.getProp(Node.FUNCTION_PROP); \r
- debugSource = (StringBuffer) tree.getProp(Node.DEBUGSOURCE_PROP);\r
- if (itsFunctionList != null)\r
- generateNestedFunctions(scope, cx, securityDomain);\r
- Object[] regExpLiterals = null;\r
- Vector regexps = (Vector)tree.getProp(Node.REGEXP_PROP);\r
- if (regexps != null) \r
- regExpLiterals = generateRegExpLiterals(cx, scope, regexps);\r
- \r
- VariableTable varTable = (VariableTable)tree.getProp(Node.VARS_PROP);\r
- // The default is not to generate debug information\r
- boolean activationNeeded = cx.isGeneratingDebugChanged() && \r
- cx.isGeneratingDebug();\r
- generateICodeFromTree(tree, varTable, activationNeeded, securityDomain);\r
- itsData.itsNestedFunctions = itsNestedFunctions;\r
- itsData.itsRegExpLiterals = regExpLiterals;\r
- if (printICode) dumpICode(itsData);\r
- \r
- String[] argNames = itsVariableTable.getAllNames();\r
- short argCount = (short)itsVariableTable.getParameterCount();\r
- InterpretedScript\r
- result = new InterpretedScript(cx, itsData, argNames, argCount);\r
- if (cx.debugger != null) {\r
- cx.debugger.handleCompilationDone(cx, result, debugSource);\r
- }\r
- return result;\r
- }\r
- \r
- private void generateNestedFunctions(Scriptable scope,\r
- Context cx, \r
- Object securityDomain)\r
- {\r
- itsNestedFunctions = new InterpretedFunction[itsFunctionList.size()];\r
- for (short i = 0; i < itsFunctionList.size(); i++) {\r
- FunctionNode def = (FunctionNode)itsFunctionList.elementAt(i);\r
- Interpreter jsi = new Interpreter();\r
- jsi.itsSourceFile = itsSourceFile;\r
- jsi.itsData = new InterpreterData(0, 0, 0, securityDomain,\r
- cx.hasCompileFunctionsWithDynamicScope(),\r
- def.getCheckThis());\r
- jsi.itsData.itsFunctionType = def.getFunctionType();\r
- jsi.itsInFunctionFlag = true;\r
- jsi.debugSource = debugSource;\r
- itsNestedFunctions[i] = jsi.generateFunctionICode(cx, scope, def, \r
- securityDomain);\r
- def.putProp(Node.FUNCTION_PROP, new Short(i));\r
- }\r
- } \r
- \r
- private InterpretedFunction \r
- generateFunctionICode(Context cx, Scriptable scope, \r
- FunctionNode theFunction, Object securityDomain)\r
- {\r
- itsFunctionList = (Vector) theFunction.getProp(Node.FUNCTION_PROP);\r
- if (itsFunctionList != null) \r
- generateNestedFunctions(scope, cx, securityDomain);\r
- Object[] regExpLiterals = null;\r
- Vector regexps = (Vector)theFunction.getProp(Node.REGEXP_PROP);\r
- if (regexps != null) \r
- regExpLiterals = generateRegExpLiterals(cx, scope, regexps);\r
-\r
- VariableTable varTable = theFunction.getVariableTable();\r
- boolean needsActivation = theFunction.requiresActivation() ||\r
- (cx.isGeneratingDebugChanged() && \r
- cx.isGeneratingDebug());\r
- generateICodeFromTree(theFunction.getLastChild(), \r
- varTable, needsActivation,\r
- securityDomain);\r
- \r
- itsData.itsName = theFunction.getFunctionName();\r
- itsData.itsSourceFile = (String) theFunction.getProp(\r
- Node.SOURCENAME_PROP);\r
- itsData.itsSource = (String)theFunction.getProp(Node.SOURCE_PROP);\r
- itsData.itsNestedFunctions = itsNestedFunctions;\r
- itsData.itsRegExpLiterals = regExpLiterals;\r
- if (printICode) dumpICode(itsData); \r
- \r
- String[] argNames = itsVariableTable.getAllNames();\r
- short argCount = (short)itsVariableTable.getParameterCount();\r
- InterpretedFunction \r
- result = new InterpretedFunction(cx, itsData, argNames, argCount); \r
- if (cx.debugger != null) {\r
- cx.debugger.handleCompilationDone(cx, result, debugSource);\r
- }\r
- return result;\r
- }\r
- \r
- boolean itsInFunctionFlag;\r
- Vector itsFunctionList;\r
- \r
- InterpreterData itsData;\r
- VariableTable itsVariableTable;\r
- int itsTryDepth = 0;\r
- int itsStackDepth = 0;\r
- int itsEpilogLabel = -1;\r
- String itsSourceFile;\r
- int itsLineNumber = 0;\r
- InterpretedFunction[] itsNestedFunctions = null;\r
- \r
- private int updateLineNumber(Node node, int iCodeTop)\r
- {\r
- Object datum = node.getDatum();\r
- if (datum == null || !(datum instanceof Number))\r
- return iCodeTop;\r
- short lineNumber = ((Number) datum).shortValue(); \r
- if (lineNumber != itsLineNumber) {\r
- itsLineNumber = lineNumber;\r
- if (itsData.itsLineNumberTable == null && \r
- Context.getCurrentContext().isGeneratingDebug())\r
- {\r
- itsData.itsLineNumberTable = new UintMap();\r
- }\r
- if (itsData.itsLineNumberTable != null) {\r
- itsData.itsLineNumberTable.put(lineNumber, iCodeTop);\r
- }\r
- iCodeTop = addByte((byte) TokenStream.LINE, iCodeTop);\r
- iCodeTop = addByte((byte)(lineNumber >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(lineNumber & 0xff), iCodeTop);\r
- \r
- }\r
- \r
- return iCodeTop;\r
- }\r
- \r
- private void badTree(Node node)\r
- {\r
- try {\r
- out = new PrintWriter(new FileOutputStream("icode.txt", true));\r
- out.println("Un-handled node : " + node.toString());\r
- out.close();\r
- }\r
- catch (IOException x) {}\r
- throw new RuntimeException("Un-handled node : "\r
- + node.toString());\r
- }\r
- \r
- private int generateICode(Node node, int iCodeTop) {\r
- int type = node.getType();\r
- Node child = node.getFirstChild();\r
- Node firstChild = child;\r
- switch (type) {\r
- \r
- case TokenStream.FUNCTION : { \r
- iCodeTop = addByte((byte) TokenStream.CLOSURE, iCodeTop);\r
- Node fn = (Node) node.getProp(Node.FUNCTION_PROP);\r
- Short index = (Short) fn.getProp(Node.FUNCTION_PROP);\r
- iCodeTop = addByte((byte)(index.shortValue() >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(index.shortValue() & 0xff), iCodeTop); \r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- break;\r
-\r
- case TokenStream.SCRIPT :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- while (child != null) {\r
- if (child.getType() != TokenStream.FUNCTION) \r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- }\r
- break;\r
-\r
- case TokenStream.CASE :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- child = child.getNextSibling();\r
- while (child != null) {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- }\r
- break;\r
- \r
- case TokenStream.LABEL :\r
- case TokenStream.WITH :\r
- case TokenStream.LOOP :\r
- case TokenStream.DEFAULT :\r
- case TokenStream.BLOCK :\r
- case TokenStream.VOID :\r
- case TokenStream.NOP :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- while (child != null) {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- }\r
- break;\r
-\r
- case TokenStream.COMMA :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
- itsStackDepth--;\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- break;\r
- \r
- case TokenStream.SWITCH : {\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- iCodeTop = generateICode(child, iCodeTop);\r
- int theLocalSlot = itsData.itsMaxLocals++;\r
- iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);\r
- iCodeTop = addByte((byte)theLocalSlot, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
- itsStackDepth--;\r
- /*\r
- reminder - below we construct new GOTO nodes that aren't\r
- linked into the tree just for the purpose of having a node\r
- to pass to the addGoto routine. (Parallels codegen here).\r
- Seems unnecessary. \r
- */\r
- Vector cases = (Vector) node.getProp(Node.CASES_PROP);\r
- for (int i = 0; i < cases.size(); i++) {\r
- Node thisCase = (Node)cases.elementAt(i);\r
- Node first = thisCase.getFirstChild();\r
- // the case expression is the firstmost child\r
- // the rest will be generated when the case\r
- // statements are encountered as siblings of\r
- // the switch statement.\r
- iCodeTop = generateICode(first, iCodeTop); \r
- iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- iCodeTop = addByte((byte) theLocalSlot, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.SHEQ, iCodeTop);\r
- Node target = new Node(TokenStream.TARGET);\r
- thisCase.addChildAfter(target, first);\r
- Node branch = new Node(TokenStream.IFEQ);\r
- branch.putProp(Node.TARGET_PROP, target);\r
- iCodeTop = addGoto(branch, TokenStream.IFEQ, \r
- iCodeTop);\r
- itsStackDepth--;\r
- }\r
-\r
- Node defaultNode = (Node) node.getProp(Node.DEFAULT_PROP);\r
- if (defaultNode != null) {\r
- Node defaultTarget = new Node(TokenStream.TARGET);\r
- defaultNode.getFirstChild().addChildToFront(defaultTarget);\r
- Node branch = new Node(TokenStream.GOTO);\r
- branch.putProp(Node.TARGET_PROP, defaultTarget);\r
- iCodeTop = addGoto(branch, TokenStream.GOTO,\r
- iCodeTop); \r
- }\r
-\r
- Node breakTarget = (Node) node.getProp(Node.BREAK_PROP);\r
- Node branch = new Node(TokenStream.GOTO);\r
- branch.putProp(Node.TARGET_PROP, breakTarget);\r
- iCodeTop = addGoto(branch, TokenStream.GOTO, \r
- iCodeTop); \r
- }\r
- break;\r
- \r
- case TokenStream.TARGET : { \r
- Object lblObect = node.getProp(Node.LABEL_PROP);\r
- if (lblObect == null) {\r
- int label = markLabel(acquireLabel(), iCodeTop);\r
- node.putProp(Node.LABEL_PROP, new Integer(label));\r
- }\r
- else {\r
- int label = ((Integer)lblObect).intValue();\r
- markLabel(label, iCodeTop);\r
- }\r
- // if this target has a FINALLY_PROP, it is a JSR target\r
- // and so has a PC value on the top of the stack\r
- if (node.getProp(Node.FINALLY_PROP) != null) {\r
- itsStackDepth = 1;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- }\r
- break;\r
- \r
- case TokenStream.EQOP :\r
- case TokenStream.RELOP : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- int op = node.getInt();\r
- if (version == Context.VERSION_1_2) {\r
- if (op == TokenStream.EQ)\r
- op = TokenStream.SHEQ;\r
- else if (op == TokenStream.NE)\r
- op = TokenStream.SHNE;\r
- }\r
- iCodeTop = addByte((byte) op, iCodeTop);\r
- itsStackDepth--;\r
- }\r
- break;\r
- \r
- case TokenStream.NEW :\r
- case TokenStream.CALL : {\r
- if (itsSourceFile != null && (itsData.itsSourceFile == null || ! itsSourceFile.equals(itsData.itsSourceFile))) \r
- itsData.itsSourceFile = itsSourceFile;\r
- iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);\r
- \r
- int childCount = 0;\r
- short nameIndex = -1;\r
- while (child != null) {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- if (nameIndex == -1) {\r
- if (child.getType() == TokenStream.NAME)\r
- nameIndex = (short)(itsData.itsStringTableIndex - 1);\r
- else if (child.getType() == TokenStream.GETPROP)\r
- nameIndex = (short)(itsData.itsStringTableIndex - 1);\r
- }\r
- child = child.getNextSibling();\r
- childCount++;\r
- }\r
- if (node.getProp(Node.SPECIALCALL_PROP) != null) {\r
- // embed line number and source filename\r
- iCodeTop = addByte((byte) TokenStream.CALLSPECIAL, iCodeTop);\r
- iCodeTop = addByte((byte)(itsLineNumber >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(itsLineNumber & 0xff), iCodeTop);\r
- iCodeTop = addString(itsSourceFile, iCodeTop);\r
- } else {\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- iCodeTop = addByte((byte)(nameIndex >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(nameIndex & 0xFF), iCodeTop);\r
- }\r
- \r
- itsStackDepth -= (childCount - 1); // always a result value\r
- // subtract from child count to account for [thisObj &] fun\r
- if (type == TokenStream.NEW)\r
- childCount -= 1;\r
- else\r
- childCount -= 2;\r
- iCodeTop = addByte((byte)(childCount >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(childCount & 0xff), iCodeTop);\r
- if (childCount > itsData.itsMaxArgs)\r
- itsData.itsMaxArgs = childCount;\r
- \r
- iCodeTop = addByte((byte)TokenStream.SOURCEFILE, iCodeTop);\r
- }\r
- break;\r
- \r
- case TokenStream.NEWLOCAL :\r
- case TokenStream.NEWTEMP : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);\r
- iCodeTop = addLocalRef(node, iCodeTop);\r
- }\r
- break; \r
- \r
- case TokenStream.USELOCAL : {\r
- if (node.getProp(Node.TARGET_PROP) != null) \r
- iCodeTop = addByte((byte) TokenStream.RETSUB, iCodeTop);\r
- else {\r
- iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- Node temp = (Node) node.getProp(Node.LOCAL_PROP);\r
- iCodeTop = addLocalRef(temp, iCodeTop);\r
- }\r
- break; \r
-\r
- case TokenStream.USETEMP : {\r
- iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);\r
- Node temp = (Node) node.getProp(Node.TEMP_PROP);\r
- iCodeTop = addLocalRef(temp, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- break; \r
- \r
- case TokenStream.IFEQ :\r
- case TokenStream.IFNE :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- itsStackDepth--; // after the conditional GOTO, really\r
- // fall thru...\r
- case TokenStream.GOTO :\r
- iCodeTop = addGoto(node, (byte) type, iCodeTop);\r
- break;\r
-\r
- case TokenStream.JSR : {\r
- /*\r
- mark the target with a FINALLY_PROP to indicate\r
- that it will have an incoming PC value on the top\r
- of the stack.\r
- !!! \r
- This only works if the target follows the JSR\r
- in the tree.\r
- !!!\r
- */\r
- Node target = (Node)(node.getProp(Node.TARGET_PROP));\r
- target.putProp(Node.FINALLY_PROP, node);\r
- iCodeTop = addGoto(node, TokenStream.GOSUB, iCodeTop);\r
- }\r
- break;\r
- \r
- case TokenStream.AND : { \r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop); \r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- int falseTarget = acquireLabel();\r
- iCodeTop = addGoto(falseTarget, TokenStream.IFNE, \r
- iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
- itsStackDepth--;\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- markLabel(falseTarget, iCodeTop);\r
- }\r
- break;\r
-\r
- case TokenStream.OR : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.DUP, iCodeTop); \r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- int trueTarget = acquireLabel();\r
- iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,\r
- iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop); \r
- itsStackDepth--;\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- markLabel(trueTarget, iCodeTop);\r
- }\r
- break;\r
-\r
- case TokenStream.GETPROP : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);\r
- if (s != null) {\r
- if (s.equals("__proto__"))\r
- iCodeTop = addByte((byte) TokenStream.GETPROTO, iCodeTop);\r
- else\r
- if (s.equals("__parent__"))\r
- iCodeTop = addByte((byte) TokenStream.GETSCOPEPARENT, iCodeTop);\r
- else\r
- badTree(node);\r
- }\r
- else {\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);\r
- itsStackDepth--;\r
- }\r
- }\r
- break;\r
-\r
- case TokenStream.DELPROP : \r
- case TokenStream.BITAND : \r
- case TokenStream.BITOR :\r
- case TokenStream.BITXOR :\r
- case TokenStream.LSH :\r
- case TokenStream.RSH :\r
- case TokenStream.URSH :\r
- case TokenStream.ADD :\r
- case TokenStream.SUB :\r
- case TokenStream.MOD :\r
- case TokenStream.DIV :\r
- case TokenStream.MUL :\r
- case TokenStream.GETELEM :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
-\r
- case TokenStream.CONVERT : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- Object toType = node.getProp(Node.TYPE_PROP);\r
- if (toType == ScriptRuntime.NumberClass)\r
- iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);\r
- else\r
- badTree(node);\r
- }\r
- break;\r
-\r
- case TokenStream.UNARYOP :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- switch (node.getInt()) {\r
- case TokenStream.VOID :\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);\r
- break;\r
- case TokenStream.NOT : {\r
- int trueTarget = acquireLabel();\r
- int beyond = acquireLabel();\r
- iCodeTop = addGoto(trueTarget, TokenStream.IFEQ,\r
- iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.TRUE, iCodeTop);\r
- iCodeTop = addGoto(beyond, TokenStream.GOTO, \r
- iCodeTop);\r
- markLabel(trueTarget, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.FALSE, iCodeTop);\r
- markLabel(beyond, iCodeTop);\r
- }\r
- break;\r
- case TokenStream.BITNOT :\r
- iCodeTop = addByte((byte) TokenStream.BITNOT, iCodeTop);\r
- break;\r
- case TokenStream.TYPEOF :\r
- iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);\r
- break;\r
- case TokenStream.SUB :\r
- iCodeTop = addByte((byte) TokenStream.NEG, iCodeTop);\r
- break;\r
- case TokenStream.ADD :\r
- iCodeTop = addByte((byte) TokenStream.POS, iCodeTop);\r
- break;\r
- default:\r
- badTree(node);\r
- break;\r
- }\r
- break;\r
-\r
- case TokenStream.SETPROP : {\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- String s = (String) node.getProp(Node.SPECIAL_PROP_PROP);\r
- if (s != null) {\r
- if (s.equals("__proto__"))\r
- iCodeTop = addByte((byte) TokenStream.SETPROTO, iCodeTop);\r
- else\r
- if (s.equals("__parent__"))\r
- iCodeTop = addByte((byte) TokenStream.SETPARENT, iCodeTop);\r
- else\r
- badTree(node);\r
- }\r
- else {\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.SETPROP, iCodeTop);\r
- itsStackDepth -= 2;\r
- }\r
- }\r
- break; \r
-\r
- case TokenStream.SETELEM :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- itsStackDepth -= 2;\r
- break;\r
-\r
- case TokenStream.SETNAME :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.SETNAME, iCodeTop); \r
- iCodeTop = addString(firstChild.getString(), iCodeTop);\r
- itsStackDepth--;\r
- break;\r
- \r
- case TokenStream.TYPEOF : {\r
- String name = node.getString();\r
- int index = -1;\r
- // use typeofname if an activation frame exists\r
- // since the vars all exist there instead of in jregs\r
- if (itsInFunctionFlag && !itsData.itsNeedsActivation)\r
- index = itsVariableTable.getOrdinal(name);\r
- if (index == -1) { \r
- iCodeTop = addByte((byte) TokenStream.TYPEOFNAME, iCodeTop);\r
- iCodeTop = addString(name, iCodeTop);\r
- }\r
- else {\r
- iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);\r
- iCodeTop = addByte((byte) index, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.TYPEOF, iCodeTop);\r
- }\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- break;\r
-\r
- case TokenStream.PARENT :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.GETPARENT, iCodeTop);\r
- break;\r
-\r
- case TokenStream.GETBASE :\r
- case TokenStream.BINDNAME :\r
- case TokenStream.NAME :\r
- case TokenStream.STRING :\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- iCodeTop = addString(node.getString(), iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- break;\r
-\r
- case TokenStream.INC :\r
- case TokenStream.DEC : {\r
- int childType = child.getType();\r
- switch (childType) {\r
- case TokenStream.GETVAR : {\r
- String name = child.getString();\r
- if (itsData.itsNeedsActivation) {\r
- iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);\r
- iCodeTop = addString(name, iCodeTop);\r
- itsStackDepth += 2;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- iCodeTop = addByte((byte)\r
- (type == TokenStream.INC\r
- ? TokenStream.PROPINC \r
- : TokenStream.PROPDEC),\r
- iCodeTop);\r
- itsStackDepth--; \r
- }\r
- else {\r
- iCodeTop = addByte((byte)\r
- (type == TokenStream.INC\r
- ? TokenStream.VARINC\r
- : TokenStream.VARDEC),\r
- iCodeTop);\r
- int i = itsVariableTable.getOrdinal(name);\r
- iCodeTop = addByte((byte)i, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- }\r
- break;\r
- case TokenStream.GETPROP :\r
- case TokenStream.GETELEM : {\r
- Node getPropChild = child.getFirstChild();\r
- iCodeTop = generateICode(getPropChild,\r
- iCodeTop);\r
- getPropChild = getPropChild.getNextSibling();\r
- iCodeTop = generateICode(getPropChild,\r
- iCodeTop);\r
- if (childType == TokenStream.GETPROP)\r
- iCodeTop = addByte((byte)\r
- (type == TokenStream.INC\r
- ? TokenStream.PROPINC \r
- : TokenStream.PROPDEC),\r
- iCodeTop);\r
- else \r
- iCodeTop = addByte((byte)\r
- (type == TokenStream.INC\r
- ? TokenStream.ELEMINC \r
- : TokenStream.ELEMDEC),\r
- iCodeTop);\r
- itsStackDepth--; \r
- }\r
- break;\r
- default : {\r
- iCodeTop = addByte((byte)\r
- (type == TokenStream.INC \r
- ? TokenStream.NAMEINC \r
- : TokenStream.NAMEDEC),\r
- iCodeTop);\r
- iCodeTop = addString(child.getString(), \r
- iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- break;\r
- }\r
- }\r
- break;\r
-\r
- case TokenStream.NUMBER : {\r
- double num = node.getDouble();\r
- if (num == 0.0) {\r
- iCodeTop = addByte((byte) TokenStream.ZERO, iCodeTop);\r
- }\r
- else if (num == 1.0) {\r
- iCodeTop = addByte((byte) TokenStream.ONE, iCodeTop);\r
- }\r
- else {\r
- iCodeTop = addByte((byte) TokenStream.NUMBER, iCodeTop);\r
- iCodeTop = addNumber(num, iCodeTop);\r
- }\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- break;\r
- }\r
-\r
- case TokenStream.POP :\r
- case TokenStream.POPV :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- case TokenStream.ENTERWITH :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
-\r
- case TokenStream.GETTHIS :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- break;\r
- \r
- case TokenStream.NEWSCOPE :\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- break;\r
-\r
- case TokenStream.LEAVEWITH :\r
- iCodeTop = addByte((byte) type, iCodeTop);\r
- break;\r
-\r
- case TokenStream.TRY : {\r
- itsTryDepth++;\r
- if (itsTryDepth > itsData.itsMaxTryDepth)\r
- itsData.itsMaxTryDepth = itsTryDepth;\r
- Node catchTarget = (Node)node.getProp(Node.TARGET_PROP);\r
- Node finallyTarget = (Node)node.getProp(Node.FINALLY_PROP);\r
- if (catchTarget == null) {\r
- iCodeTop = addByte((byte) TokenStream.TRY, iCodeTop);\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- }\r
- else\r
- iCodeTop = \r
- addGoto(node, TokenStream.TRY, iCodeTop);\r
- int finallyHandler = 0;\r
- if (finallyTarget != null) {\r
- finallyHandler = acquireLabel();\r
- int theLabel = finallyHandler & 0x7FFFFFFF;\r
- itsLabelTable[theLabel].addFixup(iCodeTop);\r
- }\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- \r
- Node lastChild = null;\r
- /*\r
- when we encounter the child of the catchTarget, we\r
- set the stackDepth to 1 to account for the incoming\r
- exception object.\r
- */\r
- boolean insertedEndTry = false;\r
- while (child != null) {\r
- if (catchTarget != null && lastChild == catchTarget) {\r
- itsStackDepth = 1;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- /*\r
- When the following child is the catchTarget\r
- (or the finallyTarget if there are no catches),\r
- the current child is the goto at the end of\r
- the try statemets, we need to emit the endtry\r
- before that goto.\r
- */\r
- Node nextSibling = child.getNextSibling();\r
- if (!insertedEndTry && nextSibling != null &&\r
- (nextSibling == catchTarget ||\r
- nextSibling == finallyTarget))\r
- {\r
- iCodeTop = addByte((byte) TokenStream.ENDTRY,\r
- iCodeTop);\r
- insertedEndTry = true;\r
- }\r
- iCodeTop = generateICode(child, iCodeTop);\r
- lastChild = child;\r
- child = child.getNextSibling();\r
- }\r
- itsStackDepth = 0;\r
- if (finallyTarget != null) {\r
- // normal flow goes around the finally handler stublet\r
- int skippy = acquireLabel();\r
- iCodeTop = \r
- addGoto(skippy, TokenStream.GOTO, iCodeTop);\r
- // on entry the stack will have the exception object\r
- markLabel(finallyHandler, iCodeTop);\r
- itsStackDepth = 1;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- int theLocalSlot = itsData.itsMaxLocals++;\r
- iCodeTop = addByte((byte) TokenStream.NEWTEMP, iCodeTop);\r
- iCodeTop = addByte((byte)theLocalSlot, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.POP, iCodeTop);\r
- Integer finallyLabel \r
- = (Integer)(finallyTarget.getProp(Node.LABEL_PROP));\r
- iCodeTop = addGoto(finallyLabel.intValue(), \r
- TokenStream.GOSUB, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.USETEMP, iCodeTop);\r
- iCodeTop = addByte((byte)theLocalSlot, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.JTHROW, iCodeTop);\r
- itsStackDepth = 0;\r
- markLabel(skippy, iCodeTop);\r
- }\r
- itsTryDepth--;\r
- }\r
- break;\r
- \r
- case TokenStream.THROW :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.THROW, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
- \r
- case TokenStream.ASSERT:\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- if (child != null) \r
- iCodeTop = generateICode(child, iCodeTop);\r
- else {\r
- iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- iCodeTop = addGoto(node, TokenStream.ASSERT, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
- \r
- case TokenStream.RETURN :\r
- iCodeTop = updateLineNumber(node, iCodeTop);\r
- if (child != null) \r
- iCodeTop = generateICode(child, iCodeTop);\r
- else {\r
- iCodeTop = addByte((byte) TokenStream.UNDEFINED, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- iCodeTop = addGoto(node, TokenStream.RETURN, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
- \r
- case TokenStream.GETVAR : {\r
- String name = node.getString();\r
- if (itsData.itsNeedsActivation) {\r
- // SETVAR handled this by turning into a SETPROP, but\r
- // we can't do that to a GETVAR without manufacturing\r
- // bogus children. Instead we use a special op to\r
- // push the current scope.\r
- iCodeTop = addByte((byte) TokenStream.SCOPE, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.STRING, iCodeTop);\r
- iCodeTop = addString(name, iCodeTop);\r
- itsStackDepth += 2;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- iCodeTop = addByte((byte) TokenStream.GETPROP, iCodeTop);\r
- itsStackDepth--;\r
- }\r
- else {\r
- int index = itsVariableTable.getOrdinal(name);\r
- iCodeTop = addByte((byte) TokenStream.GETVAR, iCodeTop);\r
- iCodeTop = addByte((byte)index, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- }\r
- break;\r
- \r
- case TokenStream.SETVAR : {\r
- if (itsData.itsNeedsActivation) {\r
- child.setType(TokenStream.BINDNAME);\r
- node.setType(TokenStream.SETNAME);\r
- iCodeTop = generateICode(node, iCodeTop);\r
- }\r
- else {\r
- String name = child.getString();\r
- child = child.getNextSibling();\r
- iCodeTop = generateICode(child, iCodeTop);\r
- int index = itsVariableTable.getOrdinal(name);\r
- iCodeTop = addByte((byte) TokenStream.SETVAR, iCodeTop);\r
- iCodeTop = addByte((byte)index, iCodeTop);\r
- }\r
- }\r
- break;\r
- \r
- case TokenStream.PRIMARY:\r
- iCodeTop = addByte((byte) node.getInt(), iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- break;\r
-\r
- case TokenStream.ENUMINIT :\r
- iCodeTop = generateICode(child, iCodeTop);\r
- iCodeTop = addByte((byte) TokenStream.ENUMINIT, iCodeTop);\r
- iCodeTop = addLocalRef(node, iCodeTop);\r
- itsStackDepth--;\r
- break;\r
- \r
- case TokenStream.ENUMNEXT : {\r
- iCodeTop = addByte((byte) TokenStream.ENUMNEXT, iCodeTop);\r
- Node init = (Node)node.getProp(Node.ENUM_PROP);\r
- iCodeTop = addLocalRef(init, iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- } \r
- break;\r
- \r
- case TokenStream.ENUMDONE :\r
- // could release the local here??\r
- break;\r
- \r
- case TokenStream.OBJECT : {\r
- Node regexp = (Node) node.getProp(Node.REGEXP_PROP);\r
- int index = ((Integer)(regexp.getProp(\r
- Node.REGEXP_PROP))).intValue();\r
- iCodeTop = addByte((byte) TokenStream.OBJECT, iCodeTop);\r
- iCodeTop = addByte((byte)(index >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(index & 0xff), iCodeTop);\r
- itsStackDepth++;\r
- if (itsStackDepth > itsData.itsMaxStack)\r
- itsData.itsMaxStack = itsStackDepth;\r
- }\r
- break;\r
- \r
- default : \r
- badTree(node);\r
- break;\r
- }\r
- return iCodeTop;\r
- }\r
- \r
- private int addLocalRef(Node node, int iCodeTop)\r
- {\r
- int theLocalSlot;\r
- Integer localProp = (Integer)node.getProp(Node.LOCAL_PROP);\r
- if (localProp == null) {\r
- theLocalSlot = itsData.itsMaxLocals++;\r
- node.putProp(Node.LOCAL_PROP, new Integer(theLocalSlot));\r
- }\r
- else\r
- theLocalSlot = localProp.intValue();\r
- iCodeTop = addByte((byte)theLocalSlot, iCodeTop);\r
- if (theLocalSlot >= itsData.itsMaxLocals)\r
- itsData.itsMaxLocals = theLocalSlot + 1;\r
- return iCodeTop; \r
- }\r
- \r
- private int addGoto(Node node, int gotoOp, int iCodeTop)\r
- {\r
- int targetLabel;\r
- if (node.getType() == TokenStream.RETURN || node.getType() == TokenStream.ASSERT) {\r
- if (itsEpilogLabel == -1)\r
- itsEpilogLabel = acquireLabel();\r
- targetLabel = itsEpilogLabel;\r
- }\r
- else {\r
- Node target = (Node)(node.getProp(Node.TARGET_PROP));\r
- Object lblObect = target.getProp(Node.LABEL_PROP);\r
- if (lblObect == null) {\r
- targetLabel = acquireLabel();\r
- target.putProp(Node.LABEL_PROP, new Integer(targetLabel));\r
- }\r
- else\r
- targetLabel = ((Integer)lblObect).intValue();\r
- }\r
- iCodeTop = addGoto(targetLabel, (byte) gotoOp, iCodeTop);\r
- return iCodeTop;\r
- }\r
- \r
- private int addGoto(int targetLabel, int gotoOp, int iCodeTop)\r
- {\r
- int gotoPC = iCodeTop;\r
- iCodeTop = addByte((byte) gotoOp, iCodeTop);\r
- int theLabel = targetLabel & 0x7FFFFFFF;\r
- int targetPC = itsLabelTable[theLabel].getPC();\r
- if (targetPC != -1) {\r
- short offset = (short)(targetPC - gotoPC);\r
- iCodeTop = addByte((byte)(offset >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)offset, iCodeTop);\r
- }\r
- else {\r
- itsLabelTable[theLabel].addFixup(gotoPC + 1);\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- iCodeTop = addByte((byte)0, iCodeTop);\r
- }\r
- return iCodeTop;\r
- }\r
- \r
- private final int addByte(byte b, int iCodeTop) {\r
- if (itsData.itsICode.length == iCodeTop) {\r
- byte[] ba = new byte[iCodeTop * 2];\r
- System.arraycopy(itsData.itsICode, 0, ba, 0, iCodeTop);\r
- itsData.itsICode = ba;\r
- }\r
- itsData.itsICode[iCodeTop++] = b;\r
- return iCodeTop;\r
- }\r
- \r
- private final int addString(String str, int iCodeTop)\r
- {\r
- int index = itsData.itsStringTableIndex;\r
- if (itsData.itsStringTable.length == index) {\r
- String[] sa = new String[index * 2];\r
- System.arraycopy(itsData.itsStringTable, 0, sa, 0, index);\r
- itsData.itsStringTable = sa;\r
- }\r
- itsData.itsStringTable[index] = str;\r
- itsData.itsStringTableIndex = index + 1;\r
-\r
- iCodeTop = addByte((byte)(index >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);\r
- return iCodeTop;\r
- }\r
- \r
- private final int addNumber(double num, int iCodeTop)\r
- {\r
- int index = itsData.itsNumberTableIndex;\r
- if (itsData.itsNumberTable.length == index) {\r
- double[] na = new double[index * 2];\r
- System.arraycopy(itsData.itsNumberTable, 0, na, 0, index);\r
- itsData.itsNumberTable = na;\r
- }\r
- itsData.itsNumberTable[index] = num;\r
- itsData.itsNumberTableIndex = index + 1;\r
-\r
- iCodeTop = addByte((byte)(index >> 8), iCodeTop);\r
- iCodeTop = addByte((byte)(index & 0xFF), iCodeTop);\r
- return iCodeTop;\r
- }\r
- \r
- private static String getString(String[] theStringTable, byte[] iCode, \r
- int pc)\r
- {\r
- int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
- return theStringTable[index];\r
- }\r
- \r
- private static double getNumber(double[] theNumberTable, byte[] iCode, \r
- int pc)\r
- {\r
- int index = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
- return theNumberTable[index];\r
- }\r
- \r
- private static int getTarget(byte[] iCode, int pc)\r
- {\r
- int displacement = (iCode[pc] << 8) + (iCode[pc + 1] & 0xFF);\r
- return pc - 1 + displacement;\r
- }\r
- \r
- static PrintWriter out;\r
- static {\r
- if (printICode) {\r
- try {\r
- out = new PrintWriter(new FileOutputStream("icode.txt"));\r
- out.close();\r
- }\r
- catch (IOException x) {\r
- }\r
- }\r
- } \r
- \r
- private static void dumpICode(InterpreterData theData) {\r
- if (printICode) {\r
- try {\r
- int iCodeLength = theData.itsICodeTop;\r
- byte iCode[] = theData.itsICode;\r
- \r
- out = new PrintWriter(new FileOutputStream("icode.txt", true));\r
- out.println("ICode dump, for " + theData.itsName + ", length = " + iCodeLength);\r
- out.println("MaxStack = " + theData.itsMaxStack);\r
- \r
- for (int pc = 0; pc < iCodeLength; ) {\r
- out.print("[" + pc + "] ");\r
- switch ((int)(iCode[pc] & 0xff)) {\r
- case TokenStream.SCOPE :\r
- case TokenStream.GETPROTO :\r
- case TokenStream.GETPARENT :\r
- case TokenStream.GETSCOPEPARENT :\r
- case TokenStream.SETPROTO :\r
- case TokenStream.SETPARENT :\r
- case TokenStream.DELPROP :\r
- case TokenStream.TYPEOF :\r
- case TokenStream.NEWSCOPE :\r
- case TokenStream.ENTERWITH :\r
- case TokenStream.LEAVEWITH :\r
- case TokenStream.ENDTRY :\r
- case TokenStream.THROW :\r
- case TokenStream.JTHROW :\r
- case TokenStream.GETTHIS :\r
- case TokenStream.SETELEM :\r
- case TokenStream.GETELEM :\r
- case TokenStream.SETPROP :\r
- case TokenStream.GETPROP :\r
- case TokenStream.PROPINC :\r
- case TokenStream.PROPDEC :\r
- case TokenStream.ELEMINC :\r
- case TokenStream.ELEMDEC :\r
- case TokenStream.BITNOT : \r
- case TokenStream.BITAND : \r
- case TokenStream.BITOR :\r
- case TokenStream.BITXOR :\r
- case TokenStream.LSH :\r
- case TokenStream.RSH :\r
- case TokenStream.URSH :\r
- case TokenStream.NEG :\r
- case TokenStream.POS :\r
- case TokenStream.SUB :\r
- case TokenStream.MUL :\r
- case TokenStream.DIV :\r
- case TokenStream.MOD :\r
- case TokenStream.ADD :\r
- case TokenStream.POPV :\r
- case TokenStream.POP :\r
- case TokenStream.DUP :\r
- case TokenStream.LT :\r
- case TokenStream.GT :\r
- case TokenStream.LE :\r
- case TokenStream.GE :\r
- case TokenStream.IN :\r
- case TokenStream.INSTANCEOF :\r
- case TokenStream.EQ :\r
- case TokenStream.NE :\r
- case TokenStream.SHEQ :\r
- case TokenStream.SHNE :\r
- case TokenStream.ZERO :\r
- case TokenStream.ONE :\r
- case TokenStream.NULL :\r
- case TokenStream.THIS :\r
- case TokenStream.THISFN :\r
- case TokenStream.FALSE :\r
- case TokenStream.TRUE :\r
- case TokenStream.UNDEFINED :\r
- case TokenStream.SOURCEFILE : \r
- out.println(TokenStream.tokenToName(iCode[pc] & 0xff));\r
- break;\r
- case TokenStream.GOSUB :\r
- case TokenStream.RETURN :\r
- case TokenStream.GOTO :\r
- case TokenStream.IFEQ :\r
- case TokenStream.IFNE : {\r
- int newPC = getTarget(iCode, pc + 1); \r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " " + newPC);\r
- pc += 2;\r
- }\r
- break;\r
- case TokenStream.TRY : {\r
- int newPC1 = getTarget(iCode, pc + 1); \r
- int newPC2 = getTarget(iCode, pc + 3); \r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " " + newPC1 +\r
- " " + newPC2);\r
- pc += 4;\r
- }\r
- break;\r
- case TokenStream.RETSUB : \r
- case TokenStream.ENUMINIT :\r
- case TokenStream.ENUMNEXT :\r
- case TokenStream.VARINC :\r
- case TokenStream.VARDEC :\r
- case TokenStream.GETVAR :\r
- case TokenStream.SETVAR :\r
- case TokenStream.NEWTEMP :\r
- case TokenStream.USETEMP : {\r
- int slot = (iCode[pc + 1] & 0xFF);\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " " + slot);\r
- pc++;\r
- }\r
- break;\r
- case TokenStream.CALLSPECIAL : {\r
- int line = (iCode[pc + 1] << 8) \r
- | (iCode[pc + 2] & 0xFF);\r
- String name = getString(theData.itsStringTable,\r
- iCode, pc + 3);\r
- int count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " " + count + " " + line + " " + name);\r
- pc += 6;\r
- }\r
- break;\r
- case TokenStream.OBJECT :\r
- case TokenStream.CLOSURE :\r
- case TokenStream.NEW :\r
- case TokenStream.CALL : {\r
- int count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " " + count + " \"" + \r
- getString(theData.itsStringTable, iCode, \r
- pc + 1) + "\"");\r
- pc += 5;\r
- }\r
- break;\r
- case TokenStream.NUMBER :\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) + \r
- " " + getNumber(theData.itsNumberTable,\r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.TYPEOFNAME :\r
- case TokenStream.GETBASE :\r
- case TokenStream.BINDNAME :\r
- case TokenStream.SETNAME :\r
- case TokenStream.NAME :\r
- case TokenStream.NAMEINC :\r
- case TokenStream.NAMEDEC :\r
- case TokenStream.STRING :\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) +\r
- " \"" +\r
- getString(theData.itsStringTable, iCode, pc + 1) +\r
- "\"");\r
- pc += 2;\r
- break;\r
- case TokenStream.LINE : {\r
- int line = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);\r
- out.println(\r
- TokenStream.tokenToName(iCode[pc] & 0xff) + " : " + line);\r
- pc += 2;\r
- }\r
- break;\r
- default :\r
- out.close();\r
- throw new RuntimeException("Unknown icode : "\r
- + (iCode[pc] & 0xff) + " @ pc : " + pc);\r
- }\r
- pc++;\r
- }\r
- out.close();\r
- }\r
- catch (IOException x) {}\r
- }\r
- }\r
- \r
- private static void createFunctionObject(InterpretedFunction fn, \r
- Scriptable scope)\r
- {\r
- fn.setPrototype(ScriptableObject.getClassPrototype(scope, "Function"));\r
- fn.setParentScope(scope);\r
- InterpreterData id = fn.itsData;\r
- if (id.itsName.length() == 0)\r
- return;\r
- if ((id.itsFunctionType == FunctionNode.FUNCTION_STATEMENT &&\r
- fn.itsClosure == null) ||\r
- (id.itsFunctionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT &&\r
- fn.itsClosure != null))\r
- {\r
- ScriptRuntime.setProp(scope, fn.itsData.itsName, fn, scope);\r
- }\r
- }\r
- \r
- public static Object interpret(Context cx, Scriptable scope, \r
- Scriptable thisObj, Object[] args, \r
- NativeFunction fnOrScript,\r
- InterpreterData theData)\r
- throws JavaScriptException\r
- {\r
- int i;\r
- Object lhs;\r
-\r
- final int maxStack = theData.itsMaxStack;\r
- final int maxVars = (fnOrScript.argNames == null) \r
- ? 0 : fnOrScript.argNames.length;\r
- final int maxLocals = theData.itsMaxLocals;\r
- final int maxTryDepth = theData.itsMaxTryDepth;\r
- \r
- final int VAR_SHFT = maxStack; \r
- final int LOCAL_SHFT = VAR_SHFT + maxVars; \r
- final int TRY_SCOPE_SHFT = LOCAL_SHFT + maxLocals;\r
-\r
-// stack[0 <= i < VAR_SHFT]: stack data\r
-// stack[VAR_SHFT <= i < LOCAL_SHFT]: variables\r
-// stack[LOCAL_SHFT <= i < TRY_SCOPE_SHFT]: used for newtemp/usetemp\r
-// stack[TRY_SCOPE_SHFT <= i]: try scopes\r
-// when 0 <= i < LOCAL_SHFT and stack[x] == DBL_MRK, \r
-// sDbl[i] gives the number value\r
-\r
- final Object DBL_MRK = Interpreter.DBL_MRK;\r
- \r
- Object[] stack = new Object[TRY_SCOPE_SHFT + maxTryDepth];\r
- double[] sDbl = new double[TRY_SCOPE_SHFT];\r
- int stackTop = -1;\r
- byte[] iCode = theData.itsICode; \r
- int pc = 0;\r
- int iCodeLength = theData.itsICodeTop;\r
- \r
- final Scriptable undefined = Undefined.instance;\r
- if (maxVars != 0) {\r
- int definedArgs = fnOrScript.argCount;\r
- if (definedArgs != 0) {\r
- if (definedArgs > args.length) { definedArgs = args.length; }\r
- for (i = 0; i != definedArgs; ++i) {\r
- stack[VAR_SHFT + i] = args[i]; \r
- }\r
- }\r
- for (i = definedArgs; i != maxVars; ++i) {\r
- stack[VAR_SHFT + i] = undefined;\r
- }\r
- }\r
- \r
- if (theData.itsNestedFunctions != null) {\r
- for (i = 0; i < theData.itsNestedFunctions.length; i++)\r
- createFunctionObject(theData.itsNestedFunctions[i], scope);\r
- } \r
-\r
- Object id;\r
- Object rhs, val;\r
- double valDbl;\r
- boolean valBln;\r
-\r
- int count;\r
- int slot;\r
- \r
- String name = null;\r
- \r
- Object[] outArgs;\r
-\r
- int lIntValue;\r
- long lLongValue;\r
- double lDbl;\r
- int rIntValue;\r
- double rDbl;\r
- \r
- int[] catchStack = null;\r
- int tryStackTop = 0;\r
- InterpreterFrame frame = null;\r
- \r
- if (cx.debugger != null) {\r
- frame = new InterpreterFrame(scope, theData, fnOrScript);\r
- cx.pushFrame(frame);\r
- }\r
- \r
- if (maxTryDepth != 0) {\r
- // catchStack[2 * i]: starting pc of catch block\r
- // catchStack[2 * i + 1]: starting pc of finally block\r
- catchStack = new int[maxTryDepth * 2];\r
- }\r
- \r
- /* Save the security domain. Must restore upon normal exit. \r
- * If we exit the interpreter loop by throwing an exception,\r
- * set cx.interpreterSecurityDomain to null, and require the\r
- * catching function to restore it.\r
- */\r
- Object savedSecurityDomain = cx.interpreterSecurityDomain;\r
- cx.interpreterSecurityDomain = theData.securityDomain;\r
- Object result = undefined;\r
- \r
- int pcPrevBranch = pc;\r
- final int instructionThreshold = cx.instructionThreshold;\r
- // During function call this will be set to -1 so catch can properly\r
- // adjust it\r
- int instructionCount = cx.instructionCount;\r
- // arbitrary number to add to instructionCount when calling \r
- // other functions\r
- final int INVOCATION_COST = 100;\r
- \r
- while (pc < iCodeLength) {\r
- try {\r
- switch (iCode[pc] & 0xff) {\r
- case TokenStream.ENDTRY :\r
- tryStackTop--;\r
- break;\r
- case TokenStream.TRY :\r
- i = getTarget(iCode, pc + 1);\r
- if (i == pc) i = 0;\r
- catchStack[tryStackTop * 2] = i;\r
- i = getTarget(iCode, pc + 3);\r
- if (i == (pc + 2)) i = 0;\r
- catchStack[tryStackTop * 2 + 1] = i;\r
- stack[TRY_SCOPE_SHFT + tryStackTop] = scope;\r
- ++tryStackTop;\r
- pc += 4;\r
- break;\r
- case TokenStream.GE :\r
- --stackTop;\r
- rhs = stack[stackTop + 1]; \r
- lhs = stack[stackTop];\r
- if (rhs == DBL_MRK || lhs == DBL_MRK) {\r
- rDbl = stack_double(stack, sDbl, stackTop + 1);\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- valBln = (rDbl == rDbl && lDbl == lDbl \r
- && rDbl <= lDbl);\r
- }\r
- else {\r
- valBln = (1 == ScriptRuntime.cmp_LE(rhs, lhs));\r
- }\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.LE :\r
- --stackTop;\r
- rhs = stack[stackTop + 1]; \r
- lhs = stack[stackTop];\r
- if (rhs == DBL_MRK || lhs == DBL_MRK) {\r
- rDbl = stack_double(stack, sDbl, stackTop + 1);\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- valBln = (rDbl == rDbl && lDbl == lDbl \r
- && lDbl <= rDbl);\r
- }\r
- else {\r
- valBln = (1 == ScriptRuntime.cmp_LE(lhs, rhs));\r
- }\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.GT :\r
- --stackTop;\r
- rhs = stack[stackTop + 1]; \r
- lhs = stack[stackTop];\r
- if (rhs == DBL_MRK || lhs == DBL_MRK) {\r
- rDbl = stack_double(stack, sDbl, stackTop + 1);\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- valBln = (rDbl == rDbl && lDbl == lDbl \r
- && rDbl < lDbl);\r
- }\r
- else {\r
- valBln = (1 == ScriptRuntime.cmp_LT(rhs, lhs));\r
- }\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.LT :\r
- --stackTop;\r
- rhs = stack[stackTop + 1]; \r
- lhs = stack[stackTop];\r
- if (rhs == DBL_MRK || lhs == DBL_MRK) {\r
- rDbl = stack_double(stack, sDbl, stackTop + 1);\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- valBln = (rDbl == rDbl && lDbl == lDbl \r
- && lDbl < rDbl);\r
- }\r
- else {\r
- valBln = (1 == ScriptRuntime.cmp_LT(lhs, rhs));\r
- }\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.IN :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- valBln = ScriptRuntime.in(lhs, rhs, scope);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.INSTANCEOF :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- valBln = ScriptRuntime.instanceOf(scope, lhs, rhs);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.EQ :\r
- --stackTop;\r
- valBln = do_eq(stack, sDbl, stackTop);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.NE :\r
- --stackTop;\r
- valBln = !do_eq(stack, sDbl, stackTop);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.SHEQ :\r
- --stackTop;\r
- valBln = do_sheq(stack, sDbl, stackTop);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.SHNE :\r
- --stackTop;\r
- valBln = !do_sheq(stack, sDbl, stackTop);\r
- stack[stackTop] = valBln ? Boolean.TRUE : Boolean.FALSE;\r
- break;\r
- case TokenStream.IFNE :\r
- val = stack[stackTop];\r
- if (val != DBL_MRK) {\r
- valBln = !ScriptRuntime.toBoolean(val);\r
- }\r
- else {\r
- valDbl = sDbl[stackTop];\r
- valBln = !(valDbl == valDbl && valDbl != 0.0);\r
- }\r
- --stackTop;\r
- if (valBln) {\r
- if (instructionThreshold != 0) {\r
- instructionCount += pc + 3 - pcPrevBranch;\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount\r
- (instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
- continue;\r
- }\r
- pc += 2;\r
- break;\r
- case TokenStream.IFEQ :\r
- val = stack[stackTop];\r
- if (val != DBL_MRK) {\r
- valBln = ScriptRuntime.toBoolean(val);\r
- }\r
- else {\r
- valDbl = sDbl[stackTop];\r
- valBln = (valDbl == valDbl && valDbl != 0.0);\r
- }\r
- --stackTop;\r
- if (valBln) {\r
- if (instructionThreshold != 0) {\r
- instructionCount += pc + 3 - pcPrevBranch;\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount\r
- (instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
- continue;\r
- }\r
- pc += 2;\r
- break;\r
- case TokenStream.GOTO :\r
- if (instructionThreshold != 0) {\r
- instructionCount += pc + 3 - pcPrevBranch;\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount(instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc = getTarget(iCode, pc + 1);\r
- continue;\r
- case TokenStream.GOSUB :\r
- sDbl[++stackTop] = pc + 3;\r
- if (instructionThreshold != 0) {\r
- instructionCount += pc + 3 - pcPrevBranch;\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount(instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc = getTarget(iCode, pc + 1); continue;\r
- case TokenStream.RETSUB :\r
- slot = (iCode[pc + 1] & 0xFF);\r
- if (instructionThreshold != 0) {\r
- instructionCount += pc + 2 - pcPrevBranch;\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount(instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc = (int)sDbl[LOCAL_SHFT + slot];\r
- continue;\r
- case TokenStream.POP :\r
- stackTop--;\r
- break;\r
- case TokenStream.DUP :\r
- stack[stackTop + 1] = stack[stackTop];\r
- sDbl[stackTop + 1] = sDbl[stackTop];\r
- stackTop++;\r
- break;\r
- case TokenStream.POPV :\r
- result = stack[stackTop]; \r
- if (result == DBL_MRK) \r
- result = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- break;\r
- case TokenStream.RETURN :\r
- result = stack[stackTop]; \r
- if (result == DBL_MRK) \r
- result = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- pc = getTarget(iCode, pc + 1);\r
- break;\r
- case TokenStream.ASSERT :\r
- val = stack[stackTop];\r
- if (val != DBL_MRK) {\r
- valBln = ScriptRuntime.toBoolean(val);\r
- } else {\r
- valDbl = sDbl[stackTop];\r
- valBln = (valDbl == valDbl && valDbl != 0.0);\r
- }\r
- --stackTop;\r
- if (!valBln) {\r
- throw new Error("assertion failed");\r
- //System.exit(-1);\r
- }\r
- pc += 2;\r
- break;\r
- case TokenStream.BITNOT :\r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = ~rIntValue;\r
- break;\r
- case TokenStream.BITAND : \r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- --stackTop;\r
- lIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lIntValue & rIntValue;\r
- break;\r
- case TokenStream.BITOR :\r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- --stackTop;\r
- lIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lIntValue | rIntValue;\r
- break;\r
- case TokenStream.BITXOR :\r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- --stackTop;\r
- lIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lIntValue ^ rIntValue;\r
- break;\r
- case TokenStream.LSH :\r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- --stackTop;\r
- lIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lIntValue << rIntValue;\r
- break;\r
- case TokenStream.RSH :\r
- rIntValue = stack_int32(stack, sDbl, stackTop);\r
- --stackTop;\r
- lIntValue = stack_int32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lIntValue >> rIntValue;\r
- break;\r
- case TokenStream.URSH :\r
- rIntValue = stack_int32(stack, sDbl, stackTop) & 0x1F;\r
- --stackTop;\r
- lLongValue = stack_uint32(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lLongValue >>> rIntValue;\r
- break;\r
- case TokenStream.ADD :\r
- --stackTop;\r
- do_add(stack, sDbl, stackTop);\r
- break;\r
- case TokenStream.SUB :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- --stackTop;\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lDbl - rDbl;\r
- break;\r
- case TokenStream.NEG :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = -rDbl;\r
- break;\r
- case TokenStream.POS :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = rDbl;\r
- break;\r
- case TokenStream.MUL :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- --stackTop;\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lDbl * rDbl;\r
- break;\r
- case TokenStream.DIV :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- --stackTop;\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- // Detect the divide by zero or let Java do it ?\r
- sDbl[stackTop] = lDbl / rDbl;\r
- break;\r
- case TokenStream.MOD :\r
- rDbl = stack_double(stack, sDbl, stackTop);\r
- --stackTop;\r
- lDbl = stack_double(stack, sDbl, stackTop);\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = lDbl % rDbl;\r
- break;\r
- case TokenStream.BINDNAME :\r
- stack[++stackTop] = \r
- ScriptRuntime.bind(scope, \r
- getString(theData.itsStringTable, \r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.GETBASE :\r
- stack[++stackTop] =\r
- ScriptRuntime.getBase(scope, \r
- getString(theData.itsStringTable,\r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.SETNAME :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- // what about class cast exception here ?\r
- stack[stackTop] = ScriptRuntime.setName\r
- ((Scriptable)lhs, rhs, scope, \r
- getString(theData.itsStringTable, iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.DELPROP :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.delete(lhs, rhs);\r
- break;\r
- case TokenStream.GETPROP :\r
- name = (String)stack[stackTop];\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.getProp(lhs, name, scope);\r
- break;\r
- case TokenStream.SETPROP :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- name = (String)stack[stackTop];\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.setProp(lhs, name, rhs, scope);\r
- break;\r
- case TokenStream.GETELEM :\r
- id = stack[stackTop]; \r
- if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.getElem(lhs, id, scope);\r
- break;\r
- case TokenStream.SETELEM :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- id = stack[stackTop]; \r
- if (id == DBL_MRK) id = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.setElem(lhs, id, rhs, scope);\r
- break;\r
- case TokenStream.PROPINC :\r
- name = (String)stack[stackTop];\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.postIncrement(lhs, name, scope);\r
- break;\r
- case TokenStream.PROPDEC :\r
- name = (String)stack[stackTop];\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.postDecrement(lhs, name, scope);\r
- break;\r
- case TokenStream.ELEMINC :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.postIncrementElem(lhs, rhs, scope);\r
- break;\r
- case TokenStream.ELEMDEC :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.postDecrementElem(lhs, rhs, scope);\r
- break;\r
- case TokenStream.GETTHIS :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] \r
- = ScriptRuntime.getThis((Scriptable)lhs);\r
- break;\r
- case TokenStream.NEWTEMP :\r
- slot = (iCode[++pc] & 0xFF);\r
- stack[LOCAL_SHFT + slot] = stack[stackTop];\r
- sDbl[LOCAL_SHFT + slot] = sDbl[stackTop];\r
- break;\r
- case TokenStream.USETEMP :\r
- slot = (iCode[++pc] & 0xFF);\r
- ++stackTop;\r
- stack[stackTop] = stack[LOCAL_SHFT + slot];\r
- sDbl[stackTop] = sDbl[LOCAL_SHFT + slot];\r
- break;\r
- case TokenStream.CALLSPECIAL :\r
- if (instructionThreshold != 0) {\r
- instructionCount += INVOCATION_COST;\r
- cx.instructionCount = instructionCount;\r
- instructionCount = -1;\r
- }\r
- int lineNum = (iCode[pc + 1] << 8) \r
- | (iCode[pc + 2] & 0xFF); \r
- name = getString(theData.itsStringTable, iCode, pc + 3);\r
- count = (iCode[pc + 5] << 8) | (iCode[pc + 6] & 0xFF);\r
- outArgs = new Object[count];\r
- for (i = count - 1; i >= 0; i--) {\r
- val = stack[stackTop]; \r
- if (val == DBL_MRK) \r
- val = doubleWrap(sDbl[stackTop]);\r
- outArgs[i] = val;\r
- --stackTop;\r
- }\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.callSpecial(\r
- cx, lhs, rhs, outArgs, \r
- thisObj, scope, name, lineNum);\r
- pc += 6;\r
- instructionCount = cx.instructionCount;\r
- break;\r
- case TokenStream.CALL :\r
- if (instructionThreshold != 0) {\r
- instructionCount += INVOCATION_COST;\r
- cx.instructionCount = instructionCount;\r
- instructionCount = -1;\r
- }\r
- cx.instructionCount = instructionCount;\r
- count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);\r
- outArgs = new Object[count];\r
- for (i = count - 1; i >= 0; i--) {\r
- val = stack[stackTop]; \r
- if (val == DBL_MRK) \r
- val = doubleWrap(sDbl[stackTop]);\r
- outArgs[i] = val;\r
- --stackTop;\r
- }\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- if (lhs == undefined) {\r
- lhs = getString(theData.itsStringTable, iCode, \r
- pc + 1);\r
- }\r
- Scriptable calleeScope = scope;\r
- if (theData.itsNeedsActivation) {\r
- calleeScope = ScriptableObject.\r
- getTopLevelScope(scope);\r
- }\r
- stack[stackTop] = ScriptRuntime.call(cx, lhs, rhs, \r
- outArgs, \r
- calleeScope);\r
- pc += 4; instructionCount = cx.instructionCount;\r
- break;\r
- case TokenStream.NEW :\r
- if (instructionThreshold != 0) {\r
- instructionCount += INVOCATION_COST;\r
- cx.instructionCount = instructionCount;\r
- instructionCount = -1;\r
- }\r
- count = (iCode[pc + 3] << 8) | (iCode[pc + 4] & 0xFF);\r
- outArgs = new Object[count];\r
- for (i = count - 1; i >= 0; i--) {\r
- val = stack[stackTop]; \r
- if (val == DBL_MRK) \r
- val = doubleWrap(sDbl[stackTop]);\r
- outArgs[i] = val;\r
- --stackTop;\r
- }\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- if (lhs == undefined && \r
- (iCode[pc+1] << 8) + (iCode[pc+2] & 0xFF) != -1) \r
- {\r
- // special code for better error message for call \r
- // to undefined\r
- lhs = getString(theData.itsStringTable, iCode, \r
- pc + 1);\r
- }\r
- stack[stackTop] = ScriptRuntime.newObject(cx, lhs, \r
- outArgs, \r
- scope);\r
- pc += 4; instructionCount = cx.instructionCount;\r
- break;\r
- case TokenStream.TYPEOF :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.typeof(lhs);\r
- break;\r
- case TokenStream.TYPEOFNAME :\r
- name = getString(theData.itsStringTable, iCode, pc + 1);\r
- stack[++stackTop] \r
- = ScriptRuntime.typeofName(scope, name);\r
- pc += 2;\r
- break;\r
- case TokenStream.STRING :\r
- stack[++stackTop] = getString(theData.itsStringTable,\r
- iCode, pc + 1);\r
- pc += 2;\r
- break;\r
- case TokenStream.NUMBER :\r
- ++stackTop;\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = getNumber(theData.itsNumberTable,\r
- iCode, pc + 1);\r
- pc += 2;\r
- break;\r
- case TokenStream.NAME :\r
- stack[++stackTop] = ScriptRuntime.name(scope,\r
- getString(theData.itsStringTable,\r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.NAMEINC :\r
- stack[++stackTop] = ScriptRuntime.postIncrement(scope,\r
- getString(theData.itsStringTable,\r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.NAMEDEC :\r
- stack[++stackTop] = ScriptRuntime.postDecrement(scope,\r
- getString(theData.itsStringTable,\r
- iCode, pc + 1));\r
- pc += 2;\r
- break;\r
- case TokenStream.SETVAR :\r
- slot = (iCode[++pc] & 0xFF);\r
- stack[VAR_SHFT + slot] = stack[stackTop];\r
- sDbl[VAR_SHFT + slot] = sDbl[stackTop];\r
- break;\r
- case TokenStream.GETVAR :\r
- slot = (iCode[++pc] & 0xFF);\r
- ++stackTop;\r
- stack[stackTop] = stack[VAR_SHFT + slot];\r
- sDbl[stackTop] = sDbl[VAR_SHFT + slot];\r
- break;\r
- case TokenStream.VARINC :\r
- slot = (iCode[++pc] & 0xFF);\r
- ++stackTop;\r
- stack[stackTop] = stack[VAR_SHFT + slot];\r
- sDbl[stackTop] = sDbl[VAR_SHFT + slot];\r
- stack[VAR_SHFT + slot] = DBL_MRK;\r
- sDbl[VAR_SHFT + slot] \r
- = stack_double(stack, sDbl, stackTop) + 1.0;\r
- break;\r
- case TokenStream.VARDEC :\r
- slot = (iCode[++pc] & 0xFF);\r
- ++stackTop;\r
- stack[stackTop] = stack[VAR_SHFT + slot];\r
- sDbl[stackTop] = sDbl[VAR_SHFT + slot];\r
- stack[VAR_SHFT + slot] = DBL_MRK;\r
- sDbl[VAR_SHFT + slot] \r
- = stack_double(stack, sDbl, stackTop) - 1.0;\r
- break;\r
- case TokenStream.ZERO :\r
- ++stackTop;\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = 0;\r
- break;\r
- case TokenStream.ONE :\r
- ++stackTop;\r
- stack[stackTop] = DBL_MRK;\r
- sDbl[stackTop] = 1;\r
- break;\r
- case TokenStream.NULL :\r
- stack[++stackTop] = null;\r
- break;\r
- case TokenStream.THIS :\r
- stack[++stackTop] = thisObj;\r
- break;\r
- case TokenStream.THISFN :\r
- stack[++stackTop] = fnOrScript;\r
- break;\r
- case TokenStream.FALSE :\r
- stack[++stackTop] = Boolean.FALSE;\r
- break;\r
- case TokenStream.TRUE :\r
- stack[++stackTop] = Boolean.TRUE;\r
- break;\r
- case TokenStream.UNDEFINED :\r
- stack[++stackTop] = Undefined.instance;\r
- break;\r
- case TokenStream.THROW :\r
- result = stack[stackTop];\r
- if (result == DBL_MRK) \r
- result = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- throw new JavaScriptException(result);\r
- case TokenStream.JTHROW :\r
- result = stack[stackTop];\r
- // No need to check for DBL_MRK: result is Exception\r
- --stackTop;\r
- if (result instanceof JavaScriptException)\r
- throw (JavaScriptException)result;\r
- else\r
- throw (RuntimeException)result;\r
- case TokenStream.ENTERWITH :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- scope = ScriptRuntime.enterWith(lhs, scope);\r
- break;\r
- case TokenStream.LEAVEWITH :\r
- scope = ScriptRuntime.leaveWith(scope);\r
- break;\r
- case TokenStream.NEWSCOPE :\r
- stack[++stackTop] = ScriptRuntime.newScope();\r
- break;\r
- case TokenStream.ENUMINIT :\r
- slot = (iCode[++pc] & 0xFF);\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- stack[LOCAL_SHFT + slot] \r
- = ScriptRuntime.initEnum(lhs, scope);\r
- break;\r
- case TokenStream.ENUMNEXT :\r
- slot = (iCode[++pc] & 0xFF);\r
- val = stack[LOCAL_SHFT + slot]; \r
- ++stackTop;\r
- stack[stackTop] = ScriptRuntime.\r
- nextEnum((Enumeration)val);\r
- break;\r
- case TokenStream.GETPROTO :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.getProto(lhs, scope);\r
- break;\r
- case TokenStream.GETPARENT :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.getParent(lhs);\r
- break;\r
- case TokenStream.GETSCOPEPARENT :\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop] = ScriptRuntime.getParent(lhs, scope);\r
- break;\r
- case TokenStream.SETPROTO :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop]\r
- = ScriptRuntime.setProto(lhs, rhs, scope);\r
- break;\r
- case TokenStream.SETPARENT :\r
- rhs = stack[stackTop]; \r
- if (rhs == DBL_MRK) rhs = doubleWrap(sDbl[stackTop]);\r
- --stackTop;\r
- lhs = stack[stackTop]; \r
- if (lhs == DBL_MRK) lhs = doubleWrap(sDbl[stackTop]);\r
- stack[stackTop]\r
- = ScriptRuntime.setParent(lhs, rhs, scope);\r
- break;\r
- case TokenStream.SCOPE :\r
- stack[++stackTop] = scope;\r
- break;\r
- case TokenStream.CLOSURE :\r
- i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF);\r
- stack[++stackTop] \r
- = new InterpretedFunction(\r
- theData.itsNestedFunctions[i],\r
- scope, cx);\r
- createFunctionObject(\r
- (InterpretedFunction)stack[stackTop], scope);\r
- pc += 2;\r
- break;\r
- case TokenStream.OBJECT :\r
- i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF); \r
- stack[++stackTop] = theData.itsRegExpLiterals[i];\r
- pc += 2;\r
- break;\r
- case TokenStream.SOURCEFILE : \r
- cx.interpreterSourceFile = theData.itsSourceFile;\r
- break;\r
- case TokenStream.LINE : \r
- case TokenStream.BREAKPOINT :\r
- i = (iCode[pc + 1] << 8) | (iCode[pc + 2] & 0xFF); \r
- cx.interpreterLine = i;\r
- if (frame != null)\r
- frame.setLineNumber(i);\r
- if ((iCode[pc] & 0xff) == TokenStream.BREAKPOINT ||\r
- cx.inLineStepMode) \r
- {\r
- cx.getDebuggableEngine().\r
- getDebugger().handleBreakpointHit(cx);\r
- }\r
- pc += 2;\r
- break;\r
- default :\r
- dumpICode(theData);\r
- throw new RuntimeException("Unknown icode : "\r
- + (iCode[pc] & 0xff) + " @ pc : " + pc);\r
- }\r
- pc++;\r
- }\r
- catch (Throwable ex) {\r
- cx.interpreterSecurityDomain = null;\r
- \r
- if (instructionThreshold != 0) {\r
- if (instructionCount < 0) {\r
- // throw during function call\r
- instructionCount = cx.instructionCount;\r
- }\r
- else {\r
- // throw during any other operation\r
- instructionCount += pc - pcPrevBranch;\r
- cx.instructionCount = instructionCount;\r
- }\r
- }\r
-\r
- final int SCRIPT_THROW = 0, ECMA = 1, RUNTIME = 2, OTHER = 3;\r
-\r
- int exType;\r
- Object errObj; // Object seen by catch\r
- if (ex instanceof JavaScriptException) {\r
- errObj = ScriptRuntime.\r
- unwrapJavaScriptException((JavaScriptException)ex);\r
- exType = SCRIPT_THROW;\r
- }\r
- else if (ex instanceof EcmaError) {\r
- // an offical ECMA error object,\r
- errObj = ((EcmaError)ex).getErrorObject();\r
- exType = ECMA;\r
- }\r
- else if (ex instanceof RuntimeException) {\r
- errObj = ex;\r
- exType = RUNTIME;\r
- }\r
- else {\r
- errObj = ex; // Error instance\r
- exType = OTHER;\r
- }\r
-\r
- if (exType != OTHER && cx.debugger != null) {\r
- cx.debugger.handleExceptionThrown(cx, errObj);\r
- }\r
-\r
- boolean rethrow = true;\r
- if (exType != OTHER && tryStackTop > 0) {\r
- --tryStackTop;\r
- if (exType == SCRIPT_THROW || exType == ECMA) {\r
- // Check for catch only for \r
- // JavaScriptException and EcmaError\r
- pc = catchStack[tryStackTop * 2];\r
- if (pc != 0) {\r
- // Has catch block\r
- rethrow = false;\r
- }\r
- }\r
- if (rethrow) {\r
- pc = catchStack[tryStackTop * 2 + 1];\r
- if (pc != 0) {\r
- // has finally block\r
- rethrow = false;\r
- errObj = ex;\r
- }\r
- }\r
- }\r
-\r
- if (rethrow) {\r
- if (frame != null)\r
- cx.popFrame();\r
- \r
- if (exType == SCRIPT_THROW)\r
- throw (JavaScriptException)ex;\r
- if (exType == ECMA || exType == RUNTIME) \r
- throw (RuntimeException)ex;\r
- throw (Error)ex;\r
- }\r
- \r
- // We caught an exception,\r
-\r
- // Notify instruction observer if necessary\r
- // and point pcPrevBranch to start of catch/finally block\r
- if (instructionThreshold != 0) {\r
- if (instructionCount > instructionThreshold) {\r
- // Note: this can throw Error \r
- cx.observeInstructionCount(instructionCount);\r
- instructionCount = 0;\r
- }\r
- }\r
- pcPrevBranch = pc;\r
-\r
- // prepare stack and restore this function's security domain.\r
- scope = (Scriptable)stack[TRY_SCOPE_SHFT + tryStackTop];\r
- stackTop = 0;\r
- stack[0] = errObj;\r
- cx.interpreterSecurityDomain = theData.securityDomain;\r
- }\r
- }\r
- cx.interpreterSecurityDomain = savedSecurityDomain;\r
- if (frame != null)\r
- cx.popFrame();\r
-\r
- if (instructionThreshold != 0) {\r
- if (instructionCount > instructionThreshold) {\r
- cx.observeInstructionCount(instructionCount);\r
- instructionCount = 0;\r
- }\r
- cx.instructionCount = instructionCount;\r
- }\r
-\r
- return result; \r
- }\r
- \r
- private static Object doubleWrap(double x) {\r
- return new Double(x);\r
- }\r
-\r
- private static int stack_int32(Object[] stack, double[] stackDbl, int i) {\r
- Object x = stack[i];\r
- return (x != DBL_MRK)\r
- ? ScriptRuntime.toInt32(x)\r
- : ScriptRuntime.toInt32(stackDbl[i]);\r
- }\r
- \r
- private static long stack_uint32(Object[] stack, double[] stackDbl, int i) {\r
- Object x = stack[i];\r
- return (x != DBL_MRK)\r
- ? ScriptRuntime.toUint32(x)\r
- : ScriptRuntime.toUint32(stackDbl[i]);\r
- }\r
- \r
- private static double stack_double(Object[] stack, double[] stackDbl, \r
- int i) \r
- {\r
- Object x = stack[i];\r
- return (x != DBL_MRK) ? ScriptRuntime.toNumber(x) : stackDbl[i];\r
- }\r
- \r
- private static void do_add(Object[] stack, double[] stackDbl, int stackTop)\r
- {\r
- Object rhs = stack[stackTop + 1]; \r
- Object lhs = stack[stackTop];\r
- if (rhs == DBL_MRK) {\r
- double rDbl = stackDbl[stackTop + 1];\r
- if (lhs == DBL_MRK) {\r
- stackDbl[stackTop] += rDbl;\r
- }\r
- else {\r
- do_add(lhs, rDbl, stack, stackDbl, stackTop, true);\r
- }\r
- }\r
- else if (lhs == DBL_MRK) {\r
- do_add(rhs, stackDbl[stackTop], stack, stackDbl, stackTop, false);\r
- }\r
- else {\r
- if (lhs instanceof Scriptable)\r
- lhs = ((Scriptable) lhs).getDefaultValue(null);\r
- if (rhs instanceof Scriptable)\r
- rhs = ((Scriptable) rhs).getDefaultValue(null);\r
- if (lhs instanceof String || rhs instanceof String) {\r
- stack[stackTop] = ScriptRuntime.toString(lhs)\r
- + ScriptRuntime.toString(rhs);\r
- }\r
- else {\r
- double lDbl = (lhs instanceof Number)\r
- ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);\r
- double rDbl = (rhs instanceof Number)\r
- ? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);\r
- stack[stackTop] = DBL_MRK;\r
- stackDbl[stackTop] = lDbl + rDbl;\r
- }\r
- }\r
- }\r
- \r
- // x + y when x is Number, see \r
- private static void do_add\r
- (Object lhs, double rDbl, \r
- Object[] stack, double[] stackDbl, int stackTop, \r
- boolean left_right_order) \r
- {\r
- if (lhs instanceof Scriptable) {\r
- if (lhs == Undefined.instance) { lhs = ScriptRuntime.NaNobj; }\r
- lhs = ((Scriptable)lhs).getDefaultValue(null);\r
- }\r
- if (lhs instanceof String) {\r
- if (left_right_order) {\r
- stack[stackTop] = (String)lhs + ScriptRuntime.toString(rDbl);\r
- }\r
- else {\r
- stack[stackTop] = ScriptRuntime.toString(rDbl) + (String)lhs;\r
- }\r
- }\r
- else {\r
- double lDbl = (lhs instanceof Number) \r
- ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);\r
- stack[stackTop] = DBL_MRK;\r
- stackDbl[stackTop] = lDbl + rDbl;\r
- }\r
- }\r
-\r
-\r
- \r
- private static boolean do_eq(Object[] stack, double[] stackDbl,\r
- int stackTop)\r
- {\r
- boolean result;\r
- Object rhs = stack[stackTop + 1]; \r
- Object lhs = stack[stackTop];\r
- if (rhs == DBL_MRK) {\r
- if (lhs == DBL_MRK) {\r
- result = (stackDbl[stackTop] == stackDbl[stackTop + 1]);\r
- }\r
- else {\r
- result = do_eq(stackDbl[stackTop + 1], lhs);\r
- }\r
- }\r
- else {\r
- if (lhs == DBL_MRK) {\r
- result = do_eq(stackDbl[stackTop], rhs);\r
- }\r
- else {\r
- result = ScriptRuntime.eq(lhs, rhs);\r
- }\r
- }\r
- return result;\r
- }\r
- \r
-// Optimized version of ScriptRuntime.eq if x is a Number \r
- private static boolean do_eq(double x, Object y) {\r
- for (;;) {\r
- if (y instanceof Number) {\r
- return x == ((Number) y).doubleValue();\r
- }\r
- if (y instanceof String) {\r
- return x == ScriptRuntime.toNumber((String)y);\r
- }\r
- if (y instanceof Boolean) {\r
- return x == (((Boolean)y).booleanValue() ? 1 : 0);\r
- }\r
- if (y instanceof Scriptable) {\r
- if (y == Undefined.instance) { return false; }\r
- y = ScriptRuntime.toPrimitive(y);\r
- continue;\r
- }\r
- return false;\r
- }\r
- }\r
-\r
- private static boolean do_sheq(Object[] stack, double[] stackDbl,\r
- int stackTop)\r
- {\r
- boolean result;\r
- Object rhs = stack[stackTop + 1]; \r
- Object lhs = stack[stackTop];\r
- if (rhs == DBL_MRK) {\r
- double rDbl = stackDbl[stackTop + 1];\r
- if (lhs == DBL_MRK) {\r
- result = (stackDbl[stackTop] == rDbl);\r
- }\r
- else {\r
- result = (lhs instanceof Number);\r
- if (result) {\r
- result = (((Number)lhs).doubleValue() == rDbl);\r
- }\r
- }\r
- }\r
- else if (rhs instanceof Number) {\r
- double rDbl = ((Number)rhs).doubleValue();\r
- if (lhs == DBL_MRK) {\r
- result = (stackDbl[stackTop] == rDbl);\r
- }\r
- else {\r
- result = (lhs instanceof Number);\r
- if (result) {\r
- result = (((Number)lhs).doubleValue() == rDbl);\r
- }\r
- }\r
- }\r
- else {\r
- result = ScriptRuntime.shallowEq(lhs, rhs);\r
- }\r
- return result;\r
- }\r
- \r
- private int version;\r
- private boolean inLineStepMode;\r
- private StringBuffer debugSource;\r
-\r
- private static final Object DBL_MRK = new Object();\r
-}\r