mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
More parser internal changes: move all logic to initialize variable table to ScriptOrFnNode.finishParsing and its overrides in FunctionNode/OptFunctionNode so it will be constructed during parsing to avoid checks for function types in NodeTransformer.
This commit is contained in:
parent
64da256e04
commit
3f34720cd5
@ -49,8 +49,6 @@ public class FunctionNode extends ScriptOrFnNode {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
protected void markVariableTableReady() { }
|
||||
|
||||
public boolean requiresActivation() {
|
||||
return itsNeedsActivation;
|
||||
}
|
||||
@ -98,6 +96,57 @@ public class FunctionNode extends ScriptOrFnNode {
|
||||
return getVariableTable().getParameterCount();
|
||||
}
|
||||
|
||||
protected void finishParsing(IRFactory irFactory) {
|
||||
super.finishParsing(irFactory);
|
||||
int functionCount = getFunctionCount();
|
||||
if (functionCount != 0) {
|
||||
for (int i = 0; i != functionCount; ++i) {
|
||||
FunctionNode fn = getFunctionNode(i);
|
||||
|
||||
// Nested functions must check their 'this' value to insure
|
||||
// it is not an activation object: see 10.1.6 Activation Object
|
||||
fn.setCheckThis(true);
|
||||
|
||||
// nested function expression statements overrides var
|
||||
if (fn.getFunctionType() == FUNCTION_EXPRESSION_STATEMENT) {
|
||||
String name = fn.getFunctionName();
|
||||
if (name != null && name.length() != 0) {
|
||||
removeParameterOrVar(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Functions containing other functions require activation objects
|
||||
setRequiresActivation(true);
|
||||
}
|
||||
|
||||
Node stmts = getLastChild();
|
||||
if (getFunctionType() == FUNCTION_EXPRESSION) {
|
||||
String name = getFunctionName();
|
||||
if (name != null && name.length() != 0 && !hasParameterOrVar(name))
|
||||
{
|
||||
// A function expression needs to have its name as a
|
||||
// variable (if it isn't already allocated as a variable).
|
||||
// See 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.
|
||||
addVar(name);
|
||||
Node setFn = new Node(TokenStream.POP,
|
||||
new Node(TokenStream.SETVAR,
|
||||
Node.newString(name),
|
||||
new Node(TokenStream.PRIMARY,
|
||||
TokenStream.THISFN)));
|
||||
stmts.addChildrenToFront(setFn);
|
||||
}
|
||||
}
|
||||
|
||||
// Add return to end if needed.
|
||||
Node lastStmt = stmts.getLastChild();
|
||||
if (lastStmt == null || lastStmt.getType() != TokenStream.RETURN) {
|
||||
stmts.addChildToBack(new Node(TokenStream.RETURN));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean itsNeedsActivation;
|
||||
protected boolean itsCheckThis;
|
||||
protected int itsFunctionType;
|
||||
|
@ -48,7 +48,7 @@ public class IRFactory {
|
||||
this.compiler = compiler;
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
|
||||
public ScriptOrFnNode createScript() {
|
||||
return new ScriptOrFnNode(TokenStream.SCRIPT);
|
||||
}
|
||||
@ -67,6 +67,7 @@ public class IRFactory {
|
||||
|
||||
Node children = ((Node) body).getFirstChild();
|
||||
if (children != null) { scriptNode.addChildrenToBack(children); }
|
||||
scriptNode.finishParsing(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,7 +208,7 @@ public class IRFactory {
|
||||
return compiler.createFunctionNode(this, name);
|
||||
}
|
||||
|
||||
public Object initFunction(FunctionNode fnNode, int functionIndex,
|
||||
public Object initFunction(FunctionNode fnNode, int functionIndex,
|
||||
Object statements,
|
||||
String sourceName, int baseLineno,
|
||||
int endLineno, String source,
|
||||
@ -219,7 +220,8 @@ public class IRFactory {
|
||||
fnNode.setEndLineno(endLineno);
|
||||
fnNode.setFunctionType(functionType);
|
||||
fnNode.addChildToBack((Node)statements);
|
||||
|
||||
fnNode.finishParsing(this);
|
||||
|
||||
Node result = Node.newString(TokenStream.FUNCTION,
|
||||
fnNode.getFunctionName());
|
||||
result.putIntProp(Node.FUNCTION_PROP, functionIndex);
|
||||
|
@ -63,38 +63,6 @@ public class NodeTransformer {
|
||||
loops = new ObjArray();
|
||||
loopEnds = new ObjArray();
|
||||
inFunction = tree.getType() == TokenStream.FUNCTION;
|
||||
VariableTable vars = tree.getVariableTable();
|
||||
if (inFunction) {
|
||||
Node stmts = tree.getLastChild();
|
||||
FunctionNode fn = (FunctionNode)tree;
|
||||
if (fn.getFunctionType() == FunctionNode.FUNCTION_EXPRESSION) {
|
||||
String name = fn.getFunctionName();
|
||||
if (name != null && name.length() != 0
|
||||
&& !vars.hasVariable(name))
|
||||
{
|
||||
// A function expression needs to have its name as a
|
||||
// variable (if it isn't already allocated as a variable).
|
||||
// See 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);
|
||||
Node setFn = new Node(TokenStream.POP,
|
||||
new Node(TokenStream.SETVAR,
|
||||
Node.newString(name),
|
||||
new Node(TokenStream.PRIMARY,
|
||||
TokenStream.THISFN)));
|
||||
stmts.addChildrenToFront(setFn);
|
||||
}
|
||||
}
|
||||
// Add return to end if needed.
|
||||
Node lastStmt = stmts.getLastChild();
|
||||
if (lastStmt == null ||
|
||||
lastStmt.getType() != TokenStream.RETURN)
|
||||
{
|
||||
stmts.addChildToBack(new Node(TokenStream.RETURN));
|
||||
}
|
||||
fn.markVariableTableReady();
|
||||
}
|
||||
|
||||
// to save against upchecks if no finally blocks are used.
|
||||
boolean hasFinally = false;
|
||||
@ -111,16 +79,6 @@ public class NodeTransformer {
|
||||
if (node != tree) {
|
||||
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
|
||||
FunctionNode fnNode = tree.getFunctionNode(fnIndex);
|
||||
if (inFunction) {
|
||||
// Functions containing other functions require
|
||||
// activation objects
|
||||
((FunctionNode) tree).setRequiresActivation(true);
|
||||
|
||||
// Nested functions must check their 'this' value to
|
||||
// insure it is not an activation object:
|
||||
// see 10.1.6 Activation Object
|
||||
fnNode.setCheckThis(true);
|
||||
}
|
||||
NodeTransformer inner = newInstance();
|
||||
fnNode = (FunctionNode)inner.transform(fnNode);
|
||||
tree.replaceFunctionNode(fnIndex, fnNode);
|
||||
@ -431,7 +389,7 @@ public class NodeTransformer {
|
||||
// use of "arguments" requires an activation object.
|
||||
((FunctionNode) tree).setRequiresActivation(true);
|
||||
}
|
||||
if (vars.hasVariable(name)) {
|
||||
if (tree.hasParameterOrVar(name)) {
|
||||
if (type == TokenStream.SETNAME) {
|
||||
node.setType(TokenStream.SETVAR);
|
||||
bind.setType(TokenStream.STRING);
|
||||
@ -471,7 +429,7 @@ public class NodeTransformer {
|
||||
// Use of "arguments" requires an activation object.
|
||||
((FunctionNode) tree).setRequiresActivation(true);
|
||||
}
|
||||
if (vars.hasVariable(name)) {
|
||||
if (tree.hasParameterOrVar(name)) {
|
||||
node.setType(TokenStream.GETVAR);
|
||||
}
|
||||
break;
|
||||
@ -512,9 +470,10 @@ public class NodeTransformer {
|
||||
}
|
||||
boolean addGetThis = false;
|
||||
if (left.getType() == TokenStream.NAME) {
|
||||
VariableTable vars = tree.getVariableTable();
|
||||
String name = left.getString();
|
||||
if (inFunction && vars.hasVariable(name) && !inWithStatement()) {
|
||||
if (inFunction && tree.hasParameterOrVar(name)
|
||||
&& !inWithStatement())
|
||||
{
|
||||
// call to a var. Transform to Call(GetVar("a"), b, c)
|
||||
left.setType(TokenStream.GETVAR);
|
||||
// fall through to code to add GetParent
|
||||
|
@ -99,10 +99,9 @@ class Parser {
|
||||
throws IOException
|
||||
{
|
||||
currentScriptOrFn = nf.createScript();
|
||||
|
||||
|
||||
this.ok = true;
|
||||
fn_sourceTop = 0;
|
||||
fn_funcExprStmNames = null;
|
||||
sourceTop = 0;
|
||||
|
||||
int tt; // last token from getToken();
|
||||
int baseLineno = ts.getLineno(); // line number where source starts
|
||||
@ -145,7 +144,7 @@ class Parser {
|
||||
|
||||
String source = sourceToString(0);
|
||||
sourceBuffer = null; // To help GC
|
||||
|
||||
|
||||
nf.initScript(currentScriptOrFn, pn, ts.getSourceName(),
|
||||
baseLineno, ts.getLineno(), source);
|
||||
return currentScriptOrFn;
|
||||
@ -240,9 +239,8 @@ class Parser {
|
||||
|
||||
// Save current source top to restore it on exit not to include
|
||||
// function to parent source
|
||||
int saved_sourceTop = fn_sourceTop;
|
||||
ObjArray saved_funcExprStmNames = fn_funcExprStmNames;
|
||||
|
||||
int saved_sourceTop = sourceTop;
|
||||
|
||||
ScriptOrFnNode savedScriptOrFn = currentScriptOrFn;
|
||||
currentScriptOrFn = fnNode;
|
||||
|
||||
@ -285,13 +283,9 @@ class Parser {
|
||||
|
||||
// name might be null;
|
||||
source = sourceToString(saved_sourceTop);
|
||||
|
||||
// Remove name clashes for nested functions
|
||||
checkVariables(fnNode, fn_funcExprStmNames);
|
||||
}
|
||||
finally {
|
||||
fn_sourceTop = saved_sourceTop;
|
||||
fn_funcExprStmNames = saved_funcExprStmNames;
|
||||
sourceTop = saved_sourceTop;
|
||||
currentScriptOrFn = savedScriptOrFn;
|
||||
}
|
||||
|
||||
@ -303,14 +297,6 @@ class Parser {
|
||||
source,
|
||||
functionType);
|
||||
if (functionType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
|
||||
// Record the name to check for possible var and
|
||||
// function expression statement name clashes
|
||||
if (name.length()!= 0) {
|
||||
if (fn_funcExprStmNames == null) {
|
||||
fn_funcExprStmNames = new ObjArray();
|
||||
}
|
||||
fn_funcExprStmNames.add(name);
|
||||
}
|
||||
// The following can be removed but then code generators should
|
||||
// be modified not to push on the stack function expression
|
||||
// statements
|
||||
@ -341,19 +327,6 @@ class Parser {
|
||||
return pn;
|
||||
}
|
||||
|
||||
private static void
|
||||
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);
|
||||
scriptOrFn.removeParameterOrVar(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object statements(TokenStream ts)
|
||||
throws IOException
|
||||
{
|
||||
@ -1492,11 +1465,11 @@ class Parser {
|
||||
|
||||
*/
|
||||
private void sourceAdd(char c) {
|
||||
if (fn_sourceTop == sourceBuffer.length) {
|
||||
increaseSourceCapacity(fn_sourceTop + 1);
|
||||
if (sourceTop == sourceBuffer.length) {
|
||||
increaseSourceCapacity(sourceTop + 1);
|
||||
}
|
||||
sourceBuffer[fn_sourceTop] = c;
|
||||
++fn_sourceTop;
|
||||
sourceBuffer[sourceTop] = c;
|
||||
++sourceTop;
|
||||
}
|
||||
|
||||
private void sourceAddString(int type, String str) {
|
||||
@ -1510,20 +1483,20 @@ class Parser {
|
||||
if (L >= 0x8000) {
|
||||
lengthEncodingSize = 2;
|
||||
}
|
||||
int nextTop = fn_sourceTop + lengthEncodingSize + L;
|
||||
int nextTop = sourceTop + lengthEncodingSize + L;
|
||||
if (nextTop > sourceBuffer.length) {
|
||||
increaseSourceCapacity(nextTop);
|
||||
}
|
||||
if (L >= 0x8000) {
|
||||
// Use 2 chars to encode strings exceeding 32K, were the highest
|
||||
// bit in the first char indicates presence of the next byte
|
||||
sourceBuffer[fn_sourceTop] = (char)(0x8000 | (L >>> 16));
|
||||
++fn_sourceTop;
|
||||
sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16));
|
||||
++sourceTop;
|
||||
}
|
||||
sourceBuffer[fn_sourceTop] = (char)L;
|
||||
++fn_sourceTop;
|
||||
str.getChars(0, L, sourceBuffer, fn_sourceTop);
|
||||
fn_sourceTop = nextTop;
|
||||
sourceBuffer[sourceTop] = (char)L;
|
||||
++sourceTop;
|
||||
str.getChars(0, L, sourceBuffer, sourceTop);
|
||||
sourceTop = nextTop;
|
||||
}
|
||||
|
||||
private void sourceAddNumber(double n) {
|
||||
@ -1586,13 +1559,13 @@ class Parser {
|
||||
newCapacity = minimalCapacity;
|
||||
}
|
||||
char[] tmp = new char[newCapacity];
|
||||
System.arraycopy(sourceBuffer, 0, tmp, 0, fn_sourceTop);
|
||||
System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop);
|
||||
sourceBuffer = tmp;
|
||||
}
|
||||
|
||||
private String sourceToString(int offset) {
|
||||
if (offset < 0 || fn_sourceTop < offset) Context.codeBug();
|
||||
return new String(sourceBuffer, offset, fn_sourceTop - offset);
|
||||
if (offset < 0 || sourceTop < offset) Context.codeBug();
|
||||
return new String(sourceBuffer, offset, sourceTop - offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2300,14 +2273,9 @@ class Parser {
|
||||
|
||||
private char[] sourceBuffer = new char[128];
|
||||
|
||||
// fn_ prefix means per-function data that should be reset/restored in function
|
||||
|
||||
// Per function source buffer top: nested functions sources are not
|
||||
// included in parent.
|
||||
private int fn_sourceTop;
|
||||
|
||||
// Nested function number
|
||||
private ObjArray fn_funcExprStmNames;
|
||||
// Per script/function source buffer top: parent source does not include a
|
||||
// nested functions source and uses function index as a reference instead.
|
||||
private int sourceTop;
|
||||
|
||||
private ScriptOrFnNode currentScriptOrFn;
|
||||
|
||||
|
@ -43,7 +43,7 @@ public class ScriptOrFnNode extends Node {
|
||||
|
||||
public final VariableTable getVariableTable() {
|
||||
if (variableTable == null) { variableTable = new VariableTable(); }
|
||||
return variableTable;
|
||||
return variableTable;
|
||||
}
|
||||
|
||||
public final String getSourceName() { return sourceName; }
|
||||
@ -121,7 +121,7 @@ public class ScriptOrFnNode extends Node {
|
||||
regexps.add(flags);
|
||||
return regexps.size() / 2 - 1;
|
||||
}
|
||||
|
||||
|
||||
public final boolean hasParameterOrVar(String name) {
|
||||
if (variableTable == null) { return false; }
|
||||
return variableTable.hasVariable(name);
|
||||
@ -148,6 +148,8 @@ public class ScriptOrFnNode extends Node {
|
||||
++localCount;
|
||||
}
|
||||
|
||||
protected void finishParsing(IRFactory irFactory) { }
|
||||
|
||||
private String encodedSource;
|
||||
private String originalSource;
|
||||
private String sourceName;
|
||||
|
@ -46,8 +46,8 @@ class OptFunctionNode extends FunctionNode {
|
||||
itsClassName = className;
|
||||
}
|
||||
|
||||
protected void markVariableTableReady() {
|
||||
super.markVariableTableReady();
|
||||
protected void finishParsing(IRFactory irFactory) {
|
||||
super.finishParsing(irFactory);
|
||||
VariableTable vars = getVariableTable();
|
||||
int N = vars.size();
|
||||
int parameterCount = getParameterCount();
|
||||
|
Loading…
Reference in New Issue
Block a user