зеркало из https://github.com/mozilla/pjs.git
VariableTable changes toward removal of a separated NodeTransformer pass over the parser tree for variable initialization: the code to support a table of optimized variables for functions in the optimizer is moved to optimizer/OptFunctionNode and VariableTable holds only parameters/variables names now. It allowed to simplify VariableTable initialization in NodeTransformer.
This commit is contained in:
Родитель
90c8869435
Коммит
aab18156df
|
@ -43,7 +43,6 @@ public class FunctionNode extends Node {
|
|||
public FunctionNode(String name, Node statements) {
|
||||
super(TokenStream.FUNCTION, statements);
|
||||
functionName = name;
|
||||
itsVariableTable = new VariableTable();
|
||||
}
|
||||
|
||||
public String getFunctionName() {
|
||||
|
@ -54,6 +53,13 @@ public class FunctionNode extends Node {
|
|||
return itsVariableTable;
|
||||
}
|
||||
|
||||
public void setVariableTable(VariableTable variableTable) {
|
||||
// Can do it only once
|
||||
if (variableTable == null) Context.codeBug();
|
||||
if (itsVariableTable != null) Context.codeBug();
|
||||
itsVariableTable = variableTable;
|
||||
}
|
||||
|
||||
public boolean requiresActivation() {
|
||||
return itsNeedsActivation;
|
||||
}
|
||||
|
@ -97,6 +103,10 @@ public class FunctionNode extends Node {
|
|||
itsFunctionType = functionType;
|
||||
}
|
||||
|
||||
public int getParameterCount() {
|
||||
return argNames.size();
|
||||
}
|
||||
|
||||
protected VariableTable itsVariableTable;
|
||||
protected boolean itsNeedsActivation;
|
||||
protected boolean itsCheckThis;
|
||||
|
|
|
@ -230,8 +230,7 @@ public class Interpreter {
|
|||
+ itsData.itsMaxTryDepth
|
||||
+ itsData.itsMaxStack;
|
||||
|
||||
itsData.argNames = new String[itsVariableTable.size()];
|
||||
itsVariableTable.getAllVariables(itsData.argNames);
|
||||
itsData.argNames = itsVariableTable.getAllVariables();
|
||||
itsData.argCount = itsVariableTable.getParameterCount();
|
||||
}
|
||||
|
||||
|
|
|
@ -64,8 +64,15 @@ public class NodeTransformer {
|
|||
loops = new ObjArray();
|
||||
loopEnds = new ObjArray();
|
||||
inFunction = tree.getType() == TokenStream.FUNCTION;
|
||||
VariableTable vars = new VariableTable();
|
||||
if (!inFunction) {
|
||||
addVariables(tree, getVariableTable(tree));
|
||||
addVariables(tree, vars);
|
||||
tree.putProp(Node.VARS_PROP, vars);
|
||||
} else {
|
||||
FunctionNode fnNode = (FunctionNode)tree;
|
||||
addParameters(fnNode, vars);
|
||||
addVariables(tree, vars);
|
||||
fnNode.setVariableTable(vars);
|
||||
}
|
||||
irFactory = createIRFactory(ts, scope);
|
||||
|
||||
|
@ -82,11 +89,6 @@ public class NodeTransformer {
|
|||
|
||||
case TokenStream.FUNCTION:
|
||||
if (node == tree) {
|
||||
// Add the variables to variable table, the
|
||||
// parameters were added earlier.
|
||||
VariableTable vars = getVariableTable(tree);
|
||||
addVariables(tree, vars);
|
||||
|
||||
// Add return to end if needed.
|
||||
Node stmts = node.getLastChild();
|
||||
Node lastStmt = stmts.getLastChild();
|
||||
|
@ -109,7 +111,6 @@ public class NodeTransformer {
|
|||
// see 10.1.6 Activation Object
|
||||
fnNode.setCheckThis(true);
|
||||
}
|
||||
addParameters(fnNode);
|
||||
NodeTransformer inner = newInstance();
|
||||
fnNode = (FunctionNode)
|
||||
inner.transform(fnNode, tree, ts, scope);
|
||||
|
@ -435,7 +436,6 @@ public class NodeTransformer {
|
|||
// use of "arguments" requires an activation object.
|
||||
((FunctionNode) tree).setRequiresActivation(true);
|
||||
}
|
||||
VariableTable vars = getVariableTable(tree);
|
||||
if (vars.hasVariable(name)) {
|
||||
if (type == TokenStream.SETNAME) {
|
||||
node.setType(TokenStream.SETVAR);
|
||||
|
@ -477,7 +477,6 @@ public class NodeTransformer {
|
|||
// Use of "arguments" requires an activation object.
|
||||
((FunctionNode) tree).setRequiresActivation(true);
|
||||
}
|
||||
VariableTable vars = getVariableTable(tree);
|
||||
if (vars.hasVariable(name)) {
|
||||
node.setType(TokenStream.GETVAR);
|
||||
}
|
||||
|
@ -520,7 +519,7 @@ public class NodeTransformer {
|
|||
{
|
||||
String name = cursor.getString();
|
||||
if (fNames == null || !fNames.has(name))
|
||||
vars.addLocal(name, createVariableObject(name, false));
|
||||
vars.addLocal(name);
|
||||
}
|
||||
}
|
||||
if (inFunction) {
|
||||
|
@ -534,7 +533,7 @@ public class NodeTransformer {
|
|||
// ECMA Ch. 13. We add code to the beginning of the function
|
||||
// to initialize a local variable of the function's name
|
||||
// to the function value.
|
||||
vars.addLocal(name, createVariableObject(name, false));
|
||||
vars.addLocal(name);
|
||||
Node block = tree.getLastChild();
|
||||
Node setFn = new Node(TokenStream.POP,
|
||||
new Node(TokenStream.SETVAR,
|
||||
|
@ -546,22 +545,17 @@ public class NodeTransformer {
|
|||
}
|
||||
}
|
||||
|
||||
protected void addParameters(FunctionNode fnNode) {
|
||||
VariableTable vars = fnNode.getVariableTable();
|
||||
protected void addParameters(FunctionNode fnNode, VariableTable vars) {
|
||||
if (vars.getParameterCount() == 0) {
|
||||
ObjArray argNames = fnNode.argNames;
|
||||
// Add parameters
|
||||
for (int i = 0, N = argNames.size(); i != N; ++i) {
|
||||
String arg = (String)argNames.get(i);
|
||||
vars.addParameter(arg, createVariableObject(arg, true));
|
||||
vars.addParameter(arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Object createVariableObject(String name, boolean isParameter) {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void visitNew(Node node, Node tree) {
|
||||
}
|
||||
|
||||
|
@ -679,20 +673,12 @@ public class NodeTransformer {
|
|||
return false;
|
||||
}
|
||||
|
||||
protected VariableTable createVariableTable() {
|
||||
return new VariableTable();
|
||||
}
|
||||
|
||||
protected VariableTable getVariableTable(Node tree) {
|
||||
if (inFunction) {
|
||||
return ((FunctionNode)tree).getVariableTable();
|
||||
} else {
|
||||
return (VariableTable)(tree.getProp(Node.VARS_PROP));
|
||||
}
|
||||
VariableTable result = (VariableTable)(tree.getProp(Node.VARS_PROP));
|
||||
if (result == null) {
|
||||
result = createVariableTable();
|
||||
tree.putProp(Node.VARS_PROP, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void reportMessage(Context cx, String msg, Node stmt,
|
||||
|
|
|
@ -48,31 +48,25 @@ public class VariableTable {
|
|||
return varStart;
|
||||
}
|
||||
|
||||
public Object getVariable(int index) {
|
||||
return itsVariables.get(index);
|
||||
public String getVariable(int index) {
|
||||
return (String)itsVariables.get(index);
|
||||
}
|
||||
|
||||
public boolean hasVariable(String name) {
|
||||
return itsVariableNames.has(name);
|
||||
}
|
||||
|
||||
public Object getVariable(String name) {
|
||||
int vIndex = itsVariableNames.get(name, -1);
|
||||
if (vIndex != -1)
|
||||
return itsVariables.get(vIndex);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getOrdinal(String name) {
|
||||
return itsVariableNames.get(name, -1);
|
||||
}
|
||||
|
||||
public void getAllVariables(Object[] destination) {
|
||||
itsVariables.toArray(destination);
|
||||
public String[] getAllVariables() {
|
||||
String[] array = new String[itsVariables.size()];
|
||||
itsVariables.toArray(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
public void addParameter(String pName, Object paramObj) {
|
||||
public void addParameter(String pName) {
|
||||
// Check addParameter is not called after addLocal
|
||||
if (varStart != itsVariables.size()) Context.codeBug();
|
||||
int pIndex = itsVariableNames.get(pName, -1);
|
||||
|
@ -81,18 +75,18 @@ public class VariableTable {
|
|||
Context.reportWarning(message, null, 0, null, 0);
|
||||
}
|
||||
int index = varStart++;
|
||||
itsVariables.add(paramObj);
|
||||
itsVariables.add(pName);
|
||||
itsVariableNames.put(pName, index);
|
||||
}
|
||||
|
||||
public void addLocal(String vName, Object varObj) {
|
||||
public void addLocal(String vName) {
|
||||
int vIndex = itsVariableNames.get(vName, -1);
|
||||
if (vIndex != -1) {
|
||||
// There's already a variable or parameter with this name.
|
||||
return;
|
||||
}
|
||||
int index = itsVariables.size();
|
||||
itsVariables.add(varObj);
|
||||
itsVariables.add(vName);
|
||||
itsVariableNames.put(vName, index);
|
||||
}
|
||||
|
||||
|
|
|
@ -193,14 +193,14 @@ public class Block {
|
|||
|
||||
*/
|
||||
void lookForVariablesAndCalls(Node n, boolean liveSet[],
|
||||
VariableTable theVariables)
|
||||
OptFunctionNode fn)
|
||||
{
|
||||
switch (n.getType()) {
|
||||
case TokenStream.SETVAR :
|
||||
{
|
||||
Node lhs = n.getFirstChild();
|
||||
Node rhs = lhs.getNext();
|
||||
lookForVariablesAndCalls(rhs, liveSet, theVariables);
|
||||
lookForVariablesAndCalls(rhs, liveSet, fn);
|
||||
Object theVarProp = n.getProp(Node.VARIABLE_PROP);
|
||||
if (theVarProp != null) {
|
||||
int theVarIndex = ((OptLocalVariable)theVarProp).getIndex();
|
||||
|
@ -211,12 +211,12 @@ public class Block {
|
|||
case TokenStream.CALL : {
|
||||
Node child = n.getFirstChild();
|
||||
while (child != null) {
|
||||
lookForVariablesAndCalls(child, liveSet, theVariables);
|
||||
lookForVariablesAndCalls(child, liveSet, fn);
|
||||
child = child.getNext();
|
||||
}
|
||||
for (int i = 0; i < liveSet.length; i++) {
|
||||
if (liveSet[i])
|
||||
OptLocalVariable.get(theVariables, i).markLiveAcrossCall();
|
||||
fn.getVar(i).markLiveAcrossCall();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -234,29 +234,29 @@ public class Block {
|
|||
default :
|
||||
Node child = n.getFirstChild();
|
||||
while (child != null) {
|
||||
lookForVariablesAndCalls(child, liveSet, theVariables);
|
||||
lookForVariablesAndCalls(child, liveSet, fn);
|
||||
child = child.getNext();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void markAnyTypeVariables(VariableTable theVariables)
|
||||
void markAnyTypeVariables(OptFunctionNode fn)
|
||||
{
|
||||
for (int i = 0; i < theVariables.size(); i++)
|
||||
for (int i = 0; i < fn.getVarCount(); i++)
|
||||
if (itsLiveOnEntrySet.test(i))
|
||||
OptLocalVariable.get(theVariables, i).assignType(TypeEvent.AnyType);
|
||||
fn.getVar(i).assignType(TypeEvent.AnyType);
|
||||
|
||||
}
|
||||
|
||||
void markVolatileVariables(VariableTable theVariables)
|
||||
void markVolatileVariables(OptFunctionNode fn)
|
||||
{
|
||||
boolean liveSet[] = new boolean[theVariables.size()];
|
||||
boolean liveSet[] = new boolean[fn.getVarCount()];
|
||||
for (int i = 0; i < liveSet.length; i++)
|
||||
liveSet[i] = itsLiveOnEntrySet.test(i);
|
||||
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
|
||||
Node n = itsStatementNodes[i];
|
||||
lookForVariablesAndCalls(n, liveSet, theVariables);
|
||||
lookForVariablesAndCalls(n, liveSet, fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -327,9 +327,9 @@ public class Block {
|
|||
Then walk the trees looking for defs/uses of variables
|
||||
and build the def and useBeforeDef sets.
|
||||
*/
|
||||
public void initLiveOnEntrySets(VariableTable theVariables)
|
||||
void initLiveOnEntrySets(OptFunctionNode fn)
|
||||
{
|
||||
int listLength = theVariables.size();
|
||||
int listLength = fn.getVarCount();
|
||||
Node lastUse[] = new Node[listLength];
|
||||
itsUseBeforeDefSet = new DataFlowBitSet(listLength);
|
||||
itsNotDefSet = new DataFlowBitSet(listLength);
|
||||
|
@ -630,7 +630,7 @@ public class Block {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean doTypeFlow()
|
||||
boolean doTypeFlow()
|
||||
{
|
||||
boolean changed = false;
|
||||
|
||||
|
@ -643,15 +643,15 @@ public class Block {
|
|||
return changed;
|
||||
}
|
||||
|
||||
public boolean isLiveOnEntry(int index)
|
||||
boolean isLiveOnEntry(int index)
|
||||
{
|
||||
return (itsLiveOnEntrySet != null) && (itsLiveOnEntrySet.test(index));
|
||||
}
|
||||
|
||||
public void printLiveOnEntrySet(PrintWriter pw, VariableTable theVariables)
|
||||
void printLiveOnEntrySet(PrintWriter pw, OptFunctionNode fn)
|
||||
{
|
||||
for (int i = 0; i < theVariables.size(); i++) {
|
||||
String name = OptLocalVariable.get(theVariables, i).getName();
|
||||
for (int i = 0; i < fn.getVarCount(); i++) {
|
||||
String name = fn.getVar(i).getName();
|
||||
if (itsUseBeforeDefSet.test(i))
|
||||
pw.println(name + " is used before def'd");
|
||||
if (itsNotDefSet.test(i))
|
||||
|
|
|
@ -115,10 +115,9 @@ public class Codegen extends Interpreter {
|
|||
cursor = cursor.getNext())
|
||||
{
|
||||
if (cursor.getType() == TokenStream.FUNCTION) {
|
||||
OptFunctionNode fnNode
|
||||
= (OptFunctionNode)cursor.
|
||||
getProp(Node.FUNCTION_PROP);
|
||||
obj.put(fnNode.getFunctionName(), obj, fnNode);
|
||||
FunctionNode fn
|
||||
= (FunctionNode)cursor.getProp(Node.FUNCTION_PROP);
|
||||
obj.put(fn.getFunctionName(), obj, fn);
|
||||
}
|
||||
}
|
||||
if (superClass == null) {
|
||||
|
@ -186,8 +185,7 @@ public class Codegen extends Interpreter {
|
|||
throw new RuntimeException
|
||||
("Unable to instantiate compiled class:"+ex.toString());
|
||||
}
|
||||
OptFunctionNode fnNode = (OptFunctionNode)tree;
|
||||
OptRuntime.initFunction(f, fnNode.getFunctionType(), scope, cx);
|
||||
OptRuntime.initFunction(f, fnCurrent.getFunctionType(), scope, cx);
|
||||
return f;
|
||||
} else {
|
||||
NativeScript script;
|
||||
|
@ -304,7 +302,7 @@ public class Codegen extends Interpreter {
|
|||
return classFile.acquireLabel();
|
||||
}
|
||||
|
||||
public void emitDirectConstructor(OptFunctionNode fnNode)
|
||||
public void emitDirectConstructor()
|
||||
{
|
||||
/*
|
||||
we generate ..
|
||||
|
@ -322,11 +320,11 @@ public class Codegen extends Interpreter {
|
|||
short flags = (short)(ClassFileWriter.ACC_PUBLIC
|
||||
| ClassFileWriter.ACC_FINAL);
|
||||
classFile.startMethod("constructDirect",
|
||||
fnNode.getDirectCallParameterSignature()
|
||||
+ "Ljava/lang/Object;",
|
||||
flags);
|
||||
fnCurrent.getDirectCallParameterSignature()
|
||||
+ "Ljava/lang/Object;",
|
||||
flags);
|
||||
|
||||
int argCount = fnNode.getVariableTable().getParameterCount();
|
||||
int argCount = fnCurrent.getParameterCount();
|
||||
int firstLocal = (4 + argCount * 3) + 1;
|
||||
|
||||
aload((short)0); // this
|
||||
|
@ -350,7 +348,7 @@ public class Codegen extends Interpreter {
|
|||
aload((short)(4 + argCount * 3));
|
||||
addVirtualInvoke(this.name,
|
||||
"callDirect",
|
||||
fnNode.getDirectCallParameterSignature(),
|
||||
fnCurrent.getDirectCallParameterSignature(),
|
||||
"Ljava/lang/Object;");
|
||||
astore((short)(firstLocal + 1));
|
||||
|
||||
|
@ -403,14 +401,14 @@ public class Codegen extends Interpreter {
|
|||
|
||||
Node codegenBase;
|
||||
if (inFunction) {
|
||||
OptFunctionNode fnNode = (OptFunctionNode) tree;
|
||||
inDirectCallFunction = fnNode.isTargetOfDirectCall();
|
||||
vars = fnNode.getVariableTable();
|
||||
this.name = fnNode.getClassName();
|
||||
fnCurrent = (OptFunctionNode)tree;
|
||||
inDirectCallFunction = fnCurrent.isTargetOfDirectCall();
|
||||
vars = fnCurrent.getVariableTable();
|
||||
this.name = fnCurrent.getClassName();
|
||||
classFile = new ClassFileWriter(name, superClassName, itsSourceFile);
|
||||
String name = fnNode.getFunctionName();
|
||||
String name = fnCurrent.getFunctionName();
|
||||
generateInit(cx, "<init>", tree, name);
|
||||
if (fnNode.isTargetOfDirectCall()) {
|
||||
if (fnCurrent.isTargetOfDirectCall()) {
|
||||
classFile.startMethod("call",
|
||||
"(Lorg/mozilla/javascript/Context;" +
|
||||
"Lorg/mozilla/javascript/Scriptable;" +
|
||||
|
@ -442,24 +440,24 @@ public class Codegen extends Interpreter {
|
|||
addByteCode(ByteCode.ALOAD, 4);
|
||||
addVirtualInvoke(this.name,
|
||||
"callDirect",
|
||||
fnNode.getDirectCallParameterSignature(),
|
||||
fnCurrent.getDirectCallParameterSignature(),
|
||||
"Ljava/lang/Object;");
|
||||
addByteCode(ByteCode.ARETURN);
|
||||
classFile.stopMethod((short)5, null);
|
||||
// 1 for this, 1 for js this, 1 for args[]
|
||||
|
||||
emitDirectConstructor(fnNode);
|
||||
emitDirectConstructor();
|
||||
|
||||
startNewMethod("callDirect",
|
||||
fnNode.getDirectCallParameterSignature() +
|
||||
fnCurrent.getDirectCallParameterSignature() +
|
||||
"Ljava/lang/Object;",
|
||||
1, false, true);
|
||||
assignParameterJRegs(vars);
|
||||
if (!fnNode.getParameterNumberContext()) {
|
||||
assignParameterJRegs(fnCurrent);
|
||||
if (!fnCurrent.getParameterNumberContext()) {
|
||||
// make sure that all parameters are objects
|
||||
itsForcedObjectParameters = true;
|
||||
for (int i = 0; i < vars.getParameterCount(); i++) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(vars, i);
|
||||
for (int i = 0; i < fnCurrent.getParameterCount(); i++) {
|
||||
OptLocalVariable lVar = fnCurrent.getVar(i);
|
||||
aload(lVar.getJRegister());
|
||||
classFile.add(ByteCode.GETSTATIC,
|
||||
"java/lang/Void",
|
||||
|
@ -532,15 +530,15 @@ public class Codegen extends Interpreter {
|
|||
return name;
|
||||
}
|
||||
|
||||
private static void assignParameterJRegs(VariableTable vars) {
|
||||
private static void assignParameterJRegs(OptFunctionNode fnCurrent) {
|
||||
// 0 is reserved for function Object 'this'
|
||||
// 1 is reserved for context
|
||||
// 2 is reserved for parentScope
|
||||
// 3 is reserved for script 'this'
|
||||
short jReg = 4;
|
||||
int parameterCount = vars.getParameterCount();
|
||||
int parameterCount = fnCurrent.getParameterCount();
|
||||
for (int i = 0; i < parameterCount; i++) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(vars, i);
|
||||
OptLocalVariable lVar = fnCurrent.getVar(i);
|
||||
lVar.assignJRegister(jReg);
|
||||
jReg += 3; // 3 is 1 for Object parm and 2 for double parm
|
||||
}
|
||||
|
@ -1018,8 +1016,7 @@ public class Codegen extends Interpreter {
|
|||
classFile.startMethod(methodName, methodDesc, (short) flags);
|
||||
}
|
||||
|
||||
private void finishMethod(Context cx, VariableTable vars) {
|
||||
OptLocalVariable[] array = OptLocalVariable.toArray(vars);
|
||||
private void finishMethod(Context cx, OptLocalVariable[] array) {
|
||||
classFile.stopMethod((short)(localsMax + 1), array);
|
||||
contextLocal = -1;
|
||||
}
|
||||
|
@ -1155,7 +1152,7 @@ public class Codegen extends Interpreter {
|
|||
for (int i = 0; i != N; i++) {
|
||||
addByteCode(ByteCode.DUP);
|
||||
push(i);
|
||||
push(OptLocalVariable.get(vars, i).getName());
|
||||
push(vars.getVariable(i));
|
||||
addByteCode(ByteCode.AASTORE);
|
||||
}
|
||||
addByteCode(ByteCode.ALOAD_0);
|
||||
|
@ -1195,10 +1192,9 @@ public class Codegen extends Interpreter {
|
|||
|
||||
if (tree instanceof OptFunctionNode) {
|
||||
|
||||
OptFunctionNode fnNode = (OptFunctionNode)tree;
|
||||
if (fnNode.isTargetOfDirectCall()) {
|
||||
if (fnCurrent.isTargetOfDirectCall()) {
|
||||
setNonTrivialInit(methodName);
|
||||
String className = fnNode.getClassName();
|
||||
String className = fnCurrent.getClassName();
|
||||
String fieldName = className.replace('.', '_');
|
||||
String fieldType = 'L'+classFile.fullyQualifiedForm(className)
|
||||
+';';
|
||||
|
@ -1400,8 +1396,8 @@ public class Codegen extends Interpreter {
|
|||
// 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 < vars.size(); i++) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(vars, i);
|
||||
for (int i = 0; i < fnCurrent.getVarCount(); i++) {
|
||||
OptLocalVariable lVar = fnCurrent.getVar(i);
|
||||
if (lVar.isNumber()) {
|
||||
lVar.assignJRegister(getNewWordPairLocal());
|
||||
push(0.0);
|
||||
|
@ -1430,7 +1426,7 @@ public class Codegen extends Interpreter {
|
|||
// Indicate that we should generate debug information for
|
||||
// the variable table. (If we're generating debug info at
|
||||
// all.)
|
||||
debugVars = vars;
|
||||
debugVars = fnCurrent.getVarsArray();
|
||||
|
||||
// Skip creating activation object.
|
||||
return;
|
||||
|
@ -1506,8 +1502,8 @@ public class Codegen extends Interpreter {
|
|||
lv.assignJRegister(variableObjectLocal);
|
||||
lv.setStartPC(classFile.getCurrentCodeOffset());
|
||||
|
||||
debugVars = new VariableTable();
|
||||
debugVars.addLocal(debugVariableName, lv);
|
||||
debugVars = new OptLocalVariable[1];
|
||||
debugVars[0] = lv;
|
||||
}
|
||||
|
||||
if (!inFunction) {
|
||||
|
@ -2399,7 +2395,7 @@ public class Codegen extends Interpreter {
|
|||
}
|
||||
String name = node.getString();
|
||||
if (hasVarsInRegs) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(vars, name);
|
||||
OptLocalVariable lVar = fnCurrent.getVar(name);
|
||||
if (lVar != null) {
|
||||
if (lVar.isNumber()) {
|
||||
push("number");
|
||||
|
@ -2437,7 +2433,7 @@ public class Codegen extends Interpreter {
|
|||
String routine = (isInc) ? "postIncrement" : "postDecrement";
|
||||
if (hasVarsInRegs && child.getType() == TokenStream.GETVAR) {
|
||||
if (lVar == null)
|
||||
lVar = OptLocalVariable.get(vars, child.getString());
|
||||
lVar = fnCurrent.getVar(child.getString());
|
||||
if (lVar.getJRegister() == -1)
|
||||
lVar.assignJRegister(getNewWordLocal());
|
||||
aload(lVar.getJRegister());
|
||||
|
@ -3201,7 +3197,7 @@ public class Codegen extends Interpreter {
|
|||
{
|
||||
// TODO: Clean up use of lVar here and in set.
|
||||
if (hasVarsInRegs && lVar == null)
|
||||
lVar = OptLocalVariable.get(vars, name);
|
||||
lVar = fnCurrent.getVar(name);
|
||||
if (lVar != null) {
|
||||
if (lVar.getJRegister() == -1)
|
||||
if (lVar.isNumber())
|
||||
|
@ -3272,7 +3268,7 @@ public class Codegen extends Interpreter {
|
|||
OptLocalVariable lVar = (OptLocalVariable)(node.getProp(Node.VARIABLE_PROP));
|
||||
// XXX is this right? If so, clean up.
|
||||
if (hasVarsInRegs && lVar == null)
|
||||
lVar = OptLocalVariable.get(vars, child.getString());
|
||||
lVar = fnCurrent.getVar(child.getString());
|
||||
if (lVar != null) {
|
||||
generateCodeFromNode(child.getNext(), node, -1, -1);
|
||||
if (lVar.getJRegister() == -1) {
|
||||
|
@ -3768,13 +3764,14 @@ public class Codegen extends Interpreter {
|
|||
private short itsZeroArgArray;
|
||||
private short itsOneArgArray;
|
||||
|
||||
private OptFunctionNode fnCurrent;
|
||||
private boolean itsUseDynamicScope;
|
||||
private boolean hasVarsInRegs;
|
||||
private boolean itsForcedObjectParameters;
|
||||
private boolean trivialInit;
|
||||
private short itsLocalAllocationBase;
|
||||
private VariableTable vars;
|
||||
private VariableTable debugVars;
|
||||
private OptLocalVariable[] debugVars;
|
||||
private int epilogueLabel;
|
||||
private int optLevel;
|
||||
}
|
||||
|
|
|
@ -39,15 +39,26 @@ package org.mozilla.javascript.optimizer;
|
|||
import org.mozilla.javascript.*;
|
||||
import java.util.*;
|
||||
|
||||
public class OptFunctionNode extends FunctionNode {
|
||||
class OptFunctionNode extends FunctionNode {
|
||||
|
||||
public OptFunctionNode(String name, Node statements, String className)
|
||||
OptFunctionNode(String name, Node statements, String className)
|
||||
{
|
||||
super(name, statements);
|
||||
itsClassName = className;
|
||||
}
|
||||
|
||||
public String getDirectCallParameterSignature() {
|
||||
public void setVariableTable(VariableTable variableTable) {
|
||||
super.setVariableTable(variableTable);
|
||||
int N = variableTable.size();
|
||||
int parameterCount = variableTable.getParameterCount();
|
||||
optVars = new OptLocalVariable[N];
|
||||
for (int i = 0; i != N; ++i) {
|
||||
String name = variableTable.getVariable(i);
|
||||
optVars[i] = new OptLocalVariable(name, i < parameterCount);
|
||||
}
|
||||
}
|
||||
|
||||
String getDirectCallParameterSignature() {
|
||||
int pCount = itsVariableTable.getParameterCount();
|
||||
switch (pCount) {
|
||||
case 0: return ZERO_PARAM_SIG;
|
||||
|
@ -64,15 +75,15 @@ public class OptFunctionNode extends FunctionNode {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
String getClassName() {
|
||||
return itsClassName;
|
||||
}
|
||||
|
||||
public boolean isTargetOfDirectCall() {
|
||||
boolean isTargetOfDirectCall() {
|
||||
return itsIsTargetOfDirectCall;
|
||||
}
|
||||
|
||||
public void addDirectCallTarget(FunctionNode target) {
|
||||
void addDirectCallTarget(FunctionNode target) {
|
||||
if (itsDirectCallTargets == null)
|
||||
itsDirectCallTargets = new ObjArray();
|
||||
for (int i = 0; i < itsDirectCallTargets.size(); i++) // OPT !!
|
||||
|
@ -81,40 +92,65 @@ public class OptFunctionNode extends FunctionNode {
|
|||
itsDirectCallTargets.add(target);
|
||||
}
|
||||
|
||||
public ObjArray getDirectCallTargets() {
|
||||
ObjArray getDirectCallTargets() {
|
||||
return itsDirectCallTargets;
|
||||
}
|
||||
|
||||
public void setIsTargetOfDirectCall() {
|
||||
void setIsTargetOfDirectCall() {
|
||||
itsIsTargetOfDirectCall = true;
|
||||
}
|
||||
|
||||
public void setParameterNumberContext(boolean b) {
|
||||
void setParameterNumberContext(boolean b) {
|
||||
itsParameterNumberContext = b;
|
||||
}
|
||||
|
||||
public boolean getParameterNumberContext() {
|
||||
boolean getParameterNumberContext() {
|
||||
return itsParameterNumberContext;
|
||||
}
|
||||
|
||||
public boolean containsCalls(int argCount) {
|
||||
boolean containsCalls(int argCount) {
|
||||
if ((argCount < itsContainsCallsCount.length) && (argCount >= 0))
|
||||
return itsContainsCallsCount[argCount];
|
||||
else
|
||||
return itsContainsCalls;
|
||||
}
|
||||
|
||||
public void setContainsCalls(int argCount) {
|
||||
void setContainsCalls(int argCount) {
|
||||
if (argCount < itsContainsCallsCount.length)
|
||||
itsContainsCallsCount[argCount] = true;
|
||||
itsContainsCalls = true;
|
||||
}
|
||||
|
||||
public void incrementLocalCount() {
|
||||
void incrementLocalCount() {
|
||||
int localCount = getIntProp(Node.LOCALCOUNT_PROP, 0);
|
||||
putIntProp(Node.LOCALCOUNT_PROP, localCount + 1);
|
||||
}
|
||||
|
||||
int getVarCount() {
|
||||
return optVars.length;
|
||||
}
|
||||
|
||||
OptLocalVariable getVar(int index) {
|
||||
return optVars[index];
|
||||
}
|
||||
|
||||
OptLocalVariable getVar(String name) {
|
||||
int index = itsVariableTable.getOrdinal(name);
|
||||
if (index < 0) { return null; }
|
||||
return optVars[index];
|
||||
}
|
||||
|
||||
void establishVarsIndices() {
|
||||
int N = optVars.length;
|
||||
for (int i = 0; i != N; i++) {
|
||||
optVars[i].setIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
OptLocalVariable[] getVarsArray() {
|
||||
return optVars;
|
||||
}
|
||||
|
||||
private static final String
|
||||
BEFORE_DIRECT_SIG = "(Lorg/mozilla/javascript/Context;"
|
||||
+"Lorg/mozilla/javascript/Scriptable;"
|
||||
|
@ -128,6 +164,7 @@ public class OptFunctionNode extends FunctionNode {
|
|||
TWO_PARAM_SIG = BEFORE_DIRECT_SIG+DIRECT_ARG_SIG+DIRECT_ARG_SIG
|
||||
+AFTER_DIRECT_SIG;
|
||||
|
||||
private OptLocalVariable[] optVars;
|
||||
private String itsClassName;
|
||||
private boolean itsIsTargetOfDirectCall;
|
||||
private boolean itsContainsCalls;
|
||||
|
|
|
@ -117,30 +117,6 @@ final class OptLocalVariable implements JavaVariable {
|
|||
return itsTypeUnion.getEvent();
|
||||
}
|
||||
|
||||
static OptLocalVariable get(VariableTable vars, int index) {
|
||||
return (OptLocalVariable)(vars.getVariable(index));
|
||||
}
|
||||
|
||||
static OptLocalVariable get(VariableTable vars, String name) {
|
||||
return (OptLocalVariable)(vars.getVariable(name));
|
||||
}
|
||||
|
||||
static void establishIndices(VariableTable vars) {
|
||||
int N = vars.size();
|
||||
for (int i = 0; i != N; i++) {
|
||||
get(vars, i).itsIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
static OptLocalVariable[] toArray(VariableTable vars) {
|
||||
OptLocalVariable[] array = null;
|
||||
if (vars != null) {
|
||||
array = new OptLocalVariable[vars.size()];
|
||||
vars.getAllVariables(array);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private String itsName;
|
||||
private boolean itsIsParameter;
|
||||
private int itsIndex = -1;
|
||||
|
|
|
@ -100,10 +100,6 @@ class OptTransformer extends NodeTransformer {
|
|||
return argCount;
|
||||
}
|
||||
|
||||
protected Object createVariableObject(String name, boolean isParameter) {
|
||||
return new OptLocalVariable(name, isParameter);
|
||||
}
|
||||
|
||||
protected void visitNew(Node node, Node tree) {
|
||||
detectDirectCall(node, tree);
|
||||
super.visitNew(node, tree);
|
||||
|
@ -129,20 +125,20 @@ class OptTransformer extends NodeTransformer {
|
|||
* else
|
||||
* ScriptRuntime.Call(fn, tmp, b, c)
|
||||
*/
|
||||
void markDirectCall(Node containingTree, Node callNode, int argCount,
|
||||
String targetName)
|
||||
private void markDirectCall(Node containingTree, Node callNode,
|
||||
int argCount, String targetName)
|
||||
{
|
||||
OptFunctionNode theFunction
|
||||
= (OptFunctionNode)theFnClassNameList.get(targetName);
|
||||
if (theFunction != null) {
|
||||
VariableTable varTable = theFunction.getVariableTable();
|
||||
int N = theFunction.getParameterCount();
|
||||
// Refuse to directCall any function with more
|
||||
// than 32 parameters - prevent code explosion
|
||||
// for wacky test cases
|
||||
if (varTable.getParameterCount() > 32)
|
||||
if (N > 32)
|
||||
return;
|
||||
|
||||
if (argCount == varTable.getParameterCount()) {
|
||||
if (argCount == N) {
|
||||
callNode.putProp(Node.DIRECTCALL_PROP, theFunction);
|
||||
((OptFunctionNode)containingTree)
|
||||
.addDirectCallTarget(theFunction);
|
||||
|
@ -180,7 +176,6 @@ class OptTransformer extends NodeTransformer {
|
|||
*/
|
||||
theFnClassNameList.put(name, fnNode);
|
||||
}
|
||||
addParameters(fnNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,48 +86,44 @@ class Optimizer {
|
|||
pw.println(Block.toString(theBlocks, theStatementNodes));
|
||||
}
|
||||
|
||||
VariableTable vars = theFunction.getVariableTable();
|
||||
if (vars != null) {
|
||||
OptLocalVariable.establishIndices(vars);
|
||||
for (int i = 0; i < theStatementNodes.length; i++)
|
||||
replaceVariableAccess(theStatementNodes[i], vars);
|
||||
theFunction.establishVarsIndices();
|
||||
for (int i = 0; i < theStatementNodes.length; i++)
|
||||
replaceVariableAccess(theStatementNodes[i], theFunction);
|
||||
|
||||
if(DO_CONSTANT_FOLDING){
|
||||
foldConstants(theFunction, null);
|
||||
}
|
||||
if(DO_CONSTANT_FOLDING){
|
||||
foldConstants(theFunction, null);
|
||||
}
|
||||
|
||||
reachingDefDataFlow(vars, theBlocks);
|
||||
typeFlow(vars, theBlocks);
|
||||
findSinglyTypedVars(vars, theBlocks);
|
||||
localCSE(theBlocks, theFunction);
|
||||
if (!theFunction.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);
|
||||
//System.out.println("Function " + theFunction.getFunctionName() + " has parameters in number contexts : " + parameterUsedInNumberContext);
|
||||
reachingDefDataFlow(theFunction, theBlocks);
|
||||
typeFlow(theFunction, theBlocks);
|
||||
findSinglyTypedVars(theFunction, theBlocks);
|
||||
localCSE(theBlocks, theFunction);
|
||||
if (!theFunction.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]);
|
||||
}
|
||||
if (DEBUG_OPTIMIZER) {
|
||||
for (int i = 0; i < theBlocks.length; i++) {
|
||||
pw.println("For block " + theBlocks[i].getBlockID());
|
||||
theBlocks[i].printLiveOnEntrySet(pw, vars);
|
||||
}
|
||||
int N = vars.size();
|
||||
System.out.println("Variable Table, size = " + N);
|
||||
for (int i = 0; i != N; i++) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(vars, i);
|
||||
pw.println(lVar.toString());
|
||||
}
|
||||
theFunction.setParameterNumberContext(parameterUsedInNumberContext);
|
||||
//System.out.println("Function " + theFunction.getFunctionName() + " has parameters in number contexts : " + parameterUsedInNumberContext);
|
||||
}
|
||||
if (DEBUG_OPTIMIZER) {
|
||||
for (int i = 0; i < theBlocks.length; i++) {
|
||||
pw.println("For block " + theBlocks[i].getBlockID());
|
||||
theBlocks[i].printLiveOnEntrySet(pw, theFunction);
|
||||
}
|
||||
int N = theFunction.getVarCount();
|
||||
System.out.println("Variable Table, size = " + N);
|
||||
for (int i = 0; i != N; i++) {
|
||||
OptLocalVariable lVar = theFunction.getVar(i);
|
||||
pw.println(lVar.toString());
|
||||
}
|
||||
|
||||
}
|
||||
if (DEBUG_OPTIMIZER) pw.close();
|
||||
}
|
||||
|
@ -140,7 +136,7 @@ class Optimizer {
|
|||
}
|
||||
|
||||
private static void
|
||||
findSinglyTypedVars(VariableTable theVariables, Block theBlocks[])
|
||||
findSinglyTypedVars(OptFunctionNode fn, Block theBlocks[])
|
||||
{
|
||||
/*
|
||||
discover the type events for each non-volatile variable (not live
|
||||
|
@ -158,8 +154,8 @@ class Optimizer {
|
|||
theBlocks[i].findDefs();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < theVariables.size(); i++) {
|
||||
OptLocalVariable lVar = OptLocalVariable.get(theVariables, i);
|
||||
for (int i = 0; i < fn.getVarCount(); i++) {
|
||||
OptLocalVariable lVar = fn.getVar(i);
|
||||
if (!lVar.isParameter()) {
|
||||
int theType = lVar.getTypeUnion();
|
||||
if (theType == TypeEvent.NumberType) {
|
||||
|
@ -201,7 +197,7 @@ class Optimizer {
|
|||
}
|
||||
|
||||
private static void
|
||||
typeFlow(VariableTable theVariables, Block theBlocks[])
|
||||
typeFlow(OptFunctionNode fn, Block theBlocks[])
|
||||
{
|
||||
boolean visit[] = new boolean[theBlocks.length];
|
||||
boolean doneOnce[] = new boolean[theBlocks.length];
|
||||
|
@ -237,7 +233,7 @@ class Optimizer {
|
|||
}
|
||||
|
||||
private static void
|
||||
reachingDefDataFlow(VariableTable theVariables, Block theBlocks[])
|
||||
reachingDefDataFlow(OptFunctionNode fn, Block theBlocks[])
|
||||
{
|
||||
/*
|
||||
initialize the liveOnEntry and liveOnExit sets, then discover the variables
|
||||
|
@ -245,7 +241,7 @@ class Optimizer {
|
|||
(hence liveOnEntry)
|
||||
*/
|
||||
for (int i = 0; i < theBlocks.length; i++) {
|
||||
theBlocks[i].initLiveOnEntrySets(theVariables);
|
||||
theBlocks[i].initLiveOnEntrySets(fn);
|
||||
}
|
||||
/*
|
||||
this visits every block starting at the last, re-adding the predecessors of
|
||||
|
@ -294,10 +290,10 @@ class Optimizer {
|
|||
*/
|
||||
|
||||
for (int i = 0; i < theBlocks.length; i++) {
|
||||
theBlocks[i].markVolatileVariables(theVariables);
|
||||
theBlocks[i].markVolatileVariables(fn);
|
||||
}
|
||||
|
||||
theBlocks[0].markAnyTypeVariables(theVariables);
|
||||
theBlocks[0].markAnyTypeVariables(fn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -989,23 +985,23 @@ class Optimizer {
|
|||
}
|
||||
|
||||
private static void
|
||||
replaceVariableAccess(Node n, VariableTable theVariables)
|
||||
replaceVariableAccess(Node n, OptFunctionNode fn)
|
||||
{
|
||||
Node child = n.getFirstChild();
|
||||
while (child != null) {
|
||||
replaceVariableAccess(child, theVariables);
|
||||
replaceVariableAccess(child, fn);
|
||||
child = child.getNext();
|
||||
}
|
||||
int type = n.getType();
|
||||
if (type == TokenStream.SETVAR) {
|
||||
String name = n.getFirstChild().getString();
|
||||
OptLocalVariable theVar = OptLocalVariable.get(theVariables, name);
|
||||
OptLocalVariable theVar = fn.getVar(name);
|
||||
if (theVar != null) {
|
||||
n.putProp(Node.VARIABLE_PROP, theVar);
|
||||
}
|
||||
} else if (type == TokenStream.GETVAR) {
|
||||
String name = n.getString();
|
||||
OptLocalVariable theVar = OptLocalVariable.get(theVariables, name);
|
||||
OptLocalVariable theVar = fn.getVar(name);
|
||||
if (theVar != null) {
|
||||
n.putProp(Node.VARIABLE_PROP, theVar);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче