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