mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 20:30:41 +00:00
Simplification of optimized node transformer: search for direct call optimization targets in Codegen.transform before constructing ObjTransformer instance to avoid additional checks for top-level script in ObjTransformer.transform
This commit is contained in:
parent
bc0b7a93d9
commit
c0145a6724
@ -77,12 +77,38 @@ public class Codegen extends Interpreter {
|
||||
public ScriptOrFnNode
|
||||
transform(Context cx, IRFactory irFactory, ScriptOrFnNode tree)
|
||||
{
|
||||
int optimizationLevel = cx.getOptimizationLevel();
|
||||
OptTransformer opt = new OptTransformer(irFactory, new Hashtable(11));
|
||||
tree = opt.transform(tree);
|
||||
if (optimizationLevel > 0) {
|
||||
(new Optimizer(irFactory)).optimize(tree, optimizationLevel);
|
||||
int optLevel = cx.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() == TokenStream.SCRIPT) {
|
||||
int functionCount = tree.getFunctionCount();
|
||||
for (int i = 0; i != functionCount; ++i) {
|
||||
OptFunctionNode fn;
|
||||
fn = (OptFunctionNode)tree.getFunctionNode(i);
|
||||
if (fn.getType() == FunctionNode.FUNCTION_STATEMENT) {
|
||||
String name = fn.getFunctionName();
|
||||
if (name.length() != 0) {
|
||||
if (possibleDirectCalls == null) {
|
||||
possibleDirectCalls = new Hashtable();
|
||||
}
|
||||
possibleDirectCalls.put(name, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(new OptTransformer(irFactory, possibleDirectCalls)).transform(tree);
|
||||
|
||||
if (optLevel > 0) {
|
||||
(new Optimizer(irFactory)).optimize(tree, optLevel);
|
||||
}
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
@ -47,55 +47,15 @@ import java.util.Hashtable;
|
||||
*/
|
||||
|
||||
class OptTransformer extends NodeTransformer {
|
||||
private Hashtable theFnClassNameList;
|
||||
|
||||
OptTransformer(IRFactory irFactory, Hashtable theFnClassNameList) {
|
||||
super(irFactory);
|
||||
this.theFnClassNameList = theFnClassNameList;
|
||||
}
|
||||
|
||||
public NodeTransformer newInstance() {
|
||||
Hashtable listCopy = (Hashtable) theFnClassNameList.clone();
|
||||
return new OptTransformer(irFactory, listCopy);
|
||||
}
|
||||
|
||||
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 (scriptOrFn.getType() == TokenStream.SCRIPT) {
|
||||
collectContainedFunctions(scriptOrFn);
|
||||
}
|
||||
return super.transform(scriptOrFn);
|
||||
}
|
||||
|
||||
private int detectDirectCall(Node node, ScriptOrFnNode tree)
|
||||
OptTransformer(IRFactory irFactory, Hashtable possibleDirectCalls)
|
||||
{
|
||||
Context cx = Context.getCurrentContext();
|
||||
int optLevel = cx.getOptimizationLevel();
|
||||
Node left = node.getFirstChild();
|
||||
super(irFactory);
|
||||
this.possibleDirectCalls = possibleDirectCalls;
|
||||
}
|
||||
|
||||
// count the arguments
|
||||
int argCount = 0;
|
||||
Node arg = left.getNext();
|
||||
while (arg != null) {
|
||||
arg = arg.getNext();
|
||||
argCount++;
|
||||
}
|
||||
|
||||
if (tree.getType() == TokenStream.FUNCTION && optLevel > 0) {
|
||||
if (left.getType() == TokenStream.NAME) {
|
||||
markDirectCall(tree, node, argCount, left.getString());
|
||||
} else {
|
||||
if (left.getType() == TokenStream.GETPROP) {
|
||||
Node name = left.getFirstChild().getNext();
|
||||
markDirectCall(tree, node, argCount, name.getString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return argCount;
|
||||
protected NodeTransformer newInstance() {
|
||||
return new OptTransformer(irFactory, possibleDirectCalls);
|
||||
}
|
||||
|
||||
protected void visitNew(Node node, ScriptOrFnNode tree) {
|
||||
@ -104,62 +64,62 @@ class OptTransformer extends NodeTransformer {
|
||||
}
|
||||
|
||||
protected void visitCall(Node node, ScriptOrFnNode tree) {
|
||||
int argCount = detectDirectCall(node, tree);
|
||||
if (inFunction && (argCount == 0)) {
|
||||
((OptFunctionNode)tree).itsContainsCalls0 = true;
|
||||
}
|
||||
|
||||
detectDirectCall(node, tree);
|
||||
super.visitCall(node, tree);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
private void markDirectCall(Node containingTree, Node callNode,
|
||||
int argCount, String targetName)
|
||||
private void detectDirectCall(Node node, ScriptOrFnNode tree)
|
||||
{
|
||||
OptFunctionNode theFunction
|
||||
= (OptFunctionNode)theFnClassNameList.get(targetName);
|
||||
if (theFunction != null) {
|
||||
int N = theFunction.getParamCount();
|
||||
// Refuse to directCall any function with more
|
||||
// than 32 parameters - prevent code explosion
|
||||
// for wacky test cases
|
||||
if (N > 32)
|
||||
return;
|
||||
if (tree.getType() == TokenStream.FUNCTION) {
|
||||
Node left = node.getFirstChild();
|
||||
|
||||
if (argCount == N) {
|
||||
callNode.putProp(Node.DIRECTCALL_PROP, theFunction);
|
||||
theFunction.setIsTargetOfDirectCall();
|
||||
// count the arguments
|
||||
int argCount = 0;
|
||||
Node arg = left.getNext();
|
||||
while (arg != null) {
|
||||
arg = arg.getNext();
|
||||
argCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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);
|
||||
if (argCount == 0) {
|
||||
((OptFunctionNode)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() == TokenStream.NAME) {
|
||||
targetName = left.getString();
|
||||
} else if (left.getType() == TokenStream.GETPROP) {
|
||||
targetName = left.getFirstChild().getNext().getString();
|
||||
}
|
||||
if (targetName != null) {
|
||||
OptFunctionNode fn;
|
||||
fn = (OptFunctionNode)possibleDirectCalls.get(targetName);
|
||||
if (fn != null && argCount == fn.getParamCount()) {
|
||||
// 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, fn);
|
||||
fn.setIsTargetOfDirectCall();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Hashtable possibleDirectCalls;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user