8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
--- a/nashorn/make/project.properties Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/make/project.properties Sat Mar 23 00:58:39 2013 +0100
@@ -210,7 +210,7 @@
# add '-Dtest.js.outofprocess' to run each test in a new sub-process
run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8
#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M
-run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs}
+run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main}
run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy
--- a/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Attr.java Sat Mar 23 00:58:39 2013 +0100
@@ -37,14 +37,16 @@
import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
import static jdk.nashorn.internal.ir.Symbol.IS_LET;
import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
+import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
import static jdk.nashorn.internal.ir.Symbol.IS_THIS;
import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
+import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
import java.util.Set;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
@@ -52,19 +54,19 @@
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CallNode.EvalArgs;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -117,6 +119,8 @@
*/
private Set<String> localUses;
+ private final LexicalContext lexicalContext = new LexicalContext();
+
private static final DebugLogger LOG = new DebugLogger("attr");
private static final boolean DEBUG = LOG.isEnabled();
@@ -137,14 +141,15 @@
}
@Override
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this
end(accessNode);
return accessNode;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
+ lexicalContext.push(block);
start(block);
final Set<String> savedLocalDefs = localDefs;
@@ -160,9 +165,7 @@
localDefs = new HashSet<>(savedLocalDefs);
localUses = new HashSet<>(savedLocalUses);
- for (final Node statement : block.getStatements()) {
- statement.accept(this);
- }
+ block.visitStatements(this);
} finally {
localDefs = savedLocalDefs;
localUses = savedLocalUses;
@@ -172,11 +175,12 @@
end(block);
+ lexicalContext.pop(block);
return null;
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
start(callNode);
callNode.getFunction().accept(this);
@@ -197,8 +201,7 @@
evalArgs.setThis(thisNode);
}
- newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later
- newType(callNode.getFunction().getSymbol(), Type.OBJECT);
+ newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later
end(callNode);
@@ -206,29 +209,106 @@
}
@Override
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
final IdentNode exception = catchNode.getException();
final Block block = getCurrentBlock();
start(catchNode);
// define block-local exception variable
- final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception);
+ final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception);
newType(def, Type.OBJECT);
addLocalDef(exception.getName());
return catchNode;
}
+ /**
+ * Declare the definition of a new symbol.
+ *
+ * @param name Name of symbol.
+ * @param symbolFlags Symbol flags.
+ * @param node Defining Node.
+ *
+ * @return Symbol for given name or null for redefinition.
+ */
+ private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) {
+ int flags = symbolFlags;
+ Symbol symbol = findSymbol(block, name); // Locate symbol.
+
+ if ((flags & KINDMASK) == IS_GLOBAL) {
+ flags |= IS_SCOPE;
+ }
+
+ final FunctionNode function = lexicalContext.getFunction(block);
+ if (symbol != null) {
+ // Symbol was already defined. Check if it needs to be redefined.
+ if ((flags & KINDMASK) == IS_PARAM) {
+ if (!isLocal(function, symbol)) {
+ // Not defined in this function. Create a new definition.
+ symbol = null;
+ } else if (symbol.isParam()) {
+ // Duplicate parameter. Null return will force an error.
+ assert false : "duplicate parameter";
+ return null;
+ }
+ } else if ((flags & KINDMASK) == IS_VAR) {
+ if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) {
+ assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block";
+ // Always create a new definition.
+ symbol = null;
+ } else {
+ // Not defined in this function. Create a new definition.
+ if (!isLocal(function, symbol) || symbol.less(IS_VAR)) {
+ symbol = null;
+ }
+ }
+ }
+ }
+
+ if (symbol == null) {
+ // If not found, then create a new one.
+ Block symbolBlock;
+
+ // Determine where to create it.
+ if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
+ symbolBlock = block;
+ } else {
+ symbolBlock = function;
+ }
+
+ // Create and add to appropriate block.
+ symbol = new Symbol(name, flags, node, symbolBlock);
+ symbolBlock.putSymbol(name, symbol);
+
+ if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
+ symbolBlock.getFrame().addSymbol(symbol);
+ symbol.setNeedsSlot(true);
+ }
+ } else if (symbol.less(flags)) {
+ symbol.setFlags(flags);
+ }
+
+ if (node != null) {
+ node.setSymbol(symbol);
+ }
+
+ return symbol;
+ }
+
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
start(functionNode, false);
if (functionNode.isLazy()) {
- LOG.info("LAZY: " + functionNode.getName());
+ LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT");
+ newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode);
+ functionNode.setReturnType(Type.OBJECT);
end(functionNode);
return null;
}
+ lexicalContext.push(functionNode);
+
clearLocalDefs();
clearLocalUses();
@@ -244,24 +324,36 @@
initScope(functionNode);
initReturn(functionNode);
- // Add all nested functions as symbols in this function
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
+ // Add all nested declared functions as symbols in this function
+ for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) {
final IdentNode ident = nestedFunction.getIdent();
- if (ident != null && nestedFunction.isStatement()) {
- final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction);
+ if (ident != null) {
+ assert nestedFunction.isDeclared();
+ final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction);
newType(functionSymbol, Type.typeFor(ScriptFunction.class));
}
}
- if (functionNode.isScript()) {
+ if (functionNode.isProgram()) {
initFromPropertyMap(functionNode);
}
// Add function name as local symbol
- if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) {
- final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode);
- newType(selfSymbol, Type.OBJECT);
- selfSymbol.setNode(functionNode);
+ if (!functionNode.isDeclared() && !functionNode.isProgram()) {
+ if(functionNode.getSymbol() != null) {
+ // a temporary left over from an earlier pass when the function was lazy
+ assert functionNode.getSymbol().isTemp();
+ // remove it
+ functionNode.setSymbol(null);
+ }
+ final Symbol selfSymbol;
+ if(functionNode.isAnonymous()) {
+ selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode);
+ } else {
+ selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode);
+ newType(selfSymbol, Type.OBJECT);
+ selfSymbol.setNode(functionNode);
+ }
}
/*
@@ -282,32 +374,26 @@
*/
final List<Symbol> declaredSymbols = new ArrayList<>();
- for (final VarNode decl : functionNode.getDeclarations()) {
- final IdentNode ident = decl.getName();
- // any declared symbols that aren't visited need to be typed as well, hence the list
- declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident)));
- }
-
- // Every nested function needs a definition in the outer function with its name. Add these.
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final VarNode varNode = nestedFunction.getFunctionVarNode();
- if (varNode != null) {
- varNode.accept(this);
- assert varNode.isFunctionVarNode() : varNode + " should be function var node";
+ // This visitor will assign symbol to all declared variables, except function declarations (which are taken care
+ // in a separate step above) and "var" declarations in for loop initializers.
+ functionNode.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode nestedFn) {
+ // Don't descend into nested functions
+ return nestedFn == functionNode ? nestedFn : null;
}
- }
-
- for (final Node statement : functionNode.getStatements()) {
- if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) {
- continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined"
+ @Override
+ public Node enterVarNode(VarNode varNode) {
+ if(varNode.isStatement() && !varNode.isFunctionDeclaration()) {
+ final IdentNode ident = varNode.getName();
+ // any declared symbols that aren't visited need to be typed as well, hence the list
+ declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident)));
+ }
+ return null;
}
- statement.accept(this);
- }
+ });
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName());
- nestedFunction.accept(this);
- }
+ visitFunctionStatements(functionNode);
//unknown parameters are promoted to object type.
finalizeParameters(functionNode);
@@ -343,10 +429,19 @@
functionNode.setState(CompilationState.ATTR);
end(functionNode, false);
+ lexicalContext.pop(functionNode);
return null;
}
+ private void visitFunctionStatements(final FunctionNode functionNode) {
+ final List<Node> newStatements = new ArrayList<>(functionNode.getStatements());
+ for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) {
+ stmts.set(stmts.next().accept(this));
+ }
+ functionNode.setStatements(newStatements);
+ }
+
@Override
public Node leaveCONVERT(final UnaryNode unaryNode) {
assert false : "There should be no convert operators in IR during Attribution";
@@ -355,7 +450,7 @@
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
final String name = identNode.getName();
start(identNode);
@@ -372,7 +467,7 @@
final Block block = getCurrentBlock();
final Symbol oldSymbol = identNode.getSymbol();
- Symbol symbol = block.findSymbol(name);
+ Symbol symbol = findSymbol(block, name);
//If an existing symbol with the name is found, use that otherwise, declare a new one
if (symbol != null) {
@@ -396,22 +491,13 @@
}
identNode.setSymbol(symbol);
- if (!getCurrentFunctionNode().isLocal(symbol)) {
- // non-local: we need to put symbol in scope (if it isn't already)
- if (!symbol.isScope()) {
- final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction());
- for (final Block lookupBlock : lookupBlocks) {
- final Symbol refSymbol = lookupBlock.findSymbol(name);
- if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f()
- LOG.finest("Found a ref symbol that must be scope " + refSymbol);
- refSymbol.setIsScope();
- }
- }
- }
+ // non-local: we need to put symbol in scope (if it isn't already)
+ if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) {
+ symbol.setIsScope();
}
} else {
LOG.info("No symbol exists. Declare undefined: " + symbol);
- symbol = block.useSymbol(name, identNode);
+ symbol = useSymbol(block, name, identNode);
// we have never seen this before, it can be undefined
newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway?
symbol.setCanBeUndefined();
@@ -420,9 +506,10 @@
assert symbol != null;
if(symbol.isGlobal()) {
- getCurrentFunctionNode().setUsesGlobalSymbol();
+ setUsesGlobalSymbol();
} else if(symbol.isScope()) {
- getCurrentFunctionNode().setUsesScopeSymbol(symbol);
+ final Iterator<Block> blocks = lexicalContext.getBlocks();
+ blocks.next().setUsesScopeSymbol(symbol, blocks);
}
if (symbol != oldSymbol && !identNode.isInitializedHere()) {
@@ -435,15 +522,68 @@
return null;
}
+ /**
+ * Marks the current function as one using any global symbol. The function and all its parent functions will all be
+ * marked as needing parent scope.
+ * @see #needsParentScope()
+ */
+ private void setUsesGlobalSymbol() {
+ for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) {
+ fns.next().setUsesAncestorScope();
+ }
+ }
+
+ /**
+ * Declare the use of a symbol in a block.
+ *
+ * @param block block in which the symbol is used
+ * @param name Name of symbol.
+ * @param node Using node
+ *
+ * @return Symbol for given name.
+ */
+ private Symbol useSymbol(final Block block, final String name, final Node node) {
+ Symbol symbol = findSymbol(block, name);
+
+ if (symbol == null) {
+ // If not found, declare as a free var.
+ symbol = defineSymbol(block, name, IS_GLOBAL, node);
+ } else {
+ node.setSymbol(symbol);
+ }
+
+ return symbol;
+ }
+
+
+ /**
+ * Search for symbol in the lexical context starting from the given block.
+ * @param name Symbol name.
+ * @return Found symbol or null if not found.
+ */
+ private Symbol findSymbol(final Block block, final String name) {
+ // Search up block chain to locate symbol.
+
+ for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) {
+ // Find name.
+ final Symbol symbol = blocks.next().getExistingSymbol(name);
+ // If found then we are good.
+ if(symbol != null) {
+ return symbol;
+ }
+ }
+ return null;
+ }
+
@Override
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
newTemporary(Type.OBJECT, indexNode); //TORO
return indexNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
try {
start(literalNode);
assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens
@@ -472,14 +612,14 @@
}
@Override
- public Node leave(final ObjectNode objectNode) {
+ public Node leaveObjectNode(final ObjectNode objectNode) {
newTemporary(Type.OBJECT, objectNode);
end(objectNode);
return objectNode;
}
@Override
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
// assign a pseudo symbol to property name, see NASHORN-710
propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT));
end(propertyNode);
@@ -487,31 +627,7 @@
}
@Override
- public Node enter(final ReferenceNode referenceNode) {
- final FunctionNode functionNode = referenceNode.getReference();
- if (functionNode != null) {
- functionNode.addReferencingParentBlock(getCurrentBlock());
- }
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReferenceNode referenceNode) {
- newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though
-
- final FunctionNode functionNode = referenceNode.getReference();
- //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType();
- if (functionNode.isLazy()) {
- LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT");
- functionNode.setReturnType(Type.OBJECT);
- }
- end(referenceNode);
-
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
if (expr != null) {
@@ -530,7 +646,7 @@
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
Type type = Type.UNKNOWN;
for (final CaseNode caseNode : switchNode.getCases()) {
@@ -567,7 +683,7 @@
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
tryNode.setException(exceptionSymbol());
if (tryNode.getFinallyBody() != null) {
@@ -580,13 +696,13 @@
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
start(varNode);
final IdentNode ident = varNode.getName();
final String name = ident.getName();
- final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident);
+ final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident);
assert symbol != null;
LOG.info("VarNode " + varNode + " set symbol " + symbol);
@@ -598,23 +714,15 @@
symbol.setCanBeUndefined();
}
- if (varNode.getInit() != null) {
- varNode.getInit().accept(this);
- }
-
return varNode;
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
final IdentNode ident = varNode.getName();
final String name = ident.getName();
- if (init != null) {
- addLocalDef(name);
- }
-
if (init == null) {
// var x; with no init will be treated like a use of x by
// visit(IdentNode) unless we remove the name
@@ -623,8 +731,10 @@
return varNode;
}
+ addLocalDef(name);
+
final Symbol symbol = varNode.getSymbol();
- final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56
+ final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56
if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) {
// Forbid integers as local vars for now as we have no way to treat them as undefined
newType(symbol, init.getType());
@@ -718,11 +828,9 @@
runtimeNode = new RuntimeNode(unaryNode, request, args);
assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this
- runtimeNode.accept(this);
- return runtimeNode;
+ return leaveRuntimeNode(runtimeNode);
}
-
@Override
public Node leaveNEW(final UnaryNode unaryNode) {
newTemporary(Type.OBJECT, unaryNode);
@@ -755,7 +863,7 @@
runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args);
assert runtimeNode.getSymbol() == unaryNode.getSymbol();
- runtimeNode.accept(this);
+ runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode);
end(unaryNode);
@@ -763,7 +871,7 @@
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode);
return runtimeNode;
}
@@ -823,12 +931,12 @@
final IdentNode ident = (IdentNode)lhs;
final String name = ident.getName();
- Symbol symbol = getCurrentBlock().findSymbol(name);
+ Symbol symbol = findSymbol(getCurrentBlock(), name);
if (symbol == null) {
- symbol = block.defineSymbol(name, IS_GLOBAL, ident);
+ symbol = defineSymbol(block, name, IS_GLOBAL, ident);
binaryNode.setSymbol(symbol);
- } else if (!getCurrentFunctionNode().isLocal(symbol)) {
+ } else if (!isLocal(getCurrentFunctionNode(), symbol)) {
symbol.setIsScope();
}
@@ -838,6 +946,12 @@
return binaryNode;
}
+ private boolean isLocal(FunctionNode function, Symbol symbol) {
+ final Block block = symbol.getBlock();
+ // some temp symbols have no block, so can be assumed local
+ return block == null || lexicalContext.getFunction(block) == function;
+ }
+
@Override
public Node enterASSIGN(final BinaryNode binaryNode) {
return enterAssignmentNode(binaryNode);
@@ -995,7 +1109,7 @@
return leaveBinaryArithmetic(binaryNode);
}
- private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) {
+ private Node leaveCmp(final BinaryNode binaryNode) {
final Node lhs = binaryNode.lhs();
final Node rhs = binaryNode.rhs();
@@ -1033,37 +1147,38 @@
@Override
public Node leaveEQ(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveEQ_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.EQ_STRICT);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveGE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveGT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.GT);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveIN(final BinaryNode binaryNode) {
- try {
- return new RuntimeNode(binaryNode, Request.IN).accept(this);
- } finally {
- end(binaryNode);
- }
+ return leaveBinaryRuntimeOperator(binaryNode, Request.IN);
}
@Override
public Node leaveINSTANCEOF(final BinaryNode binaryNode) {
+ return leaveBinaryRuntimeOperator(binaryNode, Request.INSTANCEOF);
+ }
+
+ private Node leaveBinaryRuntimeOperator(final BinaryNode binaryNode, final Request request) {
try {
- return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this);
+ // Don't do a full RuntimeNode.accept, as we don't want to double-visit the binary node operands
+ return leaveRuntimeNode(new RuntimeNode(binaryNode, request));
} finally {
end(binaryNode);
}
@@ -1071,12 +1186,12 @@
@Override
public Node leaveLE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveLT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.LT);
+ return leaveCmp(binaryNode);
}
@Override
@@ -1091,12 +1206,12 @@
@Override
public Node leaveNE(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE);
+ return leaveCmp(binaryNode);
}
@Override
public Node leaveNE_STRICT(final BinaryNode binaryNode) {
- return leaveCmp(binaryNode, Request.NE_STRICT);
+ return leaveCmp(binaryNode);
}
@Override
@@ -1127,9 +1242,9 @@
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
if (forNode.isForIn()) {
- forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
+ forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73
/*
* Iterators return objects, so we need to widen the scope of the
* init variable if it, for example, has been assigned double type
@@ -1144,7 +1259,7 @@
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node lhs = ternaryNode.rhs();
final Node rhs = ternaryNode.third();
@@ -1159,24 +1274,24 @@
return ternaryNode;
}
- private static void initThis(final FunctionNode functionNode) {
- final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null);
+ private void initThis(final FunctionNode functionNode) {
+ final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null);
newType(thisSymbol, Type.OBJECT);
thisSymbol.setNeedsSlot(true);
functionNode.getThisNode().setSymbol(thisSymbol);
LOG.info("Initialized scope symbol: " + thisSymbol);
}
- private static void initScope(final FunctionNode functionNode) {
- final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
+ private void initScope(final FunctionNode functionNode) {
+ final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null);
newType(scopeSymbol, Type.typeFor(ScriptObject.class));
scopeSymbol.setNeedsSlot(true);
functionNode.getScopeNode().setSymbol(scopeSymbol);
LOG.info("Initialized scope symbol: " + scopeSymbol);
}
- private static void initReturn(final FunctionNode functionNode) {
- final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
+ private void initReturn(final FunctionNode functionNode) {
+ final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null);
newType(returnSymbol, Type.OBJECT);
returnSymbol.setNeedsSlot(true);
functionNode.getResultNode().setSymbol(returnSymbol);
@@ -1186,7 +1301,7 @@
private void initVarArg(final FunctionNode functionNode) {
if (functionNode.isVarArg()) {
- final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
+ final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null);
varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY);
varArgsSymbol.setNeedsSlot(true);
functionNode.getVarArgsNode().setSymbol(varArgsSymbol);
@@ -1194,7 +1309,7 @@
if (functionNode.needsArguments()) {
final String argumentsName = functionNode.getArgumentsNode().getName();
- final Symbol argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null);
+ final Symbol argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null);
newType(argumentsSymbol, Type.typeFor(ScriptObject.class));
argumentsSymbol.setNeedsSlot(true);
functionNode.getArgumentsNode().setSymbol(argumentsSymbol);
@@ -1204,9 +1319,9 @@
}
}
- private static void initCallee(final FunctionNode functionNode) {
+ private void initCallee(final FunctionNode functionNode) {
assert functionNode.getCalleeNode() != null : functionNode + " has no callee";
- final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
+ final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null);
newType(calleeSymbol, Type.typeFor(ScriptFunction.class));
calleeSymbol.setNeedsSlot(true);
functionNode.getCalleeNode().setSymbol(calleeSymbol);
@@ -1226,7 +1341,7 @@
for (final IdentNode param : functionNode.getParameters()) {
addLocalDef(param.getName());
- final Symbol paramSymbol = functionNode.defineSymbol(param.getName(), IS_PARAM, param);
+ final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param);
if (paramSymbol != null) {
final Type callSiteParamType = functionNode.getSpecializedType(param);
if (callSiteParamType != null) {
@@ -1279,15 +1394,15 @@
* Move any properties from a global map into the scope of this method
* @param functionNode the function node for which to init scope vars
*/
- private static void initFromPropertyMap(final FunctionNode functionNode) {
+ private void initFromPropertyMap(final FunctionNode functionNode) {
// For a script, add scope symbols as defined in the property map
- assert functionNode.isScript();
+ assert functionNode.isProgram();
final PropertyMap map = Context.getGlobalMap();
for (final Property property : map.getProperties()) {
final String key = property.getKey();
- final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null);
+ final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null);
newType(symbol, Type.OBJECT);
LOG.info("Added global symbol from property map " + symbol);
}
@@ -1354,7 +1469,7 @@
private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) {
assignmentDest.accept(new NodeVisitor() {
@Override
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
final Node index = indexNode.getIndex();
index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant());
return indexNode;
@@ -1399,7 +1514,7 @@
}
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
return node.isLazy() ? null : node;
}
@@ -1419,7 +1534,7 @@
*/
@SuppressWarnings("fallthrough")
@Override
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
switch (binaryNode.tokenType()) {
default:
@@ -1477,22 +1592,6 @@
return binaryNode;
}
- private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) {
- if (currentFunction.findParentFunction() == topFunction) {
- final List<Block> blocks = new LinkedList<>();
-
- blocks.add(currentFunction.getParent());
- blocks.addAll(currentFunction.getReferencingParentBlocks());
- return blocks;
- }
- /*
- * assumption: all parent blocks of an inner function will always be in the same outer function;
- * therefore we can simply skip through intermediate functions.
- * @see FunctionNode#addReferencingParentBlock(Block)
- */
- return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction);
- }
-
private static boolean isFunctionExpressionSelfReference(final Symbol symbol) {
if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) {
return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName());
@@ -1509,16 +1608,12 @@
return newTemporary(getCurrentFunctionNode(), type, node);
}
- private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) {
- final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null);
+ private Symbol newInternal(final String name, final Type type) {
+ final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null);
iter.setType(type); // NASHORN-73
return iter;
}
- private Symbol newInternal(final String name, final Type type) {
- return newInternal(getCurrentFunctionNode(), name, type);
- }
-
private static void newType(final Symbol symbol, final Type type) {
final Type oldType = symbol.getSymbolType();
symbol.setType(type);
@@ -1577,13 +1672,13 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
toObject(block);
return block;
}
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
toObject(node);
if (node.isLazy()) {
return null;
--- a/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ClassEmitter.java Sat Mar 23 00:58:39 2013 +0100
@@ -195,6 +195,14 @@
}
/**
+ * Returns the name of the compile unit class name.
+ * @return the name of the compile unit class name.
+ */
+ String getUnitClassName() {
+ return unitClassName;
+ }
+
+ /**
* Convert a binary name to a package/class name.
*
* @param name Binary name.
@@ -244,7 +252,7 @@
// $getMap - get the ith entry from the constants table and cast to PropertyMap.
final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class);
getMapMethod.begin();
- getMapMethod.loadConstants(unitClassName)
+ getMapMethod.loadConstants()
.load(Type.INT, 0)
.arrayload()
.checkcast(PropertyMap.class)
@@ -254,7 +262,7 @@
// $setMap - overwrite an existing map.
final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class);
setMapMethod.begin();
- setMapMethod.loadConstants(unitClassName)
+ setMapMethod.loadConstants()
.load(Type.INT, 0)
.load(Type.OBJECT, 1)
.arraystore();
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Mar 23 00:58:39 2013 +0100
@@ -76,18 +76,18 @@
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -107,6 +107,7 @@
import jdk.nashorn.internal.parser.Lexer.RegexToken;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -156,12 +157,20 @@
/** How many regexp fields have been emitted */
private int regexFieldCount;
+ /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling
+ * a just-defined anonymous function expression. */
+ private boolean functionNodeIsCallee;
+
/** Map of shared scope call sites */
private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>();
+ private final LexicalContext lexicalContext = new LexicalContext();
+
/** When should we stop caching regexp expressions in fields to limit bytecode size? */
private static final int MAX_REGEX_FIELDS = 2 * 1024;
+ private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug");
+
/**
* Constructor.
*
@@ -210,7 +219,7 @@
final int flags = CALLSITE_SCOPE | getCallSiteFlags();
method.loadScope();
- if (symbol.isFastScope(getCurrentFunctionNode())) {
+ if (isFastScope(symbol)) {
// Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope.
if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) {
return loadSharedScopeVar(identNode.getType(), symbol, flags);
@@ -221,8 +230,28 @@
}
}
+ /**
+ * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
+ *
+ * @param function function to check for fast scope
+ * @return true if fast scope
+ */
+ private boolean isFastScope(final Symbol symbol) {
+ if (!symbol.isScope() || !symbol.getBlock().needsScope()) {
+ return false;
+ }
+ // Allow fast scope access if no function contains with or eval
+ for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) {
+ final FunctionNode func = it.next();
+ if (func.hasWith() || func.hasEval()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) {
- method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
+ method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1);
final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE);
scopeCall.generateInvoke(method);
return method;
@@ -240,30 +269,18 @@
return method;
}
- private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) {
- if (currentBlock == symbol.getBlock()) {
- return 0;
- }
-
- final int delta = currentBlock.needsScope() ? 1 : 0;
- final Block parentBlock = currentBlock.getParent();
-
- if (parentBlock != null) {
- final int result = getScopeProtoDepth(parentBlock, symbol);
- if (result != -1) {
- return delta + result;
+ private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) {
+ int depth = 0;
+ final Block definingBlock = symbol.getBlock();
+ for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) {
+ final Block currentBlock = blocks.next();
+ if (currentBlock == definingBlock) {
+ return depth;
+ }
+ if (currentBlock.needsScope()) {
+ ++depth;
}
}
-
- if (currentBlock instanceof FunctionNode) {
- for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) {
- final int result = getScopeProtoDepth(lookupBlock, symbol);
- if (result != -1) {
- return delta + result;
- }
- }
- }
-
return -1;
}
@@ -313,13 +330,13 @@
node.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
loadIdent(identNode);
return null;
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
if (!baseAlreadyOnStack) {
load(accessNode.getBase()).convert(Type.OBJECT);
}
@@ -329,7 +346,7 @@
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
if (!baseAlreadyOnStack) {
load(indexNode.getBase()).convert(Type.OBJECT);
load(indexNode.getIndex());
@@ -339,6 +356,14 @@
}
@Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ // function nodes will always leave a constructed function object on stack, no need to load the symbol
+ // separately as in enterDefault()
+ functionNode.accept(codegen);
+ return null;
+ }
+
+ @Override
public Node enterDefault(final Node otherNode) {
otherNode.accept(codegen); // generate code for whatever we are looking at.
method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there)
@@ -350,7 +375,7 @@
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
if (accessNode.testResolved()) {
return null;
}
@@ -422,10 +447,11 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (block.testResolved()) {
return null;
}
+ lexicalContext.push(block);
method.label(block.getEntryLabel());
initLocals(block);
@@ -434,14 +460,14 @@
}
@Override
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
method.label(block.getBreakLabel());
symbolInfo(block);
if (block.needsScope()) {
popBlockScope(block);
}
-
+ lexicalContext.pop(block);
return block;
}
@@ -467,7 +493,7 @@
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
if (breakNode.testResolved()) {
return null;
}
@@ -515,14 +541,13 @@
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
if (callNode.testResolved()) {
return null;
}
final List<Node> args = callNode.getArgs();
final Node function = callNode.getFunction();
- final FunctionNode currentFunction = getCurrentFunctionNode();
final Block currentBlock = getCurrentBlock();
function.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@@ -531,7 +556,7 @@
final Symbol symbol = identNode.getSymbol();
int scopeCallFlags = flags;
method.loadScope();
- if (symbol.isFastScope(currentFunction)) {
+ if (isFastScope(symbol)) {
method.load(getScopeProtoDepth(currentBlock, symbol));
scopeCallFlags |= CALLSITE_FAST_SCOPE;
} else {
@@ -593,7 +618,7 @@
}
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
if (symbol.isScope()) {
@@ -606,7 +631,7 @@
if (callNode.isEval()) {
evalCall(node, flags);
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
- || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
+ || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
|| callNode.inWithBlock()) {
scopeCall(node, flags);
} else {
@@ -621,7 +646,7 @@
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
load(node.getBase());
method.convert(Type.OBJECT);
method.dup();
@@ -634,8 +659,7 @@
}
@Override
- public Node enter(final ReferenceNode node) {
- final FunctionNode callee = node.getReference();
+ public Node enterFunctionNode(final FunctionNode callee) {
final boolean isVarArg = callee.isVarArg();
final int argCount = isVarArg ? -1 : callee.getParameters().size();
@@ -653,12 +677,13 @@
loadArgs(args, signature, isVarArg, argCount);
method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature);
assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType();
-
+ functionNodeIsCallee = true;
+ callee.accept(CodeGenerator.this);
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
load(node.getBase());
method.convert(Type.OBJECT);
method.dup();
@@ -694,7 +719,7 @@
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
if (continueNode.testResolved()) {
return null;
}
@@ -709,17 +734,17 @@
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return null;
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
if (executeNode.testResolved()) {
return null;
}
@@ -731,7 +756,7 @@
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
if (forNode.testResolved()) {
return null;
}
@@ -813,7 +838,7 @@
* @param block block with local vars.
*/
private void initLocals(final Block block) {
- final FunctionNode function = block.getFunction();
+ final FunctionNode function = lexicalContext.getFunction(block);
final boolean isFunctionNode = block == function;
/*
@@ -915,7 +940,7 @@
foc.makeObject(method);
// runScript(): merge scope into global
- if (isFunctionNode && function.isScript()) {
+ if (isFunctionNode && function.isProgram()) {
method.invoke(ScriptRuntime.MERGE_SCOPE);
}
@@ -958,19 +983,29 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
- if (functionNode.isLazy()) {
- return null;
- }
+ public Node enterFunctionNode(final FunctionNode functionNode) {
+ final boolean isCallee = functionNodeIsCallee;
+ functionNodeIsCallee = false;
if (functionNode.testResolved()) {
return null;
}
+ if(!(isCallee || functionNode == compiler.getFunctionNode())) {
+ newFunctionObject(functionNode);
+ }
+
+ if (functionNode.isLazy()) {
+ return null;
+ }
+
+ LOG.info("=== BEGIN " + functionNode.getName());
+ lexicalContext.push(functionNode);
+
setCurrentCompileUnit(functionNode.getCompileUnit());
assert getCurrentCompileUnit() != null;
- method = getCurrentCompileUnit().getClassEmitter().method(functionNode);
+ setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode));
functionNode.setMethodEmitter(method);
// Mark end for variable tables.
method.begin();
@@ -983,7 +1018,7 @@
}
@Override
- public Node leave(final FunctionNode functionNode) {
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
// Mark end for variable tables.
method.label(functionNode.getBreakLabel());
@@ -1001,16 +1036,18 @@
throw e;
}
+ lexicalContext.pop(functionNode);
+ LOG.info("=== END " + functionNode.getName());
return functionNode;
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
return null;
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
if (ifNode.testResolved()) {
return null;
}
@@ -1049,7 +1086,7 @@
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
if (indexNode.testResolved()) {
return null;
}
@@ -1060,7 +1097,7 @@
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (lineNumberNode.testResolved()) {
return null;
}
@@ -1068,7 +1105,6 @@
final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")");
method.label(label);
method.lineNumber(lineNumberNode.getLineNumber(), label);
-
return null;
}
@@ -1106,7 +1142,7 @@
final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag());
final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type);
- method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature);
+ setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature));
method.setFunctionNode(getCurrentFunctionNode());
method.begin();
@@ -1212,7 +1248,7 @@
method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class));
classEmitter.needGetConstantMethod(cls);
} else {
- method.loadConstants(unitClassName).load(index).arrayload();
+ method.loadConstants().load(index).arrayload();
if (cls != Object.class) {
method.checkcast(cls);
}
@@ -1292,14 +1328,14 @@
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
assert literalNode.getSymbol() != null : literalNode + " has no symbol";
load(literalNode).store(literalNode.getSymbol());
return null;
}
@Override
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
if (objectNode.testResolved()) {
return null;
}
@@ -1372,10 +1408,10 @@
}
for (final Node element : elements) {
- final PropertyNode propertyNode = (PropertyNode)element;
- final Object key = propertyNode.getKey();
- final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter();
- final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter();
+ final PropertyNode propertyNode = (PropertyNode)element;
+ final Object key = propertyNode.getKey();
+ final FunctionNode getter = (FunctionNode)propertyNode.getGetter();
+ final FunctionNode setter = (FunctionNode)propertyNode.getSetter();
if (getter == null && setter == null) {
continue;
@@ -1404,18 +1440,7 @@
}
@Override
- public Node enter(final ReferenceNode referenceNode) {
- if (referenceNode.testResolved()) {
- return null;
- }
-
- newFunctionObject(referenceNode.getReference());
-
- return null;
- }
-
- @Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
if (returnNode.testResolved()) {
return null;
}
@@ -1556,7 +1581,7 @@
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
if (runtimeNode.testResolved()) {
return null;
}
@@ -1637,7 +1662,7 @@
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
if (splitNode.testResolved()) {
return null;
}
@@ -1706,7 +1731,7 @@
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
try {
// Wrap up this method.
method.loadResult();
@@ -1763,7 +1788,7 @@
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
if (switchNode.testResolved()) {
return null;
}
@@ -1895,7 +1920,7 @@
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
if (throwNode.testResolved()) {
return null;
}
@@ -1922,7 +1947,7 @@
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
if (tryNode.testResolved()) {
return null;
}
@@ -1955,7 +1980,7 @@
setCurrentBlock(catchBlock);
try {
- enter(catchBlock);
+ enterBlock(catchBlock);
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
final IdentNode exception = catchNode.getException();
@@ -1966,6 +1991,7 @@
// Generate catch body (inlined finally) and rethrow exception
catchBody.accept(this);
method.load(symbol).athrow();
+ lexicalContext.pop(catchBlock);
continue;
}
@@ -2012,7 +2038,7 @@
}
}
- leave(catchBlock);
+ leaveBlock(catchBlock);
} finally {
setCurrentBlock(saveBlock);
}
@@ -2027,7 +2053,7 @@
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
final Node init = varNode.getInit();
if (varNode.testResolved() || init == null) {
@@ -2049,7 +2075,7 @@
int flags = CALLSITE_SCOPE | getCallSiteFlags();
final IdentNode identNode = varNode.getName();
final Type type = identNode.getType();
- if (varSymbol.isFastScope(getCurrentFunctionNode())) {
+ if (isFastScope(varSymbol)) {
storeFastScopeVar(type, varSymbol, flags);
} else {
method.dynamicSet(type, identNode.getName(), flags);
@@ -2065,7 +2091,7 @@
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
if (whileNode.testResolved()) {
return null;
}
@@ -2098,7 +2124,7 @@
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
if (withNode.testResolved()) {
return null;
}
@@ -2864,7 +2890,7 @@
* Ternary visits.
*/
@Override
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
if (ternaryNode.testResolved()) {
return null;
}
@@ -3060,7 +3086,7 @@
target.accept(new NodeVisitor(getCurrentCompileUnit(), method) {
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
if (targetSymbol.isScope()) {
method.load(scopeSymbol);
depth++;
@@ -3083,13 +3109,13 @@
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
enterBaseNode();
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
enterBaseNode();
final Node index = node.getIndex();
@@ -3155,8 +3181,6 @@
}
private void epilogue() {
- final FunctionNode currentFunction = getCurrentFunctionNode();
-
/**
* Take the original target args from the stack and use them
* together with the value to be stored to emit the store code
@@ -3174,7 +3198,7 @@
}
@Override
- public Node enter(final UnaryNode node) {
+ public Node enterUnaryNode(final UnaryNode node) {
if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) {
method.convert(node.rhs().getType());
}
@@ -3182,11 +3206,11 @@
}
@Override
- public Node enter(final IdentNode node) {
+ public Node enterIdentNode(final IdentNode node) {
final Symbol symbol = node.getSymbol();
assert symbol != null;
if (symbol.isScope()) {
- if (symbol.isFastScope(currentFunction)) {
+ if (isFastScope(symbol)) {
storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags());
} else {
method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags());
@@ -3199,13 +3223,13 @@
}
@Override
- public Node enter(final AccessNode node) {
+ public Node enterAccessNode(final AccessNode node) {
method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags());
return null;
}
@Override
- public Node enter(final IndexNode node) {
+ public Node enterIndexNode(final IndexNode node) {
method.dynamicSetIndex(getCallSiteFlags());
return null;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationPhase.java Sat Mar 23 00:58:39 2013 +0100
@@ -14,16 +14,16 @@
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
-
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.ir.debug.ASTWriter;
import jdk.nashorn.internal.ir.debug.PrintVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.ECMAErrors;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.Timing;
@@ -65,17 +65,17 @@
outermostFunctionNode.accept(new NodeVisitor() {
// self references are done with invokestatic and thus cannot have trampolines - never lazy
@Override
- public Node enter(final CallNode node) {
+ public Node enterCallNode(final CallNode node) {
final Node callee = node.getFunction();
- if (callee instanceof ReferenceNode) {
- neverLazy.add(((ReferenceNode)callee).getReference());
+ if (callee instanceof FunctionNode) {
+ neverLazy.add(((FunctionNode)callee));
return null;
}
return node;
}
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
if (node == outermostFunctionNode) {
return node;
}
@@ -94,15 +94,24 @@
lazy.remove(node);
}
- for (final FunctionNode node : lazy) {
- Compiler.LOG.fine("Marking " + node.getName() + " as lazy");
- node.setIsLazy(true);
- final FunctionNode parent = node.findParentFunction();
- if (parent != null) {
- Compiler.LOG.fine("Marking " + parent.getName() + " as having lazy children - it needs scope for all variables");
- parent.setHasLazyChildren();
+ outermostFunctionNode.accept(new NodeOperatorVisitor() {
+ private final LexicalContext lexicalContext = new LexicalContext();
+ @Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ lexicalContext.push(functionNode);
+ if(lazy.contains(functionNode)) {
+ Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy");
+ functionNode.setIsLazy(true);
+ lexicalContext.getParentFunction(functionNode).setHasLazyChildren();
+ }
+ return functionNode;
}
- }
+ @Override
+ public Node leaveFunctionNode(FunctionNode functionNode) {
+ lexicalContext.pop(functionNode);
+ return functionNode;
+ }
+ });
}
@Override
@@ -241,6 +250,16 @@
final CodeGenerator codegen = new CodeGenerator(compiler);
fn.accept(codegen);
codegen.generateScopeCalls();
+ fn.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode functionNode) {
+ if(functionNode.isLazy()) {
+ functionNode.resetResolved();
+ return null;
+ }
+ return fn;
+ }
+ });
} catch (final VerifyError e) {
if (env._verify_code || env._print_code) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Sat Mar 23 00:58:39 2013 +0100
@@ -46,7 +46,6 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Level;
-
import jdk.internal.dynalink.support.NameCodec;
import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
import jdk.nashorn.internal.codegen.types.Type;
@@ -383,7 +382,7 @@
functionNode.accept(new NodeVisitor() {
@Override
- public Node enter(final FunctionNode node) {
+ public Node enterFunctionNode(final FunctionNode node) {
if (node.isLazy()) {
return null;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Sat Mar 23 00:58:39 2013 +0100
@@ -34,20 +34,20 @@
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CallNode.EvalArgs;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.DoWhileNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.RuntimeNode.Request;
@@ -85,11 +85,13 @@
private static final DebugLogger LOG = new DebugLogger("finalize");
+ private final LexicalContext lexicalContext = new LexicalContext();
+
FinalizeTypes() {
}
@Override
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
final EvalArgs evalArgs = callNode.getEvalArgs();
if (evalArgs != null) {
evalArgs.setCode(evalArgs.getCode().accept(this));
@@ -97,15 +99,14 @@
// AccessSpecializer - call return type may change the access for this location
final Node function = callNode.getFunction();
- if (function instanceof ReferenceNode) {
- setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType());
+ if (function instanceof FunctionNode) {
+ return setTypeOverride(callNode, ((FunctionNode)function).getReturnType());
}
return callNode;
}
private Node leaveUnary(final UnaryNode unaryNode) {
- unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
- return unaryNode;
+ return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType()));
}
@Override
@@ -126,8 +127,7 @@
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
- specialize(unaryNode);
- return unaryNode;
+ return specialize(unaryNode).node;
}
@Override
@@ -159,9 +159,7 @@
}
}
- binaryNode.setLHS(convert(lhs, type));
- binaryNode.setRHS(convert(rhs, type));
- return binaryNode;
+ return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type));
}
@Override
@@ -171,12 +169,13 @@
@Override
public Node leaveASSIGN(final BinaryNode binaryNode) {
- Type destType = specialize(binaryNode);
+ final SpecializedNode specialized = specialize(binaryNode);
+ final BinaryNode specBinaryNode = (BinaryNode)specialized.node;
+ Type destType = specialized.type;
if (destType == null) {
- destType = binaryNode.getType();
+ destType = specBinaryNode.getType();
}
- binaryNode.setRHS(convert(binaryNode.rhs(), destType));
- return binaryNode;
+ return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType));
}
@Override
@@ -255,21 +254,21 @@
@Override
public Node leaveCOMMALEFT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- binaryNode.setRHS(discard(binaryNode.rhs()));
+ final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs()));
// AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(binaryNode, binaryNode.lhs().getType());
- return binaryNode;
+ propagateType(newBinaryNode, newBinaryNode.lhs().getType());
+ return newBinaryNode;
}
@Override
public Node leaveCOMMARIGHT(final BinaryNode binaryNode) {
assert binaryNode.getSymbol() != null;
- binaryNode.setLHS(discard(binaryNode.lhs()));
+ final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs()));
// AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed
// in that case, update the node type as well
- propagateType(binaryNode, binaryNode.rhs().getType());
- return binaryNode;
+ propagateType(newBinaryNode, newBinaryNode.rhs().getType());
+ return newBinaryNode;
}
@Override
@@ -355,13 +354,20 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
+ lexicalContext.push(block);
updateSymbols(block);
return block;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveBlock(Block block) {
+ lexicalContext.pop(block);
+ return super.leaveBlock(block);
+ }
+
+ @Override
+ public Node leaveCatchNode(final CatchNode catchNode) {
final Node exceptionCondition = catchNode.getExceptionCondition();
if (exceptionCondition != null) {
catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN));
@@ -370,23 +376,23 @@
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
- return leave((WhileNode)doWhileNode);
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
+ return leaveWhileNode(doWhileNode);
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
executeNode.setExpression(discard(executeNode.getExpression()));
return executeNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
final Node init = forNode.getInit();
final Node test = forNode.getTest();
final Node modify = forNode.getModify();
@@ -414,11 +420,12 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return null;
}
+ lexicalContext.push(functionNode);
// If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do
// this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the
// need for the callee.
@@ -439,14 +446,20 @@
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveFunctionNode(FunctionNode functionNode) {
+ lexicalContext.pop(functionNode);
+ return super.leaveFunctionNode(functionNode);
+ }
+
+ @Override
+ public Node leaveIfNode(final IfNode ifNode) {
ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN));
return ifNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
if (literalNode instanceof ArrayLiteralNode) {
final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode;
final Node[] array = arrayLiteralNode.getValue();
@@ -464,7 +477,7 @@
}
@Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
final Node expr = returnNode.getExpression();
if (expr != null) {
returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType()));
@@ -473,7 +486,7 @@
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
final List<Node> args = runtimeNode.getArgs();
for (final Node arg : args) {
assert !arg.getType().isUnknown();
@@ -482,7 +495,7 @@
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
final Node expression = switchNode.getExpression();
final List<CaseNode> cases = switchNode.getCases();
final boolean allInteger = switchNode.getTag().getSymbolType().isInteger();
@@ -501,33 +514,34 @@
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
- ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
- return ternaryNode;
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
+ return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN));
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT));
return throwNode;
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
final Node rhs = varNode.getInit();
if (rhs != null) {
- Type destType = specialize(varNode);
+ final SpecializedNode specialized = specialize(varNode);
+ final VarNode specVarNode = (VarNode)specialized.node;
+ Type destType = specialized.type;
if (destType == null) {
- destType = varNode.getType();
+ destType = specVarNode.getType();
}
- assert varNode.hasType() : varNode + " doesn't have a type";
- varNode.setInit(convert(rhs, destType));
+ assert specVarNode.hasType() : specVarNode + " doesn't have a type";
+ return specVarNode.setInit(convert(rhs, destType));
}
return varNode;
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
if (test != null) {
whileNode.setTest(convert(test, Type.BOOLEAN));
@@ -536,7 +550,7 @@
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT));
return withNode;
}
@@ -555,14 +569,14 @@
* that scope and slot information is correct for every symbol
* @param block block for which to to finalize type info.
*/
- private static void updateSymbols(final Block block) {
+ private void updateSymbols(final Block block) {
if (!block.needsScope()) {
return; // nothing to do
}
- assert !(block instanceof FunctionNode) || block.getFunction() == block;
+ final FunctionNode functionNode = lexicalContext.getFunction(block);
+ assert !(block instanceof FunctionNode) || functionNode == block;
- final FunctionNode functionNode = block.getFunction();
final List<Symbol> symbols = block.getFrame().getSymbols();
final boolean allVarsInScope = functionNode.allVarsInScope();
final boolean isVarArg = functionNode.isVarArg();
@@ -631,10 +645,7 @@
break;
}
- binaryNode.setLHS(convert(lhs, widest));
- binaryNode.setRHS(convert(rhs, widest));
-
- return binaryNode;
+ return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest));
}
/**
@@ -656,9 +667,7 @@
}
private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) {
- binaryNode.setLHS(convert(binaryNode.lhs(), lhsType));
- binaryNode.setRHS(convert(binaryNode.rhs(), rhsType));
- return binaryNode;
+ return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType));
}
/**
@@ -679,7 +688,7 @@
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
if (!exclude.contains(identNode)) {
setCanBePrimitive(identNode.getSymbol());
}
@@ -687,26 +696,36 @@
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
setCanBePrimitive(accessNode.getProperty().getSymbol());
return null;
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine
return indexNode;
}
});
}
- private static Type specialize(final Assignment<?> assignment) {
+ private static class SpecializedNode {
+ final Node node;
+ final Type type;
+
+ SpecializedNode(Node node, Type type) {
+ this.node = node;
+ this.type = type;
+ }
+ }
+
+ private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) {
final Node node = ((Node)assignment);
- final Node lhs = assignment.getAssignmentDest();
+ final T lhs = assignment.getAssignmentDest();
final Node rhs = assignment.getAssignmentSource();
if (!canHaveCallSiteType(lhs)) {
- return null;
+ return new SpecializedNode(node, null);
}
final Type to;
@@ -718,13 +737,13 @@
if (!isSupportedCallSiteType(to)) {
//meaningless to specialize to boolean or object
- return null;
+ return new SpecializedNode(node, null);
}
- setTypeOverride(lhs, to);
- propagateType(node, to);
+ final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to));
+ propagateType(newNode, to);
- return to;
+ return new SpecializedNode(newNode, to);
}
@@ -736,7 +755,7 @@
* @return true if node can have a callsite type
*/
private static boolean canHaveCallSiteType(final Node node) {
- return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType();
+ return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType();
}
/**
@@ -762,7 +781,8 @@
* @param node node for which to change type
* @param to new type
*/
- private static void setTypeOverride(final Node node, final Type to) {
+ @SuppressWarnings("unchecked")
+ private static <T extends Node> T setTypeOverride(final T node, final Type to) {
final Type from = node.getType();
if (!node.getType().equals(to)) {
LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to);
@@ -771,7 +791,7 @@
}
}
LOG.info("Type override for lhs in '" + node + "' => " + to);
- ((TypeOverride)node).setType(to);
+ return ((TypeOverride<T>)node).setType(to);
}
/**
@@ -816,8 +836,8 @@
}
} else {
if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) {
- setTypeOverride(node, to);
- return resultNode;
+ assert node instanceof TypeOverride;
+ return setTypeOverride(node, to);
}
resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node);
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FoldConstants.java Sat Mar 23 00:58:39 2013 +0100
@@ -31,12 +31,12 @@
import jdk.nashorn.internal.ir.EmptyNode;
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.TernaryNode;
import jdk.nashorn.internal.ir.UnaryNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.JSType;
@@ -54,7 +54,7 @@
}
@Override
- public Node leave(final UnaryNode unaryNode) {
+ public Node leaveUnaryNode(final UnaryNode unaryNode) {
final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval();
if (literalNode != null) {
LOG.info("Unary constant folded " + unaryNode + " to " + literalNode);
@@ -64,7 +64,7 @@
}
@Override
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval();
if (literalNode != null) {
LOG.info("Binary constant folded " + binaryNode + " to " + literalNode);
@@ -74,7 +74,7 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return null;
}
@@ -82,13 +82,13 @@
}
@Override
- public Node leave(final FunctionNode functionNode) {
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
functionNode.setState(CompilationState.CONSTANT_FOLDED);
return functionNode;
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
final Node test = ifNode.getTest();
if (test instanceof LiteralNode) {
final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail();
@@ -101,7 +101,7 @@
}
@Override
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
final Node test = ternaryNode.lhs();
if (test instanceof LiteralNode) {
return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
--- a/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/FunctionSignature.java Sat Mar 23 00:58:39 2013 +0100
@@ -155,7 +155,7 @@
true,
functionNode.needsCallee(),
functionNode.getReturnType(),
- (functionNode.isVarArg() && !functionNode.isScript()) ?
+ (functionNode.isVarArg() && !functionNode.isProgram()) ?
null :
functionNode.getParameters());
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Lower.java Sat Mar 23 00:58:39 2013 +0100
@@ -37,8 +37,8 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
+import java.util.Iterator;
import java.util.List;
-import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
@@ -52,11 +52,12 @@
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
-import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LabeledNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
@@ -69,7 +70,6 @@
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Token;
@@ -103,6 +103,8 @@
private List<Node> statements;
+ private LexicalContext lexicalContext = new LexicalContext();
+
/**
* Constructor.
*
@@ -114,14 +116,15 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
final Node savedLastStatement = lastStatement;
final List<Node> savedStatements = statements;
-
+ lexicalContext.push(block);
try {
this.statements = new ArrayList<>();
+ NodeVisitor visitor = this;
for (final Node statement : block.getStatements()) {
- statement.accept(this);
+ statement.accept(visitor);
/*
* This is slightly unsound, for example if we have a loop with
* a guarded statement like if (x) continue in the body and the
@@ -133,7 +136,7 @@
*/
if (lastStatement != null && lastStatement.isTerminal()) {
copyTerminal(block, lastStatement);
- break;
+ visitor = new DeadCodeVarDeclarationVisitor();
}
}
block.setStatements(statements);
@@ -141,18 +144,19 @@
} finally {
this.statements = savedStatements;
this.lastStatement = savedLastStatement;
+ lexicalContext.pop(block);
}
return null;
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
return enterBreakOrContinue(breakNode);
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
final Node function = markerFunction(callNode.getFunction());
callNode.setFunction(function);
checkEval(callNode); //check if this is an eval call and store the information
@@ -160,44 +164,44 @@
}
@Override
- public Node leave(final CaseNode caseNode) {
+ public Node leaveCaseNode(final CaseNode caseNode) {
caseNode.copyTerminalFlags(caseNode.getBody());
return caseNode;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
catchNode.copyTerminalFlags(catchNode.getBody());
addStatement(catchNode);
return catchNode;
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
return enterBreakOrContinue(continueNode);
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
- return enter((WhileNode)doWhileNode);
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
+ return enterWhileNode(doWhileNode);
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
- return leave((WhileNode)doWhileNode);
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
+ return leaveWhileNode(doWhileNode);
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return null;
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
final Node expr = executeNode.getExpression();
- if (getCurrentFunctionNode().isScript()) {
- if (!(expr instanceof Block)) {
+ if (getCurrentFunctionNode().isProgram()) {
+ if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function
if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) {
executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN),
getCurrentFunctionNode().getResultNode(),
@@ -213,13 +217,13 @@
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
nest(forNode);
return forNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
final Node test = forNode.getTest();
final Block body = forNode.getBody();
@@ -247,18 +251,16 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
LOG.info("START FunctionNode: " + functionNode.getName());
if (functionNode.isLazy()) {
LOG.info("LAZY: " + functionNode.getName());
return null;
}
-
+ lexicalContext.push(functionNode);
initFunctionNode(functionNode);
- Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED);
-
nest(functionNode);
/*
@@ -272,60 +274,40 @@
statements = new ArrayList<>();
lastStatement = null;
- // for initial eval result is the last declared function
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final IdentNode ident = nestedFunction.getIdent();
- if (ident != null && nestedFunction.isStatement()) {
- initialEvalResult = new IdentNode(ident);
- }
- }
-
if (functionNode.needsSelfSymbol()) {
//function needs to start with var funcIdent = __callee_;
statements.add(functionNode.getSelfSymbolInit().accept(this));
}
+ NodeVisitor visitor = this;
try {
- // Every nested function needs a definition in the outer function with its name. Add these.
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- final VarNode varNode = nestedFunction.getFunctionVarNode();
- if (varNode != null) {
- final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode();
- if (lineNumberNode != null) {
- lineNumberNode.accept(this);
- }
- varNode.accept(this);
- varNode.setIsFunctionVarNode();
+ //do the statements - this fills the block with code
+ boolean needsInitialEvalResult = functionNode.isProgram();
+ for (final Node statement : functionNode.getStatements()) {
+ // If this function is a program, then insert an assignment to the initial eval result after all
+ // function declarations.
+ if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) {
+ addInitialEvalResult(functionNode);
+ needsInitialEvalResult = false;
}
- }
-
- if (functionNode.isScript()) {
- new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
- }
-
- //do the statements - this fills the block with code
- for (final Node statement : functionNode.getStatements()) {
- statement.accept(this);
+ statement.accept(visitor);
//If there are unused terminated endpoints in the function, we need
// to add a "return undefined" in those places for correct semantics
LOG.info("Checking lastStatement="+lastStatement+" for terminal flags");
if (lastStatement != null && lastStatement.hasTerminalFlags()) {
copyTerminal(functionNode, lastStatement);
- break;
+ assert !needsInitialEvalResult;
+ visitor = new DeadCodeVarDeclarationVisitor();
}
}
-
+ if(needsInitialEvalResult) {
+ addInitialEvalResult(functionNode);
+ }
functionNode.setStatements(statements);
if (!functionNode.isTerminal()) {
guaranteeReturn(functionNode);
}
-
- //lower all nested functions
- for (final FunctionNode nestedFunction : functionNode.getFunctions()) {
- nestedFunction.accept(this);
- }
-
} finally {
statements = savedStatements;
lastStatement = savedLastStatement;
@@ -333,19 +315,67 @@
LOG.info("END FunctionNode: " + functionNode.getName());
unnest(functionNode);
+ lexicalContext.pop(functionNode);
functionNode.setState(CompilationState.LOWERED);
return null;
}
+ /**
+ * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the
+ * var declarations in them still have the effect of declaring a local variable on the function level. Therefore,
+ * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their
+ * initializers are wiped out as those are, in fact, dead code.
+ */
+ private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor {
+ DeadCodeVarDeclarationVisitor() {
+ }
+
+ @Override
+ public Node enterVarNode(VarNode varNode) {
+ // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was
+ // encountered, and all function declarations precede any terminal statements.
+ assert !varNode.isFunctionDeclaration();
+ if(varNode.getInit() == null) {
+ // No initializer, just pass it to Lower.
+ return varNode.accept(Lower.this);
+ }
+ // Wipe out the initializer and then pass it to Lower.
+ return varNode.setInit(null).accept(Lower.this);
+ }
+ }
+
+ private void addInitialEvalResult(final FunctionNode functionNode) {
+ new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(),
+ getInitialEvalResult(functionNode)).accept(this);
+ }
+
+ /**
+ * Result of initial result of evaluating a particular program, which is either the last function it declares, or
+ * undefined if it doesn't declare any functions.
+ * @param program
+ * @return the initial result of evaluating the program
+ */
+ private static Node getInitialEvalResult(final FunctionNode program) {
+ IdentNode lastFnName = null;
+ for (final FunctionNode fn : program.getDeclaredFunctions()) {
+ assert fn.isDeclared();
+ final IdentNode fnName = fn.getIdent();
+ if(fnName != null) {
+ lastFnName = fnName;
+ }
+ }
+ return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED);
+ }
+
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
return nest(ifNode);
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
final Node pass = ifNode.getPass();
final Node fail = ifNode.getFail();
@@ -360,7 +390,7 @@
}
@Override
- public Node enter(LabelNode labelNode) {
+ public Node enterLabelNode(LabelNode labelNode) {
final Block body = labelNode.getBody();
body.accept(this);
copyTerminal(labelNode, body);
@@ -369,13 +399,13 @@
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
addStatement(lineNumberNode, false); // don't put it in lastStatement cache
return null;
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
final TryNode tryNode = returnNode.getTryChain();
final Node expr = returnNode.getExpression();
@@ -413,19 +443,19 @@
}
@Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor
return returnNode;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
nest(switchNode);
return switchNode;
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
unnest(switchNode);
final List<CaseNode> cases = switchNode.getCases();
@@ -446,13 +476,13 @@
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor
return throwNode;
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
final Block finallyBody = tryNode.getFinallyBody();
final long token = tryNode.getToken();
final int finish = tryNode.getFinish();
@@ -538,26 +568,19 @@
// set outer tryNode's body to innerTryNode
final Block outerBody;
- outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode());
+ outerBody = new Block(source, token, finish);
outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode)));
tryNode.setBody(outerBody);
tryNode.setCatchBlocks(null);
-
- // now before we go on, we have to fix the block parents
- // (we repair the block tree after the insertion so that all references are intact)
- innerTryNode.getBody().setParent(tryNode.getBody());
- for (final Block block : innerTryNode.getCatchBlocks()) {
- block.setParent(tryNode.getBody());
- }
}
// create a catch-all that inlines finally and rethrows
- final Block catchBlock = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode());
+ final Block catchBlock = new Block(source, token, finish);
//this catch block should get define symbol
- final Block catchBody = new Block(source, token, finish, catchBlock, getCurrentFunctionNode());
- final Node catchAllFinally = finallyBody.clone();
+ final Block catchBody = new Block(source, token, finish);
+ final Node catchAllFinally = finallyBody.copy();
catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally));
setTerminal(catchBody, true);
@@ -584,7 +607,7 @@
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
final Block finallyBody = tryNode.getFinallyBody();
boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal());
@@ -608,18 +631,18 @@
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
return varNode;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
return nest(whileNode);
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
final Node test = whileNode.getTest();
if (test == null) {
@@ -653,7 +676,7 @@
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
if (withNode.getBody().isTerminal()) {
setTerminal(withNode, true);
}
@@ -682,28 +705,10 @@
*/
private static Node markerFunction(final Node function) {
if (function instanceof IdentNode) {
- return new IdentNode((IdentNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
- } else if (function instanceof AccessNode) {
- return new AccessNode((AccessNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
- } else if (function instanceof IndexNode) {
- return new IndexNode((IndexNode)function) {
- @Override
- public boolean isFunction() {
- return true;
- }
- };
+ return ((IdentNode)function).setIsFunction();
+ } else if (function instanceof BaseNode) {
+ return ((BaseNode)function).setIsFunction();
}
-
return function;
}
@@ -746,7 +751,7 @@
if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) {
final CallNode.EvalArgs evalArgs =
new CallNode.EvalArgs(
- args.get(0).clone().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
+ args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case"
getCurrentFunctionNode().getThisNode(),
evalLocation(callee),
getCurrentFunctionNode().isStrictMode());
@@ -773,13 +778,13 @@
loopBody.accept(new NodeVisitor() {
@Override
- public Node leave(final BreakNode node) {
+ public Node leaveBreakNode(final BreakNode node) {
escapes.add(node);
return node;
}
@Override
- public Node leave(final ContinueNode node) {
+ public Node leaveContinueNode(final ContinueNode node) {
// all inner loops have been popped.
if (nesting.contains(node.getTargetNode())) {
escapes.add(node);
@@ -794,7 +799,7 @@
private void guaranteeReturn(final FunctionNode functionNode) {
Node resultNode;
- if (functionNode.isScript()) {
+ if (functionNode.isProgram()) {
resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr
} else {
if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) {
@@ -859,18 +864,15 @@
* @return true if try block is inside the target, false otherwise.
*/
private boolean isNestedTry(final TryNode tryNode, final Block target) {
- for (Block current = getCurrentBlock(); current != target; current = current.getParent()) {
- if (tryNode.getBody() == current) {
+ for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) {
+ final Block block = blocks.next();
+ if(block == target) {
+ return false;
+ }
+ if(tryNode.isChildBlock(block)) {
return true;
}
-
- for (final Block catchBlock : tryNode.getCatchBlocks()) {
- if (catchBlock == current) {
- return true;
- }
- }
}
-
return false;
}
@@ -899,7 +901,7 @@
continue;
}
- finallyBody = (Block)finallyBody.clone();
+ finallyBody = (Block)finallyBody.copy();
final boolean hasTerminalFlags = finallyBody.hasTerminalFlags();
new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this);
@@ -974,6 +976,3 @@
}
}
-
-
-
--- a/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MethodEmitter.java Sat Mar 23 00:58:39 2013 +0100
@@ -651,11 +651,10 @@
/**
* Load the constants array
- * @param unitClassName name of the compile unit from which to load constants
* @return this method emitter
*/
- MethodEmitter loadConstants(final String unitClassName) {
- getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor());
+ MethodEmitter loadConstants() {
+ getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor());
assert peekType().isArray() : peekType();
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Splitter.java Sat Mar 23 00:58:39 2013 +0100
@@ -41,6 +41,7 @@
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
@@ -49,6 +50,7 @@
import jdk.nashorn.internal.ir.SplitNode;
import jdk.nashorn.internal.ir.SwitchNode;
import jdk.nashorn.internal.ir.WhileNode;
+import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.Source;
@@ -70,6 +72,8 @@
/** Cache for calculated block weights. */
private final Map<Node, Long> weightCache = new HashMap<>();
+ private final LexicalContext lexicalContext = new LexicalContext();
+
/** Weight threshold for when to start a split. */
public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024);
@@ -112,7 +116,7 @@
}
if (weight >= SPLIT_THRESHOLD) {
- weight = splitBlock(functionNode);
+ weight = splitBlock(functionNode, functionNode);
}
if (functionNode.isSplit()) {
@@ -132,9 +136,20 @@
}
// Recursively split nested functions
- for (final FunctionNode function : functionNode.getFunctions()) {
- new Splitter(compiler, function, outermostCompileUnit).split();
- }
+ functionNode.accept(new NodeOperatorVisitor() {
+ @Override
+ public Node enterFunctionNode(FunctionNode function) {
+ if(function == functionNode) {
+ // Don't process outermost function (it was already processed) but descend into it to find nested
+ // functions.
+ return function;
+ }
+ // Process a nested function
+ new Splitter(compiler, function, outermostCompileUnit).split();
+ // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions.
+ return null;
+ }
+ });
functionNode.setState(CompilationState.SPLIT);
}
@@ -155,7 +170,7 @@
*
* @return new weight for the resulting block.
*/
- private long splitBlock(final Block block) {
+ private long splitBlock(final Block block, final FunctionNode function) {
functionNode.setIsSplit();
final List<Node> splits = new ArrayList<>();
@@ -167,7 +182,7 @@
if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) {
if (!statements.isEmpty()) {
- splits.add(createBlockSplitNode(block, statements, statementsWeight));
+ splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
statements = new ArrayList<>();
statementsWeight = 0;
}
@@ -183,7 +198,7 @@
}
if (!statements.isEmpty()) {
- splits.add(createBlockSplitNode(block, statements, statementsWeight));
+ splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
}
block.setStatements(splits);
@@ -199,13 +214,13 @@
*
* @return New split node.
*/
- private SplitNode createBlockSplitNode(final Block parent, final List<Node> statements, final long weight) {
+ private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) {
final Source source = parent.getSource();
final long token = parent.getToken();
final int finish = parent.getFinish();
- final String name = parent.getFunction().uniqueName(SPLIT_PREFIX.tag());
+ final String name = function.uniqueName(SPLIT_PREFIX.tag());
- final Block newBlock = new Block(source, token, finish, parent, functionNode);
+ final Block newBlock = new Block(source, token, finish);
newBlock.setFrame(new Frame(parent.getFrame()));
newBlock.setStatements(statements);
@@ -217,15 +232,17 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (block.isCatchBlock()) {
return null;
}
+ lexicalContext.push(block);
final long weight = WeighNodes.weigh(block, weightCache);
if (weight < SPLIT_THRESHOLD) {
weightCache.put(block, weight);
+ lexicalContext.pop(block);
return null;
}
@@ -233,23 +250,24 @@
}
@Override
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
assert !block.isCatchBlock();
// Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have
// been split already, so weigh again before splitting.
long weight = WeighNodes.weigh(block, weightCache);
if (weight >= SPLIT_THRESHOLD) {
- weight = splitBlock(block);
+ weight = splitBlock(block, lexicalContext.getFunction(block));
}
weightCache.put(block, weight);
+ lexicalContext.pop(block);
return block;
}
@SuppressWarnings("rawtypes")
@Override
- public Node leave(final LiteralNode literal) {
+ public Node leaveLiteralNode(final LiteralNode literal) {
long weight = WeighNodes.weigh(literal);
if (weight < SPLIT_THRESHOLD) {
@@ -294,17 +312,12 @@
}
@Override
- public Node enter(final FunctionNode node) {
- if (node.isLazy()) {
- return null;
+ public Node enterFunctionNode(final FunctionNode node) {
+ if(node == functionNode && !node.isLazy()) {
+ lexicalContext.push(node);
+ node.visitStatements(this);
+ lexicalContext.pop(node);
}
-
- final List<Node> statements = node.getStatements();
-
- for (final Node statement : statements) {
- statement.accept(this);
- }
-
return null;
}
@@ -321,38 +334,38 @@
}
@Override
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
registerJumpTarget(labelNode.getBreakNode());
registerJumpTarget(labelNode.getContinueNode());
return labelNode;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
registerJumpTarget(whileNode);
return whileNode;
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
registerJumpTarget(doWhileNode);
return doWhileNode;
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
registerJumpTarget(forNode);
return forNode;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
registerJumpTarget(switchNode);
return switchNode;
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
for (final SplitNode split : splitStack) {
split.setHasReturn(true);
}
@@ -360,25 +373,25 @@
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel());
return continueNode;
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel());
return breakNode;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
splitStack.addFirst(splitNode);
return splitNode;
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
assert splitNode == splitStack.peekFirst();
splitStack.removeFirst();
return splitNode;
--- a/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/codegen/WeighNodes.java Sat Mar 23 00:58:39 2013 +0100
@@ -47,7 +47,6 @@
import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -80,7 +79,7 @@
private static final long LITERAL_WEIGHT = 10;
private static final long LOOP_WEIGHT = 4;
private static final long NEW_WEIGHT = 6;
- private static final long REFERENCE_WEIGHT = 20;
+ private static final long FUNC_EXPR_WEIGHT = 20;
private static final long RETURN_WEIGHT = 2;
private static final long SPLIT_WEIGHT = 40;
private static final long SWITCH_WEIGHT = 8;
@@ -94,36 +93,37 @@
/** Optional cache for weight of block nodes. */
private final Map<Node, Long> weightCache;
- /*
+ private final FunctionNode topFunction;
+
+ /**
* Constructor
*
* @param weightCache cache of already calculated block weights
*/
- private WeighNodes(final Map<Node, Long> weightCache) {
+ private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) {
super(null, null);
+ this.topFunction = topFunction;
this.weightCache = weightCache;
}
static long weigh(final Node node) {
- final WeighNodes weighNodes = new WeighNodes(null);
- node.accept(weighNodes);
- return weighNodes.weight;
+ return weigh(node, null);
}
static long weigh(final Node node, final Map<Node, Long> weightCache) {
- final WeighNodes weighNodes = new WeighNodes(weightCache);
+ final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache);
node.accept(weighNodes);
return weighNodes.weight;
}
@Override
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
weight += ACCESS_WEIGHT;
return accessNode;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
if (weightCache != null && weightCache.containsKey(block)) {
weight += weightCache.get(block);
return null;
@@ -133,78 +133,79 @@
}
@Override
- public Node leave(final BreakNode breakNode) {
+ public Node leaveBreakNode(final BreakNode breakNode) {
weight += BREAK_WEIGHT;
return breakNode;
}
@Override
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
weight += CALL_WEIGHT;
return callNode;
}
@Override
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
weight += CATCH_WEIGHT;
return catchNode;
}
@Override
- public Node leave(final ContinueNode continueNode) {
+ public Node leaveContinueNode(final ContinueNode continueNode) {
weight += CONTINUE_WEIGHT;
return continueNode;
}
@Override
- public Node leave(final DoWhileNode doWhileNode) {
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
weight += LOOP_WEIGHT;
return doWhileNode;
}
@Override
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
return executeNode;
}
@Override
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
weight += LOOP_WEIGHT;
return forNode;
}
@Override
- public Node enter(final FunctionNode functionNode) {
- final List<Node> statements = functionNode.getStatements();
-
- for (final Node statement : statements) {
- statement.accept(this);
+ public Node enterFunctionNode(final FunctionNode functionNode) {
+ if(functionNode == topFunction) {
+ // the function being weighted; descend into its statements
+ functionNode.visitStatements(this);
+ } else {
+ // just a reference to inner function from outer function
+ weight += FUNC_EXPR_WEIGHT;
}
-
return null;
}
@Override
- public Node leave(final IdentNode identNode) {
+ public Node leaveIdentNode(final IdentNode identNode) {
weight += ACCESS_WEIGHT + identNode.getName().length() * 2;
return identNode;
}
@Override
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
weight += IF_WEIGHT;
return ifNode;
}
@Override
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
weight += ACCESS_WEIGHT;
return indexNode;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
weight += LITERAL_WEIGHT;
if (literalNode instanceof ArrayLiteralNode) {
@@ -230,67 +231,61 @@
}
@Override
- public Node leave(final PropertyNode propertyNode) {
+ public Node leavePropertyNode(final PropertyNode propertyNode) {
weight += LITERAL_WEIGHT;
return propertyNode;
}
@Override
- public Node leave(final ReferenceNode referenceNode) {
- weight += REFERENCE_WEIGHT;
- return referenceNode;
- }
-
- @Override
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
weight += RETURN_WEIGHT;
return returnNode;
}
@Override
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
weight += CALL_WEIGHT;
return runtimeNode;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
weight += SPLIT_WEIGHT;
return null;
}
@Override
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
weight += SWITCH_WEIGHT;
return switchNode;
}
@Override
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
weight += THROW_WEIGHT;
return throwNode;
}
@Override
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
weight += THROW_WEIGHT;
return tryNode;
}
@Override
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
weight += VAR_WEIGHT;
return varNode;
}
@Override
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
weight += LOOP_WEIGHT;
return whileNode;
}
@Override
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
weight += WITH_WEIGHT;
return withNode;
}
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -36,7 +36,7 @@
* IR representation of a property access (period operator.)
*
*/
-public class AccessNode extends BaseNode implements TypeOverride {
+public class AccessNode extends BaseNode implements TypeOverride<AccessNode> {
/** Property ident. */
private IdentNode property;
@@ -56,9 +56,7 @@
super(source, token, finish, base);
this.start = base.getStart();
- this.property = property;
-
- this.property.setIsPropertyName();
+ this.property = property.setIsPropertyName();
}
/**
@@ -106,10 +104,10 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterAccessNode(this) != null) {
base = base.accept(visitor);
property = (IdentNode)property.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveAccessNode(this);
}
return this;
@@ -150,13 +148,14 @@
}
@Override
- public void setType(final Type type) {
+ public AccessNode setType(final Type type) {
if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
- property.setType(type);
+ property = property.setType(type);
getSymbol().setTypeOverride(type); //always a temp so this is fine.
hasCallSiteType = true;
+ return this;
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/ir/Assignment.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/Assignment.java Sat Mar 23 00:58:39 2013 +0100
@@ -46,4 +46,11 @@
* @return get the assignment source node
*/
public Node getAssignmentSource();
+
+ /**
+ * Set assignment destination node.
+ * @param n the assignment destination node.
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public Node setAssignmentDest(D n);
}
--- a/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/BaseNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -38,6 +38,8 @@
/** Base Node. */
protected Node base;
+ private boolean function;
+
/**
* Constructor
*
@@ -96,6 +98,15 @@
@Override
public boolean isFunction() {
- return false;
+ return function;
+ }
+
+ /**
+ * Mark this node as being the callee operand of a {@link CallNode}.
+ * @return a base node identical to this one in all aspects except with its function flag set.
+ */
+ public BaseNode setIsFunction() {
+ function = true;
+ return this;
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -35,7 +35,7 @@
*/
public class BinaryNode extends UnaryNode {
/** Left hand side argument. */
- protected Node lhs;
+ private Node lhs;
/**
* Constructor
@@ -140,6 +140,11 @@
}
@Override
+ public Node setAssignmentDest(Node n) {
+ return setLHS(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return rhs();
}
@@ -163,10 +168,9 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- lhs = lhs.accept(visitor);
- rhs = rhs.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterBinaryNode(this) != null) {
+ // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers
+ return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor)));
}
return this;
@@ -229,8 +233,12 @@
/**
* Set the left hand side expression for this node
* @param lhs new left hand side expression
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setLHS(final Node lhs) {
- this.lhs = lhs;
+ public BinaryNode setLHS(final Node lhs) {
+ if(this.lhs == lhs) return this;
+ final BinaryNode n = (BinaryNode)clone();
+ n.lhs = lhs;
+ return n;
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/Block.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/Block.java Sat Mar 23 00:58:39 2013 +0100
@@ -25,14 +25,6 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL;
-import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL;
-import static jdk.nashorn.internal.ir.Symbol.IS_LET;
-import static jdk.nashorn.internal.ir.Symbol.IS_PARAM;
-import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE;
-import static jdk.nashorn.internal.ir.Symbol.IS_VAR;
-import static jdk.nashorn.internal.ir.Symbol.KINDMASK;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -40,9 +32,9 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.ListIterator;
import jdk.nashorn.internal.codegen.Frame;
import jdk.nashorn.internal.codegen.Label;
-import jdk.nashorn.internal.ir.annotations.Reference;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.runtime.Source;
@@ -51,14 +43,6 @@
* basis for script body.
*/
public class Block extends Node {
- /** Parent context */
- @Reference
- private Block parent;
-
- /** Owning function - a FunctionNode has itself as function */
- @Reference
- protected FunctionNode function;
-
/** List of statements */
protected List<Node> statements;
@@ -83,14 +67,10 @@
* @param source source code
* @param token token
* @param finish finish
- * @param parent reference to parent block
- * @param function function node this block is in
*/
- public Block(final Source source, final long token, final int finish, final Block parent, final FunctionNode function) {
+ public Block(final Source source, final long token, final int finish) {
super(source, token, finish);
- this.parent = parent;
- this.function = function;
this.statements = new ArrayList<>();
this.symbols = new HashMap<>();
this.entryLabel = new Label("block_entry");
@@ -106,8 +86,6 @@
protected Block(final Block block, final CopyState cs) {
super(block);
- this.parent = block.parent;
- this.function = block.function;
this.statements = new ArrayList<>();
for (final Node statement : block.getStatements()) {
statements.add(cs.existingOrCopy(statement));
@@ -122,55 +100,7 @@
@Override
protected Node copy(final CopyState cs) {
- return fixBlockChain(new Block(this, cs));
- }
-
- /**
- * Whenever a clone that contains a hierarchy of blocks is created,
- * this function has to be called to ensure that the parents point
- * to the correct parent blocks or two different ASTs would not
- * be completely separated.
- *
- * @return the argument
- */
- static Block fixBlockChain(final Block root) {
- root.accept(new NodeVisitor() {
- private Block parent = root.getParent();
- private final FunctionNode function = root.getFunction();
-
- @Override
- public Node enter(final Block block) {
- assert block.getFunction() == function;
- block.setParent(parent);
- parent = block;
-
- return block;
- }
-
- @Override
- public Node leave(final Block block) {
- parent = block.getParent();
-
- return block;
- }
-
- @Override
- public Node enter(final FunctionNode functionNode) {
- assert functionNode.getFunction() == function;
-
- return enter((Block)functionNode);
- }
-
- @Override
- public Node leave(final FunctionNode functionNode) {
- assert functionNode.getFunction() == function;
-
- return leave((Block)functionNode);
- }
-
- });
-
- return root;
+ return new Block(this, cs);
}
/**
@@ -188,17 +118,12 @@
}
/**
- * Prepend a statement to the statement list
+ * Prepend statements to the statement list
*
- * @param statement Statement node to add
+ * @param prepended statement to add
*/
- public void prependStatement(final Node statement) {
- if (statement != null) {
- final List<Node> newStatements = new ArrayList<>();
- newStatements.add(statement);
- newStatements.addAll(statements);
- setStatements(newStatements);
- }
+ public void prependStatements(final List<Node> prepended) {
+ statements.addAll(0, prepended);
}
/**
@@ -211,39 +136,6 @@
}
/**
- * Add a new function to the function list.
- *
- * @param functionNode Function node to add.
- */
- public void addFunction(final FunctionNode functionNode) {
- assert parent != null : "Parent context missing.";
-
- parent.addFunction(functionNode);
- }
-
- /**
- * Add a list of functions to the function list.
- *
- * @param functionNodes Function nodes to add.
- */
- public void addFunctions(final List<FunctionNode> functionNodes) {
- assert parent != null : "Parent context missing.";
-
- parent.addFunctions(functionNodes);
- }
-
- /**
- * Set the function list to a new one
- *
- * @param functionNodes the nodes to set
- */
- public void setFunctions(final List<FunctionNode> functionNodes) {
- assert parent != null : "Parent context missing.";
-
- parent.setFunctions(functionNodes);
- }
-
- /**
* Assist in IR navigation.
*
* @param visitor IR navigating visitor.
@@ -257,13 +149,9 @@
try {
// Ignore parent to avoid recursion.
- if (visitor.enter(this) != null) {
- for (int i = 0, count = statements.size(); i < count; i++) {
- final Node statement = statements.get(i);
- statements.set(i, statement.accept(visitor));
- }
-
- return visitor.leave(this);
+ if (visitor.enterBlock(this) != null) {
+ visitStatements(visitor);
+ return visitor.leaveBlock(this);
}
} finally {
visitor.setCurrentBlock(saveBlock);
@@ -281,51 +169,13 @@
}
/**
- * Search for symbol.
- *
- * @param name Symbol name.
- *
- * @return Found symbol or null if not found.
+ * Retrieves an existing symbol defined in the current block.
+ * @param name the name of the symbol
+ * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't
+ * define a symbol with this name.
*/
- public Symbol findSymbol(final String name) {
- // Search up block chain to locate symbol.
-
- for (Block block = this; block != null; block = block.getParent()) {
- // Find name.
- final Symbol symbol = block.symbols.get(name);
- // If found then we are good.
- if (symbol != null) {
- return symbol;
- }
- }
- return null;
- }
-
- /**
- * Search for symbol in current function.
- *
- * @param name Symbol name.
- *
- * @return Found symbol or null if not found.
- */
- public Symbol findLocalSymbol(final String name) {
- // Search up block chain to locate symbol.
- for (Block block = this; block != null; block = block.getParent()) {
- // Find name.
- final Symbol symbol = block.symbols.get(name);
- // If found then we are good.
- if (symbol != null) {
- return symbol;
- }
-
- // If searched function then we are done.
- if (block == block.function) {
- break;
- }
- }
-
- // Not found.
- return null;
+ public Symbol getExistingSymbol(final String name) {
+ return symbols.get(name);
}
/**
@@ -338,122 +188,6 @@
return statements.size() == 1 && statements.get(0) instanceof CatchNode;
}
- /**
- * Test to see if a symbol is local to the function.
- *
- * @param symbol Symbol to test.
- * @return True if a local symbol.
- */
- public boolean isLocal(final Symbol symbol) {
- // some temp symbols have no block, so can be assumed local
- final Block block = symbol.getBlock();
- return block == null || block.getFunction() == function;
- }
-
- /**
- * Declare the definition of a new symbol.
- *
- * @param name Name of symbol.
- * @param symbolFlags Symbol flags.
- * @param node Defining Node.
- *
- * @return Symbol for given name or null for redefinition.
- */
- public Symbol defineSymbol(final String name, final int symbolFlags, final Node node) {
- int flags = symbolFlags;
- Symbol symbol = findSymbol(name); // Locate symbol.
-
- if ((flags & KINDMASK) == IS_GLOBAL) {
- flags |= IS_SCOPE;
- }
-
- if (symbol != null) {
- // Symbol was already defined. Check if it needs to be redefined.
- if ((flags & KINDMASK) == IS_PARAM) {
- if (!function.isLocal(symbol)) {
- // Not defined in this function. Create a new definition.
- symbol = null;
- } else if (symbol.isParam()) {
- // Duplicate parameter. Null return will force an error.
- assert false : "duplicate parameter";
- return null;
- }
- } else if ((flags & KINDMASK) == IS_VAR) {
- if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & Symbol.IS_LET) == Symbol.IS_LET) {
- assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == this) : "duplicate let variable in block";
- // Always create a new definition.
- symbol = null;
- } else {
- // Not defined in this function. Create a new definition.
- if (!function.isLocal(symbol) || symbol.less(IS_VAR)) {
- symbol = null;
- }
- }
- }
- }
-
- if (symbol == null) {
- // If not found, then create a new one.
- Block symbolBlock;
-
- // Determine where to create it.
- if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) {
- symbolBlock = this;
- } else {
- symbolBlock = getFunction();
- }
-
- // Create and add to appropriate block.
- symbol = new Symbol(name, flags, node, symbolBlock);
- symbolBlock.putSymbol(name, symbol);
-
- if ((flags & Symbol.KINDMASK) != IS_GLOBAL) {
- symbolBlock.getFrame().addSymbol(symbol);
- symbol.setNeedsSlot(true);
- }
- } else if (symbol.less(flags)) {
- symbol.setFlags(flags);
- }
-
- if (node != null) {
- node.setSymbol(symbol);
- }
-
- return symbol;
- }
-
- /**
- * Declare the use of a symbol.
- *
- * @param name Name of symbol.
- * @param node Using node
- *
- * @return Symbol for given name.
- */
- public Symbol useSymbol(final String name, final Node node) {
- Symbol symbol = findSymbol(name);
-
- if (symbol == null) {
- // If not found, declare as a free var.
- symbol = defineSymbol(name, IS_GLOBAL, node);
- } else {
- node.setSymbol(symbol);
- }
-
- return symbol;
- }
-
- /**
- * Add parent name to the builder.
- *
- * @param sb String bulder.
- */
- public void addParentName(final StringBuilder sb) {
- if (parent != null) {
- parent.addParentName(sb);
- }
- }
-
@Override
public void toString(final StringBuilder sb) {
for (final Node statement : statements) {
@@ -512,16 +246,6 @@
}
/**
- * Get the FunctionNode for this block, i.e. the function it
- * belongs to
- *
- * @return the function node
- */
- public FunctionNode getFunction() {
- return function;
- }
-
- /**
* Reset the frame for this block
*
* @param frame the new frame
@@ -531,24 +255,6 @@
}
/**
- * Get the parent block
- *
- * @return parent block, or null if none exists
- */
- public Block getParent() {
- return parent;
- }
-
- /**
- * Set the parent block
- *
- * @param parent the new parent block
- */
- public void setParent(final Block parent) {
- this.parent = parent;
- }
-
- /**
* Get the list of statements in this block
*
* @return a list of statements
@@ -558,6 +264,15 @@
}
/**
+ * Applies the specified visitor to all statements in the block.
+ * @param visitor the visitor.
+ */
+ public void visitStatements(NodeVisitor visitor) {
+ for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) {
+ stmts.set(stmts.next().accept(visitor));
+ }
+ }
+ /**
* Reset the statement list for this block
*
* @param statements new statement list
@@ -592,4 +307,29 @@
needsScope = true;
}
+ /**
+ * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not
+ * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol
+ * will be marked as one that needs to have its own scope.
+ * @param symbol the symbol being used.
+ * @param ancestors the iterator over block's containing lexical context
+ */
+ public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
+ if(symbol.getBlock() == this) {
+ setNeedsScope();
+ } else {
+ setUsesParentScopeSymbol(symbol, ancestors);
+ }
+ }
+
+ /**
+ * Invoked when this block uses a scope symbol defined in one of its ancestors.
+ * @param symbol the scope symbol being used
+ * @param ancestors iterator over ancestor blocks
+ */
+ void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) {
+ if(ancestors.hasNext()) {
+ ancestors.next().setUsesScopeSymbol(symbol, ancestors);
+ }
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/BreakNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -64,8 +64,8 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterBreakNode(this) != null) {
+ return visitor.leaveBreakNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/CallNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -37,7 +37,7 @@
* IR representation for a function call.
*
*/
-public class CallNode extends Node implements TypeOverride {
+public class CallNode extends Node implements TypeOverride<CallNode> {
private Type type;
@@ -176,13 +176,13 @@
if (hasCallSiteType()) {
return type;
}
- assert !function.getType().isUnknown();
- return function.getType();
+ return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT;
}
@Override
- public void setType(final Type type) {
+ public CallNode setType(final Type type) {
this.type = type;
+ return this;
}
private boolean hasCallSiteType() {
@@ -208,14 +208,14 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCallNode(this) != null) {
function = function.accept(visitor);
for (int i = 0, count = args.size(); i < count; i++) {
args.set(i, args.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveCallNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/CaseNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -79,7 +79,7 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCaseNode(this) != null) {
if (test != null) {
test = test.accept(visitor);
}
@@ -87,7 +87,7 @@
body = (Block)body.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveCaseNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/CatchNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -84,7 +84,7 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterCatchNode(this) != null) {
exception = (IdentNode)exception.accept(visitor);
if (exceptionCondition != null) {
@@ -92,7 +92,7 @@
}
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveCatchNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ContinueNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -61,8 +61,8 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterContinueNode(this) != null) {
+ return visitor.leaveContinueNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/DoWhileNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/DoWhileNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -63,11 +63,11 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterDoWhileNode(this) != null) {
body = (Block)body.accept(visitor);
test = test.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveDoWhileNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/EmptyNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -57,8 +57,8 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterEmptyNode(this) != null) {
+ return visitor.leaveEmptyNode(this);
}
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ExecuteNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -85,9 +85,9 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterExecuteNode(this) != null) {
setExpression(expression.accept(visitor));
- return visitor.leave(this);
+ return visitor.leaveExecuteNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ForNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -76,7 +76,7 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterForNode(this) != null) {
if (init != null) {
init = init.accept(visitor);
}
@@ -91,7 +91,7 @@
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveForNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -34,7 +34,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
-import java.util.LinkedList;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
@@ -47,7 +47,7 @@
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.Parser;
-import jdk.nashorn.internal.runtime.Debug;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -57,6 +57,8 @@
*/
public class FunctionNode extends Block {
+ private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
+
/** Function kinds */
public enum Kind {
/** a normal function - nothing special */
@@ -112,9 +114,6 @@
/** List of parameters. */
private List<IdentNode> parameters;
- /** List of nested functions. */
- private List<FunctionNode> functions;
-
/** First token of function. **/
private long firstToken;
@@ -157,10 +156,6 @@
/** Pending control list. */
private final Stack<Node> controlStack;
- /** Variable declarations in the function's scope */
- @Ignore
- private final List<VarNode> declarations;
-
/** VarNode for this function statement */
@Ignore //this is explicit code anyway and should not be traversed after lower
private VarNode funcVarNode;
@@ -184,33 +179,35 @@
private int flags;
/** Is anonymous function flag. */
- private static final int IS_ANONYMOUS = 0b0000_0000_0000_0001;
- /** Is statement flag */
- private static final int IS_STATEMENT = 0b0000_0000_0000_0010;
+ private static final int IS_ANONYMOUS = 1 << 0;
+ /** Is the function created in a function declaration (as opposed to a function expression) */
+ private static final int IS_DECLARED = 1 << 1;
/** is this a strict mode function? */
- private static final int IS_STRICT_MODE = 0b0000_0000_0000_0100;
+ private static final int IS_STRICT_MODE = 1 << 2;
/** Does the function use the "arguments" identifier ? */
- private static final int USES_ARGUMENTS = 0b0000_0000_0000_1000;
+ private static final int USES_ARGUMENTS = 1 << 3;
/** Are we lowered ? */
- private static final int IS_LOWERED = 0b0000_0000_0001_0000;
+ private static final int IS_LOWERED = 1 << 4;
/** Has this node been split because it was too large? */
- private static final int IS_SPLIT = 0b0000_0000_0010_0000;
+ private static final int IS_SPLIT = 1 << 5;
/** Does the function call eval? */
- private static final int HAS_EVAL = 0b0000_0000_0100_0000;
+ private static final int HAS_EVAL = 1 << 6;
/** Does the function contain a with block ? */
- private static final int HAS_WITH = 0b0000_0000_1000_0000;
+ private static final int HAS_WITH = 1 << 7;
/** Does a descendant function contain a with or eval? */
- private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0001_0000_0000;
+ private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8;
/** Does the function define "arguments" identifier as a parameter of nested function name? */
- private static final int DEFINES_ARGUMENTS = 0b0000_0010_0000_0000;
+ private static final int DEFINES_ARGUMENTS = 1 << 9;
/** Does the function need a self symbol? */
- private static final int NEEDS_SELF_SYMBOL = 0b0000_0100_0000_0000;
+ private static final int NEEDS_SELF_SYMBOL = 1 << 10;
/** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
- private static final int USES_ANCESTOR_SCOPE = 0b0000_1000_0000_0000;
+ private static final int USES_ANCESTOR_SCOPE = 1 << 11;
/** Is this function lazily compiled? */
- private static final int IS_LAZY = 0b0001_0000_0000_0000;
+ private static final int IS_LAZY = 1 << 12;
/** Does this function have lazy, yet uncompiled children */
- private static final int HAS_LAZY_CHILDREN = 0b0010_0000_0000_0000;
+ private static final int HAS_LAZY_CHILDREN = 1 << 13;
+ /** Does this function have lazy, yet uncompiled children */
+ private static final int IS_PROGRAM = 1 << 14;
/** Does this function or any nested functions contain a with or an eval? */
private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
@@ -226,56 +223,34 @@
private Type returnType = Type.UNKNOWN;
/**
- * Used to keep track of a function's parent blocks.
- * This is needed when a (finally body) block is cloned than contains inner functions.
- * Does not include function.getParent().
- */
- @Ignore
- private List<Block> referencingParentBlocks;
-
- /**
* Constructor
*
* @param source the source
* @param token token
* @param finish finish
* @param namespace the namespace
- * @param parent the parent block
* @param ident the identifier
* @param name the name of the function
*/
- @SuppressWarnings("LeakingThisInConstructor")
- public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) {
- super(source, token, finish, parent, null);
+ public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) {
+ super(source, token, finish);
this.ident = ident;
this.name = name;
this.kind = Kind.NORMAL;
this.parameters = new ArrayList<>();
- this.functions = new ArrayList<>();
this.firstToken = token;
this.lastToken = token;
this.namespace = namespace;
this.labelStack = new Stack<>();
this.controlStack = new Stack<>();
- this.declarations = new ArrayList<>();
- // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
- // it as such a leak - this is a false positive as we're setting this into a field of the object being
- // constructed, so it can't be seen from other threads.
- this.function = this;
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.specializedTypes = new HashMap<>();
}
- @SuppressWarnings("LeakingThisInConstructor")
private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
super(functionNode, cs);
- this.functions = new ArrayList<>();
- for (final FunctionNode f : functionNode.getFunctions()) {
- this.functions.add((FunctionNode)cs.existingOrCopy(f));
- }
-
this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident);
this.name = functionNode.name;
this.kind = functionNode.kind;
@@ -296,22 +271,12 @@
this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
this.labelStack = new Stack<>();
this.controlStack = new Stack<>();
- this.declarations = new ArrayList<>();
-
- for (final VarNode decl : functionNode.getDeclarations()) {
- declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same?
- }
this.flags = functionNode.flags;
this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
/** VarNode for this function statement */
- // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
- // it as such a leak - this is a false positive as we're setting this into a field of the object being
- // constructed, so it can't be seen from other threads.
- this.function = this;
-
this.compilationState = EnumSet.copyOf(functionNode.compilationState);
this.specializedTypes = new HashMap<>();
}
@@ -319,21 +284,21 @@
@Override
protected Node copy(final CopyState cs) {
// deep clone all parent blocks
- return fixBlockChain(new FunctionNode(this, cs));
+ return new FunctionNode(this, cs);
}
@Override
public Node accept(final NodeVisitor visitor) {
- final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
- final Block saveBlock = visitor.getCurrentBlock();
+ final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
+ final Block saveBlock = visitor.getCurrentBlock();
+ final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter();
+ final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit();
visitor.setCurrentFunctionNode(this);
- visitor.setCurrentCompileUnit(getCompileUnit());
- visitor.setCurrentMethodEmitter(getMethodEmitter());
visitor.setCurrentBlock(this);
try {
- if (visitor.enter(this) != null) {
+ if (visitor.enterFunctionNode(this) != null) {
if (ident != null) {
ident = (IdentNode)ident.accept(visitor);
}
@@ -342,51 +307,25 @@
parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
}
- for (int i = 0, count = functions.size(); i < count; i++) {
- functions.set(i, (FunctionNode)functions.get(i).accept(visitor));
- }
-
for (int i = 0, count = statements.size(); i < count; i++) {
statements.set(i, statements.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveFunctionNode(this);
}
} finally {
visitor.setCurrentBlock(saveBlock);
visitor.setCurrentFunctionNode(saveFunctionNode);
- visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null);
- visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null);
+ visitor.setCurrentCompileUnit(saveCompileUnit);
+ visitor.setCurrentMethodEmitter(saveMethodEmitter);
}
return this;
}
- /**
- * Locate the parent function.
- *
- * @return Parent function.
- */
- public FunctionNode findParentFunction() {
- return getParent() != null ? getParent().getFunction() : null;
- }
-
- /**
- * Add parent name to the builder.
- *
- * @param sb String builder.
- */
- @Override
- public void addParentName(final StringBuilder sb) {
- if (!isScript()) {
- sb.append(getName());
- sb.append("$");
- }
- }
-
@Override
public boolean needsScope() {
- return super.needsScope() || isScript();
+ return super.needsScope() || isProgram();
}
/**
@@ -544,12 +483,18 @@
}
/**
- * Determine if script function.
- *
- * @return True if script function.
+ * Returns true if the function is the top-level program.
+ * @return True if this function node represents the top-level program.
*/
- public boolean isScript() {
- return getParent() == null;
+ public boolean isProgram() {
+ return (flags & IS_PROGRAM) != 0;
+ }
+
+ /**
+ * Marks the function as representing the top-level program.
+ */
+ public void setProgram() {
+ flags |= IS_PROGRAM;
}
/**
@@ -589,31 +534,31 @@
/**
* Flag this function as using the {@code with} keyword
+ * @param ancestors the iterator over functions in this functions's containing lexical context
*/
- public void setHasWith() {
+ public void setHasWith(final Iterator<FunctionNode> ancestors) {
if(!hasWith()) {
this.flags |= HAS_WITH;
// with requires scope in parents.
// TODO: refine this. with should not force all variables in parents to be in scope, only those that are
// actually referenced as identifiers by name
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
- private void markParentForWithOrEval() {
+ private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) {
// If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
setNeedsScope();
- final FunctionNode parentFunction = findParentFunction();
- if(parentFunction != null) {
- parentFunction.setDescendantHasWithOrEval();
+ if(ancestors.hasNext()) {
+ ancestors.next().setDescendantHasWithOrEval(ancestors);
}
}
- private void setDescendantHasWithOrEval() {
+ private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) {
if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
flags |= HAS_DESCENDANT_WITH_OR_EVAL;
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
@@ -628,11 +573,12 @@
/**
* Flag this function as calling the {@code eval} function
+ * @param ancestors the iterator over functions in this functions's containing lexical context
*/
- public void setHasEval() {
+ public void setHasEval(final Iterator<FunctionNode> ancestors) {
if(!hasEval()) {
this.flags |= HAS_EVAL;
- markParentForWithOrEval();
+ markParentForWithOrEval(ancestors);
}
}
@@ -665,11 +611,34 @@
}
/**
- * Get all nested functions
- * @return list of nested functions in this function
+ * Returns a list of functions declared by this function. Only includes declared functions, and does not include any
+ * function expressions that might occur in its body.
+ * @return a list of functions declared by this function.
*/
- public List<FunctionNode> getFunctions() {
- return Collections.unmodifiableList(functions);
+ public List<FunctionNode> getDeclaredFunctions() {
+ // Note that the function does not have a dedicated list of declared functions, but rather relies on the
+ // invariant that all function declarations are at the beginning of the statement list as VarNode with a
+ // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a
+ // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors.
+ final List<FunctionNode> fns = new ArrayList<>();
+ for (final Node stmt : statements) {
+ if(stmt instanceof LineNumberNode) {
+ continue;
+ } else if(stmt instanceof VarNode) {
+ final Node init = ((VarNode)stmt).getInit();
+ if(init instanceof FunctionNode) {
+ final FunctionNode fn = (FunctionNode)init;
+ if(fn.isDeclared()) {
+ fns.add(fn);
+ continue;
+ }
+ }
+ }
+ // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are
+ // at the start of the function, we've reached the end of function declarations.
+ break;
+ }
+ return fns;
}
/**
@@ -801,7 +770,7 @@
public boolean needsArguments() {
// uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
// for top-level script, "arguments" is picked up from Context by Global.init() instead.
- return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript();
+ return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram();
}
/**
@@ -820,7 +789,7 @@
* @return true if the function needs parent scope.
*/
public boolean needsParentScope() {
- return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript();
+ return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram();
}
/**
@@ -880,7 +849,7 @@
* @return true if all variables should be in scope
*/
public boolean allVarsInScope() {
- return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
+ return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
}
/**
@@ -989,19 +958,19 @@
}
/**
- * Check if this function is a statement
- * @return true if function is a statement
+ * Check if this function is created as a function declaration (as opposed to function expression)
+ * @return true if function is declared.
*/
- public boolean isStatement() {
- return (flags & IS_STATEMENT) != 0;
+ public boolean isDeclared() {
+ return (flags & IS_DECLARED) != 0;
}
/**
- * Flag this function as a statement
+ * Flag this function as being created as a function declaration (as opposed to a function expression).
* @see Parser
*/
- public void setIsStatement() {
- this.flags |= IS_STATEMENT;
+ public void setIsDeclared() {
+ this.flags |= IS_DECLARED;
}
/**
@@ -1049,35 +1018,16 @@
}
/**
- * Marks this function as one using any global symbol. The function and all its parent functions will all be marked
- * as needing parent scope.
- * @see #needsParentScope()
+ * Marks this function as using any of its ancestors' scopes.
*/
- public void setUsesGlobalSymbol() {
+ public void setUsesAncestorScope() {
this.flags |= USES_ANCESTOR_SCOPE;
- final FunctionNode parentFn = findParentFunction();
- if(parentFn != null) {
- parentFn.setUsesGlobalSymbol();
- }
}
- /**
- * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not
- * including the function defining the symbol will be marked as needing parent scope. The function defining the
- * symbol will be marked as one that needs to have its own scope.
- * @param symbol the symbol being used.
- * @see #needsParentScope()
- */
- public void setUsesScopeSymbol(final Symbol symbol) {
- if(symbol.getBlock() == this) {
- setNeedsScope();
- } else {
- this.flags |= USES_ANCESTOR_SCOPE;
- final FunctionNode parentFn = findParentFunction();
- if (parentFn != null) {
- parentFn.setUsesScopeSymbol(symbol);
- }
- }
+ @Override
+ void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) {
+ setUsesAncestorScope();
+ super.setUsesParentScopeSymbol(symbol, ancestors);
}
/**
@@ -1152,7 +1102,7 @@
@Override
public Type getType() {
- return getReturnType();
+ return FUNCTION_TYPE;
}
/**
@@ -1212,56 +1162,6 @@
}
/**
- * Add a new function to the function list.
- *
- * @param functionNode Function node to add.
- */
- @Override
- public void addFunction(final FunctionNode functionNode) {
- assert functionNode != null;
- functions.add(functionNode);
- }
-
- /**
- * Add a list of functions to the function list.
- *
- * @param functionNodes Function nodes to add.
- */
- @Override
- public void addFunctions(final List<FunctionNode> functionNodes) {
- functions.addAll(functionNodes);
- }
-
- /**
- * Set a function list
- *
- * @param functionNodes to set
- */
- @Override
- public void setFunctions(final List<FunctionNode> functionNodes) {
- this.functions = functionNodes;
- }
-
- /**
- * Add a variable declaration that should be visible to the entire function
- * scope. Parser does this.
- *
- * @param varNode a var node
- */
- public void addDeclaration(final VarNode varNode) {
- declarations.add(varNode);
- }
-
- /**
- * Return all variable declarations from this function scope
- *
- * @return all VarNodes in scope
- */
- public List<VarNode> getDeclarations() {
- return Collections.unmodifiableList(declarations);
- }
-
- /**
* Get the compile unit used to compile this function
* @see Compiler
* @return the compile unit
@@ -1294,32 +1194,4 @@
public void setMethodEmitter(final MethodEmitter method) {
this.method = method;
}
-
- /**
- * Each FunctionNode maintains a list of reference to its parent blocks.
- * Add a parent block to this function.
- *
- * @param parentBlock a block to remember as parent
- */
- public void addReferencingParentBlock(final Block parentBlock) {
- assert parentBlock.getFunction() == function.findParentFunction() : Debug.id(parentBlock.getFunction()) + "!=" + Debug.id(function.findParentFunction()); // all parent blocks must be in the same function
- if (parentBlock != function.getParent()) {
- if (referencingParentBlocks == null) {
- referencingParentBlocks = new LinkedList<>();
- }
- referencingParentBlocks.add(parentBlock);
- }
- }
-
- /**
- * Get the known parent blocks to this function
- *
- * @return list of parent blocks
- */
- public List<Block> getReferencingParentBlocks() {
- if (referencingParentBlocks == null) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(referencingParentBlocks);
- }
}
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -38,18 +38,18 @@
/**
* IR representation for an identifier.
*/
-public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall {
+public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall {
+ private static final int PROPERTY_NAME = 1 << 0;
+ private static final int INITIALIZED_HERE = 1 << 1;
+ private static final int FUNCTION = 1 << 2;
+
/** Identifier. */
private final String name;
/** Type for a callsite, e.g. X in a get()X or a set(X)V */
private Type callSiteType;
- /** flag for an ident that is the property name of an AccessNode. */
- private boolean isPropertyName;
-
- /** flag for an ident on the left hand side of <code>var lhs = rhs;</code>. */
- private boolean isInitializedHere;
+ private byte flags;
/**
* Constructor
@@ -71,9 +71,8 @@
*/
public IdentNode(final IdentNode identNode) {
super(identNode);
- this.name = identNode.getName();
- this.isPropertyName = identNode.isPropertyName;
- this.isInitializedHere = identNode.isInitializedHere;
+ this.name = identNode.getName();
+ this.flags = identNode.flags;
}
@Override
@@ -92,12 +91,17 @@
}
@Override
- public void setType(final Type type) {
+ public IdentNode setType(final Type type) {
if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
- this.callSiteType = type;
// do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't
+ if(this.callSiteType == type) {
+ return this;
+ }
+ final IdentNode n = (IdentNode)clone();
+ n.callSiteType = type;
+ return n;
}
@Override
@@ -131,8 +135,8 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterIdentNode(this) != null) {
+ return visitor.leaveIdentNode(this);
}
return this;
@@ -179,14 +183,18 @@
* @return true if this is a property name
*/
public boolean isPropertyName() {
- return isPropertyName;
+ return (flags & PROPERTY_NAME) != 0;
}
/**
* Flag this IdentNode as a property name
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setIsPropertyName() {
- isPropertyName = true;
+ public IdentNode setIsPropertyName() {
+ if(isPropertyName()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= PROPERTY_NAME;
+ return n;
}
/**
@@ -194,14 +202,18 @@
* @return true if IdentNode is initialized on creation
*/
public boolean isInitializedHere() {
- return isInitializedHere;
+ return (flags & INITIALIZED_HERE) != 0;
}
/**
* Flag IdentNode to be initialized on creation
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setIsInitializedHere() {
- isInitializedHere = true;
+ public IdentNode setIsInitializedHere() {
+ if(isInitializedHere()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= INITIALIZED_HERE;
+ return n;
}
/**
@@ -216,6 +228,17 @@
@Override
public boolean isFunction() {
- return false;
+ return (flags & FUNCTION) != 0;
+ }
+
+ /**
+ * Mark this node as being the callee operand of a {@link CallNode}.
+ * @return an ident node identical to this one in all aspects except with its function flag set.
+ */
+ public IdentNode setIsFunction() {
+ if(isFunction()) return this;
+ final IdentNode n = (IdentNode)clone();
+ n.flags |= FUNCTION;
+ return n;
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/IfNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -75,7 +75,7 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterIfNode(this) != null) {
test = test.accept(visitor);
pass = (Block)pass.accept(visitor);
@@ -84,7 +84,7 @@
fail = (Block)fail.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveIfNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -36,7 +36,7 @@
* IR representation of an indexed access (brackets operator.)
*
*/
-public class IndexNode extends BaseNode implements TypeOverride {
+public class IndexNode extends BaseNode implements TypeOverride<IndexNode> {
/** Property ident. */
private Node index;
@@ -92,10 +92,10 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterIndexNode(this) != null) {
base = base.accept(visitor);
index = index.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveIndexNode(this);
}
return this;
@@ -144,12 +144,13 @@
}
@Override
- public void setType(final Type type) {
+ public IndexNode setType(final Type type) {
if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) {
ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType());
}
hasCallSiteType = true;
getSymbol().setTypeOverride(type);
+ return this;
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/LabelNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -81,10 +81,10 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLabelNode(this) != null) {
label = (IdentNode)label.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveLabelNode(this);
}
return this;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java Sat Mar 23 00:58:39 2013 +0100
@@ -0,0 +1,198 @@
+package jdk.nashorn.internal.ir;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special
+ * methods to retrieve useful subsets of the context.
+ */
+public class LexicalContext implements Cloneable {
+ private final Deque<Block> lexicalContext;
+
+ /**
+ * Creates a new empty lexical context.
+ */
+ public LexicalContext() {
+ lexicalContext = new ArrayDeque<>();
+ }
+
+ /**
+ * Pushes a new block on top of the context, making it the innermost open block.
+ * @param block the new block
+ */
+ public void push(Block block) {
+ //new Exception(block.toString()).printStackTrace();
+ lexicalContext.push(block);
+ }
+
+ /**
+ * Pops the innermost block off the context.
+ * @param the block expected to be popped, used to detect unbalanced pushes/pops
+ */
+ public void pop(Block block) {
+ final Block popped = lexicalContext.pop();
+ assert popped == block;
+ }
+
+ /**
+ * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first.
+ * @return an iterator over all blocks in the context.
+ */
+ public Iterator<Block> getBlocks() {
+ return lexicalContext.iterator();
+ }
+
+ /**
+ * Returns an iterator over all functions in the context, with the top (innermost open) function first.
+ * @return an iterator over all functions in the context.
+ */
+ public Iterator<FunctionNode> getFunctions() {
+ return new FunctionIterator(getBlocks());
+ }
+
+ private static final class FunctionIterator implements Iterator<FunctionNode> {
+ private final Iterator<Block> it;
+ private FunctionNode next;
+
+ FunctionIterator(Iterator<Block> it) {
+ this.it = it;
+ next = findNext();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public FunctionNode next() {
+ if(next == null) {
+ throw new NoSuchElementException();
+ }
+ FunctionNode lnext = next;
+ next = findNext();
+ return lnext;
+ }
+
+ private FunctionNode findNext() {
+ while(it.hasNext()) {
+ final Block block = it.next();
+ if(block instanceof FunctionNode) {
+ return ((FunctionNode)block);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Returns an iterator over all ancestors block of the given block, with its parent block first.
+ * @param block the block whose ancestors are returned
+ * @return an iterator over all ancestors block of the given block.
+ */
+ public Iterator<Block> getAncestorBlocks(Block block) {
+ final Iterator<Block> it = getBlocks();
+ while(it.hasNext()) {
+ final Block b = it.next();
+ if(block == b) {
+ return it;
+ }
+ }
+ throw new AssertionError("Block is not on the current lexical context stack");
+ }
+
+ /**
+ * Returns an iterator over a block and all its ancestors blocks, with the block first.
+ * @param block the block that is the starting point of the iteration.
+ * @return an iterator over a block and all its ancestors.
+ */
+ public Iterator<Block> getBlocks(final Block block) {
+ final Iterator<Block> it = getAncestorBlocks(block);
+ return new Iterator<Block>() {
+ boolean blockReturned = false;
+ @Override
+ public boolean hasNext() {
+ return it.hasNext() || !blockReturned;
+ }
+ @Override
+ public Block next() {
+ if(blockReturned) {
+ return it.next();
+ }
+ blockReturned = true;
+ return block;
+ }
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Returns the closest function node to the block. If the block is itself a function, it is returned.
+ * @param block the block
+ * @return the function closest to the block.
+ * @see #getParentFunction(Block)
+ */
+ public FunctionNode getFunction(Block block) {
+ if(block instanceof FunctionNode) {
+ return (FunctionNode)block;
+ }
+ return getParentFunction(block);
+ }
+
+ /**
+ * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function,
+ * it is returned too.
+ * @param block the block
+ * @return the closest function node to the block and all its ancestor functions.
+ */
+ public Iterator<FunctionNode> getFunctions(final Block block) {
+ return new FunctionIterator(getBlocks(block));
+ }
+
+ /**
+ * Returns the containing function of the block. If the block is itself a function, its parent function is returned.
+ * @param block the block
+ * @return the containing function of the block.
+ * @see #getFunction(Block)
+ */
+ public FunctionNode getParentFunction(Block block) {
+ return getFirstFunction(getAncestorBlocks(block));
+ }
+
+ private static FunctionNode getFirstFunction(Iterator<Block> it) {
+ while(it.hasNext()) {
+ final Block ancestor = it.next();
+ if(ancestor instanceof FunctionNode) {
+ return (FunctionNode)ancestor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the innermost block in the context.
+ * @return the innermost block in the context.
+ */
+ public Block getCurrentBlock() {
+ return lexicalContext.element();
+ }
+
+ /**
+ * Returns the innermost function in the context.
+ * @return the innermost function in the context.
+ */
+ public FunctionNode getCurrentFunction() {
+ return getFirstFunction(getBlocks());
+ }
+}
--- a/nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/LineNumberNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -63,8 +63,8 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterLineNumberNode(this) != null) {
+ return visitor.leaveLineNumberNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/LiteralNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -46,7 +46,7 @@
*/
public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** Literal value */
- protected T value;
+ protected final T value;
/**
* Constructor
@@ -67,8 +67,17 @@
* @param literalNode source node
*/
protected LiteralNode(final LiteralNode<T> literalNode) {
+ this(literalNode, literalNode.value);
+ }
+
+ /**
+ * A copy constructor with value change.
+ * @param literalNode the original literal node
+ * @param newValue new value for this node
+ */
+ protected LiteralNode(final LiteralNode<T> literalNode, final T newValue) {
super(literalNode);
- this.value = literalNode.value;
+ this.value = newValue;
}
@Override
@@ -217,8 +226,8 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
+ if (visitor.enterLiteralNode(this) != null) {
+ return visitor.leaveLiteralNode(this);
}
return this;
@@ -544,6 +553,10 @@
super(literalNode);
}
+ private NodeLiteralNode(final LiteralNode<Node> literalNode, final Node value) {
+ super(literalNode, value);
+ }
+
@Override
protected Node copy(final CopyState cs) {
return new NodeLiteralNode(this);
@@ -551,11 +564,14 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLiteralNode(this) != null) {
if (value != null) {
- value = value.accept(visitor);
+ final Node newValue = value.accept(visitor);
+ if(value != newValue) {
+ return visitor.leaveLiteralNode(new NodeLiteralNode(this, newValue));
+ }
}
- return visitor.leave(this);
+ return visitor.leaveLiteralNode(this);
}
return this;
@@ -878,14 +894,14 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterLiteralNode(this) != null) {
for (int i = 0; i < value.length; i++) {
final Node element = value[i];
if (element != null) {
value[i] = element.accept(visitor);
}
}
- return visitor.leave(this);
+ return visitor.leaveLiteralNode(this);
}
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/ir/Location.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/Location.java Sat Mar 23 00:58:39 2013 +0100
@@ -65,7 +65,11 @@
@Override
protected Object clone() {
- return new Location(this);
+ try {
+ return super.clone();
+ } catch(CloneNotSupportedException e) {
+ throw new AssertionError(e);
+ }
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/ir/Node.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/Node.java Sat Mar 23 00:58:39 2013 +0100
@@ -165,12 +165,19 @@
return true;
}
- setIsResolved();
+ setIsResolved(true);
return false;
}
/**
+ * Reset the resolved flag.
+ */
+ public void resetResolved() {
+ setIsResolved(false);
+ }
+
+ /**
* Is this a debug info node like LineNumberNode etc?
*
* @return true if this is a debug node
@@ -234,8 +241,7 @@
*
* @return Deep copy of the Node.
*/
- @Override
- public final Node clone() {
+ public final Node copy() {
return copy(new CopyState());
}
@@ -349,10 +355,10 @@
}
/**
- * Flag this node as resolved, i.e. code has been generated for it
+ * Flag this node as resolved or not, i.e. code has been generated for it
*/
- public void setIsResolved() {
- this.isResolved = true;
+ private void setIsResolved(boolean isResolved) {
+ this.isResolved = isResolved;
}
/**
--- a/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ObjectNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -72,12 +72,12 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterObjectNode(this) != null) {
for (int i = 0, count = elements.size(); i < count; i++) {
elements.set(i, elements.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveObjectNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/PropertyNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -88,7 +88,7 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterPropertyNode(this) != null) {
key = (PropertyKey)((Node)key).accept(visitor);
if (value != null) {
@@ -103,7 +103,7 @@
setter = setter.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leavePropertyNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/ReferenceNode.java Tue Mar 19 11:03:24 2013 -0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.ir;
-
-import jdk.nashorn.internal.ir.annotations.Reference;
-import jdk.nashorn.internal.ir.visitor.NodeVisitor;
-import jdk.nashorn.internal.runtime.Source;
-
-/**
- * IR representation of a reference to another entity (function.)
- */
-public class ReferenceNode extends Node {
- /** Node referenced. */
- @Reference
- private final FunctionNode reference;
-
- /**
- * Constructor
- *
- * @param source the source
- * @param token token
- * @param finish finish
- * @param reference the function node to reference
- */
- public ReferenceNode(final Source source, final long token, final int finish, final FunctionNode reference) {
- super(source, token, finish);
-
- this.reference = reference;
- }
-
- private ReferenceNode(final ReferenceNode referenceNode) {
- super(referenceNode);
-
- this.reference = referenceNode.reference;
- }
-
- @Override
- protected Node copy(final CopyState cs) {
- return new ReferenceNode(this);
- }
-
- @Override
- public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- return visitor.leave(this);
- }
-
- return this;
- }
-
- @Override
- public void toString(final StringBuilder sb) {
- if (reference == null) {
- sb.append("null");
- } else {
- reference.toString(sb);
- }
- }
-
- /**
- * Get there function node reference that this node points tp
- * @return a function node reference
- */
- public FunctionNode getReference() {
- return reference;
- }
-
-}
--- a/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ReturnNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -100,12 +100,12 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterReturnNode(this) != null) {
if (expression != null) {
expression = expression.accept(visitor);
}
- return visitor.leave(this);
+ return visitor.leaveReturnNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/RuntimeNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -38,7 +38,7 @@
* IR representation for a runtime call.
*
*/
-public class RuntimeNode extends Node implements TypeOverride {
+public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> {
/**
* Request enum used for meta-information about the runtime request
@@ -393,8 +393,9 @@
}
@Override
- public void setType(final Type type) {
+ public RuntimeNode setType(final Type type) {
this.callSiteType = type;
+ return this;
}
@Override
@@ -408,12 +409,12 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterRuntimeNode(this) != null) {
for (int i = 0, count = args.size(); i < count; i++) {
args.set(i, args.get(i).accept(visitor));
}
- return visitor.leave(this);
+ return visitor.leaveRuntimeNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/SplitNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -108,10 +108,10 @@
visitor.setCurrentMethodEmitter(getMethodEmitter());
try {
- if (visitor.enter(this) != null) {
+ if (visitor.enterSplitNode(this) != null) {
body = body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveSplitNode(this);
}
} finally {
visitor.setCurrentCompileUnit(saveCompileUnit);
--- a/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/SwitchNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -85,7 +85,7 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterSwitchNode(this) != null) {
expression = expression.accept(visitor);
for (int i = 0, count = cases.size(); i < count; i++) {
@@ -94,7 +94,7 @@
//the default case is in the cases list and should not be explicitly traversed!
- return visitor.leave(this);
+ return visitor.leaveSwitchNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/Symbol.java Sat Mar 23 00:58:39 2013 +0100
@@ -38,31 +38,31 @@
*/
public final class Symbol implements Comparable<Symbol> {
- /** Symbol flags. Kind ordered by precedence. */
- public static final int IS_TEMP = 0b0000_0001;
+ /** Symbol kinds. Kind ordered by precedence. */
+ public static final int IS_TEMP = 1;
/** Is this Global */
- public static final int IS_GLOBAL = 0b0000_0010;
+ public static final int IS_GLOBAL = 2;
/** Is this a variable */
- public static final int IS_VAR = 0b0000_0011;
+ public static final int IS_VAR = 3;
/** Is this a parameter */
- public static final int IS_PARAM = 0b0000_0100;
+ public static final int IS_PARAM = 4;
/** Is this a constant */
- public static final int IS_CONSTANT = 0b0000_0101;
-
- static final int KINDMASK = 0b0000_1111;
+ public static final int IS_CONSTANT = 5;
+ /** Mask for kind flags */
+ public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits
/** Is this scope */
- public static final int IS_SCOPE = 0b0000_0001_0000;
+ public static final int IS_SCOPE = 1 << 4;
/** Is this a this symbol */
- public static final int IS_THIS = 0b0000_0010_0000;
+ public static final int IS_THIS = 1 << 5;
/** Can this symbol ever be undefined */
- public static final int CAN_BE_UNDEFINED = 0b0000_0100_0000;
+ public static final int CAN_BE_UNDEFINED = 1 << 6;
/** Can this symbol ever have primitive types */
- public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000;
+ public static final int CAN_BE_PRIMITIVE = 1 << 7;
/** Is this a let */
- public static final int IS_LET = 0b0001_0000_0000;
+ public static final int IS_LET = 1 << 8;
/** Is this an internal symbol, never represented explicitly in source code */
- public static final int IS_INTERNAL = 0b0010_0000_0000;
+ public static final int IS_INTERNAL = 1 << 9;
/** Null or name identifying symbol. */
private final String name;
@@ -269,15 +269,6 @@
return type.isCategory2() ? 2 : 1;
}
- /**
- * Return the defining function (scope.)
- *
- * @return Defining function.
- */
- public FunctionNode findFunction() {
- return block != null ? block.getFunction() : null;
- }
-
@Override
public boolean equals(final Object other) {
if (!(other instanceof Symbol)) {
@@ -487,27 +478,6 @@
}
/**
- * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load
- *
- * @param currentFunction function to check for fast scope
- * @return true if fast scope
- */
- public boolean isFastScope(final FunctionNode currentFunction) {
- if (!isScope() || !block.needsScope()) {
- return false;
- }
- // Allow fast scope access if no parent function contains with or eval
- FunctionNode func = currentFunction;
- while (func != null) {
- if (func.hasWith() || func.hasEval()) {
- return false;
- }
- func = func.findParentFunction();
- }
- return true;
- }
-
- /**
* Get the block in which the symbol is defined
* @return a block
*/
@@ -651,7 +621,7 @@
* @return true if this this is a global scope symbol
*/
public boolean isTopLevel() {
- return block instanceof FunctionNode && ((FunctionNode) block).isScript();
+ return block instanceof FunctionNode && ((FunctionNode) block).isProgram();
}
--- a/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/TernaryNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -77,11 +77,11 @@
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- lhs = lhs.accept(visitor);
- rhs = rhs.accept(visitor);
- third = third.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterTernaryNode(this) != null) {
+ final Node newLhs = lhs().accept(visitor);
+ final Node newRhs = rhs().accept(visitor);
+ final Node newThird = third.accept(visitor);
+ return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs));
}
return this;
@@ -133,8 +133,12 @@
/**
* Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z
* @param third a node
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setThird(final Node third) {
- this.third = third;
+ public TernaryNode setThird(final Node third) {
+ if(this.third == third) return this;
+ final TernaryNode n = (TernaryNode)clone();
+ n.third = third;
+ return n;
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/ThrowNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -75,9 +75,9 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterThrowNode(this) != null) {
setExpression(expression.accept(visitor));
- return visitor.leave(this);
+ return visitor.leaveThrowNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/TryNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -101,7 +101,7 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterTryNode(this) != null) {
// Need to do first for termination analysis.
if (finallyBody != null) {
finallyBody = (Block)finallyBody.accept(visitor);
@@ -115,7 +115,7 @@
}
this.catchBlocks = newCatchBlocks;
- return visitor.leave(this);
+ return visitor.leaveTryNode(this);
}
return this;
@@ -155,6 +155,15 @@
}
/**
+ * Returns true if the specified block is the body of this try block, or any of its catch blocks.
+ * @param block the block
+ * @return true if the specified block is the body of this try block, or any of its catch blocks.
+ */
+ public boolean isChildBlock(Block block) {
+ return body == block || catchBlocks.contains(block);
+ }
+
+ /**
* Get the catch blocks for this try block
* @return a list of blocks
*/
--- a/nashorn/src/jdk/nashorn/internal/ir/TypeOverride.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/TypeOverride.java Sat Mar 23 00:58:39 2013 +0100
@@ -36,15 +36,17 @@
* by using JSType.toInt32. Especially in scenarios where the field is already stored
* as a primitive, this will be much faster than the "object is all I see" scope
* available in the method
+ * @param <T> the type of the node implementing the interface
*/
-public interface TypeOverride {
+public interface TypeOverride<T extends Node> {
/**
* Set the override type
*
* @param type the type
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setType(final Type type);
+ public T setType(final Type type);
/**
* Returns true if this node can have a callsite override, e.g. all scope ident nodes
--- a/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/UnaryNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -41,7 +41,7 @@
*/
public class UnaryNode extends Node implements Assignment<Node> {
/** Right hand side argument. */
- protected Node rhs;
+ private Node rhs;
/**
* Constructor
@@ -104,6 +104,11 @@
}
@Override
+ public Node setAssignmentDest(Node n) {
+ return setRHS(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return getAssignmentDest();
}
@@ -132,9 +137,8 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- rhs = rhs.accept(visitor);
- return visitor.leave(this);
+ if (visitor.enterUnaryNode(this) != null) {
+ return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor)));
}
return this;
@@ -212,10 +216,12 @@
* @see BinaryNode
*
* @param rhs right hand side or expression node
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setRHS(final Node rhs) {
- this.rhs = rhs;
+ public UnaryNode setRHS(final Node rhs) {
+ if(this.rhs == rhs) return this;
+ final UnaryNode n = (UnaryNode)clone();
+ n.rhs = rhs;
+ return n;
}
-
-
}
--- a/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/VarNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -38,8 +38,8 @@
/** Initialization expression. */
private Node init;
- /** Is this a function var node */
- private boolean isFunctionVarNode;
+ /** Is this a var statement (as opposed to a "var" in a for loop statement) */
+ private final boolean isStatement;
/**
* Constructor
@@ -51,20 +51,34 @@
* @param init init node or null if just a declaration
*/
public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) {
+ this(source, token, finish, name, init, true);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param source the source
+ * @param token token
+ * @param finish finish
+ * @param name name of variable
+ * @param init init node or null if just a declaration
+ * @param isStatement if this is a var statement (true), or a for-loop initializer (false)
+ */
+ public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) {
super(source, token, finish);
- this.name = name;
+ this.name = init == null ? name : name.setIsInitializedHere();
this.init = init;
- if (init != null) {
- this.name.setIsInitializedHere();
- }
+ this.isStatement = isStatement;
}
+
private VarNode(final VarNode varNode, final CopyState cs) {
super(varNode);
this.name = (IdentNode)cs.existingOrCopy(varNode.name);
this.init = cs.existingOrCopy(varNode.init);
+ this.isStatement = varNode.isStatement;
}
@Override
@@ -83,6 +97,11 @@
}
@Override
+ public Node setAssignmentDest(IdentNode n) {
+ return setName(n);
+ }
+
+ @Override
public Node getAssignmentSource() {
return isAssignment() ? getInit() : null;
}
@@ -127,16 +146,19 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
- name = (IdentNode)name.accept(visitor);
-
- if (init != null) {
- init = init.accept(visitor);
+ if (visitor.enterVarNode(this) != null) {
+ final IdentNode newName = (IdentNode)name.accept(visitor);
+ final Node newInit = init == null ? null : init.accept(visitor);
+ final VarNode newThis;
+ if(name != newName || init != newInit) {
+ newThis = (VarNode)clone();
+ newThis.init = newInit;
+ newThis.name = newInit == null ? newName : newName.setIsInitializedHere();
+ } else {
+ newThis = this;
}
-
- return visitor.leave(this);
+ return visitor.leaveVarNode(newThis);
}
-
return this;
}
@@ -162,9 +184,13 @@
/**
* Reset the initialization expression
* @param init new initialization expression
+ * @return a node equivalent to this one except for the requested change.
*/
- public void setInit(final Node init) {
- this.init = init;
+ public VarNode setInit(final Node init) {
+ if(this.init == init) return this;
+ final VarNode n = (VarNode)clone();
+ n.init = init;
+ return n;
}
/**
@@ -179,30 +205,26 @@
* Reset the identifier for this VarNode
* @param name new IdentNode representing the variable being set or declared
*/
- public void setName(final IdentNode name) {
- this.name = name;
+ private VarNode setName(final IdentNode name) {
+ if(this.name == name) return this;
+ final VarNode n = (VarNode)clone();
+ n.name = name;
+ return n;
}
/**
- * Check if this is a virtual assignment of a function node. Function nodes declared
- * with a name are hoisted to the top of the scope and appear as symbols too. This is
- * implemented by representing them as virtual VarNode assignments added to the code
- * during lowering
- *
- * @see FunctionNode
- *
- * @return true if this is a virtual function declaration
+ * Returns true if this is a var statement (as opposed to a var initializer in a for loop).
+ * @return true if this is a var statement (as opposed to a var initializer in a for loop).
*/
- public boolean isFunctionVarNode() {
- return isFunctionVarNode;
+ public boolean isStatement() {
+ return isStatement;
}
/**
- * Flag this var node as a virtual function var node assignment as described in
- * {@link VarNode#isFunctionVarNode()}
+ * Returns true if this is a function declaration.
+ * @return true if this is a function declaration.
*/
- public void setIsFunctionVarNode() {
- this.isFunctionVarNode = true;
+ public boolean isFunctionDeclaration() {
+ return init instanceof FunctionNode && ((FunctionNode)init).isDeclared();
}
-
}
--- a/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/WhileNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -88,11 +88,11 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterWhileNode(this) != null) {
test = test.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveWhileNode(this);
}
return this;
}
--- a/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/WithNode.java Sat Mar 23 00:58:39 2013 +0100
@@ -73,10 +73,10 @@
*/
@Override
public Node accept(final NodeVisitor visitor) {
- if (visitor.enter(this) != null) {
+ if (visitor.enterWithNode(this) != null) {
expression = expression.accept(visitor);
body = (Block)body.accept(visitor);
- return visitor.leave(this);
+ return visitor.leaveWithNode(this);
}
return this;
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Sat Mar 23 00:58:39 2013 +0100
@@ -112,7 +112,7 @@
}
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
enterDefault(accessNode);
type("MemberExpression");
@@ -132,7 +132,7 @@
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
enterDefault(block);
type("BlockStatement");
@@ -154,7 +154,7 @@
}
@Override
- public Node enter(final BinaryNode binaryNode) {
+ public Node enterBinaryNode(final BinaryNode binaryNode) {
enterDefault(binaryNode);
final String name;
@@ -183,7 +183,7 @@
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
enterDefault(breakNode);
type("BreakStatement");
@@ -201,7 +201,7 @@
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
enterDefault(callNode);
type("CallExpression");
@@ -217,7 +217,7 @@
}
@Override
- public Node enter(final CaseNode caseNode) {
+ public Node enterCaseNode(final CaseNode caseNode) {
enterDefault(caseNode);
type("SwitchCase");
@@ -238,7 +238,7 @@
}
@Override
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
enterDefault(catchNode);
type("CatchClause");
@@ -264,7 +264,7 @@
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
enterDefault(continueNode);
type("ContinueStatement");
@@ -282,7 +282,7 @@
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
enterDefault(doWhileNode);
type("DoWhileStatement");
@@ -299,7 +299,7 @@
}
@Override
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
enterDefault(emptyNode);
type("EmptyStatement");
@@ -308,7 +308,7 @@
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
enterDefault(executeNode);
type("ExpressionStatement");
@@ -321,7 +321,7 @@
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
enterDefault(forNode);
if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) {
@@ -384,14 +384,14 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
enterDefault(functionNode);
- final boolean program = functionNode.isScript();
+ final boolean program = functionNode.isProgram();
final String name;
if (program) {
name = "Program";
- } else if (functionNode.isStatement()) {
+ } else if (functionNode.isDeclared()) {
name = "FunctionDeclaration";
} else {
name = "FunctionExpression";
@@ -419,20 +419,11 @@
}
// body consists of nested functions and statements
- final List<FunctionNode> funcs = functionNode.getFunctions();
final List<Node> stats = functionNode.getStatements();
- final int size = stats.size() + funcs.size();
+ final int size = stats.size();
int idx = 0;
arrayStart("body");
- for (final Node func : funcs) {
- func.accept(this);
- if (idx != (size - 1)) {
- comma();
- }
- idx++;
- }
-
for (final Node stat : stats) {
if (! stat.isDebug()) {
stat.accept(this);
@@ -448,7 +439,7 @@
}
@Override
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
enterDefault(identNode);
final String name = identNode.getName();
@@ -464,7 +455,7 @@
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
enterDefault(ifNode);
type("IfStatement");
@@ -490,7 +481,7 @@
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
enterDefault(indexNode);
type("MemberExpression");
@@ -510,7 +501,7 @@
}
@Override
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
enterDefault(labelNode);
type("LabeledStatement");
@@ -527,13 +518,13 @@
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
return null;
}
@SuppressWarnings("rawtypes")
@Override
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode literalNode) {
enterDefault(literalNode);
if (literalNode instanceof LiteralNode.ArrayLiteralNode) {
@@ -569,7 +560,7 @@
}
@Override
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
enterDefault(objectNode);
type("ObjectExpression");
@@ -581,7 +572,7 @@
}
@Override
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
final Node key = propertyNode.getKey();
final Node value = propertyNode.getValue();
@@ -647,7 +638,7 @@
}
@Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
enterDefault(returnNode);
type("ReturnStatement");
@@ -665,7 +656,7 @@
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
final RuntimeNode.Request req = runtimeNode.getRequest();
if (req == RuntimeNode.Request.DEBUGGER) {
@@ -680,12 +671,12 @@
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
return null;
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
enterDefault(switchNode);
type("SwitchStatement");
@@ -701,7 +692,7 @@
}
@Override
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
enterDefault(ternaryNode);
type("ConditionalExpression");
@@ -722,7 +713,7 @@
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
enterDefault(throwNode);
type("ThrowStatement");
@@ -735,7 +726,7 @@
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
enterDefault(tryNode);
type("TryStatement");
@@ -760,7 +751,7 @@
}
@Override
- public Node enter(final UnaryNode unaryNode) {
+ public Node enterUnaryNode(final UnaryNode unaryNode) {
enterDefault(unaryNode);
final TokenType tokenType = unaryNode.tokenType();
@@ -816,7 +807,7 @@
}
@Override
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
enterDefault(varNode);
type("VariableDeclaration");
@@ -852,7 +843,7 @@
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
enterDefault(whileNode);
type("WhileStatement");
@@ -869,7 +860,7 @@
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
enterDefault(withNode);
type("WithStatement");
--- a/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Sat Mar 23 00:58:39 2013 +0100
@@ -42,7 +42,6 @@
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.Node;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -138,13 +137,13 @@
* Visits.
*/
@Override
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
accessNode.toString(sb);
return null;
}
@Override
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
sb.append(' ');
sb.append('{');
@@ -152,21 +151,6 @@
final boolean isFunction = block instanceof FunctionNode;
- if (isFunction) {
- final FunctionNode function = (FunctionNode)block;
- final List<FunctionNode> functions = function.getFunctions();
-
- for (final FunctionNode f : functions) {
- sb.append(EOLN);
- indent();
- f.accept(this);
- }
-
- if (!functions.isEmpty()) {
- sb.append(EOLN);
- }
- }
-
final List<Node> statements = block.getStatements();
boolean lastLineNumber = false;
@@ -224,25 +208,25 @@
}
@Override
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
breakNode.toString(sb);
return null;
}
@Override
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
callNode.toString(sb);
return null;
}
@Override
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
continueNode.toString(sb);
return null;
}
@Override
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
sb.append("do");
doWhileNode.getBody().accept(this);
sb.append(' ');
@@ -252,7 +236,7 @@
}
@Override
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
final Node expression = executeNode.getExpression();
if (expression instanceof UnaryNode) {
@@ -265,7 +249,7 @@
}
@Override
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
forNode.toString(sb);
forNode.getBody().accept(this);
@@ -273,15 +257,15 @@
}
@Override
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
functionNode.toString(sb);
- enter((Block)functionNode);
+ enterBlock(functionNode);
return null;
}
@Override
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
ifNode.toString(sb);
ifNode.getPass().accept(this);
@@ -296,13 +280,13 @@
}
@Override
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
indexNode.toString(sb);
return null;
}
@Override
- public Node enter(final LabelNode labeledNode) {
+ public Node enterLabelNode(final LabelNode labeledNode) {
indent -= TABWIDTH;
indent();
indent += TABWIDTH;
@@ -313,7 +297,7 @@
}
@Override
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (printLineNumbers) {
lineNumberNode.toString(sb);
}
@@ -323,25 +307,19 @@
@Override
- public Node enter(final ReferenceNode referenceNode) {
- referenceNode.toString(sb);
- return null;
- }
-
- @Override
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
returnNode.toString(sb);
return null;
}
@Override
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
runtimeNode.toString(sb);
return null;
}
@Override
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
splitNode.toString(sb);
sb.append(EOLN);
indent += TABWIDTH;
@@ -350,7 +328,7 @@
}
@Override
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
sb.append("</split>");
sb.append(EOLN);
indent -= TABWIDTH;
@@ -359,7 +337,7 @@
}
@Override
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
switchNode.toString(sb);
sb.append(" {");
@@ -383,13 +361,13 @@
}
@Override
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
throwNode.toString(sb);
return null;
}
@Override
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
tryNode.toString(sb);
tryNode.getBody().accept(this);
@@ -412,13 +390,19 @@
}
@Override
- public Node enter(final VarNode varNode) {
- varNode.toString(sb);
+ public Node enterVarNode(final VarNode varNode) {
+ sb.append("var ");
+ varNode.getName().toString(sb);
+ final Node init = varNode.getInit();
+ if(init != null) {
+ sb.append(" = ");
+ init.accept(this);
+ }
return null;
}
@Override
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
whileNode.toString(sb);
whileNode.getBody().accept(this);
@@ -426,7 +410,7 @@
}
@Override
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
withNode.toString(sb);
withNode.getBody().accept(this);
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Sat Mar 23 00:58:39 2013 +0100
@@ -53,7 +53,7 @@
}
@Override
- public final Node enter(final UnaryNode unaryNode) {
+ public final Node enterUnaryNode(final UnaryNode unaryNode) {
switch (unaryNode.tokenType()) {
case ADD:
return enterADD(unaryNode);
@@ -81,12 +81,12 @@
case INCPOSTFIX:
return enterDECINC(unaryNode);
default:
- return super.enter(unaryNode);
+ return super.enterUnaryNode(unaryNode);
}
}
@Override
- public final Node leave(final UnaryNode unaryNode) {
+ public final Node leaveUnaryNode(final UnaryNode unaryNode) {
switch (unaryNode.tokenType()) {
case ADD:
return leaveADD(unaryNode);
@@ -114,12 +114,12 @@
case INCPOSTFIX:
return leaveDECINC(unaryNode);
default:
- return super.leave(unaryNode);
+ return super.leaveUnaryNode(unaryNode);
}
}
@Override
- public final Node enter(final BinaryNode binaryNode) {
+ public final Node enterBinaryNode(final BinaryNode binaryNode) {
switch (binaryNode.tokenType()) {
case ADD:
return enterADD(binaryNode);
@@ -198,12 +198,12 @@
case SUB:
return enterSUB(binaryNode);
default:
- return super.enter(binaryNode);
+ return super.enterBinaryNode(binaryNode);
}
}
@Override
- public final Node leave(final BinaryNode binaryNode) {
+ public final Node leaveBinaryNode(final BinaryNode binaryNode) {
switch (binaryNode.tokenType()) {
case ADD:
return leaveADD(binaryNode);
@@ -282,7 +282,7 @@
case SUB:
return leaveSUB(binaryNode);
default:
- return super.leave(binaryNode);
+ return super.leaveBinaryNode(binaryNode);
}
}
--- a/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Sat Mar 23 00:58:39 2013 +0100
@@ -49,7 +49,6 @@
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SplitNode;
@@ -153,7 +152,7 @@
* @param accessNode the node
* @return processed node, null if traversal should end, null if traversal should end
*/
- public Node enter(final AccessNode accessNode) {
+ public Node enterAccessNode(final AccessNode accessNode) {
return enterDefault(accessNode);
}
@@ -163,7 +162,7 @@
* @param accessNode the node
* @return processed node, null if traversal should end
*/
- public Node leave(final AccessNode accessNode) {
+ public Node leaveAccessNode(final AccessNode accessNode) {
return leaveDefault(accessNode);
}
@@ -173,7 +172,7 @@
* @param block the node
* @return processed node, null if traversal should end
*/
- public Node enter(final Block block) {
+ public Node enterBlock(final Block block) {
return enterDefault(block);
}
@@ -183,7 +182,7 @@
* @param block the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final Block block) {
+ public Node leaveBlock(final Block block) {
return leaveDefault(block);
}
@@ -193,7 +192,7 @@
* @param binaryNode the node
* @return processed node
*/
- public Node enter(final BinaryNode binaryNode) {
+ public Node enterBinaryNode(final BinaryNode binaryNode) {
return enterDefault(binaryNode);
}
@@ -203,7 +202,7 @@
* @param binaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final BinaryNode binaryNode) {
+ public Node leaveBinaryNode(final BinaryNode binaryNode) {
return leaveDefault(binaryNode);
}
@@ -213,7 +212,7 @@
* @param breakNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final BreakNode breakNode) {
+ public Node enterBreakNode(final BreakNode breakNode) {
return enterDefault(breakNode);
}
@@ -223,7 +222,7 @@
* @param breakNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final BreakNode breakNode) {
+ public Node leaveBreakNode(final BreakNode breakNode) {
return leaveDefault(breakNode);
}
@@ -233,7 +232,7 @@
* @param callNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CallNode callNode) {
+ public Node enterCallNode(final CallNode callNode) {
return enterDefault(callNode);
}
@@ -243,7 +242,7 @@
* @param callNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CallNode callNode) {
+ public Node leaveCallNode(final CallNode callNode) {
return leaveDefault(callNode);
}
@@ -253,7 +252,7 @@
* @param caseNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CaseNode caseNode) {
+ public Node enterCaseNode(final CaseNode caseNode) {
return enterDefault(caseNode);
}
@@ -263,7 +262,7 @@
* @param caseNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CaseNode caseNode) {
+ public Node leaveCaseNode(final CaseNode caseNode) {
return leaveDefault(caseNode);
}
@@ -273,7 +272,7 @@
* @param catchNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final CatchNode catchNode) {
+ public Node enterCatchNode(final CatchNode catchNode) {
return enterDefault(catchNode);
}
@@ -283,7 +282,7 @@
* @param catchNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final CatchNode catchNode) {
+ public Node leaveCatchNode(final CatchNode catchNode) {
return leaveDefault(catchNode);
}
@@ -293,7 +292,7 @@
* @param continueNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ContinueNode continueNode) {
+ public Node enterContinueNode(final ContinueNode continueNode) {
return enterDefault(continueNode);
}
@@ -303,7 +302,7 @@
* @param continueNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ContinueNode continueNode) {
+ public Node leaveContinueNode(final ContinueNode continueNode) {
return leaveDefault(continueNode);
}
@@ -313,7 +312,7 @@
* @param doWhileNode the node
* @return processed node
*/
- public Node enter(final DoWhileNode doWhileNode) {
+ public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
return enterDefault(doWhileNode);
}
@@ -323,7 +322,7 @@
* @param doWhileNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final DoWhileNode doWhileNode) {
+ public Node leaveDoWhileNode(final DoWhileNode doWhileNode) {
return leaveDefault(doWhileNode);
}
@@ -333,7 +332,7 @@
* @param emptyNode the node
* @return processed node
*/
- public Node enter(final EmptyNode emptyNode) {
+ public Node enterEmptyNode(final EmptyNode emptyNode) {
return enterDefault(emptyNode);
}
@@ -343,7 +342,7 @@
* @param emptyNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final EmptyNode emptyNode) {
+ public Node leaveEmptyNode(final EmptyNode emptyNode) {
return leaveDefault(emptyNode);
}
@@ -353,7 +352,7 @@
* @param executeNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ExecuteNode executeNode) {
+ public Node enterExecuteNode(final ExecuteNode executeNode) {
return enterDefault(executeNode);
}
@@ -363,7 +362,7 @@
* @param executeNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ExecuteNode executeNode) {
+ public Node leaveExecuteNode(final ExecuteNode executeNode) {
return leaveDefault(executeNode);
}
@@ -373,7 +372,7 @@
* @param forNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ForNode forNode) {
+ public Node enterForNode(final ForNode forNode) {
return enterDefault(forNode);
}
@@ -383,7 +382,7 @@
* @param forNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ForNode forNode) {
+ public Node leaveForNode(final ForNode forNode) {
return leaveDefault(forNode);
}
@@ -393,7 +392,7 @@
* @param functionNode the node
* @return processed node
*/
- public Node enter(final FunctionNode functionNode) {
+ public Node enterFunctionNode(final FunctionNode functionNode) {
return enterDefault(functionNode);
}
@@ -403,7 +402,7 @@
* @param functionNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final FunctionNode functionNode) {
+ public Node leaveFunctionNode(final FunctionNode functionNode) {
return leaveDefault(functionNode);
}
@@ -413,7 +412,7 @@
* @param identNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IdentNode identNode) {
+ public Node enterIdentNode(final IdentNode identNode) {
return enterDefault(identNode);
}
@@ -423,7 +422,7 @@
* @param identNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IdentNode identNode) {
+ public Node leaveIdentNode(final IdentNode identNode) {
return leaveDefault(identNode);
}
@@ -433,7 +432,7 @@
* @param ifNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IfNode ifNode) {
+ public Node enterIfNode(final IfNode ifNode) {
return enterDefault(ifNode);
}
@@ -443,7 +442,7 @@
* @param ifNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IfNode ifNode) {
+ public Node leaveIfNode(final IfNode ifNode) {
return leaveDefault(ifNode);
}
@@ -453,7 +452,7 @@
* @param indexNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final IndexNode indexNode) {
+ public Node enterIndexNode(final IndexNode indexNode) {
return enterDefault(indexNode);
}
@@ -463,7 +462,7 @@
* @param indexNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final IndexNode indexNode) {
+ public Node leaveIndexNode(final IndexNode indexNode) {
return leaveDefault(indexNode);
}
@@ -473,7 +472,7 @@
* @param labelNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final LabelNode labelNode) {
+ public Node enterLabelNode(final LabelNode labelNode) {
return enterDefault(labelNode);
}
@@ -483,7 +482,7 @@
* @param labelNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final LabelNode labelNode) {
+ public Node leaveLabelNode(final LabelNode labelNode) {
return leaveDefault(labelNode);
}
@@ -493,7 +492,7 @@
* @param lineNumberNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final LineNumberNode lineNumberNode) {
+ public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
return enterDefault(lineNumberNode);
}
@@ -503,7 +502,7 @@
* @param lineNumberNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final LineNumberNode lineNumberNode) {
+ public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) {
return leaveDefault(lineNumberNode);
}
@@ -513,8 +512,7 @@
* @param literalNode the node
* @return processed node
*/
- @SuppressWarnings("rawtypes")
- public Node enter(final LiteralNode literalNode) {
+ public Node enterLiteralNode(final LiteralNode<?> literalNode) {
return enterDefault(literalNode);
}
@@ -524,8 +522,7 @@
* @param literalNode the node
* @return processed node, which will replace the original one, or the original node
*/
- @SuppressWarnings("rawtypes")
- public Node leave(final LiteralNode literalNode) {
+ public Node leaveLiteralNode(final LiteralNode<?> literalNode) {
return leaveDefault(literalNode);
}
@@ -535,7 +532,7 @@
* @param objectNode the node
* @return processed node
*/
- public Node enter(final ObjectNode objectNode) {
+ public Node enterObjectNode(final ObjectNode objectNode) {
return enterDefault(objectNode);
}
@@ -545,7 +542,7 @@
* @param objectNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ObjectNode objectNode) {
+ public Node leaveObjectNode(final ObjectNode objectNode) {
return leaveDefault(objectNode);
}
@@ -555,7 +552,7 @@
* @param propertyNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final PropertyNode propertyNode) {
+ public Node enterPropertyNode(final PropertyNode propertyNode) {
return enterDefault(propertyNode);
}
@@ -565,37 +562,17 @@
* @param propertyNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final PropertyNode propertyNode) {
+ public Node leavePropertyNode(final PropertyNode propertyNode) {
return leaveDefault(propertyNode);
}
/**
- * Callback for entering a ReferenceNode
- *
- * @param referenceNode the node
- * @return processed node, null if traversal should end
- */
- public Node enter(final ReferenceNode referenceNode) {
- return enterDefault(referenceNode);
- }
-
- /**
- * Callback for leaving a ReferenceNode
- *
- * @param referenceNode the node
- * @return processed node, which will replace the original one, or the original node
- */
- public Node leave(final ReferenceNode referenceNode) {
- return leaveDefault(referenceNode);
- }
-
- /**
* Callback for entering a ReturnNode
*
* @param returnNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ReturnNode returnNode) {
+ public Node enterReturnNode(final ReturnNode returnNode) {
return enterDefault(returnNode);
}
@@ -605,7 +582,7 @@
* @param returnNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ReturnNode returnNode) {
+ public Node leaveReturnNode(final ReturnNode returnNode) {
return leaveDefault(returnNode);
}
@@ -615,7 +592,7 @@
* @param runtimeNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final RuntimeNode runtimeNode) {
+ public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
return enterDefault(runtimeNode);
}
@@ -625,7 +602,7 @@
* @param runtimeNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final RuntimeNode runtimeNode) {
+ public Node leaveRuntimeNode(final RuntimeNode runtimeNode) {
return leaveDefault(runtimeNode);
}
@@ -635,7 +612,7 @@
* @param splitNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final SplitNode splitNode) {
+ public Node enterSplitNode(final SplitNode splitNode) {
return enterDefault(splitNode);
}
@@ -645,7 +622,7 @@
* @param splitNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final SplitNode splitNode) {
+ public Node leaveSplitNode(final SplitNode splitNode) {
return leaveDefault(splitNode);
}
@@ -655,7 +632,7 @@
* @param switchNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final SwitchNode switchNode) {
+ public Node enterSwitchNode(final SwitchNode switchNode) {
return enterDefault(switchNode);
}
@@ -665,7 +642,7 @@
* @param switchNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final SwitchNode switchNode) {
+ public Node leaveSwitchNode(final SwitchNode switchNode) {
return leaveDefault(switchNode);
}
@@ -675,7 +652,7 @@
* @param ternaryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final TernaryNode ternaryNode) {
+ public Node enterTernaryNode(final TernaryNode ternaryNode) {
return enterDefault(ternaryNode);
}
@@ -685,7 +662,7 @@
* @param ternaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final TernaryNode ternaryNode) {
+ public Node leaveTernaryNode(final TernaryNode ternaryNode) {
return leaveDefault(ternaryNode);
}
@@ -695,7 +672,7 @@
* @param throwNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final ThrowNode throwNode) {
+ public Node enterThrowNode(final ThrowNode throwNode) {
return enterDefault(throwNode);
}
@@ -705,7 +682,7 @@
* @param throwNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final ThrowNode throwNode) {
+ public Node leaveThrowNode(final ThrowNode throwNode) {
return leaveDefault(throwNode);
}
@@ -715,7 +692,7 @@
* @param tryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final TryNode tryNode) {
+ public Node enterTryNode(final TryNode tryNode) {
return enterDefault(tryNode);
}
@@ -725,7 +702,7 @@
* @param tryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final TryNode tryNode) {
+ public Node leaveTryNode(final TryNode tryNode) {
return leaveDefault(tryNode);
}
@@ -735,7 +712,7 @@
* @param unaryNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final UnaryNode unaryNode) {
+ public Node enterUnaryNode(final UnaryNode unaryNode) {
return enterDefault(unaryNode);
}
@@ -745,7 +722,7 @@
* @param unaryNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final UnaryNode unaryNode) {
+ public Node leaveUnaryNode(final UnaryNode unaryNode) {
return leaveDefault(unaryNode);
}
@@ -755,7 +732,7 @@
* @param varNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final VarNode varNode) {
+ public Node enterVarNode(final VarNode varNode) {
return enterDefault(varNode);
}
@@ -765,7 +742,7 @@
* @param varNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final VarNode varNode) {
+ public Node leaveVarNode(final VarNode varNode) {
return leaveDefault(varNode);
}
@@ -775,7 +752,7 @@
* @param whileNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final WhileNode whileNode) {
+ public Node enterWhileNode(final WhileNode whileNode) {
return enterDefault(whileNode);
}
@@ -785,7 +762,7 @@
* @param whileNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final WhileNode whileNode) {
+ public Node leaveWhileNode(final WhileNode whileNode) {
return leaveDefault(whileNode);
}
@@ -795,7 +772,7 @@
* @param withNode the node
* @return processed node, null if traversal should end
*/
- public Node enter(final WithNode withNode) {
+ public Node enterWithNode(final WithNode withNode) {
return enterDefault(withNode);
}
@@ -805,7 +782,7 @@
* @param withNode the node
* @return processed node, which will replace the original one, or the original node
*/
- public Node leave(final WithNode withNode) {
+ public Node leaveWithNode(final WithNode withNode) {
return leaveDefault(withNode);
}
--- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java Sat Mar 23 00:58:39 2013 +0100
@@ -56,10 +56,10 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
-
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.Namespace;
import jdk.nashorn.internal.ir.AccessNode;
@@ -76,17 +76,18 @@
import jdk.nashorn.internal.ir.ExecuteNode;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LineNumberNode;
import jdk.nashorn.internal.ir.LiteralNode;
import jdk.nashorn.internal.ir.Node;
import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyKey;
import jdk.nashorn.internal.ir.PropertyNode;
-import jdk.nashorn.internal.ir.ReferenceNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.SwitchNode;
@@ -97,7 +98,6 @@
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
-import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
import jdk.nashorn.internal.runtime.DebugLogger;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSErrorType;
@@ -117,11 +117,8 @@
/** Is scripting mode. */
private final boolean scripting;
- /** Current function being parsed. */
- private FunctionNode function;
-
- /** Current parsing block. */
- private Block block;
+ private final LexicalContext lexicalContext = new LexicalContext();
+ private List<Node> functionDeclarations;
/** Namespace for function names where not explicitly given */
private final Namespace namespace;
@@ -277,7 +274,9 @@
* @return New block.
*/
private Block newBlock() {
- return block = new Block(source, token, Token.descPosition(token), block, function);
+ final Block block = new Block(source, token, Token.descPosition(token));
+ lexicalContext.push(block);
+ return block;
}
/**
@@ -290,19 +289,23 @@
// Build function name.
final StringBuilder sb = new StringBuilder();
- if (block != null) {
- block.addParentName(sb);
+ final FunctionNode parentFunction = getFunction();
+ if(parentFunction != null && !parentFunction.isProgram()) {
+ sb.append(parentFunction.getName()).append('$');
}
sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag());
final String name = namespace.uniqueName(sb.toString());
- assert function != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript().
+ assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript().
// Start new block.
- final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name);
- block = function = functionBlock;
- function.setStrictMode(isStrictMode);
- function.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+ final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name);
+ if(parentFunction == null) {
+ functionBlock.setProgram();
+ }
+ functionBlock.setStrictMode(isStrictMode);
+ functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED);
+ lexicalContext.push(functionBlock);
return functionBlock;
}
@@ -310,9 +313,8 @@
/**
* Restore the current block.
*/
- private void restoreBlock() {
- block = block.getParent();
- function = block.getFunction();
+ private void restoreBlock(Block block) {
+ lexicalContext.pop(block);
}
/**
@@ -322,19 +324,22 @@
private Block getBlock(final boolean needsBraces) {
// Set up new block. Captures LBRACE.
final Block newBlock = newBlock();
- pushControlNode(newBlock);
-
- // Block opening brace.
- if (needsBraces) {
- expect(LBRACE);
- }
-
try {
- // Accumulate block statements.
- statementList();
+ pushControlNode(newBlock);
+
+ // Block opening brace.
+ if (needsBraces) {
+ expect(LBRACE);
+ }
+
+ try {
+ // Accumulate block statements.
+ statementList();
+ } finally {
+ popControlNode();
+ }
} finally {
- restoreBlock();
- popControlNode();
+ restoreBlock(newBlock);
}
final int possibleEnd = Token.descPosition(token) + Token.descLength(token);
@@ -364,7 +369,7 @@
// Accumulate statements.
statement();
} finally {
- restoreBlock();
+ restoreBlock(newBlock);
}
return newBlock;
@@ -378,7 +383,10 @@
final String name = ident.getName();
if (EVAL.tag().equals(name)) {
- function.setHasEval();
+ final Iterator<FunctionNode> it = lexicalContext.getFunctions();
+ if(it.hasNext()) {
+ it.next().setHasEval(it);
+ }
}
}
@@ -390,7 +398,7 @@
final String name = ident.getName();
if (ARGUMENTS.tag().equals(name)) {
- function.setUsesArguments();
+ getFunction().setUsesArguments();
}
}
@@ -481,7 +489,7 @@
* @return null or the found label node.
*/
private LabelNode findLabel(final IdentNode ident) {
- for (final LabelNode labelNode : function.getLabelStack()) {
+ for (final LabelNode labelNode : getFunction().getLabelStack()) {
if (labelNode.getLabel().equals(ident)) {
return labelNode;
}
@@ -495,14 +503,14 @@
* @param labelNode Label to add.
*/
private void pushLabel(final LabelNode labelNode) {
- function.getLabelStack().push(labelNode);
+ getFunction().getLabelStack().push(labelNode);
}
/**
* Remove a label from the label stack.
*/
private void popLabel() {
- function.getLabelStack().pop();
+ getFunction().getLabelStack().pop();
}
/**
@@ -512,6 +520,7 @@
private void pushControlNode(final Node node) {
final boolean isLoop = node instanceof WhileNode;
final boolean isBreakable = node instanceof BreakableNode || node instanceof Block;
+ final FunctionNode function = getFunction();
function.getControlStack().push(node);
for (final LabelNode labelNode : function.getLabelStack()) {
@@ -530,7 +539,7 @@
*/
private void popControlNode() {
// Get control stack.
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
// Can be empty if missing brace.
if (!controlStack.isEmpty()) {
@@ -540,7 +549,7 @@
private void popControlNode(final Node node) {
// Get control stack.
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
// Can be empty if missing brace.
if (!controlStack.isEmpty() && controlStack.peek() == node) {
@@ -549,7 +558,7 @@
}
private boolean isInWithBlock() {
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -562,7 +571,7 @@
}
private <T extends Node> T findControl(final Class<T> ctype) {
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -576,7 +585,7 @@
private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) {
final List<T> nodes = new ArrayList<>();
- final Stack<Node> controlStack = function.getControlStack();
+ final Stack<Node> controlStack = getFunction().getControlStack();
for (int i = controlStack.size() - 1; i >= 0; i--) {
final Node node = controlStack.get(i);
@@ -625,7 +634,10 @@
script.setKind(FunctionNode.Kind.SCRIPT);
script.setFirstToken(functionToken);
+ functionDeclarations = new ArrayList<>();
sourceElements();
+ script.prependStatements(functionDeclarations);
+ functionDeclarations = null;
expect(EOF);
script.setLastToken(token);
script.setFinish(source.getLength() - 1);
@@ -704,7 +716,7 @@
// check for directive prologues
if (checkDirective) {
// skip any debug statement like line number to get actual first line
- final Node lastStatement = lastStatement(block.getStatements());
+ final Node lastStatement = lastStatement(getBlock().getStatements());
// get directive prologue, if any
final String directive = getDirective(lastStatement);
@@ -724,6 +736,7 @@
// handle use strict directive
if ("use strict".equals(directive)) {
isStrictMode = true;
+ final FunctionNode function = getFunction();
function.setStrictMode(true);
// We don't need to check these, if lexical environment is already strict
@@ -796,11 +809,11 @@
if (isStrictMode && !topLevel) {
error(AbstractParser.message("strict.no.func.here"), token);
}
- functionExpression(true);
+ functionExpression(true, topLevel);
return;
}
- block.addStatement(lineNumberNode);
+ getBlock().addStatement(lineNumberNode);
switch (type) {
case LBRACE:
@@ -886,7 +899,7 @@
// Force block execution.
final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
- block.addStatement(executeNode);
+ getBlock().addStatement(executeNode);
}
/**
@@ -981,13 +994,9 @@
// Allocate var node.
final VarNode var = new VarNode(source, varToken, finish, name, init);
- if (isStatement) {
- function.addDeclaration(var);
- }
-
vars.add(var);
// Add to current block.
- block.addStatement(var);
+ getBlock().addStatement(var);
if (type != COMMARIGHT) {
break;
@@ -1000,7 +1009,7 @@
boolean semicolon = type == SEMICOLON;
endOfLine();
if (semicolon) {
- block.setFinish(finish);
+ getBlock().setFinish(finish);
}
}
@@ -1017,7 +1026,7 @@
*/
private void emptyStatement() {
if (env._empty_statements) {
- block.addStatement(new EmptyNode(source, token,
+ getBlock().addStatement(new EmptyNode(source, token,
Token.descPosition(token) + Token.descLength(token)));
}
@@ -1043,7 +1052,7 @@
ExecuteNode executeNode = null;
if (expression != null) {
executeNode = new ExecuteNode(source, expressionToken, finish, expression);
- block.addStatement(executeNode);
+ getBlock().addStatement(executeNode);
} else {
expect(null);
}
@@ -1052,7 +1061,7 @@
if (executeNode != null) {
executeNode.setFinish(finish);
- block.setFinish(finish);
+ getBlock().setFinish(finish);
}
}
@@ -1094,7 +1103,7 @@
// Construct and add new if node.
final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail);
- block.addStatement(ifNode);
+ getBlock().addStatement(ifNode);
}
/**
@@ -1143,13 +1152,13 @@
outer.setFinish(body.getFinish());
// Add for to current block.
- block.addStatement(forNode);
+ getBlock().addStatement(forNode);
} finally {
- restoreBlock();
+ restoreBlock(outer);
popControlNode();
}
- block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1283,7 +1292,7 @@
whileNode.setFinish(statements.getFinish());
// Add WHILE node.
- block.addStatement(whileNode);
+ getBlock().addStatement(whileNode);
} finally {
popControlNode();
}
@@ -1330,7 +1339,7 @@
doWhileNode.setFinish(finish);
// Add DO node.
- block.addStatement(doWhileNode);
+ getBlock().addStatement(doWhileNode);
} finally {
popControlNode();
}
@@ -1382,7 +1391,7 @@
final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class));
continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
- block.addStatement(continueNode);
+ getBlock().addStatement(continueNode);
}
/**
@@ -1430,7 +1439,7 @@
final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class));
breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode));
- block.addStatement(breakNode);
+ getBlock().addStatement(breakNode);
}
/**
@@ -1443,7 +1452,7 @@
*/
private void returnStatement() {
// check for return outside function
- if (function.getKind() == FunctionNode.Kind.SCRIPT) {
+ if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) {
error(AbstractParser.message("invalid.return"));
}
@@ -1470,7 +1479,7 @@
// Construct and add RETURN node.
final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class));
- block.addStatement(returnNode);
+ getBlock().addStatement(returnNode);
}
/**
@@ -1505,7 +1514,7 @@
// Construct and add YIELD node.
final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class));
- block.addStatement(yieldNode);
+ getBlock().addStatement(yieldNode);
}
/**
@@ -1529,7 +1538,10 @@
// Get WITH expression.
final WithNode withNode = new WithNode(source, withToken, finish, null, null);
- function.setHasWith();
+ final Iterator<FunctionNode> it = lexicalContext.getFunctions();
+ if(it.hasNext()) {
+ it.next().setHasWith(it);
+ }
try {
pushControlNode(withNode);
@@ -1549,7 +1561,7 @@
popControlNode(withNode);
}
- block.addStatement(withNode);
+ getBlock().addStatement(withNode);
}
/**
@@ -1649,7 +1661,7 @@
switchNode.setFinish(finish);
- block.addStatement(switchNode);
+ getBlock().addStatement(switchNode);
} finally {
popControlNode();
}
@@ -1684,7 +1696,7 @@
labelNode.setBody(statements);
labelNode.setFinish(finish);
- block.addStatement(labelNode);
+ getBlock().addStatement(labelNode);
} finally {
// Remove label.
popLabel();
@@ -1727,7 +1739,7 @@
// Construct and add THROW node.
final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class));
- block.addStatement(throwNode);
+ getBlock().addStatement(throwNode);
}
/**
@@ -1793,18 +1805,18 @@
expect(RPAREN);
+ final Block catchBlock = newBlock();
try {
- final Block catchBlock = newBlock();
// Get CATCH body.
final Block catchBody = getBlock(true);
// Create and add catch.
final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody);
- block.addStatement(catchNode);
+ getBlock().addStatement(catchNode);
catchBlocks.add(catchBlock);
} finally {
- restoreBlock();
+ restoreBlock(catchBlock);
}
// If unconditional catch then should to be the end.
@@ -1840,11 +1852,11 @@
outer.addStatement(tryNode);
} finally {
popControlNode(tryNode);
- restoreBlock();
+ restoreBlock(outer);
popControlNode(outer);
}
- block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
+ getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer));
}
/**
@@ -1864,7 +1876,7 @@
endOfLine();
final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>());
- block.addStatement(runtimeNode);
+ getBlock().addStatement(runtimeNode);
}
/**
@@ -2244,7 +2256,7 @@
parameters = new ArrayList<>();
functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER);
propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null);
- propertyNode.setGetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+ propertyNode.setGetter(functionNode);
return propertyNode;
case "set":
@@ -2259,7 +2271,7 @@
parameters.add(argIdent);
functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER);
propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null);
- propertyNode.setSetter(new ReferenceNode(source, propertyToken, finish, functionNode));
+ propertyNode.setSetter(functionNode);
return propertyNode;
default:
@@ -2440,7 +2452,7 @@
case FUNCTION:
// Get function expression.
- lhs = functionExpression(false);
+ lhs = functionExpression(false, false);
break;
default:
@@ -2545,7 +2557,7 @@
*
* @return Expression node.
*/
- private Node functionExpression(final boolean isStatement) {
+ private Node functionExpression(final boolean isStatement, final boolean topLevel) {
final LineNumberNode lineNumber = lineNumber();
final long functionToken = token;
@@ -2580,10 +2592,12 @@
final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL);
- if (isStatement && !isInWithBlock()) {
- functionNode.setIsStatement();
+ if (isStatement) {
+ if(topLevel) {
+ functionNode.setIsDeclared();
+ }
if(ARGUMENTS.tag().equals(name.getName())) {
- functionNode.findParentFunction().setDefinesArguments();
+ getFunction().setDefinesArguments();
}
}
@@ -2591,8 +2605,6 @@
functionNode.setIsAnonymous();
}
- final ReferenceNode referenceNode = new ReferenceNode(source, functionToken, finish, functionNode);
-
final int arity = parameters.size();
final boolean strict = functionNode.isStrictMode();
@@ -2628,17 +2640,18 @@
}
if (isStatement) {
- final VarNode var = new VarNode(source, functionToken, finish, name, referenceNode);
- if (isInWithBlock()) {
- function.addDeclaration(var);
- // Add to current block.
- block.addStatement(var);
+ final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true);
+ if(topLevel) {
+ functionDeclarations.add(lineNumber);
+ functionDeclarations.add(varNode);
} else {
- functionNode.setFunctionVarNode(var, lineNumber);
+ final Block block = getBlock();
+ block.addStatement(lineNumber);
+ block.addStatement(varNode);
}
}
- return referenceNode;
+ return functionNode;
}
/**
@@ -2721,7 +2734,14 @@
expect(LBRACE);
// Gather the function elements.
- sourceElements();
+ final List<Node> prevFunctionDecls = functionDeclarations;
+ functionDeclarations = new ArrayList<>();
+ try {
+ sourceElements();
+ functionNode.prependStatements(functionDeclarations);
+ } finally {
+ functionDeclarations = prevFunctionDecls;
+ }
functionNode.setLastToken(token);
expect(RBRACE);
@@ -2729,12 +2749,9 @@
}
} finally {
- restoreBlock();
+ restoreBlock(functionNode);
}
- // Add the body of the function to the current block.
- block.addFunction(functionNode);
-
return functionNode;
}
@@ -3069,4 +3086,12 @@
public String toString() {
return "[JavaScript Parsing]";
}
+
+ private Block getBlock() {
+ return lexicalContext.getCurrentBlock();
+ }
+
+ private FunctionNode getFunction() {
+ return lexicalContext.getCurrentFunction();
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java Sat Mar 23 00:58:39 2013 +0100
@@ -27,9 +27,9 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT;
import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.io.File;
import java.io.IOException;
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Sat Mar 23 00:58:39 2013 +0100
@@ -42,6 +42,8 @@
parser.error.expected.comma=Expected comma but found {0}
parser.error.expected=Expected {0} but found {1}
parser.error.invalid.return=Invalid return statement
+parser.error.no.func.decl.here=Function declarations can only occur at program or function body level. You should use a function expression here instead.
+parser.error.no.func.decl.here.warn=Function declarations should only occur at program or function body level. Function declaration in nested block was converted to a function expression.
parser.error.property.redefinition=Property "{0}" already defined
parser.error.unexpected.token=Unexpected token: {0}
parser.error.many.vars.in.for.in.loop=Only one variable allowed in for..in loop
@@ -57,7 +59,7 @@
parser.error.strict.cant.delete.ident=cannot delete identifier "{0}" in strict mode
parser.error.strict.param.redefinition=strict mode function cannot have duplicate parameter name "{0}"
parser.error.strict.no.octal=cannot use octal value in strict mode
-parser.error.strict.no.func.here=In strict mode, functions can only be declared at top-level or immediately within a function
+parser.error.strict.no.func.decl.here=In strict mode, function declarations can only occur at program or function body level. You should use a function expression here instead.
type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "arguments" properties can not be accessed on functions or the arguments object
# not the expected type in a given context
--- a/nashorn/test/script/basic/JDK-8006755.js Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/test/script/basic/JDK-8006755.js Sat Mar 23 00:58:39 2013 +0100
@@ -31,7 +31,7 @@
var scope = { x: "hello" };
with (scope) {
- function main() {
+ var main = function() {
if (x != "hello") {
fail("x != 'hello'");
}
--- a/nashorn/test/script/basic/NASHORN-837.js Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/test/script/basic/NASHORN-837.js Sat Mar 23 00:58:39 2013 +0100
@@ -28,23 +28,13 @@
* @run
*/
-var failed = false;
-
try {
- try {
- throw new TypeError('error');
- } catch (iox) {
- function f() {
- print(iox.message);
- }
+ throw new TypeError('error');
+} catch (iox) {
+ var f = function() {
+ if(iox.message != 'error') {
+ print("Failure! iox did not throw correct exception");
+ }
}
- f();
-} catch (e) {
- failed = (e instanceof ReferenceError);
- //iox not defined should be thrown
}
-
-if (!failed) {
- print("Failure! iox did not throw correct exception");
-}
-
+f();
--- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Tue Mar 19 11:03:24 2013 -0300
+++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Sat Mar 23 00:58:39 2013 +0100
@@ -44,6 +44,7 @@
private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("compilertest.verbose"));
private static final boolean TEST262 = Boolean.valueOf(System.getProperty("compilertest.test262"));
private static final String TEST_BASIC_DIR = System.getProperty("test.basic.dir");
+ private static final String TEST_NODE_DIR = System.getProperty("test.node.dir");
private static final String TEST262_SUITE_DIR = System.getProperty("test262.suite.dir");
interface TestFilter {
@@ -81,21 +82,22 @@
@Test
public void compileAllTests() {
if (TEST262) {
- compileTestSet(TEST262_SUITE_DIR, new TestFilter() {
+ compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() {
@Override
public boolean exclude(final File file, final String content) {
return content.indexOf("@negative") != -1;
}
});
}
- compileTestSet(TEST_BASIC_DIR, null);
+ compileTestSet(new File(TEST_BASIC_DIR), null);
+ compileTestSet(new File(TEST_NODE_DIR, "node"), null);
+ compileTestSet(new File(TEST_NODE_DIR, "src"), null);
}
- private void compileTestSet(final String testSet, final TestFilter filter) {
+ private void compileTestSet(final File testSetDir, final TestFilter filter) {
passed = 0;
failed = 0;
skipped = 0;
- final File testSetDir = new File(testSet);
if (! testSetDir.isDirectory()) {
log("WARNING: " + testSetDir + " not found or not a directory");
return;
@@ -103,7 +105,7 @@
log(testSetDir.getAbsolutePath());
compileJSDirectory(testSetDir, filter);
- log(testSet + " compile done!");
+ log(testSetDir + " compile done!");
log("compile ok: " + passed);
log("compile failed: " + failed);
log("compile skipped: " + skipped);