diff options
Diffstat (limited to 'infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer')
8 files changed, 0 insertions, 7097 deletions
diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java deleted file mode 100644 index bd56714..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Block.java +++ /dev/null @@ -1,615 +0,0 @@ -/* ***** 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-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Igor Bukanov - * Roger Lawrence - * - * 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.optimizer; - -import org.mozilla.javascript.*; - -import java.util.Hashtable; - -import java.io.PrintWriter; -import java.io.StringWriter; - -class Block -{ - - private static class FatBlock - { - - private static Block[] reduceToArray(ObjToIntMap map) - { - Block[] result = null; - if (!map.isEmpty()) { - result = new Block[map.size()]; - int i = 0; - ObjToIntMap.Iterator iter = map.newIterator(); - for (iter.start(); !iter.done(); iter.next()) { - FatBlock fb = (FatBlock)(iter.getKey()); - result[i++] = fb.realBlock; - } - } - return result; - } - - void addSuccessor(FatBlock b) { successors.put(b, 0); } - void addPredecessor(FatBlock b) { predecessors.put(b, 0); } - - Block[] getSuccessors() { return reduceToArray(successors); } - Block[] getPredecessors() { return reduceToArray(predecessors); } - - // all the Blocks that come immediately after this - private ObjToIntMap successors = new ObjToIntMap(); - // all the Blocks that come immediately before this - private ObjToIntMap predecessors = new ObjToIntMap(); - - Block realBlock; - } - - Block(int startNodeIndex, int endNodeIndex) - { - itsStartNodeIndex = startNodeIndex; - itsEndNodeIndex = endNodeIndex; - } - - static void runFlowAnalyzes(OptFunctionNode fn, Node[] statementNodes) - { - int paramCount = fn.fnode.getParamCount(); - int varCount = fn.fnode.getParamAndVarCount(); - int[] varTypes = new int[varCount]; - // If the variable is a parameter, it could have any type. - for (int i = 0; i != paramCount; ++i) { - varTypes[i] = Optimizer.AnyType; - } - // If the variable is from a "var" statement, its typeEvent will be set - // when we see the setVar node. - for (int i = paramCount; i != varCount; ++i) { - varTypes[i] = Optimizer.NoType; - } - - Block[] theBlocks = buildBlocks(statementNodes); - - if (DEBUG) { - ++debug_blockCount; - System.out.println("-------------------"+fn.fnode.getFunctionName()+" "+debug_blockCount+"--------"); - System.out.println(toString(theBlocks, statementNodes)); - } - - reachingDefDataFlow(fn, statementNodes, theBlocks, varTypes); - typeFlow(fn, statementNodes, theBlocks, varTypes); - - if (DEBUG) { - for (int i = 0; i < theBlocks.length; i++) { - System.out.println("For block " + theBlocks[i].itsBlockID); - theBlocks[i].printLiveOnEntrySet(fn); - } - System.out.println("Variable Table, size = " + varCount); - for (int i = 0; i != varCount; i++) { - System.out.println("["+i+"] type: "+varTypes[i]); - } - } - - for (int i = paramCount; i != varCount; i++) { - if (varTypes[i] == Optimizer.NumberType) { - fn.setIsNumberVar(i); - } - } - - } - - private static Block[] buildBlocks(Node[] statementNodes) - { - // a mapping from each target node to the block it begins - Hashtable theTargetBlocks = new Hashtable(); - ObjArray theBlocks = new ObjArray(); - - // there's a block that starts at index 0 - int beginNodeIndex = 0; - - for (int i = 0; i < statementNodes.length; i++) { - switch (statementNodes[i].getType()) { - case Token.TARGET : - { - if (i != beginNodeIndex) { - FatBlock fb = newFatBlock(beginNodeIndex, i - 1); - if (statementNodes[beginNodeIndex].getType() - == Token.TARGET) - theTargetBlocks.put(statementNodes[beginNodeIndex], fb); - theBlocks.add(fb); - // start the next block at this node - beginNodeIndex = i; - } - } - break; - case Token.IFNE : - case Token.IFEQ : - case Token.GOTO : - { - FatBlock fb = newFatBlock(beginNodeIndex, i); - if (statementNodes[beginNodeIndex].getType() - == Token.TARGET) - theTargetBlocks.put(statementNodes[beginNodeIndex], fb); - theBlocks.add(fb); - // start the next block at the next node - beginNodeIndex = i + 1; - } - break; - } - } - - if (beginNodeIndex != statementNodes.length) { - FatBlock fb = newFatBlock(beginNodeIndex, statementNodes.length - 1); - if (statementNodes[beginNodeIndex].getType() == Token.TARGET) - theTargetBlocks.put(statementNodes[beginNodeIndex], fb); - theBlocks.add(fb); - } - - // build successor and predecessor links - - for (int i = 0; i < theBlocks.size(); i++) { - FatBlock fb = (FatBlock)(theBlocks.get(i)); - - Node blockEndNode = statementNodes[fb.realBlock.itsEndNodeIndex]; - int blockEndNodeType = blockEndNode.getType(); - - if ((blockEndNodeType != Token.GOTO) - && (i < (theBlocks.size() - 1))) { - FatBlock fallThruTarget = (FatBlock)(theBlocks.get(i + 1)); - fb.addSuccessor(fallThruTarget); - fallThruTarget.addPredecessor(fb); - } - - - if ( (blockEndNodeType == Token.IFNE) - || (blockEndNodeType == Token.IFEQ) - || (blockEndNodeType == Token.GOTO) ) { - Node target = ((Node.Jump)blockEndNode).target; - FatBlock branchTargetBlock - = (FatBlock)(theTargetBlocks.get(target)); - target.putProp(Node.TARGETBLOCK_PROP, - branchTargetBlock.realBlock); - fb.addSuccessor(branchTargetBlock); - branchTargetBlock.addPredecessor(fb); - } - } - - Block[] result = new Block[theBlocks.size()]; - - for (int i = 0; i < theBlocks.size(); i++) { - FatBlock fb = (FatBlock)(theBlocks.get(i)); - Block b = fb.realBlock; - b.itsSuccessors = fb.getSuccessors(); - b.itsPredecessors = fb.getPredecessors(); - b.itsBlockID = i; - result[i] = b; - } - - return result; - } - - private static FatBlock newFatBlock(int startNodeIndex, int endNodeIndex) - { - FatBlock fb = new FatBlock(); - fb.realBlock = new Block(startNodeIndex, endNodeIndex); - return fb; - } - - private static String toString(Block[] blockList, Node[] statementNodes) - { - if (!DEBUG) return null; - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - - pw.println(blockList.length + " Blocks"); - for (int i = 0; i < blockList.length; i++) { - Block b = blockList[i]; - pw.println("#" + b.itsBlockID); - pw.println("from " + b.itsStartNodeIndex - + " " - + statementNodes[b.itsStartNodeIndex].toString()); - pw.println("thru " + b.itsEndNodeIndex - + " " - + statementNodes[b.itsEndNodeIndex].toString()); - pw.print("Predecessors "); - if (b.itsPredecessors != null) { - for (int j = 0; j < b.itsPredecessors.length; j++) - pw.print(b.itsPredecessors[j].itsBlockID + " "); - pw.println(); - } - else - pw.println("none"); - pw.print("Successors "); - if (b.itsSuccessors != null) { - for (int j = 0; j < b.itsSuccessors.length; j++) - pw.print(b.itsSuccessors[j].itsBlockID + " "); - pw.println(); - } - else - pw.println("none"); - } - return sw.toString(); - } - - private static void reachingDefDataFlow(OptFunctionNode fn, Node[] statementNodes, Block theBlocks[], int[] varTypes) - { -/* - initialize the liveOnEntry and liveOnExit sets, then discover the variables - that are def'd by each function, and those that are used before being def'd - (hence liveOnEntry) -*/ - for (int i = 0; i < theBlocks.length; i++) { - theBlocks[i].initLiveOnEntrySets(fn, statementNodes); - } -/* - this visits every block starting at the last, re-adding the predecessors of - any block whose inputs change as a result of the dataflow. - REMIND, better would be to visit in CFG postorder -*/ - boolean visit[] = new boolean[theBlocks.length]; - boolean doneOnce[] = new boolean[theBlocks.length]; - int vIndex = theBlocks.length - 1; - boolean needRescan = false; - visit[vIndex] = true; - while (true) { - if (visit[vIndex] || !doneOnce[vIndex]) { - doneOnce[vIndex] = true; - visit[vIndex] = false; - if (theBlocks[vIndex].doReachedUseDataFlow()) { - Block pred[] = theBlocks[vIndex].itsPredecessors; - if (pred != null) { - for (int i = 0; i < pred.length; i++) { - int index = pred[i].itsBlockID; - visit[index] = true; - needRescan |= (index > vIndex); - } - } - } - } - if (vIndex == 0) { - if (needRescan) { - vIndex = theBlocks.length - 1; - needRescan = false; - } - else - break; - } - else - vIndex--; - } -/* - if any variable is live on entry to block 0, we have to mark it as - not jRegable - since it means that someone is trying to access the - 'undefined'-ness of that variable. -*/ - - theBlocks[0].markAnyTypeVariables(varTypes); - } - - private static void typeFlow(OptFunctionNode fn, Node[] statementNodes, Block theBlocks[], int[] varTypes) - { - boolean visit[] = new boolean[theBlocks.length]; - boolean doneOnce[] = new boolean[theBlocks.length]; - int vIndex = 0; - boolean needRescan = false; - visit[vIndex] = true; - while (true) { - if (visit[vIndex] || !doneOnce[vIndex]) { - doneOnce[vIndex] = true; - visit[vIndex] = false; - if (theBlocks[vIndex].doTypeFlow(fn, statementNodes, varTypes)) - { - Block succ[] = theBlocks[vIndex].itsSuccessors; - if (succ != null) { - for (int i = 0; i < succ.length; i++) { - int index = succ[i].itsBlockID; - visit[index] = true; - needRescan |= (index < vIndex); - } - } - } - } - if (vIndex == (theBlocks.length - 1)) { - if (needRescan) { - vIndex = 0; - needRescan = false; - } - else - break; - } - else - vIndex++; - } - } - - private static boolean assignType(int[] varTypes, int index, int type) - { - return type != (varTypes[index] |= type); - } - - private void markAnyTypeVariables(int[] varTypes) - { - for (int i = 0; i != varTypes.length; i++) { - if (itsLiveOnEntrySet.test(i)) { - assignType(varTypes, i, Optimizer.AnyType); - } - } - - } - - /* - We're tracking uses and defs - in order to - build the def set and to identify the last use - nodes. - - The itsNotDefSet is built reversed then flipped later. - - */ - private void lookForVariableAccess(OptFunctionNode fn, Node n) - { - switch (n.getType()) { - case Token.DEC : - case Token.INC : - { - Node child = n.getFirstChild(); - if (child.getType() == Token.GETVAR) { - int varIndex = fn.getVarIndex(child); - if (!itsNotDefSet.test(varIndex)) - itsUseBeforeDefSet.set(varIndex); - itsNotDefSet.set(varIndex); - } - } - break; - case Token.SETVAR : - { - Node lhs = n.getFirstChild(); - Node rhs = lhs.getNext(); - lookForVariableAccess(fn, rhs); - itsNotDefSet.set(fn.getVarIndex(n)); - } - break; - case Token.GETVAR : - { - int varIndex = fn.getVarIndex(n); - if (!itsNotDefSet.test(varIndex)) - itsUseBeforeDefSet.set(varIndex); - } - break; - default : - Node child = n.getFirstChild(); - while (child != null) { - lookForVariableAccess(fn, child); - child = child.getNext(); - } - break; - } - } - - /* - build the live on entry/exit sets. - Then walk the trees looking for defs/uses of variables - and build the def and useBeforeDef sets. - */ - private void initLiveOnEntrySets(OptFunctionNode fn, Node[] statementNodes) - { - int listLength = fn.getVarCount(); - itsUseBeforeDefSet = new DataFlowBitSet(listLength); - itsNotDefSet = new DataFlowBitSet(listLength); - itsLiveOnEntrySet = new DataFlowBitSet(listLength); - itsLiveOnExitSet = new DataFlowBitSet(listLength); - for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) { - Node n = statementNodes[i]; - lookForVariableAccess(fn, n); - } - itsNotDefSet.not(); // truth in advertising - } - - /* - the liveOnEntry of each successor is the liveOnExit for this block. - The liveOnEntry for this block is - - liveOnEntry = liveOnExit - defsInThisBlock + useBeforeDefsInThisBlock - - */ - private boolean doReachedUseDataFlow() - { - itsLiveOnExitSet.clear(); - if (itsSuccessors != null) - for (int i = 0; i < itsSuccessors.length; i++) - itsLiveOnExitSet.or(itsSuccessors[i].itsLiveOnEntrySet); - return itsLiveOnEntrySet.df2(itsLiveOnExitSet, - itsUseBeforeDefSet, itsNotDefSet); - } - - /* - the type of an expression is relatively unknown. Cases we can be sure - about are - - Literals, - Arithmetic operations - always return a Number - */ - private static int findExpressionType(OptFunctionNode fn, Node n, - int[] varTypes) - { - switch (n.getType()) { - case Token.NUMBER : - return Optimizer.NumberType; - - case Token.CALL : - case Token.NEW : - case Token.REF_CALL : - return Optimizer.AnyType; - - case Token.GETELEM : - return Optimizer.AnyType; - - case Token.GETVAR : - return varTypes[fn.getVarIndex(n)]; - - case Token.INC : - case Token.DEC : - case Token.DIV: - case Token.MOD: - case Token.BITOR: - case Token.BITXOR: - case Token.BITAND: - case Token.LSH: - case Token.RSH: - case Token.URSH: - case Token.SUB : - return Optimizer.NumberType; - - case Token.ARRAYLIT: - case Token.OBJECTLIT: - return Optimizer.AnyType; // XXX: actually, we know it's not - // number, but no type yet for that - - case Token.ADD : { - // if the lhs & rhs are known to be numbers, we can be sure that's - // the result, otherwise it could be a string. - Node child = n.getFirstChild(); - int lType = findExpressionType(fn, child, varTypes); - int rType = findExpressionType(fn, child.getNext(), varTypes); - return lType | rType; // we're not distinguishing strings yet - } - } - - Node child = n.getFirstChild(); - if (child == null) { - return Optimizer.AnyType; - } else { - int result = Optimizer.NoType; - while (child != null) { - result |= findExpressionType(fn, child, varTypes); - child = child.getNext(); - } - return result; - } - } - - private static boolean findDefPoints(OptFunctionNode fn, Node n, - int[] varTypes) - { - boolean result = false; - Node child = n.getFirstChild(); - switch (n.getType()) { - default : - while (child != null) { - result |= findDefPoints(fn, child, varTypes); - child = child.getNext(); - } - break; - case Token.DEC : - case Token.INC : - if (child.getType() == Token.GETVAR) { - // theVar is a Number now - int i = fn.getVarIndex(child); - result |= assignType(varTypes, i, Optimizer.NumberType); - } - break; - case Token.SETPROP : - case Token.SETPROP_OP : - if (child.getType() == Token.GETVAR) { - int i = fn.getVarIndex(child); - assignType(varTypes, i, Optimizer.AnyType); - } - while (child != null) { - result |= findDefPoints(fn, child, varTypes); - child = child.getNext(); - } - break; - case Token.SETVAR : { - Node rValue = child.getNext(); - int theType = findExpressionType(fn, rValue, varTypes); - int i = fn.getVarIndex(n); - result |= assignType(varTypes, i, theType); - break; - } - } - return result; - } - - private boolean doTypeFlow(OptFunctionNode fn, Node[] statementNodes, - int[] varTypes) - { - boolean changed = false; - - for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) { - Node n = statementNodes[i]; - if (n != null) - changed |= findDefPoints(fn, n, varTypes); - } - - return changed; - } - - private void printLiveOnEntrySet(OptFunctionNode fn) - { - if (DEBUG) { - for (int i = 0; i < fn.getVarCount(); i++) { - String name = fn.fnode.getParamOrVarName(i); - if (itsUseBeforeDefSet.test(i)) - System.out.println(name + " is used before def'd"); - if (itsNotDefSet.test(i)) - System.out.println(name + " is not def'd"); - if (itsLiveOnEntrySet.test(i)) - System.out.println(name + " is live on entry"); - if (itsLiveOnExitSet.test(i)) - System.out.println(name + " is live on exit"); - } - } - } - - // all the Blocks that come immediately after this - private Block[] itsSuccessors; - // all the Blocks that come immediately before this - private Block[] itsPredecessors; - - private int itsStartNodeIndex; // the Node at the start of the block - private int itsEndNodeIndex; // the Node at the end of the block - - private int itsBlockID; // a unique index for each block - -// reaching def bit sets - - private DataFlowBitSet itsLiveOnEntrySet; - private DataFlowBitSet itsLiveOnExitSet; - private DataFlowBitSet itsUseBeforeDefSet; - private DataFlowBitSet itsNotDefSet; - - static final boolean DEBUG = false; - private static int debug_blockCount; - -} - diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java deleted file mode 100644 index 4a69c6a..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/ClassCompiler.java +++ /dev/null @@ -1,214 +0,0 @@ -/* ***** 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): - * Igor Bukanov - * - * 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.optimizer; - -import org.mozilla.javascript.*; - -/** - * Generates class files from script sources. - * - * since 1.5 Release 5 - * @author Igor Bukanov - */ - -public class ClassCompiler -{ - /** - * Construct ClassCompiler that uses the specified compiler environment - * when generating classes. - */ - public ClassCompiler(CompilerEnvirons compilerEnv) - { - if (compilerEnv == null) throw new IllegalArgumentException(); - this.compilerEnv = compilerEnv; - this.mainMethodClassName = Codegen.DEFAULT_MAIN_METHOD_CLASS; - } - - /** - * Set the class name to use for main method implementation. - * The class must have a method matching - * <tt>public static void main(Script sc, String[] args)</tt>, it will be - * called when <tt>main(String[] args)</tt> is called in the generated - * class. The class name should be fully qulified name and include the - * package name like in <tt>org.foo.Bar<tt>. - */ - public void setMainMethodClass(String className) - { - // XXX Should this check for a valid class name? - mainMethodClassName = className; - } - - /** - * Get the name of the class for main method implementation. - * @see #setMainMethodClass(String) - */ - public String getMainMethodClass() - { - return mainMethodClassName; - } - - /** - * Get the compiler environment the compiler uses. - */ - public CompilerEnvirons getCompilerEnv() - { - return compilerEnv; - } - - /** - * Get the class that the generated target will extend. - */ - public Class getTargetExtends() - { - return targetExtends; - } - - /** - * Set the class that the generated target will extend. - * - * @param extendsClass the class it extends - */ - public void setTargetExtends(Class extendsClass) - { - targetExtends = extendsClass; - } - - /** - * Get the interfaces that the generated target will implement. - */ - public Class[] getTargetImplements() - { - return targetImplements == null ? null : (Class[])targetImplements.clone(); - } - - /** - * Set the interfaces that the generated target will implement. - * - * @param implementsClasses an array of Class objects, one for each - * interface the target will extend - */ - public void setTargetImplements(Class[] implementsClasses) - { - targetImplements = implementsClasses == null ? null : (Class[])implementsClasses.clone(); - } - - /** - * Build class name for a auxiliary class generated by compiler. - * If the compiler needs to generate extra classes beyond the main class, - * it will call this function to build the auxiliary class name. - * The default implementation simply appends auxMarker to mainClassName - * but this can be overridden. - */ - protected String makeAuxiliaryClassName(String mainClassName, - String auxMarker) - { - return mainClassName+auxMarker; - } - - /** - * Compile JavaScript source into one or more Java class files. - * The first compiled class will have name mainClassName. - * If the results of {@link #getTargetExtends()} or - * {@link #getTargetImplements()} are not null, then the first compiled - * class will extend the specified super class and implement - * specified interfaces. - * - * @return array where elements with even indexes specifies class name - * and the following odd index gives class file body as byte[] - * array. The initial element of the array always holds - * mainClassName and array[1] holds its byte code. - */ - public Object[] compileToClassFiles(String source, - String sourceLocation, - int lineno, - String mainClassName) - { - /*APPJET*/ - Parser p = - InformativeParser.makeParser(compilerEnv, - compilerEnv.getErrorReporter()); - ScriptOrFnNode tree = p.parse(source, sourceLocation, lineno); - String encodedSource = p.getEncodedSource(); - - Class superClass = getTargetExtends(); - Class[] interfaces = getTargetImplements(); - String scriptClassName; - boolean isPrimary = (interfaces == null && superClass == null); - if (isPrimary) { - scriptClassName = mainClassName; - } else { - scriptClassName = makeAuxiliaryClassName(mainClassName, "1"); - } - - Codegen codegen = new Codegen(); - codegen.setMainMethodClass(mainMethodClassName); - byte[] scriptClassBytes - = codegen.compileToClassFile(compilerEnv, scriptClassName, - tree, encodedSource, - false); - - if (isPrimary) { - return new Object[] { scriptClassName, scriptClassBytes }; - } - int functionCount = tree.getFunctionCount(); - ObjToIntMap functionNames = new ObjToIntMap(functionCount); - for (int i = 0; i != functionCount; ++i) { - FunctionNode ofn = tree.getFunctionNode(i); - String name = ofn.getFunctionName(); - if (name != null && name.length() != 0) { - functionNames.put(name, ofn.getParamCount()); - } - } - if (superClass == null) { - superClass = ScriptRuntime.ObjectClass; - } - byte[] mainClassBytes - = JavaAdapter.createAdapterCode( - functionNames, mainClassName, - superClass, interfaces, scriptClassName); - - return new Object[] { mainClassName, mainClassBytes, - scriptClassName, scriptClassBytes }; - } - - private String mainMethodClassName; - private CompilerEnvirons compilerEnv; - private Class targetExtends; - private Class[] targetImplements; - -} - diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java deleted file mode 100644 index 64952bf..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Codegen.java +++ /dev/null @@ -1,5031 +0,0 @@ -/* ***** 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): - * Norris Boyd - * Kemal Bayram - * Igor Bukanov - * Bob Jervis - * Roger Lawrence - * Andi Vajda - * 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.optimizer; - -import org.mozilla.javascript.*; -import org.mozilla.classfile.*; -import java.util.*; -import java.lang.reflect.Constructor; -import java.util.Hashtable; - -/** - * This class generates code for a given IR tree. - * - * @author Norris Boyd - * @author Roger Lawrence - */ - -public class Codegen implements Evaluator -{ - public void captureStackInfo(RhinoException ex) { - throw new UnsupportedOperationException(); - } - - public String getSourcePositionFromStack(Context cx, int[] linep) { - throw new UnsupportedOperationException(); - } - - public String getPatchedStack(RhinoException ex, String nativeStackTrace) { - throw new UnsupportedOperationException(); - } - - public List getScriptStack(RhinoException ex) { - throw new UnsupportedOperationException(); - } - - public void setEvalScriptFlag(Script script) { - throw new UnsupportedOperationException(); - } - - public Object compile(CompilerEnvirons compilerEnv, - ScriptOrFnNode tree, - String encodedSource, - boolean returnFunction) - { - int serial; - synchronized (globalLock) { - serial = ++globalSerialClassCounter; - } - String mainClassName = "org.mozilla.javascript.gen.c"+serial; - - byte[] mainClassBytes = compileToClassFile(compilerEnv, mainClassName, - tree, encodedSource, - returnFunction); - - return new Object[] { mainClassName, mainClassBytes }; - } - - public Script createScriptObject(Object bytecode, - Object staticSecurityDomain) - { - Class cl = defineClass(bytecode, staticSecurityDomain); - - Script script; - try { - script = (Script)cl.newInstance(); - } catch (Exception ex) { - throw new RuntimeException - ("Unable to instantiate compiled class:"+ex.toString()); - } - return script; - } - - public Function createFunctionObject(Context cx, Scriptable scope, - Object bytecode, - Object staticSecurityDomain) - { - Class cl = defineClass(bytecode, staticSecurityDomain); - - NativeFunction f; - try { - Constructor ctor = cl.getConstructors()[0]; - Object[] initArgs = { scope, cx, new Integer(0) }; - f = (NativeFunction)ctor.newInstance(initArgs); - } catch (Exception ex) { - throw new RuntimeException - ("Unable to instantiate compiled class:"+ex.toString()); - } - return f; - } - - private Class defineClass(Object bytecode, - Object staticSecurityDomain) - { - Object[] nameBytesPair = (Object[])bytecode; - String className = (String)nameBytesPair[0]; - byte[] classBytes = (byte[])nameBytesPair[1]; - - // The generated classes in this case refer only to Rhino classes - // which must be accessible through this class loader - ClassLoader rhinoLoader = getClass().getClassLoader(); - GeneratedClassLoader loader; - loader = SecurityController.createLoader(rhinoLoader, - staticSecurityDomain); - Exception e; - try { - Class cl = loader.defineClass(className, classBytes); - loader.linkClass(cl); - return cl; - } catch (SecurityException x) { - e = x; - } catch (IllegalArgumentException x) { - e = x; - } - throw new RuntimeException("Malformed optimizer package " + e); - } - - byte[] compileToClassFile(CompilerEnvirons compilerEnv, - String mainClassName, - ScriptOrFnNode scriptOrFn, - String encodedSource, - boolean returnFunction) - { - this.compilerEnv = compilerEnv; - - transform(scriptOrFn); - - if (Token.printTrees) { - /*APPJET*///System.out.println(scriptOrFn.toStringTree(scriptOrFn)); - } - - if (returnFunction) { - scriptOrFn = scriptOrFn.getFunctionNode(0); - } - - initScriptOrFnNodesData(scriptOrFn); - - this.mainClassName = mainClassName; - this.mainClassSignature - = ClassFileWriter.classNameToSignature(mainClassName); - - try { - return generateCode(encodedSource); - } catch (ClassFileWriter.ClassFileFormatException e) { - throw reportClassFileFormatException(scriptOrFn, e.getMessage()); - } - } - - private RuntimeException reportClassFileFormatException( - ScriptOrFnNode scriptOrFn, - String message) - { - String msg = scriptOrFn instanceof FunctionNode - ? ScriptRuntime.getMessage2("msg.while.compiling.fn", - ((FunctionNode)scriptOrFn).getFunctionName(), message) - : ScriptRuntime.getMessage1("msg.while.compiling.script", message); - return Context.reportRuntimeError(msg, scriptOrFn.getSourceName(), - scriptOrFn.getLineno(), null, 0); - } - - private void transform(ScriptOrFnNode tree) - { - initOptFunctions_r(tree); - - int optLevel = compilerEnv.getOptimizationLevel(); - - Hashtable possibleDirectCalls = null; - if (optLevel > 0) { - /* - * Collect all of the contained functions into a hashtable - * so that the call optimizer can access the class name & parameter - * count for any call it encounters - */ - if (tree.getType() == Token.SCRIPT) { - int functionCount = tree.getFunctionCount(); - for (int i = 0; i != functionCount; ++i) { - OptFunctionNode ofn = OptFunctionNode.get(tree, i); - if (ofn.fnode.getFunctionType() - == FunctionNode.FUNCTION_STATEMENT) - { - String name = ofn.fnode.getFunctionName(); - if (name.length() != 0) { - if (possibleDirectCalls == null) { - possibleDirectCalls = new Hashtable(); - } - possibleDirectCalls.put(name, ofn); - } - } - } - } - } - - if (possibleDirectCalls != null) { - directCallTargets = new ObjArray(); - } - - OptTransformer ot = new OptTransformer(possibleDirectCalls, - directCallTargets); - ot.transform(tree); - - if (optLevel > 0) { - (new Optimizer()).optimize(tree); - } - } - - private static void initOptFunctions_r(ScriptOrFnNode scriptOrFn) - { - for (int i = 0, N = scriptOrFn.getFunctionCount(); i != N; ++i) { - FunctionNode fn = scriptOrFn.getFunctionNode(i); - new OptFunctionNode(fn); - initOptFunctions_r(fn); - } - } - - private void initScriptOrFnNodesData(ScriptOrFnNode scriptOrFn) - { - ObjArray x = new ObjArray(); - collectScriptOrFnNodes_r(scriptOrFn, x); - - int count = x.size(); - scriptOrFnNodes = new ScriptOrFnNode[count]; - x.toArray(scriptOrFnNodes); - - scriptOrFnIndexes = new ObjToIntMap(count); - for (int i = 0; i != count; ++i) { - scriptOrFnIndexes.put(scriptOrFnNodes[i], i); - } - } - - private static void collectScriptOrFnNodes_r(ScriptOrFnNode n, - ObjArray x) - { - x.add(n); - int nestedCount = n.getFunctionCount(); - for (int i = 0; i != nestedCount; ++i) { - collectScriptOrFnNodes_r(n.getFunctionNode(i), x); - } - } - - private byte[] generateCode(String encodedSource) - { - boolean hasScript = (scriptOrFnNodes[0].getType() == Token.SCRIPT); - boolean hasFunctions = (scriptOrFnNodes.length > 1 || !hasScript); - - String sourceFile = null; - if (compilerEnv.isGenerateDebugInfo()) { - sourceFile = scriptOrFnNodes[0].getSourceName(); - } - - ClassFileWriter cfw = new ClassFileWriter(mainClassName, - SUPER_CLASS_NAME, - sourceFile); - cfw.addField(ID_FIELD_NAME, "I", - ClassFileWriter.ACC_PRIVATE); - cfw.addField(DIRECT_CALL_PARENT_FIELD, mainClassSignature, - ClassFileWriter.ACC_PRIVATE); - cfw.addField(REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE, - ClassFileWriter.ACC_PRIVATE); - - if (hasFunctions) { - generateFunctionConstructor(cfw); - } - - if (hasScript) { - cfw.addInterface("org/mozilla/javascript/Script"); - generateScriptCtor(cfw); - generateMain(cfw); - generateExecute(cfw); - } - - generateCallMethod(cfw); - generateResumeGenerator(cfw); - - generateNativeFunctionOverrides(cfw, encodedSource); - - int count = scriptOrFnNodes.length; - for (int i = 0; i != count; ++i) { - ScriptOrFnNode n = scriptOrFnNodes[i]; - - BodyCodegen bodygen = new BodyCodegen(); - bodygen.cfw = cfw; - bodygen.codegen = this; - bodygen.compilerEnv = compilerEnv; - bodygen.scriptOrFn = n; - bodygen.scriptOrFnIndex = i; - - try { - bodygen.generateBodyCode(); - } catch (ClassFileWriter.ClassFileFormatException e) { - throw reportClassFileFormatException(n, e.getMessage()); - } - - if (n.getType() == Token.FUNCTION) { - OptFunctionNode ofn = OptFunctionNode.get(n); - generateFunctionInit(cfw, ofn); - if (ofn.isTargetOfDirectCall()) { - emitDirectConstructor(cfw, ofn); - } - } - } - - if (directCallTargets != null) { - int N = directCallTargets.size(); - for (int j = 0; j != N; ++j) { - cfw.addField(getDirectTargetFieldName(j), - mainClassSignature, - ClassFileWriter.ACC_PRIVATE); - } - } - - emitRegExpInit(cfw); - emitConstantDudeInitializers(cfw); - - return cfw.toByteArray(); - } - - private void emitDirectConstructor(ClassFileWriter cfw, - OptFunctionNode ofn) - { -/* - we generate .. - Scriptable directConstruct(<directCallArgs>) { - Scriptable newInstance = createObject(cx, scope); - Object val = <body-name>(cx, scope, newInstance, <directCallArgs>); - if (val instanceof Scriptable) { - return (Scriptable) val; - } - return newInstance; - } -*/ - cfw.startMethod(getDirectCtorName(ofn.fnode), - getBodyMethodSignature(ofn.fnode), - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - - int argCount = ofn.fnode.getParamCount(); - int firstLocal = (4 + argCount * 3) + 1; - - cfw.addALoad(0); // this - cfw.addALoad(1); // cx - cfw.addALoad(2); // scope - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, - "org/mozilla/javascript/BaseFunction", - "createObject", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(firstLocal); - - cfw.addALoad(0); - cfw.addALoad(1); - cfw.addALoad(2); - cfw.addALoad(firstLocal); - for (int i = 0; i < argCount; i++) { - cfw.addALoad(4 + (i * 3)); - cfw.addDLoad(5 + (i * 3)); - } - cfw.addALoad(4 + argCount * 3); - cfw.addInvoke(ByteCode.INVOKESTATIC, - mainClassName, - getBodyMethodName(ofn.fnode), - getBodyMethodSignature(ofn.fnode)); - int exitLabel = cfw.acquireLabel(); - cfw.add(ByteCode.DUP); // make a copy of direct call result - cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Scriptable"); - cfw.add(ByteCode.IFEQ, exitLabel); - // cast direct call result - cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/Scriptable"); - cfw.add(ByteCode.ARETURN); - cfw.markLabel(exitLabel); - - cfw.addALoad(firstLocal); - cfw.add(ByteCode.ARETURN); - - cfw.stopMethod((short)(firstLocal + 1)); - } - - static boolean isGenerator(ScriptOrFnNode node) - { - return (node.getType() == Token.FUNCTION ) && - ((FunctionNode)node).isGenerator(); - } - - // How dispatch to generators works: - // Two methods are generated corresponding to a user-written generator. - // One of these creates a generator object (NativeGenerator), which is - // returned to the user. The other method contains all of the body code - // of the generator. - // When a user calls a generator, the call() method dispatches control to - // to the method that creates the NativeGenerator object. Subsequently when - // the user invokes .next(), .send() or any such method on the generator - // object, the resumeGenerator() below dispatches the call to the - // method corresponding to the generator body. As a matter of convention - // the generator body is given the name of the generator activation function - // appended by "_gen". - private void generateResumeGenerator(ClassFileWriter cfw) - { - boolean hasGenerators = false; - for (int i=0; i < scriptOrFnNodes.length; i++) { - if (isGenerator(scriptOrFnNodes[i])) - hasGenerators = true; - } - - // if there are no generators defined, we don't implement a - // resumeGenerator(). The base class provides a default implementation. - if (!hasGenerators) - return; - - cfw.startMethod("resumeGenerator", - "(Lorg/mozilla/javascript/Context;" + - "Lorg/mozilla/javascript/Scriptable;" + - "ILjava/lang/Object;" + - "Ljava/lang/Object;)Ljava/lang/Object;", - (short)(ClassFileWriter.ACC_PUBLIC - | ClassFileWriter.ACC_FINAL)); - - // load arguments for dispatch to the corresponding *_gen method - cfw.addALoad(0); - cfw.addALoad(1); - cfw.addALoad(2); - cfw.addALoad(4); - cfw.addALoad(5); - cfw.addILoad(3); - - cfw.addLoadThis(); - cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); - - int startSwitch = cfw.addTableSwitch(0, scriptOrFnNodes.length - 1); - cfw.markTableSwitchDefault(startSwitch); - int endlabel = cfw.acquireLabel(); - - for (int i = 0; i < scriptOrFnNodes.length; i++) { - ScriptOrFnNode n = scriptOrFnNodes[i]; - cfw.markTableSwitchCase(startSwitch, i, (short)6); - if (isGenerator(n)) { - String type = "(" + - mainClassSignature + - "Lorg/mozilla/javascript/Context;" + - "Lorg/mozilla/javascript/Scriptable;" + - "Ljava/lang/Object;" + - "Ljava/lang/Object;I)Ljava/lang/Object;"; - cfw.addInvoke(ByteCode.INVOKESTATIC, - mainClassName, - getBodyMethodName(n) + "_gen", - type); - cfw.add(ByteCode.ARETURN); - } else { - cfw.add(ByteCode.GOTO, endlabel); - } - } - - cfw.markLabel(endlabel); - pushUndefined(cfw); - cfw.add(ByteCode.ARETURN); - - - // this method uses as many locals as there are arguments (hence 6) - cfw.stopMethod((short)6); - } - - private void generateCallMethod(ClassFileWriter cfw) - { - cfw.startMethod("call", - "(Lorg/mozilla/javascript/Context;" + - "Lorg/mozilla/javascript/Scriptable;" + - "Lorg/mozilla/javascript/Scriptable;" + - "[Ljava/lang/Object;)Ljava/lang/Object;", - (short)(ClassFileWriter.ACC_PUBLIC - | ClassFileWriter.ACC_FINAL)); - - // Generate code for: - // if (!ScriptRuntime.hasTopCall(cx)) { - // return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args); - // } - - int nonTopCallLabel = cfw.acquireLabel(); - cfw.addALoad(1); //cx - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org/mozilla/javascript/ScriptRuntime", - "hasTopCall", - "(Lorg/mozilla/javascript/Context;" - +")Z"); - cfw.add(ByteCode.IFNE, nonTopCallLabel); - cfw.addALoad(0); - cfw.addALoad(1); - cfw.addALoad(2); - cfw.addALoad(3); - cfw.addALoad(4); - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org/mozilla/javascript/ScriptRuntime", - "doTopCall", - "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Ljava/lang/Object;"); - cfw.add(ByteCode.ARETURN); - cfw.markLabel(nonTopCallLabel); - - // Now generate switch to call the real methods - cfw.addALoad(0); - cfw.addALoad(1); - cfw.addALoad(2); - cfw.addALoad(3); - cfw.addALoad(4); - - int end = scriptOrFnNodes.length; - boolean generateSwitch = (2 <= end); - - int switchStart = 0; - int switchStackTop = 0; - if (generateSwitch) { - cfw.addLoadThis(); - cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); - // do switch from (1, end - 1) mapping 0 to - // the default case - switchStart = cfw.addTableSwitch(1, end - 1); - } - - for (int i = 0; i != end; ++i) { - ScriptOrFnNode n = scriptOrFnNodes[i]; - if (generateSwitch) { - if (i == 0) { - cfw.markTableSwitchDefault(switchStart); - switchStackTop = cfw.getStackTop(); - } else { - cfw.markTableSwitchCase(switchStart, i - 1, - switchStackTop); - } - } - if (n.getType() == Token.FUNCTION) { - OptFunctionNode ofn = OptFunctionNode.get(n); - if (ofn.isTargetOfDirectCall()) { - int pcount = ofn.fnode.getParamCount(); - if (pcount != 0) { - // loop invariant: - // stack top == arguments array from addALoad4() - for (int p = 0; p != pcount; ++p) { - cfw.add(ByteCode.ARRAYLENGTH); - cfw.addPush(p); - int undefArg = cfw.acquireLabel(); - int beyond = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ICMPLE, undefArg); - // get array[p] - cfw.addALoad(4); - cfw.addPush(p); - cfw.add(ByteCode.AALOAD); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(undefArg); - pushUndefined(cfw); - cfw.markLabel(beyond); - // Only one push - cfw.adjustStackTop(-1); - cfw.addPush(0.0); - // restore invariant - cfw.addALoad(4); - } - } - } - } - cfw.addInvoke(ByteCode.INVOKESTATIC, - mainClassName, - getBodyMethodName(n), - getBodyMethodSignature(n)); - cfw.add(ByteCode.ARETURN); - } - cfw.stopMethod((short)5); - // 5: this, cx, scope, js this, args[] - } - - private void generateMain(ClassFileWriter cfw) - { - cfw.startMethod("main", "([Ljava/lang/String;)V", - (short)(ClassFileWriter.ACC_PUBLIC - | ClassFileWriter.ACC_STATIC)); - - // load new ScriptImpl() - cfw.add(ByteCode.NEW, cfw.getClassName()); - cfw.add(ByteCode.DUP); - cfw.addInvoke(ByteCode.INVOKESPECIAL, cfw.getClassName(), - "<init>", "()V"); - // load 'args' - cfw.add(ByteCode.ALOAD_0); - // Call mainMethodClass.main(Script script, String[] args) - cfw.addInvoke(ByteCode.INVOKESTATIC, - mainMethodClass, - "main", - "(Lorg/mozilla/javascript/Script;[Ljava/lang/String;)V"); - cfw.add(ByteCode.RETURN); - // 1 = String[] args - cfw.stopMethod((short)1); - } - - private void generateExecute(ClassFileWriter cfw) - { - cfw.startMethod("exec", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;", - (short)(ClassFileWriter.ACC_PUBLIC - | ClassFileWriter.ACC_FINAL)); - - final int CONTEXT_ARG = 1; - final int SCOPE_ARG = 2; - - cfw.addLoadThis(); - cfw.addALoad(CONTEXT_ARG); - cfw.addALoad(SCOPE_ARG); - cfw.add(ByteCode.DUP); - cfw.add(ByteCode.ACONST_NULL); - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, - cfw.getClassName(), - "call", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Ljava/lang/Object;"); - - cfw.add(ByteCode.ARETURN); - // 3 = this + context + scope - cfw.stopMethod((short)3); - } - - private void generateScriptCtor(ClassFileWriter cfw) - { - cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC); - - cfw.addLoadThis(); - cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME, - "<init>", "()V"); - // set id to 0 - cfw.addLoadThis(); - cfw.addPush(0); - cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); - - cfw.add(ByteCode.RETURN); - // 1 parameter = this - cfw.stopMethod((short)1); - } - - private void generateFunctionConstructor(ClassFileWriter cfw) - { - final int SCOPE_ARG = 1; - final int CONTEXT_ARG = 2; - final int ID_ARG = 3; - - cfw.startMethod("<init>", FUNCTION_CONSTRUCTOR_SIGNATURE, - ClassFileWriter.ACC_PUBLIC); - cfw.addALoad(0); - cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME, - "<init>", "()V"); - - cfw.addLoadThis(); - cfw.addILoad(ID_ARG); - cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); - - cfw.addLoadThis(); - cfw.addALoad(CONTEXT_ARG); - cfw.addALoad(SCOPE_ARG); - - int start = (scriptOrFnNodes[0].getType() == Token.SCRIPT) ? 1 : 0; - int end = scriptOrFnNodes.length; - if (start == end) throw badTree(); - boolean generateSwitch = (2 <= end - start); - - int switchStart = 0; - int switchStackTop = 0; - if (generateSwitch) { - cfw.addILoad(ID_ARG); - // do switch from (start + 1, end - 1) mapping start to - // the default case - switchStart = cfw.addTableSwitch(start + 1, end - 1); - } - - for (int i = start; i != end; ++i) { - if (generateSwitch) { - if (i == start) { - cfw.markTableSwitchDefault(switchStart); - switchStackTop = cfw.getStackTop(); - } else { - cfw.markTableSwitchCase(switchStart, i - 1 - start, - switchStackTop); - } - } - OptFunctionNode ofn = OptFunctionNode.get(scriptOrFnNodes[i]); - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, - mainClassName, - getFunctionInitMethodName(ofn), - FUNCTION_INIT_SIGNATURE); - cfw.add(ByteCode.RETURN); - } - - // 4 = this + scope + context + id - cfw.stopMethod((short)4); - } - - private void generateFunctionInit(ClassFileWriter cfw, - OptFunctionNode ofn) - { - final int CONTEXT_ARG = 1; - final int SCOPE_ARG = 2; - cfw.startMethod(getFunctionInitMethodName(ofn), - FUNCTION_INIT_SIGNATURE, - (short)(ClassFileWriter.ACC_PRIVATE - | ClassFileWriter.ACC_FINAL)); - - // Call NativeFunction.initScriptFunction - cfw.addLoadThis(); - cfw.addALoad(CONTEXT_ARG); - cfw.addALoad(SCOPE_ARG); - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, - "org/mozilla/javascript/NativeFunction", - "initScriptFunction", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")V"); - - // precompile all regexp literals - int regexpCount = ofn.fnode.getRegexpCount(); - if (regexpCount != 0) { - cfw.addLoadThis(); - pushRegExpArray(cfw, ofn.fnode, CONTEXT_ARG, SCOPE_ARG); - cfw.add(ByteCode.PUTFIELD, mainClassName, - REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE); - } - - cfw.add(ByteCode.RETURN); - // 3 = (scriptThis/functionRef) + scope + context - cfw.stopMethod((short)3); - } - - private void generateNativeFunctionOverrides(ClassFileWriter cfw, - String encodedSource) - { - // Override NativeFunction.getLanguageVersion() with - // public int getLanguageVersion() { return <version-constant>; } - - cfw.startMethod("getLanguageVersion", "()I", - ClassFileWriter.ACC_PUBLIC); - - cfw.addPush(compilerEnv.getLanguageVersion()); - cfw.add(ByteCode.IRETURN); - - // 1: this and no argument or locals - cfw.stopMethod((short)1); - - // The rest of NativeFunction overrides require specific code for each - // script/function id - - final int Do_getFunctionName = 0; - final int Do_getParamCount = 1; - final int Do_getParamAndVarCount = 2; - final int Do_getParamOrVarName = 3; - final int Do_getEncodedSource = 4; - final int Do_getParamOrVarConst = 5; - final int SWITCH_COUNT = 6; - - for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex) { - if (methodIndex == Do_getEncodedSource && encodedSource == null) { - continue; - } - - // Generate: - // prologue; - // switch over function id to implement function-specific action - // epilogue - - short methodLocals; - switch (methodIndex) { - case Do_getFunctionName: - methodLocals = 1; // Only this - cfw.startMethod("getFunctionName", "()Ljava/lang/String;", - ClassFileWriter.ACC_PUBLIC); - break; - case Do_getParamCount: - methodLocals = 1; // Only this - cfw.startMethod("getParamCount", "()I", - ClassFileWriter.ACC_PUBLIC); - break; - case Do_getParamAndVarCount: - methodLocals = 1; // Only this - cfw.startMethod("getParamAndVarCount", "()I", - ClassFileWriter.ACC_PUBLIC); - break; - case Do_getParamOrVarName: - methodLocals = 1 + 1; // this + paramOrVarIndex - cfw.startMethod("getParamOrVarName", "(I)Ljava/lang/String;", - ClassFileWriter.ACC_PUBLIC); - break; - case Do_getParamOrVarConst: - methodLocals = 1 + 1 + 1; // this + paramOrVarName - cfw.startMethod("getParamOrVarConst", "(I)Z", - ClassFileWriter.ACC_PUBLIC); - break; - case Do_getEncodedSource: - methodLocals = 1; // Only this - cfw.startMethod("getEncodedSource", "()Ljava/lang/String;", - ClassFileWriter.ACC_PUBLIC); - cfw.addPush(encodedSource); - break; - default: - throw Kit.codeBug(); - } - - int count = scriptOrFnNodes.length; - - int switchStart = 0; - int switchStackTop = 0; - if (count > 1) { - // Generate switch but only if there is more then one - // script/function - cfw.addLoadThis(); - cfw.add(ByteCode.GETFIELD, cfw.getClassName(), - ID_FIELD_NAME, "I"); - - // do switch from 1 .. count - 1 mapping 0 to the default case - switchStart = cfw.addTableSwitch(1, count - 1); - } - - for (int i = 0; i != count; ++i) { - ScriptOrFnNode n = scriptOrFnNodes[i]; - if (i == 0) { - if (count > 1) { - cfw.markTableSwitchDefault(switchStart); - switchStackTop = cfw.getStackTop(); - } - } else { - cfw.markTableSwitchCase(switchStart, i - 1, - switchStackTop); - } - - // Impelemnet method-specific switch code - switch (methodIndex) { - case Do_getFunctionName: - // Push function name - if (n.getType() == Token.SCRIPT) { - cfw.addPush(""); - } else { - String name = ((FunctionNode)n).getFunctionName(); - cfw.addPush(name); - } - cfw.add(ByteCode.ARETURN); - break; - - case Do_getParamCount: - // Push number of defined parameters - cfw.addPush(n.getParamCount()); - cfw.add(ByteCode.IRETURN); - break; - - case Do_getParamAndVarCount: - // Push number of defined parameters and declared variables - cfw.addPush(n.getParamAndVarCount()); - cfw.add(ByteCode.IRETURN); - break; - - case Do_getParamOrVarName: - // Push name of parameter using another switch - // over paramAndVarCount - int paramAndVarCount = n.getParamAndVarCount(); - if (paramAndVarCount == 0) { - // The runtime should never call the method in this - // case but to make bytecode verifier happy return null - // as throwing execption takes more code - cfw.add(ByteCode.ACONST_NULL); - cfw.add(ByteCode.ARETURN); - } else if (paramAndVarCount == 1) { - // As above do not check for valid index but always - // return the name of the first param - cfw.addPush(n.getParamOrVarName(0)); - cfw.add(ByteCode.ARETURN); - } else { - // Do switch over getParamOrVarName - cfw.addILoad(1); // param or var index - // do switch from 1 .. paramAndVarCount - 1 mapping 0 - // to the default case - int paramSwitchStart = cfw.addTableSwitch( - 1, paramAndVarCount - 1); - for (int j = 0; j != paramAndVarCount; ++j) { - if (cfw.getStackTop() != 0) Kit.codeBug(); - String s = n.getParamOrVarName(j); - if (j == 0) { - cfw.markTableSwitchDefault(paramSwitchStart); - } else { - cfw.markTableSwitchCase(paramSwitchStart, j - 1, - 0); - } - cfw.addPush(s); - cfw.add(ByteCode.ARETURN); - } - } - break; - - case Do_getParamOrVarConst: - // Push name of parameter using another switch - // over paramAndVarCount - paramAndVarCount = n.getParamAndVarCount(); - boolean [] constness = n.getParamAndVarConst(); - if (paramAndVarCount == 0) { - // The runtime should never call the method in this - // case but to make bytecode verifier happy return null - // as throwing execption takes more code - cfw.add(ByteCode.ICONST_0); - cfw.add(ByteCode.IRETURN); - } else if (paramAndVarCount == 1) { - // As above do not check for valid index but always - // return the name of the first param - cfw.addPush(constness[0]); - cfw.add(ByteCode.IRETURN); - } else { - // Do switch over getParamOrVarName - cfw.addILoad(1); // param or var index - // do switch from 1 .. paramAndVarCount - 1 mapping 0 - // to the default case - int paramSwitchStart = cfw.addTableSwitch( - 1, paramAndVarCount - 1); - for (int j = 0; j != paramAndVarCount; ++j) { - if (cfw.getStackTop() != 0) Kit.codeBug(); - if (j == 0) { - cfw.markTableSwitchDefault(paramSwitchStart); - } else { - cfw.markTableSwitchCase(paramSwitchStart, j - 1, - 0); - } - cfw.addPush(constness[j]); - cfw.add(ByteCode.IRETURN); - } - } - break; - - case Do_getEncodedSource: - // Push number encoded source start and end - // to prepare for encodedSource.substring(start, end) - cfw.addPush(n.getEncodedSourceStart()); - cfw.addPush(n.getEncodedSourceEnd()); - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, - "java/lang/String", - "substring", - "(II)Ljava/lang/String;"); - cfw.add(ByteCode.ARETURN); - break; - - default: - throw Kit.codeBug(); - } - } - - cfw.stopMethod(methodLocals); - } - } - - private void emitRegExpInit(ClassFileWriter cfw) - { - // precompile all regexp literals - - int totalRegCount = 0; - for (int i = 0; i != scriptOrFnNodes.length; ++i) { - totalRegCount += scriptOrFnNodes[i].getRegexpCount(); - } - if (totalRegCount == 0) { - return; - } - - cfw.startMethod(REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE, - (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE - | ClassFileWriter.ACC_SYNCHRONIZED)); - cfw.addField("_reInitDone", "Z", - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - cfw.add(ByteCode.GETSTATIC, mainClassName, "_reInitDone", "Z"); - int doInit = cfw.acquireLabel(); - cfw.add(ByteCode.IFEQ, doInit); - cfw.add(ByteCode.RETURN); - cfw.markLabel(doInit); - - for (int i = 0; i != scriptOrFnNodes.length; ++i) { - ScriptOrFnNode n = scriptOrFnNodes[i]; - int regCount = n.getRegexpCount(); - for (int j = 0; j != regCount; ++j) { - String reFieldName = getCompiledRegexpName(n, j); - String reFieldType = "Ljava/lang/Object;"; - String reString = n.getRegexpString(j); - String reFlags = n.getRegexpFlags(j); - cfw.addField(reFieldName, reFieldType, - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - cfw.addALoad(0); // proxy - cfw.addALoad(1); // context - cfw.addPush(reString); - if (reFlags == null) { - cfw.add(ByteCode.ACONST_NULL); - } else { - cfw.addPush(reFlags); - } - /*APPJET*/cfw.addLineNumberEntry((short)n.getRegexpLineno(j)); - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/RegExpProxy", - "compileRegExp", - "(Lorg/mozilla/javascript/Context;" - +"Ljava/lang/String;Ljava/lang/String;" - +")Ljava/lang/Object;"); - cfw.add(ByteCode.PUTSTATIC, mainClassName, - reFieldName, reFieldType); - } - } - - cfw.addPush(1); - cfw.add(ByteCode.PUTSTATIC, mainClassName, "_reInitDone", "Z"); - cfw.add(ByteCode.RETURN); - cfw.stopMethod((short)2); - } - - private void emitConstantDudeInitializers(ClassFileWriter cfw) - { - int N = itsConstantListSize; - if (N == 0) - return; - - cfw.startMethod("<clinit>", "()V", - (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_FINAL)); - - double[] array = itsConstantList; - for (int i = 0; i != N; ++i) { - double num = array[i]; - String constantName = "_k" + i; - String constantType = getStaticConstantWrapperType(num); - cfw.addField(constantName, constantType, - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - int inum = (int)num; - if (inum == num) { - cfw.add(ByteCode.NEW, "java/lang/Integer"); - cfw.add(ByteCode.DUP); - cfw.addPush(inum); - cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Integer", - "<init>", "(I)V"); - } else { - cfw.addPush(num); - addDoubleWrap(cfw); - } - cfw.add(ByteCode.PUTSTATIC, mainClassName, - constantName, constantType); - } - - cfw.add(ByteCode.RETURN); - cfw.stopMethod((short)0); - } - - void pushRegExpArray(ClassFileWriter cfw, ScriptOrFnNode n, - int contextArg, int scopeArg) - { - int regexpCount = n.getRegexpCount(); - if (regexpCount == 0) throw badTree(); - - cfw.addPush(regexpCount); - cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); - - cfw.addALoad(contextArg); - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org/mozilla/javascript/ScriptRuntime", - "checkRegExpProxy", - "(Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/RegExpProxy;"); - // Stack: proxy, array - cfw.add(ByteCode.DUP); - cfw.addALoad(contextArg); - cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, - REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE); - for (int i = 0; i != regexpCount; ++i) { - // Stack: proxy, array - cfw.add(ByteCode.DUP2); - cfw.addALoad(contextArg); - cfw.addALoad(scopeArg); - cfw.add(ByteCode.GETSTATIC, mainClassName, - getCompiledRegexpName(n, i), "Ljava/lang/Object;"); - // Stack: compiledRegExp, scope, cx, proxy, array, proxy, array - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/RegExpProxy", - "wrapRegExp", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/Object;" - +")Lorg/mozilla/javascript/Scriptable;"); - // Stack: wrappedRegExp, array, proxy, array - cfw.addPush(i); - cfw.add(ByteCode.SWAP); - cfw.add(ByteCode.AASTORE); - // Stack: proxy, array - } - // remove proxy - cfw.add(ByteCode.POP); - } - - void pushNumberAsObject(ClassFileWriter cfw, double num) - { - if (num == 0.0) { - if (1 / num > 0) { - // +0.0 - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/optimizer/OptRuntime", - "zeroObj", "Ljava/lang/Double;"); - } else { - cfw.addPush(num); - addDoubleWrap(cfw); - } - - } else if (num == 1.0) { - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/optimizer/OptRuntime", - "oneObj", "Ljava/lang/Double;"); - return; - - } else if (num == -1.0) { - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/optimizer/OptRuntime", - "minusOneObj", "Ljava/lang/Double;"); - - } else if (num != num) { - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/ScriptRuntime", - "NaNobj", "Ljava/lang/Double;"); - - } else if (itsConstantListSize >= 2000) { - // There appears to be a limit in the JVM on either the number - // of static fields in a class or the size of the class - // initializer. Either way, we can't have any more than 2000 - // statically init'd constants. - cfw.addPush(num); - addDoubleWrap(cfw); - - } else { - int N = itsConstantListSize; - int index = 0; - if (N == 0) { - itsConstantList = new double[64]; - } else { - double[] array = itsConstantList; - while (index != N && array[index] != num) { - ++index; - } - if (N == array.length) { - array = new double[N * 2]; - System.arraycopy(itsConstantList, 0, array, 0, N); - itsConstantList = array; - } - } - if (index == N) { - itsConstantList[N] = num; - itsConstantListSize = N + 1; - } - String constantName = "_k" + index; - String constantType = getStaticConstantWrapperType(num); - cfw.add(ByteCode.GETSTATIC, mainClassName, - constantName, constantType); - } - } - - private static void addDoubleWrap(ClassFileWriter cfw) - { - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org/mozilla/javascript/optimizer/OptRuntime", - "wrapDouble", "(D)Ljava/lang/Double;"); - } - - private static String getStaticConstantWrapperType(double num) - { - int inum = (int)num; - if (inum == num) { - return "Ljava/lang/Integer;"; - } else { - return "Ljava/lang/Double;"; - } - } - static void pushUndefined(ClassFileWriter cfw) - { - cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/Undefined", - "instance", "Ljava/lang/Object;"); - } - - int getIndex(ScriptOrFnNode n) - { - return scriptOrFnIndexes.getExisting(n); - } - - static String getDirectTargetFieldName(int i) - { - return "_dt" + i; - } - - String getDirectCtorName(ScriptOrFnNode n) - { - return "_n"+getIndex(n); - } - - String getBodyMethodName(ScriptOrFnNode n) - { - return "_c"+getIndex(n); - } - - String getBodyMethodSignature(ScriptOrFnNode n) - { - StringBuffer sb = new StringBuffer(); - sb.append('('); - sb.append(mainClassSignature); - sb.append("Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;"); - if (n.getType() == Token.FUNCTION) { - OptFunctionNode ofn = OptFunctionNode.get(n); - if (ofn.isTargetOfDirectCall()) { - int pCount = ofn.fnode.getParamCount(); - for (int i = 0; i != pCount; i++) { - sb.append("Ljava/lang/Object;D"); - } - } - } - sb.append("[Ljava/lang/Object;)Ljava/lang/Object;"); - return sb.toString(); - } - - String getFunctionInitMethodName(OptFunctionNode ofn) - { - return "_i"+getIndex(ofn.fnode); - } - - String getCompiledRegexpName(ScriptOrFnNode n, int regexpIndex) - { - return "_re"+getIndex(n)+"_"+regexpIndex; - } - - static RuntimeException badTree() - { - throw new RuntimeException("Bad tree in codegen"); - } - - void setMainMethodClass(String className) - { - mainMethodClass = className; - } - - static final String DEFAULT_MAIN_METHOD_CLASS - = "org.mozilla.javascript.optimizer.OptRuntime"; - - private static final String SUPER_CLASS_NAME - = "org.mozilla.javascript.NativeFunction"; - - static final String DIRECT_CALL_PARENT_FIELD = "_dcp"; - private static final String ID_FIELD_NAME = "_id"; - - private static final String REGEXP_INIT_METHOD_NAME = "_reInit"; - private static final String REGEXP_INIT_METHOD_SIGNATURE - = "(Lorg/mozilla/javascript/RegExpProxy;" - +"Lorg/mozilla/javascript/Context;" - +")V"; - static final String REGEXP_ARRAY_FIELD_NAME = "_re"; - static final String REGEXP_ARRAY_FIELD_TYPE = "[Ljava/lang/Object;"; - - static final String FUNCTION_INIT_SIGNATURE - = "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")V"; - - static final String FUNCTION_CONSTRUCTOR_SIGNATURE - = "(Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Context;I)V"; - - private static final Object globalLock = new Object(); - private static int globalSerialClassCounter; - - private CompilerEnvirons compilerEnv; - - private ObjArray directCallTargets; - ScriptOrFnNode[] scriptOrFnNodes; - private ObjToIntMap scriptOrFnIndexes; - - private String mainMethodClass = DEFAULT_MAIN_METHOD_CLASS; - - String mainClassName; - String mainClassSignature; - - private double[] itsConstantList; - private int itsConstantListSize; -} - - -class BodyCodegen -{ - void generateBodyCode() - { - isGenerator = Codegen.isGenerator(scriptOrFn); - - // generate the body of the current function or script object - initBodyGeneration(); - - if (isGenerator) { - - // All functions in the generated bytecode have a unique name. Every - // generator has a unique prefix followed by _gen - String type = "(" + - codegen.mainClassSignature + - "Lorg/mozilla/javascript/Context;" + - "Lorg/mozilla/javascript/Scriptable;" + - "Ljava/lang/Object;" + - "Ljava/lang/Object;I)Ljava/lang/Object;"; - cfw.startMethod(codegen.getBodyMethodName(scriptOrFn) + "_gen", - type, - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - } else { - cfw.startMethod(codegen.getBodyMethodName(scriptOrFn), - codegen.getBodyMethodSignature(scriptOrFn), - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - } - - generatePrologue(); - Node treeTop; - if (fnCurrent != null) { - treeTop = scriptOrFn.getLastChild(); - } else { - treeTop = scriptOrFn; - } - generateStatement(treeTop); - generateEpilogue(); - - cfw.stopMethod((short)(localsMax + 1)); - - if (isGenerator) { - // generate the user visible method which when invoked will - // return a generator object - generateGenerator(); - } - } - - // This creates a the user-facing function that returns a NativeGenerator - // object. - private void generateGenerator() - { - cfw.startMethod(codegen.getBodyMethodName(scriptOrFn), - codegen.getBodyMethodSignature(scriptOrFn), - (short)(ClassFileWriter.ACC_STATIC - | ClassFileWriter.ACC_PRIVATE)); - - initBodyGeneration(); - argsLocal = firstFreeLocal++; - localsMax = firstFreeLocal; - - // get top level scope - if (fnCurrent != null && !inDirectCallFunction - && (!compilerEnv.isUseDynamicScope() - || fnCurrent.fnode.getIgnoreDynamicScope())) - { - // Unless we're either in a direct call or using dynamic scope, - // use the enclosing scope of the function as our variable object. - cfw.addALoad(funObjLocal); - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/Scriptable", - "getParentScope", - "()Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - } - - // generators are forced to have an activation record - cfw.addALoad(funObjLocal); - cfw.addALoad(variableObjectLocal); - cfw.addALoad(argsLocal); - addScriptRuntimeInvoke("createFunctionActivation", - "(Lorg/mozilla/javascript/NativeFunction;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - - // create a function object - cfw.add(ByteCode.NEW, codegen.mainClassName); - // Call function constructor - cfw.add(ByteCode.DUP); - cfw.addALoad(variableObjectLocal); - cfw.addALoad(contextLocal); // load 'cx' - cfw.addPush(scriptOrFnIndex); - cfw.addInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName, - "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE); - - // Init mainScript field - cfw.add(ByteCode.DUP); - if (isTopLevel) Kit.codeBug(); // Only functions can be generators - cfw.add(ByteCode.ALOAD_0); - cfw.add(ByteCode.GETFIELD, - codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - cfw.add(ByteCode.PUTFIELD, - codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - - generateNestedFunctionInits(); - - // create the NativeGenerator object that we return - cfw.addALoad(variableObjectLocal); - cfw.addALoad(thisObjLocal); - cfw.addLoadConstant(maxLocals); - cfw.addLoadConstant(maxStack); - addOptRuntimeInvoke("createNativeGenerator", - "(Lorg/mozilla/javascript/NativeFunction;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;II" - +")Lorg/mozilla/javascript/Scriptable;"); - - cfw.add(ByteCode.ARETURN); - cfw.stopMethod((short)(localsMax + 1)); - } - - private void generateNestedFunctionInits() - { - int functionCount = scriptOrFn.getFunctionCount(); - for (int i = 0; i != functionCount; i++) { - OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, i); - if (ofn.fnode.getFunctionType() - == FunctionNode.FUNCTION_STATEMENT) - { - visitFunction(ofn, FunctionNode.FUNCTION_STATEMENT); - } - } - } - - private void initBodyGeneration() - { - isTopLevel = (scriptOrFn == codegen.scriptOrFnNodes[0]); - - varRegisters = null; - if (scriptOrFn.getType() == Token.FUNCTION) { - fnCurrent = OptFunctionNode.get(scriptOrFn); - hasVarsInRegs = !fnCurrent.fnode.requiresActivation(); - if (hasVarsInRegs) { - int n = fnCurrent.fnode.getParamAndVarCount(); - if (n != 0) { - varRegisters = new short[n]; - } - } - inDirectCallFunction = fnCurrent.isTargetOfDirectCall(); - if (inDirectCallFunction && !hasVarsInRegs) Codegen.badTree(); - } else { - fnCurrent = null; - hasVarsInRegs = false; - inDirectCallFunction = false; - } - - locals = new int[MAX_LOCALS]; - - funObjLocal = 0; - contextLocal = 1; - variableObjectLocal = 2; - thisObjLocal = 3; - localsMax = (short) 4; // number of parms + "this" - firstFreeLocal = 4; - - popvLocal = -1; - argsLocal = -1; - itsZeroArgArray = -1; - itsOneArgArray = -1; - scriptRegexpLocal = -1; - epilogueLabel = -1; - enterAreaStartLabel = -1; - generatorStateLocal = -1; - } - - /** - * Generate the prologue for a function or script. - */ - private void generatePrologue() - { - if (inDirectCallFunction) { - int directParameterCount = scriptOrFn.getParamCount(); - // 0 is reserved for function Object 'this' - // 1 is reserved for context - // 2 is reserved for parentScope - // 3 is reserved for script 'this' - if (firstFreeLocal != 4) Kit.codeBug(); - for (int i = 0; i != directParameterCount; ++i) { - varRegisters[i] = firstFreeLocal; - // 3 is 1 for Object parm and 2 for double parm - firstFreeLocal += 3; - } - if (!fnCurrent.getParameterNumberContext()) { - // make sure that all parameters are objects - itsForcedObjectParameters = true; - for (int i = 0; i != directParameterCount; ++i) { - short reg = varRegisters[i]; - cfw.addALoad(reg); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - int isObjectLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPNE, isObjectLabel); - cfw.addDLoad(reg + 1); - addDoubleWrap(); - cfw.addAStore(reg); - cfw.markLabel(isObjectLabel); - } - } - } - - if (fnCurrent != null && !inDirectCallFunction - && (!compilerEnv.isUseDynamicScope() - || fnCurrent.fnode.getIgnoreDynamicScope())) - { - // Unless we're either in a direct call or using dynamic scope, - // use the enclosing scope of the function as our variable object. - cfw.addALoad(funObjLocal); - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/Scriptable", - "getParentScope", - "()Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - } - - // reserve 'args[]' - argsLocal = firstFreeLocal++; - localsMax = firstFreeLocal; - - // Generate Generator specific prelude - if (isGenerator) { - - // reserve 'args[]' - operationLocal = firstFreeLocal++; - localsMax = firstFreeLocal; - - // Local 3 is a reference to a GeneratorState object. The rest - // of codegen expects local 3 to be a reference to the thisObj. - // So move the value in local 3 to generatorStateLocal, and load - // the saved thisObj from the GeneratorState object. - cfw.addALoad(thisObjLocal); - generatorStateLocal = firstFreeLocal++; - localsMax = firstFreeLocal; - cfw.add(ByteCode.CHECKCAST, OptRuntime.GeneratorState.CLASS_NAME); - cfw.add(ByteCode.DUP); - cfw.addAStore(generatorStateLocal); - cfw.add(ByteCode.GETFIELD, - OptRuntime.GeneratorState.CLASS_NAME, - OptRuntime.GeneratorState.thisObj_NAME, - OptRuntime.GeneratorState.thisObj_TYPE); - cfw.addAStore(thisObjLocal); - - if (epilogueLabel == -1) { - epilogueLabel = cfw.acquireLabel(); - } - - ArrayList targets = ((FunctionNode)scriptOrFn).getResumptionPoints(); - if (targets != null) { - // get resumption point - generateGetGeneratorResumptionPoint(); - - // generate dispatch table - generatorSwitch = cfw.addTableSwitch(0, - targets.size() + GENERATOR_START); - generateCheckForThrowOrClose(-1, false, GENERATOR_START); - } - } - - if (fnCurrent == null) { - // See comments in case Token.REGEXP - if (scriptOrFn.getRegexpCount() != 0) { - scriptRegexpLocal = getNewWordLocal(); - codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal, - variableObjectLocal); - cfw.addAStore(scriptRegexpLocal); - } - } - - if (compilerEnv.isGenerateObserverCount()) - saveCurrentCodeOffset(); - - if (hasVarsInRegs) { - // No need to create activation. Pad arguments if need be. - int parmCount = scriptOrFn.getParamCount(); - if (parmCount > 0 && !inDirectCallFunction) { - // Set up args array - // check length of arguments, pad if need be - cfw.addALoad(argsLocal); - cfw.add(ByteCode.ARRAYLENGTH); - cfw.addPush(parmCount); - int label = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ICMPGE, label); - cfw.addALoad(argsLocal); - cfw.addPush(parmCount); - addScriptRuntimeInvoke("padArguments", - "([Ljava/lang/Object;I" - +")[Ljava/lang/Object;"); - cfw.addAStore(argsLocal); - cfw.markLabel(label); - } - - int paramCount = fnCurrent.fnode.getParamCount(); - int varCount = fnCurrent.fnode.getParamAndVarCount(); - boolean [] constDeclarations = fnCurrent.fnode.getParamAndVarConst(); - - // REMIND - only need to initialize the vars that don't get a value - // before the next call and are used in the function - short firstUndefVar = -1; - for (int i = 0; i != varCount; ++i) { - short reg = -1; - if (i < paramCount) { - if (!inDirectCallFunction) { - reg = getNewWordLocal(); - cfw.addALoad(argsLocal); - cfw.addPush(i); - cfw.add(ByteCode.AALOAD); - cfw.addAStore(reg); - } - } else if (fnCurrent.isNumberVar(i)) { - reg = getNewWordPairLocal(constDeclarations[i]); - cfw.addPush(0.0); - cfw.addDStore(reg); - } else { - reg = getNewWordLocal(constDeclarations[i]); - if (firstUndefVar == -1) { - Codegen.pushUndefined(cfw); - firstUndefVar = reg; - } else { - cfw.addALoad(firstUndefVar); - } - cfw.addAStore(reg); - } - if (reg >= 0) { - if (constDeclarations[i]) { - cfw.addPush(0); - cfw.addIStore(reg + (fnCurrent.isNumberVar(i) ? 2 : 1)); - } - varRegisters[i] = reg; - } - - // Add debug table entry if we're generating debug info - if (compilerEnv.isGenerateDebugInfo()) { - String name = fnCurrent.fnode.getParamOrVarName(i); - String type = fnCurrent.isNumberVar(i) - ? "D" : "Ljava/lang/Object;"; - int startPC = cfw.getCurrentCodeOffset(); - if (reg < 0) { - reg = varRegisters[i]; - } - cfw.addVariableDescriptor(name, type, startPC, reg); - } - } - - // Skip creating activation object. - return; - } - - // skip creating activation object for the body of a generator. The - // activation record required by a generator has already been created - // in generateGenerator(). - if (isGenerator) - return; - - - String debugVariableName; - if (fnCurrent != null) { - debugVariableName = "activation"; - cfw.addALoad(funObjLocal); - cfw.addALoad(variableObjectLocal); - cfw.addALoad(argsLocal); - addScriptRuntimeInvoke("createFunctionActivation", - "(Lorg/mozilla/javascript/NativeFunction;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke("enterActivationFunction", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")V"); - } else { - debugVariableName = "global"; - cfw.addALoad(funObjLocal); - cfw.addALoad(thisObjLocal); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - cfw.addPush(0); // false to indicate it is not eval script - addScriptRuntimeInvoke("initScript", - "(Lorg/mozilla/javascript/NativeFunction;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Z" - +")V"); - } - - enterAreaStartLabel = cfw.acquireLabel(); - epilogueLabel = cfw.acquireLabel(); - cfw.markLabel(enterAreaStartLabel); - - generateNestedFunctionInits(); - - // default is to generate debug info - if (compilerEnv.isGenerateDebugInfo()) { - cfw.addVariableDescriptor(debugVariableName, - "Lorg/mozilla/javascript/Scriptable;", - cfw.getCurrentCodeOffset(), variableObjectLocal); - } - - if (fnCurrent == null) { - // OPT: use dataflow to prove that this assignment is dead - popvLocal = getNewWordLocal(); - Codegen.pushUndefined(cfw); - cfw.addAStore(popvLocal); - - int linenum = scriptOrFn.getEndLineno(); - if (linenum != -1) - cfw.addLineNumberEntry((short)linenum); - - } else { - if (fnCurrent.itsContainsCalls0) { - itsZeroArgArray = getNewWordLocal(); - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/ScriptRuntime", - "emptyArgs", "[Ljava/lang/Object;"); - cfw.addAStore(itsZeroArgArray); - } - if (fnCurrent.itsContainsCalls1) { - itsOneArgArray = getNewWordLocal(); - cfw.addPush(1); - cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); - cfw.addAStore(itsOneArgArray); - } - } - } - - private void generateGetGeneratorResumptionPoint() - { - cfw.addALoad(generatorStateLocal); - cfw.add(ByteCode.GETFIELD, - OptRuntime.GeneratorState.CLASS_NAME, - OptRuntime.GeneratorState.resumptionPoint_NAME, - OptRuntime.GeneratorState.resumptionPoint_TYPE); - } - - private void generateSetGeneratorResumptionPoint(int nextState) - { - cfw.addALoad(generatorStateLocal); - cfw.addLoadConstant(nextState); - cfw.add(ByteCode.PUTFIELD, - OptRuntime.GeneratorState.CLASS_NAME, - OptRuntime.GeneratorState.resumptionPoint_NAME, - OptRuntime.GeneratorState.resumptionPoint_TYPE); - } - - private void generateGetGeneratorStackState() - { - cfw.addALoad(generatorStateLocal); - addOptRuntimeInvoke("getGeneratorStackState", - "(Ljava/lang/Object;)[Ljava/lang/Object;"); - } - - private void generateEpilogue() - { - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - if (isGenerator) { - // generate locals initialization - HashMap liveLocals = ((FunctionNode)scriptOrFn).getLiveLocals(); - if (liveLocals != null) { - ArrayList nodes = ((FunctionNode)scriptOrFn).getResumptionPoints(); - for (int i = 0; i < nodes.size(); i++) { - Node node = (Node) nodes.get(i); - int[] live = (int [])liveLocals.get(node); - if (live != null) { - cfw.markTableSwitchCase(generatorSwitch, - getNextGeneratorState(node)); - generateGetGeneratorLocalsState(); - for (int j = 0; j < live.length; j++) { - cfw.add(ByteCode.DUP); - cfw.addLoadConstant(j); - cfw.add(ByteCode.AALOAD); - cfw.addAStore(live[j]); - } - cfw.add(ByteCode.POP); - cfw.add(ByteCode.GOTO, getTargetLabel(node)); - } - } - } - - // generate dispatch tables for finally - if (finallys != null) { - Enumeration en = finallys.keys(); - while(en.hasMoreElements()) { - Node n = (Node) en.nextElement(); - if (n.getType() == Token.FINALLY) { - FinallyReturnPoint ret = - (FinallyReturnPoint)finallys.get(n); - // the finally will jump here - cfw.markLabel(ret.tableLabel, (short)1); - - // start generating a dispatch table - int startSwitch = cfw.addTableSwitch(0, - ret.jsrPoints.size() - 1); - int c = 0; - cfw.markTableSwitchDefault(startSwitch); - for (int i = 0; i < ret.jsrPoints.size(); i++) { - // generate gotos back to the JSR location - cfw.markTableSwitchCase(startSwitch, c); - cfw.add(ByteCode.GOTO, - ((Integer)ret.jsrPoints.get(i)).intValue()); - c++; - } - } - } - } - } - - if (epilogueLabel != -1) { - cfw.markLabel(epilogueLabel); - } - - if (hasVarsInRegs) { - cfw.add(ByteCode.ARETURN); - return; - } else if (isGenerator) { - if (((FunctionNode)scriptOrFn).getResumptionPoints() != null) { - cfw.markTableSwitchDefault(generatorSwitch); - } - - // change state for re-entry - generateSetGeneratorResumptionPoint(GENERATOR_TERMINATE); - - // throw StopIteration - cfw.addALoad(variableObjectLocal); - addOptRuntimeInvoke("throwStopIteration", - "(Ljava/lang/Object;)V"); - - Codegen.pushUndefined(cfw); - cfw.add(ByteCode.ARETURN); - - } else if (fnCurrent == null) { - cfw.addALoad(popvLocal); - cfw.add(ByteCode.ARETURN); - } else { - generateActivationExit(); - cfw.add(ByteCode.ARETURN); - - // Generate catch block to catch all and rethrow to call exit code - // under exception propagation as well. - - int finallyHandler = cfw.acquireLabel(); - cfw.markHandler(finallyHandler); - short exceptionObject = getNewWordLocal(); - cfw.addAStore(exceptionObject); - - // Duplicate generateActivationExit() in the catch block since it - // takes less space then full-featured ByteCode.JSR/ByteCode.RET - generateActivationExit(); - - cfw.addALoad(exceptionObject); - releaseWordLocal(exceptionObject); - // rethrow - cfw.add(ByteCode.ATHROW); - - // mark the handler - cfw.addExceptionHandler(enterAreaStartLabel, epilogueLabel, - finallyHandler, null); // catch any - } - } - - private void generateGetGeneratorLocalsState() { - cfw.addALoad(generatorStateLocal); - addOptRuntimeInvoke("getGeneratorLocalsState", - "(Ljava/lang/Object;)[Ljava/lang/Object;"); - } - - private void generateActivationExit() - { - if (fnCurrent == null || hasVarsInRegs) throw Kit.codeBug(); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("exitActivationFunction", - "(Lorg/mozilla/javascript/Context;)V"); - } - - private void generateStatement(Node node) - { - updateLineNumber(node); - int type = node.getType(); - Node child = node.getFirstChild(); - switch (type) { - case Token.LOOP: - case Token.LABEL: - case Token.WITH: - case Token.SCRIPT: - case Token.BLOCK: - case Token.EMPTY: - // no-ops. - while (child != null) { - generateStatement(child); - child = child.getNext(); - } - break; - - case Token.LOCAL_BLOCK: { - int local = getNewWordLocal(); - if (isGenerator) { - cfw.add(ByteCode.ACONST_NULL); - cfw.addAStore(local); - } - node.putIntProp(Node.LOCAL_PROP, local); - while (child != null) { - generateStatement(child); - child = child.getNext(); - } - releaseWordLocal((short)local); - node.removeProp(Node.LOCAL_PROP); - break; - } - - case Token.FUNCTION: { - int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); - OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, fnIndex); - int t = ofn.fnode.getFunctionType(); - if (t == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { - visitFunction(ofn, t); - } else { - if (t != FunctionNode.FUNCTION_STATEMENT) { - throw Codegen.badTree(); - } - } - break; - } - - case Token.TRY: - visitTryCatchFinally((Node.Jump)node, child); - break; - - case Token.CATCH_SCOPE: - { - // nothing stays on the stack on entry into a catch scope - cfw.setStackTop((short) 0); - - int local = getLocalBlockRegister(node); - int scopeIndex - = node.getExistingIntProp(Node.CATCH_SCOPE_PROP); - - String name = child.getString(); // name of exception - child = child.getNext(); - generateExpression(child, node); // load expression object - if (scopeIndex == 0) { - cfw.add(ByteCode.ACONST_NULL); - } else { - // Load previous catch scope object - cfw.addALoad(local); - } - cfw.addPush(name); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - - addScriptRuntimeInvoke( - "newCatchScope", - "(Ljava/lang/Throwable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(local); - } - break; - - case Token.THROW: - generateExpression(child, node); - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - generateThrowJavaScriptException(); - break; - - case Token.RETHROW: - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - cfw.addALoad(getLocalBlockRegister(node)); - cfw.add(ByteCode.ATHROW); - break; - - case Token.RETURN_RESULT: - case Token.RETURN: - if (!isGenerator) { - if (child != null) { - generateExpression(child, node); - } else if (type == Token.RETURN) { - Codegen.pushUndefined(cfw); - } else { - if (popvLocal < 0) throw Codegen.badTree(); - cfw.addALoad(popvLocal); - } - } - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - if (epilogueLabel == -1) { - if (!hasVarsInRegs) throw Codegen.badTree(); - epilogueLabel = cfw.acquireLabel(); - } - cfw.add(ByteCode.GOTO, epilogueLabel); - break; - - case Token.SWITCH: - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - visitSwitch((Node.Jump)node, child); - break; - - case Token.ENTERWITH: - generateExpression(child, node); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke( - "enterWith", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - incReferenceWordLocal(variableObjectLocal); - break; - - case Token.LEAVEWITH: - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke( - "leaveWith", - "(Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - decReferenceWordLocal(variableObjectLocal); - break; - - case Token.ENUM_INIT_KEYS: - case Token.ENUM_INIT_VALUES: - case Token.ENUM_INIT_ARRAY: - generateExpression(child, node); - cfw.addALoad(contextLocal); - int enumType = type == Token.ENUM_INIT_KEYS - ? ScriptRuntime.ENUMERATE_KEYS : - type == Token.ENUM_INIT_VALUES - ? ScriptRuntime.ENUMERATE_VALUES : - ScriptRuntime.ENUMERATE_ARRAY; - cfw.addPush(enumType); - addScriptRuntimeInvoke("enumInit", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"I" - +")Ljava/lang/Object;"); - cfw.addAStore(getLocalBlockRegister(node)); - break; - - case Token.EXPR_VOID: - if (child.getType() == Token.SETVAR) { - /* special case this so as to avoid unnecessary - load's & pop's */ - visitSetVar(child, child.getFirstChild(), false); - } - else if (child.getType() == Token.SETCONSTVAR) { - /* special case this so as to avoid unnecessary - load's & pop's */ - visitSetConstVar(child, child.getFirstChild(), false); - } - else if (child.getType() == Token.YIELD) { - generateYieldPoint(child, false); - } - else { - generateExpression(child, node); - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) - cfw.add(ByteCode.POP2); - else - cfw.add(ByteCode.POP); - } - break; - - case Token.EXPR_RESULT: - generateExpression(child, node); - if (popvLocal < 0) { - popvLocal = getNewWordLocal(); - } - cfw.addAStore(popvLocal); - break; - - case Token.TARGET: - { - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - int label = getTargetLabel(node); - cfw.markLabel(label); - if (compilerEnv.isGenerateObserverCount()) - saveCurrentCodeOffset(); - } - break; - - case Token.JSR: - case Token.GOTO: - case Token.IFEQ: - case Token.IFNE: - if (compilerEnv.isGenerateObserverCount()) - addInstructionCount(); - visitGoto((Node.Jump)node, type, child); - break; - - case Token.FINALLY: - { - if (compilerEnv.isGenerateObserverCount()) - saveCurrentCodeOffset(); - // there is exactly one value on the stack when enterring - // finally blocks: the return address (or its int encoding) - cfw.setStackTop((short)1); - - // Save return address in a new local - int finallyRegister = getNewWordLocal(); - if (isGenerator) - generateIntegerWrap(); - cfw.addAStore(finallyRegister); - - while (child != null) { - generateStatement(child); - child = child.getNext(); - } - if (isGenerator) { - cfw.addALoad(finallyRegister); - cfw.add(ByteCode.CHECKCAST, "java/lang/Integer"); - generateIntegerUnwrap(); - FinallyReturnPoint ret = - (FinallyReturnPoint)finallys.get(node); - ret.tableLabel = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, ret.tableLabel); - } else { - cfw.add(ByteCode.RET, finallyRegister); - } - releaseWordLocal((short)finallyRegister); - } - break; - - case Token.DEBUGGER: - break; - - default: - throw Codegen.badTree(); - } - - } - - private void generateIntegerWrap() - { - cfw.addInvoke(ByteCode.INVOKESTATIC, "java/lang/Integer", "valueOf", - "(I)Ljava/lang/Integer;"); - } - - - private void generateIntegerUnwrap() - { - cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/Integer", - "intValue", "()I"); - } - - - private void generateThrowJavaScriptException() - { - cfw.add(ByteCode.NEW, - "org/mozilla/javascript/JavaScriptException"); - cfw.add(ByteCode.DUP_X1); - cfw.add(ByteCode.SWAP); - cfw.addPush(scriptOrFn.getSourceName()); - cfw.addPush(itsLineNumber); - cfw.addInvoke( - ByteCode.INVOKESPECIAL, - "org/mozilla/javascript/JavaScriptException", - "<init>", - "(Ljava/lang/Object;Ljava/lang/String;I)V"); - cfw.add(ByteCode.ATHROW); - } - - private int getNextGeneratorState(Node node) - { - int nodeIndex = ((FunctionNode)scriptOrFn).getResumptionPoints() - .indexOf(node); - return nodeIndex + GENERATOR_YIELD_START; - } - - private void generateExpression(Node node, Node parent) - { - int type = node.getType(); - Node child = node.getFirstChild(); - switch (type) { - case Token.USE_STACK: - break; - - case Token.FUNCTION: - if (fnCurrent != null || parent.getType() != Token.SCRIPT) { - int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); - OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, - fnIndex); - int t = ofn.fnode.getFunctionType(); - if (t != FunctionNode.FUNCTION_EXPRESSION) { - throw Codegen.badTree(); - } - visitFunction(ofn, t); - } - break; - - case Token.NAME: - { - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - cfw.addPush(node.getString()); - addScriptRuntimeInvoke( - "name", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +")Ljava/lang/Object;"); - } - break; - - case Token.CALL: - case Token.NEW: - { - int specialType = node.getIntProp(Node.SPECIALCALL_PROP, - Node.NON_SPECIALCALL); - if (specialType == Node.NON_SPECIALCALL) { - OptFunctionNode target; - target = (OptFunctionNode)node.getProp( - Node.DIRECTCALL_PROP); - - if (target != null) { - visitOptimizedCall(node, target, type, child); - } else if (type == Token.CALL) { - visitStandardCall(node, child); - } else { - visitStandardNew(node, child); - } - } else { - visitSpecialCall(node, type, specialType, child); - } - } - break; - - case Token.REF_CALL: - generateFunctionAndThisObj(child, node); - // stack: ... functionObj thisObj - child = child.getNext(); - generateCallArgArray(node, child, false); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "callRef", - "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Ref;"); - break; - - case Token.NUMBER: - { - double num = node.getDouble(); - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) { - cfw.addPush(num); - } else { - codegen.pushNumberAsObject(cfw, num); - } - } - break; - - case Token.STRING: - cfw.addPush(node.getString()); - break; - - case Token.THIS: - cfw.addALoad(thisObjLocal); - break; - - case Token.THISFN: - cfw.add(ByteCode.ALOAD_0); - break; - - case Token.NULL: - cfw.add(ByteCode.ACONST_NULL); - break; - - case Token.TRUE: - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "TRUE", "Ljava/lang/Boolean;"); - break; - - case Token.FALSE: - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "FALSE", "Ljava/lang/Boolean;"); - break; - - case Token.REGEXP: - { - int i = node.getExistingIntProp(Node.REGEXP_PROP); - // Scripts can not use REGEXP_ARRAY_FIELD_NAME since - // it it will make script.exec non-reentrant so they - // store regexp array in a local variable while - // functions always access precomputed - // REGEXP_ARRAY_FIELD_NAME not to consume locals - if (fnCurrent == null) { - cfw.addALoad(scriptRegexpLocal); - } else { - cfw.addALoad(funObjLocal); - cfw.add(ByteCode.GETFIELD, codegen.mainClassName, - Codegen.REGEXP_ARRAY_FIELD_NAME, - Codegen.REGEXP_ARRAY_FIELD_TYPE); - } - cfw.addPush(i); - cfw.add(ByteCode.AALOAD); - } - break; - - case Token.COMMA: { - Node next = child.getNext(); - while (next != null) { - generateExpression(child, node); - cfw.add(ByteCode.POP); - child = next; - next = next.getNext(); - } - generateExpression(child, node); - break; - } - - case Token.ENUM_NEXT: - case Token.ENUM_ID: { - int local = getLocalBlockRegister(node); - cfw.addALoad(local); - if (type == Token.ENUM_NEXT) { - addScriptRuntimeInvoke( - "enumNext", "(Ljava/lang/Object;)Ljava/lang/Boolean;"); - } else { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("enumId", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - break; - } - - case Token.ARRAYLIT: - visitArrayLiteral(node, child); - break; - - case Token.OBJECTLIT: - visitObjectLiteral(node, child); - break; - - case Token.NOT: { - int trueTarget = cfw.acquireLabel(); - int falseTarget = cfw.acquireLabel(); - int beyond = cfw.acquireLabel(); - generateIfJump(child, node, trueTarget, falseTarget); - - cfw.markLabel(trueTarget); - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "FALSE", "Ljava/lang/Boolean;"); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(falseTarget); - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "TRUE", "Ljava/lang/Boolean;"); - cfw.markLabel(beyond); - cfw.adjustStackTop(-1); - break; - } - - case Token.BITNOT: - generateExpression(child, node); - addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I"); - cfw.addPush(-1); // implement ~a as (a ^ -1) - cfw.add(ByteCode.IXOR); - cfw.add(ByteCode.I2D); - addDoubleWrap(); - break; - - case Token.VOID: - generateExpression(child, node); - cfw.add(ByteCode.POP); - Codegen.pushUndefined(cfw); - break; - - case Token.TYPEOF: - generateExpression(child, node); - addScriptRuntimeInvoke("typeof", - "(Ljava/lang/Object;" - +")Ljava/lang/String;"); - break; - - case Token.TYPEOFNAME: - visitTypeofname(node); - break; - - case Token.INC: - case Token.DEC: - visitIncDec(node); - break; - - case Token.OR: - case Token.AND: { - generateExpression(child, node); - cfw.add(ByteCode.DUP); - addScriptRuntimeInvoke("toBoolean", - "(Ljava/lang/Object;)Z"); - int falseTarget = cfw.acquireLabel(); - if (type == Token.AND) - cfw.add(ByteCode.IFEQ, falseTarget); - else - cfw.add(ByteCode.IFNE, falseTarget); - cfw.add(ByteCode.POP); - generateExpression(child.getNext(), node); - cfw.markLabel(falseTarget); - } - break; - - case Token.HOOK : { - Node ifThen = child.getNext(); - Node ifElse = ifThen.getNext(); - generateExpression(child, node); - addScriptRuntimeInvoke("toBoolean", - "(Ljava/lang/Object;)Z"); - int elseTarget = cfw.acquireLabel(); - cfw.add(ByteCode.IFEQ, elseTarget); - short stack = cfw.getStackTop(); - generateExpression(ifThen, node); - int afterHook = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, afterHook); - cfw.markLabel(elseTarget, stack); - generateExpression(ifElse, node); - cfw.markLabel(afterHook); - } - break; - - case Token.ADD: { - generateExpression(child, node); - generateExpression(child.getNext(), node); - switch (node.getIntProp(Node.ISNUMBER_PROP, -1)) { - case Node.BOTH: - cfw.add(ByteCode.DADD); - break; - case Node.LEFT: - addOptRuntimeInvoke("add", - "(DLjava/lang/Object;)Ljava/lang/Object;"); - break; - case Node.RIGHT: - addOptRuntimeInvoke("add", - "(Ljava/lang/Object;D)Ljava/lang/Object;"); - break; - default: - if (child.getType() == Token.STRING) { - addScriptRuntimeInvoke("add", - "(Ljava/lang/String;" - +"Ljava/lang/Object;" - +")Ljava/lang/String;"); - } else if (child.getNext().getType() == Token.STRING) { - addScriptRuntimeInvoke("add", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +")Ljava/lang/String;"); - } else { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("add", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - } - } - break; - - case Token.MUL: - visitArithmetic(node, ByteCode.DMUL, child, parent); - break; - - case Token.SUB: - visitArithmetic(node, ByteCode.DSUB, child, parent); - break; - - case Token.DIV: - case Token.MOD: - visitArithmetic(node, type == Token.DIV - ? ByteCode.DDIV - : ByteCode.DREM, child, parent); - break; - - case Token.BITOR: - case Token.BITXOR: - case Token.BITAND: - case Token.LSH: - case Token.RSH: - case Token.URSH: - visitBitOp(node, type, child); - break; - - case Token.POS: - case Token.NEG: - generateExpression(child, node); - addObjectToDouble(); - if (type == Token.NEG) { - cfw.add(ByteCode.DNEG); - } - addDoubleWrap(); - break; - - case Token.TO_DOUBLE: - // cnvt to double (not Double) - generateExpression(child, node); - addObjectToDouble(); - break; - - case Token.TO_OBJECT: { - // convert from double - int prop = -1; - if (child.getType() == Token.NUMBER) { - prop = child.getIntProp(Node.ISNUMBER_PROP, -1); - } - if (prop != -1) { - child.removeProp(Node.ISNUMBER_PROP); - generateExpression(child, node); - child.putIntProp(Node.ISNUMBER_PROP, prop); - } else { - generateExpression(child, node); - addDoubleWrap(); - } - break; - } - - case Token.IN: - case Token.INSTANCEOF: - case Token.LE: - case Token.LT: - case Token.GE: - case Token.GT: { - int trueGOTO = cfw.acquireLabel(); - int falseGOTO = cfw.acquireLabel(); - visitIfJumpRelOp(node, child, trueGOTO, falseGOTO); - addJumpedBooleanWrap(trueGOTO, falseGOTO); - break; - } - - case Token.EQ: - case Token.NE: - case Token.SHEQ: - case Token.SHNE: { - int trueGOTO = cfw.acquireLabel(); - int falseGOTO = cfw.acquireLabel(); - visitIfJumpEqOp(node, child, trueGOTO, falseGOTO); - addJumpedBooleanWrap(trueGOTO, falseGOTO); - break; - } - - case Token.GETPROP: - case Token.GETPROPNOWARN: - visitGetProp(node, child); - break; - - case Token.GETELEM: - generateExpression(child, node); // object - generateExpression(child.getNext(), node); // id - cfw.addALoad(contextLocal); - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) { - addScriptRuntimeInvoke( - "getObjectIndex", - "(Ljava/lang/Object;D" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - else { - addScriptRuntimeInvoke( - "getObjectElem", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - break; - - case Token.GET_REF: - generateExpression(child, node); // reference - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "refGet", - "(Lorg/mozilla/javascript/Ref;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - break; - - case Token.GETVAR: - visitGetVar(node); - break; - - case Token.SETVAR: - visitSetVar(node, child, true); - break; - - case Token.SETNAME: - visitSetName(node, child); - break; - - case Token.SETCONST: - visitSetConst(node, child); - break; - - case Token.SETCONSTVAR: - visitSetConstVar(node, child, true); - break; - - case Token.SETPROP: - case Token.SETPROP_OP: - visitSetProp(type, node, child); - break; - - case Token.SETELEM: - case Token.SETELEM_OP: - visitSetElem(type, node, child); - break; - - case Token.SET_REF: - case Token.SET_REF_OP: - { - generateExpression(child, node); - child = child.getNext(); - if (type == Token.SET_REF_OP) { - cfw.add(ByteCode.DUP); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "refGet", - "(Lorg/mozilla/javascript/Ref;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "refSet", - "(Lorg/mozilla/javascript/Ref;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - break; - - case Token.DEL_REF: - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("refDel", - "(Lorg/mozilla/javascript/Ref;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - break; - - case Token.DELPROP: - generateExpression(child, node); - child = child.getNext(); - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("delete", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - break; - - case Token.BINDNAME: - { - while (child != null) { - generateExpression(child, node); - child = child.getNext(); - } - // Generate code for "ScriptRuntime.bind(varObj, "s")" - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - cfw.addPush(node.getString()); - addScriptRuntimeInvoke( - "bind", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +")Lorg/mozilla/javascript/Scriptable;"); - } - break; - - case Token.LOCAL_LOAD: - cfw.addALoad(getLocalBlockRegister(node)); - break; - - case Token.REF_SPECIAL: - { - String special = (String)node.getProp(Node.NAME_PROP); - generateExpression(child, node); - cfw.addPush(special); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "specialRef", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Ref;"); - } - 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 - do { - generateExpression(child, node); - child = child.getNext(); - } while (child != null); - cfw.addALoad(contextLocal); - String methodName, signature; - switch (type) { - case Token.REF_MEMBER: - methodName = "memberRef"; - signature = "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"I" - +")Lorg/mozilla/javascript/Ref;"; - break; - case Token.REF_NS_MEMBER: - methodName = "memberRef"; - signature = "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"I" - +")Lorg/mozilla/javascript/Ref;"; - break; - case Token.REF_NAME: - methodName = "nameRef"; - signature = "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"I" - +")Lorg/mozilla/javascript/Ref;"; - cfw.addALoad(variableObjectLocal); - break; - case Token.REF_NS_NAME: - methodName = "nameRef"; - signature = "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"I" - +")Lorg/mozilla/javascript/Ref;"; - cfw.addALoad(variableObjectLocal); - break; - default: - throw Kit.codeBug(); - } - cfw.addPush(memberTypeFlags); - addScriptRuntimeInvoke(methodName, signature); - } - break; - - case Token.DOTQUERY: - visitDotQuery(node, child); - break; - - case Token.ESCXMLATTR: - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("escapeAttributeValue", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/String;"); - break; - - case Token.ESCXMLTEXT: - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("escapeTextValue", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/String;"); - break; - - case Token.DEFAULTNAMESPACE: - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke("setDefaultNamespace", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - break; - - case Token.YIELD: - generateYieldPoint(node, true); - break; - - case Token.WITHEXPR: { - Node enterWith = child; - Node with = enterWith.getNext(); - Node leaveWith = with.getNext(); - generateStatement(enterWith); - generateExpression(with.getFirstChild(), with); - generateStatement(leaveWith); - break; - } - - case Token.ARRAYCOMP: { - Node initStmt = child; - Node expr = child.getNext(); - generateStatement(initStmt); - generateExpression(expr, node); - break; - } - - default: - throw new RuntimeException("Unexpected node type "+type); - } - - } - - private void generateYieldPoint(Node node, boolean exprContext) { - // save stack state - int top = cfw.getStackTop(); - maxStack = maxStack > top ? maxStack : top; - if (cfw.getStackTop() != 0) { - generateGetGeneratorStackState(); - for (int i = 0; i < top; i++) { - cfw.add(ByteCode.DUP_X1); - cfw.add(ByteCode.SWAP); - cfw.addLoadConstant(i); - cfw.add(ByteCode.SWAP); - cfw.add(ByteCode.AASTORE); - } - // pop the array object - cfw.add(ByteCode.POP); - } - - // generate the yield argument - Node child = node.getFirstChild(); - if (child != null) - generateExpression(child, node); - else - Codegen.pushUndefined(cfw); - - // change the resumption state - int nextState = getNextGeneratorState(node); - generateSetGeneratorResumptionPoint(nextState); - - boolean hasLocals = generateSaveLocals(node); - - cfw.add(ByteCode.ARETURN); - - generateCheckForThrowOrClose(getTargetLabel(node), - hasLocals, nextState); - - // reconstruct the stack - if (top != 0) { - generateGetGeneratorStackState(); - for (int i = 0; i < top; i++) { - cfw.add(ByteCode.DUP); - cfw.addLoadConstant(top - i - 1); - cfw.add(ByteCode.AALOAD); - cfw.add(ByteCode.SWAP); - } - cfw.add(ByteCode.POP); - } - - // load return value from yield - if (exprContext) { - cfw.addALoad(argsLocal); - } - } - - private void generateCheckForThrowOrClose(int label, - boolean hasLocals, - int nextState) { - int throwLabel = cfw.acquireLabel(); - int closeLabel = cfw.acquireLabel(); - - // throw the user provided object, if the operation is .throw() - cfw.markLabel(throwLabel); - cfw.addALoad(argsLocal); - generateThrowJavaScriptException(); - - // throw our special internal exception if the generator is being closed - cfw.markLabel(closeLabel); - cfw.addALoad(argsLocal); - cfw.add(ByteCode.CHECKCAST, "java/lang/Throwable"); - cfw.add(ByteCode.ATHROW); - - // mark the re-entry point - // jump here after initializing the locals - if (label != -1) - cfw.markLabel(label); - if (!hasLocals) { - // jump here directly if there are no locals - cfw.markTableSwitchCase(generatorSwitch, nextState); - } - - // see if we need to dispatch for .close() or .throw() - cfw.addILoad(operationLocal); - cfw.addLoadConstant(NativeGenerator.GENERATOR_CLOSE); - cfw.add(ByteCode.IF_ICMPEQ, closeLabel); - cfw.addILoad(operationLocal); - cfw.addLoadConstant(NativeGenerator.GENERATOR_THROW); - cfw.add(ByteCode.IF_ICMPEQ, throwLabel); - } - - private void generateIfJump(Node node, Node parent, - int trueLabel, int falseLabel) - { - // System.out.println("gen code for " + node.toString()); - - int type = node.getType(); - Node child = node.getFirstChild(); - - switch (type) { - case Token.NOT: - generateIfJump(child, node, falseLabel, trueLabel); - break; - - case Token.OR: - case Token.AND: { - int interLabel = cfw.acquireLabel(); - if (type == Token.AND) { - generateIfJump(child, node, interLabel, falseLabel); - } - else { - generateIfJump(child, node, trueLabel, interLabel); - } - cfw.markLabel(interLabel); - child = child.getNext(); - generateIfJump(child, node, trueLabel, falseLabel); - break; - } - - case Token.IN: - case Token.INSTANCEOF: - case Token.LE: - case Token.LT: - case Token.GE: - case Token.GT: - visitIfJumpRelOp(node, child, trueLabel, falseLabel); - break; - - case Token.EQ: - case Token.NE: - case Token.SHEQ: - case Token.SHNE: - visitIfJumpEqOp(node, child, trueLabel, falseLabel); - break; - - default: - // Generate generic code for non-optimized jump - generateExpression(node, parent); - addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z"); - cfw.add(ByteCode.IFNE, trueLabel); - cfw.add(ByteCode.GOTO, falseLabel); - } - } - - private void visitFunction(OptFunctionNode ofn, int functionType) - { - int fnIndex = codegen.getIndex(ofn.fnode); - cfw.add(ByteCode.NEW, codegen.mainClassName); - // Call function constructor - cfw.add(ByteCode.DUP); - cfw.addALoad(variableObjectLocal); - cfw.addALoad(contextLocal); // load 'cx' - cfw.addPush(fnIndex); - cfw.addInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName, - "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE); - - // Init mainScript field; - cfw.add(ByteCode.DUP); - if (isTopLevel) { - cfw.add(ByteCode.ALOAD_0); - } else { - cfw.add(ByteCode.ALOAD_0); - cfw.add(ByteCode.GETFIELD, - codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - } - cfw.add(ByteCode.PUTFIELD, - codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - - int directTargetIndex = ofn.getDirectTargetIndex(); - if (directTargetIndex >= 0) { - cfw.add(ByteCode.DUP); - if (isTopLevel) { - cfw.add(ByteCode.ALOAD_0); - } else { - cfw.add(ByteCode.ALOAD_0); - cfw.add(ByteCode.GETFIELD, - codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - } - cfw.add(ByteCode.SWAP); - cfw.add(ByteCode.PUTFIELD, - codegen.mainClassName, - Codegen.getDirectTargetFieldName(directTargetIndex), - codegen.mainClassSignature); - } - - if (functionType == FunctionNode.FUNCTION_EXPRESSION) { - // Leave closure object on stack and do not pass it to - // initFunction which suppose to connect statements to scope - return; - } - cfw.addPush(functionType); - cfw.addALoad(variableObjectLocal); - cfw.addALoad(contextLocal); // load 'cx' - addOptRuntimeInvoke("initFunction", - "(Lorg/mozilla/javascript/NativeFunction;" - +"I" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Context;" - +")V"); - } - - private int getTargetLabel(Node target) - { - int labelId = target.labelId(); - if (labelId == -1) { - labelId = cfw.acquireLabel(); - target.labelId(labelId); - } - return labelId; - } - - private void visitGoto(Node.Jump node, int type, Node child) - { - Node target = node.target; - if (type == Token.IFEQ || type == Token.IFNE) { - if (child == null) throw Codegen.badTree(); - int targetLabel = getTargetLabel(target); - int fallThruLabel = cfw.acquireLabel(); - if (type == Token.IFEQ) - generateIfJump(child, node, targetLabel, fallThruLabel); - else - generateIfJump(child, node, fallThruLabel, targetLabel); - cfw.markLabel(fallThruLabel); - } else { - if (type == Token.JSR) { - if (isGenerator) { - addGotoWithReturn(target); - } else { - addGoto(target, ByteCode.JSR); - } - } else { - addGoto(target, ByteCode.GOTO); - } - } - } - - private void addGotoWithReturn(Node target) { - FinallyReturnPoint ret = - (FinallyReturnPoint)finallys.get(target); - cfw.addLoadConstant(ret.jsrPoints.size()); - addGoto(target, ByteCode.GOTO); - int retLabel = cfw.acquireLabel(); - cfw.markLabel(retLabel); - ret.jsrPoints.add(Integer.valueOf(retLabel)); - } - - private void visitArrayLiteral(Node node, Node child) - { - int count = 0; - for (Node cursor = child; cursor != null; cursor = cursor.getNext()) { - ++count; - } - // load array to store array literal objects - addNewObjectArray(count); - for (int i = 0; i != count; ++i) { - cfw.add(ByteCode.DUP); - cfw.addPush(i); - generateExpression(child, node); - cfw.add(ByteCode.AASTORE); - child = child.getNext(); - } - int[] skipIndexes = (int[])node.getProp(Node.SKIP_INDEXES_PROP); - if (skipIndexes == null) { - cfw.add(ByteCode.ACONST_NULL); - cfw.add(ByteCode.ICONST_0); - } else { - cfw.addPush(OptRuntime.encodeIntArray(skipIndexes)); - cfw.addPush(skipIndexes.length); - } - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addOptRuntimeInvoke("newArrayLiteral", - "([Ljava/lang/Object;" - +"Ljava/lang/String;" - +"I" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - } - - private void visitObjectLiteral(Node node, Node child) - { - Object[] properties = (Object[])node.getProp(Node.OBJECT_IDS_PROP); - int count = properties.length; - - // load array with property ids - addNewObjectArray(count); - for (int i = 0; i != count; ++i) { - cfw.add(ByteCode.DUP); - cfw.addPush(i); - Object id = properties[i]; - if (id instanceof String) { - cfw.addPush((String)id); - } else { - cfw.addPush(((Integer)id).intValue()); - addScriptRuntimeInvoke("wrapInt", "(I)Ljava/lang/Integer;"); - } - cfw.add(ByteCode.AASTORE); - } - // load array with property values - addNewObjectArray(count); - Node child2 = child; - for (int i = 0; i != count; ++i) { - cfw.add(ByteCode.DUP); - cfw.addPush(i); - int childType = child.getType(); - if (childType == Token.GET) { - generateExpression(child.getFirstChild(), node); - } else if (childType == Token.SET) { - generateExpression(child.getFirstChild(), node); - } else { - generateExpression(child, node); - } - cfw.add(ByteCode.AASTORE); - child = child.getNext(); - } - // load array with getterSetter values - cfw.addPush(count); - cfw.add(ByteCode.NEWARRAY, ByteCode.T_INT); - for (int i = 0; i != count; ++i) { - cfw.add(ByteCode.DUP); - cfw.addPush(i); - int childType = child2.getType(); - if (childType == Token.GET) { - cfw.add(ByteCode.ICONST_M1); - } else if (childType == Token.SET) { - cfw.add(ByteCode.ICONST_1); - } else { - cfw.add(ByteCode.ICONST_0); - } - cfw.add(ByteCode.IASTORE); - child2 = child2.getNext(); - } - - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke("newObjectLiteral", - "([Ljava/lang/Object;" - +"[Ljava/lang/Object;" - +"[I" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - } - - private void visitSpecialCall(Node node, int type, int specialType, - Node child) - { - cfw.addALoad(contextLocal); - - if (type == Token.NEW) { - generateExpression(child, node); - // stack: ... cx functionObj - } else { - generateFunctionAndThisObj(child, node); - // stack: ... cx functionObj thisObj - } - child = child.getNext(); - - generateCallArgArray(node, child, false); - - String methodName; - String callSignature; - - if (type == Token.NEW) { - methodName = "newObjectSpecial"; - callSignature = "(Lorg/mozilla/javascript/Context;" - +"Ljava/lang/Object;" - +"[Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"I" // call type - +")Ljava/lang/Object;"; - cfw.addALoad(variableObjectLocal); - cfw.addALoad(thisObjLocal); - cfw.addPush(specialType); - } else { - methodName = "callSpecial"; - callSignature = "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"I" // call type - +"Ljava/lang/String;I" // filename, linenumber - +")Ljava/lang/Object;"; - cfw.addALoad(variableObjectLocal); - cfw.addALoad(thisObjLocal); - cfw.addPush(specialType); - String sourceName = scriptOrFn.getSourceName(); - cfw.addPush(sourceName == null ? "" : sourceName); - cfw.addPush(itsLineNumber); - } - - addOptRuntimeInvoke(methodName, callSignature); - } - - private void visitStandardCall(Node node, Node child) - { - if (node.getType() != Token.CALL) throw Codegen.badTree(); - - Node firstArgChild = child.getNext(); - int childType = child.getType(); - - String methodName; - String signature; - - if (firstArgChild == null) { - if (childType == Token.NAME) { - // name() call - String name = child.getString(); - cfw.addPush(name); - methodName = "callName0"; - signature = "(Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } else if (childType == Token.GETPROP) { - // x.name() call - Node propTarget = child.getFirstChild(); - generateExpression(propTarget, node); - Node id = propTarget.getNext(); - String property = id.getString(); - cfw.addPush(property); - methodName = "callProp0"; - signature = "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } else if (childType == Token.GETPROPNOWARN) { - throw Kit.codeBug(); - } else { - generateFunctionAndThisObj(child, node); - methodName = "call0"; - signature = "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } - - } else if (childType == Token.NAME) { - // XXX: this optimization is only possible if name - // resolution - // is not affected by arguments evaluation and currently - // there are no checks for it - String name = child.getString(); - generateCallArgArray(node, firstArgChild, false); - cfw.addPush(name); - methodName = "callName"; - signature = "([Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } else { - int argCount = 0; - for (Node arg = firstArgChild; arg != null; arg = arg.getNext()) { - ++argCount; - } - generateFunctionAndThisObj(child, node); - // stack: ... functionObj thisObj - if (argCount == 1) { - generateExpression(firstArgChild, node); - methodName = "call1"; - signature = "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } else if (argCount == 2) { - generateExpression(firstArgChild, node); - generateExpression(firstArgChild.getNext(), node); - methodName = "call2"; - signature = "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } else { - generateCallArgArray(node, firstArgChild, false); - methodName = "callN"; - signature = "(Lorg/mozilla/javascript/Callable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"; - } - } - - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addOptRuntimeInvoke(methodName, signature); - } - - private void visitStandardNew(Node node, Node child) - { - if (node.getType() != Token.NEW) throw Codegen.badTree(); - - Node firstArgChild = child.getNext(); - - generateExpression(child, node); - // stack: ... functionObj - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - // stack: ... functionObj cx scope - generateCallArgArray(node, firstArgChild, false); - addScriptRuntimeInvoke( - "newObject", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Lorg/mozilla/javascript/Scriptable;"); - } - - private void visitOptimizedCall(Node node, OptFunctionNode target, - int type, Node child) - { - Node firstArgChild = child.getNext(); - - short thisObjLocal = 0; - if (type == Token.NEW) { - generateExpression(child, node); - } else { - generateFunctionAndThisObj(child, node); - thisObjLocal = getNewWordLocal(); - cfw.addAStore(thisObjLocal); - } - // stack: ... functionObj - - int beyond = cfw.acquireLabel(); - - int directTargetIndex = target.getDirectTargetIndex(); - if (isTopLevel) { - cfw.add(ByteCode.ALOAD_0); - } else { - cfw.add(ByteCode.ALOAD_0); - cfw.add(ByteCode.GETFIELD, codegen.mainClassName, - Codegen.DIRECT_CALL_PARENT_FIELD, - codegen.mainClassSignature); - } - cfw.add(ByteCode.GETFIELD, codegen.mainClassName, - Codegen.getDirectTargetFieldName(directTargetIndex), - codegen.mainClassSignature); - - cfw.add(ByteCode.DUP2); - // stack: ... functionObj directFunct functionObj directFunct - - int regularCall = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPNE, regularCall); - - // stack: ... functionObj directFunct - short stackHeight = cfw.getStackTop(); - cfw.add(ByteCode.SWAP); - cfw.add(ByteCode.POP); - // stack: ... directFunct - if (compilerEnv.isUseDynamicScope()) { - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - } else { - cfw.add(ByteCode.DUP); - // stack: ... directFunct directFunct - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/Scriptable", - "getParentScope", - "()Lorg/mozilla/javascript/Scriptable;"); - // stack: ... directFunct scope - cfw.addALoad(contextLocal); - // stack: ... directFunct scope cx - cfw.add(ByteCode.SWAP); - } - // stack: ... directFunc cx scope - - if (type == Token.NEW) { - cfw.add(ByteCode.ACONST_NULL); - } else { - cfw.addALoad(thisObjLocal); - } - // stack: ... directFunc cx scope thisObj -/* -Remember that directCall parameters are paired in 1 aReg and 1 dReg -If the argument is an incoming arg, just pass the orginal pair thru. -Else, if the argument is known to be typed 'Number', pass Void.TYPE -in the aReg and the number is the dReg -Else pass the JS object in the aReg and 0.0 in the dReg. -*/ - Node argChild = firstArgChild; - while (argChild != null) { - int dcp_register = nodeIsDirectCallParameter(argChild); - if (dcp_register >= 0) { - cfw.addALoad(dcp_register); - cfw.addDLoad(dcp_register + 1); - } else if (argChild.getIntProp(Node.ISNUMBER_PROP, -1) - == Node.BOTH) - { - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - generateExpression(argChild, node); - } else { - generateExpression(argChild, node); - cfw.addPush(0.0); - } - argChild = argChild.getNext(); - } - - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/ScriptRuntime", - "emptyArgs", "[Ljava/lang/Object;"); - cfw.addInvoke(ByteCode.INVOKESTATIC, - codegen.mainClassName, - (type == Token.NEW) - ? codegen.getDirectCtorName(target.fnode) - : codegen.getBodyMethodName(target.fnode), - codegen.getBodyMethodSignature(target.fnode)); - - cfw.add(ByteCode.GOTO, beyond); - - cfw.markLabel(regularCall, stackHeight); - // stack: ... functionObj directFunct - cfw.add(ByteCode.POP); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - // stack: ... functionObj cx scope - if (type != Token.NEW) { - cfw.addALoad(thisObjLocal); - releaseWordLocal(thisObjLocal); - // stack: ... functionObj cx scope thisObj - } - // XXX: this will generate code for the child array the second time, - // so expression code generation better not to alter tree structure... - generateCallArgArray(node, firstArgChild, true); - - if (type == Token.NEW) { - addScriptRuntimeInvoke( - "newObject", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Lorg/mozilla/javascript/Scriptable;"); - } else { - cfw.addInvoke(ByteCode.INVOKEINTERFACE, - "org/mozilla/javascript/Callable", - "call", - "(Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Lorg/mozilla/javascript/Scriptable;" - +"[Ljava/lang/Object;" - +")Ljava/lang/Object;"); - } - - cfw.markLabel(beyond); - } - - private void generateCallArgArray(Node node, Node argChild, boolean directCall) - { - int argCount = 0; - for (Node child = argChild; child != null; child = child.getNext()) { - ++argCount; - } - // load array object to set arguments - if (argCount == 1 && itsOneArgArray >= 0) { - cfw.addALoad(itsOneArgArray); - } else { - addNewObjectArray(argCount); - } - // Copy arguments into it - for (int i = 0; i != argCount; ++i) { - // If we are compiling a generator an argument could be the result - // of a yield. In that case we will have an immediate on the stack - // which we need to avoid - if (!isGenerator) { - cfw.add(ByteCode.DUP); - cfw.addPush(i); - } - - if (!directCall) { - generateExpression(argChild, node); - } else { - // If this has also been a directCall sequence, the Number - // flag will have remained set for any parameter so that - // the values could be copied directly into the outgoing - // args. Here we want to force it to be treated as not in - // a Number context, so we set the flag off. - int dcp_register = nodeIsDirectCallParameter(argChild); - if (dcp_register >= 0) { - dcpLoadAsObject(dcp_register); - } else { - generateExpression(argChild, node); - int childNumberFlag - = argChild.getIntProp(Node.ISNUMBER_PROP, -1); - if (childNumberFlag == Node.BOTH) { - addDoubleWrap(); - } - } - } - - // When compiling generators, any argument to a method may be a - // yield expression. Hence we compile the argument first and then - // load the argument index and assign the value to the args array. - if (isGenerator) { - short tempLocal = getNewWordLocal(); - cfw.addAStore(tempLocal); - cfw.add(ByteCode.CHECKCAST, "[Ljava/lang/Object;"); - cfw.add(ByteCode.DUP); - cfw.addPush(i); - cfw.addALoad(tempLocal); - releaseWordLocal(tempLocal); - } - - cfw.add(ByteCode.AASTORE); - - argChild = argChild.getNext(); - } - } - - private void generateFunctionAndThisObj(Node node, Node parent) - { - // Place on stack (function object, function this) pair - int type = node.getType(); - switch (node.getType()) { - case Token.GETPROPNOWARN: - throw Kit.codeBug(); - - case Token.GETPROP: - case Token.GETELEM: { - Node target = node.getFirstChild(); - generateExpression(target, node); - Node id = target.getNext(); - if (type == Token.GETPROP) { - String property = id.getString(); - cfw.addPush(property); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getPropFunctionAndThis", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Callable;"); - } else { - // Optimizer do not optimize this case for now - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) - throw Codegen.badTree(); - generateExpression(id, node); // id - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getElemFunctionAndThis", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Callable;"); - } - break; - } - - case Token.NAME: { - String name = node.getString(); - cfw.addPush(name); - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke( - "getNameFunctionAndThis", - "(Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Callable;"); - break; - } - - default: // including GETVAR - generateExpression(node, parent); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getValueFunctionAndThis", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Callable;"); - break; - } - // Get thisObj prepared by get(Name|Prop|Elem|Value)FunctionAndThis - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "lastStoredScriptable", - "(Lorg/mozilla/javascript/Context;" - +")Lorg/mozilla/javascript/Scriptable;"); - } - - private void updateLineNumber(Node node) - { - itsLineNumber = node.getLineno(); - if (itsLineNumber == -1) - return; - cfw.addLineNumberEntry((short)itsLineNumber); - } - - private void visitTryCatchFinally(Node.Jump node, Node child) - { - /* Save the variable object, in case there are with statements - * enclosed by the try block and we catch some exception. - * We'll restore it for the catch block so that catch block - * statements get the right scope. - */ - - // OPT we only need to do this if there are enclosed WITH - // statements; could statically check and omit this if there aren't any. - - // XXX OPT Maybe instead do syntactic transforms to associate - // each 'with' with a try/finally block that does the exitwith. - - short savedVariableObject = getNewWordLocal(); - cfw.addALoad(variableObjectLocal); - cfw.addAStore(savedVariableObject); - - /* - * Generate the code for the tree; most of the work is done in IRFactory - * and NodeTransformer; Codegen just adds the java handlers for the - * javascript catch and finally clauses. */ - - int startLabel = cfw.acquireLabel(); - cfw.markLabel(startLabel, (short)0); - - Node catchTarget = node.target; - Node finallyTarget = node.getFinally(); - - // create a table for the equivalent of JSR returns - if (isGenerator && finallyTarget != null) { - FinallyReturnPoint ret = new FinallyReturnPoint(); - if (finallys == null) { - finallys = new Hashtable(); - } - // add the finally target to hashtable - finallys.put(finallyTarget, ret); - // add the finally node as well to the hash table - finallys.put(finallyTarget.getNext(), ret); - } - - while (child != null) { - generateStatement(child); - child = child.getNext(); - } - - // control flow skips the handlers - int realEnd = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, realEnd); - - int exceptionLocal = getLocalBlockRegister(node); - // javascript handler; unwrap exception and GOTO to javascript - // catch area. - if (catchTarget != null) { - // get the label to goto - int catchLabel = catchTarget.labelId(); - - generateCatchBlock(JAVASCRIPT_EXCEPTION, savedVariableObject, - catchLabel, startLabel, exceptionLocal); - /* - * catch WrappedExceptions, see if they are wrapped - * JavaScriptExceptions. Otherwise, rethrow. - */ - generateCatchBlock(EVALUATOR_EXCEPTION, savedVariableObject, - catchLabel, startLabel, exceptionLocal); - - /* - we also need to catch EcmaErrors and feed the - associated error object to the handler - */ - generateCatchBlock(ECMAERROR_EXCEPTION, savedVariableObject, - catchLabel, startLabel, exceptionLocal); - - Context cx = Context.getCurrentContext(); - if (cx != null && - cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) - { - generateCatchBlock(THROWABLE_EXCEPTION, savedVariableObject, - catchLabel, startLabel, exceptionLocal); - } - } - - // finally handler; catch all exceptions, store to a local; JSR to - // the finally, then re-throw. - if (finallyTarget != null) { - int finallyHandler = cfw.acquireLabel(); - cfw.markHandler(finallyHandler); - cfw.addAStore(exceptionLocal); - - // reset the variable object local - cfw.addALoad(savedVariableObject); - cfw.addAStore(variableObjectLocal); - - // get the label to JSR to - int finallyLabel = finallyTarget.labelId(); - if (isGenerator) - addGotoWithReturn(finallyTarget); - else - cfw.add(ByteCode.JSR, finallyLabel); - - // rethrow - cfw.addALoad(exceptionLocal); - if (isGenerator) - cfw.add(ByteCode.CHECKCAST, "java/lang/Throwable"); - cfw.add(ByteCode.ATHROW); - - // mark the handler - cfw.addExceptionHandler(startLabel, finallyLabel, - finallyHandler, null); // catch any - } - releaseWordLocal(savedVariableObject); - cfw.markLabel(realEnd); - } - - private static final int JAVASCRIPT_EXCEPTION = 0; - private static final int EVALUATOR_EXCEPTION = 1; - private static final int ECMAERROR_EXCEPTION = 2; - private static final int THROWABLE_EXCEPTION = 3; - - private void generateCatchBlock(int exceptionType, - short savedVariableObject, - int catchLabel, int startLabel, - int exceptionLocal) - { - int handler = cfw.acquireLabel(); - cfw.markHandler(handler); - - // MS JVM gets cranky if the exception object is left on the stack - cfw.addAStore(exceptionLocal); - - // reset the variable object local - cfw.addALoad(savedVariableObject); - cfw.addAStore(variableObjectLocal); - - String exceptionName; - if (exceptionType == JAVASCRIPT_EXCEPTION) { - exceptionName = "org/mozilla/javascript/JavaScriptException"; - } else if (exceptionType == EVALUATOR_EXCEPTION) { - exceptionName = "org/mozilla/javascript/EvaluatorException"; - } else if (exceptionType == ECMAERROR_EXCEPTION) { - exceptionName = "org/mozilla/javascript/EcmaError"; - } else if (exceptionType == THROWABLE_EXCEPTION) { - exceptionName = "java/lang/Throwable"; - } else { - throw Kit.codeBug(); - } - - // mark the handler - cfw.addExceptionHandler(startLabel, catchLabel, handler, - exceptionName); - - cfw.add(ByteCode.GOTO, catchLabel); - } - - - private boolean generateSaveLocals(Node node) - { - int count = 0; - for (int i = 0; i < firstFreeLocal; i++) { - if (locals[i] != 0) - count++; - } - - if (count == 0) { - ((FunctionNode)scriptOrFn).addLiveLocals(node, null); - return false; - } - - // calculate the max locals - maxLocals = maxLocals > count ? maxLocals : count; - - // create a locals list - int[] ls = new int[count]; - int s = 0; - for (int i = 0; i < firstFreeLocal; i++) { - if (locals[i] != 0) { - ls[s] = i; - s++; - } - } - - // save the locals - ((FunctionNode)scriptOrFn).addLiveLocals(node, ls); - - // save locals - generateGetGeneratorLocalsState(); - for (int i = 0; i < count; i++) { - cfw.add(ByteCode.DUP); - cfw.addLoadConstant(i); - cfw.addALoad(ls[i]); - cfw.add(ByteCode.AASTORE); - } - // pop the array off the stack - cfw.add(ByteCode.POP); - - return true; - } - - private void visitSwitch(Node.Jump switchNode, Node child) - { - // See comments in IRFactory.createSwitch() for description - // of SWITCH node - - generateExpression(child, switchNode); - // save selector value - short selector = getNewWordLocal(); - cfw.addAStore(selector); - - for (Node.Jump caseNode = (Node.Jump)child.getNext(); - caseNode != null; - caseNode = (Node.Jump)caseNode.getNext()) - { - if (caseNode.getType() != Token.CASE) - throw Codegen.badTree(); - Node test = caseNode.getFirstChild(); - generateExpression(test, caseNode); - cfw.addALoad(selector); - addScriptRuntimeInvoke("shallowEq", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +")Z"); - addGoto(caseNode.target, ByteCode.IFNE); - } - releaseWordLocal(selector); - } - - private void visitTypeofname(Node node) - { - if (hasVarsInRegs) { - int varIndex = fnCurrent.fnode.getIndexForNameNode(node); - if (varIndex >= 0) { - if (fnCurrent.isNumberVar(varIndex)) { - cfw.addPush("number"); - } else if (varIsDirectCallParameter(varIndex)) { - int dcp_register = varRegisters[varIndex]; - cfw.addALoad(dcp_register); - cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE", - "Ljava/lang/Class;"); - int isNumberLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel); - short stack = cfw.getStackTop(); - cfw.addALoad(dcp_register); - addScriptRuntimeInvoke("typeof", - "(Ljava/lang/Object;" - +")Ljava/lang/String;"); - int beyond = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(isNumberLabel, stack); - cfw.addPush("number"); - cfw.markLabel(beyond); - } else { - cfw.addALoad(varRegisters[varIndex]); - addScriptRuntimeInvoke("typeof", - "(Ljava/lang/Object;" - +")Ljava/lang/String;"); - } - return; - } - } - cfw.addALoad(variableObjectLocal); - cfw.addPush(node.getString()); - addScriptRuntimeInvoke("typeofName", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +")Ljava/lang/String;"); - } - - /** - * Save the current code offset. This saved code offset is used to - * compute instruction counts in subsequent calls to - * {@link #addInstructionCount}. - */ - private void saveCurrentCodeOffset() { - savedCodeOffset = cfw.getCurrentCodeOffset(); - } - - /** - * Generate calls to ScriptRuntime.addInstructionCount to keep track of - * executed instructions and call <code>observeInstructionCount()</code> - * if a threshold is exceeded. - */ - private void addInstructionCount() { - int count = cfw.getCurrentCodeOffset() - savedCodeOffset; - if (count == 0) - return; - cfw.addALoad(contextLocal); - cfw.addPush(count); - addScriptRuntimeInvoke("addInstructionCount", - "(Lorg/mozilla/javascript/Context;" - +"I)V"); - } - - private void visitIncDec(Node node) - { - int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP); - Node child = node.getFirstChild(); - switch (child.getType()) { - case Token.GETVAR: - if (!hasVarsInRegs) Kit.codeBug(); - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) { - boolean post = ((incrDecrMask & Node.POST_FLAG) != 0); - int varIndex = fnCurrent.getVarIndex(child); - short reg = varRegisters[varIndex]; - int offset = varIsDirectCallParameter(varIndex) ? 1 : 0; - cfw.addDLoad(reg + offset); - if (post) { - cfw.add(ByteCode.DUP2); - } - cfw.addPush(1.0); - if ((incrDecrMask & Node.DECR_FLAG) == 0) { - cfw.add(ByteCode.DADD); - } else { - cfw.add(ByteCode.DSUB); - } - if (!post) { - cfw.add(ByteCode.DUP2); - } - cfw.addDStore(reg + offset); - } else { - boolean post = ((incrDecrMask & Node.POST_FLAG) != 0); - int varIndex = fnCurrent.getVarIndex(child); - short reg = varRegisters[varIndex]; - cfw.addALoad(reg); - if (post) { - cfw.add(ByteCode.DUP); - } - addObjectToDouble(); - cfw.addPush(1.0); - if ((incrDecrMask & Node.DECR_FLAG) == 0) { - cfw.add(ByteCode.DADD); - } else { - cfw.add(ByteCode.DSUB); - } - addDoubleWrap(); - if (!post) { - cfw.add(ByteCode.DUP); - } - cfw.addAStore(reg); - break; - } - break; - case Token.NAME: - cfw.addALoad(variableObjectLocal); - cfw.addPush(child.getString()); // push name - cfw.addALoad(contextLocal); - cfw.addPush(incrDecrMask); - addScriptRuntimeInvoke("nameIncrDecr", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"I)Ljava/lang/Object;"); - break; - case Token.GETPROPNOWARN: - throw Kit.codeBug(); - case Token.GETPROP: { - Node getPropChild = child.getFirstChild(); - generateExpression(getPropChild, node); - generateExpression(getPropChild.getNext(), node); - cfw.addALoad(contextLocal); - cfw.addPush(incrDecrMask); - addScriptRuntimeInvoke("propIncrDecr", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +"I)Ljava/lang/Object;"); - break; - } - case Token.GETELEM: { - Node elemChild = child.getFirstChild(); - generateExpression(elemChild, node); - generateExpression(elemChild.getNext(), node); - cfw.addALoad(contextLocal); - cfw.addPush(incrDecrMask); - if (elemChild.getNext().getIntProp(Node.ISNUMBER_PROP, -1) != -1) { - addOptRuntimeInvoke("elemIncrDecr", - "(Ljava/lang/Object;" - +"D" - +"Lorg/mozilla/javascript/Context;" - +"I" - +")Ljava/lang/Object;"); - } else { - addScriptRuntimeInvoke("elemIncrDecr", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"I" - +")Ljava/lang/Object;"); - } - break; - } - case Token.GET_REF: { - Node refChild = child.getFirstChild(); - generateExpression(refChild, node); - cfw.addALoad(contextLocal); - cfw.addPush(incrDecrMask); - addScriptRuntimeInvoke( - "refIncrDecr", - "(Lorg/mozilla/javascript/Ref;" - +"Lorg/mozilla/javascript/Context;" - +"I)Ljava/lang/Object;"); - break; - } - default: - Codegen.badTree(); - } - } - - private static boolean isArithmeticNode(Node node) - { - int type = node.getType(); - return (type == Token.SUB) - || (type == Token.MOD) - || (type == Token.DIV) - || (type == Token.MUL); - } - - private void visitArithmetic(Node node, int opCode, Node child, - Node parent) - { - int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1); - if (childNumberFlag != -1) { - generateExpression(child, node); - generateExpression(child.getNext(), node); - cfw.add(opCode); - } - else { - boolean childOfArithmetic = isArithmeticNode(parent); - generateExpression(child, node); - if (!isArithmeticNode(child)) - addObjectToDouble(); - generateExpression(child.getNext(), node); - if (!isArithmeticNode(child.getNext())) - addObjectToDouble(); - cfw.add(opCode); - if (!childOfArithmetic) { - addDoubleWrap(); - } - } - } - - private void visitBitOp(Node node, int type, Node child) - { - int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1); - generateExpression(child, node); - - // special-case URSH; work with the target arg as a long, so - // that we can return a 32-bit unsigned value, and call - // toUint32 instead of toInt32. - if (type == Token.URSH) { - addScriptRuntimeInvoke("toUint32", "(Ljava/lang/Object;)J"); - generateExpression(child.getNext(), node); - addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I"); - // Looks like we need to explicitly mask the shift to 5 bits - - // LUSHR takes 6 bits. - cfw.addPush(31); - cfw.add(ByteCode.IAND); - cfw.add(ByteCode.LUSHR); - cfw.add(ByteCode.L2D); - addDoubleWrap(); - return; - } - if (childNumberFlag == -1) { - addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I"); - generateExpression(child.getNext(), node); - addScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I"); - } - else { - addScriptRuntimeInvoke("toInt32", "(D)I"); - generateExpression(child.getNext(), node); - addScriptRuntimeInvoke("toInt32", "(D)I"); - } - switch (type) { - case Token.BITOR: - cfw.add(ByteCode.IOR); - break; - case Token.BITXOR: - cfw.add(ByteCode.IXOR); - break; - case Token.BITAND: - cfw.add(ByteCode.IAND); - break; - case Token.RSH: - cfw.add(ByteCode.ISHR); - break; - case Token.LSH: - cfw.add(ByteCode.ISHL); - break; - default: - throw Codegen.badTree(); - } - cfw.add(ByteCode.I2D); - if (childNumberFlag == -1) { - addDoubleWrap(); - } - } - - private int nodeIsDirectCallParameter(Node node) - { - if (node.getType() == Token.GETVAR - && inDirectCallFunction && !itsForcedObjectParameters) - { - int varIndex = fnCurrent.getVarIndex(node); - if (fnCurrent.isParameter(varIndex)) { - return varRegisters[varIndex]; - } - } - return -1; - } - - private boolean varIsDirectCallParameter(int varIndex) - { - return fnCurrent.isParameter(varIndex) - && inDirectCallFunction && !itsForcedObjectParameters; - } - - private void genSimpleCompare(int type, int trueGOTO, int falseGOTO) - { - if (trueGOTO == -1) throw Codegen.badTree(); - switch (type) { - case Token.LE : - cfw.add(ByteCode.DCMPG); - cfw.add(ByteCode.IFLE, trueGOTO); - break; - case Token.GE : - cfw.add(ByteCode.DCMPL); - cfw.add(ByteCode.IFGE, trueGOTO); - break; - case Token.LT : - cfw.add(ByteCode.DCMPG); - cfw.add(ByteCode.IFLT, trueGOTO); - break; - case Token.GT : - cfw.add(ByteCode.DCMPL); - cfw.add(ByteCode.IFGT, trueGOTO); - break; - default : - throw Codegen.badTree(); - - } - if (falseGOTO != -1) - cfw.add(ByteCode.GOTO, falseGOTO); - } - - private void visitIfJumpRelOp(Node node, Node child, - int trueGOTO, int falseGOTO) - { - if (trueGOTO == -1 || falseGOTO == -1) throw Codegen.badTree(); - int type = node.getType(); - Node rChild = child.getNext(); - if (type == Token.INSTANCEOF || type == Token.IN) { - generateExpression(child, node); - generateExpression(rChild, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - (type == Token.INSTANCEOF) ? "instanceOf" : "in", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Z"); - cfw.add(ByteCode.IFNE, trueGOTO); - cfw.add(ByteCode.GOTO, falseGOTO); - return; - } - int childNumberFlag = node.getIntProp(Node.ISNUMBER_PROP, -1); - int left_dcp_register = nodeIsDirectCallParameter(child); - int right_dcp_register = nodeIsDirectCallParameter(rChild); - if (childNumberFlag != -1) { - // Force numeric context on both parameters and optimize - // direct call case as Optimizer currently does not handle it - - if (childNumberFlag != Node.RIGHT) { - // Left already has number content - generateExpression(child, node); - } else if (left_dcp_register != -1) { - dcpLoadAsNumber(left_dcp_register); - } else { - generateExpression(child, node); - addObjectToDouble(); - } - - if (childNumberFlag != Node.LEFT) { - // Right already has number content - generateExpression(rChild, node); - } else if (right_dcp_register != -1) { - dcpLoadAsNumber(right_dcp_register); - } else { - generateExpression(rChild, node); - addObjectToDouble(); - } - - genSimpleCompare(type, trueGOTO, falseGOTO); - - } else { - if (left_dcp_register != -1 && right_dcp_register != -1) { - // Generate code to dynamically check for number content - // if both operands are dcp - short stack = cfw.getStackTop(); - int leftIsNotNumber = cfw.acquireLabel(); - cfw.addALoad(left_dcp_register); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - cfw.add(ByteCode.IF_ACMPNE, leftIsNotNumber); - cfw.addDLoad(left_dcp_register + 1); - dcpLoadAsNumber(right_dcp_register); - genSimpleCompare(type, trueGOTO, falseGOTO); - if (stack != cfw.getStackTop()) throw Codegen.badTree(); - - cfw.markLabel(leftIsNotNumber); - int rightIsNotNumber = cfw.acquireLabel(); - cfw.addALoad(right_dcp_register); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - cfw.add(ByteCode.IF_ACMPNE, rightIsNotNumber); - cfw.addALoad(left_dcp_register); - addObjectToDouble(); - cfw.addDLoad(right_dcp_register + 1); - genSimpleCompare(type, trueGOTO, falseGOTO); - if (stack != cfw.getStackTop()) throw Codegen.badTree(); - - cfw.markLabel(rightIsNotNumber); - // Load both register as objects to call generic cmp_* - cfw.addALoad(left_dcp_register); - cfw.addALoad(right_dcp_register); - - } else { - generateExpression(child, node); - generateExpression(rChild, node); - } - - if (type == Token.GE || type == Token.GT) { - cfw.add(ByteCode.SWAP); - } - String routine = ((type == Token.LT) - || (type == Token.GT)) ? "cmp_LT" : "cmp_LE"; - addScriptRuntimeInvoke(routine, - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +")Z"); - cfw.add(ByteCode.IFNE, trueGOTO); - cfw.add(ByteCode.GOTO, falseGOTO); - } - } - - private void visitIfJumpEqOp(Node node, Node child, - int trueGOTO, int falseGOTO) - { - if (trueGOTO == -1 || falseGOTO == -1) throw Codegen.badTree(); - - short stackInitial = cfw.getStackTop(); - int type = node.getType(); - Node rChild = child.getNext(); - - // Optimize if one of operands is null - if (child.getType() == Token.NULL || rChild.getType() == Token.NULL) { - // eq is symmetric in this case - if (child.getType() == Token.NULL) { - child = rChild; - } - generateExpression(child, node); - if (type == Token.SHEQ || type == Token.SHNE) { - int testCode = (type == Token.SHEQ) - ? ByteCode.IFNULL : ByteCode.IFNONNULL; - cfw.add(testCode, trueGOTO); - } else { - if (type != Token.EQ) { - // swap false/true targets for != - if (type != Token.NE) throw Codegen.badTree(); - int tmp = trueGOTO; - trueGOTO = falseGOTO; - falseGOTO = tmp; - } - cfw.add(ByteCode.DUP); - int undefCheckLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IFNONNULL, undefCheckLabel); - short stack = cfw.getStackTop(); - cfw.add(ByteCode.POP); - cfw.add(ByteCode.GOTO, trueGOTO); - cfw.markLabel(undefCheckLabel, stack); - Codegen.pushUndefined(cfw); - cfw.add(ByteCode.IF_ACMPEQ, trueGOTO); - } - cfw.add(ByteCode.GOTO, falseGOTO); - } else { - int child_dcp_register = nodeIsDirectCallParameter(child); - if (child_dcp_register != -1 - && rChild.getType() == Token.TO_OBJECT) - { - Node convertChild = rChild.getFirstChild(); - if (convertChild.getType() == Token.NUMBER) { - cfw.addALoad(child_dcp_register); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - int notNumbersLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPNE, notNumbersLabel); - cfw.addDLoad(child_dcp_register + 1); - cfw.addPush(convertChild.getDouble()); - cfw.add(ByteCode.DCMPL); - if (type == Token.EQ) - cfw.add(ByteCode.IFEQ, trueGOTO); - else - cfw.add(ByteCode.IFNE, trueGOTO); - cfw.add(ByteCode.GOTO, falseGOTO); - cfw.markLabel(notNumbersLabel); - // fall thru into generic handling - } - } - - generateExpression(child, node); - generateExpression(rChild, node); - - String name; - int testCode; - switch (type) { - case Token.EQ: - name = "eq"; - testCode = ByteCode.IFNE; - break; - case Token.NE: - name = "eq"; - testCode = ByteCode.IFEQ; - break; - case Token.SHEQ: - name = "shallowEq"; - testCode = ByteCode.IFNE; - break; - case Token.SHNE: - name = "shallowEq"; - testCode = ByteCode.IFEQ; - break; - default: - throw Codegen.badTree(); - } - addScriptRuntimeInvoke(name, - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +")Z"); - cfw.add(testCode, trueGOTO); - cfw.add(ByteCode.GOTO, falseGOTO); - } - if (stackInitial != cfw.getStackTop()) throw Codegen.badTree(); - } - - private void visitSetName(Node node, Node child) - { - String name = node.getFirstChild().getString(); - while (child != null) { - generateExpression(child, node); - child = child.getNext(); - } - cfw.addALoad(contextLocal); - cfw.addALoad(variableObjectLocal); - cfw.addPush(name); - addScriptRuntimeInvoke( - "setName", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +")Ljava/lang/Object;"); - } - - private void visitSetConst(Node node, Node child) - { - String name = node.getFirstChild().getString(); - while (child != null) { - generateExpression(child, node); - child = child.getNext(); - } - cfw.addALoad(contextLocal); - cfw.addPush(name); - addScriptRuntimeInvoke( - "setConst", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +"Ljava/lang/String;" - +")Ljava/lang/Object;"); - } - - private void visitGetVar(Node node) - { - if (!hasVarsInRegs) Kit.codeBug(); - int varIndex = fnCurrent.getVarIndex(node); - short reg = varRegisters[varIndex]; - if (varIsDirectCallParameter(varIndex)) { - // Remember that here the isNumber flag means that we - // want to use the incoming parameter in a Number - // context, so test the object type and convert the - // value as necessary. - if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) { - dcpLoadAsNumber(reg); - } else { - dcpLoadAsObject(reg); - } - } else if (fnCurrent.isNumberVar(varIndex)) { - cfw.addDLoad(reg); - } else { - cfw.addALoad(reg); - } - } - - private void visitSetVar(Node node, Node child, boolean needValue) - { - if (!hasVarsInRegs) Kit.codeBug(); - int varIndex = fnCurrent.getVarIndex(node); - generateExpression(child.getNext(), node); - boolean isNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1); - short reg = varRegisters[varIndex]; - boolean [] constDeclarations = fnCurrent.fnode.getParamAndVarConst(); - if (constDeclarations[varIndex]) { - if (!needValue) { - if (isNumber) - cfw.add(ByteCode.POP2); - else - cfw.add(ByteCode.POP); - } - } - else if (varIsDirectCallParameter(varIndex)) { - if (isNumber) { - if (needValue) cfw.add(ByteCode.DUP2); - cfw.addALoad(reg); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - int isNumberLabel = cfw.acquireLabel(); - int beyond = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel); - short stack = cfw.getStackTop(); - addDoubleWrap(); - cfw.addAStore(reg); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(isNumberLabel, stack); - cfw.addDStore(reg + 1); - cfw.markLabel(beyond); - } - else { - if (needValue) cfw.add(ByteCode.DUP); - cfw.addAStore(reg); - } - } else { - boolean isNumberVar = fnCurrent.isNumberVar(varIndex); - if (isNumber) { - if (isNumberVar) { - cfw.addDStore(reg); - if (needValue) cfw.addDLoad(reg); - } else { - if (needValue) cfw.add(ByteCode.DUP2); - // Cannot save number in variable since !isNumberVar, - // so convert to object - addDoubleWrap(); - cfw.addAStore(reg); - } - } else { - if (isNumberVar) Kit.codeBug(); - cfw.addAStore(reg); - if (needValue) cfw.addALoad(reg); - } - } - } - - private void visitSetConstVar(Node node, Node child, boolean needValue) - { - if (!hasVarsInRegs) Kit.codeBug(); - int varIndex = fnCurrent.getVarIndex(node); - generateExpression(child.getNext(), node); - boolean isNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1); - short reg = varRegisters[varIndex]; - int beyond = cfw.acquireLabel(); - int noAssign = cfw.acquireLabel(); - if (isNumber) { - cfw.addILoad(reg + 2); - cfw.add(ByteCode.IFNE, noAssign); - short stack = cfw.getStackTop(); - cfw.addPush(1); - cfw.addIStore(reg + 2); - cfw.addDStore(reg); - if (needValue) { - cfw.addDLoad(reg); - cfw.markLabel(noAssign, stack); - } else { - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(noAssign, stack); - cfw.add(ByteCode.POP2); - } - } - else { - cfw.addILoad(reg + 1); - cfw.add(ByteCode.IFNE, noAssign); - short stack = cfw.getStackTop(); - cfw.addPush(1); - cfw.addIStore(reg + 1); - cfw.addAStore(reg); - if (needValue) { - cfw.addALoad(reg); - cfw.markLabel(noAssign, stack); - } else { - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(noAssign, stack); - cfw.add(ByteCode.POP); - } - } - cfw.markLabel(beyond); - } - - private void visitGetProp(Node node, Node child) - { - generateExpression(child, node); // object - Node nameChild = child.getNext(); - generateExpression(nameChild, node); // the name - if (node.getType() == Token.GETPROPNOWARN) { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectPropNoWarn", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - return; - } - /* - for 'this.foo' we call getObjectProp(Scriptable...) which can - skip some casting overhead. - */ - int childType = child.getType(); - if (childType == Token.THIS && nameChild.getType() == Token.STRING) { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectProp", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } else { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectProp", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - } - - private void visitSetProp(int type, Node node, Node child) - { - Node objectChild = child; - generateExpression(child, node); - child = child.getNext(); - if (type == Token.SETPROP_OP) { - cfw.add(ByteCode.DUP); - } - Node nameChild = child; - generateExpression(child, node); - child = child.getNext(); - if (type == Token.SETPROP_OP) { - // stack: ... object object name -> ... object name object name - cfw.add(ByteCode.DUP_X1); - //for 'this.foo += ...' we call thisGet which can skip some - //casting overhead. - if (objectChild.getType() == Token.THIS - && nameChild.getType() == Token.STRING) - { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectProp", - "(Lorg/mozilla/javascript/Scriptable;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } else { - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectProp", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - } - generateExpression(child, node); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "setObjectProp", - "(Ljava/lang/Object;" - +"Ljava/lang/String;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - - private void visitSetElem(int type, Node node, Node child) - { - generateExpression(child, node); - child = child.getNext(); - if (type == Token.SETELEM_OP) { - cfw.add(ByteCode.DUP); - } - generateExpression(child, node); - child = child.getNext(); - boolean indexIsNumber = (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1); - if (type == Token.SETELEM_OP) { - if (indexIsNumber) { - // stack: ... object object number - // -> ... object number object number - cfw.add(ByteCode.DUP2_X1); - cfw.addALoad(contextLocal); - addOptRuntimeInvoke( - "getObjectIndex", - "(Ljava/lang/Object;D" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } else { - // stack: ... object object indexObject - // -> ... object indexObject object indexObject - cfw.add(ByteCode.DUP_X1); - cfw.addALoad(contextLocal); - addScriptRuntimeInvoke( - "getObjectElem", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - } - generateExpression(child, node); - cfw.addALoad(contextLocal); - if (indexIsNumber) { - addScriptRuntimeInvoke( - "setObjectIndex", - "(Ljava/lang/Object;" - +"D" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } else { - addScriptRuntimeInvoke( - "setObjectElem", - "(Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Context;" - +")Ljava/lang/Object;"); - } - } - - private void visitDotQuery(Node node, Node child) - { - updateLineNumber(node); - generateExpression(child, node); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke("enterDotQuery", - "(Ljava/lang/Object;" - +"Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - - // add push null/pop with label in between to simplify code for loop - // continue when it is necessary to pop the null result from - // updateDotQuery - cfw.add(ByteCode.ACONST_NULL); - int queryLoopStart = cfw.acquireLabel(); - cfw.markLabel(queryLoopStart); // loop continue jumps here - cfw.add(ByteCode.POP); - - generateExpression(child.getNext(), node); - addScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z"); - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke("updateDotQuery", - "(Z" - +"Lorg/mozilla/javascript/Scriptable;" - +")Ljava/lang/Object;"); - cfw.add(ByteCode.DUP); - cfw.add(ByteCode.IFNULL, queryLoopStart); - // stack: ... non_null_result_of_updateDotQuery - cfw.addALoad(variableObjectLocal); - addScriptRuntimeInvoke("leaveDotQuery", - "(Lorg/mozilla/javascript/Scriptable;" - +")Lorg/mozilla/javascript/Scriptable;"); - cfw.addAStore(variableObjectLocal); - } - - private int getLocalBlockRegister(Node node) - { - Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP); - int localSlot = localBlock.getExistingIntProp(Node.LOCAL_PROP); - return localSlot; - } - - private void dcpLoadAsNumber(int dcp_register) - { - cfw.addALoad(dcp_register); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - int isNumberLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel); - short stack = cfw.getStackTop(); - cfw.addALoad(dcp_register); - addObjectToDouble(); - int beyond = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(isNumberLabel, stack); - cfw.addDLoad(dcp_register + 1); - cfw.markLabel(beyond); - } - - private void dcpLoadAsObject(int dcp_register) - { - cfw.addALoad(dcp_register); - cfw.add(ByteCode.GETSTATIC, - "java/lang/Void", - "TYPE", - "Ljava/lang/Class;"); - int isNumberLabel = cfw.acquireLabel(); - cfw.add(ByteCode.IF_ACMPEQ, isNumberLabel); - short stack = cfw.getStackTop(); - cfw.addALoad(dcp_register); - int beyond = cfw.acquireLabel(); - cfw.add(ByteCode.GOTO, beyond); - cfw.markLabel(isNumberLabel, stack); - cfw.addDLoad(dcp_register + 1); - addDoubleWrap(); - cfw.markLabel(beyond); - } - - private void addGoto(Node target, int jumpcode) - { - int targetLabel = getTargetLabel(target); - cfw.add(jumpcode, targetLabel); - } - - private void addObjectToDouble() - { - addScriptRuntimeInvoke("toNumber", "(Ljava/lang/Object;)D"); - } - - private void addNewObjectArray(int size) - { - if (size == 0) { - if (itsZeroArgArray >= 0) { - cfw.addALoad(itsZeroArgArray); - } else { - cfw.add(ByteCode.GETSTATIC, - "org/mozilla/javascript/ScriptRuntime", - "emptyArgs", "[Ljava/lang/Object;"); - } - } else { - cfw.addPush(size); - cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); - } - } - - private void addScriptRuntimeInvoke(String methodName, - String methodSignature) - { - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org.mozilla.javascript.ScriptRuntime", - methodName, - methodSignature); - } - - private void addOptRuntimeInvoke(String methodName, - String methodSignature) - { - cfw.addInvoke(ByteCode.INVOKESTATIC, - "org/mozilla/javascript/optimizer/OptRuntime", - methodName, - methodSignature); - } - - private void addJumpedBooleanWrap(int trueLabel, int falseLabel) - { - cfw.markLabel(falseLabel); - int skip = cfw.acquireLabel(); - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "FALSE", "Ljava/lang/Boolean;"); - cfw.add(ByteCode.GOTO, skip); - cfw.markLabel(trueLabel); - cfw.add(ByteCode.GETSTATIC, "java/lang/Boolean", - "TRUE", "Ljava/lang/Boolean;"); - cfw.markLabel(skip); - cfw.adjustStackTop(-1); // only have 1 of true/false - } - - private void addDoubleWrap() - { - addOptRuntimeInvoke("wrapDouble", "(D)Ljava/lang/Double;"); - } - - /** - * Const locals use an extra slot to hold the has-been-assigned-once flag at - * runtime. - * @param isConst true iff the variable is const - * @return the register for the word pair (double/long) - */ - private short getNewWordPairLocal(boolean isConst) - { - short result = getConsecutiveSlots(2, isConst); - if (result < (MAX_LOCALS - 1)) { - locals[result] = 1; - locals[result + 1] = 1; - if (isConst) - locals[result + 2] = 1; - if (result == firstFreeLocal) { - for (int i = firstFreeLocal + 2; i < MAX_LOCALS; i++) { - if (locals[i] == 0) { - firstFreeLocal = (short) i; - if (localsMax < firstFreeLocal) - localsMax = firstFreeLocal; - return result; - } - } - } - else { - return result; - } - } - throw Context.reportRuntimeError("Program too complex " + - "(out of locals)"); - } - - private short getNewWordLocal(boolean isConst) - { - short result = getConsecutiveSlots(1, isConst); - if (result < (MAX_LOCALS - 1)) { - locals[result] = 1; - if (isConst) - locals[result + 1] = 1; - if (result == firstFreeLocal) { - for (int i = firstFreeLocal + 2; i < MAX_LOCALS; i++) { - if (locals[i] == 0) { - firstFreeLocal = (short) i; - if (localsMax < firstFreeLocal) - localsMax = firstFreeLocal; - return result; - } - } - } - else { - return result; - } - } - throw Context.reportRuntimeError("Program too complex " + - "(out of locals)"); - } - - private short getNewWordLocal() - { - short result = firstFreeLocal; - locals[result] = 1; - for (int i = firstFreeLocal + 1; i < MAX_LOCALS; i++) { - if (locals[i] == 0) { - firstFreeLocal = (short) i; - if (localsMax < firstFreeLocal) - localsMax = firstFreeLocal; - return result; - } - } - throw Context.reportRuntimeError("Program too complex " + - "(out of locals)"); - } - - private short getConsecutiveSlots(int count, boolean isConst) { - if (isConst) - count++; - short result = firstFreeLocal; - while (true) { - if (result >= (MAX_LOCALS - 1)) - break; - int i; - for (i = 0; i < count; i++) - if (locals[result + i] != 0) - break; - if (i >= count) - break; - result++; - } - return result; - } - - // This is a valid call only for a local that is allocated by default. - private void incReferenceWordLocal(short local) - { - locals[local]++; - } - - // This is a valid call only for a local that is allocated by default. - private void decReferenceWordLocal(short local) - { - locals[local]--; - } - - private void releaseWordLocal(short local) - { - if (local < firstFreeLocal) - firstFreeLocal = local; - locals[local] = 0; - } - - - static final int GENERATOR_TERMINATE = -1; - static final int GENERATOR_START = 0; - static final int GENERATOR_YIELD_START = 1; - - ClassFileWriter cfw; - Codegen codegen; - CompilerEnvirons compilerEnv; - ScriptOrFnNode scriptOrFn; - public int scriptOrFnIndex; - private int savedCodeOffset; - - private OptFunctionNode fnCurrent; - private boolean isTopLevel; - - private static final int MAX_LOCALS = 256; - private int[] locals; - private short firstFreeLocal; - private short localsMax; - - private int itsLineNumber; - - private boolean hasVarsInRegs; - private short[] varRegisters; - private boolean inDirectCallFunction; - private boolean itsForcedObjectParameters; - private int enterAreaStartLabel; - private int epilogueLabel; - - // special known locals. If you add a new local here, be sure - // to initialize it to -1 in initBodyGeneration - private short variableObjectLocal; - private short popvLocal; - private short contextLocal; - private short argsLocal; - private short operationLocal; - private short thisObjLocal; - private short funObjLocal; - private short itsZeroArgArray; - private short itsOneArgArray; - private short scriptRegexpLocal; - private short generatorStateLocal; - - private boolean isGenerator; - private int generatorSwitch; - private int maxLocals = 0; - private int maxStack = 0; - - private Hashtable finallys; - - class FinallyReturnPoint { - public ArrayList jsrPoints = new ArrayList(); - public int tableLabel = 0; - } -} diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java deleted file mode 100644 index 607e649..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/DataFlowBitSet.java +++ /dev/null @@ -1,134 +0,0 @@ -/* ***** 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-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Roger Lawrence - * - * 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.optimizer; - -class DataFlowBitSet { - - private int itsBits[]; - private int itsSize; - - DataFlowBitSet(int size) - { - itsSize = size; - itsBits = new int[(size + 31) >> 5]; - } - - void set(int n) - { - if (!(0 <= n && n < itsSize)) badIndex(n); - itsBits[n >> 5] |= 1 << (n & 31); - } - - boolean test(int n) - { - if (!(0 <= n && n < itsSize)) badIndex(n); - return ((itsBits[n >> 5] & (1 << (n & 31))) != 0); - } - - void not() - { - int bitsLength = itsBits.length; - for (int i = 0; i < bitsLength; i++) - itsBits[i] = ~itsBits[i]; - } - - void clear(int n) - { - if (!(0 <= n && n < itsSize)) badIndex(n); - itsBits[n >> 5] &= ~(1 << (n & 31)); - } - - void clear() - { - int bitsLength = itsBits.length; - for (int i = 0; i < bitsLength; i++) - itsBits[i] = 0; - } - - void or(DataFlowBitSet b) - { - int bitsLength = itsBits.length; - for (int i = 0; i < bitsLength; i++) - itsBits[i] |= b.itsBits[i]; - } - - public String toString() - { - StringBuffer sb = new StringBuffer(); - sb.append("DataFlowBitSet, size = "); - sb.append(itsSize); - sb.append('\n'); - int bitsLength = itsBits.length; - for (int i = 0; i < bitsLength; i++) { - sb.append(Integer.toHexString(itsBits[i])); - sb.append(' '); - } - return sb.toString(); - } - - boolean df(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill) - { - int bitsLength = itsBits.length; - boolean changed = false; - for (int i = 0; i < bitsLength; i++) { - int oldBits = itsBits[i]; - itsBits[i] = (in.itsBits[i] | gen.itsBits[i]) & notKill.itsBits[i]; - changed |= (oldBits != itsBits[i]); - } - return changed; - } - - boolean df2(DataFlowBitSet in, DataFlowBitSet gen, DataFlowBitSet notKill) - { - int bitsLength = itsBits.length; - boolean changed = false; - for (int i = 0; i < bitsLength; i++) { - int oldBits = itsBits[i]; - itsBits[i] = (in.itsBits[i] & notKill.itsBits[i]) | gen.itsBits[i]; - changed |= (oldBits != itsBits[i]); - } - return changed; - } - - private void badIndex(int n) - { - throw new RuntimeException("DataFlowBitSet bad index " + n); - } -} diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java deleted file mode 100644 index e043165..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptFunctionNode.java +++ /dev/null @@ -1,149 +0,0 @@ -/* ***** 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-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Bob Jervis - * Roger Lawrence - * - * 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.optimizer; - -import org.mozilla.javascript.*; - -final class OptFunctionNode -{ - OptFunctionNode(FunctionNode fnode) - { - this.fnode = fnode; - fnode.setCompilerData(this); - } - - static OptFunctionNode get(ScriptOrFnNode scriptOrFn, int i) - { - FunctionNode fnode = scriptOrFn.getFunctionNode(i); - return (OptFunctionNode)fnode.getCompilerData(); - } - - static OptFunctionNode get(ScriptOrFnNode scriptOrFn) - { - return (OptFunctionNode)scriptOrFn.getCompilerData(); - } - - boolean isTargetOfDirectCall() - { - return directTargetIndex >= 0; - } - - int getDirectTargetIndex() - { - return directTargetIndex; - } - - void setDirectTargetIndex(int directTargetIndex) - { - // One time action - if (directTargetIndex < 0 || this.directTargetIndex >= 0) - Kit.codeBug(); - this.directTargetIndex = directTargetIndex; - } - - void setParameterNumberContext(boolean b) - { - itsParameterNumberContext = b; - } - - boolean getParameterNumberContext() - { - return itsParameterNumberContext; - } - - int getVarCount() - { - return fnode.getParamAndVarCount(); - } - - boolean isParameter(int varIndex) - { - return varIndex < fnode.getParamCount(); - } - - boolean isNumberVar(int varIndex) - { - varIndex -= fnode.getParamCount(); - if (varIndex >= 0 && numberVarFlags != null) { - return numberVarFlags[varIndex]; - } - return false; - } - - void setIsNumberVar(int varIndex) - { - varIndex -= fnode.getParamCount(); - // Can only be used with non-parameters - if (varIndex < 0) Kit.codeBug(); - if (numberVarFlags == null) { - int size = fnode.getParamAndVarCount() - fnode.getParamCount(); - numberVarFlags = new boolean[size]; - } - numberVarFlags[varIndex] = true; - } - - int getVarIndex(Node n) - { - int index = n.getIntProp(Node.VARIABLE_PROP, -1); - if (index == -1) { - Node node; - int type = n.getType(); - if (type == Token.GETVAR) { - node = n; - } else if (type == Token.SETVAR || - type == Token.SETCONSTVAR) { - node = n.getFirstChild(); - } else { - throw Kit.codeBug(); - } - index = fnode.getIndexForNameNode(node); - if (index < 0) throw Kit.codeBug(); - n.putIntProp(Node.VARIABLE_PROP, index); - } - return index; - } - - FunctionNode fnode; - private boolean[] numberVarFlags; - private int directTargetIndex = -1; - private boolean itsParameterNumberContext; - boolean itsContainsCalls0; - boolean itsContainsCalls1; -} diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java deleted file mode 100644 index ba8ca03..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptRuntime.java +++ /dev/null @@ -1,311 +0,0 @@ -/* ***** 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): - * Norris Boyd - * Roger Lawrence - * 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.optimizer; - -import org.mozilla.javascript.*; - -public final class OptRuntime extends ScriptRuntime -{ - - public static final Double zeroObj = new Double(0.0); - public static final Double oneObj = new Double(1.0); - public static final Double minusOneObj = new Double(-1.0); - - /** - * Implement ....() call shrinking optimizer code. - */ - public static Object call0(Callable fun, Scriptable thisObj, - Context cx, Scriptable scope) - { - return fun.call(cx, scope, thisObj, ScriptRuntime.emptyArgs); - } - - /** - * Implement ....(arg) call shrinking optimizer code. - */ - public static Object call1(Callable fun, Scriptable thisObj, Object arg0, - Context cx, Scriptable scope) - { - return fun.call(cx, scope, thisObj, new Object[] { arg0 } ); - } - - /** - * Implement ....(arg0, arg1) call shrinking optimizer code. - */ - public static Object call2(Callable fun, Scriptable thisObj, - Object arg0, Object arg1, - Context cx, Scriptable scope) - { - return fun.call(cx, scope, thisObj, new Object[] { arg0, arg1 }); - } - - /** - * Implement ....(arg0, arg1, ...) call shrinking optimizer code. - */ - public static Object callN(Callable fun, Scriptable thisObj, - Object[] args, - Context cx, Scriptable scope) - { - return fun.call(cx, scope, thisObj, args); - } - - /** - * Implement name(args) call shrinking optimizer code. - */ - public static Object callName(Object[] args, String name, - Context cx, Scriptable scope) - { - Callable f = getNameFunctionAndThis(name, cx, scope); - Scriptable thisObj = lastStoredScriptable(cx); - return f.call(cx, scope, thisObj, args); - } - - /** - * Implement name() call shrinking optimizer code. - */ - public static Object callName0(String name, - Context cx, Scriptable scope) - { - Callable f = getNameFunctionAndThis(name, cx, scope); - Scriptable thisObj = lastStoredScriptable(cx); - return f.call(cx, scope, thisObj, ScriptRuntime.emptyArgs); - } - - /** - * Implement x.property() call shrinking optimizer code. - */ - public static Object callProp0(Object value, String property, - Context cx, Scriptable scope) - { - Callable f = getPropFunctionAndThis(value, property, cx); - Scriptable thisObj = lastStoredScriptable(cx); - return f.call(cx, scope, thisObj, ScriptRuntime.emptyArgs); - } - - public static Object add(Object val1, double val2) - { - if (val1 instanceof Scriptable) - val1 = ((Scriptable) val1).getDefaultValue(null); - if (!(val1 instanceof String)) - return wrapDouble(toNumber(val1) + val2); - return ((String)val1).concat(toString(val2)); - } - - public static Object add(double val1, Object val2) - { - if (val2 instanceof Scriptable) - val2 = ((Scriptable) val2).getDefaultValue(null); - if (!(val2 instanceof String)) - return wrapDouble(toNumber(val2) + val1); - return toString(val1).concat((String)val2); - } - - public static Object elemIncrDecr(Object obj, double index, - Context cx, int incrDecrMask) - { - return ScriptRuntime.elemIncrDecr(obj, new Double(index), cx, - incrDecrMask); - } - - public static Object[] padStart(Object[] currentArgs, int count) { - Object[] result = new Object[currentArgs.length + count]; - System.arraycopy(currentArgs, 0, result, count, currentArgs.length); - return result; - } - - public static void initFunction(NativeFunction fn, int functionType, - Scriptable scope, Context cx) - { - ScriptRuntime.initFunction(cx, scope, fn, functionType, false); - } - - public static Object callSpecial(Context cx, Callable fun, - Scriptable thisObj, Object[] args, - Scriptable scope, - Scriptable callerThis, int callType, - String fileName, int lineNumber) - { - return ScriptRuntime.callSpecial(cx, fun, thisObj, args, scope, - callerThis, callType, - fileName, lineNumber); - } - - public static Object newObjectSpecial(Context cx, Object fun, - Object[] args, Scriptable scope, - Scriptable callerThis, int callType) - { - return ScriptRuntime.newSpecial(cx, fun, args, scope, callType); - } - - public static Double wrapDouble(double num) - { - if (num == 0.0) { - if (1 / num > 0) { - // +0.0 - return zeroObj; - } - } else if (num == 1.0) { - return oneObj; - } else if (num == -1.0) { - return minusOneObj; - } else if (num != num) { - return NaNobj; - } - return new Double(num); - } - - static String encodeIntArray(int[] array) - { - // XXX: this extremely inefficient for small integers - if (array == null) { return null; } - int n = array.length; - char[] buffer = new char[1 + n * 2]; - buffer[0] = 1; - for (int i = 0; i != n; ++i) { - int value = array[i]; - int shift = 1 + i * 2; - buffer[shift] = (char)(value >>> 16); - buffer[shift + 1] = (char)value; - } - return new String(buffer); - } - - private static int[] decodeIntArray(String str, int arraySize) - { - // XXX: this extremely inefficient for small integers - if (arraySize == 0) { - if (str != null) throw new IllegalArgumentException(); - return null; - } - if (str.length() != 1 + arraySize * 2 && str.charAt(0) != 1) { - throw new IllegalArgumentException(); - } - int[] array = new int[arraySize]; - for (int i = 0; i != arraySize; ++i) { - int shift = 1 + i * 2; - array[i] = (str.charAt(shift) << 16) | str.charAt(shift + 1); - } - return array; - } - - public static Scriptable newArrayLiteral(Object[] objects, - String encodedInts, - int skipCount, - Context cx, - Scriptable scope) - { - int[] skipIndexces = decodeIntArray(encodedInts, skipCount); - return newArrayLiteral(objects, skipIndexces, cx, scope); - } - - public static void main(final Script script, final String[] args) - { - Context.call(new ContextAction() { - public Object run(Context cx) - { - ScriptableObject global = getGlobal(cx); - - // get the command line arguments and define "arguments" - // array in the top-level object - Object[] argsCopy = new Object[args.length]; - System.arraycopy(args, 0, argsCopy, 0, args.length); - Scriptable argsObj = cx.newArray(global, argsCopy); - global.defineProperty("arguments", argsObj, - ScriptableObject.DONTENUM); - script.exec(cx, global); - return null; - } - }); - } - - public static void throwStopIteration(Object obj) { - throw new JavaScriptException( - NativeIterator.getStopIterationObject((Scriptable)obj), "", 0); - } - - public static Scriptable createNativeGenerator(NativeFunction funObj, - Scriptable scope, - Scriptable thisObj, - int maxLocals, - int maxStack) - { - return new NativeGenerator(scope, funObj, - new GeneratorState(thisObj, maxLocals, maxStack)); - } - - public static Object[] getGeneratorStackState(Object obj) { - GeneratorState rgs = (GeneratorState) obj; - if (rgs.stackState == null) - rgs.stackState = new Object[rgs.maxStack]; - return rgs.stackState; - } - - public static Object[] getGeneratorLocalsState(Object obj) { - GeneratorState rgs = (GeneratorState) obj; - if (rgs.localsState == null) - rgs.localsState = new Object[rgs.maxLocals]; - return rgs.localsState; - } - - public static class GeneratorState { - static final String CLASS_NAME = - "org/mozilla/javascript/optimizer/OptRuntime$GeneratorState"; - - public int resumptionPoint; - static final String resumptionPoint_NAME = "resumptionPoint"; - static final String resumptionPoint_TYPE = "I"; - - public Scriptable thisObj; - static final String thisObj_NAME = "thisObj"; - static final String thisObj_TYPE = - "Lorg/mozilla/javascript/Scriptable;"; - - Object[] stackState; - Object[] localsState; - int maxLocals; - int maxStack; - - GeneratorState(Scriptable thisObj, int maxLocals, int maxStack) { - this.thisObj = thisObj; - this.maxLocals = maxLocals; - this.maxStack = maxStack; - } - } -} diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java deleted file mode 100644 index 7cf679f..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/OptTransformer.java +++ /dev/null @@ -1,133 +0,0 @@ -/* ***** 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-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Roger Lawrence - * - * 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.optimizer; - -import org.mozilla.javascript.*; -import java.util.Hashtable; - -/** - * This class performs node transforms to prepare for optimization. - * - * @see NodeTransformer - * @author Norris Boyd - */ - -class OptTransformer extends NodeTransformer { - - OptTransformer(Hashtable possibleDirectCalls, ObjArray directCallTargets) - { - this.possibleDirectCalls = possibleDirectCalls; - this.directCallTargets = directCallTargets; - } - - protected void visitNew(Node node, ScriptOrFnNode tree) { - detectDirectCall(node, tree); - super.visitNew(node, tree); - } - - protected void visitCall(Node node, ScriptOrFnNode tree) { - detectDirectCall(node, tree); - super.visitCall(node, tree); - } - - private void detectDirectCall(Node node, ScriptOrFnNode tree) - { - if (tree.getType() == Token.FUNCTION) { - Node left = node.getFirstChild(); - - // count the arguments - int argCount = 0; - Node arg = left.getNext(); - while (arg != null) { - arg = arg.getNext(); - argCount++; - } - - if (argCount == 0) { - OptFunctionNode.get(tree).itsContainsCalls0 = true; - } - - /* - * Optimize a call site by converting call("a", b, c) into : - * - * FunctionObjectFor"a" <-- instance variable init'd by constructor - * - * // this is a DIRECTCALL node - * fn = GetProp(tmp = GetBase("a"), "a"); - * if (fn == FunctionObjectFor"a") - * fn.call(tmp, b, c) - * else - * ScriptRuntime.Call(fn, tmp, b, c) - */ - if (possibleDirectCalls != null) { - String targetName = null; - if (left.getType() == Token.NAME) { - targetName = left.getString(); - } else if (left.getType() == Token.GETPROP) { - targetName = left.getFirstChild().getNext().getString(); - } else if (left.getType() == Token.GETPROPNOWARN) { - throw Kit.codeBug(); - } - if (targetName != null) { - OptFunctionNode ofn; - ofn = (OptFunctionNode)possibleDirectCalls.get(targetName); - if (ofn != null - && argCount == ofn.fnode.getParamCount() - && !ofn.fnode.requiresActivation()) - { - // Refuse to directCall any function with more - // than 32 parameters - prevent code explosion - // for wacky test cases - if (argCount <= 32) { - node.putProp(Node.DIRECTCALL_PROP, ofn); - if (!ofn.isTargetOfDirectCall()) { - int index = directCallTargets.size(); - directCallTargets.add(ofn); - ofn.setDirectTargetIndex(index); - } - } - } - } - } - } - } - - private Hashtable possibleDirectCalls; - private ObjArray directCallTargets; -} diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java deleted file mode 100644 index 575c7e7..0000000 --- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/optimizer/Optimizer.java +++ /dev/null @@ -1,510 +0,0 @@ -/* ***** 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-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Roger Lawrence - * - * 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.optimizer; - -import org.mozilla.javascript.*; - -class Optimizer -{ - - static final int NoType = 0; - static final int NumberType = 1; - static final int AnyType = 3; - - // It is assumed that (NumberType | AnyType) == AnyType - - void optimize(ScriptOrFnNode scriptOrFn) - { - // run on one function at a time for now - int functionCount = scriptOrFn.getFunctionCount(); - for (int i = 0; i != functionCount; ++i) { - OptFunctionNode f = OptFunctionNode.get(scriptOrFn, i); - optimizeFunction(f); - } - } - - private void optimizeFunction(OptFunctionNode theFunction) - { - if (theFunction.fnode.requiresActivation()) return; - - inDirectCallFunction = theFunction.isTargetOfDirectCall(); - this.theFunction = theFunction; - - ObjArray statementsArray = new ObjArray(); - buildStatementList_r(theFunction.fnode, statementsArray); - Node[] theStatementNodes = new Node[statementsArray.size()]; - statementsArray.toArray(theStatementNodes); - - Block.runFlowAnalyzes(theFunction, theStatementNodes); - - if (!theFunction.fnode.requiresActivation()) { - /* - * Now that we know which local vars are in fact always - * Numbers, we re-write the tree to take advantage of - * that. Any arithmetic or assignment op involving just - * Number typed vars is marked so that the codegen will - * generate non-object code. - */ - parameterUsedInNumberContext = false; - for (int i = 0; i < theStatementNodes.length; i++) { - rewriteForNumberVariables(theStatementNodes[i]); - } - theFunction.setParameterNumberContext(parameterUsedInNumberContext); - } - - } - - -/* - Each directCall parameter is passed as a pair of values - an object - and a double. The value passed depends on the type of value available at - the call site. If a double is available, the object in java/lang/Void.TYPE - is passed as the object value, and if an object value is available, then - 0.0 is passed as the double value. - - The receiving routine always tests the object value before proceeding. - If the parameter is being accessed in a 'Number Context' then the code - sequence is : - if ("parameter_objectValue" == java/lang/Void.TYPE) - ...fine..., use the parameter_doubleValue - else - toNumber(parameter_objectValue) - - and if the parameter is being referenced in an Object context, the code is - if ("parameter_objectValue" == java/lang/Void.TYPE) - new Double(parameter_doubleValue) - else - ...fine..., use the parameter_objectValue - - If the receiving code never uses the doubleValue, it is converted on - entry to a Double instead. -*/ - - -/* - We're referencing a node in a Number context (i.e. we'd prefer it - was a double value). If the node is a parameter in a directCall - function, mark it as being referenced in this context. -*/ - private void markDCPNumberContext(Node n) - { - if (inDirectCallFunction && n.getType() == Token.GETVAR) { - int varIndex = theFunction.getVarIndex(n); - if (theFunction.isParameter(varIndex)) { - parameterUsedInNumberContext = true; - } - } - } - - private boolean convertParameter(Node n) - { - if (inDirectCallFunction && n.getType() == Token.GETVAR) { - int varIndex = theFunction.getVarIndex(n); - if (theFunction.isParameter(varIndex)) { - n.removeProp(Node.ISNUMBER_PROP); - return true; - } - } - return false; - } - - private int rewriteForNumberVariables(Node n) - { - switch (n.getType()) { - case Token.EXPR_VOID : { - Node child = n.getFirstChild(); - int type = rewriteForNumberVariables(child); - if (type == NumberType) - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NoType; - } - case Token.NUMBER : - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - - case Token.GETVAR : - { - int varIndex = theFunction.getVarIndex(n); - if (inDirectCallFunction - && theFunction.isParameter(varIndex)) - { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - else if (theFunction.isNumberVar(varIndex)) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - return NoType; - } - - case Token.INC : - case Token.DEC : { - Node child = n.getFirstChild(); - // "child" will be GETVAR or GETPROP or GETELEM - if (child.getType() == Token.GETVAR) { - if (rewriteForNumberVariables(child) == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - markDCPNumberContext(child); - return NumberType; - } - return NoType; - } - else if (child.getType() == Token.GETELEM) { - return rewriteForNumberVariables(child); - } - return NoType; - } - case Token.SETVAR : { - Node lChild = n.getFirstChild(); - Node rChild = lChild.getNext(); - int rType = rewriteForNumberVariables(rChild); - int varIndex = theFunction.getVarIndex(n); - if (inDirectCallFunction - && theFunction.isParameter(varIndex)) - { - if (rType == NumberType) { - if (!convertParameter(rChild)) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - markDCPNumberContext(rChild); - return NoType; - } - else - return rType; - } - else if (theFunction.isNumberVar(varIndex)) { - if (rType != NumberType) { - n.removeChild(rChild); - n.addChildToBack( - new Node(Token.TO_DOUBLE, rChild)); - } - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - markDCPNumberContext(rChild); - return NumberType; - } - else { - if (rType == NumberType) { - if (!convertParameter(rChild)) { - n.removeChild(rChild); - n.addChildToBack( - new Node(Token.TO_OBJECT, rChild)); - } - } - return NoType; - } - } - case Token.LE : - case Token.LT : - case Token.GE : - case Token.GT : { - Node lChild = n.getFirstChild(); - Node rChild = lChild.getNext(); - int lType = rewriteForNumberVariables(lChild); - int rType = rewriteForNumberVariables(rChild); - markDCPNumberContext(lChild); - markDCPNumberContext(rChild); - - if (convertParameter(lChild)) { - if (convertParameter(rChild)) { - return NoType; - } else if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT); - } - } - else if (convertParameter(rChild)) { - if (lType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT); - } - } - else { - if (lType == NumberType) { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - } - else { - n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT); - } - } - else { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT); - } - } - } - // we actually build a boolean value - return NoType; - } - - case Token.ADD : { - Node lChild = n.getFirstChild(); - Node rChild = lChild.getNext(); - int lType = rewriteForNumberVariables(lChild); - int rType = rewriteForNumberVariables(rChild); - - - if (convertParameter(lChild)) { - if (convertParameter(rChild)) { - return NoType; - } - else { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT); - } - } - } - else { - if (convertParameter(rChild)) { - if (lType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT); - } - } - else { - if (lType == NumberType) { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - else { - n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT); - } - } - else { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, - Node.RIGHT); - } - } - } - } - return NoType; - } - - case Token.BITXOR : - case Token.BITOR : - case Token.BITAND : - case Token.RSH : - case Token.LSH : - case Token.SUB : - case Token.MUL : - case Token.DIV : - case Token.MOD : { - Node lChild = n.getFirstChild(); - Node rChild = lChild.getNext(); - int lType = rewriteForNumberVariables(lChild); - int rType = rewriteForNumberVariables(rChild); - markDCPNumberContext(lChild); - markDCPNumberContext(rChild); - if (lType == NumberType) { - if (rType == NumberType) { - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - else { - if (!convertParameter(rChild)) { - n.removeChild(rChild); - n.addChildToBack( - new Node(Token.TO_DOUBLE, rChild)); - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - } - return NumberType; - } - } - else { - if (rType == NumberType) { - if (!convertParameter(lChild)) { - n.removeChild(lChild); - n.addChildToFront( - new Node(Token.TO_DOUBLE, lChild)); - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - } - return NumberType; - } - else { - if (!convertParameter(lChild)) { - n.removeChild(lChild); - n.addChildToFront( - new Node(Token.TO_DOUBLE, lChild)); - } - if (!convertParameter(rChild)) { - n.removeChild(rChild); - n.addChildToBack( - new Node(Token.TO_DOUBLE, rChild)); - } - n.putIntProp(Node.ISNUMBER_PROP, Node.BOTH); - return NumberType; - } - } - } - case Token.SETELEM : - case Token.SETELEM_OP : { - Node arrayBase = n.getFirstChild(); - Node arrayIndex = arrayBase.getNext(); - Node rValue = arrayIndex.getNext(); - int baseType = rewriteForNumberVariables(arrayBase); - if (baseType == NumberType) {// can never happen ??? - if (!convertParameter(arrayBase)) { - n.removeChild(arrayBase); - n.addChildToFront( - new Node(Token.TO_OBJECT, arrayBase)); - } - } - int indexType = rewriteForNumberVariables(arrayIndex); - if (indexType == NumberType) { - // setting the ISNUMBER_PROP signals the codegen - // to use the OptRuntime.setObjectIndex that takes - // a double index - n.putIntProp(Node.ISNUMBER_PROP, Node.LEFT); - markDCPNumberContext(arrayIndex); - } - int rValueType = rewriteForNumberVariables(rValue); - if (rValueType == NumberType) { - if (!convertParameter(rValue)) { - n.removeChild(rValue); - n.addChildToBack( - new Node(Token.TO_OBJECT, rValue)); - } - } - return NoType; - } - case Token.GETELEM : { - Node arrayBase = n.getFirstChild(); - Node arrayIndex = arrayBase.getNext(); - int baseType = rewriteForNumberVariables(arrayBase); - if (baseType == NumberType) {// can never happen ??? - if (!convertParameter(arrayBase)) { - n.removeChild(arrayBase); - n.addChildToFront( - new Node(Token.TO_OBJECT, arrayBase)); - } - } - int indexType = rewriteForNumberVariables(arrayIndex); - if (indexType == NumberType) { - if (!convertParameter(arrayIndex)) { - // setting the ISNUMBER_PROP signals the codegen - // to use the OptRuntime.getObjectIndex that takes - // a double index - n.putIntProp(Node.ISNUMBER_PROP, Node.RIGHT); - } - } - return NoType; - } - case Token.CALL : - { - Node child = n.getFirstChild(); // the function node - if (child.getType() == Token.GETELEM) { - // Optimization of x[0]() is not supported - // so bypass GETELEM optimization that - // rewriteForNumberVariables would trigger - rewriteAsObjectChildren(child, child.getFirstChild()); - } else { - rewriteForNumberVariables(child); - } - child = child.getNext(); // the first arg - - OptFunctionNode target - = (OptFunctionNode)n.getProp(Node.DIRECTCALL_PROP); - if (target != null) { -/* - we leave each child as a Number if it can be. The codegen will - handle moving the pairs of parameters. -*/ - while (child != null) { - int type = rewriteForNumberVariables(child); - if (type == NumberType) { - markDCPNumberContext(child); - } - child = child.getNext(); - } - } else { - rewriteAsObjectChildren(n, child); - } - return NoType; - } - default : { - rewriteAsObjectChildren(n, n.getFirstChild()); - return NoType; - } - } - } - - private void rewriteAsObjectChildren(Node n, Node child) - { - // Force optimized children to be objects - while (child != null) { - Node nextChild = child.getNext(); - int type = rewriteForNumberVariables(child); - if (type == NumberType) { - if (!convertParameter(child)) { - n.removeChild(child); - Node nuChild = new Node(Token.TO_OBJECT, child); - if (nextChild == null) - n.addChildToBack(nuChild); - else - n.addChildBefore(nuChild, nextChild); - } - } - child = nextChild; - } - } - - private static void buildStatementList_r(Node node, ObjArray statements) - { - int type = node.getType(); - if (type == Token.BLOCK - || type == Token.LOCAL_BLOCK - || type == Token.LOOP - || type == Token.FUNCTION) - { - Node child = node.getFirstChild(); - while (child != null) { - buildStatementList_r(child, statements); - child = child.getNext(); - } - } else { - statements.add(node); - } - } - - private boolean inDirectCallFunction; - OptFunctionNode theFunction; - private boolean parameterUsedInNumberContext; -} |