8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable

Reviewed-by: jlaskey, lagergren
This commit is contained in:
Attila Szegedi 2013-03-23 00:58:39 +01:00
parent e4b8273cc6
commit 7188961426
63 changed files with 1671 additions and 1721 deletions

View File

@ -210,7 +210,7 @@ run.test.xms=2G
# 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

View File

@ -37,14 +37,16 @@ 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_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.BinaryNode;
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 @@ final class Attr extends NodeOperatorVisitor {
*/
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
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 class Attr extends NodeOperatorVisitor {
*/
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
public Node leave(final TryNode tryNode) {
public Node leaveTryNode(final TryNode tryNode) {
tryNode.setException(exceptionSymbol());
if (tryNode.getFinallyBody() != null) {
@ -580,13 +696,13 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
@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 @@ final class Attr extends NodeOperatorVisitor {
@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 @@ final class Attr extends NodeOperatorVisitor {
@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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
}
@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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
}
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
* 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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@Override
public Node enter(final FunctionNode node) {
public Node enterFunctionNode(final FunctionNode node) {
return node.isLazy() ? null : node;
}
@ -1419,7 +1534,7 @@ final class Attr extends NodeOperatorVisitor {
*/
@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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
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 @@ final class Attr extends NodeOperatorVisitor {
}
@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;

View File

@ -194,6 +194,14 @@ public class ClassEmitter implements Emitter {
defineCommonStatics(strictMode);
}
/**
* 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.
*
@ -244,7 +252,7 @@ public class ClassEmitter implements Emitter {
// $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 @@ public class ClassEmitter implements Emitter {
// $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();

View File

@ -76,18 +76,18 @@ import jdk.nashorn.internal.ir.EmptyNode;
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.ir.visitor.NodeVisitor;
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
/** 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 class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
}
/**
* 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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final IndexNode indexNode) {
public Node enterIndexNode(final IndexNode indexNode) {
if (!baseAlreadyOnStack) {
load(indexNode.getBase()).convert(Type.OBJECT);
load(indexNode.getIndex());
@ -338,6 +355,14 @@ final class CodeGenerator extends NodeOperatorVisitor {
return null;
}
@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.
@ -350,7 +375,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final AccessNode accessNode) {
public Node enterAccessNode(final AccessNode accessNode) {
if (accessNode.testResolved()) {
return null;
}
@ -422,10 +447,11 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final BreakNode breakNode) {
public Node enterBreakNode(final BreakNode breakNode) {
if (breakNode.testResolved()) {
return null;
}
@ -515,14 +541,13 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final ContinueNode continueNode) {
public Node enterContinueNode(final ContinueNode continueNode) {
if (continueNode.testResolved()) {
return null;
}
@ -709,17 +734,17 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final ForNode forNode) {
public Node enterForNode(final ForNode forNode) {
if (forNode.testResolved()) {
return null;
}
@ -813,7 +838,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* @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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final IndexNode indexNode) {
public Node enterIndexNode(final IndexNode indexNode) {
if (indexNode.testResolved()) {
return null;
}
@ -1060,7 +1097,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final LineNumberNode lineNumberNode) {
public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (lineNumberNode.testResolved()) {
return null;
}
@ -1068,7 +1105,6 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final RuntimeNode runtimeNode) {
public Node enterRuntimeNode(final RuntimeNode runtimeNode) {
if (runtimeNode.testResolved()) {
return null;
}
@ -1637,7 +1662,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final SplitNode splitNode) {
public Node enterSplitNode(final SplitNode splitNode) {
if (splitNode.testResolved()) {
return null;
}
@ -1706,7 +1731,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node leave(final SplitNode splitNode) {
public Node leaveSplitNode(final SplitNode splitNode) {
try {
// Wrap up this method.
method.loadResult();
@ -1763,7 +1788,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final SwitchNode switchNode) {
public Node enterSwitchNode(final SwitchNode switchNode) {
if (switchNode.testResolved()) {
return null;
}
@ -1895,7 +1920,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final ThrowNode throwNode) {
public Node enterThrowNode(final ThrowNode throwNode) {
if (throwNode.testResolved()) {
return null;
}
@ -1922,7 +1947,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final TryNode tryNode) {
public Node enterTryNode(final TryNode tryNode) {
if (tryNode.testResolved()) {
return null;
}
@ -1955,7 +1980,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
// Generate catch body (inlined finally) and rethrow exception
catchBody.accept(this);
method.load(symbol).athrow();
lexicalContext.pop(catchBlock);
continue;
}
@ -2012,7 +2038,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
}
leave(catchBlock);
leaveBlock(catchBlock);
} finally {
setCurrentBlock(saveBlock);
}
@ -2027,7 +2053,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final WhileNode whileNode) {
public Node enterWhileNode(final WhileNode whileNode) {
if (whileNode.testResolved()) {
return null;
}
@ -2098,7 +2124,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@Override
public Node enter(final WithNode withNode) {
public Node enterWithNode(final WithNode withNode) {
if (withNode.testResolved()) {
return null;
}
@ -2864,7 +2890,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
* Ternary visits.
*/
@Override
public Node enter(final TernaryNode ternaryNode) {
public Node enterTernaryNode(final TernaryNode ternaryNode) {
if (ternaryNode.testResolved()) {
return null;
}
@ -3060,7 +3086,7 @@ final class CodeGenerator extends NodeOperatorVisitor {
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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 @@ final class CodeGenerator extends NodeOperatorVisitor {
}
@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;
}

View File

@ -14,16 +14,16 @@ import java.io.IOException;
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 @@ enum CompilationPhase {
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 @@ enum CompilationPhase {
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 @@ enum CompilationPhase {
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) {

View File

@ -46,7 +46,6 @@ import java.util.Map;
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 @@ public final class Compiler {
functionNode.accept(new NodeVisitor() {
@Override
public Node enter(final FunctionNode node) {
public Node enterFunctionNode(final FunctionNode node) {
if (node.isLazy()) {
return null;
}

View File

@ -34,20 +34,20 @@ import jdk.nashorn.internal.ir.BinaryNode;
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
// 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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@Override
public Node leaveDECINC(final UnaryNode unaryNode) {
specialize(unaryNode);
return unaryNode;
return specialize(unaryNode).node;
}
@Override
@ -159,9 +159,7 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* 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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@Override
public Node enter(final IdentNode identNode) {
public Node enterIdentNode(final IdentNode identNode) {
if (!exclude.contains(identNode)) {
setCanBePrimitive(identNode.getSymbol());
}
@ -687,26 +696,36 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
@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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
* @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 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
}
LOG.info("Type override for lhs in '" + node + "' => " + to);
((TypeOverride)node).setType(to);
return ((TypeOverride<T>)node).setType(to);
}
/**
@ -816,8 +836,8 @@ final class FinalizeTypes extends NodeOperatorVisitor {
}
} 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);
}

View File

@ -31,12 +31,12 @@ import jdk.nashorn.internal.ir.Block;
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 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@Override
public Node enter(final FunctionNode functionNode) {
public Node enterFunctionNode(final FunctionNode functionNode) {
if (functionNode.isLazy()) {
return null;
}
@ -82,13 +82,13 @@ final class FoldConstants extends NodeVisitor {
}
@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 @@ final class FoldConstants extends NodeVisitor {
}
@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();

View File

@ -155,7 +155,7 @@ public final class FunctionSignature {
true,
functionNode.needsCallee(),
functionNode.getReturnType(),
(functionNode.isVarArg() && !functionNode.isScript()) ?
(functionNode.isVarArg() && !functionNode.isProgram()) ?
null :
functionNode.getParameters());
}

View File

@ -37,8 +37,8 @@ import java.util.ArrayDeque;
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.EmptyNode;
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.UnaryNode;
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 @@ final class Lower extends NodeOperatorVisitor {
private List<Node> statements;
private LexicalContext lexicalContext = new LexicalContext();
/**
* Constructor.
*
@ -114,14 +116,15 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
*/
if (lastStatement != null && lastStatement.isTerminal()) {
copyTerminal(block, lastStatement);
break;
visitor = new DeadCodeVarDeclarationVisitor();
}
}
block.setStatements(statements);
@ -141,18 +144,19 @@ final class Lower extends NodeOperatorVisitor {
} 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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
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();
}
}
if (functionNode.isScript()) {
new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this);
}
//do the statements - this fills the block with code
boolean needsInitialEvalResult = functionNode.isProgram();
for (final Node statement : functionNode.getStatements()) {
statement.accept(this);
// 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;
}
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 @@ final class Lower extends NodeOperatorVisitor {
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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
// 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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@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 @@ final class Lower extends NodeOperatorVisitor {
}
@Override
public Node leave(final WithNode withNode) {
public Node leaveWithNode(final WithNode withNode) {
if (withNode.getBody().isTerminal()) {
setTerminal(withNode, true);
}
@ -682,28 +705,10 @@ final class Lower extends NodeOperatorVisitor {
*/
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 @@ final class Lower extends NodeOperatorVisitor {
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 @@ final class Lower extends NodeOperatorVisitor {
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 @@ final class Lower extends NodeOperatorVisitor {
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 @@ final class Lower extends NodeOperatorVisitor {
* @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 @@ final class Lower extends NodeOperatorVisitor {
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 @@ final class Lower extends NodeOperatorVisitor {
}
}

View File

@ -651,11 +651,10 @@ public class MethodEmitter implements Emitter {
/**
* 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;
}

View File

@ -41,6 +41,7 @@ import jdk.nashorn.internal.ir.ForNode;
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.ReturnNode;
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 @@ final class Splitter extends NodeVisitor {
/** 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 @@ final class Splitter extends NodeVisitor {
}
if (weight >= SPLIT_THRESHOLD) {
weight = splitBlock(functionNode);
weight = splitBlock(functionNode, functionNode);
}
if (functionNode.isSplit()) {
@ -132,9 +136,20 @@ final class Splitter extends NodeVisitor {
}
// 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 @@ final class Splitter extends NodeVisitor {
*
* @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 @@ final class Splitter extends NodeVisitor {
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 @@ final class Splitter extends NodeVisitor {
}
if (!statements.isEmpty()) {
splits.add(createBlockSplitNode(block, statements, statementsWeight));
splits.add(createBlockSplitNode(block, function, statements, statementsWeight));
}
block.setStatements(splits);
@ -199,13 +214,13 @@ final class Splitter extends NodeVisitor {
*
* @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 @@ final class Splitter extends NodeVisitor {
}
@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 @@ final class Splitter extends NodeVisitor {
}
@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 @@ final class Splitter extends NodeVisitor {
}
@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 @@ final class Splitter extends NodeVisitor {
}
@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 @@ final class Splitter extends NodeVisitor {
}
@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;

View File

@ -47,7 +47,6 @@ 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.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 @@ final class WeighNodes extends NodeOperatorVisitor {
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 @@ final class WeighNodes extends NodeOperatorVisitor {
/** 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 @@ final class WeighNodes extends NodeOperatorVisitor {
}
@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 @@ final class WeighNodes extends NodeOperatorVisitor {
}
@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;
}

View File

@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.Source;
* 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 @@ public class AccessNode extends BaseNode implements TypeOverride {
super(source, token, finish, base);
this.start = base.getStart();
this.property = property;
this.property.setIsPropertyName();
this.property = property.setIsPropertyName();
}
/**
@ -106,10 +104,10 @@ public class AccessNode extends BaseNode implements TypeOverride {
*/
@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 @@ public class AccessNode extends BaseNode implements TypeOverride {
}
@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

View File

@ -46,4 +46,11 @@ public interface Assignment<D extends Node> {
* @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);
}

View File

@ -38,6 +38,8 @@ public abstract class BaseNode extends Node implements FunctionCall {
/** Base Node. */
protected Node base;
private boolean function;
/**
* Constructor
*
@ -96,6 +98,15 @@ public abstract class BaseNode extends Node implements FunctionCall {
@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;
}
}

View File

@ -35,7 +35,7 @@ import jdk.nashorn.internal.runtime.Source;
*/
public class BinaryNode extends UnaryNode {
/** Left hand side argument. */
protected Node lhs;
private Node lhs;
/**
* Constructor
@ -139,6 +139,11 @@ public class BinaryNode extends UnaryNode {
return isAssignment() ? lhs() : null;
}
@Override
public Node setAssignmentDest(Node n) {
return setLHS(n);
}
@Override
public Node getAssignmentSource() {
return rhs();
@ -163,10 +168,9 @@ public class BinaryNode extends UnaryNode {
*/
@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 @@ public class BinaryNode extends UnaryNode {
/**
* 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;
}
}

View File

@ -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.Comparator;
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 @@ import jdk.nashorn.internal.runtime.Source;
* 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 @@ public class Block extends Node {
* @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 @@ public class Block extends Node {
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 @@ public class Block extends Node {
@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 @@ public class Block extends Node {
}
/**
* 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);
}
/**
@ -210,39 +135,6 @@ public class Block extends Node {
statements.addAll(statementList);
}
/**
* 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.
*
@ -257,13 +149,9 @@ public class Block extends Node {
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 @@ public class Block extends Node {
}
/**
* 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 @@ public class Block extends Node {
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) {
@ -511,16 +245,6 @@ public class Block extends Node {
return frame;
}
/**
* 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
*
@ -530,24 +254,6 @@ public class Block extends Node {
this.frame = frame;
}
/**
* 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
*
@ -557,6 +263,15 @@ public class Block extends Node {
return Collections.unmodifiableList(statements);
}
/**
* 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
*
@ -592,4 +307,29 @@ public class Block extends Node {
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);
}
}
}

View File

@ -64,8 +64,8 @@ public class BreakNode extends LabeledNode {
*/
@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;

View File

@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.Source;
* 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 @@ public class CallNode extends Node implements TypeOverride {
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 @@ public class CallNode extends Node implements TypeOverride {
*/
@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;

View File

@ -79,7 +79,7 @@ public class CaseNode extends BreakableNode {
*/
@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 @@ public class CaseNode extends BreakableNode {
body = (Block)body.accept(visitor);
}
return visitor.leave(this);
return visitor.leaveCaseNode(this);
}
return this;

View File

@ -84,7 +84,7 @@ public class CatchNode extends Node {
*/
@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 @@ public class CatchNode extends Node {
}
body = (Block)body.accept(visitor);
return visitor.leave(this);
return visitor.leaveCatchNode(this);
}
return this;

View File

@ -61,8 +61,8 @@ public class ContinueNode extends LabeledNode {
@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;

View File

@ -63,11 +63,11 @@ public class DoWhileNode extends WhileNode {
@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;

View File

@ -57,8 +57,8 @@ public class EmptyNode extends Node {
@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;
}

View File

@ -85,9 +85,9 @@ public class ExecuteNode extends Node {
@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;

View File

@ -76,7 +76,7 @@ public class ForNode extends WhileNode {
@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 @@ public class ForNode extends WhileNode {
body = (Block)body.accept(visitor);
return visitor.leave(this);
return visitor.leaveForNode(this);
}
return this;

View File

@ -34,7 +34,7 @@ import java.util.ArrayList;
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.codegen.types.Type;
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 @@ import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
*/
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 @@ public class FunctionNode extends Block {
/** 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 @@ public class FunctionNode extends Block {
/** 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 @@ public class FunctionNode extends Block {
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;
@ -225,14 +222,6 @@ public class FunctionNode extends Block {
/** What is the return type of this function? */
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
*
@ -240,42 +229,28 @@ public class FunctionNode extends Block {
* @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 @@ public class FunctionNode extends Block {
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 @@ public class FunctionNode extends Block {
@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 @@ public class FunctionNode extends Block {
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 @@ public class FunctionNode extends Block {
}
/**
* 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 @@ public class FunctionNode extends Block {
/**
* 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 @@ public class FunctionNode extends Block {
/**
* 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 @@ public class FunctionNode extends Block {
}
/**
* 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 class FunctionNode extends Block {
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 @@ public class FunctionNode extends Block {
* @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 @@ public class FunctionNode extends Block {
* @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 @@ public class FunctionNode extends Block {
}
/**
* 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 @@ public class FunctionNode extends Block {
}
/**
* 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 @@ public class FunctionNode extends Block {
@Override
public Type getType() {
return getReturnType();
return FUNCTION_TYPE;
}
/**
@ -1211,56 +1161,6 @@ public class FunctionNode extends Block {
return (flags & IS_LOWERED) != 0;
}
/**
* 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
@ -1294,32 +1194,4 @@ public class FunctionNode extends Block {
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);
}
}

View File

@ -38,18 +38,18 @@ import jdk.nashorn.internal.runtime.Source;
/**
* 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 class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
*/
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 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
}
@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 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
*/
@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 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
* @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 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
* @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 @@ public class IdentNode extends Node implements PropertyKey, TypeOverride, Functi
@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;
}
}

View File

@ -75,7 +75,7 @@ public class IfNode extends Node {
@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 @@ public class IfNode extends Node {
fail = (Block)fail.accept(visitor);
}
return visitor.leave(this);
return visitor.leaveIfNode(this);
}
return this;

View File

@ -36,7 +36,7 @@ import jdk.nashorn.internal.runtime.Source;
* 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 @@ public class IndexNode extends BaseNode implements TypeOverride {
@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 @@ public class IndexNode extends BaseNode implements TypeOverride {
}
@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

View File

@ -81,10 +81,10 @@ public class LabelNode extends Node {
@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;

View File

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

View File

@ -63,8 +63,8 @@ public class LineNumberNode extends Node {
@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;

View File

@ -46,7 +46,7 @@ import jdk.nashorn.internal.runtime.Undefined;
*/
public abstract class LiteralNode<T> extends Node implements PropertyKey {
/** Literal value */
protected T value;
protected final T value;
/**
* Constructor
@ -67,8 +67,17 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
* @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 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
*/
@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 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
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 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@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 @@ public abstract class LiteralNode<T> extends Node implements PropertyKey {
@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;
}

View File

@ -65,7 +65,11 @@ public class Location implements Cloneable {
@Override
protected Object clone() {
return new Location(this);
try {
return super.clone();
} catch(CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
@Override

View File

@ -165,11 +165,18 @@ public abstract class Node extends Location {
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?
*
@ -234,8 +241,7 @@ public abstract class Node extends Location {
*
* @return Deep copy of the Node.
*/
@Override
public final Node clone() {
public final Node copy() {
return copy(new CopyState());
}
@ -349,10 +355,10 @@ public abstract class Node extends Location {
}
/**
* 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;
}
/**

View File

@ -72,12 +72,12 @@ public class ObjectNode extends Node {
@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;

View File

@ -88,7 +88,7 @@ public class PropertyNode extends Node {
@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 @@ public class PropertyNode extends Node {
setter = setter.accept(visitor);
}
return visitor.leave(this);
return visitor.leavePropertyNode(this);
}
return this;

View File

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

View File

@ -100,12 +100,12 @@ public class ReturnNode extends Node {
@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;

View File

@ -38,7 +38,7 @@ import jdk.nashorn.internal.runtime.Source;
* 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 @@ public class RuntimeNode extends Node implements TypeOverride {
}
@Override
public void setType(final Type type) {
public RuntimeNode setType(final Type type) {
this.callSiteType = type;
return this;
}
@Override
@ -408,12 +409,12 @@ public class RuntimeNode extends Node implements TypeOverride {
@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;

View File

@ -108,10 +108,10 @@ public class SplitNode extends Node {
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);

View File

@ -85,7 +85,7 @@ public class SwitchNode extends BreakableNode {
@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 @@ public class SwitchNode extends BreakableNode {
//the default case is in the cases list and should not be explicitly traversed!
return visitor.leave(this);
return visitor.leaveSwitchNode(this);
}
return this;

View File

@ -38,31 +38,31 @@ import jdk.nashorn.internal.runtime.options.Options;
*/
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 @@ public final class Symbol implements Comparable<Symbol> {
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)) {
@ -486,27 +477,6 @@ public final class Symbol implements Comparable<Symbol> {
flags |= IS_LET;
}
/**
* 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 @@ public final class Symbol implements Comparable<Symbol> {
* @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();
}

View File

@ -77,11 +77,11 @@ public class TernaryNode extends BinaryNode {
@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 @@ public class TernaryNode extends BinaryNode {
/**
* 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;
}
}

View File

@ -75,9 +75,9 @@ public class ThrowNode extends Node {
*/
@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;

View File

@ -101,7 +101,7 @@ public class TryNode extends Node {
*/
@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 @@ public class TryNode extends Node {
}
this.catchBlocks = newCatchBlocks;
return visitor.leave(this);
return visitor.leaveTryNode(this);
}
return this;
@ -154,6 +154,15 @@ public class TryNode extends Node {
return catches;
}
/**
* 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

View File

@ -36,15 +36,17 @@ import jdk.nashorn.internal.codegen.types.Type;
* 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

View File

@ -41,7 +41,7 @@ import jdk.nashorn.internal.runtime.Source;
*/
public class UnaryNode extends Node implements Assignment<Node> {
/** Right hand side argument. */
protected Node rhs;
private Node rhs;
/**
* Constructor
@ -103,6 +103,11 @@ public class UnaryNode extends Node implements Assignment<Node> {
return isAssignment() ? rhs() : null;
}
@Override
public Node setAssignmentDest(Node n) {
return setRHS(n);
}
@Override
public Node getAssignmentSource() {
return getAssignmentDest();
@ -132,9 +137,8 @@ public class UnaryNode extends Node implements Assignment<Node> {
*/
@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 @@ public class UnaryNode extends Node implements Assignment<Node> {
* @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;
}
}

View File

@ -38,8 +38,8 @@ public class VarNode extends Node implements Assignment<IdentNode> {
/** 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 @@ public class VarNode extends Node implements Assignment<IdentNode> {
* @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
@ -82,6 +96,11 @@ public class VarNode extends Node implements Assignment<IdentNode> {
return isAssignment() ? name : null;
}
@Override
public Node setAssignmentDest(IdentNode n) {
return setName(n);
}
@Override
public Node getAssignmentSource() {
return isAssignment() ? getInit() : null;
@ -127,16 +146,19 @@ public class VarNode extends Node implements Assignment<IdentNode> {
*/
@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 @@ public class VarNode extends Node implements Assignment<IdentNode> {
/**
* 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 @@ public class VarNode extends Node implements Assignment<IdentNode> {
* 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();
}
}

View File

@ -88,11 +88,11 @@ public class WhileNode extends BreakableNode {
*/
@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;
}

View File

@ -73,10 +73,10 @@ public class WithNode extends Node {
*/
@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;

View File

@ -112,7 +112,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final AccessNode accessNode) {
public Node enterAccessNode(final AccessNode accessNode) {
enterDefault(accessNode);
type("MemberExpression");
@ -132,7 +132,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final Block block) {
public Node enterBlock(final Block block) {
enterDefault(block);
type("BlockStatement");
@ -154,7 +154,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final BinaryNode binaryNode) {
public Node enterBinaryNode(final BinaryNode binaryNode) {
enterDefault(binaryNode);
final String name;
@ -183,7 +183,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final BreakNode breakNode) {
public Node enterBreakNode(final BreakNode breakNode) {
enterDefault(breakNode);
type("BreakStatement");
@ -201,7 +201,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final CallNode callNode) {
public Node enterCallNode(final CallNode callNode) {
enterDefault(callNode);
type("CallExpression");
@ -217,7 +217,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final CaseNode caseNode) {
public Node enterCaseNode(final CaseNode caseNode) {
enterDefault(caseNode);
type("SwitchCase");
@ -238,7 +238,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final CatchNode catchNode) {
public Node enterCatchNode(final CatchNode catchNode) {
enterDefault(catchNode);
type("CatchClause");
@ -264,7 +264,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final ContinueNode continueNode) {
public Node enterContinueNode(final ContinueNode continueNode) {
enterDefault(continueNode);
type("ContinueStatement");
@ -282,7 +282,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final DoWhileNode doWhileNode) {
public Node enterDoWhileNode(final DoWhileNode doWhileNode) {
enterDefault(doWhileNode);
type("DoWhileStatement");
@ -299,7 +299,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final EmptyNode emptyNode) {
public Node enterEmptyNode(final EmptyNode emptyNode) {
enterDefault(emptyNode);
type("EmptyStatement");
@ -308,7 +308,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final ExecuteNode executeNode) {
public Node enterExecuteNode(final ExecuteNode executeNode) {
enterDefault(executeNode);
type("ExpressionStatement");
@ -321,7 +321,7 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
// 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 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final IdentNode identNode) {
public Node enterIdentNode(final IdentNode identNode) {
enterDefault(identNode);
final String name = identNode.getName();
@ -464,7 +455,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final IfNode ifNode) {
public Node enterIfNode(final IfNode ifNode) {
enterDefault(ifNode);
type("IfStatement");
@ -490,7 +481,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final IndexNode indexNode) {
public Node enterIndexNode(final IndexNode indexNode) {
enterDefault(indexNode);
type("MemberExpression");
@ -510,7 +501,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final LabelNode labelNode) {
public Node enterLabelNode(final LabelNode labelNode) {
enterDefault(labelNode);
type("LabeledStatement");
@ -527,13 +518,13 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final ObjectNode objectNode) {
public Node enterObjectNode(final ObjectNode objectNode) {
enterDefault(objectNode);
type("ObjectExpression");
@ -581,7 +572,7 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final ReturnNode returnNode) {
public Node enterReturnNode(final ReturnNode returnNode) {
enterDefault(returnNode);
type("ReturnStatement");
@ -665,7 +656,7 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
@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 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final TernaryNode ternaryNode) {
public Node enterTernaryNode(final TernaryNode ternaryNode) {
enterDefault(ternaryNode);
type("ConditionalExpression");
@ -722,7 +713,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final ThrowNode throwNode) {
public Node enterThrowNode(final ThrowNode throwNode) {
enterDefault(throwNode);
type("ThrowStatement");
@ -735,7 +726,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final TryNode tryNode) {
public Node enterTryNode(final TryNode tryNode) {
enterDefault(tryNode);
type("TryStatement");
@ -760,7 +751,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final UnaryNode unaryNode) {
public Node enterUnaryNode(final UnaryNode unaryNode) {
enterDefault(unaryNode);
final TokenType tokenType = unaryNode.tokenType();
@ -816,7 +807,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final VarNode varNode) {
public Node enterVarNode(final VarNode varNode) {
enterDefault(varNode);
type("VariableDeclaration");
@ -852,7 +843,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final WhileNode whileNode) {
public Node enterWhileNode(final WhileNode whileNode) {
enterDefault(whileNode);
type("WhileStatement");
@ -869,7 +860,7 @@ public final class JSONWriter extends NodeVisitor {
}
@Override
public Node enter(final WithNode withNode) {
public Node enterWithNode(final WithNode withNode) {
enterDefault(withNode);
type("WithStatement");

View File

@ -42,7 +42,6 @@ import jdk.nashorn.internal.ir.IndexNode;
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 @@ public final class PrintVisitor extends NodeVisitor {
* 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 @@ public final class PrintVisitor extends NodeVisitor {
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 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
public Node enter(final ForNode forNode) {
public Node enterForNode(final ForNode forNode) {
forNode.toString(sb);
forNode.getBody().accept(this);
@ -273,15 +257,15 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
public Node enter(final LineNumberNode lineNumberNode) {
public Node enterLineNumberNode(final LineNumberNode lineNumberNode) {
if (printLineNumbers) {
lineNumberNode.toString(sb);
}
@ -323,25 +307,19 @@ public final class PrintVisitor extends NodeVisitor {
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
public Node enter(final SwitchNode switchNode) {
public Node enterSwitchNode(final SwitchNode switchNode) {
switchNode.toString(sb);
sb.append(" {");
@ -383,13 +361,13 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@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 @@ public final class PrintVisitor extends NodeVisitor {
}
@Override
public Node enter(final WithNode withNode) {
public Node enterWithNode(final WithNode withNode) {
withNode.toString(sb);
withNode.getBody().accept(this);

View File

@ -53,7 +53,7 @@ public class NodeOperatorVisitor extends NodeVisitor {
}
@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 @@ public class NodeOperatorVisitor extends NodeVisitor {
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 @@ public class NodeOperatorVisitor extends NodeVisitor {
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 @@ public class NodeOperatorVisitor extends NodeVisitor {
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 @@ public class NodeOperatorVisitor extends NodeVisitor {
case SUB:
return leaveSUB(binaryNode);
default:
return super.leave(binaryNode);
return super.leaveBinaryNode(binaryNode);
}
}

View File

@ -49,7 +49,6 @@ import jdk.nashorn.internal.ir.LiteralNode;
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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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 @@ public abstract class NodeVisitor {
* @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);
}

View File

@ -56,10 +56,10 @@ import static jdk.nashorn.internal.parser.TokenType.WHILE;
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.EmptyNode;
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.UnaryNode;
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 @@ public class Parser extends AbstractParser {
/** 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 @@ loop:
* @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 @@ loop:
// 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 @@ loop:
/**
* 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 @@ loop:
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 @@ loop:
// Accumulate statements.
statement();
} finally {
restoreBlock();
restoreBlock(newBlock);
}
return newBlock;
@ -378,7 +383,10 @@ loop:
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 @@ loop:
final String name = ident.getName();
if (ARGUMENTS.tag().equals(name)) {
function.setUsesArguments();
getFunction().setUsesArguments();
}
}
@ -481,7 +489,7 @@ loop:
* @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 @@ loop:
* @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 @@ loop:
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 @@ loop:
*/
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 @@ loop:
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 @@ loop:
}
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 @@ loop:
}
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 @@ loop:
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 @@ loop:
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 @@ loop:
// 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 @@ loop:
// 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 @@ loop:
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 @@ loop:
// Force block execution.
final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock);
block.addStatement(executeNode);
getBlock().addStatement(executeNode);
}
/**
@ -981,13 +994,9 @@ loop:
// 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 @@ loop:
boolean semicolon = type == SEMICOLON;
endOfLine();
if (semicolon) {
block.setFinish(finish);
getBlock().setFinish(finish);
}
}
@ -1017,7 +1026,7 @@ loop:
*/
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 @@ loop:
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 @@ loop:
if (executeNode != null) {
executeNode.setFinish(finish);
block.setFinish(finish);
getBlock().setFinish(finish);
}
}
@ -1094,7 +1103,7 @@ loop:
// 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 @@ loop:
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 @@ loop:
whileNode.setFinish(statements.getFinish());
// Add WHILE node.
block.addStatement(whileNode);
getBlock().addStatement(whileNode);
} finally {
popControlNode();
}
@ -1330,7 +1339,7 @@ loop:
doWhileNode.setFinish(finish);
// Add DO node.
block.addStatement(doWhileNode);
getBlock().addStatement(doWhileNode);
} finally {
popControlNode();
}
@ -1382,7 +1391,7 @@ loop:
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 @@ loop:
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 @@ loop:
*/
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 @@ loop:
// 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 @@ loop:
// 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 @@ loop:
// 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 @@ loop:
popControlNode(withNode);
}
block.addStatement(withNode);
getBlock().addStatement(withNode);
}
/**
@ -1649,7 +1661,7 @@ loop:
switchNode.setFinish(finish);
block.addStatement(switchNode);
getBlock().addStatement(switchNode);
} finally {
popControlNode();
}
@ -1684,7 +1696,7 @@ loop:
labelNode.setBody(statements);
labelNode.setFinish(finish);
block.addStatement(labelNode);
getBlock().addStatement(labelNode);
} finally {
// Remove label.
popLabel();
@ -1727,7 +1739,7 @@ loop:
// 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 @@ loop:
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 @@ loop:
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 @@ loop:
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 @@ loop:
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 @@ loop:
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 @@ loop:
case FUNCTION:
// Get function expression.
lhs = functionExpression(false);
lhs = functionExpression(false, false);
break;
default:
@ -2545,7 +2557,7 @@ loop:
*
* @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 @@ loop:
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 @@ loop:
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 @@ loop:
}
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 @@ loop:
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 @@ loop:
}
} finally {
restoreBlock();
restoreBlock(functionNode);
}
// Add the body of the function to the current block.
block.addFunction(functionNode);
return functionNode;
}
@ -3069,4 +3086,12 @@ loop:
public String toString() {
return "[JavaScript Parsing]";
}
private Block getBlock() {
return lexicalContext.getCurrentBlock();
}
private FunctionNode getFunction() {
return lexicalContext.getCurrentFunction();
}
}

View File

@ -27,9 +27,9 @@ package jdk.nashorn.internal.runtime;
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;

View File

@ -42,6 +42,8 @@ parser.error.expected.stmt=Expected statement but found {0}
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.name="{0}" cannot be used as {1} in strict mode
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

View File

@ -31,7 +31,7 @@
var scope = { x: "hello" };
with (scope) {
function main() {
var main = function() {
if (x != "hello") {
fail("x != 'hello'");
}

View File

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

View File

@ -44,6 +44,7 @@ public class CompilerTest {
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 @@ public class CompilerTest {
@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 @@ public class CompilerTest {
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);