From 5ea134dca77466f579b599d3e198c9fa7358896d Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Wed, 19 Feb 2003 14:50:30 +0000 Subject: [PATCH] During parsing collect all nested function in script or function directly into array in ScriptOrFnNode. In this way there is no need to walk over tree to find nested functions during tree transformation since the function nodes are available directly. git-svn-id: svn://10.0.0.236/trunk@137979 18797224-902f-48f8-a5cc-f745e15eee43 --- .../src/org/mozilla/javascript/Context.java | 8 +- .../src/org/mozilla/javascript/IRFactory.java | 60 +++++---- .../org/mozilla/javascript/Interpreter.java | 61 ++++----- .../mozilla/javascript/NodeTransformer.java | 7 +- .../src/org/mozilla/javascript/Parser.java | 83 ++++++------ .../mozilla/javascript/ScriptOrFnNode.java | 31 ++++- .../mozilla/javascript/optimizer/Codegen.java | 127 +++++++++--------- .../javascript/optimizer/OptTransformer.java | 32 ++--- .../javascript/optimizer/Optimizer.java | 17 +-- 9 files changed, 210 insertions(+), 216 deletions(-) diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Context.java b/mozilla/js/rhino/src/org/mozilla/javascript/Context.java index b8889cdc7d6..1f69fab30fb 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/Context.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/Context.java @@ -2011,12 +2011,10 @@ public class Context { if (printTrees) { System.out.println(tree.toStringTree()); } if (returnFunction) { - Node first = tree.getFirstChild(); - if (first == null) - return null; - tree = (ScriptOrFnNode)first.getProp(Node.FUNCTION_PROP); - if (tree == null) + int functionCount = tree.getFunctionCount(); + if (functionCount == 0) return null; + tree = tree.getFunctionNode(0); } if (debugger != null) { diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java b/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java index 592e9c66365..c84c57aa300 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/IRFactory.java @@ -48,24 +48,25 @@ public class IRFactory { this.compiler = compiler; this.ts = ts; } + + public ScriptOrFnNode createScript() { + return new ScriptOrFnNode(TokenStream.SCRIPT); + } /** * Script (for associating file/url names with toplevel scripts.) */ - public ScriptOrFnNode - createScript(Object body, VariableTable vars, String sourceName, - int baseLineno, int endLineno, String source) + public void + initScript(ScriptOrFnNode scriptNode, Object body, + String sourceName, int baseLineno, int endLineno, String source) { - ScriptOrFnNode result = new ScriptOrFnNode(TokenStream.SCRIPT); - result.variableTable = vars; - result.setEncodedSource(source); - result.setSourceName(sourceName); - result.setBaseLineno(baseLineno); - result.setEndLineno(endLineno); + scriptNode.setEncodedSource(source); + scriptNode.setSourceName(sourceName); + scriptNode.setBaseLineno(baseLineno); + scriptNode.setEndLineno(endLineno); Node children = ((Node) body).getFirstChild(); - if (children != null) { result.addChildrenToBack(children); } - return result; + if (children != null) { scriptNode.addChildrenToBack(children); } } /** @@ -202,25 +203,26 @@ public class IRFactory { return new Node(TokenStream.BLOCK, lineno); } - public Object createFunction(String name, VariableTable vars, - Object statements, - String sourceName, int baseLineno, - int endLineno, String source, - int functionType) + public FunctionNode createFunction(String name) { + return compiler.createFunctionNode(this, name); + } + + public Object initFunction(FunctionNode fnNode, int functionIndex, + Object statements, + String sourceName, int baseLineno, + int endLineno, String source, + int functionType) { - if (name == null) { - name = ""; - } - FunctionNode f = compiler.createFunctionNode(this, name); - f.variableTable = vars; - f.setEncodedSource(source); - f.setSourceName(sourceName); - f.setBaseLineno(baseLineno); - f.setEndLineno(endLineno); - f.setFunctionType(functionType); - f.addChildToBack((Node)statements); - Node result = Node.newString(TokenStream.FUNCTION, name); - result.putProp(Node.FUNCTION_PROP, f); + fnNode.setEncodedSource(source); + fnNode.setSourceName(sourceName); + fnNode.setBaseLineno(baseLineno); + fnNode.setEndLineno(endLineno); + fnNode.setFunctionType(functionType); + fnNode.addChildToBack((Node)statements); + + Node result = Node.newString(TokenStream.FUNCTION, + fnNode.getFunctionName()); + result.putIntProp(Node.FUNCTION_PROP, functionIndex); return result; } diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java b/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java index 3ad7932f1b9..902993c4cd2 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/Interpreter.java @@ -81,32 +81,30 @@ public class Interpreter { compile(Context cx, Scriptable scope, ScriptOrFnNode tree, SecurityController securityController, Object securityDomain) { + scriptOrFn = tree; version = cx.getLanguageVersion(); itsData = new InterpreterData(securityDomain); if (tree instanceof FunctionNode) { - FunctionNode f = (FunctionNode) tree; - itsData.itsFunctionType = f.getFunctionType(); - generateFunctionICode(cx, scope, f); + generateFunctionICode(cx, scope); return createFunction(cx, scope, itsData, false); } else { - generateScriptICode(cx, scope, tree); + generateScriptICode(cx, scope); return new InterpretedScript(cx, itsData); } } - private void - generateScriptICode(Context cx, Scriptable scope, ScriptOrFnNode tree) + private void generateScriptICode(Context cx, Scriptable scope) { - itsSourceFile = tree.getSourceName(); + itsSourceFile = scriptOrFn.getSourceName(); itsData.itsSourceFile = itsSourceFile; - debugSource = tree.getOriginalSource(); + debugSource = scriptOrFn.getOriginalSource(); - generateNestedFunctions(cx, scope, tree); + generateNestedFunctions(cx, scope); - generateRegExpLiterals(cx, scope, tree); + generateRegExpLiterals(cx, scope); - itsVariableTable = tree.getVariableTable(); - generateICodeFromTree(tree); + itsVariableTable = scriptOrFn.getVariableTable(); + generateICodeFromTree(scriptOrFn); if (Context.printICode) dumpICode(itsData); if (cx.debugger != null) { @@ -114,9 +112,10 @@ public class Interpreter { } } - private void generateFunctionICode(Context cx, Scriptable scope, - FunctionNode theFunction) + private void generateFunctionICode(Context cx, Scriptable scope) { + FunctionNode theFunction = (FunctionNode)scriptOrFn; + itsData.itsFunctionType = theFunction.getFunctionType(); // check if function has own source, which is the case // with Function(...) String savedSource = debugSource; @@ -124,9 +123,9 @@ public class Interpreter { if (debugSource == null) { debugSource = savedSource; } - generateNestedFunctions(cx, scope, theFunction); + generateNestedFunctions(cx, scope); - generateRegExpLiterals(cx, scope, theFunction); + generateRegExpLiterals(cx, scope); itsData.itsNeedsActivation = theFunction.requiresActivation(); @@ -144,34 +143,30 @@ public class Interpreter { debugSource = savedSource; } - private void generateNestedFunctions(Context cx, Scriptable scope, - ScriptOrFnNode tree) + private void generateNestedFunctions(Context cx, Scriptable scope) { - int functionCount = tree.getFunctionCount(); + int functionCount = scriptOrFn.getFunctionCount(); if (functionCount == 0) return; InterpreterData[] array = new InterpreterData[functionCount]; for (int i = 0; i != functionCount; i++) { - FunctionNode def = tree.getFunctionNode(i); + FunctionNode def = scriptOrFn.getFunctionNode(i); Interpreter jsi = new Interpreter(); + jsi.scriptOrFn = def; jsi.itsSourceFile = itsSourceFile; jsi.itsData = new InterpreterData(itsData.securityDomain); jsi.itsData.itsCheckThis = def.getCheckThis(); - jsi.itsData.itsFunctionType = def.getFunctionType(); jsi.itsInFunctionFlag = true; jsi.debugSource = debugSource; - jsi.generateFunctionICode(cx, scope, def); + jsi.generateFunctionICode(cx, scope); array[i] = jsi.itsData; - def.putIntProp(Node.FUNCTION_PROP, i); } itsData.itsNestedFunctions = array; } - private void generateRegExpLiterals(Context cx, - Scriptable scope, - ScriptOrFnNode tree) + private void generateRegExpLiterals(Context cx, Scriptable scope) { - int N = tree.getRegexpCount(); + int N = scriptOrFn.getRegexpCount(); if (N == 0) return; RegExpProxy rep = cx.getRegExpProxy(); @@ -180,8 +175,8 @@ public class Interpreter { } Object[] array = new Object[N]; for (int i = 0; i != N; i++) { - String string = tree.getRegexpString(i); - String flags = tree.getRegexpFlags(i); + String string = scriptOrFn.getRegexpString(i); + String flags = scriptOrFn.getRegexpFlags(i); array[i] = rep.newRegExp(cx, scope, string, flags, false); } itsData.itsRegExpLiterals = array; @@ -265,16 +260,15 @@ public class Interpreter { switch (type) { case TokenStream.FUNCTION : { - FunctionNode fn - = (FunctionNode) node.getProp(Node.FUNCTION_PROP); + int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); + FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex); if (fn.itsFunctionType != FunctionNode.FUNCTION_STATEMENT) { // Only function expressions or function expression // statements needs closure code creating new function // object on stack as function statements are initialized // at script/function start - int index = fn.getExistingIntProp(Node.FUNCTION_PROP); iCodeTop = addByte(TokenStream.CLOSURE, iCodeTop); - iCodeTop = addIndex(index, iCodeTop); + iCodeTop = addIndex(fnIndex, iCodeTop); itsStackDepth++; if (itsStackDepth > itsData.itsMaxStack) itsData.itsMaxStack = itsStackDepth; @@ -2891,6 +2885,7 @@ public class Interpreter { private boolean itsInFunctionFlag; private InterpreterData itsData; + private ScriptOrFnNode scriptOrFn; private VariableTable itsVariableTable; private int itsTryDepth = 0; private int itsStackDepth = 0; diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java b/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java index 0408373644e..838b52cc791 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NodeTransformer.java @@ -109,8 +109,8 @@ public class NodeTransformer { case TokenStream.FUNCTION: if (node != tree) { - FunctionNode - fnNode = (FunctionNode)node.getProp(Node.FUNCTION_PROP); + int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); + FunctionNode fnNode = tree.getFunctionNode(fnIndex); if (inFunction) { // Functions containing other functions require // activation objects @@ -123,8 +123,7 @@ public class NodeTransformer { } NodeTransformer inner = newInstance(); fnNode = (FunctionNode)inner.transform(fnNode); - node.putProp(Node.FUNCTION_PROP, fnNode); - tree.addFunction(fnNode); + tree.replaceFunctionNode(fnIndex, fnNode); } break; diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java b/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java index 073d7871108..79e27beb51e 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/Parser.java @@ -98,10 +98,10 @@ class Parser { public ScriptOrFnNode parse(TokenStream ts) throws IOException { + currentScriptOrFn = nf.createScript(); + this.ok = true; fn_sourceTop = 0; - fn_functionNumber = 0; - fn_vars = new VariableTable(); fn_funcExprStmNames = null; int tt; // last token from getToken(); @@ -145,8 +145,10 @@ class Parser { String source = sourceToString(0); sourceBuffer = null; // To help GC - return nf.createScript(pn, fn_vars, ts.getSourceName(), - baseLineno, ts.getLineno(), source); + + nf.initScript(currentScriptOrFn, pn, ts.getSourceName(), + baseLineno, ts.getLineno(), source); + return currentScriptOrFn; } /* @@ -203,16 +205,16 @@ class Parser { // by '(', assume starts memberExpr sourceAddString(ts.NAME, name); Object memberExprHead = nf.createName(name); - name = null; + name = ""; memberExprNode = memberExprTail(ts, false, memberExprHead); } mustMatchToken(ts, ts.LP, "msg.no.paren.parms"); } } else if (ts.matchToken(ts.LP)) { // Anonymous function - name = null; + name = ""; } else { - name = null; + name = ""; if (allowMemberExprAsFunctionName) { // Note that memberExpr can not start with '(' like // in function (1+2).toString(), because 'function (' already @@ -229,29 +231,28 @@ class Parser { sourceAdd((char)ts.NOP); } + FunctionNode fnNode = nf.createFunction(name); + int functionIndex = currentScriptOrFn.addFunction(fnNode); + // save a reference to the function in the enclosing source. sourceAdd((char) ts.FUNCTION); - sourceAdd((char)fn_functionNumber); - ++fn_functionNumber; + sourceAdd((char)functionIndex); // Save current source top to restore it on exit not to include // function to parent source int saved_sourceTop = fn_sourceTop; - int saved_functionNumber = fn_functionNumber; - VariableTable saved_vars = fn_vars; - VariableTable new_vars = new VariableTable(); ObjArray saved_funcExprStmNames = fn_funcExprStmNames; + + ScriptOrFnNode savedScriptOrFn = currentScriptOrFn; + currentScriptOrFn = fnNode; Object body; String source; try { - fn_functionNumber = 0; - fn_vars = new_vars; - // FUNCTION as the first token in a Source means it's a function // definition, and not a reference. sourceAdd((char) ts.FUNCTION); - if (name != null) { sourceAddString(ts.NAME, name); } + if (name.length() != 0) { sourceAddString(ts.NAME, name); } sourceAdd((char) ts.LP); if (!ts.matchToken(ts.RP)) { @@ -262,11 +263,11 @@ class Parser { first = false; mustMatchToken(ts, ts.NAME, "msg.no.parm"); String s = ts.getString(); - if (new_vars.hasVariable(s)) { + if (fnNode.hasParameterOrVar(s)) { Object[] msgArgs = { s }; ts.reportCurrentLineWarning("msg.dup.parms", msgArgs); } - new_vars.addParameter(s); + fnNode.addParameter(s); sourceAddString(ts.NAME, s); } while (ts.matchToken(ts.COMMA)); @@ -286,26 +287,25 @@ class Parser { source = sourceToString(saved_sourceTop); // Remove name clashes for nested functions - checkVariables(new_vars, fn_funcExprStmNames); + checkVariables(fnNode, fn_funcExprStmNames); } finally { fn_sourceTop = saved_sourceTop; - fn_functionNumber = saved_functionNumber; - fn_vars = saved_vars; fn_funcExprStmNames = saved_funcExprStmNames; + currentScriptOrFn = savedScriptOrFn; } Object pn; if (memberExprNode == null) { - pn = nf.createFunction(name, new_vars, body, - ts.getSourceName(), - baseLineno, ts.getLineno(), - source, - functionType); + pn = nf.initFunction(fnNode, functionIndex, body, + ts.getSourceName(), + baseLineno, ts.getLineno(), + source, + functionType); if (functionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { // Record the name to check for possible var and // function expression statement name clashes - if (name != null && name.length()!= 0) { + if (name.length()!= 0) { if (fn_funcExprStmNames == null) { fn_funcExprStmNames = new ObjArray(); } @@ -323,11 +323,11 @@ class Parser { checkWellTerminatedFunction(ts); } } else { - pn = nf.createFunction(name, new_vars, body, - ts.getSourceName(), - baseLineno, ts.getLineno(), - source, - FunctionNode.FUNCTION_EXPRESSION); + pn = nf.initFunction(fnNode, functionIndex, body, + ts.getSourceName(), + baseLineno, ts.getLineno(), + source, + FunctionNode.FUNCTION_EXPRESSION); pn = nf.createBinary(ts.ASSIGN, ts.NOP, memberExprNode, pn); if (functionType != FunctionNode.FUNCTION_EXPRESSION) { pn = nf.createExprStatement(pn, baseLineno); @@ -342,14 +342,14 @@ class Parser { } private static void - checkVariables(VariableTable vars, ObjArray funcExprStmNames) + checkVariables(ScriptOrFnNode scriptOrFn, ObjArray funcExprStmNames) { // Remove all variables corresponding to function expression statements if (funcExprStmNames != null) { int N = funcExprStmNames.size(); for (int i = 0; i != N; ++i) { String name = (String)funcExprStmNames.get(i); - vars.removeLocal(name); + scriptOrFn.removeParameterOrVar(name); } } } @@ -909,7 +909,7 @@ class Parser { first = false; sourceAddString(ts.NAME, s); - fn_vars.addLocal(s); + currentScriptOrFn.addVar(s); name = nf.createName(s); // omitted check for argument hiding @@ -1810,15 +1810,15 @@ class Parser { */ ++i; - int functionNumber = source.charAt(i); + int functionIndex = source.charAt(i); if (childNodes == null - || functionNumber + 1 > childNodes.length) + || functionIndex + 1 > childNodes.length) { throw Context.reportRuntimeError(Context.getMessage1 ("msg.no.function.ref.found", - new Integer(functionNumber))); + new Integer(functionIndex))); } - decompile_r(childNodes[functionNumber + 1], version, + decompile_r(childNodes[functionIndex + 1], version, indent, NESTED_FUNCTION, false, srcData, result); break; } @@ -2306,13 +2306,10 @@ class Parser { // included in parent. private int fn_sourceTop; -// Nested function number - private int fn_functionNumber; - // Nested function number private ObjArray fn_funcExprStmNames; - private VariableTable fn_vars; + private ScriptOrFnNode currentScriptOrFn; private static final int TOP_LEVEL_SCRIPT_OR_FUNCTION = 0; private static final int CONSTRUCTED_FUNCTION = 1; diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/ScriptOrFnNode.java b/mozilla/js/rhino/src/org/mozilla/javascript/ScriptOrFnNode.java index d8854988e8e..bf08e8408b4 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/ScriptOrFnNode.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/ScriptOrFnNode.java @@ -41,7 +41,10 @@ public class ScriptOrFnNode extends Node { super(nodeType); } - public final VariableTable getVariableTable() { return variableTable; } + public final VariableTable getVariableTable() { + if (variableTable == null) { variableTable = new VariableTable(); } + return variableTable; + } public final String getSourceName() { return sourceName; } @@ -95,7 +98,7 @@ public class ScriptOrFnNode extends Node { if (fnNode == null) Context.codeBug(); if (functions == null) { functions = new ObjArray(); } functions.add(fnNode); - return functions.size(); + return functions.size() - 1; } public final int getRegexpCount() { @@ -116,7 +119,27 @@ public class ScriptOrFnNode extends Node { if (regexps == null) { regexps = new ObjArray(); } regexps.add(string); regexps.add(flags); - return (regexps.size() - 2) / 2; + return regexps.size() / 2 - 1; + } + + public final boolean hasParameterOrVar(String name) { + if (variableTable == null) { return false; } + return variableTable.hasVariable(name); + } + + public final void addParameter(String name) { + if (variableTable == null) { variableTable = new VariableTable(); } + variableTable.addParameter(name); + } + + public final void addVar(String name) { + if (variableTable == null) { variableTable = new VariableTable(); } + variableTable.addLocal(name); + } + + public final void removeParameterOrVar(String name) { + if (variableTable == null) { return; } + variableTable.removeLocal(name); } public final int getLocalCount() { return localCount; } @@ -125,7 +148,6 @@ public class ScriptOrFnNode extends Node { ++localCount; } - VariableTable variableTable; private String encodedSource; private String originalSource; private String sourceName; @@ -133,6 +155,7 @@ public class ScriptOrFnNode extends Node { private int endLineno = -1; private ObjArray functions; private ObjArray regexps; + private VariableTable variableTable; private int localCount; } diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java index 108ec1a6cb1..3baf798bdfe 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Codegen.java @@ -89,12 +89,12 @@ public class Codegen extends Interpreter { } public Object - compile(Context cx, Scriptable scope, ScriptOrFnNode tree, + compile(Context cx, Scriptable scope, ScriptOrFnNode scriptOrFn, SecurityController securityController, Object securityDomain) { ObjArray classFiles = new ObjArray(); ObjArray names = new ObjArray(); - generateCode(tree, names, classFiles); + generateCode(scriptOrFn, names, classFiles); String generatedName = name; boolean onlySave = false; @@ -120,12 +120,12 @@ public class Codegen extends Interpreter { if (interfaces != null || superClass != null) { String adapterClassName = getScriptClassName(null, true); ScriptableObject obj = new NativeObject(); - for (Node cursor = tree.getFirstChild(); cursor != null; - cursor = cursor.getNext()) - { - if (cursor.getType() == TokenStream.FUNCTION) { - FunctionNode fn - = (FunctionNode)cursor.getProp(Node.FUNCTION_PROP); + int functionCount = scriptOrFn.getFunctionCount(); + for (int i = 0; i != functionCount; ++i) { + OptFunctionNode fn; + fn = (OptFunctionNode)scriptOrFn.getFunctionNode(i); + String name = fn.getFunctionName(); + if (name != null && name.length() != 0) { obj.put(fn.getFunctionName(), obj, fn); } } @@ -184,7 +184,7 @@ public class Codegen extends Interpreter { if (e != null) throw new RuntimeException("Malformed optimizer package " + e); - if (tree instanceof OptFunctionNode) { + if (scriptOrFn instanceof OptFunctionNode) { NativeFunction f; try { Constructor ctor = result.getConstructors()[0]; @@ -383,15 +383,14 @@ public class Codegen extends Interpreter { } private String - generateCode(ScriptOrFnNode tree, ObjArray names, ObjArray classFiles) + generateCode(ScriptOrFnNode scriptOrFn, ObjArray names, ObjArray classFiles) { - int functionCount = tree.getFunctionCount(); - if (functionCount != 0) { - for (int i = 0; i != functionCount; ++i) { - OptFunctionNode fn = (OptFunctionNode)tree.getFunctionNode(i); - Codegen codegen = new Codegen(this); - codegen.generateCode(fn, names, classFiles); - } + this.scriptOrFn = scriptOrFn; + int functionCount = scriptOrFn.getFunctionCount(); + for (int i = 0; i != functionCount; ++i) { + OptFunctionNode fn = (OptFunctionNode)scriptOrFn.getFunctionNode(i); + Codegen codegen = new Codegen(this); + codegen.generateCode(fn, names, classFiles); } Context cx = Context.getCurrentContext(); @@ -400,11 +399,11 @@ public class Codegen extends Interpreter { itsSourceFile = null; // default is to generate debug info if (!cx.isGeneratingDebugChanged() || cx.isGeneratingDebug()) { - itsSourceFile = tree.getSourceName(); + itsSourceFile = scriptOrFn.getSourceName(); } version = cx.getLanguageVersion(); optLevel = cx.getOptimizationLevel(); - inFunction = tree.getType() == TokenStream.FUNCTION; + inFunction = scriptOrFn.getType() == TokenStream.FUNCTION; superClassName = inFunction ? functionSuperClassName : scriptSuperClassName; @@ -412,13 +411,13 @@ public class Codegen extends Interpreter { Node codegenBase; if (inFunction) { - fnCurrent = (OptFunctionNode)tree; + fnCurrent = (OptFunctionNode)scriptOrFn; inDirectCallFunction = fnCurrent.isTargetOfDirectCall(); vars = fnCurrent.getVariableTable(); this.name = fnCurrent.getClassName(); classFile = new ClassFileWriter(name, superClassName, itsSourceFile); String name = fnCurrent.getFunctionName(); - generateInit(cx, "", tree, name); + generateInit(cx, "", name); if (fnCurrent.isTargetOfDirectCall()) { classFile.startMethod("call", "(Lorg/mozilla/javascript/Context;" + @@ -484,7 +483,7 @@ public class Codegen extends Interpreter { markLabel(isObjectLabel); } } - generatePrologue(cx, tree, true, vars.getParameterCount()); + generatePrologue(cx, true, vars.getParameterCount()); } else { startNewMethod("call", "(Lorg/mozilla/javascript/Context;" + @@ -492,22 +491,22 @@ public class Codegen extends Interpreter { "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;)Ljava/lang/Object;", 1, false, true); - generatePrologue(cx, tree, true, -1); + generatePrologue(cx, true, -1); } - codegenBase = tree.getLastChild(); + codegenBase = scriptOrFn.getLastChild(); } else { // better be a script - if (tree.getType() != TokenStream.SCRIPT) + if (scriptOrFn.getType() != TokenStream.SCRIPT) badTree(); - vars = tree.getVariableTable(); + vars = scriptOrFn.getVariableTable(); boolean isPrimary = nameHelper.getTargetExtends() == null && nameHelper.getTargetImplements() == null; this.name = getScriptClassName(null, isPrimary); classFile = new ClassFileWriter(name, superClassName, itsSourceFile); classFile.addInterface("org/mozilla/javascript/Script"); - generateScriptCtor(cx, tree); + generateScriptCtor(cx); generateMain(cx); - generateInit(cx, "initScript", tree, ""); + generateInit(cx, "initScript", ""); generateExecute(cx); startNewMethod("call", "(Lorg/mozilla/javascript/Context;" + @@ -515,12 +514,12 @@ public class Codegen extends Interpreter { "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;)Ljava/lang/Object;", 1, false, true); - generatePrologue(cx, tree, false, -1); - int linenum = tree.getEndLineno(); + generatePrologue(cx, false, -1); + int linenum = scriptOrFn.getEndLineno(); if (linenum != -1) classFile.addLineNumberEntry((short)linenum); - tree.addChildToBack(new Node(TokenStream.RETURN)); - codegenBase = tree; + scriptOrFn.addChildToBack(new Node(TokenStream.RETURN)); + codegenBase = scriptOrFn; } generateCodeFromNode(codegenBase, null, -1, -1); @@ -591,8 +590,9 @@ public class Codegen extends Interpreter { case TokenStream.FUNCTION: if (inFunction || parent.getType() != TokenStream.SCRIPT) { - OptFunctionNode fn - = (OptFunctionNode) node.getProp(Node.FUNCTION_PROP); + int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); + OptFunctionNode fn; + fn = (OptFunctionNode)scriptOrFn.getFunctionNode(fnIndex); int t = fn.getFunctionType(); if (t != FunctionNode.FUNCTION_STATEMENT) { visitFunction(fn, t); @@ -1085,7 +1085,7 @@ public class Codegen extends Interpreter { finishMethod(cx, null); } - private void generateScriptCtor(Context cx, Node tree) { + private void generateScriptCtor(Context cx) { startNewMethod("", "()V", 1, false, false); addByteCode(ByteCode.ALOAD_0); addSpecialInvoke(superClassSlashName, @@ -1114,12 +1114,11 @@ public class Codegen extends Interpreter { contextLocal = reserveWordLocal(2); // reserve 2 for 'context' } - private void generateInit(Context cx, String methodName, - ScriptOrFnNode tree, String name) + private void generateInit(Context cx, String methodName, String name) { trivialInit = true; boolean inCtor = false; - VariableTable vars = tree.getVariableTable(); + VariableTable vars = scriptOrFn.getVariableTable(); if (methodName.equals("")) { inCtor = true; setNonTrivialInit(methodName); @@ -1190,13 +1189,13 @@ public class Codegen extends Interpreter { } // precompile all regexp literals - int regexpCount = tree.getRegexpCount(); + int regexpCount = scriptOrFn.getRegexpCount(); if (regexpCount != 0) { setNonTrivialInit(methodName); - generateRegExpLiterals(tree, inCtor); + generateRegExpLiterals(inCtor); } - if (tree instanceof OptFunctionNode) { + if (scriptOrFn instanceof OptFunctionNode) { if (fnCurrent.isTargetOfDirectCall()) { setNonTrivialInit(methodName); @@ -1227,7 +1226,7 @@ public class Codegen extends Interpreter { // Change Parser if changing ordering. if (cx.isGeneratingSource()) { - String source = tree.getEncodedSource(); + String source = scriptOrFn.getEncodedSource(); if (source != null && source.length() < 65536) { short flags = ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_STATIC; @@ -1235,7 +1234,7 @@ public class Codegen extends Interpreter { classFile.startMethod(getSourceMethodStr, "()Ljava/lang/Object;", (short)flags); - int functionCount = tree.getFunctionCount(); + int functionCount = scriptOrFn.getFunctionCount(); if (functionCount == 0) { // generate return ; push(source); @@ -1257,7 +1256,7 @@ public class Codegen extends Interpreter { OptFunctionNode fn; addByteCode(ByteCode.DUP); // dup array reference push(1 + i); - fn = (OptFunctionNode)tree.getFunctionNode(i); + fn = (OptFunctionNode)scriptOrFn.getFunctionNode(i); classFile.add(ByteCode.INVOKESTATIC, fn.getClassName(), getSourceMethodStr, @@ -1272,8 +1271,8 @@ public class Codegen extends Interpreter { } } - private void generateRegExpLiterals(ScriptOrFnNode tree, boolean inCtor) { - int regexpCount = tree.getRegexpCount(); + private void generateRegExpLiterals(boolean inCtor) { + int regexpCount = scriptOrFn.getRegexpCount(); for (int i=0; i < regexpCount; i++) { String fieldName = getRegexpFieldName(i); short flags = ClassFileWriter.ACC_PRIVATE; @@ -1289,8 +1288,8 @@ public class Codegen extends Interpreter { aload(contextLocal); // load 'context' aload(variableObjectLocal); // load 'scope' - push(tree.getRegexpString(i)); - String regexpFlags = tree.getRegexpFlags(i); + push(scriptOrFn.getRegexpString(i)); + String regexpFlags = scriptOrFn.getRegexpFlags(i); if (regexpFlags == null) { addByteCode(ByteCode.ACONST_NULL); } else { @@ -1318,15 +1317,13 @@ public class Codegen extends Interpreter { * Generate the prologue for a function or script. * * @param cx the context - * @param tree the tree to generate code for * @param inFunction true if generating the prologue for a function * (as opposed to a script) * @param directParameterCount number of parameters for direct call, * or -1 if not direct call */ private void - generatePrologue(Context cx, ScriptOrFnNode tree, boolean inFunction, - int directParameterCount) + generatePrologue(Context cx, boolean inFunction, int directParameterCount) { funObjLocal = reserveWordLocal(0); contextLocal = reserveWordLocal(1); @@ -1358,7 +1355,7 @@ public class Codegen extends Interpreter { // These locals are to be pre-allocated since they need function scope. // They are primarily used by the exception handling mechanism - int localCount = tree.getLocalCount(); + int localCount = scriptOrFn.getLocalCount(); if (localCount != 0) { itsLocalAllocationBase = (short)(argsLocal + 1); for (int i = 0; i < localCount; i++) { @@ -1366,7 +1363,7 @@ public class Codegen extends Interpreter { } } - if (inFunction && ((OptFunctionNode)tree).getCheckThis()) { + if (inFunction && ((OptFunctionNode)scriptOrFn).getCheckThis()) { // Nested functions must check their 'this' value to // insure it is not an activation object: // see 10.1.6 Activation Object @@ -1378,7 +1375,7 @@ public class Codegen extends Interpreter { } hasVarsInRegs = inFunction && - !((OptFunctionNode)tree).requiresActivation(); + !((OptFunctionNode)scriptOrFn).requiresActivation(); if (hasVarsInRegs) { // No need to create activation. Pad arguments if need be. int parmCount = vars.getParameterCount(); @@ -1489,18 +1486,15 @@ public class Codegen extends Interpreter { } astore(variableObjectLocal); - int functionCount = tree.getFunctionCount(); - if (functionCount != 0) { - for (int i=0; i < functionCount; i++) { - OptFunctionNode fn = (OptFunctionNode)tree.getFunctionNode(i); - if (fn.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) { - visitFunction(fn, FunctionNode.FUNCTION_STATEMENT); - addByteCode(ByteCode.POP); - } + int functionCount = scriptOrFn.getFunctionCount(); + for (int i = 0; i != functionCount; i++) { + OptFunctionNode fn = (OptFunctionNode)scriptOrFn.getFunctionNode(i); + if (fn.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) { + visitFunction(fn, FunctionNode.FUNCTION_STATEMENT); + addByteCode(ByteCode.POP); } } - // default is to generate debug info if (!cx.isGeneratingDebugChanged() || cx.isGeneratingDebug()) { OptLocalVariable lv = new OptLocalVariable(debugVariableName, @@ -1519,15 +1513,15 @@ public class Codegen extends Interpreter { astore(scriptResultLocal); } - if (inFunction && ((OptFunctionNode)tree).containsCalls(-1)) { - if (((OptFunctionNode)tree).containsCalls(0)) { + if (inFunction && ((OptFunctionNode)scriptOrFn).containsCalls(-1)) { + if (((OptFunctionNode)scriptOrFn).containsCalls(0)) { itsZeroArgArray = getNewWordLocal(); classFile.add(ByteCode.GETSTATIC, "org/mozilla/javascript/ScriptRuntime", "emptyArgs", "[Ljava/lang/Object;"); astore(itsZeroArgArray); } - if (((OptFunctionNode)tree).containsCalls(1)) { + if (((OptFunctionNode)scriptOrFn).containsCalls(1)) { itsOneArgArray = getNewWordLocal(); push(1); addByteCode(ByteCode.ANEWARRAY, "java/lang/Object"); @@ -3770,6 +3764,7 @@ public class Codegen extends Interpreter { private short itsZeroArgArray; private short itsOneArgArray; + private ScriptOrFnNode scriptOrFn; private OptFunctionNode fnCurrent; private boolean itsUseDynamicScope; private boolean hasVarsInRegs; diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/OptTransformer.java b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/OptTransformer.java index 81d337af872..aa71ad868cd 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/OptTransformer.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/OptTransformer.java @@ -59,16 +59,15 @@ class OptTransformer extends NodeTransformer { return new OptTransformer(irFactory, listCopy); } - public ScriptOrFnNode transform(ScriptOrFnNode tree) { + public ScriptOrFnNode transform(ScriptOrFnNode scriptOrFn) { // Collect all of the script 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() == TokenStream.SCRIPT) { - collectContainedFunctions(tree.getFirstChild()); + if (scriptOrFn.getType() == TokenStream.SCRIPT) { + collectContainedFunctions(scriptOrFn); } - - return super.transform(tree); + return super.transform(scriptOrFn); } private int detectDirectCall(Node node, ScriptOrFnNode tree) @@ -151,21 +150,14 @@ class OptTransformer extends NodeTransformer { * so that the call optimizer can access the class name & parameter * count for any call it encounters */ - private void collectContainedFunctions(Node node) { - for (Node tNode=node; tNode != null; tNode = tNode.getNext()) { - if (tNode.getType() == TokenStream.FUNCTION) { - FunctionNode - fnNode = (FunctionNode)tNode.getProp(Node.FUNCTION_PROP); - if (fnNode.getType() == FunctionNode.FUNCTION_STATEMENT) { - String name = fnNode.getFunctionName(); - if (name.length() != 0) { - Object oldFn = theFnClassNameList.get(name); - if (oldFn == fnNode) { - // already processed this list of functions - return; - } - theFnClassNameList.put(name, fnNode); - } + private void collectContainedFunctions(ScriptOrFnNode scriptOrFn) { + int functionCount = scriptOrFn.getFunctionCount(); + for (int i = 0; i != functionCount; ++i) { + OptFunctionNode f = (OptFunctionNode)scriptOrFn.getFunctionNode(i); + if (f.getType() == FunctionNode.FUNCTION_STATEMENT) { + String name = f.getFunctionName(); + if (name.length() != 0) { + theFnClassNameList.put(name, f); } } } diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java index c3aac64e971..83fcadd4b01 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/optimizer/Optimizer.java @@ -53,21 +53,14 @@ class Optimizer { this.irFactory = irFactory; } - void optimize(Node tree, int optLevel) + void optimize(ScriptOrFnNode scriptOrFn, int optLevel) { itsOptLevel = optLevel; // run on one function at a time for now - PreorderNodeIterator iter = new PreorderNodeIterator(); - for (iter.start(tree); !iter.done(); iter.next()) { - // should be able to do this more cheaply ? - // - run through initial block children ? - Node node = iter.getCurrent(); - if (node.getType() == TokenStream.FUNCTION) { - OptFunctionNode theFunction = (OptFunctionNode) - node.getProp(Node.FUNCTION_PROP); - if (theFunction != null) - optimizeFunction(theFunction); - } + int functionCount = scriptOrFn.getFunctionCount(); + for (int i = 0; i != functionCount; ++i) { + OptFunctionNode f = (OptFunctionNode)scriptOrFn.getFunctionNode(i); + optimizeFunction(f); } }