Sat, 23 Mar 2013 00:58:39 +0100
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
1.1 --- a/make/project.properties Tue Mar 19 11:03:24 2013 -0300 1.2 +++ b/make/project.properties Sat Mar 23 00:58:39 2013 +0100 1.3 @@ -210,7 +210,7 @@ 1.4 # add '-Dtest.js.outofprocess' to run each test in a new sub-process 1.5 run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:-TieredCompilation -esa -ea -Dnashorn.debug=true -Dfile.encoding=UTF-8 1.6 #-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M 1.7 -run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs} 1.8 +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} 1.9 1.10 run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy 1.11
2.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Tue Mar 19 11:03:24 2013 -0300 2.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Sat Mar 23 00:58:39 2013 +0100 2.3 @@ -37,14 +37,16 @@ 2.4 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; 2.5 import static jdk.nashorn.internal.ir.Symbol.IS_LET; 2.6 import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; 2.7 +import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; 2.8 import static jdk.nashorn.internal.ir.Symbol.IS_THIS; 2.9 import static jdk.nashorn.internal.ir.Symbol.IS_VAR; 2.10 +import static jdk.nashorn.internal.ir.Symbol.KINDMASK; 2.11 2.12 import java.util.ArrayList; 2.13 import java.util.HashSet; 2.14 import java.util.Iterator; 2.15 -import java.util.LinkedList; 2.16 import java.util.List; 2.17 +import java.util.ListIterator; 2.18 import java.util.Set; 2.19 import jdk.nashorn.internal.codegen.types.Type; 2.20 import jdk.nashorn.internal.ir.AccessNode; 2.21 @@ -52,19 +54,19 @@ 2.22 import jdk.nashorn.internal.ir.Block; 2.23 import jdk.nashorn.internal.ir.CallNode; 2.24 import jdk.nashorn.internal.ir.CallNode.EvalArgs; 2.25 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 2.26 import jdk.nashorn.internal.ir.CaseNode; 2.27 import jdk.nashorn.internal.ir.CatchNode; 2.28 import jdk.nashorn.internal.ir.ForNode; 2.29 import jdk.nashorn.internal.ir.FunctionNode; 2.30 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 2.31 import jdk.nashorn.internal.ir.IdentNode; 2.32 import jdk.nashorn.internal.ir.IndexNode; 2.33 +import jdk.nashorn.internal.ir.LexicalContext; 2.34 import jdk.nashorn.internal.ir.LiteralNode; 2.35 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 2.36 import jdk.nashorn.internal.ir.Node; 2.37 import jdk.nashorn.internal.ir.ObjectNode; 2.38 import jdk.nashorn.internal.ir.PropertyNode; 2.39 -import jdk.nashorn.internal.ir.ReferenceNode; 2.40 import jdk.nashorn.internal.ir.ReturnNode; 2.41 import jdk.nashorn.internal.ir.RuntimeNode; 2.42 import jdk.nashorn.internal.ir.RuntimeNode.Request; 2.43 @@ -117,6 +119,8 @@ 2.44 */ 2.45 private Set<String> localUses; 2.46 2.47 + private final LexicalContext lexicalContext = new LexicalContext(); 2.48 + 2.49 private static final DebugLogger LOG = new DebugLogger("attr"); 2.50 private static final boolean DEBUG = LOG.isEnabled(); 2.51 2.52 @@ -137,14 +141,15 @@ 2.53 } 2.54 2.55 @Override 2.56 - public Node leave(final AccessNode accessNode) { 2.57 + public Node leaveAccessNode(final AccessNode accessNode) { 2.58 newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this 2.59 end(accessNode); 2.60 return accessNode; 2.61 } 2.62 2.63 @Override 2.64 - public Node enter(final Block block) { 2.65 + public Node enterBlock(final Block block) { 2.66 + lexicalContext.push(block); 2.67 start(block); 2.68 2.69 final Set<String> savedLocalDefs = localDefs; 2.70 @@ -160,9 +165,7 @@ 2.71 localDefs = new HashSet<>(savedLocalDefs); 2.72 localUses = new HashSet<>(savedLocalUses); 2.73 2.74 - for (final Node statement : block.getStatements()) { 2.75 - statement.accept(this); 2.76 - } 2.77 + block.visitStatements(this); 2.78 } finally { 2.79 localDefs = savedLocalDefs; 2.80 localUses = savedLocalUses; 2.81 @@ -172,11 +175,12 @@ 2.82 2.83 end(block); 2.84 2.85 + lexicalContext.pop(block); 2.86 return null; 2.87 } 2.88 2.89 @Override 2.90 - public Node enter(final CallNode callNode) { 2.91 + public Node enterCallNode(final CallNode callNode) { 2.92 start(callNode); 2.93 2.94 callNode.getFunction().accept(this); 2.95 @@ -197,8 +201,7 @@ 2.96 evalArgs.setThis(thisNode); 2.97 } 2.98 2.99 - newTemporary(Type.OBJECT, callNode); // object type here, access specialization in FinalizeTypes may narrow it later 2.100 - newType(callNode.getFunction().getSymbol(), Type.OBJECT); 2.101 + newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later 2.102 2.103 end(callNode); 2.104 2.105 @@ -206,29 +209,106 @@ 2.106 } 2.107 2.108 @Override 2.109 - public Node enter(final CatchNode catchNode) { 2.110 + public Node enterCatchNode(final CatchNode catchNode) { 2.111 final IdentNode exception = catchNode.getException(); 2.112 final Block block = getCurrentBlock(); 2.113 2.114 start(catchNode); 2.115 2.116 // define block-local exception variable 2.117 - final Symbol def = block.defineSymbol(exception.getName(), IS_VAR | IS_LET, exception); 2.118 + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); 2.119 newType(def, Type.OBJECT); 2.120 addLocalDef(exception.getName()); 2.121 2.122 return catchNode; 2.123 } 2.124 2.125 + /** 2.126 + * Declare the definition of a new symbol. 2.127 + * 2.128 + * @param name Name of symbol. 2.129 + * @param symbolFlags Symbol flags. 2.130 + * @param node Defining Node. 2.131 + * 2.132 + * @return Symbol for given name or null for redefinition. 2.133 + */ 2.134 + private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { 2.135 + int flags = symbolFlags; 2.136 + Symbol symbol = findSymbol(block, name); // Locate symbol. 2.137 + 2.138 + if ((flags & KINDMASK) == IS_GLOBAL) { 2.139 + flags |= IS_SCOPE; 2.140 + } 2.141 + 2.142 + final FunctionNode function = lexicalContext.getFunction(block); 2.143 + if (symbol != null) { 2.144 + // Symbol was already defined. Check if it needs to be redefined. 2.145 + if ((flags & KINDMASK) == IS_PARAM) { 2.146 + if (!isLocal(function, symbol)) { 2.147 + // Not defined in this function. Create a new definition. 2.148 + symbol = null; 2.149 + } else if (symbol.isParam()) { 2.150 + // Duplicate parameter. Null return will force an error. 2.151 + assert false : "duplicate parameter"; 2.152 + return null; 2.153 + } 2.154 + } else if ((flags & KINDMASK) == IS_VAR) { 2.155 + if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) { 2.156 + assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block"; 2.157 + // Always create a new definition. 2.158 + symbol = null; 2.159 + } else { 2.160 + // Not defined in this function. Create a new definition. 2.161 + if (!isLocal(function, symbol) || symbol.less(IS_VAR)) { 2.162 + symbol = null; 2.163 + } 2.164 + } 2.165 + } 2.166 + } 2.167 + 2.168 + if (symbol == null) { 2.169 + // If not found, then create a new one. 2.170 + Block symbolBlock; 2.171 + 2.172 + // Determine where to create it. 2.173 + if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { 2.174 + symbolBlock = block; 2.175 + } else { 2.176 + symbolBlock = function; 2.177 + } 2.178 + 2.179 + // Create and add to appropriate block. 2.180 + symbol = new Symbol(name, flags, node, symbolBlock); 2.181 + symbolBlock.putSymbol(name, symbol); 2.182 + 2.183 + if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { 2.184 + symbolBlock.getFrame().addSymbol(symbol); 2.185 + symbol.setNeedsSlot(true); 2.186 + } 2.187 + } else if (symbol.less(flags)) { 2.188 + symbol.setFlags(flags); 2.189 + } 2.190 + 2.191 + if (node != null) { 2.192 + node.setSymbol(symbol); 2.193 + } 2.194 + 2.195 + return symbol; 2.196 + } 2.197 + 2.198 @Override 2.199 - public Node enter(final FunctionNode functionNode) { 2.200 + public Node enterFunctionNode(final FunctionNode functionNode) { 2.201 start(functionNode, false); 2.202 if (functionNode.isLazy()) { 2.203 - LOG.info("LAZY: " + functionNode.getName()); 2.204 + LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT"); 2.205 + newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode); 2.206 + functionNode.setReturnType(Type.OBJECT); 2.207 end(functionNode); 2.208 return null; 2.209 } 2.210 2.211 + lexicalContext.push(functionNode); 2.212 + 2.213 clearLocalDefs(); 2.214 clearLocalUses(); 2.215 2.216 @@ -244,24 +324,36 @@ 2.217 initScope(functionNode); 2.218 initReturn(functionNode); 2.219 2.220 - // Add all nested functions as symbols in this function 2.221 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 2.222 + // Add all nested declared functions as symbols in this function 2.223 + for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) { 2.224 final IdentNode ident = nestedFunction.getIdent(); 2.225 - if (ident != null && nestedFunction.isStatement()) { 2.226 - final Symbol functionSymbol = functionNode.defineSymbol(ident.getName(), IS_VAR, nestedFunction); 2.227 + if (ident != null) { 2.228 + assert nestedFunction.isDeclared(); 2.229 + final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction); 2.230 newType(functionSymbol, Type.typeFor(ScriptFunction.class)); 2.231 } 2.232 } 2.233 2.234 - if (functionNode.isScript()) { 2.235 + if (functionNode.isProgram()) { 2.236 initFromPropertyMap(functionNode); 2.237 } 2.238 2.239 // Add function name as local symbol 2.240 - if (!functionNode.isStatement() && !functionNode.isAnonymous() && !functionNode.isScript()) { 2.241 - final Symbol selfSymbol = functionNode.defineSymbol(functionNode.getIdent().getName(), IS_VAR, functionNode); 2.242 - newType(selfSymbol, Type.OBJECT); 2.243 - selfSymbol.setNode(functionNode); 2.244 + if (!functionNode.isDeclared() && !functionNode.isProgram()) { 2.245 + if(functionNode.getSymbol() != null) { 2.246 + // a temporary left over from an earlier pass when the function was lazy 2.247 + assert functionNode.getSymbol().isTemp(); 2.248 + // remove it 2.249 + functionNode.setSymbol(null); 2.250 + } 2.251 + final Symbol selfSymbol; 2.252 + if(functionNode.isAnonymous()) { 2.253 + selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode); 2.254 + } else { 2.255 + selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode); 2.256 + newType(selfSymbol, Type.OBJECT); 2.257 + selfSymbol.setNode(functionNode); 2.258 + } 2.259 } 2.260 2.261 /* 2.262 @@ -282,32 +374,26 @@ 2.263 */ 2.264 2.265 final List<Symbol> declaredSymbols = new ArrayList<>(); 2.266 - for (final VarNode decl : functionNode.getDeclarations()) { 2.267 - final IdentNode ident = decl.getName(); 2.268 - // any declared symbols that aren't visited need to be typed as well, hence the list 2.269 - declaredSymbols.add(functionNode.defineSymbol(ident.getName(), IS_VAR, new IdentNode(ident))); 2.270 - } 2.271 + // This visitor will assign symbol to all declared variables, except function declarations (which are taken care 2.272 + // in a separate step above) and "var" declarations in for loop initializers. 2.273 + functionNode.accept(new NodeOperatorVisitor() { 2.274 + @Override 2.275 + public Node enterFunctionNode(FunctionNode nestedFn) { 2.276 + // Don't descend into nested functions 2.277 + return nestedFn == functionNode ? nestedFn : null; 2.278 + } 2.279 + @Override 2.280 + public Node enterVarNode(VarNode varNode) { 2.281 + if(varNode.isStatement() && !varNode.isFunctionDeclaration()) { 2.282 + final IdentNode ident = varNode.getName(); 2.283 + // any declared symbols that aren't visited need to be typed as well, hence the list 2.284 + declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident))); 2.285 + } 2.286 + return null; 2.287 + } 2.288 + }); 2.289 2.290 - // Every nested function needs a definition in the outer function with its name. Add these. 2.291 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 2.292 - final VarNode varNode = nestedFunction.getFunctionVarNode(); 2.293 - if (varNode != null) { 2.294 - varNode.accept(this); 2.295 - assert varNode.isFunctionVarNode() : varNode + " should be function var node"; 2.296 - } 2.297 - } 2.298 - 2.299 - for (final Node statement : functionNode.getStatements()) { 2.300 - if (statement instanceof VarNode && ((VarNode)statement).isFunctionVarNode()) { 2.301 - continue; //var nodes have already been processed, skip or they will generate additional defs/uses and false "can be undefined" 2.302 - } 2.303 - statement.accept(this); 2.304 - } 2.305 - 2.306 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 2.307 - LOG.info("Going into nested function " + functionNode.getName() + " -> " + nestedFunction.getName()); 2.308 - nestedFunction.accept(this); 2.309 - } 2.310 + visitFunctionStatements(functionNode); 2.311 2.312 //unknown parameters are promoted to object type. 2.313 finalizeParameters(functionNode); 2.314 @@ -343,10 +429,19 @@ 2.315 functionNode.setState(CompilationState.ATTR); 2.316 2.317 end(functionNode, false); 2.318 + lexicalContext.pop(functionNode); 2.319 2.320 return null; 2.321 } 2.322 2.323 + private void visitFunctionStatements(final FunctionNode functionNode) { 2.324 + final List<Node> newStatements = new ArrayList<>(functionNode.getStatements()); 2.325 + for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) { 2.326 + stmts.set(stmts.next().accept(this)); 2.327 + } 2.328 + functionNode.setStatements(newStatements); 2.329 + } 2.330 + 2.331 @Override 2.332 public Node leaveCONVERT(final UnaryNode unaryNode) { 2.333 assert false : "There should be no convert operators in IR during Attribution"; 2.334 @@ -355,7 +450,7 @@ 2.335 } 2.336 2.337 @Override 2.338 - public Node enter(final IdentNode identNode) { 2.339 + public Node enterIdentNode(final IdentNode identNode) { 2.340 final String name = identNode.getName(); 2.341 2.342 start(identNode); 2.343 @@ -372,7 +467,7 @@ 2.344 final Block block = getCurrentBlock(); 2.345 final Symbol oldSymbol = identNode.getSymbol(); 2.346 2.347 - Symbol symbol = block.findSymbol(name); 2.348 + Symbol symbol = findSymbol(block, name); 2.349 2.350 //If an existing symbol with the name is found, use that otherwise, declare a new one 2.351 if (symbol != null) { 2.352 @@ -396,22 +491,13 @@ 2.353 } 2.354 2.355 identNode.setSymbol(symbol); 2.356 - if (!getCurrentFunctionNode().isLocal(symbol)) { 2.357 - // non-local: we need to put symbol in scope (if it isn't already) 2.358 - if (!symbol.isScope()) { 2.359 - final List<Block> lookupBlocks = findLookupBlocksHelper(getCurrentFunctionNode(), symbol.findFunction()); 2.360 - for (final Block lookupBlock : lookupBlocks) { 2.361 - final Symbol refSymbol = lookupBlock.findSymbol(name); 2.362 - if (refSymbol != null) { // See NASHORN-837, function declaration in lexical scope: try {} catch (x){ function f() { use(x) } } f() 2.363 - LOG.finest("Found a ref symbol that must be scope " + refSymbol); 2.364 - refSymbol.setIsScope(); 2.365 - } 2.366 - } 2.367 - } 2.368 + // non-local: we need to put symbol in scope (if it isn't already) 2.369 + if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) { 2.370 + symbol.setIsScope(); 2.371 } 2.372 } else { 2.373 LOG.info("No symbol exists. Declare undefined: " + symbol); 2.374 - symbol = block.useSymbol(name, identNode); 2.375 + symbol = useSymbol(block, name, identNode); 2.376 // we have never seen this before, it can be undefined 2.377 newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? 2.378 symbol.setCanBeUndefined(); 2.379 @@ -420,9 +506,10 @@ 2.380 2.381 assert symbol != null; 2.382 if(symbol.isGlobal()) { 2.383 - getCurrentFunctionNode().setUsesGlobalSymbol(); 2.384 + setUsesGlobalSymbol(); 2.385 } else if(symbol.isScope()) { 2.386 - getCurrentFunctionNode().setUsesScopeSymbol(symbol); 2.387 + final Iterator<Block> blocks = lexicalContext.getBlocks(); 2.388 + blocks.next().setUsesScopeSymbol(symbol, blocks); 2.389 } 2.390 2.391 if (symbol != oldSymbol && !identNode.isInitializedHere()) { 2.392 @@ -435,15 +522,68 @@ 2.393 return null; 2.394 } 2.395 2.396 + /** 2.397 + * Marks the current function as one using any global symbol. The function and all its parent functions will all be 2.398 + * marked as needing parent scope. 2.399 + * @see #needsParentScope() 2.400 + */ 2.401 + private void setUsesGlobalSymbol() { 2.402 + for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) { 2.403 + fns.next().setUsesAncestorScope(); 2.404 + } 2.405 + } 2.406 + 2.407 + /** 2.408 + * Declare the use of a symbol in a block. 2.409 + * 2.410 + * @param block block in which the symbol is used 2.411 + * @param name Name of symbol. 2.412 + * @param node Using node 2.413 + * 2.414 + * @return Symbol for given name. 2.415 + */ 2.416 + private Symbol useSymbol(final Block block, final String name, final Node node) { 2.417 + Symbol symbol = findSymbol(block, name); 2.418 + 2.419 + if (symbol == null) { 2.420 + // If not found, declare as a free var. 2.421 + symbol = defineSymbol(block, name, IS_GLOBAL, node); 2.422 + } else { 2.423 + node.setSymbol(symbol); 2.424 + } 2.425 + 2.426 + return symbol; 2.427 + } 2.428 + 2.429 + 2.430 + /** 2.431 + * Search for symbol in the lexical context starting from the given block. 2.432 + * @param name Symbol name. 2.433 + * @return Found symbol or null if not found. 2.434 + */ 2.435 + private Symbol findSymbol(final Block block, final String name) { 2.436 + // Search up block chain to locate symbol. 2.437 + 2.438 + for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) { 2.439 + // Find name. 2.440 + final Symbol symbol = blocks.next().getExistingSymbol(name); 2.441 + // If found then we are good. 2.442 + if(symbol != null) { 2.443 + return symbol; 2.444 + } 2.445 + } 2.446 + return null; 2.447 + } 2.448 + 2.449 @Override 2.450 - public Node leave(final IndexNode indexNode) { 2.451 + public Node leaveIndexNode(final IndexNode indexNode) { 2.452 newTemporary(Type.OBJECT, indexNode); //TORO 2.453 return indexNode; 2.454 } 2.455 2.456 @SuppressWarnings("rawtypes") 2.457 @Override 2.458 - public Node enter(final LiteralNode literalNode) { 2.459 + public Node enterLiteralNode(final LiteralNode literalNode) { 2.460 try { 2.461 start(literalNode); 2.462 assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens 2.463 @@ -472,14 +612,14 @@ 2.464 } 2.465 2.466 @Override 2.467 - public Node leave(final ObjectNode objectNode) { 2.468 + public Node leaveObjectNode(final ObjectNode objectNode) { 2.469 newTemporary(Type.OBJECT, objectNode); 2.470 end(objectNode); 2.471 return objectNode; 2.472 } 2.473 2.474 @Override 2.475 - public Node enter(final PropertyNode propertyNode) { 2.476 + public Node enterPropertyNode(final PropertyNode propertyNode) { 2.477 // assign a pseudo symbol to property name, see NASHORN-710 2.478 propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); 2.479 end(propertyNode); 2.480 @@ -487,31 +627,7 @@ 2.481 } 2.482 2.483 @Override 2.484 - public Node enter(final ReferenceNode referenceNode) { 2.485 - final FunctionNode functionNode = referenceNode.getReference(); 2.486 - if (functionNode != null) { 2.487 - functionNode.addReferencingParentBlock(getCurrentBlock()); 2.488 - } 2.489 - return referenceNode; 2.490 - } 2.491 - 2.492 - @Override 2.493 - public Node leave(final ReferenceNode referenceNode) { 2.494 - newTemporary(Type.OBJECT, referenceNode); //reference node type is always an object, i.e. the scriptFunction. the function return type varies though 2.495 - 2.496 - final FunctionNode functionNode = referenceNode.getReference(); 2.497 - //assert !functionNode.getType().isUnknown() || functionNode.isLazy() : functionNode.getType(); 2.498 - if (functionNode.isLazy()) { 2.499 - LOG.info("Lazy function node call reference: " + functionNode.getName() + " => Promoting to OBJECT"); 2.500 - functionNode.setReturnType(Type.OBJECT); 2.501 - } 2.502 - end(referenceNode); 2.503 - 2.504 - return referenceNode; 2.505 - } 2.506 - 2.507 - @Override 2.508 - public Node leave(final ReturnNode returnNode) { 2.509 + public Node leaveReturnNode(final ReturnNode returnNode) { 2.510 final Node expr = returnNode.getExpression(); 2.511 2.512 if (expr != null) { 2.513 @@ -530,7 +646,7 @@ 2.514 } 2.515 2.516 @Override 2.517 - public Node leave(final SwitchNode switchNode) { 2.518 + public Node leaveSwitchNode(final SwitchNode switchNode) { 2.519 Type type = Type.UNKNOWN; 2.520 2.521 for (final CaseNode caseNode : switchNode.getCases()) { 2.522 @@ -567,7 +683,7 @@ 2.523 } 2.524 2.525 @Override 2.526 - public Node leave(final TryNode tryNode) { 2.527 + public Node leaveTryNode(final TryNode tryNode) { 2.528 tryNode.setException(exceptionSymbol()); 2.529 2.530 if (tryNode.getFinallyBody() != null) { 2.531 @@ -580,13 +696,13 @@ 2.532 } 2.533 2.534 @Override 2.535 - public Node enter(final VarNode varNode) { 2.536 + public Node enterVarNode(final VarNode varNode) { 2.537 start(varNode); 2.538 2.539 final IdentNode ident = varNode.getName(); 2.540 final String name = ident.getName(); 2.541 2.542 - final Symbol symbol = getCurrentBlock().defineSymbol(name, IS_VAR, ident); 2.543 + final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident); 2.544 assert symbol != null; 2.545 2.546 LOG.info("VarNode " + varNode + " set symbol " + symbol); 2.547 @@ -598,23 +714,15 @@ 2.548 symbol.setCanBeUndefined(); 2.549 } 2.550 2.551 - if (varNode.getInit() != null) { 2.552 - varNode.getInit().accept(this); 2.553 - } 2.554 - 2.555 return varNode; 2.556 } 2.557 2.558 @Override 2.559 - public Node leave(final VarNode varNode) { 2.560 + public Node leaveVarNode(final VarNode varNode) { 2.561 final Node init = varNode.getInit(); 2.562 final IdentNode ident = varNode.getName(); 2.563 final String name = ident.getName(); 2.564 2.565 - if (init != null) { 2.566 - addLocalDef(name); 2.567 - } 2.568 - 2.569 if (init == null) { 2.570 // var x; with no init will be treated like a use of x by 2.571 // visit(IdentNode) unless we remove the name 2.572 @@ -623,8 +731,10 @@ 2.573 return varNode; 2.574 } 2.575 2.576 + addLocalDef(name); 2.577 + 2.578 final Symbol symbol = varNode.getSymbol(); 2.579 - final boolean isScript = symbol.getBlock().getFunction().isScript(); //see NASHORN-56 2.580 + final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56 2.581 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { 2.582 // Forbid integers as local vars for now as we have no way to treat them as undefined 2.583 newType(symbol, init.getType()); 2.584 @@ -718,11 +828,9 @@ 2.585 runtimeNode = new RuntimeNode(unaryNode, request, args); 2.586 assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this 2.587 2.588 - runtimeNode.accept(this); 2.589 - return runtimeNode; 2.590 + return leaveRuntimeNode(runtimeNode); 2.591 } 2.592 2.593 - 2.594 @Override 2.595 public Node leaveNEW(final UnaryNode unaryNode) { 2.596 newTemporary(Type.OBJECT, unaryNode); 2.597 @@ -755,7 +863,7 @@ 2.598 runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); 2.599 assert runtimeNode.getSymbol() == unaryNode.getSymbol(); 2.600 2.601 - runtimeNode.accept(this); 2.602 + runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode); 2.603 2.604 end(unaryNode); 2.605 2.606 @@ -763,7 +871,7 @@ 2.607 } 2.608 2.609 @Override 2.610 - public Node leave(final RuntimeNode runtimeNode) { 2.611 + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 2.612 newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode); 2.613 return runtimeNode; 2.614 } 2.615 @@ -823,12 +931,12 @@ 2.616 final IdentNode ident = (IdentNode)lhs; 2.617 final String name = ident.getName(); 2.618 2.619 - Symbol symbol = getCurrentBlock().findSymbol(name); 2.620 + Symbol symbol = findSymbol(getCurrentBlock(), name); 2.621 2.622 if (symbol == null) { 2.623 - symbol = block.defineSymbol(name, IS_GLOBAL, ident); 2.624 + symbol = defineSymbol(block, name, IS_GLOBAL, ident); 2.625 binaryNode.setSymbol(symbol); 2.626 - } else if (!getCurrentFunctionNode().isLocal(symbol)) { 2.627 + } else if (!isLocal(getCurrentFunctionNode(), symbol)) { 2.628 symbol.setIsScope(); 2.629 } 2.630 2.631 @@ -838,6 +946,12 @@ 2.632 return binaryNode; 2.633 } 2.634 2.635 + private boolean isLocal(FunctionNode function, Symbol symbol) { 2.636 + final Block block = symbol.getBlock(); 2.637 + // some temp symbols have no block, so can be assumed local 2.638 + return block == null || lexicalContext.getFunction(block) == function; 2.639 + } 2.640 + 2.641 @Override 2.642 public Node enterASSIGN(final BinaryNode binaryNode) { 2.643 return enterAssignmentNode(binaryNode); 2.644 @@ -995,7 +1109,7 @@ 2.645 return leaveBinaryArithmetic(binaryNode); 2.646 } 2.647 2.648 - private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) { 2.649 + private Node leaveCmp(final BinaryNode binaryNode) { 2.650 final Node lhs = binaryNode.lhs(); 2.651 final Node rhs = binaryNode.rhs(); 2.652 2.653 @@ -1033,37 +1147,38 @@ 2.654 2.655 @Override 2.656 public Node leaveEQ(final BinaryNode binaryNode) { 2.657 - return leaveCmp(binaryNode, Request.EQ); 2.658 + return leaveCmp(binaryNode); 2.659 } 2.660 2.661 @Override 2.662 public Node leaveEQ_STRICT(final BinaryNode binaryNode) { 2.663 - return leaveCmp(binaryNode, Request.EQ_STRICT); 2.664 + return leaveCmp(binaryNode); 2.665 } 2.666 2.667 @Override 2.668 public Node leaveGE(final BinaryNode binaryNode) { 2.669 - return leaveCmp(binaryNode, Request.GE); 2.670 + return leaveCmp(binaryNode); 2.671 } 2.672 2.673 @Override 2.674 public Node leaveGT(final BinaryNode binaryNode) { 2.675 - return leaveCmp(binaryNode, Request.GT); 2.676 + return leaveCmp(binaryNode); 2.677 } 2.678 2.679 @Override 2.680 public Node leaveIN(final BinaryNode binaryNode) { 2.681 - try { 2.682 - return new RuntimeNode(binaryNode, Request.IN).accept(this); 2.683 - } finally { 2.684 - end(binaryNode); 2.685 - } 2.686 + return leaveBinaryRuntimeOperator(binaryNode, Request.IN); 2.687 } 2.688 2.689 @Override 2.690 public Node leaveINSTANCEOF(final BinaryNode binaryNode) { 2.691 + return leaveBinaryRuntimeOperator(binaryNode, Request.INSTANCEOF); 2.692 + } 2.693 + 2.694 + private Node leaveBinaryRuntimeOperator(final BinaryNode binaryNode, final Request request) { 2.695 try { 2.696 - return new RuntimeNode(binaryNode, Request.INSTANCEOF).accept(this); 2.697 + // Don't do a full RuntimeNode.accept, as we don't want to double-visit the binary node operands 2.698 + return leaveRuntimeNode(new RuntimeNode(binaryNode, request)); 2.699 } finally { 2.700 end(binaryNode); 2.701 } 2.702 @@ -1071,12 +1186,12 @@ 2.703 2.704 @Override 2.705 public Node leaveLE(final BinaryNode binaryNode) { 2.706 - return leaveCmp(binaryNode, Request.LE); 2.707 + return leaveCmp(binaryNode); 2.708 } 2.709 2.710 @Override 2.711 public Node leaveLT(final BinaryNode binaryNode) { 2.712 - return leaveCmp(binaryNode, Request.LT); 2.713 + return leaveCmp(binaryNode); 2.714 } 2.715 2.716 @Override 2.717 @@ -1091,12 +1206,12 @@ 2.718 2.719 @Override 2.720 public Node leaveNE(final BinaryNode binaryNode) { 2.721 - return leaveCmp(binaryNode, Request.NE); 2.722 + return leaveCmp(binaryNode); 2.723 } 2.724 2.725 @Override 2.726 public Node leaveNE_STRICT(final BinaryNode binaryNode) { 2.727 - return leaveCmp(binaryNode, Request.NE_STRICT); 2.728 + return leaveCmp(binaryNode); 2.729 } 2.730 2.731 @Override 2.732 @@ -1127,9 +1242,9 @@ 2.733 } 2.734 2.735 @Override 2.736 - public Node leave(final ForNode forNode) { 2.737 + public Node leaveForNode(final ForNode forNode) { 2.738 if (forNode.isForIn()) { 2.739 - forNode.setIterator(newInternal(getCurrentFunctionNode(), getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 2.740 + forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 2.741 /* 2.742 * Iterators return objects, so we need to widen the scope of the 2.743 * init variable if it, for example, has been assigned double type 2.744 @@ -1144,7 +1259,7 @@ 2.745 } 2.746 2.747 @Override 2.748 - public Node leave(final TernaryNode ternaryNode) { 2.749 + public Node leaveTernaryNode(final TernaryNode ternaryNode) { 2.750 final Node lhs = ternaryNode.rhs(); 2.751 final Node rhs = ternaryNode.third(); 2.752 2.753 @@ -1159,24 +1274,24 @@ 2.754 return ternaryNode; 2.755 } 2.756 2.757 - private static void initThis(final FunctionNode functionNode) { 2.758 - final Symbol thisSymbol = functionNode.defineSymbol(THIS.tag(), IS_PARAM | IS_THIS, null); 2.759 + private void initThis(final FunctionNode functionNode) { 2.760 + final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null); 2.761 newType(thisSymbol, Type.OBJECT); 2.762 thisSymbol.setNeedsSlot(true); 2.763 functionNode.getThisNode().setSymbol(thisSymbol); 2.764 LOG.info("Initialized scope symbol: " + thisSymbol); 2.765 } 2.766 2.767 - private static void initScope(final FunctionNode functionNode) { 2.768 - final Symbol scopeSymbol = functionNode.defineSymbol(SCOPE.tag(), IS_VAR | IS_INTERNAL, null); 2.769 + private void initScope(final FunctionNode functionNode) { 2.770 + final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null); 2.771 newType(scopeSymbol, Type.typeFor(ScriptObject.class)); 2.772 scopeSymbol.setNeedsSlot(true); 2.773 functionNode.getScopeNode().setSymbol(scopeSymbol); 2.774 LOG.info("Initialized scope symbol: " + scopeSymbol); 2.775 } 2.776 2.777 - private static void initReturn(final FunctionNode functionNode) { 2.778 - final Symbol returnSymbol = functionNode.defineSymbol(SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); 2.779 + private void initReturn(final FunctionNode functionNode) { 2.780 + final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); 2.781 newType(returnSymbol, Type.OBJECT); 2.782 returnSymbol.setNeedsSlot(true); 2.783 functionNode.getResultNode().setSymbol(returnSymbol); 2.784 @@ -1186,7 +1301,7 @@ 2.785 2.786 private void initVarArg(final FunctionNode functionNode) { 2.787 if (functionNode.isVarArg()) { 2.788 - final Symbol varArgsSymbol = functionNode.defineSymbol(VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); 2.789 + final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); 2.790 varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); 2.791 varArgsSymbol.setNeedsSlot(true); 2.792 functionNode.getVarArgsNode().setSymbol(varArgsSymbol); 2.793 @@ -1194,7 +1309,7 @@ 2.794 2.795 if (functionNode.needsArguments()) { 2.796 final String argumentsName = functionNode.getArgumentsNode().getName(); 2.797 - final Symbol argumentsSymbol = functionNode.defineSymbol(argumentsName, IS_VAR | IS_INTERNAL, null); 2.798 + final Symbol argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null); 2.799 newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); 2.800 argumentsSymbol.setNeedsSlot(true); 2.801 functionNode.getArgumentsNode().setSymbol(argumentsSymbol); 2.802 @@ -1204,9 +1319,9 @@ 2.803 } 2.804 } 2.805 2.806 - private static void initCallee(final FunctionNode functionNode) { 2.807 + private void initCallee(final FunctionNode functionNode) { 2.808 assert functionNode.getCalleeNode() != null : functionNode + " has no callee"; 2.809 - final Symbol calleeSymbol = functionNode.defineSymbol(CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); 2.810 + final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); 2.811 newType(calleeSymbol, Type.typeFor(ScriptFunction.class)); 2.812 calleeSymbol.setNeedsSlot(true); 2.813 functionNode.getCalleeNode().setSymbol(calleeSymbol); 2.814 @@ -1226,7 +1341,7 @@ 2.815 2.816 for (final IdentNode param : functionNode.getParameters()) { 2.817 addLocalDef(param.getName()); 2.818 - final Symbol paramSymbol = functionNode.defineSymbol(param.getName(), IS_PARAM, param); 2.819 + final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param); 2.820 if (paramSymbol != null) { 2.821 final Type callSiteParamType = functionNode.getSpecializedType(param); 2.822 if (callSiteParamType != null) { 2.823 @@ -1279,15 +1394,15 @@ 2.824 * Move any properties from a global map into the scope of this method 2.825 * @param functionNode the function node for which to init scope vars 2.826 */ 2.827 - private static void initFromPropertyMap(final FunctionNode functionNode) { 2.828 + private void initFromPropertyMap(final FunctionNode functionNode) { 2.829 // For a script, add scope symbols as defined in the property map 2.830 - assert functionNode.isScript(); 2.831 + assert functionNode.isProgram(); 2.832 2.833 final PropertyMap map = Context.getGlobalMap(); 2.834 2.835 for (final Property property : map.getProperties()) { 2.836 final String key = property.getKey(); 2.837 - final Symbol symbol = functionNode.defineSymbol(key, IS_GLOBAL, null); 2.838 + final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null); 2.839 newType(symbol, Type.OBJECT); 2.840 LOG.info("Added global symbol from property map " + symbol); 2.841 } 2.842 @@ -1354,7 +1469,7 @@ 2.843 private static void ensureAssignmentSlots(final FunctionNode functionNode, final Node assignmentDest) { 2.844 assignmentDest.accept(new NodeVisitor() { 2.845 @Override 2.846 - public Node leave(final IndexNode indexNode) { 2.847 + public Node leaveIndexNode(final IndexNode indexNode) { 2.848 final Node index = indexNode.getIndex(); 2.849 index.getSymbol().setNeedsSlot(!index.getSymbol().isConstant()); 2.850 return indexNode; 2.851 @@ -1399,7 +1514,7 @@ 2.852 } 2.853 2.854 @Override 2.855 - public Node enter(final FunctionNode node) { 2.856 + public Node enterFunctionNode(final FunctionNode node) { 2.857 return node.isLazy() ? null : node; 2.858 } 2.859 2.860 @@ -1419,7 +1534,7 @@ 2.861 */ 2.862 @SuppressWarnings("fallthrough") 2.863 @Override 2.864 - public Node leave(final BinaryNode binaryNode) { 2.865 + public Node leaveBinaryNode(final BinaryNode binaryNode) { 2.866 final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 2.867 switch (binaryNode.tokenType()) { 2.868 default: 2.869 @@ -1477,22 +1592,6 @@ 2.870 return binaryNode; 2.871 } 2.872 2.873 - private static List<Block> findLookupBlocksHelper(final FunctionNode currentFunction, final FunctionNode topFunction) { 2.874 - if (currentFunction.findParentFunction() == topFunction) { 2.875 - final List<Block> blocks = new LinkedList<>(); 2.876 - 2.877 - blocks.add(currentFunction.getParent()); 2.878 - blocks.addAll(currentFunction.getReferencingParentBlocks()); 2.879 - return blocks; 2.880 - } 2.881 - /* 2.882 - * assumption: all parent blocks of an inner function will always be in the same outer function; 2.883 - * therefore we can simply skip through intermediate functions. 2.884 - * @see FunctionNode#addReferencingParentBlock(Block) 2.885 - */ 2.886 - return findLookupBlocksHelper(currentFunction.findParentFunction(), topFunction); 2.887 - } 2.888 - 2.889 private static boolean isFunctionExpressionSelfReference(final Symbol symbol) { 2.890 if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) { 2.891 return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName()); 2.892 @@ -1509,16 +1608,12 @@ 2.893 return newTemporary(getCurrentFunctionNode(), type, node); 2.894 } 2.895 2.896 - private Symbol newInternal(final FunctionNode functionNode, final String name, final Type type) { 2.897 - final Symbol iter = getCurrentFunctionNode().defineSymbol(name, IS_VAR | IS_INTERNAL, null); 2.898 + private Symbol newInternal(final String name, final Type type) { 2.899 + final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null); 2.900 iter.setType(type); // NASHORN-73 2.901 return iter; 2.902 } 2.903 2.904 - private Symbol newInternal(final String name, final Type type) { 2.905 - return newInternal(getCurrentFunctionNode(), name, type); 2.906 - } 2.907 - 2.908 private static void newType(final Symbol symbol, final Type type) { 2.909 final Type oldType = symbol.getSymbolType(); 2.910 symbol.setType(type); 2.911 @@ -1577,13 +1672,13 @@ 2.912 } 2.913 2.914 @Override 2.915 - public Node enter(final Block block) { 2.916 + public Node enterBlock(final Block block) { 2.917 toObject(block); 2.918 return block; 2.919 } 2.920 2.921 @Override 2.922 - public Node enter(final FunctionNode node) { 2.923 + public Node enterFunctionNode(final FunctionNode node) { 2.924 toObject(node); 2.925 if (node.isLazy()) { 2.926 return null;
3.1 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java Tue Mar 19 11:03:24 2013 -0300 3.2 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java Sat Mar 23 00:58:39 2013 +0100 3.3 @@ -195,6 +195,14 @@ 3.4 } 3.5 3.6 /** 3.7 + * Returns the name of the compile unit class name. 3.8 + * @return the name of the compile unit class name. 3.9 + */ 3.10 + String getUnitClassName() { 3.11 + return unitClassName; 3.12 + } 3.13 + 3.14 + /** 3.15 * Convert a binary name to a package/class name. 3.16 * 3.17 * @param name Binary name. 3.18 @@ -244,7 +252,7 @@ 3.19 // $getMap - get the ith entry from the constants table and cast to PropertyMap. 3.20 final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class); 3.21 getMapMethod.begin(); 3.22 - getMapMethod.loadConstants(unitClassName) 3.23 + getMapMethod.loadConstants() 3.24 .load(Type.INT, 0) 3.25 .arrayload() 3.26 .checkcast(PropertyMap.class) 3.27 @@ -254,7 +262,7 @@ 3.28 // $setMap - overwrite an existing map. 3.29 final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class); 3.30 setMapMethod.begin(); 3.31 - setMapMethod.loadConstants(unitClassName) 3.32 + setMapMethod.loadConstants() 3.33 .load(Type.INT, 0) 3.34 .load(Type.OBJECT, 1) 3.35 .arraystore();
4.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Mar 19 11:03:24 2013 -0300 4.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Sat Mar 23 00:58:39 2013 +0100 4.3 @@ -76,18 +76,18 @@ 4.4 import jdk.nashorn.internal.ir.ExecuteNode; 4.5 import jdk.nashorn.internal.ir.ForNode; 4.6 import jdk.nashorn.internal.ir.FunctionNode; 4.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 4.8 import jdk.nashorn.internal.ir.IdentNode; 4.9 import jdk.nashorn.internal.ir.IfNode; 4.10 import jdk.nashorn.internal.ir.IndexNode; 4.11 +import jdk.nashorn.internal.ir.LexicalContext; 4.12 import jdk.nashorn.internal.ir.LineNumberNode; 4.13 import jdk.nashorn.internal.ir.LiteralNode; 4.14 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 4.15 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 4.16 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 4.17 import jdk.nashorn.internal.ir.Node; 4.18 import jdk.nashorn.internal.ir.ObjectNode; 4.19 import jdk.nashorn.internal.ir.PropertyNode; 4.20 -import jdk.nashorn.internal.ir.ReferenceNode; 4.21 import jdk.nashorn.internal.ir.ReturnNode; 4.22 import jdk.nashorn.internal.ir.RuntimeNode; 4.23 import jdk.nashorn.internal.ir.RuntimeNode.Request; 4.24 @@ -107,6 +107,7 @@ 4.25 import jdk.nashorn.internal.parser.Lexer.RegexToken; 4.26 import jdk.nashorn.internal.parser.TokenType; 4.27 import jdk.nashorn.internal.runtime.Context; 4.28 +import jdk.nashorn.internal.runtime.DebugLogger; 4.29 import jdk.nashorn.internal.runtime.ECMAException; 4.30 import jdk.nashorn.internal.runtime.Property; 4.31 import jdk.nashorn.internal.runtime.PropertyMap; 4.32 @@ -156,12 +157,20 @@ 4.33 /** How many regexp fields have been emitted */ 4.34 private int regexFieldCount; 4.35 4.36 + /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling 4.37 + * a just-defined anonymous function expression. */ 4.38 + private boolean functionNodeIsCallee; 4.39 + 4.40 /** Map of shared scope call sites */ 4.41 private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>(); 4.42 4.43 + private final LexicalContext lexicalContext = new LexicalContext(); 4.44 + 4.45 /** When should we stop caching regexp expressions in fields to limit bytecode size? */ 4.46 private static final int MAX_REGEX_FIELDS = 2 * 1024; 4.47 4.48 + private static final DebugLogger LOG = new DebugLogger("codegen", "nashorn.codegen.debug"); 4.49 + 4.50 /** 4.51 * Constructor. 4.52 * 4.53 @@ -210,7 +219,7 @@ 4.54 final int flags = CALLSITE_SCOPE | getCallSiteFlags(); 4.55 method.loadScope(); 4.56 4.57 - if (symbol.isFastScope(getCurrentFunctionNode())) { 4.58 + if (isFastScope(symbol)) { 4.59 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. 4.60 if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { 4.61 return loadSharedScopeVar(identNode.getType(), symbol, flags); 4.62 @@ -221,8 +230,28 @@ 4.63 } 4.64 } 4.65 4.66 + /** 4.67 + * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load 4.68 + * 4.69 + * @param function function to check for fast scope 4.70 + * @return true if fast scope 4.71 + */ 4.72 + private boolean isFastScope(final Symbol symbol) { 4.73 + if (!symbol.isScope() || !symbol.getBlock().needsScope()) { 4.74 + return false; 4.75 + } 4.76 + // Allow fast scope access if no function contains with or eval 4.77 + for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) { 4.78 + final FunctionNode func = it.next(); 4.79 + if (func.hasWith() || func.hasEval()) { 4.80 + return false; 4.81 + } 4.82 + } 4.83 + return true; 4.84 + } 4.85 + 4.86 private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { 4.87 - method.load(symbol.isFastScope(getCurrentFunctionNode()) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); 4.88 + method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); 4.89 final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); 4.90 scopeCall.generateInvoke(method); 4.91 return method; 4.92 @@ -240,30 +269,18 @@ 4.93 return method; 4.94 } 4.95 4.96 - private static int getScopeProtoDepth(final Block currentBlock, final Symbol symbol) { 4.97 - if (currentBlock == symbol.getBlock()) { 4.98 - return 0; 4.99 - } 4.100 - 4.101 - final int delta = currentBlock.needsScope() ? 1 : 0; 4.102 - final Block parentBlock = currentBlock.getParent(); 4.103 - 4.104 - if (parentBlock != null) { 4.105 - final int result = getScopeProtoDepth(parentBlock, symbol); 4.106 - if (result != -1) { 4.107 - return delta + result; 4.108 + private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { 4.109 + int depth = 0; 4.110 + final Block definingBlock = symbol.getBlock(); 4.111 + for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) { 4.112 + final Block currentBlock = blocks.next(); 4.113 + if (currentBlock == definingBlock) { 4.114 + return depth; 4.115 + } 4.116 + if (currentBlock.needsScope()) { 4.117 + ++depth; 4.118 } 4.119 } 4.120 - 4.121 - if (currentBlock instanceof FunctionNode) { 4.122 - for (final Block lookupBlock : ((FunctionNode)currentBlock).getReferencingParentBlocks()) { 4.123 - final int result = getScopeProtoDepth(lookupBlock, symbol); 4.124 - if (result != -1) { 4.125 - return delta + result; 4.126 - } 4.127 - } 4.128 - } 4.129 - 4.130 return -1; 4.131 } 4.132 4.133 @@ -313,13 +330,13 @@ 4.134 4.135 node.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 4.136 @Override 4.137 - public Node enter(final IdentNode identNode) { 4.138 + public Node enterIdentNode(final IdentNode identNode) { 4.139 loadIdent(identNode); 4.140 return null; 4.141 } 4.142 4.143 @Override 4.144 - public Node enter(final AccessNode accessNode) { 4.145 + public Node enterAccessNode(final AccessNode accessNode) { 4.146 if (!baseAlreadyOnStack) { 4.147 load(accessNode.getBase()).convert(Type.OBJECT); 4.148 } 4.149 @@ -329,7 +346,7 @@ 4.150 } 4.151 4.152 @Override 4.153 - public Node enter(final IndexNode indexNode) { 4.154 + public Node enterIndexNode(final IndexNode indexNode) { 4.155 if (!baseAlreadyOnStack) { 4.156 load(indexNode.getBase()).convert(Type.OBJECT); 4.157 load(indexNode.getIndex()); 4.158 @@ -339,6 +356,14 @@ 4.159 } 4.160 4.161 @Override 4.162 + public Node enterFunctionNode(FunctionNode functionNode) { 4.163 + // function nodes will always leave a constructed function object on stack, no need to load the symbol 4.164 + // separately as in enterDefault() 4.165 + functionNode.accept(codegen); 4.166 + return null; 4.167 + } 4.168 + 4.169 + @Override 4.170 public Node enterDefault(final Node otherNode) { 4.171 otherNode.accept(codegen); // generate code for whatever we are looking at. 4.172 method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) 4.173 @@ -350,7 +375,7 @@ 4.174 } 4.175 4.176 @Override 4.177 - public Node enter(final AccessNode accessNode) { 4.178 + public Node enterAccessNode(final AccessNode accessNode) { 4.179 if (accessNode.testResolved()) { 4.180 return null; 4.181 } 4.182 @@ -422,10 +447,11 @@ 4.183 } 4.184 4.185 @Override 4.186 - public Node enter(final Block block) { 4.187 + public Node enterBlock(final Block block) { 4.188 if (block.testResolved()) { 4.189 return null; 4.190 } 4.191 + lexicalContext.push(block); 4.192 4.193 method.label(block.getEntryLabel()); 4.194 initLocals(block); 4.195 @@ -434,14 +460,14 @@ 4.196 } 4.197 4.198 @Override 4.199 - public Node leave(final Block block) { 4.200 + public Node leaveBlock(final Block block) { 4.201 method.label(block.getBreakLabel()); 4.202 symbolInfo(block); 4.203 4.204 if (block.needsScope()) { 4.205 popBlockScope(block); 4.206 } 4.207 - 4.208 + lexicalContext.pop(block); 4.209 return block; 4.210 } 4.211 4.212 @@ -467,7 +493,7 @@ 4.213 } 4.214 4.215 @Override 4.216 - public Node enter(final BreakNode breakNode) { 4.217 + public Node enterBreakNode(final BreakNode breakNode) { 4.218 if (breakNode.testResolved()) { 4.219 return null; 4.220 } 4.221 @@ -515,14 +541,13 @@ 4.222 } 4.223 4.224 @Override 4.225 - public Node enter(final CallNode callNode) { 4.226 + public Node enterCallNode(final CallNode callNode) { 4.227 if (callNode.testResolved()) { 4.228 return null; 4.229 } 4.230 4.231 final List<Node> args = callNode.getArgs(); 4.232 final Node function = callNode.getFunction(); 4.233 - final FunctionNode currentFunction = getCurrentFunctionNode(); 4.234 final Block currentBlock = getCurrentBlock(); 4.235 4.236 function.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 4.237 @@ -531,7 +556,7 @@ 4.238 final Symbol symbol = identNode.getSymbol(); 4.239 int scopeCallFlags = flags; 4.240 method.loadScope(); 4.241 - if (symbol.isFastScope(currentFunction)) { 4.242 + if (isFastScope(symbol)) { 4.243 method.load(getScopeProtoDepth(currentBlock, symbol)); 4.244 scopeCallFlags |= CALLSITE_FAST_SCOPE; 4.245 } else { 4.246 @@ -593,7 +618,7 @@ 4.247 } 4.248 4.249 @Override 4.250 - public Node enter(final IdentNode node) { 4.251 + public Node enterIdentNode(final IdentNode node) { 4.252 final Symbol symbol = node.getSymbol(); 4.253 4.254 if (symbol.isScope()) { 4.255 @@ -606,7 +631,7 @@ 4.256 if (callNode.isEval()) { 4.257 evalCall(node, flags); 4.258 } else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD 4.259 - || (!symbol.isFastScope(currentFunction) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) 4.260 + || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD) 4.261 || callNode.inWithBlock()) { 4.262 scopeCall(node, flags); 4.263 } else { 4.264 @@ -621,7 +646,7 @@ 4.265 } 4.266 4.267 @Override 4.268 - public Node enter(final AccessNode node) { 4.269 + public Node enterAccessNode(final AccessNode node) { 4.270 load(node.getBase()); 4.271 method.convert(Type.OBJECT); 4.272 method.dup(); 4.273 @@ -634,8 +659,7 @@ 4.274 } 4.275 4.276 @Override 4.277 - public Node enter(final ReferenceNode node) { 4.278 - final FunctionNode callee = node.getReference(); 4.279 + public Node enterFunctionNode(final FunctionNode callee) { 4.280 final boolean isVarArg = callee.isVarArg(); 4.281 final int argCount = isVarArg ? -1 : callee.getParameters().size(); 4.282 4.283 @@ -653,12 +677,13 @@ 4.284 loadArgs(args, signature, isVarArg, argCount); 4.285 method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); 4.286 assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); 4.287 - 4.288 + functionNodeIsCallee = true; 4.289 + callee.accept(CodeGenerator.this); 4.290 return null; 4.291 } 4.292 4.293 @Override 4.294 - public Node enter(final IndexNode node) { 4.295 + public Node enterIndexNode(final IndexNode node) { 4.296 load(node.getBase()); 4.297 method.convert(Type.OBJECT); 4.298 method.dup(); 4.299 @@ -694,7 +719,7 @@ 4.300 } 4.301 4.302 @Override 4.303 - public Node enter(final ContinueNode continueNode) { 4.304 + public Node enterContinueNode(final ContinueNode continueNode) { 4.305 if (continueNode.testResolved()) { 4.306 return null; 4.307 } 4.308 @@ -709,17 +734,17 @@ 4.309 } 4.310 4.311 @Override 4.312 - public Node enter(final DoWhileNode doWhileNode) { 4.313 - return enter((WhileNode)doWhileNode); 4.314 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 4.315 + return enterWhileNode(doWhileNode); 4.316 } 4.317 4.318 @Override 4.319 - public Node enter(final EmptyNode emptyNode) { 4.320 + public Node enterEmptyNode(final EmptyNode emptyNode) { 4.321 return null; 4.322 } 4.323 4.324 @Override 4.325 - public Node enter(final ExecuteNode executeNode) { 4.326 + public Node enterExecuteNode(final ExecuteNode executeNode) { 4.327 if (executeNode.testResolved()) { 4.328 return null; 4.329 } 4.330 @@ -731,7 +756,7 @@ 4.331 } 4.332 4.333 @Override 4.334 - public Node enter(final ForNode forNode) { 4.335 + public Node enterForNode(final ForNode forNode) { 4.336 if (forNode.testResolved()) { 4.337 return null; 4.338 } 4.339 @@ -813,7 +838,7 @@ 4.340 * @param block block with local vars. 4.341 */ 4.342 private void initLocals(final Block block) { 4.343 - final FunctionNode function = block.getFunction(); 4.344 + final FunctionNode function = lexicalContext.getFunction(block); 4.345 final boolean isFunctionNode = block == function; 4.346 4.347 /* 4.348 @@ -915,7 +940,7 @@ 4.349 foc.makeObject(method); 4.350 4.351 // runScript(): merge scope into global 4.352 - if (isFunctionNode && function.isScript()) { 4.353 + if (isFunctionNode && function.isProgram()) { 4.354 method.invoke(ScriptRuntime.MERGE_SCOPE); 4.355 } 4.356 4.357 @@ -958,19 +983,29 @@ 4.358 } 4.359 4.360 @Override 4.361 - public Node enter(final FunctionNode functionNode) { 4.362 + public Node enterFunctionNode(final FunctionNode functionNode) { 4.363 + final boolean isCallee = functionNodeIsCallee; 4.364 + functionNodeIsCallee = false; 4.365 + 4.366 + if (functionNode.testResolved()) { 4.367 + return null; 4.368 + } 4.369 + 4.370 + if(!(isCallee || functionNode == compiler.getFunctionNode())) { 4.371 + newFunctionObject(functionNode); 4.372 + } 4.373 + 4.374 if (functionNode.isLazy()) { 4.375 return null; 4.376 } 4.377 4.378 - if (functionNode.testResolved()) { 4.379 - return null; 4.380 - } 4.381 + LOG.info("=== BEGIN " + functionNode.getName()); 4.382 + lexicalContext.push(functionNode); 4.383 4.384 setCurrentCompileUnit(functionNode.getCompileUnit()); 4.385 assert getCurrentCompileUnit() != null; 4.386 4.387 - method = getCurrentCompileUnit().getClassEmitter().method(functionNode); 4.388 + setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode)); 4.389 functionNode.setMethodEmitter(method); 4.390 // Mark end for variable tables. 4.391 method.begin(); 4.392 @@ -983,7 +1018,7 @@ 4.393 } 4.394 4.395 @Override 4.396 - public Node leave(final FunctionNode functionNode) { 4.397 + public Node leaveFunctionNode(final FunctionNode functionNode) { 4.398 // Mark end for variable tables. 4.399 method.label(functionNode.getBreakLabel()); 4.400 4.401 @@ -1001,16 +1036,18 @@ 4.402 throw e; 4.403 } 4.404 4.405 + lexicalContext.pop(functionNode); 4.406 + LOG.info("=== END " + functionNode.getName()); 4.407 return functionNode; 4.408 } 4.409 4.410 @Override 4.411 - public Node enter(final IdentNode identNode) { 4.412 + public Node enterIdentNode(final IdentNode identNode) { 4.413 return null; 4.414 } 4.415 4.416 @Override 4.417 - public Node enter(final IfNode ifNode) { 4.418 + public Node enterIfNode(final IfNode ifNode) { 4.419 if (ifNode.testResolved()) { 4.420 return null; 4.421 } 4.422 @@ -1049,7 +1086,7 @@ 4.423 } 4.424 4.425 @Override 4.426 - public Node enter(final IndexNode indexNode) { 4.427 + public Node enterIndexNode(final IndexNode indexNode) { 4.428 if (indexNode.testResolved()) { 4.429 return null; 4.430 } 4.431 @@ -1060,7 +1097,7 @@ 4.432 } 4.433 4.434 @Override 4.435 - public Node enter(final LineNumberNode lineNumberNode) { 4.436 + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 4.437 if (lineNumberNode.testResolved()) { 4.438 return null; 4.439 } 4.440 @@ -1068,7 +1105,6 @@ 4.441 final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")"); 4.442 method.label(label); 4.443 method.lineNumber(lineNumberNode.getLineNumber(), label); 4.444 - 4.445 return null; 4.446 } 4.447 4.448 @@ -1106,7 +1142,7 @@ 4.449 final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag()); 4.450 final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); 4.451 4.452 - method = getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); 4.453 + setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature)); 4.454 method.setFunctionNode(getCurrentFunctionNode()); 4.455 method.begin(); 4.456 4.457 @@ -1212,7 +1248,7 @@ 4.458 method.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); 4.459 classEmitter.needGetConstantMethod(cls); 4.460 } else { 4.461 - method.loadConstants(unitClassName).load(index).arrayload(); 4.462 + method.loadConstants().load(index).arrayload(); 4.463 if (cls != Object.class) { 4.464 method.checkcast(cls); 4.465 } 4.466 @@ -1292,14 +1328,14 @@ 4.467 4.468 @SuppressWarnings("rawtypes") 4.469 @Override 4.470 - public Node enter(final LiteralNode literalNode) { 4.471 + public Node enterLiteralNode(final LiteralNode literalNode) { 4.472 assert literalNode.getSymbol() != null : literalNode + " has no symbol"; 4.473 load(literalNode).store(literalNode.getSymbol()); 4.474 return null; 4.475 } 4.476 4.477 @Override 4.478 - public Node enter(final ObjectNode objectNode) { 4.479 + public Node enterObjectNode(final ObjectNode objectNode) { 4.480 if (objectNode.testResolved()) { 4.481 return null; 4.482 } 4.483 @@ -1372,10 +1408,10 @@ 4.484 } 4.485 4.486 for (final Node element : elements) { 4.487 - final PropertyNode propertyNode = (PropertyNode)element; 4.488 - final Object key = propertyNode.getKey(); 4.489 - final ReferenceNode getter = (ReferenceNode)propertyNode.getGetter(); 4.490 - final ReferenceNode setter = (ReferenceNode)propertyNode.getSetter(); 4.491 + final PropertyNode propertyNode = (PropertyNode)element; 4.492 + final Object key = propertyNode.getKey(); 4.493 + final FunctionNode getter = (FunctionNode)propertyNode.getGetter(); 4.494 + final FunctionNode setter = (FunctionNode)propertyNode.getSetter(); 4.495 4.496 if (getter == null && setter == null) { 4.497 continue; 4.498 @@ -1404,18 +1440,7 @@ 4.499 } 4.500 4.501 @Override 4.502 - public Node enter(final ReferenceNode referenceNode) { 4.503 - if (referenceNode.testResolved()) { 4.504 - return null; 4.505 - } 4.506 - 4.507 - newFunctionObject(referenceNode.getReference()); 4.508 - 4.509 - return null; 4.510 - } 4.511 - 4.512 - @Override 4.513 - public Node enter(final ReturnNode returnNode) { 4.514 + public Node enterReturnNode(final ReturnNode returnNode) { 4.515 if (returnNode.testResolved()) { 4.516 return null; 4.517 } 4.518 @@ -1556,7 +1581,7 @@ 4.519 } 4.520 4.521 @Override 4.522 - public Node enter(final RuntimeNode runtimeNode) { 4.523 + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 4.524 if (runtimeNode.testResolved()) { 4.525 return null; 4.526 } 4.527 @@ -1637,7 +1662,7 @@ 4.528 } 4.529 4.530 @Override 4.531 - public Node enter(final SplitNode splitNode) { 4.532 + public Node enterSplitNode(final SplitNode splitNode) { 4.533 if (splitNode.testResolved()) { 4.534 return null; 4.535 } 4.536 @@ -1706,7 +1731,7 @@ 4.537 } 4.538 4.539 @Override 4.540 - public Node leave(final SplitNode splitNode) { 4.541 + public Node leaveSplitNode(final SplitNode splitNode) { 4.542 try { 4.543 // Wrap up this method. 4.544 method.loadResult(); 4.545 @@ -1763,7 +1788,7 @@ 4.546 } 4.547 4.548 @Override 4.549 - public Node enter(final SwitchNode switchNode) { 4.550 + public Node enterSwitchNode(final SwitchNode switchNode) { 4.551 if (switchNode.testResolved()) { 4.552 return null; 4.553 } 4.554 @@ -1895,7 +1920,7 @@ 4.555 } 4.556 4.557 @Override 4.558 - public Node enter(final ThrowNode throwNode) { 4.559 + public Node enterThrowNode(final ThrowNode throwNode) { 4.560 if (throwNode.testResolved()) { 4.561 return null; 4.562 } 4.563 @@ -1922,7 +1947,7 @@ 4.564 } 4.565 4.566 @Override 4.567 - public Node enter(final TryNode tryNode) { 4.568 + public Node enterTryNode(final TryNode tryNode) { 4.569 if (tryNode.testResolved()) { 4.570 return null; 4.571 } 4.572 @@ -1955,7 +1980,7 @@ 4.573 setCurrentBlock(catchBlock); 4.574 4.575 try { 4.576 - enter(catchBlock); 4.577 + enterBlock(catchBlock); 4.578 4.579 final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); 4.580 final IdentNode exception = catchNode.getException(); 4.581 @@ -1966,6 +1991,7 @@ 4.582 // Generate catch body (inlined finally) and rethrow exception 4.583 catchBody.accept(this); 4.584 method.load(symbol).athrow(); 4.585 + lexicalContext.pop(catchBlock); 4.586 continue; 4.587 } 4.588 4.589 @@ -2012,7 +2038,7 @@ 4.590 } 4.591 } 4.592 4.593 - leave(catchBlock); 4.594 + leaveBlock(catchBlock); 4.595 } finally { 4.596 setCurrentBlock(saveBlock); 4.597 } 4.598 @@ -2027,7 +2053,7 @@ 4.599 } 4.600 4.601 @Override 4.602 - public Node enter(final VarNode varNode) { 4.603 + public Node enterVarNode(final VarNode varNode) { 4.604 final Node init = varNode.getInit(); 4.605 4.606 if (varNode.testResolved() || init == null) { 4.607 @@ -2049,7 +2075,7 @@ 4.608 int flags = CALLSITE_SCOPE | getCallSiteFlags(); 4.609 final IdentNode identNode = varNode.getName(); 4.610 final Type type = identNode.getType(); 4.611 - if (varSymbol.isFastScope(getCurrentFunctionNode())) { 4.612 + if (isFastScope(varSymbol)) { 4.613 storeFastScopeVar(type, varSymbol, flags); 4.614 } else { 4.615 method.dynamicSet(type, identNode.getName(), flags); 4.616 @@ -2065,7 +2091,7 @@ 4.617 } 4.618 4.619 @Override 4.620 - public Node enter(final WhileNode whileNode) { 4.621 + public Node enterWhileNode(final WhileNode whileNode) { 4.622 if (whileNode.testResolved()) { 4.623 return null; 4.624 } 4.625 @@ -2098,7 +2124,7 @@ 4.626 } 4.627 4.628 @Override 4.629 - public Node enter(final WithNode withNode) { 4.630 + public Node enterWithNode(final WithNode withNode) { 4.631 if (withNode.testResolved()) { 4.632 return null; 4.633 } 4.634 @@ -2864,7 +2890,7 @@ 4.635 * Ternary visits. 4.636 */ 4.637 @Override 4.638 - public Node enter(final TernaryNode ternaryNode) { 4.639 + public Node enterTernaryNode(final TernaryNode ternaryNode) { 4.640 if (ternaryNode.testResolved()) { 4.641 return null; 4.642 } 4.643 @@ -3060,7 +3086,7 @@ 4.644 4.645 target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 4.646 @Override 4.647 - public Node enter(final IdentNode node) { 4.648 + public Node enterIdentNode(final IdentNode node) { 4.649 if (targetSymbol.isScope()) { 4.650 method.load(scopeSymbol); 4.651 depth++; 4.652 @@ -3083,13 +3109,13 @@ 4.653 } 4.654 4.655 @Override 4.656 - public Node enter(final AccessNode node) { 4.657 + public Node enterAccessNode(final AccessNode node) { 4.658 enterBaseNode(); 4.659 return null; 4.660 } 4.661 4.662 @Override 4.663 - public Node enter(final IndexNode node) { 4.664 + public Node enterIndexNode(final IndexNode node) { 4.665 enterBaseNode(); 4.666 4.667 final Node index = node.getIndex(); 4.668 @@ -3155,8 +3181,6 @@ 4.669 } 4.670 4.671 private void epilogue() { 4.672 - final FunctionNode currentFunction = getCurrentFunctionNode(); 4.673 - 4.674 /** 4.675 * Take the original target args from the stack and use them 4.676 * together with the value to be stored to emit the store code 4.677 @@ -3174,7 +3198,7 @@ 4.678 } 4.679 4.680 @Override 4.681 - public Node enter(final UnaryNode node) { 4.682 + public Node enterUnaryNode(final UnaryNode node) { 4.683 if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { 4.684 method.convert(node.rhs().getType()); 4.685 } 4.686 @@ -3182,11 +3206,11 @@ 4.687 } 4.688 4.689 @Override 4.690 - public Node enter(final IdentNode node) { 4.691 + public Node enterIdentNode(final IdentNode node) { 4.692 final Symbol symbol = node.getSymbol(); 4.693 assert symbol != null; 4.694 if (symbol.isScope()) { 4.695 - if (symbol.isFastScope(currentFunction)) { 4.696 + if (isFastScope(symbol)) { 4.697 storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); 4.698 } else { 4.699 method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); 4.700 @@ -3199,13 +3223,13 @@ 4.701 } 4.702 4.703 @Override 4.704 - public Node enter(final AccessNode node) { 4.705 + public Node enterAccessNode(final AccessNode node) { 4.706 method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); 4.707 return null; 4.708 } 4.709 4.710 @Override 4.711 - public Node enter(final IndexNode node) { 4.712 + public Node enterIndexNode(final IndexNode node) { 4.713 method.dynamicSetIndex(getCallSiteFlags()); 4.714 return null; 4.715 }
5.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Tue Mar 19 11:03:24 2013 -0300 5.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Sat Mar 23 00:58:39 2013 +0100 5.3 @@ -14,16 +14,16 @@ 5.4 import java.util.EnumSet; 5.5 import java.util.HashSet; 5.6 import java.util.Set; 5.7 - 5.8 import jdk.nashorn.internal.codegen.types.Type; 5.9 import jdk.nashorn.internal.ir.CallNode; 5.10 import jdk.nashorn.internal.ir.FunctionNode; 5.11 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 5.12 +import jdk.nashorn.internal.ir.LexicalContext; 5.13 import jdk.nashorn.internal.ir.Node; 5.14 -import jdk.nashorn.internal.ir.ReferenceNode; 5.15 -import jdk.nashorn.internal.ir.visitor.NodeVisitor; 5.16 import jdk.nashorn.internal.ir.debug.ASTWriter; 5.17 import jdk.nashorn.internal.ir.debug.PrintVisitor; 5.18 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 5.19 +import jdk.nashorn.internal.ir.visitor.NodeVisitor; 5.20 import jdk.nashorn.internal.runtime.ECMAErrors; 5.21 import jdk.nashorn.internal.runtime.ScriptEnvironment; 5.22 import jdk.nashorn.internal.runtime.Timing; 5.23 @@ -65,17 +65,17 @@ 5.24 outermostFunctionNode.accept(new NodeVisitor() { 5.25 // self references are done with invokestatic and thus cannot have trampolines - never lazy 5.26 @Override 5.27 - public Node enter(final CallNode node) { 5.28 + public Node enterCallNode(final CallNode node) { 5.29 final Node callee = node.getFunction(); 5.30 - if (callee instanceof ReferenceNode) { 5.31 - neverLazy.add(((ReferenceNode)callee).getReference()); 5.32 + if (callee instanceof FunctionNode) { 5.33 + neverLazy.add(((FunctionNode)callee)); 5.34 return null; 5.35 } 5.36 return node; 5.37 } 5.38 5.39 @Override 5.40 - public Node enter(final FunctionNode node) { 5.41 + public Node enterFunctionNode(final FunctionNode node) { 5.42 if (node == outermostFunctionNode) { 5.43 return node; 5.44 } 5.45 @@ -94,15 +94,24 @@ 5.46 lazy.remove(node); 5.47 } 5.48 5.49 - for (final FunctionNode node : lazy) { 5.50 - Compiler.LOG.fine("Marking " + node.getName() + " as lazy"); 5.51 - node.setIsLazy(true); 5.52 - final FunctionNode parent = node.findParentFunction(); 5.53 - if (parent != null) { 5.54 - Compiler.LOG.fine("Marking " + parent.getName() + " as having lazy children - it needs scope for all variables"); 5.55 - parent.setHasLazyChildren(); 5.56 + outermostFunctionNode.accept(new NodeOperatorVisitor() { 5.57 + private final LexicalContext lexicalContext = new LexicalContext(); 5.58 + @Override 5.59 + public Node enterFunctionNode(FunctionNode functionNode) { 5.60 + lexicalContext.push(functionNode); 5.61 + if(lazy.contains(functionNode)) { 5.62 + Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy"); 5.63 + functionNode.setIsLazy(true); 5.64 + lexicalContext.getParentFunction(functionNode).setHasLazyChildren(); 5.65 + } 5.66 + return functionNode; 5.67 } 5.68 - } 5.69 + @Override 5.70 + public Node leaveFunctionNode(FunctionNode functionNode) { 5.71 + lexicalContext.pop(functionNode); 5.72 + return functionNode; 5.73 + } 5.74 + }); 5.75 } 5.76 5.77 @Override 5.78 @@ -241,6 +250,16 @@ 5.79 final CodeGenerator codegen = new CodeGenerator(compiler); 5.80 fn.accept(codegen); 5.81 codegen.generateScopeCalls(); 5.82 + fn.accept(new NodeOperatorVisitor() { 5.83 + @Override 5.84 + public Node enterFunctionNode(FunctionNode functionNode) { 5.85 + if(functionNode.isLazy()) { 5.86 + functionNode.resetResolved(); 5.87 + return null; 5.88 + } 5.89 + return fn; 5.90 + } 5.91 + }); 5.92 5.93 } catch (final VerifyError e) { 5.94 if (env._verify_code || env._print_code) {
6.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Tue Mar 19 11:03:24 2013 -0300 6.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Sat Mar 23 00:58:39 2013 +0100 6.3 @@ -46,7 +46,6 @@ 6.4 import java.util.Map.Entry; 6.5 import java.util.Set; 6.6 import java.util.logging.Level; 6.7 - 6.8 import jdk.internal.dynalink.support.NameCodec; 6.9 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 6.10 import jdk.nashorn.internal.codegen.types.Type; 6.11 @@ -383,7 +382,7 @@ 6.12 6.13 functionNode.accept(new NodeVisitor() { 6.14 @Override 6.15 - public Node enter(final FunctionNode node) { 6.16 + public Node enterFunctionNode(final FunctionNode node) { 6.17 if (node.isLazy()) { 6.18 return null; 6.19 }
7.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Tue Mar 19 11:03:24 2013 -0300 7.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Sat Mar 23 00:58:39 2013 +0100 7.3 @@ -34,20 +34,20 @@ 7.4 import jdk.nashorn.internal.ir.Block; 7.5 import jdk.nashorn.internal.ir.CallNode; 7.6 import jdk.nashorn.internal.ir.CallNode.EvalArgs; 7.7 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 7.8 import jdk.nashorn.internal.ir.CaseNode; 7.9 import jdk.nashorn.internal.ir.CatchNode; 7.10 import jdk.nashorn.internal.ir.DoWhileNode; 7.11 import jdk.nashorn.internal.ir.ExecuteNode; 7.12 import jdk.nashorn.internal.ir.ForNode; 7.13 import jdk.nashorn.internal.ir.FunctionNode; 7.14 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 7.15 import jdk.nashorn.internal.ir.IdentNode; 7.16 import jdk.nashorn.internal.ir.IfNode; 7.17 import jdk.nashorn.internal.ir.IndexNode; 7.18 +import jdk.nashorn.internal.ir.LexicalContext; 7.19 import jdk.nashorn.internal.ir.LiteralNode; 7.20 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 7.21 import jdk.nashorn.internal.ir.Node; 7.22 -import jdk.nashorn.internal.ir.ReferenceNode; 7.23 import jdk.nashorn.internal.ir.ReturnNode; 7.24 import jdk.nashorn.internal.ir.RuntimeNode; 7.25 import jdk.nashorn.internal.ir.RuntimeNode.Request; 7.26 @@ -85,11 +85,13 @@ 7.27 7.28 private static final DebugLogger LOG = new DebugLogger("finalize"); 7.29 7.30 + private final LexicalContext lexicalContext = new LexicalContext(); 7.31 + 7.32 FinalizeTypes() { 7.33 } 7.34 7.35 @Override 7.36 - public Node leave(final CallNode callNode) { 7.37 + public Node leaveCallNode(final CallNode callNode) { 7.38 final EvalArgs evalArgs = callNode.getEvalArgs(); 7.39 if (evalArgs != null) { 7.40 evalArgs.setCode(evalArgs.getCode().accept(this)); 7.41 @@ -97,15 +99,14 @@ 7.42 7.43 // AccessSpecializer - call return type may change the access for this location 7.44 final Node function = callNode.getFunction(); 7.45 - if (function instanceof ReferenceNode) { 7.46 - setTypeOverride(callNode, ((ReferenceNode)function).getReference().getType()); 7.47 + if (function instanceof FunctionNode) { 7.48 + return setTypeOverride(callNode, ((FunctionNode)function).getReturnType()); 7.49 } 7.50 return callNode; 7.51 } 7.52 7.53 private Node leaveUnary(final UnaryNode unaryNode) { 7.54 - unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType())); 7.55 - return unaryNode; 7.56 + return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType())); 7.57 } 7.58 7.59 @Override 7.60 @@ -126,8 +127,7 @@ 7.61 7.62 @Override 7.63 public Node leaveDECINC(final UnaryNode unaryNode) { 7.64 - specialize(unaryNode); 7.65 - return unaryNode; 7.66 + return specialize(unaryNode).node; 7.67 } 7.68 7.69 @Override 7.70 @@ -159,9 +159,7 @@ 7.71 } 7.72 } 7.73 7.74 - binaryNode.setLHS(convert(lhs, type)); 7.75 - binaryNode.setRHS(convert(rhs, type)); 7.76 - return binaryNode; 7.77 + return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type)); 7.78 } 7.79 7.80 @Override 7.81 @@ -171,12 +169,13 @@ 7.82 7.83 @Override 7.84 public Node leaveASSIGN(final BinaryNode binaryNode) { 7.85 - Type destType = specialize(binaryNode); 7.86 + final SpecializedNode specialized = specialize(binaryNode); 7.87 + final BinaryNode specBinaryNode = (BinaryNode)specialized.node; 7.88 + Type destType = specialized.type; 7.89 if (destType == null) { 7.90 - destType = binaryNode.getType(); 7.91 + destType = specBinaryNode.getType(); 7.92 } 7.93 - binaryNode.setRHS(convert(binaryNode.rhs(), destType)); 7.94 - return binaryNode; 7.95 + return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType)); 7.96 } 7.97 7.98 @Override 7.99 @@ -255,21 +254,21 @@ 7.100 @Override 7.101 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 7.102 assert binaryNode.getSymbol() != null; 7.103 - binaryNode.setRHS(discard(binaryNode.rhs())); 7.104 + final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs())); 7.105 // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed 7.106 // in that case, update the node type as well 7.107 - propagateType(binaryNode, binaryNode.lhs().getType()); 7.108 - return binaryNode; 7.109 + propagateType(newBinaryNode, newBinaryNode.lhs().getType()); 7.110 + return newBinaryNode; 7.111 } 7.112 7.113 @Override 7.114 public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { 7.115 assert binaryNode.getSymbol() != null; 7.116 - binaryNode.setLHS(discard(binaryNode.lhs())); 7.117 + final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs())); 7.118 // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed 7.119 // in that case, update the node type as well 7.120 - propagateType(binaryNode, binaryNode.rhs().getType()); 7.121 - return binaryNode; 7.122 + propagateType(newBinaryNode, newBinaryNode.rhs().getType()); 7.123 + return newBinaryNode; 7.124 } 7.125 7.126 @Override 7.127 @@ -355,13 +354,20 @@ 7.128 } 7.129 7.130 @Override 7.131 - public Node enter(final Block block) { 7.132 + public Node enterBlock(final Block block) { 7.133 + lexicalContext.push(block); 7.134 updateSymbols(block); 7.135 return block; 7.136 } 7.137 7.138 @Override 7.139 - public Node leave(final CatchNode catchNode) { 7.140 + public Node leaveBlock(Block block) { 7.141 + lexicalContext.pop(block); 7.142 + return super.leaveBlock(block); 7.143 + } 7.144 + 7.145 + @Override 7.146 + public Node leaveCatchNode(final CatchNode catchNode) { 7.147 final Node exceptionCondition = catchNode.getExceptionCondition(); 7.148 if (exceptionCondition != null) { 7.149 catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); 7.150 @@ -370,23 +376,23 @@ 7.151 } 7.152 7.153 @Override 7.154 - public Node enter(final DoWhileNode doWhileNode) { 7.155 - return enter((WhileNode)doWhileNode); 7.156 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 7.157 + return enterWhileNode(doWhileNode); 7.158 } 7.159 7.160 @Override 7.161 - public Node leave(final DoWhileNode doWhileNode) { 7.162 - return leave((WhileNode)doWhileNode); 7.163 + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 7.164 + return leaveWhileNode(doWhileNode); 7.165 } 7.166 7.167 @Override 7.168 - public Node leave(final ExecuteNode executeNode) { 7.169 + public Node leaveExecuteNode(final ExecuteNode executeNode) { 7.170 executeNode.setExpression(discard(executeNode.getExpression())); 7.171 return executeNode; 7.172 } 7.173 7.174 @Override 7.175 - public Node leave(final ForNode forNode) { 7.176 + public Node leaveForNode(final ForNode forNode) { 7.177 final Node init = forNode.getInit(); 7.178 final Node test = forNode.getTest(); 7.179 final Node modify = forNode.getModify(); 7.180 @@ -414,11 +420,12 @@ 7.181 } 7.182 7.183 @Override 7.184 - public Node enter(final FunctionNode functionNode) { 7.185 + public Node enterFunctionNode(final FunctionNode functionNode) { 7.186 if (functionNode.isLazy()) { 7.187 return null; 7.188 } 7.189 7.190 + lexicalContext.push(functionNode); 7.191 // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do 7.192 // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the 7.193 // need for the callee. 7.194 @@ -439,14 +446,20 @@ 7.195 } 7.196 7.197 @Override 7.198 - public Node leave(final IfNode ifNode) { 7.199 + public Node leaveFunctionNode(FunctionNode functionNode) { 7.200 + lexicalContext.pop(functionNode); 7.201 + return super.leaveFunctionNode(functionNode); 7.202 + } 7.203 + 7.204 + @Override 7.205 + public Node leaveIfNode(final IfNode ifNode) { 7.206 ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); 7.207 return ifNode; 7.208 } 7.209 7.210 @SuppressWarnings("rawtypes") 7.211 @Override 7.212 - public Node enter(final LiteralNode literalNode) { 7.213 + public Node enterLiteralNode(final LiteralNode literalNode) { 7.214 if (literalNode instanceof ArrayLiteralNode) { 7.215 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; 7.216 final Node[] array = arrayLiteralNode.getValue(); 7.217 @@ -464,7 +477,7 @@ 7.218 } 7.219 7.220 @Override 7.221 - public Node leave(final ReturnNode returnNode) { 7.222 + public Node leaveReturnNode(final ReturnNode returnNode) { 7.223 final Node expr = returnNode.getExpression(); 7.224 if (expr != null) { 7.225 returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType())); 7.226 @@ -473,7 +486,7 @@ 7.227 } 7.228 7.229 @Override 7.230 - public Node leave(final RuntimeNode runtimeNode) { 7.231 + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 7.232 final List<Node> args = runtimeNode.getArgs(); 7.233 for (final Node arg : args) { 7.234 assert !arg.getType().isUnknown(); 7.235 @@ -482,7 +495,7 @@ 7.236 } 7.237 7.238 @Override 7.239 - public Node leave(final SwitchNode switchNode) { 7.240 + public Node leaveSwitchNode(final SwitchNode switchNode) { 7.241 final Node expression = switchNode.getExpression(); 7.242 final List<CaseNode> cases = switchNode.getCases(); 7.243 final boolean allInteger = switchNode.getTag().getSymbolType().isInteger(); 7.244 @@ -501,33 +514,34 @@ 7.245 } 7.246 7.247 @Override 7.248 - public Node leave(final TernaryNode ternaryNode) { 7.249 - ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN)); 7.250 - return ternaryNode; 7.251 + public Node leaveTernaryNode(final TernaryNode ternaryNode) { 7.252 + return ternaryNode.setLHS(convert(ternaryNode.lhs(), Type.BOOLEAN)); 7.253 } 7.254 7.255 @Override 7.256 - public Node leave(final ThrowNode throwNode) { 7.257 + public Node leaveThrowNode(final ThrowNode throwNode) { 7.258 throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT)); 7.259 return throwNode; 7.260 } 7.261 7.262 @Override 7.263 - public Node leave(final VarNode varNode) { 7.264 + public Node leaveVarNode(final VarNode varNode) { 7.265 final Node rhs = varNode.getInit(); 7.266 if (rhs != null) { 7.267 - Type destType = specialize(varNode); 7.268 + final SpecializedNode specialized = specialize(varNode); 7.269 + final VarNode specVarNode = (VarNode)specialized.node; 7.270 + Type destType = specialized.type; 7.271 if (destType == null) { 7.272 - destType = varNode.getType(); 7.273 + destType = specVarNode.getType(); 7.274 } 7.275 - assert varNode.hasType() : varNode + " doesn't have a type"; 7.276 - varNode.setInit(convert(rhs, destType)); 7.277 + assert specVarNode.hasType() : specVarNode + " doesn't have a type"; 7.278 + return specVarNode.setInit(convert(rhs, destType)); 7.279 } 7.280 return varNode; 7.281 } 7.282 7.283 @Override 7.284 - public Node leave(final WhileNode whileNode) { 7.285 + public Node leaveWhileNode(final WhileNode whileNode) { 7.286 final Node test = whileNode.getTest(); 7.287 if (test != null) { 7.288 whileNode.setTest(convert(test, Type.BOOLEAN)); 7.289 @@ -536,7 +550,7 @@ 7.290 } 7.291 7.292 @Override 7.293 - public Node leave(final WithNode withNode) { 7.294 + public Node leaveWithNode(final WithNode withNode) { 7.295 withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT)); 7.296 return withNode; 7.297 } 7.298 @@ -555,14 +569,14 @@ 7.299 * that scope and slot information is correct for every symbol 7.300 * @param block block for which to to finalize type info. 7.301 */ 7.302 - private static void updateSymbols(final Block block) { 7.303 + private void updateSymbols(final Block block) { 7.304 if (!block.needsScope()) { 7.305 return; // nothing to do 7.306 } 7.307 7.308 - assert !(block instanceof FunctionNode) || block.getFunction() == block; 7.309 + final FunctionNode functionNode = lexicalContext.getFunction(block); 7.310 + assert !(block instanceof FunctionNode) || functionNode == block; 7.311 7.312 - final FunctionNode functionNode = block.getFunction(); 7.313 final List<Symbol> symbols = block.getFrame().getSymbols(); 7.314 final boolean allVarsInScope = functionNode.allVarsInScope(); 7.315 final boolean isVarArg = functionNode.isVarArg(); 7.316 @@ -631,10 +645,7 @@ 7.317 break; 7.318 } 7.319 7.320 - binaryNode.setLHS(convert(lhs, widest)); 7.321 - binaryNode.setRHS(convert(rhs, widest)); 7.322 - 7.323 - return binaryNode; 7.324 + return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest)); 7.325 } 7.326 7.327 /** 7.328 @@ -656,9 +667,7 @@ 7.329 } 7.330 7.331 private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) { 7.332 - binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)); 7.333 - binaryNode.setRHS(convert(binaryNode.rhs(), rhsType)); 7.334 - return binaryNode; 7.335 + return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType)); 7.336 } 7.337 7.338 /** 7.339 @@ -679,7 +688,7 @@ 7.340 } 7.341 7.342 @Override 7.343 - public Node enter(final IdentNode identNode) { 7.344 + public Node enterIdentNode(final IdentNode identNode) { 7.345 if (!exclude.contains(identNode)) { 7.346 setCanBePrimitive(identNode.getSymbol()); 7.347 } 7.348 @@ -687,26 +696,36 @@ 7.349 } 7.350 7.351 @Override 7.352 - public Node enter(final AccessNode accessNode) { 7.353 + public Node enterAccessNode(final AccessNode accessNode) { 7.354 setCanBePrimitive(accessNode.getProperty().getSymbol()); 7.355 return null; 7.356 } 7.357 7.358 @Override 7.359 - public Node enter(final IndexNode indexNode) { 7.360 + public Node enterIndexNode(final IndexNode indexNode) { 7.361 exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine 7.362 return indexNode; 7.363 } 7.364 }); 7.365 } 7.366 7.367 - private static Type specialize(final Assignment<?> assignment) { 7.368 + private static class SpecializedNode { 7.369 + final Node node; 7.370 + final Type type; 7.371 + 7.372 + SpecializedNode(Node node, Type type) { 7.373 + this.node = node; 7.374 + this.type = type; 7.375 + } 7.376 + } 7.377 + 7.378 + private static <T extends Node> SpecializedNode specialize(final Assignment<T> assignment) { 7.379 final Node node = ((Node)assignment); 7.380 - final Node lhs = assignment.getAssignmentDest(); 7.381 + final T lhs = assignment.getAssignmentDest(); 7.382 final Node rhs = assignment.getAssignmentSource(); 7.383 7.384 if (!canHaveCallSiteType(lhs)) { 7.385 - return null; 7.386 + return new SpecializedNode(node, null); 7.387 } 7.388 7.389 final Type to; 7.390 @@ -718,13 +737,13 @@ 7.391 7.392 if (!isSupportedCallSiteType(to)) { 7.393 //meaningless to specialize to boolean or object 7.394 - return null; 7.395 + return new SpecializedNode(node, null); 7.396 } 7.397 7.398 - setTypeOverride(lhs, to); 7.399 - propagateType(node, to); 7.400 + final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); 7.401 + propagateType(newNode, to); 7.402 7.403 - return to; 7.404 + return new SpecializedNode(newNode, to); 7.405 } 7.406 7.407 7.408 @@ -736,7 +755,7 @@ 7.409 * @return true if node can have a callsite type 7.410 */ 7.411 private static boolean canHaveCallSiteType(final Node node) { 7.412 - return node instanceof TypeOverride && ((TypeOverride)node).canHaveCallSiteType(); 7.413 + return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType(); 7.414 } 7.415 7.416 /** 7.417 @@ -762,7 +781,8 @@ 7.418 * @param node node for which to change type 7.419 * @param to new type 7.420 */ 7.421 - private static void setTypeOverride(final Node node, final Type to) { 7.422 + @SuppressWarnings("unchecked") 7.423 + private static <T extends Node> T setTypeOverride(final T node, final Type to) { 7.424 final Type from = node.getType(); 7.425 if (!node.getType().equals(to)) { 7.426 LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to); 7.427 @@ -771,7 +791,7 @@ 7.428 } 7.429 } 7.430 LOG.info("Type override for lhs in '" + node + "' => " + to); 7.431 - ((TypeOverride)node).setType(to); 7.432 + return ((TypeOverride<T>)node).setType(to); 7.433 } 7.434 7.435 /** 7.436 @@ -816,8 +836,8 @@ 7.437 } 7.438 } else { 7.439 if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) { 7.440 - setTypeOverride(node, to); 7.441 - return resultNode; 7.442 + assert node instanceof TypeOverride; 7.443 + return setTypeOverride(node, to); 7.444 } 7.445 resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node); 7.446 }
8.1 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Mar 19 11:03:24 2013 -0300 8.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Sat Mar 23 00:58:39 2013 +0100 8.3 @@ -31,12 +31,12 @@ 8.4 import jdk.nashorn.internal.ir.EmptyNode; 8.5 import jdk.nashorn.internal.ir.ExecuteNode; 8.6 import jdk.nashorn.internal.ir.FunctionNode; 8.7 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 8.8 import jdk.nashorn.internal.ir.IfNode; 8.9 import jdk.nashorn.internal.ir.LiteralNode; 8.10 import jdk.nashorn.internal.ir.Node; 8.11 import jdk.nashorn.internal.ir.TernaryNode; 8.12 import jdk.nashorn.internal.ir.UnaryNode; 8.13 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 8.14 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 8.15 import jdk.nashorn.internal.runtime.DebugLogger; 8.16 import jdk.nashorn.internal.runtime.JSType; 8.17 @@ -54,7 +54,7 @@ 8.18 } 8.19 8.20 @Override 8.21 - public Node leave(final UnaryNode unaryNode) { 8.22 + public Node leaveUnaryNode(final UnaryNode unaryNode) { 8.23 final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval(); 8.24 if (literalNode != null) { 8.25 LOG.info("Unary constant folded " + unaryNode + " to " + literalNode); 8.26 @@ -64,7 +64,7 @@ 8.27 } 8.28 8.29 @Override 8.30 - public Node leave(final BinaryNode binaryNode) { 8.31 + public Node leaveBinaryNode(final BinaryNode binaryNode) { 8.32 final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval(); 8.33 if (literalNode != null) { 8.34 LOG.info("Binary constant folded " + binaryNode + " to " + literalNode); 8.35 @@ -74,7 +74,7 @@ 8.36 } 8.37 8.38 @Override 8.39 - public Node enter(final FunctionNode functionNode) { 8.40 + public Node enterFunctionNode(final FunctionNode functionNode) { 8.41 if (functionNode.isLazy()) { 8.42 return null; 8.43 } 8.44 @@ -82,13 +82,13 @@ 8.45 } 8.46 8.47 @Override 8.48 - public Node leave(final FunctionNode functionNode) { 8.49 + public Node leaveFunctionNode(final FunctionNode functionNode) { 8.50 functionNode.setState(CompilationState.CONSTANT_FOLDED); 8.51 return functionNode; 8.52 } 8.53 8.54 @Override 8.55 - public Node leave(final IfNode ifNode) { 8.56 + public Node leaveIfNode(final IfNode ifNode) { 8.57 final Node test = ifNode.getTest(); 8.58 if (test instanceof LiteralNode) { 8.59 final Block shortCut = ((LiteralNode<?>)test).isTrue() ? ifNode.getPass() : ifNode.getFail(); 8.60 @@ -101,7 +101,7 @@ 8.61 } 8.62 8.63 @Override 8.64 - public Node leave(final TernaryNode ternaryNode) { 8.65 + public Node leaveTernaryNode(final TernaryNode ternaryNode) { 8.66 final Node test = ternaryNode.lhs(); 8.67 if (test instanceof LiteralNode) { 8.68 return ((LiteralNode<?>)test).isTrue() ? ternaryNode.rhs() : ternaryNode.third();
9.1 --- a/src/jdk/nashorn/internal/codegen/FunctionSignature.java Tue Mar 19 11:03:24 2013 -0300 9.2 +++ b/src/jdk/nashorn/internal/codegen/FunctionSignature.java Sat Mar 23 00:58:39 2013 +0100 9.3 @@ -155,7 +155,7 @@ 9.4 true, 9.5 functionNode.needsCallee(), 9.6 functionNode.getReturnType(), 9.7 - (functionNode.isVarArg() && !functionNode.isScript()) ? 9.8 + (functionNode.isVarArg() && !functionNode.isProgram()) ? 9.9 null : 9.10 functionNode.getParameters()); 9.11 }
10.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java Tue Mar 19 11:03:24 2013 -0300 10.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Sat Mar 23 00:58:39 2013 +0100 10.3 @@ -37,8 +37,8 @@ 10.4 import java.util.ArrayList; 10.5 import java.util.Arrays; 10.6 import java.util.Deque; 10.7 +import java.util.Iterator; 10.8 import java.util.List; 10.9 -import jdk.nashorn.internal.ir.AccessNode; 10.10 import jdk.nashorn.internal.ir.BaseNode; 10.11 import jdk.nashorn.internal.ir.BinaryNode; 10.12 import jdk.nashorn.internal.ir.Block; 10.13 @@ -52,11 +52,12 @@ 10.14 import jdk.nashorn.internal.ir.ExecuteNode; 10.15 import jdk.nashorn.internal.ir.ForNode; 10.16 import jdk.nashorn.internal.ir.FunctionNode; 10.17 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 10.18 import jdk.nashorn.internal.ir.IdentNode; 10.19 import jdk.nashorn.internal.ir.IfNode; 10.20 -import jdk.nashorn.internal.ir.IndexNode; 10.21 import jdk.nashorn.internal.ir.LabelNode; 10.22 import jdk.nashorn.internal.ir.LabeledNode; 10.23 +import jdk.nashorn.internal.ir.LexicalContext; 10.24 import jdk.nashorn.internal.ir.LineNumberNode; 10.25 import jdk.nashorn.internal.ir.LiteralNode; 10.26 import jdk.nashorn.internal.ir.Node; 10.27 @@ -69,7 +70,6 @@ 10.28 import jdk.nashorn.internal.ir.VarNode; 10.29 import jdk.nashorn.internal.ir.WhileNode; 10.30 import jdk.nashorn.internal.ir.WithNode; 10.31 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 10.32 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 10.33 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 10.34 import jdk.nashorn.internal.parser.Token; 10.35 @@ -103,6 +103,8 @@ 10.36 10.37 private List<Node> statements; 10.38 10.39 + private LexicalContext lexicalContext = new LexicalContext(); 10.40 + 10.41 /** 10.42 * Constructor. 10.43 * 10.44 @@ -114,14 +116,15 @@ 10.45 } 10.46 10.47 @Override 10.48 - public Node enter(final Block block) { 10.49 + public Node enterBlock(final Block block) { 10.50 final Node savedLastStatement = lastStatement; 10.51 final List<Node> savedStatements = statements; 10.52 - 10.53 + lexicalContext.push(block); 10.54 try { 10.55 this.statements = new ArrayList<>(); 10.56 + NodeVisitor visitor = this; 10.57 for (final Node statement : block.getStatements()) { 10.58 - statement.accept(this); 10.59 + statement.accept(visitor); 10.60 /* 10.61 * This is slightly unsound, for example if we have a loop with 10.62 * a guarded statement like if (x) continue in the body and the 10.63 @@ -133,7 +136,7 @@ 10.64 */ 10.65 if (lastStatement != null && lastStatement.isTerminal()) { 10.66 copyTerminal(block, lastStatement); 10.67 - break; 10.68 + visitor = new DeadCodeVarDeclarationVisitor(); 10.69 } 10.70 } 10.71 block.setStatements(statements); 10.72 @@ -141,18 +144,19 @@ 10.73 } finally { 10.74 this.statements = savedStatements; 10.75 this.lastStatement = savedLastStatement; 10.76 + lexicalContext.pop(block); 10.77 } 10.78 10.79 return null; 10.80 } 10.81 10.82 @Override 10.83 - public Node enter(final BreakNode breakNode) { 10.84 + public Node enterBreakNode(final BreakNode breakNode) { 10.85 return enterBreakOrContinue(breakNode); 10.86 } 10.87 10.88 @Override 10.89 - public Node enter(final CallNode callNode) { 10.90 + public Node enterCallNode(final CallNode callNode) { 10.91 final Node function = markerFunction(callNode.getFunction()); 10.92 callNode.setFunction(function); 10.93 checkEval(callNode); //check if this is an eval call and store the information 10.94 @@ -160,44 +164,44 @@ 10.95 } 10.96 10.97 @Override 10.98 - public Node leave(final CaseNode caseNode) { 10.99 + public Node leaveCaseNode(final CaseNode caseNode) { 10.100 caseNode.copyTerminalFlags(caseNode.getBody()); 10.101 return caseNode; 10.102 } 10.103 10.104 @Override 10.105 - public Node leave(final CatchNode catchNode) { 10.106 + public Node leaveCatchNode(final CatchNode catchNode) { 10.107 catchNode.copyTerminalFlags(catchNode.getBody()); 10.108 addStatement(catchNode); 10.109 return catchNode; 10.110 } 10.111 10.112 @Override 10.113 - public Node enter(final ContinueNode continueNode) { 10.114 + public Node enterContinueNode(final ContinueNode continueNode) { 10.115 return enterBreakOrContinue(continueNode); 10.116 } 10.117 10.118 @Override 10.119 - public Node enter(final DoWhileNode doWhileNode) { 10.120 - return enter((WhileNode)doWhileNode); 10.121 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 10.122 + return enterWhileNode(doWhileNode); 10.123 } 10.124 10.125 @Override 10.126 - public Node leave(final DoWhileNode doWhileNode) { 10.127 - return leave((WhileNode)doWhileNode); 10.128 + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 10.129 + return leaveWhileNode(doWhileNode); 10.130 } 10.131 10.132 @Override 10.133 - public Node enter(final EmptyNode emptyNode) { 10.134 + public Node enterEmptyNode(final EmptyNode emptyNode) { 10.135 return null; 10.136 } 10.137 10.138 @Override 10.139 - public Node leave(final ExecuteNode executeNode) { 10.140 + public Node leaveExecuteNode(final ExecuteNode executeNode) { 10.141 final Node expr = executeNode.getExpression(); 10.142 10.143 - if (getCurrentFunctionNode().isScript()) { 10.144 - if (!(expr instanceof Block)) { 10.145 + if (getCurrentFunctionNode().isProgram()) { 10.146 + if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function 10.147 if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { 10.148 executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN), 10.149 getCurrentFunctionNode().getResultNode(), 10.150 @@ -213,13 +217,13 @@ 10.151 } 10.152 10.153 @Override 10.154 - public Node enter(final ForNode forNode) { 10.155 + public Node enterForNode(final ForNode forNode) { 10.156 nest(forNode); 10.157 return forNode; 10.158 } 10.159 10.160 @Override 10.161 - public Node leave(final ForNode forNode) { 10.162 + public Node leaveForNode(final ForNode forNode) { 10.163 final Node test = forNode.getTest(); 10.164 final Block body = forNode.getBody(); 10.165 10.166 @@ -247,18 +251,16 @@ 10.167 } 10.168 10.169 @Override 10.170 - public Node enter(final FunctionNode functionNode) { 10.171 + public Node enterFunctionNode(final FunctionNode functionNode) { 10.172 LOG.info("START FunctionNode: " + functionNode.getName()); 10.173 10.174 if (functionNode.isLazy()) { 10.175 LOG.info("LAZY: " + functionNode.getName()); 10.176 return null; 10.177 } 10.178 - 10.179 + lexicalContext.push(functionNode); 10.180 initFunctionNode(functionNode); 10.181 10.182 - Node initialEvalResult = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED); 10.183 - 10.184 nest(functionNode); 10.185 10.186 /* 10.187 @@ -272,60 +274,40 @@ 10.188 statements = new ArrayList<>(); 10.189 lastStatement = null; 10.190 10.191 - // for initial eval result is the last declared function 10.192 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 10.193 - final IdentNode ident = nestedFunction.getIdent(); 10.194 - if (ident != null && nestedFunction.isStatement()) { 10.195 - initialEvalResult = new IdentNode(ident); 10.196 - } 10.197 - } 10.198 - 10.199 if (functionNode.needsSelfSymbol()) { 10.200 //function needs to start with var funcIdent = __callee_; 10.201 statements.add(functionNode.getSelfSymbolInit().accept(this)); 10.202 } 10.203 10.204 + NodeVisitor visitor = this; 10.205 try { 10.206 - // Every nested function needs a definition in the outer function with its name. Add these. 10.207 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 10.208 - final VarNode varNode = nestedFunction.getFunctionVarNode(); 10.209 - if (varNode != null) { 10.210 - final LineNumberNode lineNumberNode = nestedFunction.getFunctionVarLineNumberNode(); 10.211 - if (lineNumberNode != null) { 10.212 - lineNumberNode.accept(this); 10.213 - } 10.214 - varNode.accept(this); 10.215 - varNode.setIsFunctionVarNode(); 10.216 + //do the statements - this fills the block with code 10.217 + boolean needsInitialEvalResult = functionNode.isProgram(); 10.218 + for (final Node statement : functionNode.getStatements()) { 10.219 + // If this function is a program, then insert an assignment to the initial eval result after all 10.220 + // function declarations. 10.221 + if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) { 10.222 + addInitialEvalResult(functionNode); 10.223 + needsInitialEvalResult = false; 10.224 } 10.225 - } 10.226 - 10.227 - if (functionNode.isScript()) { 10.228 - new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), initialEvalResult).accept(this); 10.229 - } 10.230 - 10.231 - //do the statements - this fills the block with code 10.232 - for (final Node statement : functionNode.getStatements()) { 10.233 - statement.accept(this); 10.234 + statement.accept(visitor); 10.235 //If there are unused terminated endpoints in the function, we need 10.236 // to add a "return undefined" in those places for correct semantics 10.237 LOG.info("Checking lastStatement="+lastStatement+" for terminal flags"); 10.238 if (lastStatement != null && lastStatement.hasTerminalFlags()) { 10.239 copyTerminal(functionNode, lastStatement); 10.240 - break; 10.241 + assert !needsInitialEvalResult; 10.242 + visitor = new DeadCodeVarDeclarationVisitor(); 10.243 } 10.244 } 10.245 - 10.246 + if(needsInitialEvalResult) { 10.247 + addInitialEvalResult(functionNode); 10.248 + } 10.249 functionNode.setStatements(statements); 10.250 10.251 if (!functionNode.isTerminal()) { 10.252 guaranteeReturn(functionNode); 10.253 } 10.254 - 10.255 - //lower all nested functions 10.256 - for (final FunctionNode nestedFunction : functionNode.getFunctions()) { 10.257 - nestedFunction.accept(this); 10.258 - } 10.259 - 10.260 } finally { 10.261 statements = savedStatements; 10.262 lastStatement = savedLastStatement; 10.263 @@ -333,19 +315,67 @@ 10.264 10.265 LOG.info("END FunctionNode: " + functionNode.getName()); 10.266 unnest(functionNode); 10.267 + lexicalContext.pop(functionNode); 10.268 10.269 functionNode.setState(CompilationState.LOWERED); 10.270 10.271 return null; 10.272 } 10.273 10.274 + /** 10.275 + * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the 10.276 + * var declarations in them still have the effect of declaring a local variable on the function level. Therefore, 10.277 + * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their 10.278 + * initializers are wiped out as those are, in fact, dead code. 10.279 + */ 10.280 + private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor { 10.281 + DeadCodeVarDeclarationVisitor() { 10.282 + } 10.283 + 10.284 + @Override 10.285 + public Node enterVarNode(VarNode varNode) { 10.286 + // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was 10.287 + // encountered, and all function declarations precede any terminal statements. 10.288 + assert !varNode.isFunctionDeclaration(); 10.289 + if(varNode.getInit() == null) { 10.290 + // No initializer, just pass it to Lower. 10.291 + return varNode.accept(Lower.this); 10.292 + } 10.293 + // Wipe out the initializer and then pass it to Lower. 10.294 + return varNode.setInit(null).accept(Lower.this); 10.295 + } 10.296 + } 10.297 + 10.298 + private void addInitialEvalResult(final FunctionNode functionNode) { 10.299 + new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), 10.300 + getInitialEvalResult(functionNode)).accept(this); 10.301 + } 10.302 + 10.303 + /** 10.304 + * Result of initial result of evaluating a particular program, which is either the last function it declares, or 10.305 + * undefined if it doesn't declare any functions. 10.306 + * @param program 10.307 + * @return the initial result of evaluating the program 10.308 + */ 10.309 + private static Node getInitialEvalResult(final FunctionNode program) { 10.310 + IdentNode lastFnName = null; 10.311 + for (final FunctionNode fn : program.getDeclaredFunctions()) { 10.312 + assert fn.isDeclared(); 10.313 + final IdentNode fnName = fn.getIdent(); 10.314 + if(fnName != null) { 10.315 + lastFnName = fnName; 10.316 + } 10.317 + } 10.318 + return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED); 10.319 + } 10.320 + 10.321 @Override 10.322 - public Node enter(final IfNode ifNode) { 10.323 + public Node enterIfNode(final IfNode ifNode) { 10.324 return nest(ifNode); 10.325 } 10.326 10.327 @Override 10.328 - public Node leave(final IfNode ifNode) { 10.329 + public Node leaveIfNode(final IfNode ifNode) { 10.330 final Node pass = ifNode.getPass(); 10.331 final Node fail = ifNode.getFail(); 10.332 10.333 @@ -360,7 +390,7 @@ 10.334 } 10.335 10.336 @Override 10.337 - public Node enter(LabelNode labelNode) { 10.338 + public Node enterLabelNode(LabelNode labelNode) { 10.339 final Block body = labelNode.getBody(); 10.340 body.accept(this); 10.341 copyTerminal(labelNode, body); 10.342 @@ -369,13 +399,13 @@ 10.343 } 10.344 10.345 @Override 10.346 - public Node enter(final LineNumberNode lineNumberNode) { 10.347 + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 10.348 addStatement(lineNumberNode, false); // don't put it in lastStatement cache 10.349 return null; 10.350 } 10.351 10.352 @Override 10.353 - public Node enter(final ReturnNode returnNode) { 10.354 + public Node enterReturnNode(final ReturnNode returnNode) { 10.355 final TryNode tryNode = returnNode.getTryChain(); 10.356 final Node expr = returnNode.getExpression(); 10.357 10.358 @@ -413,19 +443,19 @@ 10.359 } 10.360 10.361 @Override 10.362 - public Node leave(final ReturnNode returnNode) { 10.363 + public Node leaveReturnNode(final ReturnNode returnNode) { 10.364 addStatement(returnNode); //ReturnNodes are always terminal, marked as such in constructor 10.365 return returnNode; 10.366 } 10.367 10.368 @Override 10.369 - public Node enter(final SwitchNode switchNode) { 10.370 + public Node enterSwitchNode(final SwitchNode switchNode) { 10.371 nest(switchNode); 10.372 return switchNode; 10.373 } 10.374 10.375 @Override 10.376 - public Node leave(final SwitchNode switchNode) { 10.377 + public Node leaveSwitchNode(final SwitchNode switchNode) { 10.378 unnest(switchNode); 10.379 10.380 final List<CaseNode> cases = switchNode.getCases(); 10.381 @@ -446,13 +476,13 @@ 10.382 } 10.383 10.384 @Override 10.385 - public Node leave(final ThrowNode throwNode) { 10.386 + public Node leaveThrowNode(final ThrowNode throwNode) { 10.387 addStatement(throwNode); //ThrowNodes are always terminal, marked as such in constructor 10.388 return throwNode; 10.389 } 10.390 10.391 @Override 10.392 - public Node enter(final TryNode tryNode) { 10.393 + public Node enterTryNode(final TryNode tryNode) { 10.394 final Block finallyBody = tryNode.getFinallyBody(); 10.395 final long token = tryNode.getToken(); 10.396 final int finish = tryNode.getFinish(); 10.397 @@ -538,26 +568,19 @@ 10.398 10.399 // set outer tryNode's body to innerTryNode 10.400 final Block outerBody; 10.401 - outerBody = new Block(source, token, finish, tryNode.getBody().getParent(), getCurrentFunctionNode()); 10.402 + outerBody = new Block(source, token, finish); 10.403 outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode))); 10.404 tryNode.setBody(outerBody); 10.405 tryNode.setCatchBlocks(null); 10.406 - 10.407 - // now before we go on, we have to fix the block parents 10.408 - // (we repair the block tree after the insertion so that all references are intact) 10.409 - innerTryNode.getBody().setParent(tryNode.getBody()); 10.410 - for (final Block block : innerTryNode.getCatchBlocks()) { 10.411 - block.setParent(tryNode.getBody()); 10.412 - } 10.413 } 10.414 10.415 // create a catch-all that inlines finally and rethrows 10.416 10.417 - final Block catchBlock = new Block(source, token, finish, getCurrentBlock(), getCurrentFunctionNode()); 10.418 + final Block catchBlock = new Block(source, token, finish); 10.419 //this catch block should get define symbol 10.420 10.421 - final Block catchBody = new Block(source, token, finish, catchBlock, getCurrentFunctionNode()); 10.422 - final Node catchAllFinally = finallyBody.clone(); 10.423 + final Block catchBody = new Block(source, token, finish); 10.424 + final Node catchAllFinally = finallyBody.copy(); 10.425 10.426 catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally)); 10.427 setTerminal(catchBody, true); 10.428 @@ -584,7 +607,7 @@ 10.429 } 10.430 10.431 @Override 10.432 - public Node leave(final TryNode tryNode) { 10.433 + public Node leaveTryNode(final TryNode tryNode) { 10.434 final Block finallyBody = tryNode.getFinallyBody(); 10.435 10.436 boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal()); 10.437 @@ -608,18 +631,18 @@ 10.438 } 10.439 10.440 @Override 10.441 - public Node leave(final VarNode varNode) { 10.442 + public Node leaveVarNode(final VarNode varNode) { 10.443 addStatement(varNode); 10.444 return varNode; 10.445 } 10.446 10.447 @Override 10.448 - public Node enter(final WhileNode whileNode) { 10.449 + public Node enterWhileNode(final WhileNode whileNode) { 10.450 return nest(whileNode); 10.451 } 10.452 10.453 @Override 10.454 - public Node leave(final WhileNode whileNode) { 10.455 + public Node leaveWhileNode(final WhileNode whileNode) { 10.456 final Node test = whileNode.getTest(); 10.457 10.458 if (test == null) { 10.459 @@ -653,7 +676,7 @@ 10.460 } 10.461 10.462 @Override 10.463 - public Node leave(final WithNode withNode) { 10.464 + public Node leaveWithNode(final WithNode withNode) { 10.465 if (withNode.getBody().isTerminal()) { 10.466 setTerminal(withNode, true); 10.467 } 10.468 @@ -682,28 +705,10 @@ 10.469 */ 10.470 private static Node markerFunction(final Node function) { 10.471 if (function instanceof IdentNode) { 10.472 - return new IdentNode((IdentNode)function) { 10.473 - @Override 10.474 - public boolean isFunction() { 10.475 - return true; 10.476 - } 10.477 - }; 10.478 - } else if (function instanceof AccessNode) { 10.479 - return new AccessNode((AccessNode)function) { 10.480 - @Override 10.481 - public boolean isFunction() { 10.482 - return true; 10.483 - } 10.484 - }; 10.485 - } else if (function instanceof IndexNode) { 10.486 - return new IndexNode((IndexNode)function) { 10.487 - @Override 10.488 - public boolean isFunction() { 10.489 - return true; 10.490 - } 10.491 - }; 10.492 + return ((IdentNode)function).setIsFunction(); 10.493 + } else if (function instanceof BaseNode) { 10.494 + return ((BaseNode)function).setIsFunction(); 10.495 } 10.496 - 10.497 return function; 10.498 } 10.499 10.500 @@ -746,7 +751,7 @@ 10.501 if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) { 10.502 final CallNode.EvalArgs evalArgs = 10.503 new CallNode.EvalArgs( 10.504 - args.get(0).clone().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case" 10.505 + args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case" 10.506 getCurrentFunctionNode().getThisNode(), 10.507 evalLocation(callee), 10.508 getCurrentFunctionNode().isStrictMode()); 10.509 @@ -773,13 +778,13 @@ 10.510 10.511 loopBody.accept(new NodeVisitor() { 10.512 @Override 10.513 - public Node leave(final BreakNode node) { 10.514 + public Node leaveBreakNode(final BreakNode node) { 10.515 escapes.add(node); 10.516 return node; 10.517 } 10.518 10.519 @Override 10.520 - public Node leave(final ContinueNode node) { 10.521 + public Node leaveContinueNode(final ContinueNode node) { 10.522 // all inner loops have been popped. 10.523 if (nesting.contains(node.getTargetNode())) { 10.524 escapes.add(node); 10.525 @@ -794,7 +799,7 @@ 10.526 private void guaranteeReturn(final FunctionNode functionNode) { 10.527 Node resultNode; 10.528 10.529 - if (functionNode.isScript()) { 10.530 + if (functionNode.isProgram()) { 10.531 resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr 10.532 } else { 10.533 if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) { 10.534 @@ -859,18 +864,15 @@ 10.535 * @return true if try block is inside the target, false otherwise. 10.536 */ 10.537 private boolean isNestedTry(final TryNode tryNode, final Block target) { 10.538 - for (Block current = getCurrentBlock(); current != target; current = current.getParent()) { 10.539 - if (tryNode.getBody() == current) { 10.540 + for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) { 10.541 + final Block block = blocks.next(); 10.542 + if(block == target) { 10.543 + return false; 10.544 + } 10.545 + if(tryNode.isChildBlock(block)) { 10.546 return true; 10.547 } 10.548 - 10.549 - for (final Block catchBlock : tryNode.getCatchBlocks()) { 10.550 - if (catchBlock == current) { 10.551 - return true; 10.552 - } 10.553 - } 10.554 } 10.555 - 10.556 return false; 10.557 } 10.558 10.559 @@ -899,7 +901,7 @@ 10.560 continue; 10.561 } 10.562 10.563 - finallyBody = (Block)finallyBody.clone(); 10.564 + finallyBody = (Block)finallyBody.copy(); 10.565 final boolean hasTerminalFlags = finallyBody.hasTerminalFlags(); 10.566 10.567 new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this); 10.568 @@ -974,6 +976,3 @@ 10.569 } 10.570 10.571 } 10.572 - 10.573 - 10.574 -
11.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Mar 19 11:03:24 2013 -0300 11.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Sat Mar 23 00:58:39 2013 +0100 11.3 @@ -651,11 +651,10 @@ 11.4 11.5 /** 11.6 * Load the constants array 11.7 - * @param unitClassName name of the compile unit from which to load constants 11.8 * @return this method emitter 11.9 */ 11.10 - MethodEmitter loadConstants(final String unitClassName) { 11.11 - getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()); 11.12 + MethodEmitter loadConstants() { 11.13 + getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor()); 11.14 assert peekType().isArray() : peekType(); 11.15 return this; 11.16 }
12.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java Tue Mar 19 11:03:24 2013 -0300 12.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Sat Mar 23 00:58:39 2013 +0100 12.3 @@ -41,6 +41,7 @@ 12.4 import jdk.nashorn.internal.ir.FunctionNode; 12.5 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 12.6 import jdk.nashorn.internal.ir.LabelNode; 12.7 +import jdk.nashorn.internal.ir.LexicalContext; 12.8 import jdk.nashorn.internal.ir.LiteralNode; 12.9 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 12.10 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 12.11 @@ -49,6 +50,7 @@ 12.12 import jdk.nashorn.internal.ir.SplitNode; 12.13 import jdk.nashorn.internal.ir.SwitchNode; 12.14 import jdk.nashorn.internal.ir.WhileNode; 12.15 +import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 12.16 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 12.17 import jdk.nashorn.internal.runtime.DebugLogger; 12.18 import jdk.nashorn.internal.runtime.Source; 12.19 @@ -70,6 +72,8 @@ 12.20 /** Cache for calculated block weights. */ 12.21 private final Map<Node, Long> weightCache = new HashMap<>(); 12.22 12.23 + private final LexicalContext lexicalContext = new LexicalContext(); 12.24 + 12.25 /** Weight threshold for when to start a split. */ 12.26 public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024); 12.27 12.28 @@ -112,7 +116,7 @@ 12.29 } 12.30 12.31 if (weight >= SPLIT_THRESHOLD) { 12.32 - weight = splitBlock(functionNode); 12.33 + weight = splitBlock(functionNode, functionNode); 12.34 } 12.35 12.36 if (functionNode.isSplit()) { 12.37 @@ -132,9 +136,20 @@ 12.38 } 12.39 12.40 // Recursively split nested functions 12.41 - for (final FunctionNode function : functionNode.getFunctions()) { 12.42 - new Splitter(compiler, function, outermostCompileUnit).split(); 12.43 - } 12.44 + functionNode.accept(new NodeOperatorVisitor() { 12.45 + @Override 12.46 + public Node enterFunctionNode(FunctionNode function) { 12.47 + if(function == functionNode) { 12.48 + // Don't process outermost function (it was already processed) but descend into it to find nested 12.49 + // functions. 12.50 + return function; 12.51 + } 12.52 + // Process a nested function 12.53 + new Splitter(compiler, function, outermostCompileUnit).split(); 12.54 + // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions. 12.55 + return null; 12.56 + } 12.57 + }); 12.58 12.59 functionNode.setState(CompilationState.SPLIT); 12.60 } 12.61 @@ -155,7 +170,7 @@ 12.62 * 12.63 * @return new weight for the resulting block. 12.64 */ 12.65 - private long splitBlock(final Block block) { 12.66 + private long splitBlock(final Block block, final FunctionNode function) { 12.67 functionNode.setIsSplit(); 12.68 12.69 final List<Node> splits = new ArrayList<>(); 12.70 @@ -167,7 +182,7 @@ 12.71 12.72 if (statementsWeight + weight >= SPLIT_THRESHOLD || statement.isTerminal()) { 12.73 if (!statements.isEmpty()) { 12.74 - splits.add(createBlockSplitNode(block, statements, statementsWeight)); 12.75 + splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); 12.76 statements = new ArrayList<>(); 12.77 statementsWeight = 0; 12.78 } 12.79 @@ -183,7 +198,7 @@ 12.80 } 12.81 12.82 if (!statements.isEmpty()) { 12.83 - splits.add(createBlockSplitNode(block, statements, statementsWeight)); 12.84 + splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); 12.85 } 12.86 12.87 block.setStatements(splits); 12.88 @@ -199,13 +214,13 @@ 12.89 * 12.90 * @return New split node. 12.91 */ 12.92 - private SplitNode createBlockSplitNode(final Block parent, final List<Node> statements, final long weight) { 12.93 + private SplitNode createBlockSplitNode(final Block parent, final FunctionNode function, final List<Node> statements, final long weight) { 12.94 final Source source = parent.getSource(); 12.95 final long token = parent.getToken(); 12.96 final int finish = parent.getFinish(); 12.97 - final String name = parent.getFunction().uniqueName(SPLIT_PREFIX.tag()); 12.98 + final String name = function.uniqueName(SPLIT_PREFIX.tag()); 12.99 12.100 - final Block newBlock = new Block(source, token, finish, parent, functionNode); 12.101 + final Block newBlock = new Block(source, token, finish); 12.102 newBlock.setFrame(new Frame(parent.getFrame())); 12.103 newBlock.setStatements(statements); 12.104 12.105 @@ -217,15 +232,17 @@ 12.106 } 12.107 12.108 @Override 12.109 - public Node enter(final Block block) { 12.110 + public Node enterBlock(final Block block) { 12.111 if (block.isCatchBlock()) { 12.112 return null; 12.113 } 12.114 + lexicalContext.push(block); 12.115 12.116 final long weight = WeighNodes.weigh(block, weightCache); 12.117 12.118 if (weight < SPLIT_THRESHOLD) { 12.119 weightCache.put(block, weight); 12.120 + lexicalContext.pop(block); 12.121 return null; 12.122 } 12.123 12.124 @@ -233,23 +250,24 @@ 12.125 } 12.126 12.127 @Override 12.128 - public Node leave(final Block block) { 12.129 + public Node leaveBlock(final Block block) { 12.130 assert !block.isCatchBlock(); 12.131 12.132 // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have 12.133 // been split already, so weigh again before splitting. 12.134 long weight = WeighNodes.weigh(block, weightCache); 12.135 if (weight >= SPLIT_THRESHOLD) { 12.136 - weight = splitBlock(block); 12.137 + weight = splitBlock(block, lexicalContext.getFunction(block)); 12.138 } 12.139 weightCache.put(block, weight); 12.140 12.141 + lexicalContext.pop(block); 12.142 return block; 12.143 } 12.144 12.145 @SuppressWarnings("rawtypes") 12.146 @Override 12.147 - public Node leave(final LiteralNode literal) { 12.148 + public Node leaveLiteralNode(final LiteralNode literal) { 12.149 long weight = WeighNodes.weigh(literal); 12.150 12.151 if (weight < SPLIT_THRESHOLD) { 12.152 @@ -294,17 +312,12 @@ 12.153 } 12.154 12.155 @Override 12.156 - public Node enter(final FunctionNode node) { 12.157 - if (node.isLazy()) { 12.158 - return null; 12.159 + public Node enterFunctionNode(final FunctionNode node) { 12.160 + if(node == functionNode && !node.isLazy()) { 12.161 + lexicalContext.push(node); 12.162 + node.visitStatements(this); 12.163 + lexicalContext.pop(node); 12.164 } 12.165 - 12.166 - final List<Node> statements = node.getStatements(); 12.167 - 12.168 - for (final Node statement : statements) { 12.169 - statement.accept(this); 12.170 - } 12.171 - 12.172 return null; 12.173 } 12.174 12.175 @@ -321,38 +334,38 @@ 12.176 } 12.177 12.178 @Override 12.179 - public Node enter(final LabelNode labelNode) { 12.180 + public Node enterLabelNode(final LabelNode labelNode) { 12.181 registerJumpTarget(labelNode.getBreakNode()); 12.182 registerJumpTarget(labelNode.getContinueNode()); 12.183 return labelNode; 12.184 } 12.185 12.186 @Override 12.187 - public Node enter(final WhileNode whileNode) { 12.188 + public Node enterWhileNode(final WhileNode whileNode) { 12.189 registerJumpTarget(whileNode); 12.190 return whileNode; 12.191 } 12.192 12.193 @Override 12.194 - public Node enter(final DoWhileNode doWhileNode) { 12.195 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 12.196 registerJumpTarget(doWhileNode); 12.197 return doWhileNode; 12.198 } 12.199 12.200 @Override 12.201 - public Node enter(final ForNode forNode) { 12.202 + public Node enterForNode(final ForNode forNode) { 12.203 registerJumpTarget(forNode); 12.204 return forNode; 12.205 } 12.206 12.207 @Override 12.208 - public Node enter(final SwitchNode switchNode) { 12.209 + public Node enterSwitchNode(final SwitchNode switchNode) { 12.210 registerJumpTarget(switchNode); 12.211 return switchNode; 12.212 } 12.213 12.214 @Override 12.215 - public Node enter(final ReturnNode returnNode) { 12.216 + public Node enterReturnNode(final ReturnNode returnNode) { 12.217 for (final SplitNode split : splitStack) { 12.218 split.setHasReturn(true); 12.219 } 12.220 @@ -360,25 +373,25 @@ 12.221 } 12.222 12.223 @Override 12.224 - public Node enter(final ContinueNode continueNode) { 12.225 + public Node enterContinueNode(final ContinueNode continueNode) { 12.226 searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel()); 12.227 return continueNode; 12.228 } 12.229 12.230 @Override 12.231 - public Node enter(final BreakNode breakNode) { 12.232 + public Node enterBreakNode(final BreakNode breakNode) { 12.233 searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel()); 12.234 return breakNode; 12.235 } 12.236 12.237 @Override 12.238 - public Node enter(final SplitNode splitNode) { 12.239 + public Node enterSplitNode(final SplitNode splitNode) { 12.240 splitStack.addFirst(splitNode); 12.241 return splitNode; 12.242 } 12.243 12.244 @Override 12.245 - public Node leave(final SplitNode splitNode) { 12.246 + public Node leaveSplitNode(final SplitNode splitNode) { 12.247 assert splitNode == splitStack.peekFirst(); 12.248 splitStack.removeFirst(); 12.249 return splitNode;
13.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java Tue Mar 19 11:03:24 2013 -0300 13.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java Sat Mar 23 00:58:39 2013 +0100 13.3 @@ -47,7 +47,6 @@ 13.4 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 13.5 import jdk.nashorn.internal.ir.Node; 13.6 import jdk.nashorn.internal.ir.PropertyNode; 13.7 -import jdk.nashorn.internal.ir.ReferenceNode; 13.8 import jdk.nashorn.internal.ir.ReturnNode; 13.9 import jdk.nashorn.internal.ir.RuntimeNode; 13.10 import jdk.nashorn.internal.ir.SplitNode; 13.11 @@ -80,7 +79,7 @@ 13.12 private static final long LITERAL_WEIGHT = 10; 13.13 private static final long LOOP_WEIGHT = 4; 13.14 private static final long NEW_WEIGHT = 6; 13.15 - private static final long REFERENCE_WEIGHT = 20; 13.16 + private static final long FUNC_EXPR_WEIGHT = 20; 13.17 private static final long RETURN_WEIGHT = 2; 13.18 private static final long SPLIT_WEIGHT = 40; 13.19 private static final long SWITCH_WEIGHT = 8; 13.20 @@ -94,36 +93,37 @@ 13.21 /** Optional cache for weight of block nodes. */ 13.22 private final Map<Node, Long> weightCache; 13.23 13.24 - /* 13.25 + private final FunctionNode topFunction; 13.26 + 13.27 + /** 13.28 * Constructor 13.29 * 13.30 * @param weightCache cache of already calculated block weights 13.31 */ 13.32 - private WeighNodes(final Map<Node, Long> weightCache) { 13.33 + private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) { 13.34 super(null, null); 13.35 + this.topFunction = topFunction; 13.36 this.weightCache = weightCache; 13.37 } 13.38 13.39 static long weigh(final Node node) { 13.40 - final WeighNodes weighNodes = new WeighNodes(null); 13.41 - node.accept(weighNodes); 13.42 - return weighNodes.weight; 13.43 + return weigh(node, null); 13.44 } 13.45 13.46 static long weigh(final Node node, final Map<Node, Long> weightCache) { 13.47 - final WeighNodes weighNodes = new WeighNodes(weightCache); 13.48 + final WeighNodes weighNodes = new WeighNodes(node instanceof FunctionNode ? (FunctionNode)node : null, weightCache); 13.49 node.accept(weighNodes); 13.50 return weighNodes.weight; 13.51 } 13.52 13.53 @Override 13.54 - public Node leave(final AccessNode accessNode) { 13.55 + public Node leaveAccessNode(final AccessNode accessNode) { 13.56 weight += ACCESS_WEIGHT; 13.57 return accessNode; 13.58 } 13.59 13.60 @Override 13.61 - public Node enter(final Block block) { 13.62 + public Node enterBlock(final Block block) { 13.63 if (weightCache != null && weightCache.containsKey(block)) { 13.64 weight += weightCache.get(block); 13.65 return null; 13.66 @@ -133,78 +133,79 @@ 13.67 } 13.68 13.69 @Override 13.70 - public Node leave(final BreakNode breakNode) { 13.71 + public Node leaveBreakNode(final BreakNode breakNode) { 13.72 weight += BREAK_WEIGHT; 13.73 return breakNode; 13.74 } 13.75 13.76 @Override 13.77 - public Node leave(final CallNode callNode) { 13.78 + public Node leaveCallNode(final CallNode callNode) { 13.79 weight += CALL_WEIGHT; 13.80 return callNode; 13.81 } 13.82 13.83 @Override 13.84 - public Node leave(final CatchNode catchNode) { 13.85 + public Node leaveCatchNode(final CatchNode catchNode) { 13.86 weight += CATCH_WEIGHT; 13.87 return catchNode; 13.88 } 13.89 13.90 @Override 13.91 - public Node leave(final ContinueNode continueNode) { 13.92 + public Node leaveContinueNode(final ContinueNode continueNode) { 13.93 weight += CONTINUE_WEIGHT; 13.94 return continueNode; 13.95 } 13.96 13.97 @Override 13.98 - public Node leave(final DoWhileNode doWhileNode) { 13.99 + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 13.100 weight += LOOP_WEIGHT; 13.101 return doWhileNode; 13.102 } 13.103 13.104 @Override 13.105 - public Node leave(final ExecuteNode executeNode) { 13.106 + public Node leaveExecuteNode(final ExecuteNode executeNode) { 13.107 return executeNode; 13.108 } 13.109 13.110 @Override 13.111 - public Node leave(final ForNode forNode) { 13.112 + public Node leaveForNode(final ForNode forNode) { 13.113 weight += LOOP_WEIGHT; 13.114 return forNode; 13.115 } 13.116 13.117 @Override 13.118 - public Node enter(final FunctionNode functionNode) { 13.119 - final List<Node> statements = functionNode.getStatements(); 13.120 - 13.121 - for (final Node statement : statements) { 13.122 - statement.accept(this); 13.123 + public Node enterFunctionNode(final FunctionNode functionNode) { 13.124 + if(functionNode == topFunction) { 13.125 + // the function being weighted; descend into its statements 13.126 + functionNode.visitStatements(this); 13.127 + } else { 13.128 + // just a reference to inner function from outer function 13.129 + weight += FUNC_EXPR_WEIGHT; 13.130 } 13.131 - 13.132 return null; 13.133 } 13.134 13.135 @Override 13.136 - public Node leave(final IdentNode identNode) { 13.137 + public Node leaveIdentNode(final IdentNode identNode) { 13.138 weight += ACCESS_WEIGHT + identNode.getName().length() * 2; 13.139 return identNode; 13.140 } 13.141 13.142 @Override 13.143 - public Node leave(final IfNode ifNode) { 13.144 + public Node leaveIfNode(final IfNode ifNode) { 13.145 weight += IF_WEIGHT; 13.146 return ifNode; 13.147 } 13.148 13.149 @Override 13.150 - public Node leave(final IndexNode indexNode) { 13.151 + public Node leaveIndexNode(final IndexNode indexNode) { 13.152 weight += ACCESS_WEIGHT; 13.153 return indexNode; 13.154 } 13.155 13.156 @SuppressWarnings("rawtypes") 13.157 @Override 13.158 - public Node enter(final LiteralNode literalNode) { 13.159 + public Node enterLiteralNode(final LiteralNode literalNode) { 13.160 weight += LITERAL_WEIGHT; 13.161 13.162 if (literalNode instanceof ArrayLiteralNode) { 13.163 @@ -230,67 +231,61 @@ 13.164 } 13.165 13.166 @Override 13.167 - public Node leave(final PropertyNode propertyNode) { 13.168 + public Node leavePropertyNode(final PropertyNode propertyNode) { 13.169 weight += LITERAL_WEIGHT; 13.170 return propertyNode; 13.171 } 13.172 13.173 @Override 13.174 - public Node leave(final ReferenceNode referenceNode) { 13.175 - weight += REFERENCE_WEIGHT; 13.176 - return referenceNode; 13.177 - } 13.178 - 13.179 - @Override 13.180 - public Node leave(final ReturnNode returnNode) { 13.181 + public Node leaveReturnNode(final ReturnNode returnNode) { 13.182 weight += RETURN_WEIGHT; 13.183 return returnNode; 13.184 } 13.185 13.186 @Override 13.187 - public Node leave(final RuntimeNode runtimeNode) { 13.188 + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 13.189 weight += CALL_WEIGHT; 13.190 return runtimeNode; 13.191 } 13.192 13.193 @Override 13.194 - public Node enter(final SplitNode splitNode) { 13.195 + public Node enterSplitNode(final SplitNode splitNode) { 13.196 weight += SPLIT_WEIGHT; 13.197 return null; 13.198 } 13.199 13.200 @Override 13.201 - public Node leave(final SwitchNode switchNode) { 13.202 + public Node leaveSwitchNode(final SwitchNode switchNode) { 13.203 weight += SWITCH_WEIGHT; 13.204 return switchNode; 13.205 } 13.206 13.207 @Override 13.208 - public Node leave(final ThrowNode throwNode) { 13.209 + public Node leaveThrowNode(final ThrowNode throwNode) { 13.210 weight += THROW_WEIGHT; 13.211 return throwNode; 13.212 } 13.213 13.214 @Override 13.215 - public Node leave(final TryNode tryNode) { 13.216 + public Node leaveTryNode(final TryNode tryNode) { 13.217 weight += THROW_WEIGHT; 13.218 return tryNode; 13.219 } 13.220 13.221 @Override 13.222 - public Node leave(final VarNode varNode) { 13.223 + public Node leaveVarNode(final VarNode varNode) { 13.224 weight += VAR_WEIGHT; 13.225 return varNode; 13.226 } 13.227 13.228 @Override 13.229 - public Node leave(final WhileNode whileNode) { 13.230 + public Node leaveWhileNode(final WhileNode whileNode) { 13.231 weight += LOOP_WEIGHT; 13.232 return whileNode; 13.233 } 13.234 13.235 @Override 13.236 - public Node leave(final WithNode withNode) { 13.237 + public Node leaveWithNode(final WithNode withNode) { 13.238 weight += WITH_WEIGHT; 13.239 return withNode; 13.240 }
14.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java Tue Mar 19 11:03:24 2013 -0300 14.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Sat Mar 23 00:58:39 2013 +0100 14.3 @@ -36,7 +36,7 @@ 14.4 * IR representation of a property access (period operator.) 14.5 * 14.6 */ 14.7 -public class AccessNode extends BaseNode implements TypeOverride { 14.8 +public class AccessNode extends BaseNode implements TypeOverride<AccessNode> { 14.9 /** Property ident. */ 14.10 private IdentNode property; 14.11 14.12 @@ -56,9 +56,7 @@ 14.13 super(source, token, finish, base); 14.14 14.15 this.start = base.getStart(); 14.16 - this.property = property; 14.17 - 14.18 - this.property.setIsPropertyName(); 14.19 + this.property = property.setIsPropertyName(); 14.20 } 14.21 14.22 /** 14.23 @@ -106,10 +104,10 @@ 14.24 */ 14.25 @Override 14.26 public Node accept(final NodeVisitor visitor) { 14.27 - if (visitor.enter(this) != null) { 14.28 + if (visitor.enterAccessNode(this) != null) { 14.29 base = base.accept(visitor); 14.30 property = (IdentNode)property.accept(visitor); 14.31 - return visitor.leave(this); 14.32 + return visitor.leaveAccessNode(this); 14.33 } 14.34 14.35 return this; 14.36 @@ -150,13 +148,14 @@ 14.37 } 14.38 14.39 @Override 14.40 - public void setType(final Type type) { 14.41 + public AccessNode setType(final Type type) { 14.42 if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 14.43 ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 14.44 } 14.45 - property.setType(type); 14.46 + property = property.setType(type); 14.47 getSymbol().setTypeOverride(type); //always a temp so this is fine. 14.48 hasCallSiteType = true; 14.49 + return this; 14.50 } 14.51 14.52 @Override
15.1 --- a/src/jdk/nashorn/internal/ir/Assignment.java Tue Mar 19 11:03:24 2013 -0300 15.2 +++ b/src/jdk/nashorn/internal/ir/Assignment.java Sat Mar 23 00:58:39 2013 +0100 15.3 @@ -46,4 +46,11 @@ 15.4 * @return get the assignment source node 15.5 */ 15.6 public Node getAssignmentSource(); 15.7 + 15.8 + /** 15.9 + * Set assignment destination node. 15.10 + * @param n the assignment destination node. 15.11 + * @return a node equivalent to this one except for the requested change. 15.12 + */ 15.13 + public Node setAssignmentDest(D n); 15.14 }
16.1 --- a/src/jdk/nashorn/internal/ir/BaseNode.java Tue Mar 19 11:03:24 2013 -0300 16.2 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java Sat Mar 23 00:58:39 2013 +0100 16.3 @@ -38,6 +38,8 @@ 16.4 /** Base Node. */ 16.5 protected Node base; 16.6 16.7 + private boolean function; 16.8 + 16.9 /** 16.10 * Constructor 16.11 * 16.12 @@ -96,6 +98,15 @@ 16.13 16.14 @Override 16.15 public boolean isFunction() { 16.16 - return false; 16.17 + return function; 16.18 + } 16.19 + 16.20 + /** 16.21 + * Mark this node as being the callee operand of a {@link CallNode}. 16.22 + * @return a base node identical to this one in all aspects except with its function flag set. 16.23 + */ 16.24 + public BaseNode setIsFunction() { 16.25 + function = true; 16.26 + return this; 16.27 } 16.28 }
17.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Mar 19 11:03:24 2013 -0300 17.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Sat Mar 23 00:58:39 2013 +0100 17.3 @@ -35,7 +35,7 @@ 17.4 */ 17.5 public class BinaryNode extends UnaryNode { 17.6 /** Left hand side argument. */ 17.7 - protected Node lhs; 17.8 + private Node lhs; 17.9 17.10 /** 17.11 * Constructor 17.12 @@ -140,6 +140,11 @@ 17.13 } 17.14 17.15 @Override 17.16 + public Node setAssignmentDest(Node n) { 17.17 + return setLHS(n); 17.18 + } 17.19 + 17.20 + @Override 17.21 public Node getAssignmentSource() { 17.22 return rhs(); 17.23 } 17.24 @@ -163,10 +168,9 @@ 17.25 */ 17.26 @Override 17.27 public Node accept(final NodeVisitor visitor) { 17.28 - if (visitor.enter(this) != null) { 17.29 - lhs = lhs.accept(visitor); 17.30 - rhs = rhs.accept(visitor); 17.31 - return visitor.leave(this); 17.32 + if (visitor.enterBinaryNode(this) != null) { 17.33 + // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers 17.34 + return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor))); 17.35 } 17.36 17.37 return this; 17.38 @@ -229,8 +233,12 @@ 17.39 /** 17.40 * Set the left hand side expression for this node 17.41 * @param lhs new left hand side expression 17.42 + * @return a node equivalent to this one except for the requested change. 17.43 */ 17.44 - public void setLHS(final Node lhs) { 17.45 - this.lhs = lhs; 17.46 + public BinaryNode setLHS(final Node lhs) { 17.47 + if(this.lhs == lhs) return this; 17.48 + final BinaryNode n = (BinaryNode)clone(); 17.49 + n.lhs = lhs; 17.50 + return n; 17.51 } 17.52 }
18.1 --- a/src/jdk/nashorn/internal/ir/Block.java Tue Mar 19 11:03:24 2013 -0300 18.2 +++ b/src/jdk/nashorn/internal/ir/Block.java Sat Mar 23 00:58:39 2013 +0100 18.3 @@ -25,14 +25,6 @@ 18.4 18.5 package jdk.nashorn.internal.ir; 18.6 18.7 -import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; 18.8 -import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; 18.9 -import static jdk.nashorn.internal.ir.Symbol.IS_LET; 18.10 -import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; 18.11 -import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; 18.12 -import static jdk.nashorn.internal.ir.Symbol.IS_VAR; 18.13 -import static jdk.nashorn.internal.ir.Symbol.KINDMASK; 18.14 - 18.15 import java.io.PrintWriter; 18.16 import java.util.ArrayList; 18.17 import java.util.Collections; 18.18 @@ -40,9 +32,9 @@ 18.19 import java.util.HashMap; 18.20 import java.util.Iterator; 18.21 import java.util.List; 18.22 +import java.util.ListIterator; 18.23 import jdk.nashorn.internal.codegen.Frame; 18.24 import jdk.nashorn.internal.codegen.Label; 18.25 -import jdk.nashorn.internal.ir.annotations.Reference; 18.26 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 18.27 import jdk.nashorn.internal.runtime.Source; 18.28 18.29 @@ -51,14 +43,6 @@ 18.30 * basis for script body. 18.31 */ 18.32 public class Block extends Node { 18.33 - /** Parent context */ 18.34 - @Reference 18.35 - private Block parent; 18.36 - 18.37 - /** Owning function - a FunctionNode has itself as function */ 18.38 - @Reference 18.39 - protected FunctionNode function; 18.40 - 18.41 /** List of statements */ 18.42 protected List<Node> statements; 18.43 18.44 @@ -83,14 +67,10 @@ 18.45 * @param source source code 18.46 * @param token token 18.47 * @param finish finish 18.48 - * @param parent reference to parent block 18.49 - * @param function function node this block is in 18.50 */ 18.51 - public Block(final Source source, final long token, final int finish, final Block parent, final FunctionNode function) { 18.52 + public Block(final Source source, final long token, final int finish) { 18.53 super(source, token, finish); 18.54 18.55 - this.parent = parent; 18.56 - this.function = function; 18.57 this.statements = new ArrayList<>(); 18.58 this.symbols = new HashMap<>(); 18.59 this.entryLabel = new Label("block_entry"); 18.60 @@ -106,8 +86,6 @@ 18.61 protected Block(final Block block, final CopyState cs) { 18.62 super(block); 18.63 18.64 - this.parent = block.parent; 18.65 - this.function = block.function; 18.66 this.statements = new ArrayList<>(); 18.67 for (final Node statement : block.getStatements()) { 18.68 statements.add(cs.existingOrCopy(statement)); 18.69 @@ -122,55 +100,7 @@ 18.70 18.71 @Override 18.72 protected Node copy(final CopyState cs) { 18.73 - return fixBlockChain(new Block(this, cs)); 18.74 - } 18.75 - 18.76 - /** 18.77 - * Whenever a clone that contains a hierarchy of blocks is created, 18.78 - * this function has to be called to ensure that the parents point 18.79 - * to the correct parent blocks or two different ASTs would not 18.80 - * be completely separated. 18.81 - * 18.82 - * @return the argument 18.83 - */ 18.84 - static Block fixBlockChain(final Block root) { 18.85 - root.accept(new NodeVisitor() { 18.86 - private Block parent = root.getParent(); 18.87 - private final FunctionNode function = root.getFunction(); 18.88 - 18.89 - @Override 18.90 - public Node enter(final Block block) { 18.91 - assert block.getFunction() == function; 18.92 - block.setParent(parent); 18.93 - parent = block; 18.94 - 18.95 - return block; 18.96 - } 18.97 - 18.98 - @Override 18.99 - public Node leave(final Block block) { 18.100 - parent = block.getParent(); 18.101 - 18.102 - return block; 18.103 - } 18.104 - 18.105 - @Override 18.106 - public Node enter(final FunctionNode functionNode) { 18.107 - assert functionNode.getFunction() == function; 18.108 - 18.109 - return enter((Block)functionNode); 18.110 - } 18.111 - 18.112 - @Override 18.113 - public Node leave(final FunctionNode functionNode) { 18.114 - assert functionNode.getFunction() == function; 18.115 - 18.116 - return leave((Block)functionNode); 18.117 - } 18.118 - 18.119 - }); 18.120 - 18.121 - return root; 18.122 + return new Block(this, cs); 18.123 } 18.124 18.125 /** 18.126 @@ -188,17 +118,12 @@ 18.127 } 18.128 18.129 /** 18.130 - * Prepend a statement to the statement list 18.131 + * Prepend statements to the statement list 18.132 * 18.133 - * @param statement Statement node to add 18.134 + * @param prepended statement to add 18.135 */ 18.136 - public void prependStatement(final Node statement) { 18.137 - if (statement != null) { 18.138 - final List<Node> newStatements = new ArrayList<>(); 18.139 - newStatements.add(statement); 18.140 - newStatements.addAll(statements); 18.141 - setStatements(newStatements); 18.142 - } 18.143 + public void prependStatements(final List<Node> prepended) { 18.144 + statements.addAll(0, prepended); 18.145 } 18.146 18.147 /** 18.148 @@ -211,39 +136,6 @@ 18.149 } 18.150 18.151 /** 18.152 - * Add a new function to the function list. 18.153 - * 18.154 - * @param functionNode Function node to add. 18.155 - */ 18.156 - public void addFunction(final FunctionNode functionNode) { 18.157 - assert parent != null : "Parent context missing."; 18.158 - 18.159 - parent.addFunction(functionNode); 18.160 - } 18.161 - 18.162 - /** 18.163 - * Add a list of functions to the function list. 18.164 - * 18.165 - * @param functionNodes Function nodes to add. 18.166 - */ 18.167 - public void addFunctions(final List<FunctionNode> functionNodes) { 18.168 - assert parent != null : "Parent context missing."; 18.169 - 18.170 - parent.addFunctions(functionNodes); 18.171 - } 18.172 - 18.173 - /** 18.174 - * Set the function list to a new one 18.175 - * 18.176 - * @param functionNodes the nodes to set 18.177 - */ 18.178 - public void setFunctions(final List<FunctionNode> functionNodes) { 18.179 - assert parent != null : "Parent context missing."; 18.180 - 18.181 - parent.setFunctions(functionNodes); 18.182 - } 18.183 - 18.184 - /** 18.185 * Assist in IR navigation. 18.186 * 18.187 * @param visitor IR navigating visitor. 18.188 @@ -257,13 +149,9 @@ 18.189 try { 18.190 // Ignore parent to avoid recursion. 18.191 18.192 - if (visitor.enter(this) != null) { 18.193 - for (int i = 0, count = statements.size(); i < count; i++) { 18.194 - final Node statement = statements.get(i); 18.195 - statements.set(i, statement.accept(visitor)); 18.196 - } 18.197 - 18.198 - return visitor.leave(this); 18.199 + if (visitor.enterBlock(this) != null) { 18.200 + visitStatements(visitor); 18.201 + return visitor.leaveBlock(this); 18.202 } 18.203 } finally { 18.204 visitor.setCurrentBlock(saveBlock); 18.205 @@ -281,51 +169,13 @@ 18.206 } 18.207 18.208 /** 18.209 - * Search for symbol. 18.210 - * 18.211 - * @param name Symbol name. 18.212 - * 18.213 - * @return Found symbol or null if not found. 18.214 + * Retrieves an existing symbol defined in the current block. 18.215 + * @param name the name of the symbol 18.216 + * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't 18.217 + * define a symbol with this name. 18.218 */ 18.219 - public Symbol findSymbol(final String name) { 18.220 - // Search up block chain to locate symbol. 18.221 - 18.222 - for (Block block = this; block != null; block = block.getParent()) { 18.223 - // Find name. 18.224 - final Symbol symbol = block.symbols.get(name); 18.225 - // If found then we are good. 18.226 - if (symbol != null) { 18.227 - return symbol; 18.228 - } 18.229 - } 18.230 - return null; 18.231 - } 18.232 - 18.233 - /** 18.234 - * Search for symbol in current function. 18.235 - * 18.236 - * @param name Symbol name. 18.237 - * 18.238 - * @return Found symbol or null if not found. 18.239 - */ 18.240 - public Symbol findLocalSymbol(final String name) { 18.241 - // Search up block chain to locate symbol. 18.242 - for (Block block = this; block != null; block = block.getParent()) { 18.243 - // Find name. 18.244 - final Symbol symbol = block.symbols.get(name); 18.245 - // If found then we are good. 18.246 - if (symbol != null) { 18.247 - return symbol; 18.248 - } 18.249 - 18.250 - // If searched function then we are done. 18.251 - if (block == block.function) { 18.252 - break; 18.253 - } 18.254 - } 18.255 - 18.256 - // Not found. 18.257 - return null; 18.258 + public Symbol getExistingSymbol(final String name) { 18.259 + return symbols.get(name); 18.260 } 18.261 18.262 /** 18.263 @@ -338,122 +188,6 @@ 18.264 return statements.size() == 1 && statements.get(0) instanceof CatchNode; 18.265 } 18.266 18.267 - /** 18.268 - * Test to see if a symbol is local to the function. 18.269 - * 18.270 - * @param symbol Symbol to test. 18.271 - * @return True if a local symbol. 18.272 - */ 18.273 - public boolean isLocal(final Symbol symbol) { 18.274 - // some temp symbols have no block, so can be assumed local 18.275 - final Block block = symbol.getBlock(); 18.276 - return block == null || block.getFunction() == function; 18.277 - } 18.278 - 18.279 - /** 18.280 - * Declare the definition of a new symbol. 18.281 - * 18.282 - * @param name Name of symbol. 18.283 - * @param symbolFlags Symbol flags. 18.284 - * @param node Defining Node. 18.285 - * 18.286 - * @return Symbol for given name or null for redefinition. 18.287 - */ 18.288 - public Symbol defineSymbol(final String name, final int symbolFlags, final Node node) { 18.289 - int flags = symbolFlags; 18.290 - Symbol symbol = findSymbol(name); // Locate symbol. 18.291 - 18.292 - if ((flags & KINDMASK) == IS_GLOBAL) { 18.293 - flags |= IS_SCOPE; 18.294 - } 18.295 - 18.296 - if (symbol != null) { 18.297 - // Symbol was already defined. Check if it needs to be redefined. 18.298 - if ((flags & KINDMASK) == IS_PARAM) { 18.299 - if (!function.isLocal(symbol)) { 18.300 - // Not defined in this function. Create a new definition. 18.301 - symbol = null; 18.302 - } else if (symbol.isParam()) { 18.303 - // Duplicate parameter. Null return will force an error. 18.304 - assert false : "duplicate parameter"; 18.305 - return null; 18.306 - } 18.307 - } else if ((flags & KINDMASK) == IS_VAR) { 18.308 - if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & Symbol.IS_LET) == Symbol.IS_LET) { 18.309 - assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == this) : "duplicate let variable in block"; 18.310 - // Always create a new definition. 18.311 - symbol = null; 18.312 - } else { 18.313 - // Not defined in this function. Create a new definition. 18.314 - if (!function.isLocal(symbol) || symbol.less(IS_VAR)) { 18.315 - symbol = null; 18.316 - } 18.317 - } 18.318 - } 18.319 - } 18.320 - 18.321 - if (symbol == null) { 18.322 - // If not found, then create a new one. 18.323 - Block symbolBlock; 18.324 - 18.325 - // Determine where to create it. 18.326 - if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { 18.327 - symbolBlock = this; 18.328 - } else { 18.329 - symbolBlock = getFunction(); 18.330 - } 18.331 - 18.332 - // Create and add to appropriate block. 18.333 - symbol = new Symbol(name, flags, node, symbolBlock); 18.334 - symbolBlock.putSymbol(name, symbol); 18.335 - 18.336 - if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { 18.337 - symbolBlock.getFrame().addSymbol(symbol); 18.338 - symbol.setNeedsSlot(true); 18.339 - } 18.340 - } else if (symbol.less(flags)) { 18.341 - symbol.setFlags(flags); 18.342 - } 18.343 - 18.344 - if (node != null) { 18.345 - node.setSymbol(symbol); 18.346 - } 18.347 - 18.348 - return symbol; 18.349 - } 18.350 - 18.351 - /** 18.352 - * Declare the use of a symbol. 18.353 - * 18.354 - * @param name Name of symbol. 18.355 - * @param node Using node 18.356 - * 18.357 - * @return Symbol for given name. 18.358 - */ 18.359 - public Symbol useSymbol(final String name, final Node node) { 18.360 - Symbol symbol = findSymbol(name); 18.361 - 18.362 - if (symbol == null) { 18.363 - // If not found, declare as a free var. 18.364 - symbol = defineSymbol(name, IS_GLOBAL, node); 18.365 - } else { 18.366 - node.setSymbol(symbol); 18.367 - } 18.368 - 18.369 - return symbol; 18.370 - } 18.371 - 18.372 - /** 18.373 - * Add parent name to the builder. 18.374 - * 18.375 - * @param sb String bulder. 18.376 - */ 18.377 - public void addParentName(final StringBuilder sb) { 18.378 - if (parent != null) { 18.379 - parent.addParentName(sb); 18.380 - } 18.381 - } 18.382 - 18.383 @Override 18.384 public void toString(final StringBuilder sb) { 18.385 for (final Node statement : statements) { 18.386 @@ -512,16 +246,6 @@ 18.387 } 18.388 18.389 /** 18.390 - * Get the FunctionNode for this block, i.e. the function it 18.391 - * belongs to 18.392 - * 18.393 - * @return the function node 18.394 - */ 18.395 - public FunctionNode getFunction() { 18.396 - return function; 18.397 - } 18.398 - 18.399 - /** 18.400 * Reset the frame for this block 18.401 * 18.402 * @param frame the new frame 18.403 @@ -531,24 +255,6 @@ 18.404 } 18.405 18.406 /** 18.407 - * Get the parent block 18.408 - * 18.409 - * @return parent block, or null if none exists 18.410 - */ 18.411 - public Block getParent() { 18.412 - return parent; 18.413 - } 18.414 - 18.415 - /** 18.416 - * Set the parent block 18.417 - * 18.418 - * @param parent the new parent block 18.419 - */ 18.420 - public void setParent(final Block parent) { 18.421 - this.parent = parent; 18.422 - } 18.423 - 18.424 - /** 18.425 * Get the list of statements in this block 18.426 * 18.427 * @return a list of statements 18.428 @@ -558,6 +264,15 @@ 18.429 } 18.430 18.431 /** 18.432 + * Applies the specified visitor to all statements in the block. 18.433 + * @param visitor the visitor. 18.434 + */ 18.435 + public void visitStatements(NodeVisitor visitor) { 18.436 + for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) { 18.437 + stmts.set(stmts.next().accept(visitor)); 18.438 + } 18.439 + } 18.440 + /** 18.441 * Reset the statement list for this block 18.442 * 18.443 * @param statements new statement list 18.444 @@ -592,4 +307,29 @@ 18.445 needsScope = true; 18.446 } 18.447 18.448 + /** 18.449 + * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not 18.450 + * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol 18.451 + * will be marked as one that needs to have its own scope. 18.452 + * @param symbol the symbol being used. 18.453 + * @param ancestors the iterator over block's containing lexical context 18.454 + */ 18.455 + public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { 18.456 + if(symbol.getBlock() == this) { 18.457 + setNeedsScope(); 18.458 + } else { 18.459 + setUsesParentScopeSymbol(symbol, ancestors); 18.460 + } 18.461 + } 18.462 + 18.463 + /** 18.464 + * Invoked when this block uses a scope symbol defined in one of its ancestors. 18.465 + * @param symbol the scope symbol being used 18.466 + * @param ancestors iterator over ancestor blocks 18.467 + */ 18.468 + void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { 18.469 + if(ancestors.hasNext()) { 18.470 + ancestors.next().setUsesScopeSymbol(symbol, ancestors); 18.471 + } 18.472 + } 18.473 }
19.1 --- a/src/jdk/nashorn/internal/ir/BreakNode.java Tue Mar 19 11:03:24 2013 -0300 19.2 +++ b/src/jdk/nashorn/internal/ir/BreakNode.java Sat Mar 23 00:58:39 2013 +0100 19.3 @@ -64,8 +64,8 @@ 19.4 */ 19.5 @Override 19.6 public Node accept(final NodeVisitor visitor) { 19.7 - if (visitor.enter(this) != null) { 19.8 - return visitor.leave(this); 19.9 + if (visitor.enterBreakNode(this) != null) { 19.10 + return visitor.leaveBreakNode(this); 19.11 } 19.12 19.13 return this;
20.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java Tue Mar 19 11:03:24 2013 -0300 20.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java Sat Mar 23 00:58:39 2013 +0100 20.3 @@ -37,7 +37,7 @@ 20.4 * IR representation for a function call. 20.5 * 20.6 */ 20.7 -public class CallNode extends Node implements TypeOverride { 20.8 +public class CallNode extends Node implements TypeOverride<CallNode> { 20.9 20.10 private Type type; 20.11 20.12 @@ -176,13 +176,13 @@ 20.13 if (hasCallSiteType()) { 20.14 return type; 20.15 } 20.16 - assert !function.getType().isUnknown(); 20.17 - return function.getType(); 20.18 + return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT; 20.19 } 20.20 20.21 @Override 20.22 - public void setType(final Type type) { 20.23 + public CallNode setType(final Type type) { 20.24 this.type = type; 20.25 + return this; 20.26 } 20.27 20.28 private boolean hasCallSiteType() { 20.29 @@ -208,14 +208,14 @@ 20.30 */ 20.31 @Override 20.32 public Node accept(final NodeVisitor visitor) { 20.33 - if (visitor.enter(this) != null) { 20.34 + if (visitor.enterCallNode(this) != null) { 20.35 function = function.accept(visitor); 20.36 20.37 for (int i = 0, count = args.size(); i < count; i++) { 20.38 args.set(i, args.get(i).accept(visitor)); 20.39 } 20.40 20.41 - return visitor.leave(this); 20.42 + return visitor.leaveCallNode(this); 20.43 } 20.44 20.45 return this;
21.1 --- a/src/jdk/nashorn/internal/ir/CaseNode.java Tue Mar 19 11:03:24 2013 -0300 21.2 +++ b/src/jdk/nashorn/internal/ir/CaseNode.java Sat Mar 23 00:58:39 2013 +0100 21.3 @@ -79,7 +79,7 @@ 21.4 */ 21.5 @Override 21.6 public Node accept(final NodeVisitor visitor) { 21.7 - if (visitor.enter(this) != null) { 21.8 + if (visitor.enterCaseNode(this) != null) { 21.9 if (test != null) { 21.10 test = test.accept(visitor); 21.11 } 21.12 @@ -87,7 +87,7 @@ 21.13 body = (Block)body.accept(visitor); 21.14 } 21.15 21.16 - return visitor.leave(this); 21.17 + return visitor.leaveCaseNode(this); 21.18 } 21.19 21.20 return this;
22.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java Tue Mar 19 11:03:24 2013 -0300 22.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Sat Mar 23 00:58:39 2013 +0100 22.3 @@ -84,7 +84,7 @@ 22.4 */ 22.5 @Override 22.6 public Node accept(final NodeVisitor visitor) { 22.7 - if (visitor.enter(this) != null) { 22.8 + if (visitor.enterCatchNode(this) != null) { 22.9 exception = (IdentNode)exception.accept(visitor); 22.10 22.11 if (exceptionCondition != null) { 22.12 @@ -92,7 +92,7 @@ 22.13 } 22.14 22.15 body = (Block)body.accept(visitor); 22.16 - return visitor.leave(this); 22.17 + return visitor.leaveCatchNode(this); 22.18 } 22.19 22.20 return this;
23.1 --- a/src/jdk/nashorn/internal/ir/ContinueNode.java Tue Mar 19 11:03:24 2013 -0300 23.2 +++ b/src/jdk/nashorn/internal/ir/ContinueNode.java Sat Mar 23 00:58:39 2013 +0100 23.3 @@ -61,8 +61,8 @@ 23.4 23.5 @Override 23.6 public Node accept(final NodeVisitor visitor) { 23.7 - if (visitor.enter(this) != null) { 23.8 - return visitor.leave(this); 23.9 + if (visitor.enterContinueNode(this) != null) { 23.10 + return visitor.leaveContinueNode(this); 23.11 } 23.12 23.13 return this;
24.1 --- a/src/jdk/nashorn/internal/ir/DoWhileNode.java Tue Mar 19 11:03:24 2013 -0300 24.2 +++ b/src/jdk/nashorn/internal/ir/DoWhileNode.java Sat Mar 23 00:58:39 2013 +0100 24.3 @@ -63,11 +63,11 @@ 24.4 24.5 @Override 24.6 public Node accept(final NodeVisitor visitor) { 24.7 - if (visitor.enter(this) != null) { 24.8 + if (visitor.enterDoWhileNode(this) != null) { 24.9 body = (Block)body.accept(visitor); 24.10 test = test.accept(visitor); 24.11 24.12 - return visitor.leave(this); 24.13 + return visitor.leaveDoWhileNode(this); 24.14 } 24.15 24.16 return this;
25.1 --- a/src/jdk/nashorn/internal/ir/EmptyNode.java Tue Mar 19 11:03:24 2013 -0300 25.2 +++ b/src/jdk/nashorn/internal/ir/EmptyNode.java Sat Mar 23 00:58:39 2013 +0100 25.3 @@ -57,8 +57,8 @@ 25.4 25.5 @Override 25.6 public Node accept(final NodeVisitor visitor) { 25.7 - if (visitor.enter(this) != null) { 25.8 - return visitor.leave(this); 25.9 + if (visitor.enterEmptyNode(this) != null) { 25.10 + return visitor.leaveEmptyNode(this); 25.11 } 25.12 return this; 25.13 }
26.1 --- a/src/jdk/nashorn/internal/ir/ExecuteNode.java Tue Mar 19 11:03:24 2013 -0300 26.2 +++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java Sat Mar 23 00:58:39 2013 +0100 26.3 @@ -85,9 +85,9 @@ 26.4 26.5 @Override 26.6 public Node accept(final NodeVisitor visitor) { 26.7 - if (visitor.enter(this) != null) { 26.8 + if (visitor.enterExecuteNode(this) != null) { 26.9 setExpression(expression.accept(visitor)); 26.10 - return visitor.leave(this); 26.11 + return visitor.leaveExecuteNode(this); 26.12 } 26.13 26.14 return this;
27.1 --- a/src/jdk/nashorn/internal/ir/ForNode.java Tue Mar 19 11:03:24 2013 -0300 27.2 +++ b/src/jdk/nashorn/internal/ir/ForNode.java Sat Mar 23 00:58:39 2013 +0100 27.3 @@ -76,7 +76,7 @@ 27.4 27.5 @Override 27.6 public Node accept(final NodeVisitor visitor) { 27.7 - if (visitor.enter(this) != null) { 27.8 + if (visitor.enterForNode(this) != null) { 27.9 if (init != null) { 27.10 init = init.accept(visitor); 27.11 } 27.12 @@ -91,7 +91,7 @@ 27.13 27.14 body = (Block)body.accept(visitor); 27.15 27.16 - return visitor.leave(this); 27.17 + return visitor.leaveForNode(this); 27.18 } 27.19 27.20 return this;
28.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Tue Mar 19 11:03:24 2013 -0300 28.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Sat Mar 23 00:58:39 2013 +0100 28.3 @@ -34,7 +34,7 @@ 28.4 import java.util.Collections; 28.5 import java.util.EnumSet; 28.6 import java.util.HashMap; 28.7 -import java.util.LinkedList; 28.8 +import java.util.Iterator; 28.9 import java.util.List; 28.10 import java.util.Map; 28.11 import java.util.Stack; 28.12 @@ -47,7 +47,7 @@ 28.13 import jdk.nashorn.internal.ir.annotations.Ignore; 28.14 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 28.15 import jdk.nashorn.internal.parser.Parser; 28.16 -import jdk.nashorn.internal.runtime.Debug; 28.17 +import jdk.nashorn.internal.runtime.ScriptFunction; 28.18 import jdk.nashorn.internal.runtime.Source; 28.19 import jdk.nashorn.internal.runtime.UserAccessorProperty; 28.20 import jdk.nashorn.internal.runtime.linker.LinkerCallSite; 28.21 @@ -57,6 +57,8 @@ 28.22 */ 28.23 public class FunctionNode extends Block { 28.24 28.25 + private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class); 28.26 + 28.27 /** Function kinds */ 28.28 public enum Kind { 28.29 /** a normal function - nothing special */ 28.30 @@ -112,9 +114,6 @@ 28.31 /** List of parameters. */ 28.32 private List<IdentNode> parameters; 28.33 28.34 - /** List of nested functions. */ 28.35 - private List<FunctionNode> functions; 28.36 - 28.37 /** First token of function. **/ 28.38 private long firstToken; 28.39 28.40 @@ -157,10 +156,6 @@ 28.41 /** Pending control list. */ 28.42 private final Stack<Node> controlStack; 28.43 28.44 - /** Variable declarations in the function's scope */ 28.45 - @Ignore 28.46 - private final List<VarNode> declarations; 28.47 - 28.48 /** VarNode for this function statement */ 28.49 @Ignore //this is explicit code anyway and should not be traversed after lower 28.50 private VarNode funcVarNode; 28.51 @@ -184,33 +179,35 @@ 28.52 private int flags; 28.53 28.54 /** Is anonymous function flag. */ 28.55 - private static final int IS_ANONYMOUS = 0b0000_0000_0000_0001; 28.56 - /** Is statement flag */ 28.57 - private static final int IS_STATEMENT = 0b0000_0000_0000_0010; 28.58 + private static final int IS_ANONYMOUS = 1 << 0; 28.59 + /** Is the function created in a function declaration (as opposed to a function expression) */ 28.60 + private static final int IS_DECLARED = 1 << 1; 28.61 /** is this a strict mode function? */ 28.62 - private static final int IS_STRICT_MODE = 0b0000_0000_0000_0100; 28.63 + private static final int IS_STRICT_MODE = 1 << 2; 28.64 /** Does the function use the "arguments" identifier ? */ 28.65 - private static final int USES_ARGUMENTS = 0b0000_0000_0000_1000; 28.66 + private static final int USES_ARGUMENTS = 1 << 3; 28.67 /** Are we lowered ? */ 28.68 - private static final int IS_LOWERED = 0b0000_0000_0001_0000; 28.69 + private static final int IS_LOWERED = 1 << 4; 28.70 /** Has this node been split because it was too large? */ 28.71 - private static final int IS_SPLIT = 0b0000_0000_0010_0000; 28.72 + private static final int IS_SPLIT = 1 << 5; 28.73 /** Does the function call eval? */ 28.74 - private static final int HAS_EVAL = 0b0000_0000_0100_0000; 28.75 + private static final int HAS_EVAL = 1 << 6; 28.76 /** Does the function contain a with block ? */ 28.77 - private static final int HAS_WITH = 0b0000_0000_1000_0000; 28.78 + private static final int HAS_WITH = 1 << 7; 28.79 /** Does a descendant function contain a with or eval? */ 28.80 - private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0001_0000_0000; 28.81 + private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8; 28.82 /** Does the function define "arguments" identifier as a parameter of nested function name? */ 28.83 - private static final int DEFINES_ARGUMENTS = 0b0000_0010_0000_0000; 28.84 + private static final int DEFINES_ARGUMENTS = 1 << 9; 28.85 /** Does the function need a self symbol? */ 28.86 - private static final int NEEDS_SELF_SYMBOL = 0b0000_0100_0000_0000; 28.87 + private static final int NEEDS_SELF_SYMBOL = 1 << 10; 28.88 /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */ 28.89 - private static final int USES_ANCESTOR_SCOPE = 0b0000_1000_0000_0000; 28.90 + private static final int USES_ANCESTOR_SCOPE = 1 << 11; 28.91 /** Is this function lazily compiled? */ 28.92 - private static final int IS_LAZY = 0b0001_0000_0000_0000; 28.93 + private static final int IS_LAZY = 1 << 12; 28.94 /** Does this function have lazy, yet uncompiled children */ 28.95 - private static final int HAS_LAZY_CHILDREN = 0b0010_0000_0000_0000; 28.96 + private static final int HAS_LAZY_CHILDREN = 1 << 13; 28.97 + /** Does this function have lazy, yet uncompiled children */ 28.98 + private static final int IS_PROGRAM = 1 << 14; 28.99 28.100 /** Does this function or any nested functions contain a with or an eval? */ 28.101 private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL; 28.102 @@ -226,56 +223,34 @@ 28.103 private Type returnType = Type.UNKNOWN; 28.104 28.105 /** 28.106 - * Used to keep track of a function's parent blocks. 28.107 - * This is needed when a (finally body) block is cloned than contains inner functions. 28.108 - * Does not include function.getParent(). 28.109 - */ 28.110 - @Ignore 28.111 - private List<Block> referencingParentBlocks; 28.112 - 28.113 - /** 28.114 * Constructor 28.115 * 28.116 * @param source the source 28.117 * @param token token 28.118 * @param finish finish 28.119 * @param namespace the namespace 28.120 - * @param parent the parent block 28.121 * @param ident the identifier 28.122 * @param name the name of the function 28.123 */ 28.124 - @SuppressWarnings("LeakingThisInConstructor") 28.125 - public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) { 28.126 - super(source, token, finish, parent, null); 28.127 + public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) { 28.128 + super(source, token, finish); 28.129 28.130 this.ident = ident; 28.131 this.name = name; 28.132 this.kind = Kind.NORMAL; 28.133 this.parameters = new ArrayList<>(); 28.134 - this.functions = new ArrayList<>(); 28.135 this.firstToken = token; 28.136 this.lastToken = token; 28.137 this.namespace = namespace; 28.138 this.labelStack = new Stack<>(); 28.139 this.controlStack = new Stack<>(); 28.140 - this.declarations = new ArrayList<>(); 28.141 - // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies 28.142 - // it as such a leak - this is a false positive as we're setting this into a field of the object being 28.143 - // constructed, so it can't be seen from other threads. 28.144 - this.function = this; 28.145 this.compilationState = EnumSet.of(CompilationState.INITIALIZED); 28.146 this.specializedTypes = new HashMap<>(); 28.147 } 28.148 28.149 - @SuppressWarnings("LeakingThisInConstructor") 28.150 private FunctionNode(final FunctionNode functionNode, final CopyState cs) { 28.151 super(functionNode, cs); 28.152 28.153 - this.functions = new ArrayList<>(); 28.154 - for (final FunctionNode f : functionNode.getFunctions()) { 28.155 - this.functions.add((FunctionNode)cs.existingOrCopy(f)); 28.156 - } 28.157 - 28.158 this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident); 28.159 this.name = functionNode.name; 28.160 this.kind = functionNode.kind; 28.161 @@ -296,22 +271,12 @@ 28.162 this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode); 28.163 this.labelStack = new Stack<>(); 28.164 this.controlStack = new Stack<>(); 28.165 - this.declarations = new ArrayList<>(); 28.166 - 28.167 - for (final VarNode decl : functionNode.getDeclarations()) { 28.168 - declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same? 28.169 - } 28.170 28.171 this.flags = functionNode.flags; 28.172 28.173 this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode); 28.174 /** VarNode for this function statement */ 28.175 28.176 - // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies 28.177 - // it as such a leak - this is a false positive as we're setting this into a field of the object being 28.178 - // constructed, so it can't be seen from other threads. 28.179 - this.function = this; 28.180 - 28.181 this.compilationState = EnumSet.copyOf(functionNode.compilationState); 28.182 this.specializedTypes = new HashMap<>(); 28.183 } 28.184 @@ -319,21 +284,21 @@ 28.185 @Override 28.186 protected Node copy(final CopyState cs) { 28.187 // deep clone all parent blocks 28.188 - return fixBlockChain(new FunctionNode(this, cs)); 28.189 + return new FunctionNode(this, cs); 28.190 } 28.191 28.192 @Override 28.193 public Node accept(final NodeVisitor visitor) { 28.194 - final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode(); 28.195 - final Block saveBlock = visitor.getCurrentBlock(); 28.196 + final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode(); 28.197 + final Block saveBlock = visitor.getCurrentBlock(); 28.198 + final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter(); 28.199 + final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit(); 28.200 28.201 visitor.setCurrentFunctionNode(this); 28.202 - visitor.setCurrentCompileUnit(getCompileUnit()); 28.203 - visitor.setCurrentMethodEmitter(getMethodEmitter()); 28.204 visitor.setCurrentBlock(this); 28.205 28.206 try { 28.207 - if (visitor.enter(this) != null) { 28.208 + if (visitor.enterFunctionNode(this) != null) { 28.209 if (ident != null) { 28.210 ident = (IdentNode)ident.accept(visitor); 28.211 } 28.212 @@ -342,51 +307,25 @@ 28.213 parameters.set(i, (IdentNode)parameters.get(i).accept(visitor)); 28.214 } 28.215 28.216 - for (int i = 0, count = functions.size(); i < count; i++) { 28.217 - functions.set(i, (FunctionNode)functions.get(i).accept(visitor)); 28.218 - } 28.219 - 28.220 for (int i = 0, count = statements.size(); i < count; i++) { 28.221 statements.set(i, statements.get(i).accept(visitor)); 28.222 } 28.223 28.224 - return visitor.leave(this); 28.225 + return visitor.leaveFunctionNode(this); 28.226 } 28.227 } finally { 28.228 visitor.setCurrentBlock(saveBlock); 28.229 visitor.setCurrentFunctionNode(saveFunctionNode); 28.230 - visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null); 28.231 - visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null); 28.232 + visitor.setCurrentCompileUnit(saveCompileUnit); 28.233 + visitor.setCurrentMethodEmitter(saveMethodEmitter); 28.234 } 28.235 28.236 return this; 28.237 } 28.238 28.239 - /** 28.240 - * Locate the parent function. 28.241 - * 28.242 - * @return Parent function. 28.243 - */ 28.244 - public FunctionNode findParentFunction() { 28.245 - return getParent() != null ? getParent().getFunction() : null; 28.246 - } 28.247 - 28.248 - /** 28.249 - * Add parent name to the builder. 28.250 - * 28.251 - * @param sb String builder. 28.252 - */ 28.253 - @Override 28.254 - public void addParentName(final StringBuilder sb) { 28.255 - if (!isScript()) { 28.256 - sb.append(getName()); 28.257 - sb.append("$"); 28.258 - } 28.259 - } 28.260 - 28.261 @Override 28.262 public boolean needsScope() { 28.263 - return super.needsScope() || isScript(); 28.264 + return super.needsScope() || isProgram(); 28.265 } 28.266 28.267 /** 28.268 @@ -544,12 +483,18 @@ 28.269 } 28.270 28.271 /** 28.272 - * Determine if script function. 28.273 - * 28.274 - * @return True if script function. 28.275 + * Returns true if the function is the top-level program. 28.276 + * @return True if this function node represents the top-level program. 28.277 */ 28.278 - public boolean isScript() { 28.279 - return getParent() == null; 28.280 + public boolean isProgram() { 28.281 + return (flags & IS_PROGRAM) != 0; 28.282 + } 28.283 + 28.284 + /** 28.285 + * Marks the function as representing the top-level program. 28.286 + */ 28.287 + public void setProgram() { 28.288 + flags |= IS_PROGRAM; 28.289 } 28.290 28.291 /** 28.292 @@ -589,31 +534,31 @@ 28.293 28.294 /** 28.295 * Flag this function as using the {@code with} keyword 28.296 + * @param ancestors the iterator over functions in this functions's containing lexical context 28.297 */ 28.298 - public void setHasWith() { 28.299 + public void setHasWith(final Iterator<FunctionNode> ancestors) { 28.300 if(!hasWith()) { 28.301 this.flags |= HAS_WITH; 28.302 // with requires scope in parents. 28.303 // TODO: refine this. with should not force all variables in parents to be in scope, only those that are 28.304 // actually referenced as identifiers by name 28.305 - markParentForWithOrEval(); 28.306 + markParentForWithOrEval(ancestors); 28.307 } 28.308 } 28.309 28.310 - private void markParentForWithOrEval() { 28.311 + private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) { 28.312 // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope. 28.313 setNeedsScope(); 28.314 28.315 - final FunctionNode parentFunction = findParentFunction(); 28.316 - if(parentFunction != null) { 28.317 - parentFunction.setDescendantHasWithOrEval(); 28.318 + if(ancestors.hasNext()) { 28.319 + ancestors.next().setDescendantHasWithOrEval(ancestors); 28.320 } 28.321 } 28.322 28.323 - private void setDescendantHasWithOrEval() { 28.324 + private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) { 28.325 if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) { 28.326 flags |= HAS_DESCENDANT_WITH_OR_EVAL; 28.327 - markParentForWithOrEval(); 28.328 + markParentForWithOrEval(ancestors); 28.329 } 28.330 } 28.331 28.332 @@ -628,11 +573,12 @@ 28.333 28.334 /** 28.335 * Flag this function as calling the {@code eval} function 28.336 + * @param ancestors the iterator over functions in this functions's containing lexical context 28.337 */ 28.338 - public void setHasEval() { 28.339 + public void setHasEval(final Iterator<FunctionNode> ancestors) { 28.340 if(!hasEval()) { 28.341 this.flags |= HAS_EVAL; 28.342 - markParentForWithOrEval(); 28.343 + markParentForWithOrEval(ancestors); 28.344 } 28.345 } 28.346 28.347 @@ -665,11 +611,34 @@ 28.348 } 28.349 28.350 /** 28.351 - * Get all nested functions 28.352 - * @return list of nested functions in this function 28.353 + * Returns a list of functions declared by this function. Only includes declared functions, and does not include any 28.354 + * function expressions that might occur in its body. 28.355 + * @return a list of functions declared by this function. 28.356 */ 28.357 - public List<FunctionNode> getFunctions() { 28.358 - return Collections.unmodifiableList(functions); 28.359 + public List<FunctionNode> getDeclaredFunctions() { 28.360 + // Note that the function does not have a dedicated list of declared functions, but rather relies on the 28.361 + // invariant that all function declarations are at the beginning of the statement list as VarNode with a 28.362 + // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a 28.363 + // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors. 28.364 + final List<FunctionNode> fns = new ArrayList<>(); 28.365 + for (final Node stmt : statements) { 28.366 + if(stmt instanceof LineNumberNode) { 28.367 + continue; 28.368 + } else if(stmt instanceof VarNode) { 28.369 + final Node init = ((VarNode)stmt).getInit(); 28.370 + if(init instanceof FunctionNode) { 28.371 + final FunctionNode fn = (FunctionNode)init; 28.372 + if(fn.isDeclared()) { 28.373 + fns.add(fn); 28.374 + continue; 28.375 + } 28.376 + } 28.377 + } 28.378 + // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are 28.379 + // at the start of the function, we've reached the end of function declarations. 28.380 + break; 28.381 + } 28.382 + return fns; 28.383 } 28.384 28.385 /** 28.386 @@ -801,7 +770,7 @@ 28.387 public boolean needsArguments() { 28.388 // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since 28.389 // for top-level script, "arguments" is picked up from Context by Global.init() instead. 28.390 - return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript(); 28.391 + return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram(); 28.392 } 28.393 28.394 /** 28.395 @@ -820,7 +789,7 @@ 28.396 * @return true if the function needs parent scope. 28.397 */ 28.398 public boolean needsParentScope() { 28.399 - return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript(); 28.400 + return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram(); 28.401 } 28.402 28.403 /** 28.404 @@ -880,7 +849,7 @@ 28.405 * @return true if all variables should be in scope 28.406 */ 28.407 public boolean allVarsInScope() { 28.408 - return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0; 28.409 + return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0; 28.410 } 28.411 28.412 /** 28.413 @@ -989,19 +958,19 @@ 28.414 } 28.415 28.416 /** 28.417 - * Check if this function is a statement 28.418 - * @return true if function is a statement 28.419 + * Check if this function is created as a function declaration (as opposed to function expression) 28.420 + * @return true if function is declared. 28.421 */ 28.422 - public boolean isStatement() { 28.423 - return (flags & IS_STATEMENT) != 0; 28.424 + public boolean isDeclared() { 28.425 + return (flags & IS_DECLARED) != 0; 28.426 } 28.427 28.428 /** 28.429 - * Flag this function as a statement 28.430 + * Flag this function as being created as a function declaration (as opposed to a function expression). 28.431 * @see Parser 28.432 */ 28.433 - public void setIsStatement() { 28.434 - this.flags |= IS_STATEMENT; 28.435 + public void setIsDeclared() { 28.436 + this.flags |= IS_DECLARED; 28.437 } 28.438 28.439 /** 28.440 @@ -1049,35 +1018,16 @@ 28.441 } 28.442 28.443 /** 28.444 - * Marks this function as one using any global symbol. The function and all its parent functions will all be marked 28.445 - * as needing parent scope. 28.446 - * @see #needsParentScope() 28.447 + * Marks this function as using any of its ancestors' scopes. 28.448 */ 28.449 - public void setUsesGlobalSymbol() { 28.450 + public void setUsesAncestorScope() { 28.451 this.flags |= USES_ANCESTOR_SCOPE; 28.452 - final FunctionNode parentFn = findParentFunction(); 28.453 - if(parentFn != null) { 28.454 - parentFn.setUsesGlobalSymbol(); 28.455 - } 28.456 } 28.457 28.458 - /** 28.459 - * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not 28.460 - * including the function defining the symbol will be marked as needing parent scope. The function defining the 28.461 - * symbol will be marked as one that needs to have its own scope. 28.462 - * @param symbol the symbol being used. 28.463 - * @see #needsParentScope() 28.464 - */ 28.465 - public void setUsesScopeSymbol(final Symbol symbol) { 28.466 - if(symbol.getBlock() == this) { 28.467 - setNeedsScope(); 28.468 - } else { 28.469 - this.flags |= USES_ANCESTOR_SCOPE; 28.470 - final FunctionNode parentFn = findParentFunction(); 28.471 - if (parentFn != null) { 28.472 - parentFn.setUsesScopeSymbol(symbol); 28.473 - } 28.474 - } 28.475 + @Override 28.476 + void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) { 28.477 + setUsesAncestorScope(); 28.478 + super.setUsesParentScopeSymbol(symbol, ancestors); 28.479 } 28.480 28.481 /** 28.482 @@ -1152,7 +1102,7 @@ 28.483 28.484 @Override 28.485 public Type getType() { 28.486 - return getReturnType(); 28.487 + return FUNCTION_TYPE; 28.488 } 28.489 28.490 /** 28.491 @@ -1212,56 +1162,6 @@ 28.492 } 28.493 28.494 /** 28.495 - * Add a new function to the function list. 28.496 - * 28.497 - * @param functionNode Function node to add. 28.498 - */ 28.499 - @Override 28.500 - public void addFunction(final FunctionNode functionNode) { 28.501 - assert functionNode != null; 28.502 - functions.add(functionNode); 28.503 - } 28.504 - 28.505 - /** 28.506 - * Add a list of functions to the function list. 28.507 - * 28.508 - * @param functionNodes Function nodes to add. 28.509 - */ 28.510 - @Override 28.511 - public void addFunctions(final List<FunctionNode> functionNodes) { 28.512 - functions.addAll(functionNodes); 28.513 - } 28.514 - 28.515 - /** 28.516 - * Set a function list 28.517 - * 28.518 - * @param functionNodes to set 28.519 - */ 28.520 - @Override 28.521 - public void setFunctions(final List<FunctionNode> functionNodes) { 28.522 - this.functions = functionNodes; 28.523 - } 28.524 - 28.525 - /** 28.526 - * Add a variable declaration that should be visible to the entire function 28.527 - * scope. Parser does this. 28.528 - * 28.529 - * @param varNode a var node 28.530 - */ 28.531 - public void addDeclaration(final VarNode varNode) { 28.532 - declarations.add(varNode); 28.533 - } 28.534 - 28.535 - /** 28.536 - * Return all variable declarations from this function scope 28.537 - * 28.538 - * @return all VarNodes in scope 28.539 - */ 28.540 - public List<VarNode> getDeclarations() { 28.541 - return Collections.unmodifiableList(declarations); 28.542 - } 28.543 - 28.544 - /** 28.545 * Get the compile unit used to compile this function 28.546 * @see Compiler 28.547 * @return the compile unit 28.548 @@ -1294,32 +1194,4 @@ 28.549 public void setMethodEmitter(final MethodEmitter method) { 28.550 this.method = method; 28.551 } 28.552 - 28.553 - /** 28.554 - * Each FunctionNode maintains a list of reference to its parent blocks. 28.555 - * Add a parent block to this function. 28.556 - * 28.557 - * @param parentBlock a block to remember as parent 28.558 - */ 28.559 - public void addReferencingParentBlock(final Block parentBlock) { 28.560 - assert parentBlock.getFunction() == function.findParentFunction() : Debug.id(parentBlock.getFunction()) + "!=" + Debug.id(function.findParentFunction()); // all parent blocks must be in the same function 28.561 - if (parentBlock != function.getParent()) { 28.562 - if (referencingParentBlocks == null) { 28.563 - referencingParentBlocks = new LinkedList<>(); 28.564 - } 28.565 - referencingParentBlocks.add(parentBlock); 28.566 - } 28.567 - } 28.568 - 28.569 - /** 28.570 - * Get the known parent blocks to this function 28.571 - * 28.572 - * @return list of parent blocks 28.573 - */ 28.574 - public List<Block> getReferencingParentBlocks() { 28.575 - if (referencingParentBlocks == null) { 28.576 - return Collections.emptyList(); 28.577 - } 28.578 - return Collections.unmodifiableList(referencingParentBlocks); 28.579 - } 28.580 }
29.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java Tue Mar 19 11:03:24 2013 -0300 29.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Sat Mar 23 00:58:39 2013 +0100 29.3 @@ -38,18 +38,18 @@ 29.4 /** 29.5 * IR representation for an identifier. 29.6 */ 29.7 -public class IdentNode extends Node implements PropertyKey, TypeOverride, FunctionCall { 29.8 +public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall { 29.9 + private static final int PROPERTY_NAME = 1 << 0; 29.10 + private static final int INITIALIZED_HERE = 1 << 1; 29.11 + private static final int FUNCTION = 1 << 2; 29.12 + 29.13 /** Identifier. */ 29.14 private final String name; 29.15 29.16 /** Type for a callsite, e.g. X in a get()X or a set(X)V */ 29.17 private Type callSiteType; 29.18 29.19 - /** flag for an ident that is the property name of an AccessNode. */ 29.20 - private boolean isPropertyName; 29.21 - 29.22 - /** flag for an ident on the left hand side of <code>var lhs = rhs;</code>. */ 29.23 - private boolean isInitializedHere; 29.24 + private byte flags; 29.25 29.26 /** 29.27 * Constructor 29.28 @@ -71,9 +71,8 @@ 29.29 */ 29.30 public IdentNode(final IdentNode identNode) { 29.31 super(identNode); 29.32 - this.name = identNode.getName(); 29.33 - this.isPropertyName = identNode.isPropertyName; 29.34 - this.isInitializedHere = identNode.isInitializedHere; 29.35 + this.name = identNode.getName(); 29.36 + this.flags = identNode.flags; 29.37 } 29.38 29.39 @Override 29.40 @@ -92,12 +91,17 @@ 29.41 } 29.42 29.43 @Override 29.44 - public void setType(final Type type) { 29.45 + public IdentNode setType(final Type type) { 29.46 if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 29.47 ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 29.48 } 29.49 - this.callSiteType = type; 29.50 // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't 29.51 + if(this.callSiteType == type) { 29.52 + return this; 29.53 + } 29.54 + final IdentNode n = (IdentNode)clone(); 29.55 + n.callSiteType = type; 29.56 + return n; 29.57 } 29.58 29.59 @Override 29.60 @@ -131,8 +135,8 @@ 29.61 */ 29.62 @Override 29.63 public Node accept(final NodeVisitor visitor) { 29.64 - if (visitor.enter(this) != null) { 29.65 - return visitor.leave(this); 29.66 + if (visitor.enterIdentNode(this) != null) { 29.67 + return visitor.leaveIdentNode(this); 29.68 } 29.69 29.70 return this; 29.71 @@ -179,14 +183,18 @@ 29.72 * @return true if this is a property name 29.73 */ 29.74 public boolean isPropertyName() { 29.75 - return isPropertyName; 29.76 + return (flags & PROPERTY_NAME) != 0; 29.77 } 29.78 29.79 /** 29.80 * Flag this IdentNode as a property name 29.81 + * @return a node equivalent to this one except for the requested change. 29.82 */ 29.83 - public void setIsPropertyName() { 29.84 - isPropertyName = true; 29.85 + public IdentNode setIsPropertyName() { 29.86 + if(isPropertyName()) return this; 29.87 + final IdentNode n = (IdentNode)clone(); 29.88 + n.flags |= PROPERTY_NAME; 29.89 + return n; 29.90 } 29.91 29.92 /** 29.93 @@ -194,14 +202,18 @@ 29.94 * @return true if IdentNode is initialized on creation 29.95 */ 29.96 public boolean isInitializedHere() { 29.97 - return isInitializedHere; 29.98 + return (flags & INITIALIZED_HERE) != 0; 29.99 } 29.100 29.101 /** 29.102 * Flag IdentNode to be initialized on creation 29.103 + * @return a node equivalent to this one except for the requested change. 29.104 */ 29.105 - public void setIsInitializedHere() { 29.106 - isInitializedHere = true; 29.107 + public IdentNode setIsInitializedHere() { 29.108 + if(isInitializedHere()) return this; 29.109 + final IdentNode n = (IdentNode)clone(); 29.110 + n.flags |= INITIALIZED_HERE; 29.111 + return n; 29.112 } 29.113 29.114 /** 29.115 @@ -216,6 +228,17 @@ 29.116 29.117 @Override 29.118 public boolean isFunction() { 29.119 - return false; 29.120 + return (flags & FUNCTION) != 0; 29.121 + } 29.122 + 29.123 + /** 29.124 + * Mark this node as being the callee operand of a {@link CallNode}. 29.125 + * @return an ident node identical to this one in all aspects except with its function flag set. 29.126 + */ 29.127 + public IdentNode setIsFunction() { 29.128 + if(isFunction()) return this; 29.129 + final IdentNode n = (IdentNode)clone(); 29.130 + n.flags |= FUNCTION; 29.131 + return n; 29.132 } 29.133 }
30.1 --- a/src/jdk/nashorn/internal/ir/IfNode.java Tue Mar 19 11:03:24 2013 -0300 30.2 +++ b/src/jdk/nashorn/internal/ir/IfNode.java Sat Mar 23 00:58:39 2013 +0100 30.3 @@ -75,7 +75,7 @@ 30.4 30.5 @Override 30.6 public Node accept(final NodeVisitor visitor) { 30.7 - if (visitor.enter(this) != null) { 30.8 + if (visitor.enterIfNode(this) != null) { 30.9 test = test.accept(visitor); 30.10 30.11 pass = (Block)pass.accept(visitor); 30.12 @@ -84,7 +84,7 @@ 30.13 fail = (Block)fail.accept(visitor); 30.14 } 30.15 30.16 - return visitor.leave(this); 30.17 + return visitor.leaveIfNode(this); 30.18 } 30.19 30.20 return this;
31.1 --- a/src/jdk/nashorn/internal/ir/IndexNode.java Tue Mar 19 11:03:24 2013 -0300 31.2 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java Sat Mar 23 00:58:39 2013 +0100 31.3 @@ -36,7 +36,7 @@ 31.4 * IR representation of an indexed access (brackets operator.) 31.5 * 31.6 */ 31.7 -public class IndexNode extends BaseNode implements TypeOverride { 31.8 +public class IndexNode extends BaseNode implements TypeOverride<IndexNode> { 31.9 /** Property ident. */ 31.10 private Node index; 31.11 31.12 @@ -92,10 +92,10 @@ 31.13 31.14 @Override 31.15 public Node accept(final NodeVisitor visitor) { 31.16 - if (visitor.enter(this) != null) { 31.17 + if (visitor.enterIndexNode(this) != null) { 31.18 base = base.accept(visitor); 31.19 index = index.accept(visitor); 31.20 - return visitor.leave(this); 31.21 + return visitor.leaveIndexNode(this); 31.22 } 31.23 31.24 return this; 31.25 @@ -144,12 +144,13 @@ 31.26 } 31.27 31.28 @Override 31.29 - public void setType(final Type type) { 31.30 + public IndexNode setType(final Type type) { 31.31 if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 31.32 ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 31.33 } 31.34 hasCallSiteType = true; 31.35 getSymbol().setTypeOverride(type); 31.36 + return this; 31.37 } 31.38 31.39 @Override
32.1 --- a/src/jdk/nashorn/internal/ir/LabelNode.java Tue Mar 19 11:03:24 2013 -0300 32.2 +++ b/src/jdk/nashorn/internal/ir/LabelNode.java Sat Mar 23 00:58:39 2013 +0100 32.3 @@ -81,10 +81,10 @@ 32.4 32.5 @Override 32.6 public Node accept(final NodeVisitor visitor) { 32.7 - if (visitor.enter(this) != null) { 32.8 + if (visitor.enterLabelNode(this) != null) { 32.9 label = (IdentNode)label.accept(visitor); 32.10 body = (Block)body.accept(visitor); 32.11 - return visitor.leave(this); 32.12 + return visitor.leaveLabelNode(this); 32.13 } 32.14 32.15 return this;
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Sat Mar 23 00:58:39 2013 +0100 33.3 @@ -0,0 +1,198 @@ 33.4 +package jdk.nashorn.internal.ir; 33.5 + 33.6 +import java.util.ArrayDeque; 33.7 +import java.util.Deque; 33.8 +import java.util.Iterator; 33.9 +import java.util.NoSuchElementException; 33.10 + 33.11 +/** 33.12 + * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special 33.13 + * methods to retrieve useful subsets of the context. 33.14 + */ 33.15 +public class LexicalContext implements Cloneable { 33.16 + private final Deque<Block> lexicalContext; 33.17 + 33.18 + /** 33.19 + * Creates a new empty lexical context. 33.20 + */ 33.21 + public LexicalContext() { 33.22 + lexicalContext = new ArrayDeque<>(); 33.23 + } 33.24 + 33.25 + /** 33.26 + * Pushes a new block on top of the context, making it the innermost open block. 33.27 + * @param block the new block 33.28 + */ 33.29 + public void push(Block block) { 33.30 + //new Exception(block.toString()).printStackTrace(); 33.31 + lexicalContext.push(block); 33.32 + } 33.33 + 33.34 + /** 33.35 + * Pops the innermost block off the context. 33.36 + * @param the block expected to be popped, used to detect unbalanced pushes/pops 33.37 + */ 33.38 + public void pop(Block block) { 33.39 + final Block popped = lexicalContext.pop(); 33.40 + assert popped == block; 33.41 + } 33.42 + 33.43 + /** 33.44 + * Returns an iterator over all blocks in the context, with the top block (innermost lexical context) first. 33.45 + * @return an iterator over all blocks in the context. 33.46 + */ 33.47 + public Iterator<Block> getBlocks() { 33.48 + return lexicalContext.iterator(); 33.49 + } 33.50 + 33.51 + /** 33.52 + * Returns an iterator over all functions in the context, with the top (innermost open) function first. 33.53 + * @return an iterator over all functions in the context. 33.54 + */ 33.55 + public Iterator<FunctionNode> getFunctions() { 33.56 + return new FunctionIterator(getBlocks()); 33.57 + } 33.58 + 33.59 + private static final class FunctionIterator implements Iterator<FunctionNode> { 33.60 + private final Iterator<Block> it; 33.61 + private FunctionNode next; 33.62 + 33.63 + FunctionIterator(Iterator<Block> it) { 33.64 + this.it = it; 33.65 + next = findNext(); 33.66 + } 33.67 + 33.68 + @Override 33.69 + public boolean hasNext() { 33.70 + return next != null; 33.71 + } 33.72 + 33.73 + @Override 33.74 + public FunctionNode next() { 33.75 + if(next == null) { 33.76 + throw new NoSuchElementException(); 33.77 + } 33.78 + FunctionNode lnext = next; 33.79 + next = findNext(); 33.80 + return lnext; 33.81 + } 33.82 + 33.83 + private FunctionNode findNext() { 33.84 + while(it.hasNext()) { 33.85 + final Block block = it.next(); 33.86 + if(block instanceof FunctionNode) { 33.87 + return ((FunctionNode)block); 33.88 + } 33.89 + } 33.90 + return null; 33.91 + } 33.92 + 33.93 + @Override 33.94 + public void remove() { 33.95 + throw new UnsupportedOperationException(); 33.96 + } 33.97 + } 33.98 + 33.99 + /** 33.100 + * Returns an iterator over all ancestors block of the given block, with its parent block first. 33.101 + * @param block the block whose ancestors are returned 33.102 + * @return an iterator over all ancestors block of the given block. 33.103 + */ 33.104 + public Iterator<Block> getAncestorBlocks(Block block) { 33.105 + final Iterator<Block> it = getBlocks(); 33.106 + while(it.hasNext()) { 33.107 + final Block b = it.next(); 33.108 + if(block == b) { 33.109 + return it; 33.110 + } 33.111 + } 33.112 + throw new AssertionError("Block is not on the current lexical context stack"); 33.113 + } 33.114 + 33.115 + /** 33.116 + * Returns an iterator over a block and all its ancestors blocks, with the block first. 33.117 + * @param block the block that is the starting point of the iteration. 33.118 + * @return an iterator over a block and all its ancestors. 33.119 + */ 33.120 + public Iterator<Block> getBlocks(final Block block) { 33.121 + final Iterator<Block> it = getAncestorBlocks(block); 33.122 + return new Iterator<Block>() { 33.123 + boolean blockReturned = false; 33.124 + @Override 33.125 + public boolean hasNext() { 33.126 + return it.hasNext() || !blockReturned; 33.127 + } 33.128 + @Override 33.129 + public Block next() { 33.130 + if(blockReturned) { 33.131 + return it.next(); 33.132 + } 33.133 + blockReturned = true; 33.134 + return block; 33.135 + } 33.136 + @Override 33.137 + public void remove() { 33.138 + throw new UnsupportedOperationException(); 33.139 + } 33.140 + }; 33.141 + } 33.142 + 33.143 + /** 33.144 + * Returns the closest function node to the block. If the block is itself a function, it is returned. 33.145 + * @param block the block 33.146 + * @return the function closest to the block. 33.147 + * @see #getParentFunction(Block) 33.148 + */ 33.149 + public FunctionNode getFunction(Block block) { 33.150 + if(block instanceof FunctionNode) { 33.151 + return (FunctionNode)block; 33.152 + } 33.153 + return getParentFunction(block); 33.154 + } 33.155 + 33.156 + /** 33.157 + * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function, 33.158 + * it is returned too. 33.159 + * @param block the block 33.160 + * @return the closest function node to the block and all its ancestor functions. 33.161 + */ 33.162 + public Iterator<FunctionNode> getFunctions(final Block block) { 33.163 + return new FunctionIterator(getBlocks(block)); 33.164 + } 33.165 + 33.166 + /** 33.167 + * Returns the containing function of the block. If the block is itself a function, its parent function is returned. 33.168 + * @param block the block 33.169 + * @return the containing function of the block. 33.170 + * @see #getFunction(Block) 33.171 + */ 33.172 + public FunctionNode getParentFunction(Block block) { 33.173 + return getFirstFunction(getAncestorBlocks(block)); 33.174 + } 33.175 + 33.176 + private static FunctionNode getFirstFunction(Iterator<Block> it) { 33.177 + while(it.hasNext()) { 33.178 + final Block ancestor = it.next(); 33.179 + if(ancestor instanceof FunctionNode) { 33.180 + return (FunctionNode)ancestor; 33.181 + } 33.182 + } 33.183 + return null; 33.184 + } 33.185 + 33.186 + /** 33.187 + * Returns the innermost block in the context. 33.188 + * @return the innermost block in the context. 33.189 + */ 33.190 + public Block getCurrentBlock() { 33.191 + return lexicalContext.element(); 33.192 + } 33.193 + 33.194 + /** 33.195 + * Returns the innermost function in the context. 33.196 + * @return the innermost function in the context. 33.197 + */ 33.198 + public FunctionNode getCurrentFunction() { 33.199 + return getFirstFunction(getBlocks()); 33.200 + } 33.201 +}
34.1 --- a/src/jdk/nashorn/internal/ir/LineNumberNode.java Tue Mar 19 11:03:24 2013 -0300 34.2 +++ b/src/jdk/nashorn/internal/ir/LineNumberNode.java Sat Mar 23 00:58:39 2013 +0100 34.3 @@ -63,8 +63,8 @@ 34.4 34.5 @Override 34.6 public Node accept(final NodeVisitor visitor) { 34.7 - if (visitor.enter(this) != null) { 34.8 - return visitor.leave(this); 34.9 + if (visitor.enterLineNumberNode(this) != null) { 34.10 + return visitor.leaveLineNumberNode(this); 34.11 } 34.12 34.13 return this;
35.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Tue Mar 19 11:03:24 2013 -0300 35.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Sat Mar 23 00:58:39 2013 +0100 35.3 @@ -46,7 +46,7 @@ 35.4 */ 35.5 public abstract class LiteralNode<T> extends Node implements PropertyKey { 35.6 /** Literal value */ 35.7 - protected T value; 35.8 + protected final T value; 35.9 35.10 /** 35.11 * Constructor 35.12 @@ -67,8 +67,17 @@ 35.13 * @param literalNode source node 35.14 */ 35.15 protected LiteralNode(final LiteralNode<T> literalNode) { 35.16 + this(literalNode, literalNode.value); 35.17 + } 35.18 + 35.19 + /** 35.20 + * A copy constructor with value change. 35.21 + * @param literalNode the original literal node 35.22 + * @param newValue new value for this node 35.23 + */ 35.24 + protected LiteralNode(final LiteralNode<T> literalNode, final T newValue) { 35.25 super(literalNode); 35.26 - this.value = literalNode.value; 35.27 + this.value = newValue; 35.28 } 35.29 35.30 @Override 35.31 @@ -217,8 +226,8 @@ 35.32 */ 35.33 @Override 35.34 public Node accept(final NodeVisitor visitor) { 35.35 - if (visitor.enter(this) != null) { 35.36 - return visitor.leave(this); 35.37 + if (visitor.enterLiteralNode(this) != null) { 35.38 + return visitor.leaveLiteralNode(this); 35.39 } 35.40 35.41 return this; 35.42 @@ -544,6 +553,10 @@ 35.43 super(literalNode); 35.44 } 35.45 35.46 + private NodeLiteralNode(final LiteralNode<Node> literalNode, final Node value) { 35.47 + super(literalNode, value); 35.48 + } 35.49 + 35.50 @Override 35.51 protected Node copy(final CopyState cs) { 35.52 return new NodeLiteralNode(this); 35.53 @@ -551,11 +564,14 @@ 35.54 35.55 @Override 35.56 public Node accept(final NodeVisitor visitor) { 35.57 - if (visitor.enter(this) != null) { 35.58 + if (visitor.enterLiteralNode(this) != null) { 35.59 if (value != null) { 35.60 - value = value.accept(visitor); 35.61 + final Node newValue = value.accept(visitor); 35.62 + if(value != newValue) { 35.63 + return visitor.leaveLiteralNode(new NodeLiteralNode(this, newValue)); 35.64 + } 35.65 } 35.66 - return visitor.leave(this); 35.67 + return visitor.leaveLiteralNode(this); 35.68 } 35.69 35.70 return this; 35.71 @@ -878,14 +894,14 @@ 35.72 35.73 @Override 35.74 public Node accept(final NodeVisitor visitor) { 35.75 - if (visitor.enter(this) != null) { 35.76 + if (visitor.enterLiteralNode(this) != null) { 35.77 for (int i = 0; i < value.length; i++) { 35.78 final Node element = value[i]; 35.79 if (element != null) { 35.80 value[i] = element.accept(visitor); 35.81 } 35.82 } 35.83 - return visitor.leave(this); 35.84 + return visitor.leaveLiteralNode(this); 35.85 } 35.86 return this; 35.87 }
36.1 --- a/src/jdk/nashorn/internal/ir/Location.java Tue Mar 19 11:03:24 2013 -0300 36.2 +++ b/src/jdk/nashorn/internal/ir/Location.java Sat Mar 23 00:58:39 2013 +0100 36.3 @@ -65,7 +65,11 @@ 36.4 36.5 @Override 36.6 protected Object clone() { 36.7 - return new Location(this); 36.8 + try { 36.9 + return super.clone(); 36.10 + } catch(CloneNotSupportedException e) { 36.11 + throw new AssertionError(e); 36.12 + } 36.13 } 36.14 36.15 @Override
37.1 --- a/src/jdk/nashorn/internal/ir/Node.java Tue Mar 19 11:03:24 2013 -0300 37.2 +++ b/src/jdk/nashorn/internal/ir/Node.java Sat Mar 23 00:58:39 2013 +0100 37.3 @@ -165,12 +165,19 @@ 37.4 return true; 37.5 } 37.6 37.7 - setIsResolved(); 37.8 + setIsResolved(true); 37.9 37.10 return false; 37.11 } 37.12 37.13 /** 37.14 + * Reset the resolved flag. 37.15 + */ 37.16 + public void resetResolved() { 37.17 + setIsResolved(false); 37.18 + } 37.19 + 37.20 + /** 37.21 * Is this a debug info node like LineNumberNode etc? 37.22 * 37.23 * @return true if this is a debug node 37.24 @@ -234,8 +241,7 @@ 37.25 * 37.26 * @return Deep copy of the Node. 37.27 */ 37.28 - @Override 37.29 - public final Node clone() { 37.30 + public final Node copy() { 37.31 return copy(new CopyState()); 37.32 } 37.33 37.34 @@ -349,10 +355,10 @@ 37.35 } 37.36 37.37 /** 37.38 - * Flag this node as resolved, i.e. code has been generated for it 37.39 + * Flag this node as resolved or not, i.e. code has been generated for it 37.40 */ 37.41 - public void setIsResolved() { 37.42 - this.isResolved = true; 37.43 + private void setIsResolved(boolean isResolved) { 37.44 + this.isResolved = isResolved; 37.45 } 37.46 37.47 /**
38.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java Tue Mar 19 11:03:24 2013 -0300 38.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java Sat Mar 23 00:58:39 2013 +0100 38.3 @@ -72,12 +72,12 @@ 38.4 38.5 @Override 38.6 public Node accept(final NodeVisitor visitor) { 38.7 - if (visitor.enter(this) != null) { 38.8 + if (visitor.enterObjectNode(this) != null) { 38.9 for (int i = 0, count = elements.size(); i < count; i++) { 38.10 elements.set(i, elements.get(i).accept(visitor)); 38.11 } 38.12 38.13 - return visitor.leave(this); 38.14 + return visitor.leaveObjectNode(this); 38.15 } 38.16 38.17 return this;
39.1 --- a/src/jdk/nashorn/internal/ir/PropertyNode.java Tue Mar 19 11:03:24 2013 -0300 39.2 +++ b/src/jdk/nashorn/internal/ir/PropertyNode.java Sat Mar 23 00:58:39 2013 +0100 39.3 @@ -88,7 +88,7 @@ 39.4 39.5 @Override 39.6 public Node accept(final NodeVisitor visitor) { 39.7 - if (visitor.enter(this) != null) { 39.8 + if (visitor.enterPropertyNode(this) != null) { 39.9 key = (PropertyKey)((Node)key).accept(visitor); 39.10 39.11 if (value != null) { 39.12 @@ -103,7 +103,7 @@ 39.13 setter = setter.accept(visitor); 39.14 } 39.15 39.16 - return visitor.leave(this); 39.17 + return visitor.leavePropertyNode(this); 39.18 } 39.19 39.20 return this;
40.1 --- a/src/jdk/nashorn/internal/ir/ReferenceNode.java Tue Mar 19 11:03:24 2013 -0300 40.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 40.3 @@ -1,91 +0,0 @@ 40.4 -/* 40.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 40.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 40.7 - * 40.8 - * This code is free software; you can redistribute it and/or modify it 40.9 - * under the terms of the GNU General Public License version 2 only, as 40.10 - * published by the Free Software Foundation. Oracle designates this 40.11 - * particular file as subject to the "Classpath" exception as provided 40.12 - * by Oracle in the LICENSE file that accompanied this code. 40.13 - * 40.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 40.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 40.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 40.17 - * version 2 for more details (a copy is included in the LICENSE file that 40.18 - * accompanied this code). 40.19 - * 40.20 - * You should have received a copy of the GNU General Public License version 40.21 - * 2 along with this work; if not, write to the Free Software Foundation, 40.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 40.23 - * 40.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 40.25 - * or visit www.oracle.com if you need additional information or have any 40.26 - * questions. 40.27 - */ 40.28 - 40.29 -package jdk.nashorn.internal.ir; 40.30 - 40.31 -import jdk.nashorn.internal.ir.annotations.Reference; 40.32 -import jdk.nashorn.internal.ir.visitor.NodeVisitor; 40.33 -import jdk.nashorn.internal.runtime.Source; 40.34 - 40.35 -/** 40.36 - * IR representation of a reference to another entity (function.) 40.37 - */ 40.38 -public class ReferenceNode extends Node { 40.39 - /** Node referenced. */ 40.40 - @Reference 40.41 - private final FunctionNode reference; 40.42 - 40.43 - /** 40.44 - * Constructor 40.45 - * 40.46 - * @param source the source 40.47 - * @param token token 40.48 - * @param finish finish 40.49 - * @param reference the function node to reference 40.50 - */ 40.51 - public ReferenceNode(final Source source, final long token, final int finish, final FunctionNode reference) { 40.52 - super(source, token, finish); 40.53 - 40.54 - this.reference = reference; 40.55 - } 40.56 - 40.57 - private ReferenceNode(final ReferenceNode referenceNode) { 40.58 - super(referenceNode); 40.59 - 40.60 - this.reference = referenceNode.reference; 40.61 - } 40.62 - 40.63 - @Override 40.64 - protected Node copy(final CopyState cs) { 40.65 - return new ReferenceNode(this); 40.66 - } 40.67 - 40.68 - @Override 40.69 - public Node accept(final NodeVisitor visitor) { 40.70 - if (visitor.enter(this) != null) { 40.71 - return visitor.leave(this); 40.72 - } 40.73 - 40.74 - return this; 40.75 - } 40.76 - 40.77 - @Override 40.78 - public void toString(final StringBuilder sb) { 40.79 - if (reference == null) { 40.80 - sb.append("null"); 40.81 - } else { 40.82 - reference.toString(sb); 40.83 - } 40.84 - } 40.85 - 40.86 - /** 40.87 - * Get there function node reference that this node points tp 40.88 - * @return a function node reference 40.89 - */ 40.90 - public FunctionNode getReference() { 40.91 - return reference; 40.92 - } 40.93 - 40.94 -}
41.1 --- a/src/jdk/nashorn/internal/ir/ReturnNode.java Tue Mar 19 11:03:24 2013 -0300 41.2 +++ b/src/jdk/nashorn/internal/ir/ReturnNode.java Sat Mar 23 00:58:39 2013 +0100 41.3 @@ -100,12 +100,12 @@ 41.4 41.5 @Override 41.6 public Node accept(final NodeVisitor visitor) { 41.7 - if (visitor.enter(this) != null) { 41.8 + if (visitor.enterReturnNode(this) != null) { 41.9 if (expression != null) { 41.10 expression = expression.accept(visitor); 41.11 } 41.12 41.13 - return visitor.leave(this); 41.14 + return visitor.leaveReturnNode(this); 41.15 } 41.16 41.17 return this;
42.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Mar 19 11:03:24 2013 -0300 42.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Sat Mar 23 00:58:39 2013 +0100 42.3 @@ -38,7 +38,7 @@ 42.4 * IR representation for a runtime call. 42.5 * 42.6 */ 42.7 -public class RuntimeNode extends Node implements TypeOverride { 42.8 +public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> { 42.9 42.10 /** 42.11 * Request enum used for meta-information about the runtime request 42.12 @@ -393,8 +393,9 @@ 42.13 } 42.14 42.15 @Override 42.16 - public void setType(final Type type) { 42.17 + public RuntimeNode setType(final Type type) { 42.18 this.callSiteType = type; 42.19 + return this; 42.20 } 42.21 42.22 @Override 42.23 @@ -408,12 +409,12 @@ 42.24 42.25 @Override 42.26 public Node accept(final NodeVisitor visitor) { 42.27 - if (visitor.enter(this) != null) { 42.28 + if (visitor.enterRuntimeNode(this) != null) { 42.29 for (int i = 0, count = args.size(); i < count; i++) { 42.30 args.set(i, args.get(i).accept(visitor)); 42.31 } 42.32 42.33 - return visitor.leave(this); 42.34 + return visitor.leaveRuntimeNode(this); 42.35 } 42.36 42.37 return this;
43.1 --- a/src/jdk/nashorn/internal/ir/SplitNode.java Tue Mar 19 11:03:24 2013 -0300 43.2 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java Sat Mar 23 00:58:39 2013 +0100 43.3 @@ -108,10 +108,10 @@ 43.4 visitor.setCurrentMethodEmitter(getMethodEmitter()); 43.5 43.6 try { 43.7 - if (visitor.enter(this) != null) { 43.8 + if (visitor.enterSplitNode(this) != null) { 43.9 body = body.accept(visitor); 43.10 43.11 - return visitor.leave(this); 43.12 + return visitor.leaveSplitNode(this); 43.13 } 43.14 } finally { 43.15 visitor.setCurrentCompileUnit(saveCompileUnit);
44.1 --- a/src/jdk/nashorn/internal/ir/SwitchNode.java Tue Mar 19 11:03:24 2013 -0300 44.2 +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java Sat Mar 23 00:58:39 2013 +0100 44.3 @@ -85,7 +85,7 @@ 44.4 44.5 @Override 44.6 public Node accept(final NodeVisitor visitor) { 44.7 - if (visitor.enter(this) != null) { 44.8 + if (visitor.enterSwitchNode(this) != null) { 44.9 expression = expression.accept(visitor); 44.10 44.11 for (int i = 0, count = cases.size(); i < count; i++) { 44.12 @@ -94,7 +94,7 @@ 44.13 44.14 //the default case is in the cases list and should not be explicitly traversed! 44.15 44.16 - return visitor.leave(this); 44.17 + return visitor.leaveSwitchNode(this); 44.18 } 44.19 44.20 return this;
45.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java Tue Mar 19 11:03:24 2013 -0300 45.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Sat Mar 23 00:58:39 2013 +0100 45.3 @@ -38,31 +38,31 @@ 45.4 */ 45.5 45.6 public final class Symbol implements Comparable<Symbol> { 45.7 - /** Symbol flags. Kind ordered by precedence. */ 45.8 - public static final int IS_TEMP = 0b0000_0001; 45.9 + /** Symbol kinds. Kind ordered by precedence. */ 45.10 + public static final int IS_TEMP = 1; 45.11 /** Is this Global */ 45.12 - public static final int IS_GLOBAL = 0b0000_0010; 45.13 + public static final int IS_GLOBAL = 2; 45.14 /** Is this a variable */ 45.15 - public static final int IS_VAR = 0b0000_0011; 45.16 + public static final int IS_VAR = 3; 45.17 /** Is this a parameter */ 45.18 - public static final int IS_PARAM = 0b0000_0100; 45.19 + public static final int IS_PARAM = 4; 45.20 /** Is this a constant */ 45.21 - public static final int IS_CONSTANT = 0b0000_0101; 45.22 - 45.23 - static final int KINDMASK = 0b0000_1111; 45.24 + public static final int IS_CONSTANT = 5; 45.25 + /** Mask for kind flags */ 45.26 + public static final int KINDMASK = (1 << 3) - 1; // Kinds are represented by lower three bits 45.27 45.28 /** Is this scope */ 45.29 - public static final int IS_SCOPE = 0b0000_0001_0000; 45.30 + public static final int IS_SCOPE = 1 << 4; 45.31 /** Is this a this symbol */ 45.32 - public static final int IS_THIS = 0b0000_0010_0000; 45.33 + public static final int IS_THIS = 1 << 5; 45.34 /** Can this symbol ever be undefined */ 45.35 - public static final int CAN_BE_UNDEFINED = 0b0000_0100_0000; 45.36 + public static final int CAN_BE_UNDEFINED = 1 << 6; 45.37 /** Can this symbol ever have primitive types */ 45.38 - public static final int CAN_BE_PRIMITIVE = 0b0000_1000_0000; 45.39 + public static final int CAN_BE_PRIMITIVE = 1 << 7; 45.40 /** Is this a let */ 45.41 - public static final int IS_LET = 0b0001_0000_0000; 45.42 + public static final int IS_LET = 1 << 8; 45.43 /** Is this an internal symbol, never represented explicitly in source code */ 45.44 - public static final int IS_INTERNAL = 0b0010_0000_0000; 45.45 + public static final int IS_INTERNAL = 1 << 9; 45.46 45.47 /** Null or name identifying symbol. */ 45.48 private final String name; 45.49 @@ -269,15 +269,6 @@ 45.50 return type.isCategory2() ? 2 : 1; 45.51 } 45.52 45.53 - /** 45.54 - * Return the defining function (scope.) 45.55 - * 45.56 - * @return Defining function. 45.57 - */ 45.58 - public FunctionNode findFunction() { 45.59 - return block != null ? block.getFunction() : null; 45.60 - } 45.61 - 45.62 @Override 45.63 public boolean equals(final Object other) { 45.64 if (!(other instanceof Symbol)) { 45.65 @@ -487,27 +478,6 @@ 45.66 } 45.67 45.68 /** 45.69 - * Check if this symbol can be accessed directly with a putfield or getfield or dynamic load 45.70 - * 45.71 - * @param currentFunction function to check for fast scope 45.72 - * @return true if fast scope 45.73 - */ 45.74 - public boolean isFastScope(final FunctionNode currentFunction) { 45.75 - if (!isScope() || !block.needsScope()) { 45.76 - return false; 45.77 - } 45.78 - // Allow fast scope access if no parent function contains with or eval 45.79 - FunctionNode func = currentFunction; 45.80 - while (func != null) { 45.81 - if (func.hasWith() || func.hasEval()) { 45.82 - return false; 45.83 - } 45.84 - func = func.findParentFunction(); 45.85 - } 45.86 - return true; 45.87 - } 45.88 - 45.89 - /** 45.90 * Get the block in which the symbol is defined 45.91 * @return a block 45.92 */ 45.93 @@ -651,7 +621,7 @@ 45.94 * @return true if this this is a global scope symbol 45.95 */ 45.96 public boolean isTopLevel() { 45.97 - return block instanceof FunctionNode && ((FunctionNode) block).isScript(); 45.98 + return block instanceof FunctionNode && ((FunctionNode) block).isProgram(); 45.99 } 45.100 45.101
46.1 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java Tue Mar 19 11:03:24 2013 -0300 46.2 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java Sat Mar 23 00:58:39 2013 +0100 46.3 @@ -77,11 +77,11 @@ 46.4 46.5 @Override 46.6 public Node accept(final NodeVisitor visitor) { 46.7 - if (visitor.enter(this) != null) { 46.8 - lhs = lhs.accept(visitor); 46.9 - rhs = rhs.accept(visitor); 46.10 - third = third.accept(visitor); 46.11 - return visitor.leave(this); 46.12 + if (visitor.enterTernaryNode(this) != null) { 46.13 + final Node newLhs = lhs().accept(visitor); 46.14 + final Node newRhs = rhs().accept(visitor); 46.15 + final Node newThird = third.accept(visitor); 46.16 + return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs)); 46.17 } 46.18 46.19 return this; 46.20 @@ -133,8 +133,12 @@ 46.21 /** 46.22 * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z 46.23 * @param third a node 46.24 + * @return a node equivalent to this one except for the requested change. 46.25 */ 46.26 - public void setThird(final Node third) { 46.27 - this.third = third; 46.28 + public TernaryNode setThird(final Node third) { 46.29 + if(this.third == third) return this; 46.30 + final TernaryNode n = (TernaryNode)clone(); 46.31 + n.third = third; 46.32 + return n; 46.33 } 46.34 }
47.1 --- a/src/jdk/nashorn/internal/ir/ThrowNode.java Tue Mar 19 11:03:24 2013 -0300 47.2 +++ b/src/jdk/nashorn/internal/ir/ThrowNode.java Sat Mar 23 00:58:39 2013 +0100 47.3 @@ -75,9 +75,9 @@ 47.4 */ 47.5 @Override 47.6 public Node accept(final NodeVisitor visitor) { 47.7 - if (visitor.enter(this) != null) { 47.8 + if (visitor.enterThrowNode(this) != null) { 47.9 setExpression(expression.accept(visitor)); 47.10 - return visitor.leave(this); 47.11 + return visitor.leaveThrowNode(this); 47.12 } 47.13 47.14 return this;
48.1 --- a/src/jdk/nashorn/internal/ir/TryNode.java Tue Mar 19 11:03:24 2013 -0300 48.2 +++ b/src/jdk/nashorn/internal/ir/TryNode.java Sat Mar 23 00:58:39 2013 +0100 48.3 @@ -101,7 +101,7 @@ 48.4 */ 48.5 @Override 48.6 public Node accept(final NodeVisitor visitor) { 48.7 - if (visitor.enter(this) != null) { 48.8 + if (visitor.enterTryNode(this) != null) { 48.9 // Need to do first for termination analysis. 48.10 if (finallyBody != null) { 48.11 finallyBody = (Block)finallyBody.accept(visitor); 48.12 @@ -115,7 +115,7 @@ 48.13 } 48.14 this.catchBlocks = newCatchBlocks; 48.15 48.16 - return visitor.leave(this); 48.17 + return visitor.leaveTryNode(this); 48.18 } 48.19 48.20 return this; 48.21 @@ -155,6 +155,15 @@ 48.22 } 48.23 48.24 /** 48.25 + * Returns true if the specified block is the body of this try block, or any of its catch blocks. 48.26 + * @param block the block 48.27 + * @return true if the specified block is the body of this try block, or any of its catch blocks. 48.28 + */ 48.29 + public boolean isChildBlock(Block block) { 48.30 + return body == block || catchBlocks.contains(block); 48.31 + } 48.32 + 48.33 + /** 48.34 * Get the catch blocks for this try block 48.35 * @return a list of blocks 48.36 */
49.1 --- a/src/jdk/nashorn/internal/ir/TypeOverride.java Tue Mar 19 11:03:24 2013 -0300 49.2 +++ b/src/jdk/nashorn/internal/ir/TypeOverride.java Sat Mar 23 00:58:39 2013 +0100 49.3 @@ -36,15 +36,17 @@ 49.4 * by using JSType.toInt32. Especially in scenarios where the field is already stored 49.5 * as a primitive, this will be much faster than the "object is all I see" scope 49.6 * available in the method 49.7 + * @param <T> the type of the node implementing the interface 49.8 */ 49.9 49.10 -public interface TypeOverride { 49.11 +public interface TypeOverride<T extends Node> { 49.12 /** 49.13 * Set the override type 49.14 * 49.15 * @param type the type 49.16 + * @return a node equivalent to this one except for the requested change. 49.17 */ 49.18 - public void setType(final Type type); 49.19 + public T setType(final Type type); 49.20 49.21 /** 49.22 * Returns true if this node can have a callsite override, e.g. all scope ident nodes
50.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Mar 19 11:03:24 2013 -0300 50.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Sat Mar 23 00:58:39 2013 +0100 50.3 @@ -41,7 +41,7 @@ 50.4 */ 50.5 public class UnaryNode extends Node implements Assignment<Node> { 50.6 /** Right hand side argument. */ 50.7 - protected Node rhs; 50.8 + private Node rhs; 50.9 50.10 /** 50.11 * Constructor 50.12 @@ -104,6 +104,11 @@ 50.13 } 50.14 50.15 @Override 50.16 + public Node setAssignmentDest(Node n) { 50.17 + return setRHS(n); 50.18 + } 50.19 + 50.20 + @Override 50.21 public Node getAssignmentSource() { 50.22 return getAssignmentDest(); 50.23 } 50.24 @@ -132,9 +137,8 @@ 50.25 */ 50.26 @Override 50.27 public Node accept(final NodeVisitor visitor) { 50.28 - if (visitor.enter(this) != null) { 50.29 - rhs = rhs.accept(visitor); 50.30 - return visitor.leave(this); 50.31 + if (visitor.enterUnaryNode(this) != null) { 50.32 + return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor))); 50.33 } 50.34 50.35 return this; 50.36 @@ -212,10 +216,12 @@ 50.37 * @see BinaryNode 50.38 * 50.39 * @param rhs right hand side or expression node 50.40 + * @return a node equivalent to this one except for the requested change. 50.41 */ 50.42 - public void setRHS(final Node rhs) { 50.43 - this.rhs = rhs; 50.44 + public UnaryNode setRHS(final Node rhs) { 50.45 + if(this.rhs == rhs) return this; 50.46 + final UnaryNode n = (UnaryNode)clone(); 50.47 + n.rhs = rhs; 50.48 + return n; 50.49 } 50.50 - 50.51 - 50.52 }
51.1 --- a/src/jdk/nashorn/internal/ir/VarNode.java Tue Mar 19 11:03:24 2013 -0300 51.2 +++ b/src/jdk/nashorn/internal/ir/VarNode.java Sat Mar 23 00:58:39 2013 +0100 51.3 @@ -38,8 +38,8 @@ 51.4 /** Initialization expression. */ 51.5 private Node init; 51.6 51.7 - /** Is this a function var node */ 51.8 - private boolean isFunctionVarNode; 51.9 + /** Is this a var statement (as opposed to a "var" in a for loop statement) */ 51.10 + private final boolean isStatement; 51.11 51.12 /** 51.13 * Constructor 51.14 @@ -51,20 +51,34 @@ 51.15 * @param init init node or null if just a declaration 51.16 */ 51.17 public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) { 51.18 + this(source, token, finish, name, init, true); 51.19 + } 51.20 + 51.21 + /** 51.22 + * Constructor 51.23 + * 51.24 + * @param source the source 51.25 + * @param token token 51.26 + * @param finish finish 51.27 + * @param name name of variable 51.28 + * @param init init node or null if just a declaration 51.29 + * @param isStatement if this is a var statement (true), or a for-loop initializer (false) 51.30 + */ 51.31 + public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) { 51.32 super(source, token, finish); 51.33 51.34 - this.name = name; 51.35 + this.name = init == null ? name : name.setIsInitializedHere(); 51.36 this.init = init; 51.37 - if (init != null) { 51.38 - this.name.setIsInitializedHere(); 51.39 - } 51.40 + this.isStatement = isStatement; 51.41 } 51.42 51.43 + 51.44 private VarNode(final VarNode varNode, final CopyState cs) { 51.45 super(varNode); 51.46 51.47 this.name = (IdentNode)cs.existingOrCopy(varNode.name); 51.48 this.init = cs.existingOrCopy(varNode.init); 51.49 + this.isStatement = varNode.isStatement; 51.50 } 51.51 51.52 @Override 51.53 @@ -83,6 +97,11 @@ 51.54 } 51.55 51.56 @Override 51.57 + public Node setAssignmentDest(IdentNode n) { 51.58 + return setName(n); 51.59 + } 51.60 + 51.61 + @Override 51.62 public Node getAssignmentSource() { 51.63 return isAssignment() ? getInit() : null; 51.64 } 51.65 @@ -127,16 +146,19 @@ 51.66 */ 51.67 @Override 51.68 public Node accept(final NodeVisitor visitor) { 51.69 - if (visitor.enter(this) != null) { 51.70 - name = (IdentNode)name.accept(visitor); 51.71 - 51.72 - if (init != null) { 51.73 - init = init.accept(visitor); 51.74 + if (visitor.enterVarNode(this) != null) { 51.75 + final IdentNode newName = (IdentNode)name.accept(visitor); 51.76 + final Node newInit = init == null ? null : init.accept(visitor); 51.77 + final VarNode newThis; 51.78 + if(name != newName || init != newInit) { 51.79 + newThis = (VarNode)clone(); 51.80 + newThis.init = newInit; 51.81 + newThis.name = newInit == null ? newName : newName.setIsInitializedHere(); 51.82 + } else { 51.83 + newThis = this; 51.84 } 51.85 - 51.86 - return visitor.leave(this); 51.87 + return visitor.leaveVarNode(newThis); 51.88 } 51.89 - 51.90 return this; 51.91 } 51.92 51.93 @@ -162,9 +184,13 @@ 51.94 /** 51.95 * Reset the initialization expression 51.96 * @param init new initialization expression 51.97 + * @return a node equivalent to this one except for the requested change. 51.98 */ 51.99 - public void setInit(final Node init) { 51.100 - this.init = init; 51.101 + public VarNode setInit(final Node init) { 51.102 + if(this.init == init) return this; 51.103 + final VarNode n = (VarNode)clone(); 51.104 + n.init = init; 51.105 + return n; 51.106 } 51.107 51.108 /** 51.109 @@ -179,30 +205,26 @@ 51.110 * Reset the identifier for this VarNode 51.111 * @param name new IdentNode representing the variable being set or declared 51.112 */ 51.113 - public void setName(final IdentNode name) { 51.114 - this.name = name; 51.115 + private VarNode setName(final IdentNode name) { 51.116 + if(this.name == name) return this; 51.117 + final VarNode n = (VarNode)clone(); 51.118 + n.name = name; 51.119 + return n; 51.120 } 51.121 51.122 /** 51.123 - * Check if this is a virtual assignment of a function node. Function nodes declared 51.124 - * with a name are hoisted to the top of the scope and appear as symbols too. This is 51.125 - * implemented by representing them as virtual VarNode assignments added to the code 51.126 - * during lowering 51.127 - * 51.128 - * @see FunctionNode 51.129 - * 51.130 - * @return true if this is a virtual function declaration 51.131 + * Returns true if this is a var statement (as opposed to a var initializer in a for loop). 51.132 + * @return true if this is a var statement (as opposed to a var initializer in a for loop). 51.133 */ 51.134 - public boolean isFunctionVarNode() { 51.135 - return isFunctionVarNode; 51.136 + public boolean isStatement() { 51.137 + return isStatement; 51.138 } 51.139 51.140 /** 51.141 - * Flag this var node as a virtual function var node assignment as described in 51.142 - * {@link VarNode#isFunctionVarNode()} 51.143 + * Returns true if this is a function declaration. 51.144 + * @return true if this is a function declaration. 51.145 */ 51.146 - public void setIsFunctionVarNode() { 51.147 - this.isFunctionVarNode = true; 51.148 + public boolean isFunctionDeclaration() { 51.149 + return init instanceof FunctionNode && ((FunctionNode)init).isDeclared(); 51.150 } 51.151 - 51.152 }
52.1 --- a/src/jdk/nashorn/internal/ir/WhileNode.java Tue Mar 19 11:03:24 2013 -0300 52.2 +++ b/src/jdk/nashorn/internal/ir/WhileNode.java Sat Mar 23 00:58:39 2013 +0100 52.3 @@ -88,11 +88,11 @@ 52.4 */ 52.5 @Override 52.6 public Node accept(final NodeVisitor visitor) { 52.7 - if (visitor.enter(this) != null) { 52.8 + if (visitor.enterWhileNode(this) != null) { 52.9 test = test.accept(visitor); 52.10 body = (Block)body.accept(visitor); 52.11 52.12 - return visitor.leave(this); 52.13 + return visitor.leaveWhileNode(this); 52.14 } 52.15 return this; 52.16 }
53.1 --- a/src/jdk/nashorn/internal/ir/WithNode.java Tue Mar 19 11:03:24 2013 -0300 53.2 +++ b/src/jdk/nashorn/internal/ir/WithNode.java Sat Mar 23 00:58:39 2013 +0100 53.3 @@ -73,10 +73,10 @@ 53.4 */ 53.5 @Override 53.6 public Node accept(final NodeVisitor visitor) { 53.7 - if (visitor.enter(this) != null) { 53.8 + if (visitor.enterWithNode(this) != null) { 53.9 expression = expression.accept(visitor); 53.10 body = (Block)body.accept(visitor); 53.11 - return visitor.leave(this); 53.12 + return visitor.leaveWithNode(this); 53.13 } 53.14 53.15 return this;
54.1 --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Tue Mar 19 11:03:24 2013 -0300 54.2 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Sat Mar 23 00:58:39 2013 +0100 54.3 @@ -112,7 +112,7 @@ 54.4 } 54.5 54.6 @Override 54.7 - public Node enter(final AccessNode accessNode) { 54.8 + public Node enterAccessNode(final AccessNode accessNode) { 54.9 enterDefault(accessNode); 54.10 54.11 type("MemberExpression"); 54.12 @@ -132,7 +132,7 @@ 54.13 } 54.14 54.15 @Override 54.16 - public Node enter(final Block block) { 54.17 + public Node enterBlock(final Block block) { 54.18 enterDefault(block); 54.19 54.20 type("BlockStatement"); 54.21 @@ -154,7 +154,7 @@ 54.22 } 54.23 54.24 @Override 54.25 - public Node enter(final BinaryNode binaryNode) { 54.26 + public Node enterBinaryNode(final BinaryNode binaryNode) { 54.27 enterDefault(binaryNode); 54.28 54.29 final String name; 54.30 @@ -183,7 +183,7 @@ 54.31 } 54.32 54.33 @Override 54.34 - public Node enter(final BreakNode breakNode) { 54.35 + public Node enterBreakNode(final BreakNode breakNode) { 54.36 enterDefault(breakNode); 54.37 54.38 type("BreakStatement"); 54.39 @@ -201,7 +201,7 @@ 54.40 } 54.41 54.42 @Override 54.43 - public Node enter(final CallNode callNode) { 54.44 + public Node enterCallNode(final CallNode callNode) { 54.45 enterDefault(callNode); 54.46 54.47 type("CallExpression"); 54.48 @@ -217,7 +217,7 @@ 54.49 } 54.50 54.51 @Override 54.52 - public Node enter(final CaseNode caseNode) { 54.53 + public Node enterCaseNode(final CaseNode caseNode) { 54.54 enterDefault(caseNode); 54.55 54.56 type("SwitchCase"); 54.57 @@ -238,7 +238,7 @@ 54.58 } 54.59 54.60 @Override 54.61 - public Node enter(final CatchNode catchNode) { 54.62 + public Node enterCatchNode(final CatchNode catchNode) { 54.63 enterDefault(catchNode); 54.64 54.65 type("CatchClause"); 54.66 @@ -264,7 +264,7 @@ 54.67 } 54.68 54.69 @Override 54.70 - public Node enter(final ContinueNode continueNode) { 54.71 + public Node enterContinueNode(final ContinueNode continueNode) { 54.72 enterDefault(continueNode); 54.73 54.74 type("ContinueStatement"); 54.75 @@ -282,7 +282,7 @@ 54.76 } 54.77 54.78 @Override 54.79 - public Node enter(final DoWhileNode doWhileNode) { 54.80 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 54.81 enterDefault(doWhileNode); 54.82 54.83 type("DoWhileStatement"); 54.84 @@ -299,7 +299,7 @@ 54.85 } 54.86 54.87 @Override 54.88 - public Node enter(final EmptyNode emptyNode) { 54.89 + public Node enterEmptyNode(final EmptyNode emptyNode) { 54.90 enterDefault(emptyNode); 54.91 54.92 type("EmptyStatement"); 54.93 @@ -308,7 +308,7 @@ 54.94 } 54.95 54.96 @Override 54.97 - public Node enter(final ExecuteNode executeNode) { 54.98 + public Node enterExecuteNode(final ExecuteNode executeNode) { 54.99 enterDefault(executeNode); 54.100 54.101 type("ExpressionStatement"); 54.102 @@ -321,7 +321,7 @@ 54.103 } 54.104 54.105 @Override 54.106 - public Node enter(final ForNode forNode) { 54.107 + public Node enterForNode(final ForNode forNode) { 54.108 enterDefault(forNode); 54.109 54.110 if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) { 54.111 @@ -384,14 +384,14 @@ 54.112 } 54.113 54.114 @Override 54.115 - public Node enter(final FunctionNode functionNode) { 54.116 + public Node enterFunctionNode(final FunctionNode functionNode) { 54.117 enterDefault(functionNode); 54.118 54.119 - final boolean program = functionNode.isScript(); 54.120 + final boolean program = functionNode.isProgram(); 54.121 final String name; 54.122 if (program) { 54.123 name = "Program"; 54.124 - } else if (functionNode.isStatement()) { 54.125 + } else if (functionNode.isDeclared()) { 54.126 name = "FunctionDeclaration"; 54.127 } else { 54.128 name = "FunctionExpression"; 54.129 @@ -419,20 +419,11 @@ 54.130 } 54.131 54.132 // body consists of nested functions and statements 54.133 - final List<FunctionNode> funcs = functionNode.getFunctions(); 54.134 final List<Node> stats = functionNode.getStatements(); 54.135 - final int size = stats.size() + funcs.size(); 54.136 + final int size = stats.size(); 54.137 int idx = 0; 54.138 arrayStart("body"); 54.139 54.140 - for (final Node func : funcs) { 54.141 - func.accept(this); 54.142 - if (idx != (size - 1)) { 54.143 - comma(); 54.144 - } 54.145 - idx++; 54.146 - } 54.147 - 54.148 for (final Node stat : stats) { 54.149 if (! stat.isDebug()) { 54.150 stat.accept(this); 54.151 @@ -448,7 +439,7 @@ 54.152 } 54.153 54.154 @Override 54.155 - public Node enter(final IdentNode identNode) { 54.156 + public Node enterIdentNode(final IdentNode identNode) { 54.157 enterDefault(identNode); 54.158 54.159 final String name = identNode.getName(); 54.160 @@ -464,7 +455,7 @@ 54.161 } 54.162 54.163 @Override 54.164 - public Node enter(final IfNode ifNode) { 54.165 + public Node enterIfNode(final IfNode ifNode) { 54.166 enterDefault(ifNode); 54.167 54.168 type("IfStatement"); 54.169 @@ -490,7 +481,7 @@ 54.170 } 54.171 54.172 @Override 54.173 - public Node enter(final IndexNode indexNode) { 54.174 + public Node enterIndexNode(final IndexNode indexNode) { 54.175 enterDefault(indexNode); 54.176 54.177 type("MemberExpression"); 54.178 @@ -510,7 +501,7 @@ 54.179 } 54.180 54.181 @Override 54.182 - public Node enter(final LabelNode labelNode) { 54.183 + public Node enterLabelNode(final LabelNode labelNode) { 54.184 enterDefault(labelNode); 54.185 54.186 type("LabeledStatement"); 54.187 @@ -527,13 +518,13 @@ 54.188 } 54.189 54.190 @Override 54.191 - public Node enter(final LineNumberNode lineNumberNode) { 54.192 + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 54.193 return null; 54.194 } 54.195 54.196 @SuppressWarnings("rawtypes") 54.197 @Override 54.198 - public Node enter(final LiteralNode literalNode) { 54.199 + public Node enterLiteralNode(final LiteralNode literalNode) { 54.200 enterDefault(literalNode); 54.201 54.202 if (literalNode instanceof LiteralNode.ArrayLiteralNode) { 54.203 @@ -569,7 +560,7 @@ 54.204 } 54.205 54.206 @Override 54.207 - public Node enter(final ObjectNode objectNode) { 54.208 + public Node enterObjectNode(final ObjectNode objectNode) { 54.209 enterDefault(objectNode); 54.210 54.211 type("ObjectExpression"); 54.212 @@ -581,7 +572,7 @@ 54.213 } 54.214 54.215 @Override 54.216 - public Node enter(final PropertyNode propertyNode) { 54.217 + public Node enterPropertyNode(final PropertyNode propertyNode) { 54.218 final Node key = propertyNode.getKey(); 54.219 54.220 final Node value = propertyNode.getValue(); 54.221 @@ -647,7 +638,7 @@ 54.222 } 54.223 54.224 @Override 54.225 - public Node enter(final ReturnNode returnNode) { 54.226 + public Node enterReturnNode(final ReturnNode returnNode) { 54.227 enterDefault(returnNode); 54.228 54.229 type("ReturnStatement"); 54.230 @@ -665,7 +656,7 @@ 54.231 } 54.232 54.233 @Override 54.234 - public Node enter(final RuntimeNode runtimeNode) { 54.235 + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 54.236 final RuntimeNode.Request req = runtimeNode.getRequest(); 54.237 54.238 if (req == RuntimeNode.Request.DEBUGGER) { 54.239 @@ -680,12 +671,12 @@ 54.240 } 54.241 54.242 @Override 54.243 - public Node enter(final SplitNode splitNode) { 54.244 + public Node enterSplitNode(final SplitNode splitNode) { 54.245 return null; 54.246 } 54.247 54.248 @Override 54.249 - public Node enter(final SwitchNode switchNode) { 54.250 + public Node enterSwitchNode(final SwitchNode switchNode) { 54.251 enterDefault(switchNode); 54.252 54.253 type("SwitchStatement"); 54.254 @@ -701,7 +692,7 @@ 54.255 } 54.256 54.257 @Override 54.258 - public Node enter(final TernaryNode ternaryNode) { 54.259 + public Node enterTernaryNode(final TernaryNode ternaryNode) { 54.260 enterDefault(ternaryNode); 54.261 54.262 type("ConditionalExpression"); 54.263 @@ -722,7 +713,7 @@ 54.264 } 54.265 54.266 @Override 54.267 - public Node enter(final ThrowNode throwNode) { 54.268 + public Node enterThrowNode(final ThrowNode throwNode) { 54.269 enterDefault(throwNode); 54.270 54.271 type("ThrowStatement"); 54.272 @@ -735,7 +726,7 @@ 54.273 } 54.274 54.275 @Override 54.276 - public Node enter(final TryNode tryNode) { 54.277 + public Node enterTryNode(final TryNode tryNode) { 54.278 enterDefault(tryNode); 54.279 54.280 type("TryStatement"); 54.281 @@ -760,7 +751,7 @@ 54.282 } 54.283 54.284 @Override 54.285 - public Node enter(final UnaryNode unaryNode) { 54.286 + public Node enterUnaryNode(final UnaryNode unaryNode) { 54.287 enterDefault(unaryNode); 54.288 54.289 final TokenType tokenType = unaryNode.tokenType(); 54.290 @@ -816,7 +807,7 @@ 54.291 } 54.292 54.293 @Override 54.294 - public Node enter(final VarNode varNode) { 54.295 + public Node enterVarNode(final VarNode varNode) { 54.296 enterDefault(varNode); 54.297 54.298 type("VariableDeclaration"); 54.299 @@ -852,7 +843,7 @@ 54.300 } 54.301 54.302 @Override 54.303 - public Node enter(final WhileNode whileNode) { 54.304 + public Node enterWhileNode(final WhileNode whileNode) { 54.305 enterDefault(whileNode); 54.306 54.307 type("WhileStatement"); 54.308 @@ -869,7 +860,7 @@ 54.309 } 54.310 54.311 @Override 54.312 - public Node enter(final WithNode withNode) { 54.313 + public Node enterWithNode(final WithNode withNode) { 54.314 enterDefault(withNode); 54.315 54.316 type("WithStatement");
55.1 --- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Tue Mar 19 11:03:24 2013 -0300 55.2 +++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Sat Mar 23 00:58:39 2013 +0100 55.3 @@ -42,7 +42,6 @@ 55.4 import jdk.nashorn.internal.ir.LabelNode; 55.5 import jdk.nashorn.internal.ir.LineNumberNode; 55.6 import jdk.nashorn.internal.ir.Node; 55.7 -import jdk.nashorn.internal.ir.ReferenceNode; 55.8 import jdk.nashorn.internal.ir.ReturnNode; 55.9 import jdk.nashorn.internal.ir.RuntimeNode; 55.10 import jdk.nashorn.internal.ir.SplitNode; 55.11 @@ -138,13 +137,13 @@ 55.12 * Visits. 55.13 */ 55.14 @Override 55.15 - public Node enter(final AccessNode accessNode) { 55.16 + public Node enterAccessNode(final AccessNode accessNode) { 55.17 accessNode.toString(sb); 55.18 return null; 55.19 } 55.20 55.21 @Override 55.22 - public Node enter(final Block block) { 55.23 + public Node enterBlock(final Block block) { 55.24 sb.append(' '); 55.25 sb.append('{'); 55.26 55.27 @@ -152,21 +151,6 @@ 55.28 55.29 final boolean isFunction = block instanceof FunctionNode; 55.30 55.31 - if (isFunction) { 55.32 - final FunctionNode function = (FunctionNode)block; 55.33 - final List<FunctionNode> functions = function.getFunctions(); 55.34 - 55.35 - for (final FunctionNode f : functions) { 55.36 - sb.append(EOLN); 55.37 - indent(); 55.38 - f.accept(this); 55.39 - } 55.40 - 55.41 - if (!functions.isEmpty()) { 55.42 - sb.append(EOLN); 55.43 - } 55.44 - } 55.45 - 55.46 final List<Node> statements = block.getStatements(); 55.47 55.48 boolean lastLineNumber = false; 55.49 @@ -224,25 +208,25 @@ 55.50 } 55.51 55.52 @Override 55.53 - public Node enter(final BreakNode breakNode) { 55.54 + public Node enterBreakNode(final BreakNode breakNode) { 55.55 breakNode.toString(sb); 55.56 return null; 55.57 } 55.58 55.59 @Override 55.60 - public Node enter(final CallNode callNode) { 55.61 + public Node enterCallNode(final CallNode callNode) { 55.62 callNode.toString(sb); 55.63 return null; 55.64 } 55.65 55.66 @Override 55.67 - public Node enter(final ContinueNode continueNode) { 55.68 + public Node enterContinueNode(final ContinueNode continueNode) { 55.69 continueNode.toString(sb); 55.70 return null; 55.71 } 55.72 55.73 @Override 55.74 - public Node enter(final DoWhileNode doWhileNode) { 55.75 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 55.76 sb.append("do"); 55.77 doWhileNode.getBody().accept(this); 55.78 sb.append(' '); 55.79 @@ -252,7 +236,7 @@ 55.80 } 55.81 55.82 @Override 55.83 - public Node enter(final ExecuteNode executeNode) { 55.84 + public Node enterExecuteNode(final ExecuteNode executeNode) { 55.85 final Node expression = executeNode.getExpression(); 55.86 55.87 if (expression instanceof UnaryNode) { 55.88 @@ -265,7 +249,7 @@ 55.89 } 55.90 55.91 @Override 55.92 - public Node enter(final ForNode forNode) { 55.93 + public Node enterForNode(final ForNode forNode) { 55.94 forNode.toString(sb); 55.95 forNode.getBody().accept(this); 55.96 55.97 @@ -273,15 +257,15 @@ 55.98 } 55.99 55.100 @Override 55.101 - public Node enter(final FunctionNode functionNode) { 55.102 + public Node enterFunctionNode(final FunctionNode functionNode) { 55.103 functionNode.toString(sb); 55.104 - enter((Block)functionNode); 55.105 + enterBlock(functionNode); 55.106 55.107 return null; 55.108 } 55.109 55.110 @Override 55.111 - public Node enter(final IfNode ifNode) { 55.112 + public Node enterIfNode(final IfNode ifNode) { 55.113 ifNode.toString(sb); 55.114 ifNode.getPass().accept(this); 55.115 55.116 @@ -296,13 +280,13 @@ 55.117 } 55.118 55.119 @Override 55.120 - public Node enter(final IndexNode indexNode) { 55.121 + public Node enterIndexNode(final IndexNode indexNode) { 55.122 indexNode.toString(sb); 55.123 return null; 55.124 } 55.125 55.126 @Override 55.127 - public Node enter(final LabelNode labeledNode) { 55.128 + public Node enterLabelNode(final LabelNode labeledNode) { 55.129 indent -= TABWIDTH; 55.130 indent(); 55.131 indent += TABWIDTH; 55.132 @@ -313,7 +297,7 @@ 55.133 } 55.134 55.135 @Override 55.136 - public Node enter(final LineNumberNode lineNumberNode) { 55.137 + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 55.138 if (printLineNumbers) { 55.139 lineNumberNode.toString(sb); 55.140 } 55.141 @@ -323,25 +307,19 @@ 55.142 55.143 55.144 @Override 55.145 - public Node enter(final ReferenceNode referenceNode) { 55.146 - referenceNode.toString(sb); 55.147 - return null; 55.148 - } 55.149 - 55.150 - @Override 55.151 - public Node enter(final ReturnNode returnNode) { 55.152 + public Node enterReturnNode(final ReturnNode returnNode) { 55.153 returnNode.toString(sb); 55.154 return null; 55.155 } 55.156 55.157 @Override 55.158 - public Node enter(final RuntimeNode runtimeNode) { 55.159 + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 55.160 runtimeNode.toString(sb); 55.161 return null; 55.162 } 55.163 55.164 @Override 55.165 - public Node enter(final SplitNode splitNode) { 55.166 + public Node enterSplitNode(final SplitNode splitNode) { 55.167 splitNode.toString(sb); 55.168 sb.append(EOLN); 55.169 indent += TABWIDTH; 55.170 @@ -350,7 +328,7 @@ 55.171 } 55.172 55.173 @Override 55.174 - public Node leave(final SplitNode splitNode) { 55.175 + public Node leaveSplitNode(final SplitNode splitNode) { 55.176 sb.append("</split>"); 55.177 sb.append(EOLN); 55.178 indent -= TABWIDTH; 55.179 @@ -359,7 +337,7 @@ 55.180 } 55.181 55.182 @Override 55.183 - public Node enter(final SwitchNode switchNode) { 55.184 + public Node enterSwitchNode(final SwitchNode switchNode) { 55.185 switchNode.toString(sb); 55.186 sb.append(" {"); 55.187 55.188 @@ -383,13 +361,13 @@ 55.189 } 55.190 55.191 @Override 55.192 - public Node enter(final ThrowNode throwNode) { 55.193 + public Node enterThrowNode(final ThrowNode throwNode) { 55.194 throwNode.toString(sb); 55.195 return null; 55.196 } 55.197 55.198 @Override 55.199 - public Node enter(final TryNode tryNode) { 55.200 + public Node enterTryNode(final TryNode tryNode) { 55.201 tryNode.toString(sb); 55.202 tryNode.getBody().accept(this); 55.203 55.204 @@ -412,13 +390,19 @@ 55.205 } 55.206 55.207 @Override 55.208 - public Node enter(final VarNode varNode) { 55.209 - varNode.toString(sb); 55.210 + public Node enterVarNode(final VarNode varNode) { 55.211 + sb.append("var "); 55.212 + varNode.getName().toString(sb); 55.213 + final Node init = varNode.getInit(); 55.214 + if(init != null) { 55.215 + sb.append(" = "); 55.216 + init.accept(this); 55.217 + } 55.218 return null; 55.219 } 55.220 55.221 @Override 55.222 - public Node enter(final WhileNode whileNode) { 55.223 + public Node enterWhileNode(final WhileNode whileNode) { 55.224 whileNode.toString(sb); 55.225 whileNode.getBody().accept(this); 55.226 55.227 @@ -426,7 +410,7 @@ 55.228 } 55.229 55.230 @Override 55.231 - public Node enter(final WithNode withNode) { 55.232 + public Node enterWithNode(final WithNode withNode) { 55.233 withNode.toString(sb); 55.234 withNode.getBody().accept(this); 55.235
56.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Tue Mar 19 11:03:24 2013 -0300 56.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Sat Mar 23 00:58:39 2013 +0100 56.3 @@ -53,7 +53,7 @@ 56.4 } 56.5 56.6 @Override 56.7 - public final Node enter(final UnaryNode unaryNode) { 56.8 + public final Node enterUnaryNode(final UnaryNode unaryNode) { 56.9 switch (unaryNode.tokenType()) { 56.10 case ADD: 56.11 return enterADD(unaryNode); 56.12 @@ -81,12 +81,12 @@ 56.13 case INCPOSTFIX: 56.14 return enterDECINC(unaryNode); 56.15 default: 56.16 - return super.enter(unaryNode); 56.17 + return super.enterUnaryNode(unaryNode); 56.18 } 56.19 } 56.20 56.21 @Override 56.22 - public final Node leave(final UnaryNode unaryNode) { 56.23 + public final Node leaveUnaryNode(final UnaryNode unaryNode) { 56.24 switch (unaryNode.tokenType()) { 56.25 case ADD: 56.26 return leaveADD(unaryNode); 56.27 @@ -114,12 +114,12 @@ 56.28 case INCPOSTFIX: 56.29 return leaveDECINC(unaryNode); 56.30 default: 56.31 - return super.leave(unaryNode); 56.32 + return super.leaveUnaryNode(unaryNode); 56.33 } 56.34 } 56.35 56.36 @Override 56.37 - public final Node enter(final BinaryNode binaryNode) { 56.38 + public final Node enterBinaryNode(final BinaryNode binaryNode) { 56.39 switch (binaryNode.tokenType()) { 56.40 case ADD: 56.41 return enterADD(binaryNode); 56.42 @@ -198,12 +198,12 @@ 56.43 case SUB: 56.44 return enterSUB(binaryNode); 56.45 default: 56.46 - return super.enter(binaryNode); 56.47 + return super.enterBinaryNode(binaryNode); 56.48 } 56.49 } 56.50 56.51 @Override 56.52 - public final Node leave(final BinaryNode binaryNode) { 56.53 + public final Node leaveBinaryNode(final BinaryNode binaryNode) { 56.54 switch (binaryNode.tokenType()) { 56.55 case ADD: 56.56 return leaveADD(binaryNode); 56.57 @@ -282,7 +282,7 @@ 56.58 case SUB: 56.59 return leaveSUB(binaryNode); 56.60 default: 56.61 - return super.leave(binaryNode); 56.62 + return super.leaveBinaryNode(binaryNode); 56.63 } 56.64 } 56.65
57.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Tue Mar 19 11:03:24 2013 -0300 57.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Sat Mar 23 00:58:39 2013 +0100 57.3 @@ -49,7 +49,6 @@ 57.4 import jdk.nashorn.internal.ir.Node; 57.5 import jdk.nashorn.internal.ir.ObjectNode; 57.6 import jdk.nashorn.internal.ir.PropertyNode; 57.7 -import jdk.nashorn.internal.ir.ReferenceNode; 57.8 import jdk.nashorn.internal.ir.ReturnNode; 57.9 import jdk.nashorn.internal.ir.RuntimeNode; 57.10 import jdk.nashorn.internal.ir.SplitNode; 57.11 @@ -153,7 +152,7 @@ 57.12 * @param accessNode the node 57.13 * @return processed node, null if traversal should end, null if traversal should end 57.14 */ 57.15 - public Node enter(final AccessNode accessNode) { 57.16 + public Node enterAccessNode(final AccessNode accessNode) { 57.17 return enterDefault(accessNode); 57.18 } 57.19 57.20 @@ -163,7 +162,7 @@ 57.21 * @param accessNode the node 57.22 * @return processed node, null if traversal should end 57.23 */ 57.24 - public Node leave(final AccessNode accessNode) { 57.25 + public Node leaveAccessNode(final AccessNode accessNode) { 57.26 return leaveDefault(accessNode); 57.27 } 57.28 57.29 @@ -173,7 +172,7 @@ 57.30 * @param block the node 57.31 * @return processed node, null if traversal should end 57.32 */ 57.33 - public Node enter(final Block block) { 57.34 + public Node enterBlock(final Block block) { 57.35 return enterDefault(block); 57.36 } 57.37 57.38 @@ -183,7 +182,7 @@ 57.39 * @param block the node 57.40 * @return processed node, which will replace the original one, or the original node 57.41 */ 57.42 - public Node leave(final Block block) { 57.43 + public Node leaveBlock(final Block block) { 57.44 return leaveDefault(block); 57.45 } 57.46 57.47 @@ -193,7 +192,7 @@ 57.48 * @param binaryNode the node 57.49 * @return processed node 57.50 */ 57.51 - public Node enter(final BinaryNode binaryNode) { 57.52 + public Node enterBinaryNode(final BinaryNode binaryNode) { 57.53 return enterDefault(binaryNode); 57.54 } 57.55 57.56 @@ -203,7 +202,7 @@ 57.57 * @param binaryNode the node 57.58 * @return processed node, which will replace the original one, or the original node 57.59 */ 57.60 - public Node leave(final BinaryNode binaryNode) { 57.61 + public Node leaveBinaryNode(final BinaryNode binaryNode) { 57.62 return leaveDefault(binaryNode); 57.63 } 57.64 57.65 @@ -213,7 +212,7 @@ 57.66 * @param breakNode the node 57.67 * @return processed node, null if traversal should end 57.68 */ 57.69 - public Node enter(final BreakNode breakNode) { 57.70 + public Node enterBreakNode(final BreakNode breakNode) { 57.71 return enterDefault(breakNode); 57.72 } 57.73 57.74 @@ -223,7 +222,7 @@ 57.75 * @param breakNode the node 57.76 * @return processed node, which will replace the original one, or the original node 57.77 */ 57.78 - public Node leave(final BreakNode breakNode) { 57.79 + public Node leaveBreakNode(final BreakNode breakNode) { 57.80 return leaveDefault(breakNode); 57.81 } 57.82 57.83 @@ -233,7 +232,7 @@ 57.84 * @param callNode the node 57.85 * @return processed node, null if traversal should end 57.86 */ 57.87 - public Node enter(final CallNode callNode) { 57.88 + public Node enterCallNode(final CallNode callNode) { 57.89 return enterDefault(callNode); 57.90 } 57.91 57.92 @@ -243,7 +242,7 @@ 57.93 * @param callNode the node 57.94 * @return processed node, which will replace the original one, or the original node 57.95 */ 57.96 - public Node leave(final CallNode callNode) { 57.97 + public Node leaveCallNode(final CallNode callNode) { 57.98 return leaveDefault(callNode); 57.99 } 57.100 57.101 @@ -253,7 +252,7 @@ 57.102 * @param caseNode the node 57.103 * @return processed node, null if traversal should end 57.104 */ 57.105 - public Node enter(final CaseNode caseNode) { 57.106 + public Node enterCaseNode(final CaseNode caseNode) { 57.107 return enterDefault(caseNode); 57.108 } 57.109 57.110 @@ -263,7 +262,7 @@ 57.111 * @param caseNode the node 57.112 * @return processed node, which will replace the original one, or the original node 57.113 */ 57.114 - public Node leave(final CaseNode caseNode) { 57.115 + public Node leaveCaseNode(final CaseNode caseNode) { 57.116 return leaveDefault(caseNode); 57.117 } 57.118 57.119 @@ -273,7 +272,7 @@ 57.120 * @param catchNode the node 57.121 * @return processed node, null if traversal should end 57.122 */ 57.123 - public Node enter(final CatchNode catchNode) { 57.124 + public Node enterCatchNode(final CatchNode catchNode) { 57.125 return enterDefault(catchNode); 57.126 } 57.127 57.128 @@ -283,7 +282,7 @@ 57.129 * @param catchNode the node 57.130 * @return processed node, which will replace the original one, or the original node 57.131 */ 57.132 - public Node leave(final CatchNode catchNode) { 57.133 + public Node leaveCatchNode(final CatchNode catchNode) { 57.134 return leaveDefault(catchNode); 57.135 } 57.136 57.137 @@ -293,7 +292,7 @@ 57.138 * @param continueNode the node 57.139 * @return processed node, null if traversal should end 57.140 */ 57.141 - public Node enter(final ContinueNode continueNode) { 57.142 + public Node enterContinueNode(final ContinueNode continueNode) { 57.143 return enterDefault(continueNode); 57.144 } 57.145 57.146 @@ -303,7 +302,7 @@ 57.147 * @param continueNode the node 57.148 * @return processed node, which will replace the original one, or the original node 57.149 */ 57.150 - public Node leave(final ContinueNode continueNode) { 57.151 + public Node leaveContinueNode(final ContinueNode continueNode) { 57.152 return leaveDefault(continueNode); 57.153 } 57.154 57.155 @@ -313,7 +312,7 @@ 57.156 * @param doWhileNode the node 57.157 * @return processed node 57.158 */ 57.159 - public Node enter(final DoWhileNode doWhileNode) { 57.160 + public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 57.161 return enterDefault(doWhileNode); 57.162 } 57.163 57.164 @@ -323,7 +322,7 @@ 57.165 * @param doWhileNode the node 57.166 * @return processed node, which will replace the original one, or the original node 57.167 */ 57.168 - public Node leave(final DoWhileNode doWhileNode) { 57.169 + public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 57.170 return leaveDefault(doWhileNode); 57.171 } 57.172 57.173 @@ -333,7 +332,7 @@ 57.174 * @param emptyNode the node 57.175 * @return processed node 57.176 */ 57.177 - public Node enter(final EmptyNode emptyNode) { 57.178 + public Node enterEmptyNode(final EmptyNode emptyNode) { 57.179 return enterDefault(emptyNode); 57.180 } 57.181 57.182 @@ -343,7 +342,7 @@ 57.183 * @param emptyNode the node 57.184 * @return processed node, which will replace the original one, or the original node 57.185 */ 57.186 - public Node leave(final EmptyNode emptyNode) { 57.187 + public Node leaveEmptyNode(final EmptyNode emptyNode) { 57.188 return leaveDefault(emptyNode); 57.189 } 57.190 57.191 @@ -353,7 +352,7 @@ 57.192 * @param executeNode the node 57.193 * @return processed node, null if traversal should end 57.194 */ 57.195 - public Node enter(final ExecuteNode executeNode) { 57.196 + public Node enterExecuteNode(final ExecuteNode executeNode) { 57.197 return enterDefault(executeNode); 57.198 } 57.199 57.200 @@ -363,7 +362,7 @@ 57.201 * @param executeNode the node 57.202 * @return processed node, which will replace the original one, or the original node 57.203 */ 57.204 - public Node leave(final ExecuteNode executeNode) { 57.205 + public Node leaveExecuteNode(final ExecuteNode executeNode) { 57.206 return leaveDefault(executeNode); 57.207 } 57.208 57.209 @@ -373,7 +372,7 @@ 57.210 * @param forNode the node 57.211 * @return processed node, null if traversal should end 57.212 */ 57.213 - public Node enter(final ForNode forNode) { 57.214 + public Node enterForNode(final ForNode forNode) { 57.215 return enterDefault(forNode); 57.216 } 57.217 57.218 @@ -383,7 +382,7 @@ 57.219 * @param forNode the node 57.220 * @return processed node, which will replace the original one, or the original node 57.221 */ 57.222 - public Node leave(final ForNode forNode) { 57.223 + public Node leaveForNode(final ForNode forNode) { 57.224 return leaveDefault(forNode); 57.225 } 57.226 57.227 @@ -393,7 +392,7 @@ 57.228 * @param functionNode the node 57.229 * @return processed node 57.230 */ 57.231 - public Node enter(final FunctionNode functionNode) { 57.232 + public Node enterFunctionNode(final FunctionNode functionNode) { 57.233 return enterDefault(functionNode); 57.234 } 57.235 57.236 @@ -403,7 +402,7 @@ 57.237 * @param functionNode the node 57.238 * @return processed node, which will replace the original one, or the original node 57.239 */ 57.240 - public Node leave(final FunctionNode functionNode) { 57.241 + public Node leaveFunctionNode(final FunctionNode functionNode) { 57.242 return leaveDefault(functionNode); 57.243 } 57.244 57.245 @@ -413,7 +412,7 @@ 57.246 * @param identNode the node 57.247 * @return processed node, null if traversal should end 57.248 */ 57.249 - public Node enter(final IdentNode identNode) { 57.250 + public Node enterIdentNode(final IdentNode identNode) { 57.251 return enterDefault(identNode); 57.252 } 57.253 57.254 @@ -423,7 +422,7 @@ 57.255 * @param identNode the node 57.256 * @return processed node, which will replace the original one, or the original node 57.257 */ 57.258 - public Node leave(final IdentNode identNode) { 57.259 + public Node leaveIdentNode(final IdentNode identNode) { 57.260 return leaveDefault(identNode); 57.261 } 57.262 57.263 @@ -433,7 +432,7 @@ 57.264 * @param ifNode the node 57.265 * @return processed node, null if traversal should end 57.266 */ 57.267 - public Node enter(final IfNode ifNode) { 57.268 + public Node enterIfNode(final IfNode ifNode) { 57.269 return enterDefault(ifNode); 57.270 } 57.271 57.272 @@ -443,7 +442,7 @@ 57.273 * @param ifNode the node 57.274 * @return processed node, which will replace the original one, or the original node 57.275 */ 57.276 - public Node leave(final IfNode ifNode) { 57.277 + public Node leaveIfNode(final IfNode ifNode) { 57.278 return leaveDefault(ifNode); 57.279 } 57.280 57.281 @@ -453,7 +452,7 @@ 57.282 * @param indexNode the node 57.283 * @return processed node, null if traversal should end 57.284 */ 57.285 - public Node enter(final IndexNode indexNode) { 57.286 + public Node enterIndexNode(final IndexNode indexNode) { 57.287 return enterDefault(indexNode); 57.288 } 57.289 57.290 @@ -463,7 +462,7 @@ 57.291 * @param indexNode the node 57.292 * @return processed node, which will replace the original one, or the original node 57.293 */ 57.294 - public Node leave(final IndexNode indexNode) { 57.295 + public Node leaveIndexNode(final IndexNode indexNode) { 57.296 return leaveDefault(indexNode); 57.297 } 57.298 57.299 @@ -473,7 +472,7 @@ 57.300 * @param labelNode the node 57.301 * @return processed node, null if traversal should end 57.302 */ 57.303 - public Node enter(final LabelNode labelNode) { 57.304 + public Node enterLabelNode(final LabelNode labelNode) { 57.305 return enterDefault(labelNode); 57.306 } 57.307 57.308 @@ -483,7 +482,7 @@ 57.309 * @param labelNode the node 57.310 * @return processed node, which will replace the original one, or the original node 57.311 */ 57.312 - public Node leave(final LabelNode labelNode) { 57.313 + public Node leaveLabelNode(final LabelNode labelNode) { 57.314 return leaveDefault(labelNode); 57.315 } 57.316 57.317 @@ -493,7 +492,7 @@ 57.318 * @param lineNumberNode the node 57.319 * @return processed node, null if traversal should end 57.320 */ 57.321 - public Node enter(final LineNumberNode lineNumberNode) { 57.322 + public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 57.323 return enterDefault(lineNumberNode); 57.324 } 57.325 57.326 @@ -503,7 +502,7 @@ 57.327 * @param lineNumberNode the node 57.328 * @return processed node, which will replace the original one, or the original node 57.329 */ 57.330 - public Node leave(final LineNumberNode lineNumberNode) { 57.331 + public Node leaveLineNumberNode(final LineNumberNode lineNumberNode) { 57.332 return leaveDefault(lineNumberNode); 57.333 } 57.334 57.335 @@ -513,8 +512,7 @@ 57.336 * @param literalNode the node 57.337 * @return processed node 57.338 */ 57.339 - @SuppressWarnings("rawtypes") 57.340 - public Node enter(final LiteralNode literalNode) { 57.341 + public Node enterLiteralNode(final LiteralNode<?> literalNode) { 57.342 return enterDefault(literalNode); 57.343 } 57.344 57.345 @@ -524,8 +522,7 @@ 57.346 * @param literalNode the node 57.347 * @return processed node, which will replace the original one, or the original node 57.348 */ 57.349 - @SuppressWarnings("rawtypes") 57.350 - public Node leave(final LiteralNode literalNode) { 57.351 + public Node leaveLiteralNode(final LiteralNode<?> literalNode) { 57.352 return leaveDefault(literalNode); 57.353 } 57.354 57.355 @@ -535,7 +532,7 @@ 57.356 * @param objectNode the node 57.357 * @return processed node 57.358 */ 57.359 - public Node enter(final ObjectNode objectNode) { 57.360 + public Node enterObjectNode(final ObjectNode objectNode) { 57.361 return enterDefault(objectNode); 57.362 } 57.363 57.364 @@ -545,7 +542,7 @@ 57.365 * @param objectNode the node 57.366 * @return processed node, which will replace the original one, or the original node 57.367 */ 57.368 - public Node leave(final ObjectNode objectNode) { 57.369 + public Node leaveObjectNode(final ObjectNode objectNode) { 57.370 return leaveDefault(objectNode); 57.371 } 57.372 57.373 @@ -555,7 +552,7 @@ 57.374 * @param propertyNode the node 57.375 * @return processed node, null if traversal should end 57.376 */ 57.377 - public Node enter(final PropertyNode propertyNode) { 57.378 + public Node enterPropertyNode(final PropertyNode propertyNode) { 57.379 return enterDefault(propertyNode); 57.380 } 57.381 57.382 @@ -565,37 +562,17 @@ 57.383 * @param propertyNode the node 57.384 * @return processed node, which will replace the original one, or the original node 57.385 */ 57.386 - public Node leave(final PropertyNode propertyNode) { 57.387 + public Node leavePropertyNode(final PropertyNode propertyNode) { 57.388 return leaveDefault(propertyNode); 57.389 } 57.390 57.391 /** 57.392 - * Callback for entering a ReferenceNode 57.393 - * 57.394 - * @param referenceNode the node 57.395 - * @return processed node, null if traversal should end 57.396 - */ 57.397 - public Node enter(final ReferenceNode referenceNode) { 57.398 - return enterDefault(referenceNode); 57.399 - } 57.400 - 57.401 - /** 57.402 - * Callback for leaving a ReferenceNode 57.403 - * 57.404 - * @param referenceNode the node 57.405 - * @return processed node, which will replace the original one, or the original node 57.406 - */ 57.407 - public Node leave(final ReferenceNode referenceNode) { 57.408 - return leaveDefault(referenceNode); 57.409 - } 57.410 - 57.411 - /** 57.412 * Callback for entering a ReturnNode 57.413 * 57.414 * @param returnNode the node 57.415 * @return processed node, null if traversal should end 57.416 */ 57.417 - public Node enter(final ReturnNode returnNode) { 57.418 + public Node enterReturnNode(final ReturnNode returnNode) { 57.419 return enterDefault(returnNode); 57.420 } 57.421 57.422 @@ -605,7 +582,7 @@ 57.423 * @param returnNode the node 57.424 * @return processed node, which will replace the original one, or the original node 57.425 */ 57.426 - public Node leave(final ReturnNode returnNode) { 57.427 + public Node leaveReturnNode(final ReturnNode returnNode) { 57.428 return leaveDefault(returnNode); 57.429 } 57.430 57.431 @@ -615,7 +592,7 @@ 57.432 * @param runtimeNode the node 57.433 * @return processed node, null if traversal should end 57.434 */ 57.435 - public Node enter(final RuntimeNode runtimeNode) { 57.436 + public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 57.437 return enterDefault(runtimeNode); 57.438 } 57.439 57.440 @@ -625,7 +602,7 @@ 57.441 * @param runtimeNode the node 57.442 * @return processed node, which will replace the original one, or the original node 57.443 */ 57.444 - public Node leave(final RuntimeNode runtimeNode) { 57.445 + public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 57.446 return leaveDefault(runtimeNode); 57.447 } 57.448 57.449 @@ -635,7 +612,7 @@ 57.450 * @param splitNode the node 57.451 * @return processed node, null if traversal should end 57.452 */ 57.453 - public Node enter(final SplitNode splitNode) { 57.454 + public Node enterSplitNode(final SplitNode splitNode) { 57.455 return enterDefault(splitNode); 57.456 } 57.457 57.458 @@ -645,7 +622,7 @@ 57.459 * @param splitNode the node 57.460 * @return processed node, which will replace the original one, or the original node 57.461 */ 57.462 - public Node leave(final SplitNode splitNode) { 57.463 + public Node leaveSplitNode(final SplitNode splitNode) { 57.464 return leaveDefault(splitNode); 57.465 } 57.466 57.467 @@ -655,7 +632,7 @@ 57.468 * @param switchNode the node 57.469 * @return processed node, null if traversal should end 57.470 */ 57.471 - public Node enter(final SwitchNode switchNode) { 57.472 + public Node enterSwitchNode(final SwitchNode switchNode) { 57.473 return enterDefault(switchNode); 57.474 } 57.475 57.476 @@ -665,7 +642,7 @@ 57.477 * @param switchNode the node 57.478 * @return processed node, which will replace the original one, or the original node 57.479 */ 57.480 - public Node leave(final SwitchNode switchNode) { 57.481 + public Node leaveSwitchNode(final SwitchNode switchNode) { 57.482 return leaveDefault(switchNode); 57.483 } 57.484 57.485 @@ -675,7 +652,7 @@ 57.486 * @param ternaryNode the node 57.487 * @return processed node, null if traversal should end 57.488 */ 57.489 - public Node enter(final TernaryNode ternaryNode) { 57.490 + public Node enterTernaryNode(final TernaryNode ternaryNode) { 57.491 return enterDefault(ternaryNode); 57.492 } 57.493 57.494 @@ -685,7 +662,7 @@ 57.495 * @param ternaryNode the node 57.496 * @return processed node, which will replace the original one, or the original node 57.497 */ 57.498 - public Node leave(final TernaryNode ternaryNode) { 57.499 + public Node leaveTernaryNode(final TernaryNode ternaryNode) { 57.500 return leaveDefault(ternaryNode); 57.501 } 57.502 57.503 @@ -695,7 +672,7 @@ 57.504 * @param throwNode the node 57.505 * @return processed node, null if traversal should end 57.506 */ 57.507 - public Node enter(final ThrowNode throwNode) { 57.508 + public Node enterThrowNode(final ThrowNode throwNode) { 57.509 return enterDefault(throwNode); 57.510 } 57.511 57.512 @@ -705,7 +682,7 @@ 57.513 * @param throwNode the node 57.514 * @return processed node, which will replace the original one, or the original node 57.515 */ 57.516 - public Node leave(final ThrowNode throwNode) { 57.517 + public Node leaveThrowNode(final ThrowNode throwNode) { 57.518 return leaveDefault(throwNode); 57.519 } 57.520 57.521 @@ -715,7 +692,7 @@ 57.522 * @param tryNode the node 57.523 * @return processed node, null if traversal should end 57.524 */ 57.525 - public Node enter(final TryNode tryNode) { 57.526 + public Node enterTryNode(final TryNode tryNode) { 57.527 return enterDefault(tryNode); 57.528 } 57.529 57.530 @@ -725,7 +702,7 @@ 57.531 * @param tryNode the node 57.532 * @return processed node, which will replace the original one, or the original node 57.533 */ 57.534 - public Node leave(final TryNode tryNode) { 57.535 + public Node leaveTryNode(final TryNode tryNode) { 57.536 return leaveDefault(tryNode); 57.537 } 57.538 57.539 @@ -735,7 +712,7 @@ 57.540 * @param unaryNode the node 57.541 * @return processed node, null if traversal should end 57.542 */ 57.543 - public Node enter(final UnaryNode unaryNode) { 57.544 + public Node enterUnaryNode(final UnaryNode unaryNode) { 57.545 return enterDefault(unaryNode); 57.546 } 57.547 57.548 @@ -745,7 +722,7 @@ 57.549 * @param unaryNode the node 57.550 * @return processed node, which will replace the original one, or the original node 57.551 */ 57.552 - public Node leave(final UnaryNode unaryNode) { 57.553 + public Node leaveUnaryNode(final UnaryNode unaryNode) { 57.554 return leaveDefault(unaryNode); 57.555 } 57.556 57.557 @@ -755,7 +732,7 @@ 57.558 * @param varNode the node 57.559 * @return processed node, null if traversal should end 57.560 */ 57.561 - public Node enter(final VarNode varNode) { 57.562 + public Node enterVarNode(final VarNode varNode) { 57.563 return enterDefault(varNode); 57.564 } 57.565 57.566 @@ -765,7 +742,7 @@ 57.567 * @param varNode the node 57.568 * @return processed node, which will replace the original one, or the original node 57.569 */ 57.570 - public Node leave(final VarNode varNode) { 57.571 + public Node leaveVarNode(final VarNode varNode) { 57.572 return leaveDefault(varNode); 57.573 } 57.574 57.575 @@ -775,7 +752,7 @@ 57.576 * @param whileNode the node 57.577 * @return processed node, null if traversal should end 57.578 */ 57.579 - public Node enter(final WhileNode whileNode) { 57.580 + public Node enterWhileNode(final WhileNode whileNode) { 57.581 return enterDefault(whileNode); 57.582 } 57.583 57.584 @@ -785,7 +762,7 @@ 57.585 * @param whileNode the node 57.586 * @return processed node, which will replace the original one, or the original node 57.587 */ 57.588 - public Node leave(final WhileNode whileNode) { 57.589 + public Node leaveWhileNode(final WhileNode whileNode) { 57.590 return leaveDefault(whileNode); 57.591 } 57.592 57.593 @@ -795,7 +772,7 @@ 57.594 * @param withNode the node 57.595 * @return processed node, null if traversal should end 57.596 */ 57.597 - public Node enter(final WithNode withNode) { 57.598 + public Node enterWithNode(final WithNode withNode) { 57.599 return enterDefault(withNode); 57.600 } 57.601 57.602 @@ -805,7 +782,7 @@ 57.603 * @param withNode the node 57.604 * @return processed node, which will replace the original one, or the original node 57.605 */ 57.606 - public Node leave(final WithNode withNode) { 57.607 + public Node leaveWithNode(final WithNode withNode) { 57.608 return leaveDefault(withNode); 57.609 } 57.610
58.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Tue Mar 19 11:03:24 2013 -0300 58.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Sat Mar 23 00:58:39 2013 +0100 58.3 @@ -56,10 +56,10 @@ 58.4 import java.util.ArrayList; 58.5 import java.util.HashMap; 58.6 import java.util.HashSet; 58.7 +import java.util.Iterator; 58.8 import java.util.List; 58.9 import java.util.Map; 58.10 import java.util.Stack; 58.11 - 58.12 import jdk.nashorn.internal.codegen.CompilerConstants; 58.13 import jdk.nashorn.internal.codegen.Namespace; 58.14 import jdk.nashorn.internal.ir.AccessNode; 58.15 @@ -76,17 +76,18 @@ 58.16 import jdk.nashorn.internal.ir.ExecuteNode; 58.17 import jdk.nashorn.internal.ir.ForNode; 58.18 import jdk.nashorn.internal.ir.FunctionNode; 58.19 +import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 58.20 import jdk.nashorn.internal.ir.IdentNode; 58.21 import jdk.nashorn.internal.ir.IfNode; 58.22 import jdk.nashorn.internal.ir.IndexNode; 58.23 import jdk.nashorn.internal.ir.LabelNode; 58.24 +import jdk.nashorn.internal.ir.LexicalContext; 58.25 import jdk.nashorn.internal.ir.LineNumberNode; 58.26 import jdk.nashorn.internal.ir.LiteralNode; 58.27 import jdk.nashorn.internal.ir.Node; 58.28 import jdk.nashorn.internal.ir.ObjectNode; 58.29 import jdk.nashorn.internal.ir.PropertyKey; 58.30 import jdk.nashorn.internal.ir.PropertyNode; 58.31 -import jdk.nashorn.internal.ir.ReferenceNode; 58.32 import jdk.nashorn.internal.ir.ReturnNode; 58.33 import jdk.nashorn.internal.ir.RuntimeNode; 58.34 import jdk.nashorn.internal.ir.SwitchNode; 58.35 @@ -97,7 +98,6 @@ 58.36 import jdk.nashorn.internal.ir.VarNode; 58.37 import jdk.nashorn.internal.ir.WhileNode; 58.38 import jdk.nashorn.internal.ir.WithNode; 58.39 -import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 58.40 import jdk.nashorn.internal.runtime.DebugLogger; 58.41 import jdk.nashorn.internal.runtime.ErrorManager; 58.42 import jdk.nashorn.internal.runtime.JSErrorType; 58.43 @@ -117,11 +117,8 @@ 58.44 /** Is scripting mode. */ 58.45 private final boolean scripting; 58.46 58.47 - /** Current function being parsed. */ 58.48 - private FunctionNode function; 58.49 - 58.50 - /** Current parsing block. */ 58.51 - private Block block; 58.52 + private final LexicalContext lexicalContext = new LexicalContext(); 58.53 + private List<Node> functionDeclarations; 58.54 58.55 /** Namespace for function names where not explicitly given */ 58.56 private final Namespace namespace; 58.57 @@ -277,7 +274,9 @@ 58.58 * @return New block. 58.59 */ 58.60 private Block newBlock() { 58.61 - return block = new Block(source, token, Token.descPosition(token), block, function); 58.62 + final Block block = new Block(source, token, Token.descPosition(token)); 58.63 + lexicalContext.push(block); 58.64 + return block; 58.65 } 58.66 58.67 /** 58.68 @@ -290,19 +289,23 @@ 58.69 // Build function name. 58.70 final StringBuilder sb = new StringBuilder(); 58.71 58.72 - if (block != null) { 58.73 - block.addParentName(sb); 58.74 + final FunctionNode parentFunction = getFunction(); 58.75 + if(parentFunction != null && !parentFunction.isProgram()) { 58.76 + sb.append(parentFunction.getName()).append('$'); 58.77 } 58.78 58.79 sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag()); 58.80 final String name = namespace.uniqueName(sb.toString()); 58.81 - assert function != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). 58.82 + assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). 58.83 58.84 // Start new block. 58.85 - final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, block, ident, name); 58.86 - block = function = functionBlock; 58.87 - function.setStrictMode(isStrictMode); 58.88 - function.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 58.89 + final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name); 58.90 + if(parentFunction == null) { 58.91 + functionBlock.setProgram(); 58.92 + } 58.93 + functionBlock.setStrictMode(isStrictMode); 58.94 + functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 58.95 + lexicalContext.push(functionBlock); 58.96 58.97 return functionBlock; 58.98 } 58.99 @@ -310,9 +313,8 @@ 58.100 /** 58.101 * Restore the current block. 58.102 */ 58.103 - private void restoreBlock() { 58.104 - block = block.getParent(); 58.105 - function = block.getFunction(); 58.106 + private void restoreBlock(Block block) { 58.107 + lexicalContext.pop(block); 58.108 } 58.109 58.110 /** 58.111 @@ -322,19 +324,22 @@ 58.112 private Block getBlock(final boolean needsBraces) { 58.113 // Set up new block. Captures LBRACE. 58.114 final Block newBlock = newBlock(); 58.115 - pushControlNode(newBlock); 58.116 - 58.117 - // Block opening brace. 58.118 - if (needsBraces) { 58.119 - expect(LBRACE); 58.120 - } 58.121 - 58.122 try { 58.123 - // Accumulate block statements. 58.124 - statementList(); 58.125 + pushControlNode(newBlock); 58.126 + 58.127 + // Block opening brace. 58.128 + if (needsBraces) { 58.129 + expect(LBRACE); 58.130 + } 58.131 + 58.132 + try { 58.133 + // Accumulate block statements. 58.134 + statementList(); 58.135 + } finally { 58.136 + popControlNode(); 58.137 + } 58.138 } finally { 58.139 - restoreBlock(); 58.140 - popControlNode(); 58.141 + restoreBlock(newBlock); 58.142 } 58.143 58.144 final int possibleEnd = Token.descPosition(token) + Token.descLength(token); 58.145 @@ -364,7 +369,7 @@ 58.146 // Accumulate statements. 58.147 statement(); 58.148 } finally { 58.149 - restoreBlock(); 58.150 + restoreBlock(newBlock); 58.151 } 58.152 58.153 return newBlock; 58.154 @@ -378,7 +383,10 @@ 58.155 final String name = ident.getName(); 58.156 58.157 if (EVAL.tag().equals(name)) { 58.158 - function.setHasEval(); 58.159 + final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 58.160 + if(it.hasNext()) { 58.161 + it.next().setHasEval(it); 58.162 + } 58.163 } 58.164 } 58.165 58.166 @@ -390,7 +398,7 @@ 58.167 final String name = ident.getName(); 58.168 58.169 if (ARGUMENTS.tag().equals(name)) { 58.170 - function.setUsesArguments(); 58.171 + getFunction().setUsesArguments(); 58.172 } 58.173 } 58.174 58.175 @@ -481,7 +489,7 @@ 58.176 * @return null or the found label node. 58.177 */ 58.178 private LabelNode findLabel(final IdentNode ident) { 58.179 - for (final LabelNode labelNode : function.getLabelStack()) { 58.180 + for (final LabelNode labelNode : getFunction().getLabelStack()) { 58.181 if (labelNode.getLabel().equals(ident)) { 58.182 return labelNode; 58.183 } 58.184 @@ -495,14 +503,14 @@ 58.185 * @param labelNode Label to add. 58.186 */ 58.187 private void pushLabel(final LabelNode labelNode) { 58.188 - function.getLabelStack().push(labelNode); 58.189 + getFunction().getLabelStack().push(labelNode); 58.190 } 58.191 58.192 /** 58.193 * Remove a label from the label stack. 58.194 */ 58.195 private void popLabel() { 58.196 - function.getLabelStack().pop(); 58.197 + getFunction().getLabelStack().pop(); 58.198 } 58.199 58.200 /** 58.201 @@ -512,6 +520,7 @@ 58.202 private void pushControlNode(final Node node) { 58.203 final boolean isLoop = node instanceof WhileNode; 58.204 final boolean isBreakable = node instanceof BreakableNode || node instanceof Block; 58.205 + final FunctionNode function = getFunction(); 58.206 function.getControlStack().push(node); 58.207 58.208 for (final LabelNode labelNode : function.getLabelStack()) { 58.209 @@ -530,7 +539,7 @@ 58.210 */ 58.211 private void popControlNode() { 58.212 // Get control stack. 58.213 - final Stack<Node> controlStack = function.getControlStack(); 58.214 + final Stack<Node> controlStack = getFunction().getControlStack(); 58.215 58.216 // Can be empty if missing brace. 58.217 if (!controlStack.isEmpty()) { 58.218 @@ -540,7 +549,7 @@ 58.219 58.220 private void popControlNode(final Node node) { 58.221 // Get control stack. 58.222 - final Stack<Node> controlStack = function.getControlStack(); 58.223 + final Stack<Node> controlStack = getFunction().getControlStack(); 58.224 58.225 // Can be empty if missing brace. 58.226 if (!controlStack.isEmpty() && controlStack.peek() == node) { 58.227 @@ -549,7 +558,7 @@ 58.228 } 58.229 58.230 private boolean isInWithBlock() { 58.231 - final Stack<Node> controlStack = function.getControlStack(); 58.232 + final Stack<Node> controlStack = getFunction().getControlStack(); 58.233 for (int i = controlStack.size() - 1; i >= 0; i--) { 58.234 final Node node = controlStack.get(i); 58.235 58.236 @@ -562,7 +571,7 @@ 58.237 } 58.238 58.239 private <T extends Node> T findControl(final Class<T> ctype) { 58.240 - final Stack<Node> controlStack = function.getControlStack(); 58.241 + final Stack<Node> controlStack = getFunction().getControlStack(); 58.242 for (int i = controlStack.size() - 1; i >= 0; i--) { 58.243 final Node node = controlStack.get(i); 58.244 58.245 @@ -576,7 +585,7 @@ 58.246 58.247 private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) { 58.248 final List<T> nodes = new ArrayList<>(); 58.249 - final Stack<Node> controlStack = function.getControlStack(); 58.250 + final Stack<Node> controlStack = getFunction().getControlStack(); 58.251 for (int i = controlStack.size() - 1; i >= 0; i--) { 58.252 final Node node = controlStack.get(i); 58.253 58.254 @@ -625,7 +634,10 @@ 58.255 58.256 script.setKind(FunctionNode.Kind.SCRIPT); 58.257 script.setFirstToken(functionToken); 58.258 + functionDeclarations = new ArrayList<>(); 58.259 sourceElements(); 58.260 + script.prependStatements(functionDeclarations); 58.261 + functionDeclarations = null; 58.262 expect(EOF); 58.263 script.setLastToken(token); 58.264 script.setFinish(source.getLength() - 1); 58.265 @@ -704,7 +716,7 @@ 58.266 // check for directive prologues 58.267 if (checkDirective) { 58.268 // skip any debug statement like line number to get actual first line 58.269 - final Node lastStatement = lastStatement(block.getStatements()); 58.270 + final Node lastStatement = lastStatement(getBlock().getStatements()); 58.271 58.272 // get directive prologue, if any 58.273 final String directive = getDirective(lastStatement); 58.274 @@ -724,6 +736,7 @@ 58.275 // handle use strict directive 58.276 if ("use strict".equals(directive)) { 58.277 isStrictMode = true; 58.278 + final FunctionNode function = getFunction(); 58.279 function.setStrictMode(true); 58.280 58.281 // We don't need to check these, if lexical environment is already strict 58.282 @@ -796,11 +809,11 @@ 58.283 if (isStrictMode && !topLevel) { 58.284 error(AbstractParser.message("strict.no.func.here"), token); 58.285 } 58.286 - functionExpression(true); 58.287 + functionExpression(true, topLevel); 58.288 return; 58.289 } 58.290 58.291 - block.addStatement(lineNumberNode); 58.292 + getBlock().addStatement(lineNumberNode); 58.293 58.294 switch (type) { 58.295 case LBRACE: 58.296 @@ -886,7 +899,7 @@ 58.297 // Force block execution. 58.298 final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock); 58.299 58.300 - block.addStatement(executeNode); 58.301 + getBlock().addStatement(executeNode); 58.302 } 58.303 58.304 /** 58.305 @@ -981,13 +994,9 @@ 58.306 58.307 // Allocate var node. 58.308 final VarNode var = new VarNode(source, varToken, finish, name, init); 58.309 - if (isStatement) { 58.310 - function.addDeclaration(var); 58.311 - } 58.312 - 58.313 vars.add(var); 58.314 // Add to current block. 58.315 - block.addStatement(var); 58.316 + getBlock().addStatement(var); 58.317 58.318 if (type != COMMARIGHT) { 58.319 break; 58.320 @@ -1000,7 +1009,7 @@ 58.321 boolean semicolon = type == SEMICOLON; 58.322 endOfLine(); 58.323 if (semicolon) { 58.324 - block.setFinish(finish); 58.325 + getBlock().setFinish(finish); 58.326 } 58.327 } 58.328 58.329 @@ -1017,7 +1026,7 @@ 58.330 */ 58.331 private void emptyStatement() { 58.332 if (env._empty_statements) { 58.333 - block.addStatement(new EmptyNode(source, token, 58.334 + getBlock().addStatement(new EmptyNode(source, token, 58.335 Token.descPosition(token) + Token.descLength(token))); 58.336 } 58.337 58.338 @@ -1043,7 +1052,7 @@ 58.339 ExecuteNode executeNode = null; 58.340 if (expression != null) { 58.341 executeNode = new ExecuteNode(source, expressionToken, finish, expression); 58.342 - block.addStatement(executeNode); 58.343 + getBlock().addStatement(executeNode); 58.344 } else { 58.345 expect(null); 58.346 } 58.347 @@ -1052,7 +1061,7 @@ 58.348 58.349 if (executeNode != null) { 58.350 executeNode.setFinish(finish); 58.351 - block.setFinish(finish); 58.352 + getBlock().setFinish(finish); 58.353 } 58.354 } 58.355 58.356 @@ -1094,7 +1103,7 @@ 58.357 // Construct and add new if node. 58.358 final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail); 58.359 58.360 - block.addStatement(ifNode); 58.361 + getBlock().addStatement(ifNode); 58.362 } 58.363 58.364 /** 58.365 @@ -1143,13 +1152,13 @@ 58.366 outer.setFinish(body.getFinish()); 58.367 58.368 // Add for to current block. 58.369 - block.addStatement(forNode); 58.370 + getBlock().addStatement(forNode); 58.371 } finally { 58.372 - restoreBlock(); 58.373 + restoreBlock(outer); 58.374 popControlNode(); 58.375 } 58.376 58.377 - block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 58.378 + getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 58.379 } 58.380 58.381 /** 58.382 @@ -1283,7 +1292,7 @@ 58.383 whileNode.setFinish(statements.getFinish()); 58.384 58.385 // Add WHILE node. 58.386 - block.addStatement(whileNode); 58.387 + getBlock().addStatement(whileNode); 58.388 } finally { 58.389 popControlNode(); 58.390 } 58.391 @@ -1330,7 +1339,7 @@ 58.392 doWhileNode.setFinish(finish); 58.393 58.394 // Add DO node. 58.395 - block.addStatement(doWhileNode); 58.396 + getBlock().addStatement(doWhileNode); 58.397 } finally { 58.398 popControlNode(); 58.399 } 58.400 @@ -1382,7 +1391,7 @@ 58.401 final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class)); 58.402 continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); 58.403 58.404 - block.addStatement(continueNode); 58.405 + getBlock().addStatement(continueNode); 58.406 } 58.407 58.408 /** 58.409 @@ -1430,7 +1439,7 @@ 58.410 final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class)); 58.411 breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); 58.412 58.413 - block.addStatement(breakNode); 58.414 + getBlock().addStatement(breakNode); 58.415 } 58.416 58.417 /** 58.418 @@ -1443,7 +1452,7 @@ 58.419 */ 58.420 private void returnStatement() { 58.421 // check for return outside function 58.422 - if (function.getKind() == FunctionNode.Kind.SCRIPT) { 58.423 + if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) { 58.424 error(AbstractParser.message("invalid.return")); 58.425 } 58.426 58.427 @@ -1470,7 +1479,7 @@ 58.428 58.429 // Construct and add RETURN node. 58.430 final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class)); 58.431 - block.addStatement(returnNode); 58.432 + getBlock().addStatement(returnNode); 58.433 } 58.434 58.435 /** 58.436 @@ -1505,7 +1514,7 @@ 58.437 58.438 // Construct and add YIELD node. 58.439 final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class)); 58.440 - block.addStatement(yieldNode); 58.441 + getBlock().addStatement(yieldNode); 58.442 } 58.443 58.444 /** 58.445 @@ -1529,7 +1538,10 @@ 58.446 58.447 // Get WITH expression. 58.448 final WithNode withNode = new WithNode(source, withToken, finish, null, null); 58.449 - function.setHasWith(); 58.450 + final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 58.451 + if(it.hasNext()) { 58.452 + it.next().setHasWith(it); 58.453 + } 58.454 58.455 try { 58.456 pushControlNode(withNode); 58.457 @@ -1549,7 +1561,7 @@ 58.458 popControlNode(withNode); 58.459 } 58.460 58.461 - block.addStatement(withNode); 58.462 + getBlock().addStatement(withNode); 58.463 } 58.464 58.465 /** 58.466 @@ -1649,7 +1661,7 @@ 58.467 58.468 switchNode.setFinish(finish); 58.469 58.470 - block.addStatement(switchNode); 58.471 + getBlock().addStatement(switchNode); 58.472 } finally { 58.473 popControlNode(); 58.474 } 58.475 @@ -1684,7 +1696,7 @@ 58.476 labelNode.setBody(statements); 58.477 labelNode.setFinish(finish); 58.478 58.479 - block.addStatement(labelNode); 58.480 + getBlock().addStatement(labelNode); 58.481 } finally { 58.482 // Remove label. 58.483 popLabel(); 58.484 @@ -1727,7 +1739,7 @@ 58.485 58.486 // Construct and add THROW node. 58.487 final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class)); 58.488 - block.addStatement(throwNode); 58.489 + getBlock().addStatement(throwNode); 58.490 } 58.491 58.492 /** 58.493 @@ -1793,18 +1805,18 @@ 58.494 58.495 expect(RPAREN); 58.496 58.497 + final Block catchBlock = newBlock(); 58.498 try { 58.499 - final Block catchBlock = newBlock(); 58.500 58.501 // Get CATCH body. 58.502 final Block catchBody = getBlock(true); 58.503 58.504 // Create and add catch. 58.505 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); 58.506 - block.addStatement(catchNode); 58.507 + getBlock().addStatement(catchNode); 58.508 catchBlocks.add(catchBlock); 58.509 } finally { 58.510 - restoreBlock(); 58.511 + restoreBlock(catchBlock); 58.512 } 58.513 58.514 // If unconditional catch then should to be the end. 58.515 @@ -1840,11 +1852,11 @@ 58.516 outer.addStatement(tryNode); 58.517 } finally { 58.518 popControlNode(tryNode); 58.519 - restoreBlock(); 58.520 + restoreBlock(outer); 58.521 popControlNode(outer); 58.522 } 58.523 58.524 - block.addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 58.525 + getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 58.526 } 58.527 58.528 /** 58.529 @@ -1864,7 +1876,7 @@ 58.530 endOfLine(); 58.531 58.532 final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()); 58.533 - block.addStatement(runtimeNode); 58.534 + getBlock().addStatement(runtimeNode); 58.535 } 58.536 58.537 /** 58.538 @@ -2244,7 +2256,7 @@ 58.539 parameters = new ArrayList<>(); 58.540 functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER); 58.541 propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null); 58.542 - propertyNode.setGetter(new ReferenceNode(source, propertyToken, finish, functionNode)); 58.543 + propertyNode.setGetter(functionNode); 58.544 return propertyNode; 58.545 58.546 case "set": 58.547 @@ -2259,7 +2271,7 @@ 58.548 parameters.add(argIdent); 58.549 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); 58.550 propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null); 58.551 - propertyNode.setSetter(new ReferenceNode(source, propertyToken, finish, functionNode)); 58.552 + propertyNode.setSetter(functionNode); 58.553 return propertyNode; 58.554 58.555 default: 58.556 @@ -2440,7 +2452,7 @@ 58.557 58.558 case FUNCTION: 58.559 // Get function expression. 58.560 - lhs = functionExpression(false); 58.561 + lhs = functionExpression(false, false); 58.562 break; 58.563 58.564 default: 58.565 @@ -2545,7 +2557,7 @@ 58.566 * 58.567 * @return Expression node. 58.568 */ 58.569 - private Node functionExpression(final boolean isStatement) { 58.570 + private Node functionExpression(final boolean isStatement, final boolean topLevel) { 58.571 final LineNumberNode lineNumber = lineNumber(); 58.572 58.573 final long functionToken = token; 58.574 @@ -2580,10 +2592,12 @@ 58.575 58.576 final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); 58.577 58.578 - if (isStatement && !isInWithBlock()) { 58.579 - functionNode.setIsStatement(); 58.580 + if (isStatement) { 58.581 + if(topLevel) { 58.582 + functionNode.setIsDeclared(); 58.583 + } 58.584 if(ARGUMENTS.tag().equals(name.getName())) { 58.585 - functionNode.findParentFunction().setDefinesArguments(); 58.586 + getFunction().setDefinesArguments(); 58.587 } 58.588 } 58.589 58.590 @@ -2591,8 +2605,6 @@ 58.591 functionNode.setIsAnonymous(); 58.592 } 58.593 58.594 - final ReferenceNode referenceNode = new ReferenceNode(source, functionToken, finish, functionNode); 58.595 - 58.596 final int arity = parameters.size(); 58.597 58.598 final boolean strict = functionNode.isStrictMode(); 58.599 @@ -2628,17 +2640,18 @@ 58.600 } 58.601 58.602 if (isStatement) { 58.603 - final VarNode var = new VarNode(source, functionToken, finish, name, referenceNode); 58.604 - if (isInWithBlock()) { 58.605 - function.addDeclaration(var); 58.606 - // Add to current block. 58.607 - block.addStatement(var); 58.608 + final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true); 58.609 + if(topLevel) { 58.610 + functionDeclarations.add(lineNumber); 58.611 + functionDeclarations.add(varNode); 58.612 } else { 58.613 - functionNode.setFunctionVarNode(var, lineNumber); 58.614 + final Block block = getBlock(); 58.615 + block.addStatement(lineNumber); 58.616 + block.addStatement(varNode); 58.617 } 58.618 } 58.619 58.620 - return referenceNode; 58.621 + return functionNode; 58.622 } 58.623 58.624 /** 58.625 @@ -2721,7 +2734,14 @@ 58.626 expect(LBRACE); 58.627 58.628 // Gather the function elements. 58.629 - sourceElements(); 58.630 + final List<Node> prevFunctionDecls = functionDeclarations; 58.631 + functionDeclarations = new ArrayList<>(); 58.632 + try { 58.633 + sourceElements(); 58.634 + functionNode.prependStatements(functionDeclarations); 58.635 + } finally { 58.636 + functionDeclarations = prevFunctionDecls; 58.637 + } 58.638 58.639 functionNode.setLastToken(token); 58.640 expect(RBRACE); 58.641 @@ -2729,12 +2749,9 @@ 58.642 58.643 } 58.644 } finally { 58.645 - restoreBlock(); 58.646 + restoreBlock(functionNode); 58.647 } 58.648 58.649 - // Add the body of the function to the current block. 58.650 - block.addFunction(functionNode); 58.651 - 58.652 return functionNode; 58.653 } 58.654 58.655 @@ -3069,4 +3086,12 @@ 58.656 public String toString() { 58.657 return "[JavaScript Parsing]"; 58.658 } 58.659 + 58.660 + private Block getBlock() { 58.661 + return lexicalContext.getCurrentBlock(); 58.662 + } 58.663 + 58.664 + private FunctionNode getFunction() { 58.665 + return lexicalContext.getCurrentFunction(); 58.666 + } 58.667 }
59.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Tue Mar 19 11:03:24 2013 -0300 59.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Sat Mar 23 00:58:39 2013 +0100 59.3 @@ -27,9 +27,9 @@ 59.4 59.5 import static jdk.nashorn.internal.codegen.CompilerConstants.RUN_SCRIPT; 59.6 import static jdk.nashorn.internal.codegen.CompilerConstants.STRICT_MODE; 59.7 +import static jdk.nashorn.internal.lookup.Lookup.MH; 59.8 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 59.9 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 59.10 -import static jdk.nashorn.internal.lookup.Lookup.MH; 59.11 59.12 import java.io.File; 59.13 import java.io.IOException;
60.1 --- a/src/jdk/nashorn/internal/runtime/resources/Messages.properties Tue Mar 19 11:03:24 2013 -0300 60.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Messages.properties Sat Mar 23 00:58:39 2013 +0100 60.3 @@ -42,6 +42,8 @@ 60.4 parser.error.expected.comma=Expected comma but found {0} 60.5 parser.error.expected=Expected {0} but found {1} 60.6 parser.error.invalid.return=Invalid return statement 60.7 +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. 60.8 +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. 60.9 parser.error.property.redefinition=Property "{0}" already defined 60.10 parser.error.unexpected.token=Unexpected token: {0} 60.11 parser.error.many.vars.in.for.in.loop=Only one variable allowed in for..in loop 60.12 @@ -57,7 +59,7 @@ 60.13 parser.error.strict.cant.delete.ident=cannot delete identifier "{0}" in strict mode 60.14 parser.error.strict.param.redefinition=strict mode function cannot have duplicate parameter name "{0}" 60.15 parser.error.strict.no.octal=cannot use octal value in strict mode 60.16 -parser.error.strict.no.func.here=In strict mode, functions can only be declared at top-level or immediately within a function 60.17 +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. 60.18 type.error.strict.getter.setter.poison=In strict mode, "caller", "callee", and "arguments" properties can not be accessed on functions or the arguments object 60.19 60.20 # not the expected type in a given context
61.1 --- a/test/script/basic/JDK-8006755.js Tue Mar 19 11:03:24 2013 -0300 61.2 +++ b/test/script/basic/JDK-8006755.js Sat Mar 23 00:58:39 2013 +0100 61.3 @@ -31,7 +31,7 @@ 61.4 var scope = { x: "hello" }; 61.5 61.6 with (scope) { 61.7 - function main() { 61.8 + var main = function() { 61.9 if (x != "hello") { 61.10 fail("x != 'hello'"); 61.11 }
62.1 --- a/test/script/basic/NASHORN-837.js Tue Mar 19 11:03:24 2013 -0300 62.2 +++ b/test/script/basic/NASHORN-837.js Sat Mar 23 00:58:39 2013 +0100 62.3 @@ -28,23 +28,13 @@ 62.4 * @run 62.5 */ 62.6 62.7 -var failed = false; 62.8 - 62.9 try { 62.10 - try { 62.11 - throw new TypeError('error'); 62.12 - } catch (iox) { 62.13 - function f() { 62.14 - print(iox.message); 62.15 - } 62.16 + throw new TypeError('error'); 62.17 +} catch (iox) { 62.18 + var f = function() { 62.19 + if(iox.message != 'error') { 62.20 + print("Failure! iox did not throw correct exception"); 62.21 + } 62.22 } 62.23 - f(); 62.24 -} catch (e) { 62.25 - failed = (e instanceof ReferenceError); 62.26 - //iox not defined should be thrown 62.27 } 62.28 - 62.29 -if (!failed) { 62.30 - print("Failure! iox did not throw correct exception"); 62.31 -} 62.32 - 62.33 +f();
63.1 --- a/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Tue Mar 19 11:03:24 2013 -0300 63.2 +++ b/test/src/jdk/nashorn/internal/codegen/CompilerTest.java Sat Mar 23 00:58:39 2013 +0100 63.3 @@ -44,6 +44,7 @@ 63.4 private static final boolean VERBOSE = Boolean.valueOf(System.getProperty("compilertest.verbose")); 63.5 private static final boolean TEST262 = Boolean.valueOf(System.getProperty("compilertest.test262")); 63.6 private static final String TEST_BASIC_DIR = System.getProperty("test.basic.dir"); 63.7 + private static final String TEST_NODE_DIR = System.getProperty("test.node.dir"); 63.8 private static final String TEST262_SUITE_DIR = System.getProperty("test262.suite.dir"); 63.9 63.10 interface TestFilter { 63.11 @@ -81,21 +82,22 @@ 63.12 @Test 63.13 public void compileAllTests() { 63.14 if (TEST262) { 63.15 - compileTestSet(TEST262_SUITE_DIR, new TestFilter() { 63.16 + compileTestSet(new File(TEST262_SUITE_DIR), new TestFilter() { 63.17 @Override 63.18 public boolean exclude(final File file, final String content) { 63.19 return content.indexOf("@negative") != -1; 63.20 } 63.21 }); 63.22 } 63.23 - compileTestSet(TEST_BASIC_DIR, null); 63.24 + compileTestSet(new File(TEST_BASIC_DIR), null); 63.25 + compileTestSet(new File(TEST_NODE_DIR, "node"), null); 63.26 + compileTestSet(new File(TEST_NODE_DIR, "src"), null); 63.27 } 63.28 63.29 - private void compileTestSet(final String testSet, final TestFilter filter) { 63.30 + private void compileTestSet(final File testSetDir, final TestFilter filter) { 63.31 passed = 0; 63.32 failed = 0; 63.33 skipped = 0; 63.34 - final File testSetDir = new File(testSet); 63.35 if (! testSetDir.isDirectory()) { 63.36 log("WARNING: " + testSetDir + " not found or not a directory"); 63.37 return; 63.38 @@ -103,7 +105,7 @@ 63.39 log(testSetDir.getAbsolutePath()); 63.40 compileJSDirectory(testSetDir, filter); 63.41 63.42 - log(testSet + " compile done!"); 63.43 + log(testSetDir + " compile done!"); 63.44 log("compile ok: " + passed); 63.45 log("compile failed: " + failed); 63.46 log("compile skipped: " + skipped);