mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-20 07:58:55 +00:00
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
This commit is contained in:
parent
e4b8273cc6
commit
7188961426
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -155,7 +155,7 @@ public final class FunctionSignature {
|
||||
true,
|
||||
functionNode.needsCallee(),
|
||||
functionNode.getReturnType(),
|
||||
(functionNode.isVarArg() && !functionNode.isScript()) ?
|
||||
(functionNode.isVarArg() && !functionNode.isProgram()) ?
|
||||
null :
|
||||
functionNode.getParameters());
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
198
nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java
Normal file
198
nashorn/src/jdk/nashorn/internal/ir/LexicalContext.java
Normal 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());
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
var scope = { x: "hello" };
|
||||
|
||||
with (scope) {
|
||||
function main() {
|
||||
var main = function() {
|
||||
if (x != "hello") {
|
||||
fail("x != 'hello'");
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user