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:
igor%mir2.org 2003-02-19 23:50:42 +00:00
parent 64da256e04
commit 3f34720cd5
6 changed files with 90 additions and 110 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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();