Fri, 19 Apr 2013 16:11:16 +0200
8010701: Immutable nodes - final iteration
Reviewed-by: sundar, hannesw, jlaskey
1.1 --- a/bin/verbose_octane.sh Fri Apr 19 18:23:00 2013 +0530 1.2 +++ b/bin/verbose_octane.sh Fri Apr 19 16:11:16 2013 +0200 1.3 @@ -26,7 +26,7 @@ 1.4 ITERS=7 1.5 fi 1.6 NASHORN_JAR=dist/nashorn.jar 1.7 -JVM_FLAGS="-XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}" 1.8 +JVM_FLAGS="-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}" 1.9 JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}" 1.10 OCTANE_ARGS="--verbose --iterations ${ITERS}" 1.11
2.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Apr 19 18:23:00 2013 +0530 2.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Fri Apr 19 16:11:16 2013 +0200 2.3 @@ -397,10 +397,7 @@ 2.4 } 2.5 2.6 setContextVariables(ctxt); 2.7 - final Object val = ctxt.getAttribute(ScriptEngine.FILENAME); 2.8 - final String fileName = (val != null) ? val.toString() : "<eval>"; 2.9 - Object res = ScriptRuntime.apply(script, ctxtGlobal); 2.10 - return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(res, ctxtGlobal)); 2.11 + return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal)); 2.12 } catch (final Exception e) { 2.13 throwAsScriptException(e); 2.14 throw new AssertionError("should not reach here");
3.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Fri Apr 19 18:23:00 2013 +0530 3.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Fri Apr 19 16:11:16 2013 +0200 3.3 @@ -25,14 +25,16 @@ 3.4 3.5 package jdk.nashorn.internal.codegen; 3.6 3.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 3.8 import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 3.9 import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX; 3.10 import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX; 3.11 +import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 3.12 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 3.13 -import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN; 3.14 import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX; 3.15 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 3.16 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 3.17 +import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF; 3.18 import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; 3.19 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; 3.20 import static jdk.nashorn.internal.ir.Symbol.IS_LET; 3.21 @@ -42,18 +44,20 @@ 3.22 import static jdk.nashorn.internal.ir.Symbol.IS_VAR; 3.23 import static jdk.nashorn.internal.ir.Symbol.KINDMASK; 3.24 3.25 +import java.util.ArrayDeque; 3.26 import java.util.ArrayList; 3.27 +import java.util.Deque; 3.28 import java.util.HashSet; 3.29 +import java.util.IdentityHashMap; 3.30 import java.util.Iterator; 3.31 import java.util.List; 3.32 -import java.util.ListIterator; 3.33 +import java.util.Map; 3.34 import java.util.Set; 3.35 import jdk.nashorn.internal.codegen.types.Type; 3.36 import jdk.nashorn.internal.ir.AccessNode; 3.37 import jdk.nashorn.internal.ir.BinaryNode; 3.38 import jdk.nashorn.internal.ir.Block; 3.39 import jdk.nashorn.internal.ir.CallNode; 3.40 -import jdk.nashorn.internal.ir.CallNode.EvalArgs; 3.41 import jdk.nashorn.internal.ir.CaseNode; 3.42 import jdk.nashorn.internal.ir.CatchNode; 3.43 import jdk.nashorn.internal.ir.ForNode; 3.44 @@ -62,6 +66,7 @@ 3.45 import jdk.nashorn.internal.ir.IdentNode; 3.46 import jdk.nashorn.internal.ir.IndexNode; 3.47 import jdk.nashorn.internal.ir.LexicalContext; 3.48 +import jdk.nashorn.internal.ir.LexicalContextNode; 3.49 import jdk.nashorn.internal.ir.LiteralNode; 3.50 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 3.51 import jdk.nashorn.internal.ir.Node; 3.52 @@ -86,7 +91,6 @@ 3.53 import jdk.nashorn.internal.runtime.JSType; 3.54 import jdk.nashorn.internal.runtime.Property; 3.55 import jdk.nashorn.internal.runtime.PropertyMap; 3.56 -import jdk.nashorn.internal.runtime.ScriptFunction; 3.57 import jdk.nashorn.internal.runtime.ScriptObject; 3.58 3.59 /** 3.60 @@ -105,21 +109,24 @@ 3.61 */ 3.62 3.63 final class Attr extends NodeOperatorVisitor { 3.64 + 3.65 /** 3.66 * Local definitions in current block (to discriminate from function 3.67 * declarations always defined in the function scope. This is for 3.68 * "can be undefined" analysis. 3.69 */ 3.70 - private Set<String> localDefs; 3.71 + private final Deque<Set<String>> localDefs; 3.72 3.73 /** 3.74 * Local definitions in current block to guard against cases like 3.75 * NASHORN-467 when things can be undefined as they are used before 3.76 * their local var definition. *sigh* JavaScript... 3.77 */ 3.78 - private Set<String> localUses; 3.79 + private final Deque<Set<String>> localUses; 3.80 3.81 - private final LexicalContext lexicalContext = new LexicalContext(); 3.82 + private final Deque<Type> returnTypes; 3.83 + 3.84 + private final Map<Symbol, FunctionNode> selfSymbolToFunction = new IdentityHashMap<>(); 3.85 3.86 private static final DebugLogger LOG = new DebugLogger("attr"); 3.87 private static final boolean DEBUG = LOG.isEnabled(); 3.88 @@ -128,10 +135,13 @@ 3.89 * Constructor. 3.90 */ 3.91 Attr() { 3.92 + localDefs = new ArrayDeque<>(); 3.93 + localUses = new ArrayDeque<>(); 3.94 + returnTypes = new ArrayDeque<>(); 3.95 } 3.96 3.97 @Override 3.98 - protected Node enterDefault(final Node node) { 3.99 + protected boolean enterDefault(final Node node) { 3.100 return start(node); 3.101 } 3.102 3.103 @@ -142,217 +152,44 @@ 3.104 3.105 @Override 3.106 public Node leaveAccessNode(final AccessNode accessNode) { 3.107 - newTemporary(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this 3.108 + ensureSymbol(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this 3.109 end(accessNode); 3.110 return accessNode; 3.111 } 3.112 3.113 - @Override 3.114 - public Node enterBlock(final Block block) { 3.115 - lexicalContext.push(block); 3.116 - start(block); 3.117 + private void enterFunctionBody() { 3.118 3.119 - final Set<String> savedLocalDefs = localDefs; 3.120 - final Set<String> savedLocalUses = localUses; 3.121 - 3.122 - block.setFrame(getCurrentFunctionNode().pushFrame()); 3.123 - 3.124 - try { 3.125 - // a block starts out by copying the local defs and local uses 3.126 - // from the outer level. But we need the copies, as when we 3.127 - // leave the block the def and use sets given upon entry must 3.128 - // be restored 3.129 - localDefs = new HashSet<>(savedLocalDefs); 3.130 - localUses = new HashSet<>(savedLocalUses); 3.131 - 3.132 - block.visitStatements(this); 3.133 - } finally { 3.134 - localDefs = savedLocalDefs; 3.135 - localUses = savedLocalUses; 3.136 - 3.137 - getCurrentFunctionNode().popFrame(); 3.138 + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 3.139 + final Block body = getLexicalContext().getCurrentBlock(); 3.140 + initCallee(body); 3.141 + initThis(body); 3.142 + if (functionNode.isVarArg()) { 3.143 + initVarArg(body, functionNode.needsArguments()); 3.144 } 3.145 3.146 - end(block); 3.147 - 3.148 - lexicalContext.pop(block); 3.149 - return null; 3.150 - } 3.151 - 3.152 - @Override 3.153 - public Node enterCallNode(final CallNode callNode) { 3.154 - start(callNode); 3.155 - 3.156 - callNode.getFunction().accept(this); 3.157 - 3.158 - final List<Node> acceptedArgs = new ArrayList<>(callNode.getArgs().size()); 3.159 - for (final Node arg : callNode.getArgs()) { 3.160 - LOG.info("Doing call arg " + arg); 3.161 - acceptedArgs.add(arg.accept(this)); 3.162 - } 3.163 - callNode.setArgs(acceptedArgs); 3.164 - 3.165 - final EvalArgs evalArgs = callNode.getEvalArgs(); 3.166 - if (evalArgs != null) { 3.167 - evalArgs.setCode(evalArgs.getCode().accept(this)); 3.168 - 3.169 - final IdentNode thisNode = new IdentNode(getCurrentFunctionNode().getThisNode()); 3.170 - assert thisNode.getSymbol() != null; //should copy attributed symbol and that's it 3.171 - evalArgs.setThis(thisNode); 3.172 - } 3.173 - 3.174 - newTemporary(callNode.getType(), callNode); // access specialization in FinalizeTypes may narrow it further later 3.175 - 3.176 - end(callNode); 3.177 - 3.178 - return null; 3.179 - } 3.180 - 3.181 - @Override 3.182 - public Node enterCatchNode(final CatchNode catchNode) { 3.183 - final IdentNode exception = catchNode.getException(); 3.184 - final Block block = getCurrentBlock(); 3.185 - 3.186 - start(catchNode); 3.187 - 3.188 - // define block-local exception variable 3.189 - final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); 3.190 - newType(def, Type.OBJECT); 3.191 - addLocalDef(exception.getName()); 3.192 - 3.193 - return catchNode; 3.194 - } 3.195 - 3.196 - /** 3.197 - * Declare the definition of a new symbol. 3.198 - * 3.199 - * @param name Name of symbol. 3.200 - * @param symbolFlags Symbol flags. 3.201 - * @param node Defining Node. 3.202 - * 3.203 - * @return Symbol for given name or null for redefinition. 3.204 - */ 3.205 - private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { 3.206 - int flags = symbolFlags; 3.207 - Symbol symbol = findSymbol(block, name); // Locate symbol. 3.208 - 3.209 - if ((flags & KINDMASK) == IS_GLOBAL) { 3.210 - flags |= IS_SCOPE; 3.211 - } 3.212 - 3.213 - final FunctionNode function = lexicalContext.getFunction(block); 3.214 - if (symbol != null) { 3.215 - // Symbol was already defined. Check if it needs to be redefined. 3.216 - if ((flags & KINDMASK) == IS_PARAM) { 3.217 - if (!isLocal(function, symbol)) { 3.218 - // Not defined in this function. Create a new definition. 3.219 - symbol = null; 3.220 - } else if (symbol.isParam()) { 3.221 - // Duplicate parameter. Null return will force an error. 3.222 - assert false : "duplicate parameter"; 3.223 - return null; 3.224 - } 3.225 - } else if ((flags & KINDMASK) == IS_VAR) { 3.226 - if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) { 3.227 - assert !((flags & IS_LET) == IS_LET && symbol.getBlock() == block) : "duplicate let variable in block"; 3.228 - // Always create a new definition. 3.229 - symbol = null; 3.230 - } else { 3.231 - // Not defined in this function. Create a new definition. 3.232 - if (!isLocal(function, symbol) || symbol.less(IS_VAR)) { 3.233 - symbol = null; 3.234 - } 3.235 - } 3.236 - } 3.237 - } 3.238 - 3.239 - if (symbol == null) { 3.240 - // If not found, then create a new one. 3.241 - Block symbolBlock; 3.242 - 3.243 - // Determine where to create it. 3.244 - if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { 3.245 - symbolBlock = block; 3.246 - } else { 3.247 - symbolBlock = function; 3.248 - } 3.249 - 3.250 - // Create and add to appropriate block. 3.251 - symbol = new Symbol(name, flags, node, symbolBlock); 3.252 - symbolBlock.putSymbol(name, symbol); 3.253 - 3.254 - if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { 3.255 - symbolBlock.getFrame().addSymbol(symbol); 3.256 - symbol.setNeedsSlot(true); 3.257 - } 3.258 - } else if (symbol.less(flags)) { 3.259 - symbol.setFlags(flags); 3.260 - } 3.261 - 3.262 - if (node != null) { 3.263 - node.setSymbol(symbol); 3.264 - } 3.265 - 3.266 - return symbol; 3.267 - } 3.268 - 3.269 - @Override 3.270 - public Node enterFunctionNode(final FunctionNode functionNode) { 3.271 - start(functionNode, false); 3.272 - if (functionNode.isLazy()) { 3.273 - LOG.info("LAZY: " + functionNode.getName() + " => Promoting to OBJECT"); 3.274 - newTemporary(lexicalContext.getCurrentFunction(), Type.OBJECT, functionNode); 3.275 - functionNode.setReturnType(Type.OBJECT); 3.276 - end(functionNode); 3.277 - return null; 3.278 - } 3.279 - 3.280 - lexicalContext.push(functionNode); 3.281 - 3.282 - clearLocalDefs(); 3.283 - clearLocalUses(); 3.284 - 3.285 - functionNode.setFrame(functionNode.pushFrame()); 3.286 - 3.287 - initCallee(functionNode); 3.288 - initThis(functionNode); 3.289 - if (functionNode.isVarArg()) { 3.290 - initVarArg(functionNode); 3.291 - } 3.292 - 3.293 - initParameters(functionNode); 3.294 - initScope(functionNode); 3.295 - initReturn(functionNode); 3.296 - 3.297 - // Add all nested declared functions as symbols in this function 3.298 - for (final FunctionNode nestedFunction : functionNode.getDeclaredFunctions()) { 3.299 - final IdentNode ident = nestedFunction.getIdent(); 3.300 - if (ident != null) { 3.301 - assert nestedFunction.isDeclared(); 3.302 - final Symbol functionSymbol = defineSymbol(functionNode, ident.getName(), IS_VAR, nestedFunction); 3.303 - newType(functionSymbol, Type.typeFor(ScriptFunction.class)); 3.304 - } 3.305 - } 3.306 + initParameters(functionNode, body); 3.307 + initScope(body); 3.308 + initReturn(body); 3.309 3.310 if (functionNode.isProgram()) { 3.311 - initFromPropertyMap(functionNode); 3.312 + initFromPropertyMap(body); 3.313 } 3.314 3.315 // Add function name as local symbol 3.316 if (!functionNode.isDeclared() && !functionNode.isProgram()) { 3.317 - if(functionNode.getSymbol() != null) { 3.318 + if (functionNode.getSymbol() != null) { 3.319 // a temporary left over from an earlier pass when the function was lazy 3.320 assert functionNode.getSymbol().isTemp(); 3.321 // remove it 3.322 functionNode.setSymbol(null); 3.323 } 3.324 final Symbol selfSymbol; 3.325 - if(functionNode.isAnonymous()) { 3.326 - selfSymbol = newTemporary(functionNode, Type.OBJECT, functionNode); 3.327 + if (functionNode.isAnonymous()) { 3.328 + selfSymbol = ensureSymbol(functionNode, Type.OBJECT, functionNode); 3.329 } else { 3.330 - selfSymbol = defineSymbol(functionNode, functionNode.getIdent().getName(), IS_VAR, functionNode); 3.331 + selfSymbol = defineSymbol(body, functionNode.getIdent().getName(), IS_VAR | IS_FUNCTION_SELF, functionNode); 3.332 newType(selfSymbol, Type.OBJECT); 3.333 - selfSymbol.setNode(functionNode); 3.334 + selfSymbolToFunction.put(selfSymbol, functionNode); 3.335 } 3.336 } 3.337 3.338 @@ -373,73 +210,243 @@ 3.339 * @see NASHORN-73 3.340 */ 3.341 3.342 - final List<Symbol> declaredSymbols = new ArrayList<>(); 3.343 // This visitor will assign symbol to all declared variables, except function declarations (which are taken care 3.344 // in a separate step above) and "var" declarations in for loop initializers. 3.345 - functionNode.accept(new NodeOperatorVisitor() { 3.346 + body.accept(new NodeOperatorVisitor() { 3.347 @Override 3.348 - public Node enterFunctionNode(FunctionNode nestedFn) { 3.349 - // Don't descend into nested functions 3.350 - return nestedFn == functionNode ? nestedFn : null; 3.351 + public boolean enterFunctionNode(final FunctionNode nestedFn) { 3.352 + return false; 3.353 } 3.354 + 3.355 @Override 3.356 - public Node enterVarNode(VarNode varNode) { 3.357 - if(varNode.isStatement() && !varNode.isFunctionDeclaration()) { 3.358 + public boolean enterVarNode(final VarNode varNode) { 3.359 + 3.360 + // any declared symbols that aren't visited need to be typed as well, hence the list 3.361 + 3.362 + if (varNode.isStatement()) { 3.363 + 3.364 final IdentNode ident = varNode.getName(); 3.365 - // any declared symbols that aren't visited need to be typed as well, hence the list 3.366 - declaredSymbols.add(defineSymbol(functionNode, ident.getName(), IS_VAR, new IdentNode(ident))); 3.367 + final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident)); 3.368 + functionNode.addDeclaredSymbol(symbol); 3.369 + if (varNode.isFunctionDeclaration()) { 3.370 + newType(symbol, FunctionNode.FUNCTION_TYPE); 3.371 + } 3.372 } 3.373 - return null; 3.374 + return false; 3.375 } 3.376 }); 3.377 + } 3.378 3.379 - visitFunctionStatements(functionNode); 3.380 + @Override 3.381 + public boolean enterBlock(final Block block) { 3.382 + start(block); 3.383 + 3.384 + if (getLexicalContext().isFunctionBody()) { 3.385 + enterFunctionBody(); 3.386 + } 3.387 + pushLocalsBlock(); 3.388 + 3.389 + return true; 3.390 + } 3.391 + 3.392 + @Override 3.393 + public Node leaveBlock(final Block block) { 3.394 + popLocals(); 3.395 + return end(block); 3.396 + } 3.397 + 3.398 + @Override 3.399 + public Node leaveCallNode(final CallNode callNode) { 3.400 + ensureSymbol(callNode.getType(), callNode); 3.401 + return end(callNode); 3.402 + } 3.403 + 3.404 + @Override 3.405 + public boolean enterCallNode(final CallNode callNode) { 3.406 + return start(callNode); 3.407 + } 3.408 + 3.409 + @Override 3.410 + public boolean enterCatchNode(final CatchNode catchNode) { 3.411 + final IdentNode exception = catchNode.getException(); 3.412 + final Block block = getLexicalContext().getCurrentBlock(); 3.413 + 3.414 + start(catchNode); 3.415 + 3.416 + // define block-local exception variable 3.417 + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); 3.418 + newType(def, Type.OBJECT); 3.419 + addLocalDef(exception.getName()); 3.420 + 3.421 + return true; 3.422 + } 3.423 + 3.424 + /** 3.425 + * Declare the definition of a new symbol. 3.426 + * 3.427 + * @param name Name of symbol. 3.428 + * @param symbolFlags Symbol flags. 3.429 + * @param node Defining Node. 3.430 + * 3.431 + * @return Symbol for given name or null for redefinition. 3.432 + */ 3.433 + private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { 3.434 + int flags = symbolFlags; 3.435 + Symbol symbol = findSymbol(block, name); // Locate symbol. 3.436 + 3.437 + if ((flags & KINDMASK) == IS_GLOBAL) { 3.438 + flags |= IS_SCOPE; 3.439 + } 3.440 + 3.441 + final FunctionNode function = getLexicalContext().getFunction(block); 3.442 + if (symbol != null) { 3.443 + // Symbol was already defined. Check if it needs to be redefined. 3.444 + if ((flags & KINDMASK) == IS_PARAM) { 3.445 + if (!isLocal(function, symbol)) { 3.446 + // Not defined in this function. Create a new definition. 3.447 + symbol = null; 3.448 + } else if (symbol.isParam()) { 3.449 + // Duplicate parameter. Null return will force an error. 3.450 + assert false : "duplicate parameter"; 3.451 + return null; 3.452 + } 3.453 + } else if ((flags & KINDMASK) == IS_VAR) { 3.454 + if ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET) { 3.455 + // Always create a new definition. 3.456 + symbol = null; 3.457 + } else { 3.458 + // Not defined in this function. Create a new definition. 3.459 + if (!isLocal(function, symbol) || symbol.less(IS_VAR)) { 3.460 + symbol = null; 3.461 + } 3.462 + } 3.463 + } 3.464 + } 3.465 + 3.466 + if (symbol == null) { 3.467 + // If not found, then create a new one. 3.468 + Block symbolBlock; 3.469 + 3.470 + // Determine where to create it. 3.471 + if ((flags & Symbol.KINDMASK) == IS_VAR && ((flags & IS_INTERNAL) == IS_INTERNAL || (flags & IS_LET) == IS_LET)) { 3.472 + symbolBlock = block; //internal vars are always defined in the block closest to them 3.473 + } else { 3.474 + symbolBlock = getLexicalContext().getFunctionBody(function); 3.475 + } 3.476 + 3.477 + // Create and add to appropriate block. 3.478 + symbol = new Symbol(name, flags); 3.479 + symbolBlock.putSymbol(name, symbol); 3.480 + 3.481 + if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { 3.482 + symbol.setNeedsSlot(true); 3.483 + } 3.484 + } else if (symbol.less(flags)) { 3.485 + symbol.setFlags(flags); 3.486 + } 3.487 + 3.488 + if (node != null) { 3.489 + node.setSymbol(symbol); 3.490 + } 3.491 + 3.492 + return symbol; 3.493 + } 3.494 + 3.495 + @Override 3.496 + public boolean enterFunctionNode(final FunctionNode functionNode) { 3.497 + start(functionNode, false); 3.498 + 3.499 + if (functionNode.isDeclared()) { 3.500 + final Iterator<Block> blocks = getLexicalContext().getBlocks(); 3.501 + if (blocks.hasNext()) { 3.502 + defineSymbol( 3.503 + blocks.next(), 3.504 + functionNode.getIdent().getName(), 3.505 + IS_VAR, 3.506 + functionNode); 3.507 + } else { 3.508 + // Q: What's an outermost function in a lexical context that is not a program? 3.509 + // A: It's a function being compiled lazily! 3.510 + assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram(); 3.511 + } 3.512 + } 3.513 + 3.514 + if (functionNode.isLazy()) { 3.515 + LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT"); 3.516 + ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode); 3.517 + end(functionNode); 3.518 + return false; 3.519 + } 3.520 + 3.521 + returnTypes.push(functionNode.getReturnType()); 3.522 + pushLocalsFunction(); 3.523 + return true; 3.524 + } 3.525 + 3.526 + @Override 3.527 + public Node leaveFunctionNode(final FunctionNode functionNode) { 3.528 + FunctionNode newFunctionNode = functionNode; 3.529 + 3.530 + final LexicalContext lc = getLexicalContext(); 3.531 3.532 //unknown parameters are promoted to object type. 3.533 - finalizeParameters(functionNode); 3.534 - finalizeTypes(functionNode); 3.535 - for (final Symbol symbol : declaredSymbols) { 3.536 + finalizeParameters(newFunctionNode); 3.537 + finalizeTypes(newFunctionNode); 3.538 + for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) { 3.539 if (symbol.getSymbolType().isUnknown()) { 3.540 symbol.setType(Type.OBJECT); 3.541 symbol.setCanBeUndefined(); 3.542 } 3.543 } 3.544 3.545 - if (functionNode.getReturnType().isUnknown()) { 3.546 - LOG.info("Unknown return type promoted to object"); 3.547 - functionNode.setReturnType(Type.OBJECT); 3.548 + final Block body = newFunctionNode.getBody(); 3.549 + 3.550 + if (newFunctionNode.hasLazyChildren()) { 3.551 + //the final body has already been assigned as we have left the function node block body by now 3.552 + objectifySymbols(body); 3.553 } 3.554 3.555 - if (functionNode.getSelfSymbolInit() != null) { 3.556 - LOG.info("Accepting self symbol init " + functionNode.getSelfSymbolInit() + " for " + functionNode.getName()); 3.557 - final Node init = functionNode.getSelfSymbolInit(); 3.558 + if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) { 3.559 + final IdentNode callee = compilerConstant(CALLEE); 3.560 + final VarNode selfInit = 3.561 + new VarNode( 3.562 + newFunctionNode.getSource(), 3.563 + newFunctionNode.getToken(), 3.564 + newFunctionNode.getFinish(), 3.565 + newFunctionNode.getIdent(), 3.566 + callee); 3.567 + 3.568 + LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName()); 3.569 + 3.570 final List<Node> newStatements = new ArrayList<>(); 3.571 - newStatements.add(init); 3.572 - newStatements.addAll(functionNode.getStatements()); 3.573 - functionNode.setStatements(newStatements); 3.574 - functionNode.setNeedsSelfSymbol(functionNode.getSelfSymbolInit().accept(this)); 3.575 + newStatements.add(selfInit); 3.576 + assert callee.getSymbol() != null && callee.getSymbol().hasSlot(); 3.577 + 3.578 + final IdentNode name = selfInit.getName(); 3.579 + final Symbol nameSymbol = body.getExistingSymbol(name.getName()); 3.580 + 3.581 + assert nameSymbol != null; 3.582 + 3.583 + name.setSymbol(nameSymbol); 3.584 + selfInit.setSymbol(nameSymbol); 3.585 + 3.586 + newStatements.addAll(body.getStatements()); 3.587 + newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements)); 3.588 } 3.589 3.590 - if (functionNode.hasLazyChildren()) { 3.591 - objectifySymbols(functionNode); 3.592 + if (returnTypes.peek().isUnknown()) { 3.593 + LOG.info("Unknown return type promoted to object"); 3.594 + newFunctionNode = newFunctionNode.setReturnType(lc, Type.OBJECT); 3.595 } 3.596 + final Type returnType = returnTypes.pop(); 3.597 + newFunctionNode = newFunctionNode.setReturnType(lc, returnType.isUnknown() ? Type.OBJECT : returnType); 3.598 + newFunctionNode = newFunctionNode.setState(lc, CompilationState.ATTR); 3.599 3.600 - functionNode.popFrame(); 3.601 + popLocals(); 3.602 3.603 - functionNode.setState(CompilationState.ATTR); 3.604 + end(newFunctionNode, false); 3.605 3.606 - end(functionNode, false); 3.607 - lexicalContext.pop(functionNode); 3.608 - 3.609 - return null; 3.610 - } 3.611 - 3.612 - private void visitFunctionStatements(final FunctionNode functionNode) { 3.613 - final List<Node> newStatements = new ArrayList<>(functionNode.getStatements()); 3.614 - for(ListIterator<Node> stmts = newStatements.listIterator(); stmts.hasNext();) { 3.615 - stmts.set(stmts.next().accept(this)); 3.616 - } 3.617 - functionNode.setStatements(newStatements); 3.618 + return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode)); 3.619 } 3.620 3.621 @Override 3.622 @@ -450,7 +457,7 @@ 3.623 } 3.624 3.625 @Override 3.626 - public Node enterIdentNode(final IdentNode identNode) { 3.627 + public boolean enterIdentNode(final IdentNode identNode) { 3.628 final String name = identNode.getName(); 3.629 3.630 start(identNode); 3.631 @@ -458,31 +465,28 @@ 3.632 if (identNode.isPropertyName()) { 3.633 // assign a pseudo symbol to property name 3.634 final Symbol pseudoSymbol = pseudoSymbol(name); 3.635 - LOG.info("IdentNode is property name -> assigning pseudo symbol " + pseudoSymbol); 3.636 + LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol); 3.637 LOG.unindent(); 3.638 identNode.setSymbol(pseudoSymbol); 3.639 - return null; 3.640 + return false; 3.641 } 3.642 3.643 - final Block block = getCurrentBlock(); 3.644 - final Symbol oldSymbol = identNode.getSymbol(); 3.645 + final LexicalContext lc = getLexicalContext(); 3.646 + final Block block = lc.getCurrentBlock(); 3.647 + final Symbol oldSymbol = identNode.getSymbol(); 3.648 3.649 Symbol symbol = findSymbol(block, name); 3.650 3.651 //If an existing symbol with the name is found, use that otherwise, declare a new one 3.652 if (symbol != null) { 3.653 - LOG.info("Existing symbol = " + symbol); 3.654 - if (isFunctionExpressionSelfReference(symbol)) { 3.655 - final FunctionNode functionNode = (FunctionNode)symbol.getNode(); 3.656 - assert functionNode.getCalleeNode() != null; 3.657 - 3.658 - final VarNode var = new VarNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), functionNode.getIdent(), functionNode.getCalleeNode()); 3.659 - //newTemporary(Type.OBJECT, var); //ScriptFunction? TODO 3.660 - 3.661 - functionNode.setNeedsSelfSymbol(var); 3.662 - } 3.663 - 3.664 - if (!identNode.isInitializedHere()) { // NASHORN-448 3.665 + LOG.info("Existing symbol = ", symbol); 3.666 + if (symbol.isFunctionSelf()) { 3.667 + final FunctionNode functionNode = lc.getDefiningFunction(symbol); 3.668 + assert functionNode != null; 3.669 + assert lc.getFunctionBody(functionNode).getExistingSymbol(CALLEE.symbolName()) != null; 3.670 + lc.setFlag(functionNode.getBody(), Block.NEEDS_SELF_SYMBOL); 3.671 + newType(symbol, FunctionNode.FUNCTION_TYPE); 3.672 + } else if (!identNode.isInitializedHere()) { // NASHORN-448 3.673 // here is a use outside the local def scope 3.674 if (!isLocalDef(name)) { 3.675 newType(symbol, Type.OBJECT); 3.676 @@ -492,25 +496,19 @@ 3.677 3.678 identNode.setSymbol(symbol); 3.679 // non-local: we need to put symbol in scope (if it isn't already) 3.680 - if (!isLocal(getCurrentFunctionNode(), symbol) && !symbol.isScope()) { 3.681 - symbol.setIsScope(); 3.682 + if (!isLocal(lc.getCurrentFunction(), symbol) && !symbol.isScope()) { 3.683 + Symbol.setSymbolIsScope(lc, symbol); 3.684 } 3.685 } else { 3.686 - LOG.info("No symbol exists. Declare undefined: " + symbol); 3.687 - symbol = useSymbol(block, name, identNode); 3.688 + LOG.info("No symbol exists. Declare undefined: ", symbol); 3.689 + symbol = defineSymbol(block, name, IS_GLOBAL, identNode); 3.690 // we have never seen this before, it can be undefined 3.691 newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? 3.692 symbol.setCanBeUndefined(); 3.693 - symbol.setIsScope(); 3.694 + Symbol.setSymbolIsScope(lc, symbol); 3.695 } 3.696 3.697 - assert symbol != null; 3.698 - if(symbol.isGlobal()) { 3.699 - setUsesGlobalSymbol(); 3.700 - } else if(symbol.isScope()) { 3.701 - final Iterator<Block> blocks = lexicalContext.getBlocks(); 3.702 - blocks.next().setUsesScopeSymbol(symbol, blocks); 3.703 - } 3.704 + setBlockScope(name, symbol); 3.705 3.706 if (symbol != oldSymbol && !identNode.isInitializedHere()) { 3.707 symbol.increaseUseCount(); 3.708 @@ -519,7 +517,37 @@ 3.709 3.710 end(identNode); 3.711 3.712 - return null; 3.713 + return false; 3.714 + } 3.715 + 3.716 + private void setBlockScope(final String name, final Symbol symbol) { 3.717 + assert symbol != null; 3.718 + if (symbol.isGlobal()) { 3.719 + setUsesGlobalSymbol(); 3.720 + return; 3.721 + } 3.722 + 3.723 + if (symbol.isScope()) { 3.724 + final LexicalContext lc = getLexicalContext(); 3.725 + 3.726 + Block scopeBlock = null; 3.727 + for (final Iterator<LexicalContextNode> contextNodeIter = getLexicalContext().getAllNodes(); contextNodeIter.hasNext(); ) { 3.728 + final LexicalContextNode node = contextNodeIter.next(); 3.729 + if (node instanceof Block) { 3.730 + if (((Block)node).getExistingSymbol(name) != null) { 3.731 + scopeBlock = (Block)node; 3.732 + break; 3.733 + } 3.734 + } else if (node instanceof FunctionNode) { 3.735 + lc.setFlag(node, FunctionNode.USES_ANCESTOR_SCOPE); 3.736 + } 3.737 + } 3.738 + 3.739 + if (scopeBlock != null) { 3.740 + assert getLexicalContext().contains(scopeBlock); 3.741 + lc.setFlag(scopeBlock, Block.NEEDS_SCOPE); 3.742 + } 3.743 + } 3.744 } 3.745 3.746 /** 3.747 @@ -528,35 +556,12 @@ 3.748 * @see #needsParentScope() 3.749 */ 3.750 private void setUsesGlobalSymbol() { 3.751 - for(final Iterator<FunctionNode> fns = lexicalContext.getFunctions(); fns.hasNext();) { 3.752 - fns.next().setUsesAncestorScope(); 3.753 + for (final Iterator<FunctionNode> fns = getLexicalContext().getFunctions(); fns.hasNext();) { 3.754 + getLexicalContext().setFlag(fns.next(), FunctionNode.USES_ANCESTOR_SCOPE); 3.755 } 3.756 } 3.757 3.758 /** 3.759 - * Declare the use of a symbol in a block. 3.760 - * 3.761 - * @param block block in which the symbol is used 3.762 - * @param name Name of symbol. 3.763 - * @param node Using node 3.764 - * 3.765 - * @return Symbol for given name. 3.766 - */ 3.767 - private Symbol useSymbol(final Block block, final String name, final Node node) { 3.768 - Symbol symbol = findSymbol(block, name); 3.769 - 3.770 - if (symbol == null) { 3.771 - // If not found, declare as a free var. 3.772 - symbol = defineSymbol(block, name, IS_GLOBAL, node); 3.773 - } else { 3.774 - node.setSymbol(symbol); 3.775 - } 3.776 - 3.777 - return symbol; 3.778 - } 3.779 - 3.780 - 3.781 - /** 3.782 * Search for symbol in the lexical context starting from the given block. 3.783 * @param name Symbol name. 3.784 * @return Found symbol or null if not found. 3.785 @@ -564,7 +569,7 @@ 3.786 private Symbol findSymbol(final Block block, final String name) { 3.787 // Search up block chain to locate symbol. 3.788 3.789 - for(final Iterator<Block> blocks = lexicalContext.getBlocks(block); blocks.hasNext();) { 3.790 + for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { 3.791 // Find name. 3.792 final Symbol symbol = blocks.next().getExistingSymbol(name); 3.793 // If found then we are good. 3.794 @@ -577,13 +582,13 @@ 3.795 3.796 @Override 3.797 public Node leaveIndexNode(final IndexNode indexNode) { 3.798 - newTemporary(Type.OBJECT, indexNode); //TODO 3.799 + ensureSymbol(Type.OBJECT, indexNode); //TODO 3.800 return indexNode; 3.801 } 3.802 3.803 @SuppressWarnings("rawtypes") 3.804 @Override 3.805 - public Node enterLiteralNode(final LiteralNode literalNode) { 3.806 + public boolean enterLiteralNode(final LiteralNode literalNode) { 3.807 try { 3.808 start(literalNode); 3.809 assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens 3.810 @@ -604,26 +609,33 @@ 3.811 assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; 3.812 } 3.813 3.814 - getCurrentFunctionNode().newLiteral(literalNode); 3.815 + getLexicalContext().getCurrentFunction().newLiteral(literalNode); 3.816 } finally { 3.817 end(literalNode); 3.818 } 3.819 - return null; 3.820 + 3.821 + return false; 3.822 + } 3.823 + 3.824 + @Override 3.825 + public boolean enterObjectNode(final ObjectNode objectNode) { 3.826 + return start(objectNode); 3.827 } 3.828 3.829 @Override 3.830 public Node leaveObjectNode(final ObjectNode objectNode) { 3.831 - newTemporary(Type.OBJECT, objectNode); 3.832 - end(objectNode); 3.833 - return objectNode; 3.834 + ensureSymbol(Type.OBJECT, objectNode); 3.835 + return end(objectNode); 3.836 } 3.837 3.838 + //TODO is this correct why not leave? 3.839 @Override 3.840 - public Node enterPropertyNode(final PropertyNode propertyNode) { 3.841 + public boolean enterPropertyNode(final PropertyNode propertyNode) { 3.842 // assign a pseudo symbol to property name, see NASHORN-710 3.843 + start(propertyNode); 3.844 propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); 3.845 end(propertyNode); 3.846 - return propertyNode; 3.847 + return true; 3.848 } 3.849 3.850 @Override 3.851 @@ -636,8 +648,10 @@ 3.852 if (expr.getType().isUnknown() && symbol.isParam()) { 3.853 symbol.setType(Type.OBJECT); 3.854 } 3.855 - getCurrentFunctionNode().setReturnType(Type.widest(getCurrentFunctionNode().getReturnType(), symbol.getSymbolType())); 3.856 - LOG.info("Returntype is now " + getCurrentFunctionNode().getReturnType()); 3.857 + 3.858 + final Type returnType = Type.widest(returnTypes.pop(), symbol.getSymbolType()); 3.859 + returnTypes.push(returnType); 3.860 + LOG.info("Returntype is now ", returnType); 3.861 } 3.862 3.863 end(returnNode); 3.864 @@ -649,25 +663,29 @@ 3.865 public Node leaveSwitchNode(final SwitchNode switchNode) { 3.866 Type type = Type.UNKNOWN; 3.867 3.868 + final List<CaseNode> newCases = new ArrayList<>(); 3.869 for (final CaseNode caseNode : switchNode.getCases()) { 3.870 final Node test = caseNode.getTest(); 3.871 + 3.872 + CaseNode newCaseNode = caseNode; 3.873 if (test != null) { 3.874 if (test instanceof LiteralNode) { 3.875 //go down to integers if we can 3.876 final LiteralNode<?> lit = (LiteralNode<?>)test; 3.877 if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) { 3.878 if (JSType.isRepresentableAsInt(lit.getNumber())) { 3.879 - caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); 3.880 + newCaseNode = caseNode.setTest(LiteralNode.newInstance(lit, lit.getInt32()).accept(this)); 3.881 } 3.882 } 3.883 } else { 3.884 // the "all integer" case that CodeGenerator optimizes for currently assumes literals only 3.885 type = Type.OBJECT; 3.886 - break; 3.887 } 3.888 3.889 - type = Type.widest(type, caseNode.getTest().getType()); 3.890 + type = Type.widest(type, newCaseNode.getTest().getType()); 3.891 } 3.892 + 3.893 + newCases.add(newCaseNode); 3.894 } 3.895 3.896 //only optimize for all integers 3.897 @@ -675,11 +693,11 @@ 3.898 type = Type.OBJECT; 3.899 } 3.900 3.901 - switchNode.setTag(newInternal(getCurrentFunctionNode().uniqueName(SWITCH_TAG_PREFIX.tag()), type)); 3.902 + switchNode.setTag(newInternal(getLexicalContext().getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type)); 3.903 3.904 end(switchNode); 3.905 3.906 - return switchNode; 3.907 + return switchNode.setCases(getLexicalContext(), newCases); 3.908 } 3.909 3.910 @Override 3.911 @@ -696,25 +714,25 @@ 3.912 } 3.913 3.914 @Override 3.915 - public Node enterVarNode(final VarNode varNode) { 3.916 + public boolean enterVarNode(final VarNode varNode) { 3.917 start(varNode); 3.918 3.919 final IdentNode ident = varNode.getName(); 3.920 final String name = ident.getName(); 3.921 3.922 - final Symbol symbol = defineSymbol(getCurrentBlock(), name, IS_VAR, ident); 3.923 + final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident); 3.924 assert symbol != null; 3.925 3.926 - LOG.info("VarNode " + varNode + " set symbol " + symbol); 3.927 + LOG.info("VarNode ", varNode, " set symbol ", symbol); 3.928 varNode.setSymbol(symbol); 3.929 3.930 // NASHORN-467 - use before definition of vars - conservative 3.931 - if (localUses.contains(ident.getName())) { 3.932 + if (isLocalUse(ident.getName())) { 3.933 newType(symbol, Type.OBJECT); 3.934 symbol.setCanBeUndefined(); 3.935 } 3.936 3.937 - return varNode; 3.938 + return true; 3.939 } 3.940 3.941 @Override 3.942 @@ -734,7 +752,7 @@ 3.943 addLocalDef(name); 3.944 3.945 final Symbol symbol = varNode.getSymbol(); 3.946 - final boolean isScript = lexicalContext.getFunction(symbol.getBlock()).isProgram(); //see NASHORN-56 3.947 + final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56 3.948 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { 3.949 // Forbid integers as local vars for now as we have no way to treat them as undefined 3.950 newType(symbol, init.getType()); 3.951 @@ -751,14 +769,14 @@ 3.952 3.953 @Override 3.954 public Node leaveADD(final UnaryNode unaryNode) { 3.955 - newTemporary(arithType(), unaryNode); 3.956 + ensureSymbol(arithType(), unaryNode); 3.957 end(unaryNode); 3.958 return unaryNode; 3.959 } 3.960 3.961 @Override 3.962 public Node leaveBIT_NOT(final UnaryNode unaryNode) { 3.963 - newTemporary(Type.INT, unaryNode); 3.964 + ensureSymbol(Type.INT, unaryNode); 3.965 end(unaryNode); 3.966 return unaryNode; 3.967 } 3.968 @@ -766,30 +784,29 @@ 3.969 @Override 3.970 public Node leaveDECINC(final UnaryNode unaryNode) { 3.971 // @see assignOffset 3.972 - ensureAssignmentSlots(getCurrentFunctionNode(), unaryNode.rhs()); 3.973 + ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs()); 3.974 final Type type = arithType(); 3.975 newType(unaryNode.rhs().getSymbol(), type); 3.976 - newTemporary(type, unaryNode); 3.977 + ensureSymbol(type, unaryNode); 3.978 end(unaryNode); 3.979 return unaryNode; 3.980 } 3.981 3.982 @Override 3.983 public Node leaveDELETE(final UnaryNode unaryNode) { 3.984 - final FunctionNode currentFunctionNode = getCurrentFunctionNode(); 3.985 - final boolean strictMode = currentFunctionNode.isStrictMode(); 3.986 + final FunctionNode currentFunctionNode = getLexicalContext().getCurrentFunction(); 3.987 + final boolean strictMode = currentFunctionNode.isStrict(); 3.988 final Node rhs = unaryNode.rhs(); 3.989 final Node strictFlagNode = LiteralNode.newInstance(unaryNode, strictMode).accept(this); 3.990 3.991 Request request = Request.DELETE; 3.992 - final RuntimeNode runtimeNode; 3.993 final List<Node> args = new ArrayList<>(); 3.994 3.995 if (rhs instanceof IdentNode) { 3.996 // If this is a declared variable or a function parameter, delete always fails (except for globals). 3.997 final String name = ((IdentNode)rhs).getName(); 3.998 3.999 - final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !rhs.getSymbol().isTopLevel()); 3.1000 + final boolean failDelete = strictMode || rhs.getSymbol().isParam() || (rhs.getSymbol().isVar() && !isProgramLevelSymbol(name)); 3.1001 3.1002 if (failDelete && rhs.getSymbol().isThis()) { 3.1003 return LiteralNode.newInstance(unaryNode, true).accept(this); 3.1004 @@ -797,7 +814,7 @@ 3.1005 final Node literalNode = LiteralNode.newInstance(unaryNode, name).accept(this); 3.1006 3.1007 if (!failDelete) { 3.1008 - args.add(currentFunctionNode.getScopeNode()); 3.1009 + args.add(compilerConstant(SCOPE)); 3.1010 } 3.1011 args.add(literalNode); 3.1012 args.add(strictFlagNode); 3.1013 @@ -825,42 +842,62 @@ 3.1014 return LiteralNode.newInstance(unaryNode, true).accept(this); 3.1015 } 3.1016 3.1017 - runtimeNode = new RuntimeNode(unaryNode, request, args); 3.1018 - assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //clone constructor should do this 3.1019 + final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, request, args); 3.1020 + assert runtimeNode.getSymbol() == unaryNode.getSymbol(); //unary parent constructor should do this 3.1021 3.1022 return leaveRuntimeNode(runtimeNode); 3.1023 } 3.1024 3.1025 + /** 3.1026 + * Is the symbol denoted by the specified name in the current lexical context defined in the program level 3.1027 + * @param name the name of the symbol 3.1028 + * @return true if the symbol denoted by the specified name in the current lexical context defined in the program level. 3.1029 + */ 3.1030 + private boolean isProgramLevelSymbol(final String name) { 3.1031 + for(final Iterator<Block> it = getLexicalContext().getBlocks(); it.hasNext();) { 3.1032 + final Block next = it.next(); 3.1033 + if(next.getExistingSymbol(name) != null) { 3.1034 + return next == getLexicalContext().getFunctionBody(getLexicalContext().getOutermostFunction()); 3.1035 + } 3.1036 + } 3.1037 + throw new AssertionError("Couldn't find symbol " + name + " in the context"); 3.1038 + } 3.1039 + 3.1040 @Override 3.1041 public Node leaveNEW(final UnaryNode unaryNode) { 3.1042 - newTemporary(Type.OBJECT, unaryNode); 3.1043 + ensureSymbol(Type.OBJECT, unaryNode); 3.1044 end(unaryNode); 3.1045 return unaryNode; 3.1046 } 3.1047 3.1048 @Override 3.1049 public Node leaveNOT(final UnaryNode unaryNode) { 3.1050 - newTemporary(Type.BOOLEAN, unaryNode); 3.1051 + ensureSymbol(Type.BOOLEAN, unaryNode); 3.1052 end(unaryNode); 3.1053 return unaryNode; 3.1054 } 3.1055 3.1056 + private IdentNode compilerConstant(CompilerConstants cc) { 3.1057 + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 3.1058 + final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); 3.1059 + node.setSymbol(functionNode.compilerConstant(cc)); 3.1060 + return node; 3.1061 + } 3.1062 + 3.1063 @Override 3.1064 public Node leaveTYPEOF(final UnaryNode unaryNode) { 3.1065 - final Node rhs = unaryNode.rhs(); 3.1066 - 3.1067 - RuntimeNode runtimeNode; 3.1068 + final Node rhs = unaryNode.rhs(); 3.1069 3.1070 List<Node> args = new ArrayList<>(); 3.1071 if (rhs instanceof IdentNode && !rhs.getSymbol().isParam() && !rhs.getSymbol().isVar()) { 3.1072 - args.add(getCurrentFunctionNode().getScopeNode()); 3.1073 + args.add(compilerConstant(SCOPE)); 3.1074 args.add(LiteralNode.newInstance(rhs, ((IdentNode)rhs).getName()).accept(this)); //null 3.1075 } else { 3.1076 args.add(rhs); 3.1077 args.add(LiteralNode.newInstance(unaryNode).accept(this)); //null, do not reuse token of identifier rhs, it can be e.g. 'this' 3.1078 } 3.1079 3.1080 - runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); 3.1081 + RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.TYPEOF, args); 3.1082 assert runtimeNode.getSymbol() == unaryNode.getSymbol(); 3.1083 3.1084 runtimeNode = (RuntimeNode)leaveRuntimeNode(runtimeNode); 3.1085 @@ -872,21 +909,20 @@ 3.1086 3.1087 @Override 3.1088 public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 3.1089 - newTemporary(runtimeNode.getRequest().getReturnType(), runtimeNode); 3.1090 + ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode); 3.1091 return runtimeNode; 3.1092 } 3.1093 3.1094 @Override 3.1095 public Node leaveSUB(final UnaryNode unaryNode) { 3.1096 - newTemporary(arithType(), unaryNode); 3.1097 + ensureSymbol(arithType(), unaryNode); 3.1098 end(unaryNode); 3.1099 return unaryNode; 3.1100 } 3.1101 3.1102 @Override 3.1103 public Node leaveVOID(final UnaryNode unaryNode) { 3.1104 - final RuntimeNode runtimeNode = new RuntimeNode(unaryNode, Request.VOID); 3.1105 - runtimeNode.accept(this); 3.1106 + final RuntimeNode runtimeNode = (RuntimeNode)new RuntimeNode(unaryNode, Request.VOID).accept(this); 3.1107 assert runtimeNode.getSymbol().getSymbolType().isObject(); 3.1108 end(unaryNode); 3.1109 return runtimeNode; 3.1110 @@ -903,7 +939,7 @@ 3.1111 3.1112 ensureTypeNotUnknown(lhs); 3.1113 ensureTypeNotUnknown(rhs); 3.1114 - newTemporary(Type.widest(lhs.getType(), rhs.getType()), binaryNode); 3.1115 + ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode); 3.1116 3.1117 end(binaryNode); 3.1118 3.1119 @@ -912,7 +948,7 @@ 3.1120 3.1121 @Override 3.1122 public Node leaveAND(final BinaryNode binaryNode) { 3.1123 - newTemporary(Type.OBJECT, binaryNode); 3.1124 + ensureSymbol(Type.OBJECT, binaryNode); 3.1125 end(binaryNode); 3.1126 return binaryNode; 3.1127 } 3.1128 @@ -921,39 +957,40 @@ 3.1129 * This is a helper called before an assignment. 3.1130 * @param binaryNode assignment node 3.1131 */ 3.1132 - private Node enterAssignmentNode(final BinaryNode binaryNode) { 3.1133 + private boolean enterAssignmentNode(final BinaryNode binaryNode) { 3.1134 start(binaryNode); 3.1135 3.1136 final Node lhs = binaryNode.lhs(); 3.1137 3.1138 if (lhs instanceof IdentNode) { 3.1139 - final Block block = getCurrentBlock(); 3.1140 - final IdentNode ident = (IdentNode)lhs; 3.1141 - final String name = ident.getName(); 3.1142 + final LexicalContext lc = getLexicalContext(); 3.1143 + final Block block = lc.getCurrentBlock(); 3.1144 + final IdentNode ident = (IdentNode)lhs; 3.1145 + final String name = ident.getName(); 3.1146 3.1147 - Symbol symbol = findSymbol(getCurrentBlock(), name); 3.1148 + Symbol symbol = findSymbol(block, name); 3.1149 3.1150 if (symbol == null) { 3.1151 symbol = defineSymbol(block, name, IS_GLOBAL, ident); 3.1152 binaryNode.setSymbol(symbol); 3.1153 - } else if (!isLocal(getCurrentFunctionNode(), symbol)) { 3.1154 - symbol.setIsScope(); 3.1155 + } else if (!isLocal(lc.getCurrentFunction(), symbol)) { 3.1156 + Symbol.setSymbolIsScope(lc, symbol); 3.1157 } 3.1158 3.1159 addLocalDef(name); 3.1160 } 3.1161 3.1162 - return binaryNode; 3.1163 + return true; 3.1164 } 3.1165 3.1166 private boolean isLocal(FunctionNode function, Symbol symbol) { 3.1167 - final Block block = symbol.getBlock(); 3.1168 - // some temp symbols have no block, so can be assumed local 3.1169 - return block == null || lexicalContext.getFunction(block) == function; 3.1170 + final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol); 3.1171 + // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local 3.1172 + return definingFn == null || definingFn == function; 3.1173 } 3.1174 3.1175 @Override 3.1176 - public Node enterASSIGN(final BinaryNode binaryNode) { 3.1177 + public boolean enterASSIGN(final BinaryNode binaryNode) { 3.1178 return enterAssignmentNode(binaryNode); 3.1179 } 3.1180 3.1181 @@ -963,7 +1000,7 @@ 3.1182 } 3.1183 3.1184 @Override 3.1185 - public Node enterASSIGN_ADD(final BinaryNode binaryNode) { 3.1186 + public boolean enterASSIGN_ADD(final BinaryNode binaryNode) { 3.1187 return enterAssignmentNode(binaryNode); 3.1188 } 3.1189 3.1190 @@ -978,7 +1015,7 @@ 3.1191 } 3.1192 3.1193 @Override 3.1194 - public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 3.1195 + public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 3.1196 return enterAssignmentNode(binaryNode); 3.1197 } 3.1198 3.1199 @@ -988,7 +1025,7 @@ 3.1200 } 3.1201 3.1202 @Override 3.1203 - public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 3.1204 + public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 3.1205 return enterAssignmentNode(binaryNode); 3.1206 } 3.1207 3.1208 @@ -998,7 +1035,7 @@ 3.1209 } 3.1210 3.1211 @Override 3.1212 - public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 3.1213 + public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 3.1214 return enterAssignmentNode(binaryNode); 3.1215 } 3.1216 3.1217 @@ -1008,7 +1045,7 @@ 3.1218 } 3.1219 3.1220 @Override 3.1221 - public Node enterASSIGN_DIV(final BinaryNode binaryNode) { 3.1222 + public boolean enterASSIGN_DIV(final BinaryNode binaryNode) { 3.1223 return enterAssignmentNode(binaryNode); 3.1224 } 3.1225 3.1226 @@ -1018,7 +1055,7 @@ 3.1227 } 3.1228 3.1229 @Override 3.1230 - public Node enterASSIGN_MOD(final BinaryNode binaryNode) { 3.1231 + public boolean enterASSIGN_MOD(final BinaryNode binaryNode) { 3.1232 return enterAssignmentNode(binaryNode); 3.1233 } 3.1234 3.1235 @@ -1028,7 +1065,7 @@ 3.1236 } 3.1237 3.1238 @Override 3.1239 - public Node enterASSIGN_MUL(final BinaryNode binaryNode) { 3.1240 + public boolean enterASSIGN_MUL(final BinaryNode binaryNode) { 3.1241 return enterAssignmentNode(binaryNode); 3.1242 } 3.1243 3.1244 @@ -1038,7 +1075,7 @@ 3.1245 } 3.1246 3.1247 @Override 3.1248 - public Node enterASSIGN_SAR(final BinaryNode binaryNode) { 3.1249 + public boolean enterASSIGN_SAR(final BinaryNode binaryNode) { 3.1250 return enterAssignmentNode(binaryNode); 3.1251 } 3.1252 3.1253 @@ -1048,7 +1085,7 @@ 3.1254 } 3.1255 3.1256 @Override 3.1257 - public Node enterASSIGN_SHL(final BinaryNode binaryNode) { 3.1258 + public boolean enterASSIGN_SHL(final BinaryNode binaryNode) { 3.1259 return enterAssignmentNode(binaryNode); 3.1260 } 3.1261 3.1262 @@ -1058,7 +1095,7 @@ 3.1263 } 3.1264 3.1265 @Override 3.1266 - public Node enterASSIGN_SHR(final BinaryNode binaryNode) { 3.1267 + public boolean enterASSIGN_SHR(final BinaryNode binaryNode) { 3.1268 return enterAssignmentNode(binaryNode); 3.1269 } 3.1270 3.1271 @@ -1068,7 +1105,7 @@ 3.1272 } 3.1273 3.1274 @Override 3.1275 - public Node enterASSIGN_SUB(final BinaryNode binaryNode) { 3.1276 + public boolean enterASSIGN_SUB(final BinaryNode binaryNode) { 3.1277 return enterAssignmentNode(binaryNode); 3.1278 } 3.1279 3.1280 @@ -1094,13 +1131,13 @@ 3.1281 3.1282 @Override 3.1283 public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { 3.1284 - newTemporary(binaryNode.rhs().getType(), binaryNode); 3.1285 + ensureSymbol(binaryNode.rhs().getType(), binaryNode); 3.1286 return binaryNode; 3.1287 } 3.1288 3.1289 @Override 3.1290 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 3.1291 - newTemporary(binaryNode.lhs().getType(), binaryNode); 3.1292 + ensureSymbol(binaryNode.lhs().getType(), binaryNode); 3.1293 return binaryNode; 3.1294 } 3.1295 3.1296 @@ -1113,7 +1150,7 @@ 3.1297 final Node lhs = binaryNode.lhs(); 3.1298 final Node rhs = binaryNode.rhs(); 3.1299 3.1300 - newTemporary(Type.BOOLEAN, binaryNode); 3.1301 + ensureSymbol(Type.BOOLEAN, binaryNode); 3.1302 ensureTypeNotUnknown(lhs); 3.1303 ensureTypeNotUnknown(rhs); 3.1304 3.1305 @@ -1131,7 +1168,7 @@ 3.1306 3.1307 //newType(binaryNode.lhs().getSymbol(), operandType); 3.1308 //newType(binaryNode.rhs().getSymbol(), operandType); 3.1309 - newTemporary(destType, binaryNode); 3.1310 + ensureSymbol(destType, binaryNode); 3.1311 return binaryNode; 3.1312 } 3.1313 3.1314 @@ -1216,7 +1253,7 @@ 3.1315 3.1316 @Override 3.1317 public Node leaveOR(final BinaryNode binaryNode) { 3.1318 - newTemporary(Type.OBJECT, binaryNode); 3.1319 + ensureSymbol(Type.OBJECT, binaryNode); 3.1320 end(binaryNode); 3.1321 return binaryNode; 3.1322 } 3.1323 @@ -1244,7 +1281,7 @@ 3.1324 @Override 3.1325 public Node leaveForNode(final ForNode forNode) { 3.1326 if (forNode.isForIn()) { 3.1327 - forNode.setIterator(newInternal(getCurrentFunctionNode().uniqueName(ITERATOR_PREFIX.tag()), Type.OBJECT)); //NASHORN-73 3.1328 + forNode.setIterator(newInternal(getLexicalContext().getCurrentFunction().uniqueName(ITERATOR_PREFIX.symbolName()), Type.OBJECT)); //NASHORN-73 3.1329 /* 3.1330 * Iterators return objects, so we need to widen the scope of the 3.1331 * init variable if it, for example, has been assigned double type 3.1332 @@ -1267,65 +1304,50 @@ 3.1333 ensureTypeNotUnknown(rhs); 3.1334 3.1335 final Type type = Type.widest(lhs.getType(), rhs.getType()); 3.1336 - newTemporary(type, ternaryNode); 3.1337 + ensureSymbol(type, ternaryNode); 3.1338 3.1339 end(ternaryNode); 3.1340 + assert ternaryNode.getSymbol() != null; 3.1341 3.1342 return ternaryNode; 3.1343 } 3.1344 3.1345 - private void initThis(final FunctionNode functionNode) { 3.1346 - final Symbol thisSymbol = defineSymbol(functionNode, THIS.tag(), IS_PARAM | IS_THIS, null); 3.1347 + private void initThis(final Block block) { 3.1348 + final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null); 3.1349 newType(thisSymbol, Type.OBJECT); 3.1350 thisSymbol.setNeedsSlot(true); 3.1351 - functionNode.getThisNode().setSymbol(thisSymbol); 3.1352 - LOG.info("Initialized scope symbol: " + thisSymbol); 3.1353 } 3.1354 3.1355 - private void initScope(final FunctionNode functionNode) { 3.1356 - final Symbol scopeSymbol = defineSymbol(functionNode, SCOPE.tag(), IS_VAR | IS_INTERNAL, null); 3.1357 + private void initScope(final Block block) { 3.1358 + final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null); 3.1359 newType(scopeSymbol, Type.typeFor(ScriptObject.class)); 3.1360 scopeSymbol.setNeedsSlot(true); 3.1361 - functionNode.getScopeNode().setSymbol(scopeSymbol); 3.1362 - LOG.info("Initialized scope symbol: " + scopeSymbol); 3.1363 } 3.1364 3.1365 - private void initReturn(final FunctionNode functionNode) { 3.1366 - final Symbol returnSymbol = defineSymbol(functionNode, SCRIPT_RETURN.tag(), IS_VAR | IS_INTERNAL, null); 3.1367 + private void initReturn(final Block block) { 3.1368 + final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null); 3.1369 newType(returnSymbol, Type.OBJECT); 3.1370 returnSymbol.setNeedsSlot(true); 3.1371 - functionNode.getResultNode().setSymbol(returnSymbol); 3.1372 - LOG.info("Initialized return symbol: " + returnSymbol); 3.1373 //return symbol is always object as it's the __return__ thing. What returnType is is another matter though 3.1374 } 3.1375 3.1376 - private void initVarArg(final FunctionNode functionNode) { 3.1377 - if (functionNode.isVarArg()) { 3.1378 - final Symbol varArgsSymbol = defineSymbol(functionNode, VARARGS.tag(), IS_PARAM | IS_INTERNAL, null); 3.1379 - varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); 3.1380 - varArgsSymbol.setNeedsSlot(true); 3.1381 - functionNode.getVarArgsNode().setSymbol(varArgsSymbol); 3.1382 - LOG.info("Initialized varargs symbol: " + varArgsSymbol); 3.1383 + private void initVarArg(final Block block, final boolean needsArguments) { 3.1384 + final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null); 3.1385 + varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); 3.1386 + varArgsSymbol.setNeedsSlot(true); 3.1387 3.1388 - if (functionNode.needsArguments()) { 3.1389 - final String argumentsName = functionNode.getArgumentsNode().getName(); 3.1390 - final Symbol argumentsSymbol = defineSymbol(functionNode, argumentsName, IS_VAR | IS_INTERNAL, null); 3.1391 - newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); 3.1392 - argumentsSymbol.setNeedsSlot(true); 3.1393 - functionNode.getArgumentsNode().setSymbol(argumentsSymbol); 3.1394 - addLocalDef(argumentsName); 3.1395 - LOG.info("Initialized vararg varArgsSymbol=" + varArgsSymbol + " argumentsSymbol=" + argumentsSymbol); 3.1396 - } 3.1397 + if (needsArguments) { 3.1398 + final Symbol argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null); 3.1399 + newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); 3.1400 + argumentsSymbol.setNeedsSlot(true); 3.1401 + addLocalDef(ARGUMENTS.symbolName()); 3.1402 } 3.1403 } 3.1404 3.1405 - private void initCallee(final FunctionNode functionNode) { 3.1406 - assert functionNode.getCalleeNode() != null : functionNode + " has no callee"; 3.1407 - final Symbol calleeSymbol = defineSymbol(functionNode, CALLEE.tag(), IS_PARAM | IS_INTERNAL, null); 3.1408 - newType(calleeSymbol, Type.typeFor(ScriptFunction.class)); 3.1409 + private void initCallee(final Block block) { 3.1410 + final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null); 3.1411 + newType(calleeSymbol, FunctionNode.FUNCTION_TYPE); 3.1412 calleeSymbol.setNeedsSlot(true); 3.1413 - functionNode.getCalleeNode().setSymbol(calleeSymbol); 3.1414 - LOG.info("Initialized callee symbol " + calleeSymbol); 3.1415 } 3.1416 3.1417 /** 3.1418 @@ -1334,25 +1356,19 @@ 3.1419 * 3.1420 * @param functionNode the function node 3.1421 */ 3.1422 - private void initParameters(final FunctionNode functionNode) { 3.1423 - //If a function is specialized, we don't need to tag either it return 3.1424 - // type or its parameters with the widest (OBJECT) type for safety. 3.1425 - functionNode.setReturnType(Type.UNKNOWN); 3.1426 - 3.1427 + private void initParameters(final FunctionNode functionNode, final Block body) { 3.1428 for (final IdentNode param : functionNode.getParameters()) { 3.1429 addLocalDef(param.getName()); 3.1430 - final Symbol paramSymbol = defineSymbol(functionNode, param.getName(), IS_PARAM, param); 3.1431 + final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param); 3.1432 if (paramSymbol != null) { 3.1433 final Type callSiteParamType = functionNode.getSpecializedType(param); 3.1434 if (callSiteParamType != null) { 3.1435 - LOG.info("Param " + paramSymbol + " has a callsite type " + callSiteParamType + ". Using that."); 3.1436 - 3.1437 - System.err.println("Param " + param + " has a callsite type " + callSiteParamType + ". Using that."); 3.1438 + LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that."); 3.1439 } 3.1440 newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); 3.1441 } 3.1442 3.1443 - LOG.info("Initialized param " + paramSymbol); 3.1444 + LOG.info("Initialized param ", paramSymbol); 3.1445 } 3.1446 } 3.1447 3.1448 @@ -1378,7 +1394,7 @@ 3.1449 // this function, we can tell the runtime system that no matter what the 3.1450 // call site is, use this information. TODO 3.1451 if (!paramSymbol.getSymbolType().isObject()) { 3.1452 - LOG.finest("Parameter " + ident + " could profit from specialization to " + paramSymbol.getSymbolType()); 3.1453 + LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType()); 3.1454 } 3.1455 3.1456 newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); 3.1457 @@ -1392,19 +1408,18 @@ 3.1458 3.1459 /** 3.1460 * Move any properties from a global map into the scope of this method 3.1461 - * @param functionNode the function node for which to init scope vars 3.1462 + * @param block the function node body for which to init scope vars 3.1463 */ 3.1464 - private void initFromPropertyMap(final FunctionNode functionNode) { 3.1465 + private void initFromPropertyMap(final Block block) { 3.1466 // For a script, add scope symbols as defined in the property map 3.1467 - assert functionNode.isProgram(); 3.1468 3.1469 final PropertyMap map = Context.getGlobalMap(); 3.1470 3.1471 for (final Property property : map.getProperties()) { 3.1472 final String key = property.getKey(); 3.1473 - final Symbol symbol = defineSymbol(functionNode, key, IS_GLOBAL, null); 3.1474 + final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null); 3.1475 newType(symbol, Type.OBJECT); 3.1476 - LOG.info("Added global symbol from property map " + symbol); 3.1477 + LOG.info("Added global symbol from property map ", symbol); 3.1478 } 3.1479 } 3.1480 3.1481 @@ -1412,7 +1427,7 @@ 3.1482 3.1483 final Symbol symbol = node.getSymbol(); 3.1484 3.1485 - LOG.info("Ensure type not unknown for: " + symbol); 3.1486 + LOG.info("Ensure type not unknown for: ", symbol); 3.1487 3.1488 /* 3.1489 * Note that not just unknowns, but params need to be blown 3.1490 @@ -1452,7 +1467,7 @@ 3.1491 } 3.1492 3.1493 private Symbol exceptionSymbol() { 3.1494 - return newInternal(getCurrentFunctionNode().uniqueName(EXCEPTION_PREFIX.tag()), Type.typeFor(ECMAException.class)); 3.1495 + return newInternal(getLexicalContext().getCurrentFunction().uniqueName(EXCEPTION_PREFIX.symbolName()), Type.typeFor(ECMAException.class)); 3.1496 } 3.1497 3.1498 /** 3.1499 @@ -1512,15 +1527,15 @@ 3.1500 } 3.1501 Type from = node.getType(); 3.1502 if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { 3.1503 - LOG.fine("Had to post pass widen '" + node + "' " + Debug.id(node) + " from " + node.getType() + " to " + to); 3.1504 + LOG.fine("Had to post pass widen '", node, "' " + Debug.id(node), " from ", node.getType(), " to ", to); 3.1505 newType(node.getSymbol(), to); 3.1506 changed.add(node); 3.1507 } 3.1508 } 3.1509 3.1510 @Override 3.1511 - public Node enterFunctionNode(final FunctionNode node) { 3.1512 - return node.isLazy() ? null : node; 3.1513 + public boolean enterFunctionNode(final FunctionNode node) { 3.1514 + return !node.isLazy(); 3.1515 } 3.1516 3.1517 /** 3.1518 @@ -1574,7 +1589,7 @@ 3.1519 } else { 3.1520 type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. 3.1521 } 3.1522 - newTemporary(type, binaryNode); 3.1523 + ensureSymbol(type, binaryNode); 3.1524 newType(lhs.getSymbol(), type); 3.1525 end(binaryNode); 3.1526 return binaryNode; 3.1527 @@ -1589,32 +1604,25 @@ 3.1528 final Node lhs = binaryNode.lhs(); 3.1529 3.1530 newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType 3.1531 - newTemporary(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 3.1532 + ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 3.1533 3.1534 - ensureAssignmentSlots(getCurrentFunctionNode(), binaryNode); 3.1535 + ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode); 3.1536 3.1537 end(binaryNode); 3.1538 return binaryNode; 3.1539 } 3.1540 3.1541 - private static boolean isFunctionExpressionSelfReference(final Symbol symbol) { 3.1542 - if (symbol.isVar() && symbol.getNode() == symbol.getBlock() && symbol.getNode() instanceof FunctionNode) { 3.1543 - return ((FunctionNode)symbol.getNode()).getIdent().getName().equals(symbol.getName()); 3.1544 - } 3.1545 - return false; 3.1546 + private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) { 3.1547 + LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type); 3.1548 + return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node); 3.1549 } 3.1550 3.1551 - private static Symbol newTemporary(final FunctionNode functionNode, final Type type, final Node node) { 3.1552 - LOG.info("New TEMPORARY added to " + functionNode.getName() + " type=" + type); 3.1553 - return functionNode.newTemporary(type, node); 3.1554 - } 3.1555 - 3.1556 - private Symbol newTemporary(final Type type, final Node node) { 3.1557 - return newTemporary(getCurrentFunctionNode(), type, node); 3.1558 + private Symbol ensureSymbol(final Type type, final Node node) { 3.1559 + return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node); 3.1560 } 3.1561 3.1562 private Symbol newInternal(final String name, final Type type) { 3.1563 - final Symbol iter = defineSymbol(getCurrentFunctionNode(), name, IS_VAR | IS_INTERNAL, null); 3.1564 + final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null); 3.1565 iter.setType(type); // NASHORN-73 3.1566 return iter; 3.1567 } 3.1568 @@ -1624,40 +1632,51 @@ 3.1569 symbol.setType(type); 3.1570 3.1571 if (symbol.getSymbolType() != oldType) { 3.1572 - LOG.info("New TYPE " + type + " for " + symbol + " (was " + oldType + ")"); 3.1573 + LOG.info("New TYPE ", type, " for ", symbol," (was ", oldType, ")"); 3.1574 } 3.1575 3.1576 if (symbol.isParam()) { 3.1577 symbol.setType(type); 3.1578 - LOG.info("Param type change " + symbol); 3.1579 + LOG.info("Param type change ", symbol); 3.1580 } 3.1581 } 3.1582 3.1583 - private void clearLocalDefs() { 3.1584 - localDefs = new HashSet<>(); 3.1585 + private void pushLocalsFunction() { 3.1586 + localDefs.push(new HashSet<String>()); 3.1587 + localUses.push(new HashSet<String>()); 3.1588 + } 3.1589 + 3.1590 + private void pushLocalsBlock() { 3.1591 + localDefs.push(localDefs.isEmpty() ? new HashSet<String>() : new HashSet<>(localDefs.peek())); 3.1592 + localUses.push(localUses.isEmpty() ? new HashSet<String>() : new HashSet<>(localUses.peek())); 3.1593 + } 3.1594 + 3.1595 + private void popLocals() { 3.1596 + localDefs.pop(); 3.1597 + localUses.pop(); 3.1598 } 3.1599 3.1600 private boolean isLocalDef(final String name) { 3.1601 - return localDefs.contains(name); 3.1602 + return localDefs.peek().contains(name); 3.1603 } 3.1604 3.1605 private void addLocalDef(final String name) { 3.1606 - LOG.info("Adding local def of symbol: '" + name + "'"); 3.1607 - localDefs.add(name); 3.1608 + LOG.info("Adding local def of symbol: '", name, "'"); 3.1609 + localDefs.peek().add(name); 3.1610 } 3.1611 3.1612 private void removeLocalDef(final String name) { 3.1613 - LOG.info("Removing local def of symbol: '" + name + "'"); 3.1614 - localDefs.remove(name); 3.1615 + LOG.info("Removing local def of symbol: '", name, "'"); 3.1616 + localDefs.peek().remove(name); 3.1617 } 3.1618 3.1619 - private void clearLocalUses() { 3.1620 - localUses = new HashSet<>(); 3.1621 + private boolean isLocalUse(final String name) { 3.1622 + return localUses.peek().contains(name); 3.1623 } 3.1624 3.1625 private void addLocalUse(final String name) { 3.1626 - LOG.info("Adding local use of symbol: '" + name + "'"); 3.1627 - localUses.add(name); 3.1628 + LOG.info("Adding local use of symbol: '", name, "'"); 3.1629 + localUses.peek().add(name); 3.1630 } 3.1631 3.1632 /** 3.1633 @@ -1665,30 +1684,28 @@ 3.1634 * This is done when the function contains unevaluated black boxes such as 3.1635 * lazy sub-function nodes that have not been compiled. 3.1636 * 3.1637 - * @param functionNode function node in whose scope symbols should conservatively be made objects 3.1638 + * @param body body for the function node we are leaving 3.1639 */ 3.1640 - private static void objectifySymbols(final FunctionNode functionNode) { 3.1641 - functionNode.accept(new NodeVisitor() { 3.1642 + private static void objectifySymbols(final Block body) { 3.1643 + body.accept(new NodeVisitor() { 3.1644 private void toObject(final Block block) { 3.1645 for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) { 3.1646 final Symbol symbol = iter.next(); 3.1647 - newType(symbol, Type.OBJECT); 3.1648 + if (!symbol.isTemp()) { 3.1649 + newType(symbol, Type.OBJECT); 3.1650 + } 3.1651 } 3.1652 } 3.1653 3.1654 @Override 3.1655 - public Node enterBlock(final Block block) { 3.1656 + public boolean enterBlock(final Block block) { 3.1657 toObject(block); 3.1658 - return block; 3.1659 + return true; 3.1660 } 3.1661 3.1662 @Override 3.1663 - public Node enterFunctionNode(final FunctionNode node) { 3.1664 - toObject(node); 3.1665 - if (node.isLazy()) { 3.1666 - return null; 3.1667 - } 3.1668 - return node; 3.1669 + public boolean enterFunctionNode(final FunctionNode node) { 3.1670 + return false; 3.1671 } 3.1672 }); 3.1673 } 3.1674 @@ -1702,11 +1719,11 @@ 3.1675 return cn.substring(lastDot + 1); 3.1676 } 3.1677 3.1678 - private Node start(final Node node) { 3.1679 + private boolean start(final Node node) { 3.1680 return start(node, true); 3.1681 } 3.1682 3.1683 - private Node start(final Node node, final boolean printNode) { 3.1684 + private boolean start(final Node node, final boolean printNode) { 3.1685 if (DEBUG) { 3.1686 final StringBuilder sb = new StringBuilder(); 3.1687 3.1688 @@ -1715,13 +1732,13 @@ 3.1689 append("] "). 3.1690 append(printNode ? node.toString() : ""). 3.1691 append(" in '"). 3.1692 - append(getCurrentFunctionNode().getName()). 3.1693 + append(getLexicalContext().getCurrentFunction().getName()). 3.1694 append("'"); 3.1695 - LOG.info(sb.toString()); 3.1696 + LOG.info(sb); 3.1697 LOG.indent(); 3.1698 } 3.1699 3.1700 - return node; 3.1701 + return true; 3.1702 } 3.1703 3.1704 private Node end(final Node node) { 3.1705 @@ -1737,7 +1754,7 @@ 3.1706 append("] "). 3.1707 append(printNode ? node.toString() : ""). 3.1708 append(" in '"). 3.1709 - append(getCurrentFunctionNode().getName()); 3.1710 + append(getLexicalContext().getCurrentFunction().getName()); 3.1711 3.1712 if (node.getSymbol() == null) { 3.1713 sb.append(" <NO SYMBOL>"); 3.1714 @@ -1746,7 +1763,7 @@ 3.1715 } 3.1716 3.1717 LOG.unindent(); 3.1718 - LOG.info(sb.toString()); 3.1719 + LOG.info(sb); 3.1720 } 3.1721 3.1722 return node;
4.1 --- a/src/jdk/nashorn/internal/codegen/ClassEmitter.java Fri Apr 19 18:23:00 2013 +0530 4.2 +++ b/src/jdk/nashorn/internal/codegen/ClassEmitter.java Fri Apr 19 16:11:16 2013 +0200 4.3 @@ -58,12 +58,14 @@ 4.4 import java.util.EnumSet; 4.5 import java.util.HashSet; 4.6 import java.util.Set; 4.7 + 4.8 import jdk.internal.org.objectweb.asm.ClassReader; 4.9 import jdk.internal.org.objectweb.asm.ClassWriter; 4.10 import jdk.internal.org.objectweb.asm.MethodVisitor; 4.11 import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; 4.12 import jdk.nashorn.internal.codegen.types.Type; 4.13 import jdk.nashorn.internal.ir.FunctionNode; 4.14 +import jdk.nashorn.internal.ir.SplitNode; 4.15 import jdk.nashorn.internal.runtime.PropertyMap; 4.16 import jdk.nashorn.internal.runtime.ScriptEnvironment; 4.17 import jdk.nashorn.internal.runtime.ScriptObject; 4.18 @@ -219,14 +221,14 @@ 4.19 private void defineCommonStatics(final boolean strictMode) { 4.20 // source - used to store the source data (text) for this script. Shared across 4.21 // compile units. Set externally by the compiler. 4.22 - field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.tag(), Source.class); 4.23 + field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), SOURCE.symbolName(), Source.class); 4.24 4.25 // constants - used to the constants array for this script. Shared across 4.26 // compile units. Set externally by the compiler. 4.27 - field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.tag(), Object[].class); 4.28 + field(EnumSet.of(Flag.PRIVATE, Flag.STATIC), CONSTANTS.symbolName(), Object[].class); 4.29 4.30 // strictMode - was this script compiled in strict mode. Set externally by the compiler. 4.31 - field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.tag(), boolean.class, strictMode); 4.32 + field(EnumSet.of(Flag.PUBLIC, Flag.STATIC, Flag.FINAL), STRICT_MODE.symbolName(), boolean.class, strictMode); 4.33 } 4.34 4.35 /** 4.36 @@ -238,9 +240,9 @@ 4.37 4.38 if (constantMethodNeeded.contains(String.class)) { 4.39 // $getString - get the ith entry from the constants table and cast to String. 4.40 - final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.tag(), String.class, int.class); 4.41 + final MethodEmitter getStringMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), GET_STRING.symbolName(), String.class, int.class); 4.42 getStringMethod.begin(); 4.43 - getStringMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) 4.44 + getStringMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) 4.45 .load(Type.INT, 0) 4.46 .arrayload() 4.47 .checkcast(String.class) 4.48 @@ -250,7 +252,7 @@ 4.49 4.50 if (constantMethodNeeded.contains(PropertyMap.class)) { 4.51 // $getMap - get the ith entry from the constants table and cast to PropertyMap. 4.52 - final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.tag(), PropertyMap.class, int.class); 4.53 + final MethodEmitter getMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), GET_MAP.symbolName(), PropertyMap.class, int.class); 4.54 getMapMethod.begin(); 4.55 getMapMethod.loadConstants() 4.56 .load(Type.INT, 0) 4.57 @@ -260,7 +262,7 @@ 4.58 getMapMethod.end(); 4.59 4.60 // $setMap - overwrite an existing map. 4.61 - final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.tag(), void.class, int.class, PropertyMap.class); 4.62 + final MethodEmitter setMapMethod = method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), SET_MAP.symbolName(), void.class, int.class, PropertyMap.class); 4.63 setMapMethod.begin(); 4.64 setMapMethod.loadConstants() 4.65 .load(Type.INT, 0) 4.66 @@ -289,7 +291,7 @@ 4.67 final MethodEmitter getArrayMethod = method(EnumSet.of(Flag.PRIVATE, Flag.STATIC), methodName, cls, int.class); 4.68 4.69 getArrayMethod.begin(); 4.70 - getArrayMethod.getStatic(unitClassName, CONSTANTS.tag(), CONSTANTS.descriptor()) 4.71 + getArrayMethod.getStatic(unitClassName, CONSTANTS.symbolName(), CONSTANTS.descriptor()) 4.72 .load(Type.INT, 0) 4.73 .arrayload() 4.74 .checkcast(cls) 4.75 @@ -307,7 +309,7 @@ 4.76 */ 4.77 static String getArrayMethodName(final Class<?> cls) { 4.78 assert cls.isArray(); 4.79 - return GET_ARRAY_PREFIX.tag() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.tag(); 4.80 + return GET_ARRAY_PREFIX.symbolName() + cls.getComponentType().getSimpleName() + GET_ARRAY_SUFFIX.symbolName(); 4.81 } 4.82 4.83 /** 4.84 @@ -409,6 +411,10 @@ 4.85 methodsStarted.remove(method); 4.86 } 4.87 4.88 + SplitMethodEmitter method(final SplitNode splitNode, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 4.89 + return new SplitMethodEmitter(this, methodVisitor(EnumSet.of(Flag.PUBLIC, Flag.STATIC), methodName, rtype, ptypes), splitNode); 4.90 + } 4.91 + 4.92 /** 4.93 * Add a new method to the class - defaults to public method 4.94 * 4.95 @@ -433,7 +439,7 @@ 4.96 * @return method emitter to use for weaving this method 4.97 */ 4.98 MethodEmitter method(final EnumSet<Flag> methodFlags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 4.99 - return new MethodEmitter(this, cw.visitMethod(Flag.getValue(methodFlags), methodName, methodDescriptor(rtype, ptypes), null, null)); 4.100 + return new MethodEmitter(this, methodVisitor(methodFlags, methodName, rtype, ptypes)); 4.101 } 4.102 4.103 /** 4.104 @@ -484,7 +490,7 @@ 4.105 * @return method emitter to use for weaving <clinit> 4.106 */ 4.107 MethodEmitter clinit() { 4.108 - return method(EnumSet.of(Flag.STATIC), CLINIT.tag(), void.class); 4.109 + return method(EnumSet.of(Flag.STATIC), CLINIT.symbolName(), void.class); 4.110 } 4.111 4.112 /** 4.113 @@ -493,7 +499,7 @@ 4.114 * @return method emitter to use for weaving <init>()V 4.115 */ 4.116 MethodEmitter init() { 4.117 - return method(INIT.tag(), void.class); 4.118 + return method(INIT.symbolName(), void.class); 4.119 } 4.120 4.121 /** 4.122 @@ -503,7 +509,7 @@ 4.123 * @return method emitter to use for weaving <init>()V 4.124 */ 4.125 MethodEmitter init(final Class<?>... ptypes) { 4.126 - return method(INIT.tag(), void.class, ptypes); 4.127 + return method(INIT.symbolName(), void.class, ptypes); 4.128 } 4.129 4.130 /** 4.131 @@ -515,7 +521,7 @@ 4.132 * @return method emitter to use for weaving <init>(...)V 4.133 */ 4.134 MethodEmitter init(final EnumSet<Flag> flags, final Class<?>... ptypes) { 4.135 - return method(flags, INIT.tag(), void.class, ptypes); 4.136 + return method(flags, INIT.symbolName(), void.class, ptypes); 4.137 } 4.138 4.139 /** 4.140 @@ -628,4 +634,9 @@ 4.141 return v; 4.142 } 4.143 } 4.144 + 4.145 + private MethodVisitor methodVisitor(EnumSet<Flag> flags, final String methodName, final Class<?> rtype, final Class<?>... ptypes) { 4.146 + return cw.visitMethod(Flag.getValue(flags), methodName, methodDescriptor(rtype, ptypes), null, null); 4.147 + } 4.148 + 4.149 }
5.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Apr 19 18:23:00 2013 +0530 5.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Apr 19 16:11:16 2013 +0200 5.3 @@ -27,14 +27,18 @@ 5.4 5.5 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.PRIVATE; 5.6 import static jdk.nashorn.internal.codegen.ClassEmitter.Flag.STATIC; 5.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 5.8 +import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 5.9 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_MAP; 5.10 import static jdk.nashorn.internal.codegen.CompilerConstants.GET_STRING; 5.11 -import static jdk.nashorn.internal.codegen.CompilerConstants.LEAF; 5.12 import static jdk.nashorn.internal.codegen.CompilerConstants.QUICK_PREFIX; 5.13 import static jdk.nashorn.internal.codegen.CompilerConstants.REGEX_PREFIX; 5.14 +import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 5.15 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 5.16 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_ARRAY_ARG; 5.17 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; 5.18 +import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 5.19 +import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 5.20 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; 5.21 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; 5.22 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; 5.23 @@ -48,8 +52,10 @@ 5.24 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT; 5.25 5.26 import java.io.PrintWriter; 5.27 +import java.util.ArrayDeque; 5.28 import java.util.ArrayList; 5.29 import java.util.Arrays; 5.30 +import java.util.Deque; 5.31 import java.util.EnumSet; 5.32 import java.util.HashMap; 5.33 import java.util.Iterator; 5.34 @@ -67,11 +73,11 @@ 5.35 import jdk.nashorn.internal.ir.BinaryNode; 5.36 import jdk.nashorn.internal.ir.Block; 5.37 import jdk.nashorn.internal.ir.BreakNode; 5.38 +import jdk.nashorn.internal.ir.BreakableNode; 5.39 import jdk.nashorn.internal.ir.CallNode; 5.40 import jdk.nashorn.internal.ir.CaseNode; 5.41 import jdk.nashorn.internal.ir.CatchNode; 5.42 import jdk.nashorn.internal.ir.ContinueNode; 5.43 -import jdk.nashorn.internal.ir.DoWhileNode; 5.44 import jdk.nashorn.internal.ir.EmptyNode; 5.45 import jdk.nashorn.internal.ir.ExecuteNode; 5.46 import jdk.nashorn.internal.ir.ForNode; 5.47 @@ -85,6 +91,7 @@ 5.48 import jdk.nashorn.internal.ir.LiteralNode; 5.49 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 5.50 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 5.51 +import jdk.nashorn.internal.ir.LoopNode; 5.52 import jdk.nashorn.internal.ir.Node; 5.53 import jdk.nashorn.internal.ir.ObjectNode; 5.54 import jdk.nashorn.internal.ir.PropertyNode; 5.55 @@ -107,6 +114,7 @@ 5.56 import jdk.nashorn.internal.parser.Lexer.RegexToken; 5.57 import jdk.nashorn.internal.parser.TokenType; 5.58 import jdk.nashorn.internal.runtime.Context; 5.59 +import jdk.nashorn.internal.runtime.Debug; 5.60 import jdk.nashorn.internal.runtime.DebugLogger; 5.61 import jdk.nashorn.internal.runtime.ECMAException; 5.62 import jdk.nashorn.internal.runtime.Property; 5.63 @@ -157,14 +165,29 @@ 5.64 /** How many regexp fields have been emitted */ 5.65 private int regexFieldCount; 5.66 5.67 - /** Used for temporary signaling between enterCallNode and enterFunctionNode to handle the special case of calling 5.68 - * a just-defined anonymous function expression. */ 5.69 - private boolean functionNodeIsCallee; 5.70 - 5.71 /** Map of shared scope call sites */ 5.72 private final Map<SharedScopeCall, SharedScopeCall> scopeCalls = new HashMap<>(); 5.73 5.74 - private final LexicalContext lexicalContext = new LexicalContext(); 5.75 + /** Compile unit stack - every time we start a sub method (e.g. a split) we push one */ 5.76 + private final Deque<CompileUnit> compileUnits = new ArrayDeque<>(); 5.77 + 5.78 + /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */ 5.79 + private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>(); 5.80 + 5.81 + /** The discard stack - whenever we enter a discard node we keep track of its return value status - 5.82 + * i.e. should we keep it or throw it away */ 5.83 + private final Deque<Node> discard = new ArrayDeque<>(); 5.84 + 5.85 + // A stack tracking the next free local variable slot in the blocks. There's one entry for every block 5.86 + // currently on the lexical context stack. 5.87 + private int[] nextFreeSlots = new int[16]; 5.88 + private int nextFreeSlotsSize = 0; 5.89 + 5.90 + /** Current method emitter */ 5.91 + private MethodEmitter method; 5.92 + 5.93 + /** Current compile unit */ 5.94 + private CompileUnit unit; 5.95 5.96 /** When should we stop caching regexp expressions in fields to limit bytecode size? */ 5.97 private static final int MAX_REGEX_FIELDS = 2 * 1024; 5.98 @@ -188,7 +211,37 @@ 5.99 * @return the correct flags for a call site in the current function 5.100 */ 5.101 int getCallSiteFlags() { 5.102 - return getCurrentFunctionNode().isStrictMode() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; 5.103 + return getLexicalContext().getCurrentFunction().isStrict() ? callSiteFlags | CALLSITE_STRICT : callSiteFlags; 5.104 + } 5.105 + 5.106 + private void pushMethodEmitter(final MethodEmitter newMethod) { 5.107 + methodEmitters.push(newMethod); 5.108 + this.method = newMethod; 5.109 + } 5.110 + 5.111 + private void popMethodEmitter(final MethodEmitter oldMethod) { 5.112 + assert methodEmitters.peek() == oldMethod; 5.113 + methodEmitters.pop(); 5.114 + if (!methodEmitters.isEmpty()) { 5.115 + this.method = methodEmitters.peek(); 5.116 + } else { 5.117 + this.method = null; 5.118 + } 5.119 + } 5.120 + 5.121 + private void push(final CompileUnit newUnit) { 5.122 + compileUnits.push(newUnit); 5.123 + this.unit = newUnit; 5.124 + } 5.125 + 5.126 + private void pop(final CompileUnit oldUnit) { 5.127 + assert compileUnits.peek() == oldUnit; 5.128 + compileUnits.pop(); 5.129 + if (!compileUnits.isEmpty()) { 5.130 + this.unit = compileUnits.peek(); 5.131 + } else { 5.132 + this.unit = null; 5.133 + } 5.134 } 5.135 5.136 /** 5.137 @@ -217,7 +270,7 @@ 5.138 assert identNode.getSymbol().isScope() : identNode + " is not in scope!"; 5.139 5.140 final int flags = CALLSITE_SCOPE | getCallSiteFlags(); 5.141 - method.loadScope(); 5.142 + method.loadCompilerConstant(SCOPE); 5.143 5.144 if (isFastScope(symbol)) { 5.145 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. 5.146 @@ -237,11 +290,11 @@ 5.147 * @return true if fast scope 5.148 */ 5.149 private boolean isFastScope(final Symbol symbol) { 5.150 - if (!symbol.isScope() || !symbol.getBlock().needsScope()) { 5.151 + if (!symbol.isScope() || !getLexicalContext().getDefiningBlock(symbol).needsScope()) { 5.152 return false; 5.153 } 5.154 // Allow fast scope access if no function contains with or eval 5.155 - for(final Iterator<FunctionNode> it = lexicalContext.getFunctions(getCurrentFunctionNode()); it.hasNext();) { 5.156 + for (final Iterator<FunctionNode> it = getLexicalContext().getFunctions(); it.hasNext();) { 5.157 final FunctionNode func = it.next(); 5.158 if (func.hasWith() || func.hasEval()) { 5.159 return false; 5.160 @@ -251,7 +304,7 @@ 5.161 } 5.162 5.163 private MethodEmitter loadSharedScopeVar(final Type valueType, final Symbol symbol, final int flags) { 5.164 - method.load(isFastScope(symbol) ? getScopeProtoDepth(getCurrentBlock(), symbol) : -1); 5.165 + method.load(isFastScope(symbol) ? getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol) : -1); 5.166 final SharedScopeCall scopeCall = getScopeGet(valueType, symbol, flags | CALLSITE_FAST_SCOPE); 5.167 scopeCall.generateInvoke(method); 5.168 return method; 5.169 @@ -271,10 +324,10 @@ 5.170 5.171 private int getScopeProtoDepth(final Block startingBlock, final Symbol symbol) { 5.172 int depth = 0; 5.173 - final Block definingBlock = symbol.getBlock(); 5.174 - for(final Iterator<Block> blocks = lexicalContext.getBlocks(startingBlock); blocks.hasNext();) { 5.175 + final String name = symbol.getName(); 5.176 + for(final Iterator<Block> blocks = getLexicalContext().getBlocks(startingBlock); blocks.hasNext();) { 5.177 final Block currentBlock = blocks.next(); 5.178 - if (currentBlock == definingBlock) { 5.179 + if (currentBlock.getExistingSymbol(name) == symbol) { 5.180 return depth; 5.181 } 5.182 if (currentBlock.needsScope()) { 5.183 @@ -285,9 +338,9 @@ 5.184 } 5.185 5.186 private void loadFastScopeProto(final Symbol symbol, final boolean swap) { 5.187 - final int depth = getScopeProtoDepth(getCurrentBlock(), symbol); 5.188 + final int depth = getScopeProtoDepth(getLexicalContext().getCurrentBlock(), symbol); 5.189 assert depth != -1; 5.190 - if(depth > 0) { 5.191 + if (depth > 0) { 5.192 if (swap) { 5.193 method.swap(); 5.194 } 5.195 @@ -328,46 +381,46 @@ 5.196 */ 5.197 final CodeGenerator codegen = this; 5.198 5.199 - node.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 5.200 + node.accept(new NodeVisitor() { 5.201 @Override 5.202 - public Node enterIdentNode(final IdentNode identNode) { 5.203 + public boolean enterIdentNode(final IdentNode identNode) { 5.204 loadIdent(identNode); 5.205 - return null; 5.206 + return false; 5.207 } 5.208 5.209 @Override 5.210 - public Node enterAccessNode(final AccessNode accessNode) { 5.211 + public boolean enterAccessNode(final AccessNode accessNode) { 5.212 if (!baseAlreadyOnStack) { 5.213 load(accessNode.getBase()).convert(Type.OBJECT); 5.214 } 5.215 assert method.peekType().isObject(); 5.216 method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); 5.217 - return null; 5.218 + return false; 5.219 } 5.220 5.221 @Override 5.222 - public Node enterIndexNode(final IndexNode indexNode) { 5.223 + public boolean enterIndexNode(final IndexNode indexNode) { 5.224 if (!baseAlreadyOnStack) { 5.225 load(indexNode.getBase()).convert(Type.OBJECT); 5.226 load(indexNode.getIndex()); 5.227 } 5.228 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); 5.229 - return null; 5.230 + return false; 5.231 } 5.232 5.233 @Override 5.234 - public Node enterFunctionNode(FunctionNode functionNode) { 5.235 + public boolean enterFunctionNode(FunctionNode functionNode) { 5.236 // function nodes will always leave a constructed function object on stack, no need to load the symbol 5.237 // separately as in enterDefault() 5.238 functionNode.accept(codegen); 5.239 - return null; 5.240 + return false; 5.241 } 5.242 5.243 @Override 5.244 - public Node enterDefault(final Node otherNode) { 5.245 + public boolean enterDefault(final Node otherNode) { 5.246 otherNode.accept(codegen); // generate code for whatever we are looking at. 5.247 method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) 5.248 - return null; 5.249 + return false; 5.250 } 5.251 }); 5.252 5.253 @@ -375,14 +428,9 @@ 5.254 } 5.255 5.256 @Override 5.257 - public Node enterAccessNode(final AccessNode accessNode) { 5.258 - if (accessNode.testResolved()) { 5.259 - return null; 5.260 - } 5.261 - 5.262 + public boolean enterAccessNode(final AccessNode accessNode) { 5.263 load(accessNode); 5.264 - 5.265 - return null; 5.266 + return false; 5.267 } 5.268 5.269 /** 5.270 @@ -407,7 +455,7 @@ 5.271 final boolean isInternal = symbol.isParam() || symbol.isInternal() || symbol.isThis() || !symbol.canBeUndefined(); 5.272 5.273 if (symbol.hasSlot() && !isInternal) { 5.274 - assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getCurrentFunctionNode(); 5.275 + assert symbol.getSymbolType().isNumber() || symbol.getSymbolType().isObject() : "no potentially undefined narrower local vars than doubles are allowed: " + symbol + " in " + getLexicalContext().getCurrentFunction(); 5.276 if (symbol.getSymbolType().isNumber()) { 5.277 numbers.add(symbol); 5.278 } else if (symbol.getSymbolType().isObject()) { 5.279 @@ -441,22 +489,20 @@ 5.280 * @param block block containing symbols. 5.281 */ 5.282 private void symbolInfo(final Block block) { 5.283 - for (final Symbol symbol : block.getFrame().getSymbols()) { 5.284 - method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); 5.285 + for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 5.286 + final Symbol symbol = iter.next(); 5.287 + if (symbol.hasSlot()) { 5.288 + method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); 5.289 + } 5.290 } 5.291 } 5.292 5.293 @Override 5.294 - public Node enterBlock(final Block block) { 5.295 - if (block.testResolved()) { 5.296 - return null; 5.297 - } 5.298 - lexicalContext.push(block); 5.299 - 5.300 + public boolean enterBlock(final Block block) { 5.301 method.label(block.getEntryLabel()); 5.302 initLocals(block); 5.303 5.304 - return block; 5.305 + return true; 5.306 } 5.307 5.308 @Override 5.309 @@ -464,10 +510,10 @@ 5.310 method.label(block.getBreakLabel()); 5.311 symbolInfo(block); 5.312 5.313 - if (block.needsScope()) { 5.314 + if (block.needsScope() && !block.isTerminal()) { 5.315 popBlockScope(block); 5.316 } 5.317 - lexicalContext.pop(block); 5.318 + --nextFreeSlotsSize; 5.319 return block; 5.320 } 5.321 5.322 @@ -477,34 +523,30 @@ 5.323 final Label skipLabel = new Label("skip_catch"); 5.324 5.325 /* pop scope a la try-finally */ 5.326 - method.loadScope(); 5.327 + method.loadCompilerConstant(SCOPE); 5.328 method.invoke(ScriptObject.GET_PROTO); 5.329 - method.storeScope(); 5.330 + method.storeCompilerConstant(SCOPE); 5.331 method._goto(skipLabel); 5.332 method.label(exitLabel); 5.333 5.334 method._catch(recoveryLabel); 5.335 - method.loadScope(); 5.336 + method.loadCompilerConstant(SCOPE); 5.337 method.invoke(ScriptObject.GET_PROTO); 5.338 - method.storeScope(); 5.339 + method.storeCompilerConstant(SCOPE); 5.340 method.athrow(); 5.341 method.label(skipLabel); 5.342 method._try(block.getEntryLabel(), exitLabel, recoveryLabel, Throwable.class); 5.343 } 5.344 5.345 @Override 5.346 - public Node enterBreakNode(final BreakNode breakNode) { 5.347 - if (breakNode.testResolved()) { 5.348 - return null; 5.349 - } 5.350 - 5.351 - for (int i = 0; i < breakNode.getScopeNestingLevel(); i++) { 5.352 + public boolean enterBreakNode(final BreakNode breakNode) { 5.353 + final BreakableNode breakFrom = getLexicalContext().getBreakable(breakNode.getLabel()); 5.354 + for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(breakFrom); i++) { 5.355 closeWith(); 5.356 } 5.357 - 5.358 - method.splitAwareGoto(breakNode.getTargetLabel()); 5.359 - 5.360 - return null; 5.361 + method.splitAwareGoto(getLexicalContext(), breakFrom.getBreakLabel()); 5.362 + 5.363 + return false; 5.364 } 5.365 5.366 private int loadArgs(final List<Node> args) { 5.367 @@ -541,21 +583,17 @@ 5.368 } 5.369 5.370 @Override 5.371 - public Node enterCallNode(final CallNode callNode) { 5.372 - if (callNode.testResolved()) { 5.373 - return null; 5.374 - } 5.375 - 5.376 + public boolean enterCallNode(final CallNode callNode) { 5.377 final List<Node> args = callNode.getArgs(); 5.378 final Node function = callNode.getFunction(); 5.379 - final Block currentBlock = getCurrentBlock(); 5.380 - 5.381 - function.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 5.382 + final Block currentBlock = getLexicalContext().getCurrentBlock(); 5.383 + 5.384 + function.accept(new NodeVisitor() { 5.385 5.386 private void sharedScopeCall(final IdentNode identNode, final int flags) { 5.387 final Symbol symbol = identNode.getSymbol(); 5.388 int scopeCallFlags = flags; 5.389 - method.loadScope(); 5.390 + method.loadCompilerConstant(SCOPE); 5.391 if (isFastScope(symbol)) { 5.392 method.load(getScopeProtoDepth(currentBlock, symbol)); 5.393 scopeCallFlags |= CALLSITE_FAST_SCOPE; 5.394 @@ -591,7 +629,7 @@ 5.395 // We don't need ScriptFunction object for 'eval' 5.396 method.pop(); 5.397 5.398 - method.loadScope(); // Load up self (scope). 5.399 + method.loadCompilerConstant(SCOPE); // Load up self (scope). 5.400 5.401 final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); 5.402 // load evaluated code 5.403 @@ -618,7 +656,7 @@ 5.404 } 5.405 5.406 @Override 5.407 - public Node enterIdentNode(final IdentNode node) { 5.408 + public boolean enterIdentNode(final IdentNode node) { 5.409 final Symbol symbol = node.getSymbol(); 5.410 5.411 if (symbol.isScope()) { 5.412 @@ -637,16 +675,16 @@ 5.413 } else { 5.414 sharedScopeCall(node, flags); 5.415 } 5.416 - assert method.peekType().equals(callNode.getType()); 5.417 + assert method.peekType().equals(callNode.getType()) : method.peekType() + "!=" + callNode.getType(); 5.418 } else { 5.419 enterDefault(node); 5.420 } 5.421 5.422 - return null; 5.423 + return false; 5.424 } 5.425 5.426 @Override 5.427 - public Node enterAccessNode(final AccessNode node) { 5.428 + public boolean enterAccessNode(final AccessNode node) { 5.429 load(node.getBase()); 5.430 method.convert(Type.OBJECT); 5.431 method.dup(); 5.432 @@ -655,35 +693,34 @@ 5.433 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); 5.434 assert method.peekType().equals(callNode.getType()); 5.435 5.436 - return null; 5.437 + return false; 5.438 } 5.439 5.440 @Override 5.441 - public Node enterFunctionNode(final FunctionNode callee) { 5.442 + public boolean enterFunctionNode(final FunctionNode origCallee) { 5.443 + // NOTE: visiting the callee will leave a constructed ScriptFunction object on the stack if 5.444 + // callee.needsCallee() == true 5.445 + final FunctionNode callee = (FunctionNode)origCallee.accept(CodeGenerator.this); 5.446 + 5.447 final boolean isVarArg = callee.isVarArg(); 5.448 final int argCount = isVarArg ? -1 : callee.getParameters().size(); 5.449 5.450 final String signature = new FunctionSignature(true, callee.needsCallee(), callee.getReturnType(), isVarArg ? null : callee.getParameters()).toString(); 5.451 5.452 - if (callee.needsCallee()) { 5.453 - newFunctionObject(callee); 5.454 - } 5.455 - 5.456 - if (callee.isStrictMode()) { // self is undefined 5.457 + if (callee.isStrict()) { // self is undefined 5.458 method.loadUndefined(Type.OBJECT); 5.459 } else { // get global from scope (which is the self) 5.460 globalInstance(); 5.461 } 5.462 loadArgs(args, signature, isVarArg, argCount); 5.463 + assert callee.getCompileUnit() != null : "no compile unit for " + callee.getName() + " " + Debug.id(callee) + " " + callNode; 5.464 method.invokestatic(callee.getCompileUnit().getUnitClassName(), callee.getName(), signature); 5.465 assert method.peekType().equals(callee.getReturnType()) : method.peekType() + " != " + callee.getReturnType(); 5.466 - functionNodeIsCallee = true; 5.467 - callee.accept(CodeGenerator.this); 5.468 - return null; 5.469 + return false; 5.470 } 5.471 5.472 @Override 5.473 - public Node enterIndexNode(final IndexNode node) { 5.474 + public boolean enterIndexNode(final IndexNode node) { 5.475 load(node.getBase()); 5.476 method.convert(Type.OBJECT); 5.477 method.dup(); 5.478 @@ -697,11 +734,11 @@ 5.479 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags()); 5.480 assert method.peekType().equals(callNode.getType()); 5.481 5.482 - return null; 5.483 + return false; 5.484 } 5.485 5.486 @Override 5.487 - protected Node enterDefault(final Node node) { 5.488 + protected boolean enterDefault(final Node node) { 5.489 // Load up function. 5.490 load(function); 5.491 method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions 5.492 @@ -709,58 +746,41 @@ 5.493 method.dynamicCall(callNode.getType(), 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); 5.494 assert method.peekType().equals(callNode.getType()); 5.495 5.496 - return null; 5.497 + return false; 5.498 } 5.499 }); 5.500 5.501 method.store(callNode.getSymbol()); 5.502 5.503 - return null; 5.504 + return false; 5.505 } 5.506 5.507 @Override 5.508 - public Node enterContinueNode(final ContinueNode continueNode) { 5.509 - if (continueNode.testResolved()) { 5.510 - return null; 5.511 - } 5.512 - 5.513 - for (int i = 0; i < continueNode.getScopeNestingLevel(); i++) { 5.514 + public boolean enterContinueNode(final ContinueNode continueNode) { 5.515 + final LoopNode continueTo = getLexicalContext().getContinueTo(continueNode.getLabel()); 5.516 + for (int i = 0; i < getLexicalContext().getScopeNestingLevelTo(continueTo); i++) { 5.517 closeWith(); 5.518 } 5.519 - 5.520 - method.splitAwareGoto(continueNode.getTargetLabel()); 5.521 - 5.522 - return null; 5.523 + method.splitAwareGoto(getLexicalContext(), continueTo.getContinueLabel()); 5.524 + 5.525 + return false; 5.526 } 5.527 5.528 @Override 5.529 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 5.530 - return enterWhileNode(doWhileNode); 5.531 + public boolean enterEmptyNode(final EmptyNode emptyNode) { 5.532 + return false; 5.533 } 5.534 5.535 @Override 5.536 - public Node enterEmptyNode(final EmptyNode emptyNode) { 5.537 - return null; 5.538 - } 5.539 - 5.540 - @Override 5.541 - public Node enterExecuteNode(final ExecuteNode executeNode) { 5.542 - if (executeNode.testResolved()) { 5.543 - return null; 5.544 - } 5.545 - 5.546 + public boolean enterExecuteNode(final ExecuteNode executeNode) { 5.547 final Node expression = executeNode.getExpression(); 5.548 expression.accept(this); 5.549 5.550 - return null; 5.551 + return false; 5.552 } 5.553 5.554 @Override 5.555 - public Node enterForNode(final ForNode forNode) { 5.556 - if (forNode.testResolved()) { 5.557 - return null; 5.558 - } 5.559 - 5.560 + public boolean enterForNode(final ForNode forNode) { 5.561 final Node test = forNode.getTest(); 5.562 final Block body = forNode.getBody(); 5.563 final Node modify = forNode.getModify(); 5.564 @@ -790,6 +810,10 @@ 5.565 5.566 new Store<Node>(init) { 5.567 @Override 5.568 + protected void storeNonDiscard() { 5.569 + return; 5.570 + } 5.571 + @Override 5.572 protected void evaluate() { 5.573 method.load(iter); 5.574 method.invoke(interfaceCallNoLookup(Iterator.class, "next", Object.class)); 5.575 @@ -829,7 +853,19 @@ 5.576 method.label(breakLabel); 5.577 } 5.578 5.579 - return null; 5.580 + return false; 5.581 + } 5.582 + 5.583 + private static int assignSlots(final Block block, final int firstSlot) { 5.584 + int nextSlot = firstSlot; 5.585 + for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 5.586 + final Symbol next = iter.next(); 5.587 + if (next.hasSlot()) { 5.588 + next.setSlot(nextSlot); 5.589 + nextSlot += next.slotCount(); 5.590 + } 5.591 + } 5.592 + return nextSlot; 5.593 } 5.594 5.595 /** 5.596 @@ -838,21 +874,26 @@ 5.597 * @param block block with local vars. 5.598 */ 5.599 private void initLocals(final Block block) { 5.600 - final FunctionNode function = lexicalContext.getFunction(block); 5.601 - final boolean isFunctionNode = block == function; 5.602 - 5.603 - /* 5.604 - * Get the symbols from the frame and realign the frame so that all 5.605 - * slots get correct numbers. The slot numbering is not fixed until 5.606 - * after initLocals has been run 5.607 - */ 5.608 - final Frame frame = block.getFrame(); 5.609 - final List<Symbol> symbols = frame.getSymbols(); 5.610 - 5.611 - /* Fix the predefined slots so they have numbers >= 0, like varargs. */ 5.612 - frame.realign(); 5.613 - 5.614 - if (isFunctionNode) { 5.615 + final boolean isFunctionBody = getLexicalContext().isFunctionBody(); 5.616 + 5.617 + final int nextFreeSlot; 5.618 + if (isFunctionBody) { 5.619 + // On entry to function, start with slot 0 5.620 + nextFreeSlot = 0; 5.621 + } else { 5.622 + // Otherwise, continue from previous block's first free slot 5.623 + nextFreeSlot = nextFreeSlots[nextFreeSlotsSize - 1]; 5.624 + } 5.625 + if(nextFreeSlotsSize == nextFreeSlots.length) { 5.626 + final int[] newNextFreeSlots = new int[nextFreeSlotsSize * 2]; 5.627 + System.arraycopy(nextFreeSlots, 0, newNextFreeSlots, 0, nextFreeSlotsSize); 5.628 + nextFreeSlots = newNextFreeSlots; 5.629 + } 5.630 + nextFreeSlots[nextFreeSlotsSize++] = assignSlots(block, nextFreeSlot); 5.631 + 5.632 + final FunctionNode function = getLexicalContext().getCurrentFunction(); 5.633 + if (isFunctionBody) { 5.634 + /* Fix the predefined slots so they have numbers >= 0, like varargs. */ 5.635 if (function.needsParentScope()) { 5.636 initParentScope(); 5.637 } 5.638 @@ -876,14 +917,18 @@ 5.639 final List<String> nameList = new ArrayList<>(); 5.640 final List<Symbol> locals = new ArrayList<>(); 5.641 5.642 - 5.643 // Initalize symbols and values 5.644 final List<Symbol> newSymbols = new ArrayList<>(); 5.645 final List<Symbol> values = new ArrayList<>(); 5.646 5.647 final boolean hasArguments = function.needsArguments(); 5.648 - for (final Symbol symbol : symbols) { 5.649 - if (symbol.isInternal() || symbol.isThis()) { 5.650 + 5.651 + final Iterator<Symbol> symbols = block.symbolIterator(); 5.652 + 5.653 + while (symbols.hasNext()) { 5.654 + final Symbol symbol = symbols.next(); 5.655 + 5.656 + if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { 5.657 continue; 5.658 } 5.659 5.660 @@ -907,9 +952,6 @@ 5.661 } 5.662 } 5.663 5.664 - /* Correct slot numbering again */ 5.665 - frame.realign(); 5.666 - 5.667 // we may have locals that need to be initialized 5.668 initSymbols(locals); 5.669 5.670 @@ -931,7 +973,7 @@ 5.671 @Override 5.672 protected void loadScope(MethodEmitter m) { 5.673 if(function.needsParentScope()) { 5.674 - m.loadScope(); 5.675 + m.loadCompilerConstant(SCOPE); 5.676 } else { 5.677 m.loadNull(); 5.678 } 5.679 @@ -940,118 +982,102 @@ 5.680 foc.makeObject(method); 5.681 5.682 // runScript(): merge scope into global 5.683 - if (isFunctionNode && function.isProgram()) { 5.684 + if (isFunctionBody && function.isProgram()) { 5.685 method.invoke(ScriptRuntime.MERGE_SCOPE); 5.686 } 5.687 5.688 - method.storeScope(); 5.689 + method.storeCompilerConstant(SCOPE); 5.690 } else { 5.691 // Since we don't have a scope, parameters didn't get assigned array indices by the FieldObjectCreator, so 5.692 // we need to assign them separately here. 5.693 int nextParam = 0; 5.694 - if (isFunctionNode && function.isVarArg()) { 5.695 + if (isFunctionBody && function.isVarArg()) { 5.696 for (final IdentNode param : function.getParameters()) { 5.697 param.getSymbol().setFieldIndex(nextParam++); 5.698 } 5.699 } 5.700 + 5.701 + final Iterator<Symbol> iter = block.symbolIterator(); 5.702 + final List<Symbol> symbols = new ArrayList<>(); 5.703 + while (iter.hasNext()) { 5.704 + symbols.add(iter.next()); 5.705 + } 5.706 initSymbols(symbols); 5.707 } 5.708 5.709 // Debugging: print symbols? @see --print-symbols flag 5.710 - printSymbols(block, (isFunctionNode ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName())); 5.711 + printSymbols(block, (isFunctionBody ? "Function " : "Block in ") + (function.getIdent() == null ? "<anonymous>" : function.getIdent().getName())); 5.712 } 5.713 5.714 private void initArguments(final FunctionNode function) { 5.715 - method.loadVarArgs(); 5.716 + method.loadCompilerConstant(VARARGS); 5.717 if(function.needsCallee()) { 5.718 - method.loadCallee(); 5.719 + method.loadCompilerConstant(CALLEE); 5.720 } else { 5.721 // If function is strict mode, "arguments.callee" is not populated, so we don't necessarily need the 5.722 // caller. 5.723 - assert function.isStrictMode(); 5.724 + assert function.isStrict(); 5.725 method.loadNull(); 5.726 } 5.727 method.load(function.getParameters().size()); 5.728 globalAllocateArguments(); 5.729 - method.storeArguments(); 5.730 + method.storeCompilerConstant(ARGUMENTS); 5.731 } 5.732 5.733 private void initParentScope() { 5.734 - method.loadCallee(); 5.735 + method.loadCompilerConstant(CALLEE); 5.736 method.invoke(ScriptFunction.GET_SCOPE); 5.737 - method.storeScope(); 5.738 + method.storeCompilerConstant(SCOPE); 5.739 } 5.740 5.741 @Override 5.742 - public Node enterFunctionNode(final FunctionNode functionNode) { 5.743 - final boolean isCallee = functionNodeIsCallee; 5.744 - functionNodeIsCallee = false; 5.745 - 5.746 - if (functionNode.testResolved()) { 5.747 - return null; 5.748 + public boolean enterFunctionNode(final FunctionNode functionNode) { 5.749 + if (functionNode.isLazy()) { 5.750 + // Must do it now; can't postpone it until leaveFunctionNode() 5.751 + newFunctionObject(functionNode, functionNode); 5.752 + return false; 5.753 } 5.754 5.755 - if(!(isCallee || functionNode == compiler.getFunctionNode())) { 5.756 - newFunctionObject(functionNode); 5.757 - } 5.758 - 5.759 - if (functionNode.isLazy()) { 5.760 - return null; 5.761 - } 5.762 - 5.763 - LOG.info("=== BEGIN " + functionNode.getName()); 5.764 - lexicalContext.push(functionNode); 5.765 - 5.766 - setCurrentCompileUnit(functionNode.getCompileUnit()); 5.767 - assert getCurrentCompileUnit() != null; 5.768 - 5.769 - setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(functionNode)); 5.770 - functionNode.setMethodEmitter(method); 5.771 + LOG.info("=== BEGIN ", functionNode.getName()); 5.772 + 5.773 + assert functionNode.getCompileUnit() != null : "no compile unit for " + functionNode.getName() + " " + Debug.id(functionNode); 5.774 + push(functionNode.getCompileUnit()); 5.775 + assert !compileUnits.isEmpty(); 5.776 + 5.777 + pushMethodEmitter(unit.getClassEmitter().method(functionNode)); 5.778 // Mark end for variable tables. 5.779 method.begin(); 5.780 - method.label(functionNode.getEntryLabel()); 5.781 - 5.782 - initLocals(functionNode); 5.783 - functionNode.setState(CompilationState.EMITTED); 5.784 - 5.785 - return functionNode; 5.786 + 5.787 + return true; 5.788 } 5.789 5.790 @Override 5.791 public Node leaveFunctionNode(final FunctionNode functionNode) { 5.792 - // Mark end for variable tables. 5.793 - method.label(functionNode.getBreakLabel()); 5.794 - 5.795 - if (!functionNode.needsScope()) { 5.796 - method.markerVariable(LEAF.tag(), functionNode.getEntryLabel(), functionNode.getBreakLabel()); 5.797 - } 5.798 - 5.799 - symbolInfo(functionNode); 5.800 try { 5.801 method.end(); // wrap up this method 5.802 + pop(functionNode.getCompileUnit()); 5.803 + popMethodEmitter(method); 5.804 + LOG.info("=== END ", functionNode.getName()); 5.805 + 5.806 + final FunctionNode newFunctionNode = functionNode.setState(getLexicalContext(), CompilationState.EMITTED); 5.807 + 5.808 + newFunctionObject(newFunctionNode, functionNode); 5.809 + return newFunctionNode; 5.810 } catch (final Throwable t) { 5.811 Context.printStackTrace(t); 5.812 final VerifyError e = new VerifyError("Code generation bug in \"" + functionNode.getName() + "\": likely stack misaligned: " + t + " " + functionNode.getSource().getName()); 5.813 e.initCause(t); 5.814 throw e; 5.815 } 5.816 - 5.817 - lexicalContext.pop(functionNode); 5.818 - LOG.info("=== END " + functionNode.getName()); 5.819 - return functionNode; 5.820 } 5.821 5.822 @Override 5.823 - public Node enterIdentNode(final IdentNode identNode) { 5.824 - return null; 5.825 + public boolean enterIdentNode(final IdentNode identNode) { 5.826 + return false; 5.827 } 5.828 5.829 @Override 5.830 - public Node enterIfNode(final IfNode ifNode) { 5.831 - if (ifNode.testResolved()) { 5.832 - return null; 5.833 - } 5.834 - 5.835 + public boolean enterIfNode(final IfNode ifNode) { 5.836 final Node test = ifNode.getTest(); 5.837 final Block pass = ifNode.getPass(); 5.838 final Block fail = ifNode.getFail(); 5.839 @@ -1082,30 +1108,21 @@ 5.840 method.label(afterLabel); 5.841 } 5.842 5.843 - return null; 5.844 + return false; 5.845 } 5.846 5.847 @Override 5.848 - public Node enterIndexNode(final IndexNode indexNode) { 5.849 - if (indexNode.testResolved()) { 5.850 - return null; 5.851 - } 5.852 - 5.853 + public boolean enterIndexNode(final IndexNode indexNode) { 5.854 load(indexNode); 5.855 - 5.856 - return null; 5.857 + return false; 5.858 } 5.859 5.860 @Override 5.861 - public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 5.862 - if (lineNumberNode.testResolved()) { 5.863 - return null; 5.864 - } 5.865 - 5.866 - final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getCurrentFunctionNode().getName() + ")"); 5.867 + public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { 5.868 + final Label label = new Label("line:" + lineNumberNode.getLineNumber() + " (" + getLexicalContext().getCurrentFunction().getName() + ")"); 5.869 method.label(label); 5.870 method.lineNumber(lineNumberNode.getLineNumber(), label); 5.871 - return null; 5.872 + return false; 5.873 } 5.874 5.875 /** 5.876 @@ -1131,43 +1148,43 @@ 5.877 final Type elementType = arrayType.getElementType(); 5.878 5.879 if (units != null) { 5.880 - final CompileUnit savedCompileUnit = getCurrentCompileUnit(); 5.881 - final MethodEmitter savedMethod = getCurrentMethodEmitter(); 5.882 - 5.883 - try { 5.884 - for (final ArrayUnit unit : units) { 5.885 - setCurrentCompileUnit(unit.getCompileUnit()); 5.886 - 5.887 - final String className = getCurrentCompileUnit().getUnitClassName(); 5.888 - final String name = getCurrentFunctionNode().uniqueName(SPLIT_PREFIX.tag()); 5.889 - final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); 5.890 - 5.891 - setCurrentMethodEmitter(getCurrentCompileUnit().getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature)); 5.892 - method.setFunctionNode(getCurrentFunctionNode()); 5.893 - method.begin(); 5.894 - 5.895 - fixScopeSlot(); 5.896 - 5.897 - method.load(arrayType, SPLIT_ARRAY_ARG.slot()); 5.898 - 5.899 - for (int i = unit.getLo(); i < unit.getHi(); i++) { 5.900 - storeElement(nodes, elementType, postsets[i]); 5.901 - } 5.902 - 5.903 - method._return(); 5.904 - method.end(); 5.905 - 5.906 - savedMethod.loadThis(); 5.907 - savedMethod.swap(); 5.908 - savedMethod.loadCallee(); 5.909 - savedMethod.swap(); 5.910 - savedMethod.loadScope(); 5.911 - savedMethod.swap(); 5.912 - savedMethod.invokestatic(className, name, signature); 5.913 + final MethodEmitter savedMethod = method; 5.914 + 5.915 + for (final ArrayUnit arrayUnit : units) { 5.916 + push(arrayUnit.getCompileUnit()); 5.917 + 5.918 + final String className = unit.getUnitClassName(); 5.919 + final String name = getLexicalContext().getCurrentFunction().uniqueName(SPLIT_PREFIX.symbolName()); 5.920 + final String signature = methodDescriptor(type, Object.class, ScriptFunction.class, ScriptObject.class, type); 5.921 + 5.922 + final MethodEmitter me = unit.getClassEmitter().method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), name, signature); 5.923 + pushMethodEmitter(me); 5.924 + 5.925 + method.setFunctionNode(getLexicalContext().getCurrentFunction()); 5.926 + method.begin(); 5.927 + 5.928 + fixScopeSlot(); 5.929 + 5.930 + method.load(arrayType, SPLIT_ARRAY_ARG.slot()); 5.931 + 5.932 + for (int i = arrayUnit.getLo(); i < arrayUnit.getHi(); i++) { 5.933 + storeElement(nodes, elementType, postsets[i]); 5.934 } 5.935 - } finally { 5.936 - setCurrentCompileUnit(savedCompileUnit); 5.937 - setCurrentMethodEmitter(savedMethod); 5.938 + 5.939 + method._return(); 5.940 + method.end(); 5.941 + popMethodEmitter(me); 5.942 + 5.943 + assert method == savedMethod; 5.944 + method.loadCompilerConstant(THIS); 5.945 + method.swap(); 5.946 + method.loadCompilerConstant(CALLEE); 5.947 + method.swap(); 5.948 + method.loadCompilerConstant(SCOPE); 5.949 + method.swap(); 5.950 + method.invokestatic(className, name, signature); 5.951 + 5.952 + pop(unit); 5.953 } 5.954 5.955 return method; 5.956 @@ -1217,12 +1234,12 @@ 5.957 * @param string string to load 5.958 */ 5.959 void loadConstant(final String string) { 5.960 - final String unitClassName = getCurrentCompileUnit().getUnitClassName(); 5.961 - final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); 5.962 + final String unitClassName = unit.getUnitClassName(); 5.963 + final ClassEmitter classEmitter = unit.getClassEmitter(); 5.964 final int index = compiler.getConstantData().add(string); 5.965 5.966 method.load(index); 5.967 - method.invokestatic(unitClassName, GET_STRING.tag(), methodDescriptor(String.class, int.class)); 5.968 + method.invokestatic(unitClassName, GET_STRING.symbolName(), methodDescriptor(String.class, int.class)); 5.969 classEmitter.needGetConstantMethod(String.class); 5.970 } 5.971 5.972 @@ -1233,14 +1250,14 @@ 5.973 * @param object object to load 5.974 */ 5.975 void loadConstant(final Object object) { 5.976 - final String unitClassName = getCurrentCompileUnit().getUnitClassName(); 5.977 - final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); 5.978 + final String unitClassName = unit.getUnitClassName(); 5.979 + final ClassEmitter classEmitter = unit.getClassEmitter(); 5.980 final int index = compiler.getConstantData().add(object); 5.981 final Class<?> cls = object.getClass(); 5.982 5.983 if (cls == PropertyMap.class) { 5.984 method.load(index); 5.985 - method.invokestatic(unitClassName, GET_MAP.tag(), methodDescriptor(PropertyMap.class, int.class)); 5.986 + method.invokestatic(unitClassName, GET_MAP.symbolName(), methodDescriptor(PropertyMap.class, int.class)); 5.987 classEmitter.needGetConstantMethod(PropertyMap.class); 5.988 } else if (cls.isArray()) { 5.989 method.load(index); 5.990 @@ -1303,14 +1320,14 @@ 5.991 return loadRegexToken(regexToken); 5.992 } 5.993 // emit field 5.994 - final String regexName = getCurrentFunctionNode().uniqueName(REGEX_PREFIX.tag()); 5.995 - final ClassEmitter classEmitter = getCurrentCompileUnit().getClassEmitter(); 5.996 + final String regexName = getLexicalContext().getCurrentFunction().uniqueName(REGEX_PREFIX.symbolName()); 5.997 + final ClassEmitter classEmitter = unit.getClassEmitter(); 5.998 5.999 classEmitter.field(EnumSet.of(PRIVATE, STATIC), regexName, Object.class); 5.1000 regexFieldCount++; 5.1001 5.1002 // get field, if null create new regex, finally clone regex object 5.1003 - method.getStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); 5.1004 + method.getStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class)); 5.1005 method.dup(); 5.1006 final Label cachedLabel = new Label("cached"); 5.1007 method.ifnonnull(cachedLabel); 5.1008 @@ -1318,7 +1335,7 @@ 5.1009 method.pop(); 5.1010 loadRegexToken(regexToken); 5.1011 method.dup(); 5.1012 - method.putStatic(getCurrentCompileUnit().getUnitClassName(), regexName, typeDescriptor(Object.class)); 5.1013 + method.putStatic(unit.getUnitClassName(), regexName, typeDescriptor(Object.class)); 5.1014 5.1015 method.label(cachedLabel); 5.1016 globalRegExpCopy(); 5.1017 @@ -1328,18 +1345,14 @@ 5.1018 5.1019 @SuppressWarnings("rawtypes") 5.1020 @Override 5.1021 - public Node enterLiteralNode(final LiteralNode literalNode) { 5.1022 + public boolean enterLiteralNode(final LiteralNode literalNode) { 5.1023 assert literalNode.getSymbol() != null : literalNode + " has no symbol"; 5.1024 load(literalNode).store(literalNode.getSymbol()); 5.1025 - return null; 5.1026 + return false; 5.1027 } 5.1028 5.1029 @Override 5.1030 - public Node enterObjectNode(final ObjectNode objectNode) { 5.1031 - if (objectNode.testResolved()) { 5.1032 - return null; 5.1033 - } 5.1034 - 5.1035 + public boolean enterObjectNode(final ObjectNode objectNode) { 5.1036 final List<Node> elements = objectNode.getElements(); 5.1037 final int size = elements.size(); 5.1038 5.1039 @@ -1404,14 +1417,14 @@ 5.1040 5.1041 if (!hasGettersSetters) { 5.1042 method.store(objectNode.getSymbol()); 5.1043 - return null; 5.1044 + return false; 5.1045 } 5.1046 5.1047 for (final Node element : elements) { 5.1048 final PropertyNode propertyNode = (PropertyNode)element; 5.1049 final Object key = propertyNode.getKey(); 5.1050 - final FunctionNode getter = (FunctionNode)propertyNode.getGetter(); 5.1051 - final FunctionNode setter = (FunctionNode)propertyNode.getSetter(); 5.1052 + final FunctionNode getter = propertyNode.getGetter(); 5.1053 + final FunctionNode setter = propertyNode.getSetter(); 5.1054 5.1055 if (getter == null && setter == null) { 5.1056 continue; 5.1057 @@ -1436,35 +1449,25 @@ 5.1058 5.1059 method.store(objectNode.getSymbol()); 5.1060 5.1061 - return null; 5.1062 + return false; 5.1063 } 5.1064 5.1065 @Override 5.1066 - public Node enterReturnNode(final ReturnNode returnNode) { 5.1067 - if (returnNode.testResolved()) { 5.1068 - return null; 5.1069 - } 5.1070 - 5.1071 - // Set the split return flag in the scope if this is a split method fragment. 5.1072 - if (method.getSplitNode() != null) { 5.1073 - assert method.getSplitNode().hasReturn() : "unexpected return in split node"; 5.1074 - 5.1075 - method.loadScope(); 5.1076 - method.checkcast(Scope.class); 5.1077 - method.load(0); 5.1078 - method.invoke(Scope.SET_SPLIT_STATE); 5.1079 - } 5.1080 + public boolean enterReturnNode(final ReturnNode returnNode) { 5.1081 + method.registerReturn(); 5.1082 + 5.1083 + final Type returnType = getLexicalContext().getCurrentFunction().getReturnType(); 5.1084 5.1085 final Node expression = returnNode.getExpression(); 5.1086 if (expression != null) { 5.1087 load(expression); 5.1088 } else { 5.1089 - method.loadUndefined(getCurrentFunctionNode().getReturnType()); 5.1090 + method.loadUndefined(returnType); 5.1091 } 5.1092 5.1093 - method._return(getCurrentFunctionNode().getReturnType()); 5.1094 - 5.1095 - return null; 5.1096 + method._return(returnType); 5.1097 + 5.1098 + return false; 5.1099 } 5.1100 5.1101 private static boolean isNullLiteral(final Node node) { 5.1102 @@ -1542,19 +1545,20 @@ 5.1103 } 5.1104 5.1105 assert args.size() == 2; 5.1106 - final Node lhs = args.get(0); 5.1107 - final Node rhs = args.get(1); 5.1108 - 5.1109 final Type returnType = node.getType(); 5.1110 - load(lhs); 5.1111 - load(rhs); 5.1112 + 5.1113 + load(args.get(0)); 5.1114 + load(args.get(1)); 5.1115 5.1116 Request finalRequest = request; 5.1117 5.1118 + //if the request is a comparison, i.e. one that can be reversed 5.1119 + //it keeps its semantic, but make sure that the object comes in 5.1120 + //last 5.1121 final Request reverse = Request.reverse(request); 5.1122 - if (method.peekType().isObject() && reverse != null) { 5.1123 - if (!method.peekType(1).isObject()) { 5.1124 - method.swap(); 5.1125 + if (method.peekType().isObject() && reverse != null) { //rhs is object 5.1126 + if (!method.peekType(1).isObject()) { //lhs is not object 5.1127 + method.swap(); //prefer object as lhs 5.1128 finalRequest = reverse; 5.1129 } 5.1130 } 5.1131 @@ -1581,11 +1585,7 @@ 5.1132 } 5.1133 5.1134 @Override 5.1135 - public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 5.1136 - if (runtimeNode.testResolved()) { 5.1137 - return null; 5.1138 - } 5.1139 - 5.1140 + public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 5.1141 /* 5.1142 * First check if this should be something other than a runtime node 5.1143 * AccessSpecializer might have changed the type 5.1144 @@ -1624,7 +1624,7 @@ 5.1145 method.add(); 5.1146 method.convert(type); 5.1147 method.store(symbol); 5.1148 - return null; 5.1149 + return false; 5.1150 default: 5.1151 // it's ok to send this one on with only primitive arguments, maybe INSTANCEOF(true, true) or similar 5.1152 // assert false : runtimeNode + " has all primitive arguments. This is an inconsistent state"; 5.1153 @@ -1636,11 +1636,11 @@ 5.1154 final List<Node> args = runtimeNode.getArgs(); 5.1155 5.1156 if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { 5.1157 - return null; 5.1158 + return false; 5.1159 } 5.1160 5.1161 if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { 5.1162 - return null; 5.1163 + return false; 5.1164 } 5.1165 5.1166 for (final Node arg : runtimeNode.getArgs()) { 5.1167 @@ -1658,129 +1658,146 @@ 5.1168 method.convert(runtimeNode.getType()); 5.1169 method.store(runtimeNode.getSymbol()); 5.1170 5.1171 - return null; 5.1172 + return false; 5.1173 } 5.1174 5.1175 @Override 5.1176 - public Node enterSplitNode(final SplitNode splitNode) { 5.1177 - if (splitNode.testResolved()) { 5.1178 - return null; 5.1179 - } 5.1180 - 5.1181 + public boolean enterSplitNode(final SplitNode splitNode) { 5.1182 final CompileUnit splitCompileUnit = splitNode.getCompileUnit(); 5.1183 5.1184 - final FunctionNode fn = getCurrentFunctionNode(); 5.1185 + final FunctionNode fn = getLexicalContext().getCurrentFunction(); 5.1186 final String className = splitCompileUnit.getUnitClassName(); 5.1187 final String name = splitNode.getName(); 5.1188 5.1189 - final Class<?> rtype = fn.getReturnType().getTypeClass(); 5.1190 - final boolean needsArguments = fn.needsArguments(); 5.1191 - final Class<?>[] ptypes = needsArguments ? 5.1192 + final Class<?> rtype = fn.getReturnType().getTypeClass(); 5.1193 + final boolean needsArguments = fn.needsArguments(); 5.1194 + final Class<?>[] ptypes = needsArguments ? 5.1195 new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class, Object.class} : 5.1196 new Class<?>[] {ScriptFunction.class, Object.class, ScriptObject.class}; 5.1197 5.1198 - setCurrentCompileUnit(splitCompileUnit); 5.1199 - splitNode.setCompileUnit(splitCompileUnit); 5.1200 + final MethodEmitter caller = method; 5.1201 + push(splitCompileUnit); 5.1202 5.1203 final Call splitCall = staticCallNoLookup( 5.1204 className, 5.1205 name, 5.1206 methodDescriptor(rtype, ptypes)); 5.1207 5.1208 - setCurrentMethodEmitter( 5.1209 - splitCompileUnit.getClassEmitter().method( 5.1210 - EnumSet.of(Flag.PUBLIC, Flag.STATIC), 5.1211 - name, 5.1212 - rtype, 5.1213 - ptypes)); 5.1214 + final MethodEmitter splitEmitter = 5.1215 + splitCompileUnit.getClassEmitter().method( 5.1216 + splitNode, 5.1217 + name, 5.1218 + rtype, 5.1219 + ptypes); 5.1220 + 5.1221 + pushMethodEmitter(splitEmitter); 5.1222 5.1223 method.setFunctionNode(fn); 5.1224 - method.setSplitNode(splitNode); 5.1225 - splitNode.setMethodEmitter(method); 5.1226 - 5.1227 - final MethodEmitter caller = splitNode.getCaller(); 5.1228 - if(fn.needsCallee()) { 5.1229 - caller.loadCallee(); 5.1230 + 5.1231 + if (fn.needsCallee()) { 5.1232 + caller.loadCompilerConstant(CALLEE); 5.1233 } else { 5.1234 caller.loadNull(); 5.1235 } 5.1236 - caller.loadThis(); 5.1237 - caller.loadScope(); 5.1238 + caller.loadCompilerConstant(THIS); 5.1239 + caller.loadCompilerConstant(SCOPE); 5.1240 if (needsArguments) { 5.1241 - caller.loadArguments(); 5.1242 + caller.loadCompilerConstant(ARGUMENTS); 5.1243 } 5.1244 caller.invoke(splitCall); 5.1245 - caller.storeResult(); 5.1246 + caller.storeCompilerConstant(RETURN); 5.1247 5.1248 method.begin(); 5.1249 5.1250 method.loadUndefined(fn.getReturnType()); 5.1251 - method.storeResult(); 5.1252 + method.storeCompilerConstant(RETURN); 5.1253 5.1254 fixScopeSlot(); 5.1255 5.1256 - return splitNode; 5.1257 + return true; 5.1258 } 5.1259 5.1260 private void fixScopeSlot() { 5.1261 - if (getCurrentFunctionNode().getScopeNode().getSymbol().getSlot() != SCOPE.slot()) { 5.1262 + if (getLexicalContext().getCurrentFunction().compilerConstant(SCOPE).getSlot() != SCOPE.slot()) { 5.1263 // TODO hack to move the scope to the expected slot (that's needed because split methods reuse the same slots as the root method) 5.1264 method.load(Type.typeFor(ScriptObject.class), SCOPE.slot()); 5.1265 - method.storeScope(); 5.1266 + method.storeCompilerConstant(SCOPE); 5.1267 } 5.1268 } 5.1269 5.1270 @Override 5.1271 public Node leaveSplitNode(final SplitNode splitNode) { 5.1272 + assert method instanceof SplitMethodEmitter; 5.1273 + final boolean hasReturn = method.hasReturn(); 5.1274 + final List<Label> targets = method.getExternalTargets(); 5.1275 + 5.1276 try { 5.1277 // Wrap up this method. 5.1278 - method.loadResult(); 5.1279 - method._return(getCurrentFunctionNode().getReturnType()); 5.1280 + 5.1281 + method.loadCompilerConstant(RETURN); 5.1282 + method._return(getLexicalContext().getCurrentFunction().getReturnType()); 5.1283 method.end(); 5.1284 + 5.1285 + pop(splitNode.getCompileUnit()); 5.1286 + popMethodEmitter(method); 5.1287 + 5.1288 } catch (final Throwable t) { 5.1289 Context.printStackTrace(t); 5.1290 - final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getCurrentFunctionNode().getSource().getName()); 5.1291 + final VerifyError e = new VerifyError("Code generation bug in \"" + splitNode.getName() + "\": likely stack misaligned: " + t + " " + getLexicalContext().getCurrentFunction().getSource().getName()); 5.1292 e.initCause(t); 5.1293 throw e; 5.1294 } 5.1295 5.1296 // Handle return from split method if there was one. 5.1297 - final MethodEmitter caller = splitNode.getCaller(); 5.1298 - final List<Label> targets = splitNode.getExternalTargets(); 5.1299 - final int targetCount = targets.size(); 5.1300 - 5.1301 - if (splitNode.hasReturn() || targetCount > 0) { 5.1302 - 5.1303 - caller.loadScope(); 5.1304 - caller.checkcast(Scope.class); 5.1305 - caller.invoke(Scope.GET_SPLIT_STATE); 5.1306 - 5.1307 - // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue 5.1308 - final Label breakLabel = new Label("no_split_state"); 5.1309 - final int low = splitNode.hasReturn() ? 0 : 1; 5.1310 - final int labelCount = targetCount + 1 - low; 5.1311 - final Label[] labels = new Label[labelCount]; 5.1312 + final MethodEmitter caller = method; 5.1313 + final int targetCount = targets.size(); 5.1314 + 5.1315 + //no external jump targets or return in switch node 5.1316 + if (!hasReturn && targets.isEmpty()) { 5.1317 + return splitNode; 5.1318 + } 5.1319 + 5.1320 + caller.loadCompilerConstant(SCOPE); 5.1321 + caller.checkcast(Scope.class); 5.1322 + caller.invoke(Scope.GET_SPLIT_STATE); 5.1323 + 5.1324 + final Label breakLabel = new Label("no_split_state"); 5.1325 + // Split state is -1 for no split state, 0 for return, 1..n+1 for break/continue 5.1326 + 5.1327 + //the common case is that we don't need a switch 5.1328 + if (targetCount == 0) { 5.1329 + assert hasReturn; 5.1330 + caller.ifne(breakLabel); 5.1331 + //has to be zero 5.1332 + caller.label(new Label("split_return")); 5.1333 + method.loadCompilerConstant(RETURN); 5.1334 + caller._return(getLexicalContext().getCurrentFunction().getReturnType()); 5.1335 + caller.label(breakLabel); 5.1336 + } else { 5.1337 + assert !targets.isEmpty(); 5.1338 + 5.1339 + final int low = hasReturn ? 0 : 1; 5.1340 + final int labelCount = targetCount + 1 - low; 5.1341 + final Label[] labels = new Label[labelCount]; 5.1342 5.1343 for (int i = 0; i < labelCount; i++) { 5.1344 - labels[i] = new Label("split_state_" + i); 5.1345 + labels[i] = new Label(i == 0 ? "split_return" : "split_" + targets.get(i - 1)); 5.1346 } 5.1347 - 5.1348 caller.tableswitch(low, targetCount, breakLabel, labels); 5.1349 for (int i = low; i <= targetCount; i++) { 5.1350 caller.label(labels[i - low]); 5.1351 if (i == 0) { 5.1352 - caller.loadResult(); 5.1353 - caller._return(getCurrentFunctionNode().getReturnType()); 5.1354 + caller.loadCompilerConstant(RETURN); 5.1355 + caller._return(getLexicalContext().getCurrentFunction().getReturnType()); 5.1356 } else { 5.1357 // Clear split state. 5.1358 - caller.loadScope(); 5.1359 + caller.loadCompilerConstant(SCOPE); 5.1360 caller.checkcast(Scope.class); 5.1361 caller.load(-1); 5.1362 caller.invoke(Scope.SET_SPLIT_STATE); 5.1363 - caller.splitAwareGoto(targets.get(i - 1)); 5.1364 + caller.splitAwareGoto(getLexicalContext(), targets.get(i - 1)); 5.1365 } 5.1366 } 5.1367 - 5.1368 caller.label(breakLabel); 5.1369 } 5.1370 5.1371 @@ -1788,11 +1805,7 @@ 5.1372 } 5.1373 5.1374 @Override 5.1375 - public Node enterSwitchNode(final SwitchNode switchNode) { 5.1376 - if (switchNode.testResolved()) { 5.1377 - return null; 5.1378 - } 5.1379 - 5.1380 + public boolean enterSwitchNode(final SwitchNode switchNode) { 5.1381 final Node expression = switchNode.getExpression(); 5.1382 final Symbol tag = switchNode.getTag(); 5.1383 final boolean allInteger = tag.getSymbolType().isInteger(); 5.1384 @@ -1810,7 +1823,7 @@ 5.1385 5.1386 if (cases.isEmpty()) { 5.1387 method.label(breakLabel); 5.1388 - return null; 5.1389 + return false; 5.1390 } 5.1391 5.1392 if (allInteger) { 5.1393 @@ -1916,15 +1929,11 @@ 5.1394 method.label(breakLabel); 5.1395 } 5.1396 5.1397 - return null; 5.1398 + return false; 5.1399 } 5.1400 5.1401 @Override 5.1402 - public Node enterThrowNode(final ThrowNode throwNode) { 5.1403 - if (throwNode.testResolved()) { 5.1404 - return null; 5.1405 - } 5.1406 - 5.1407 + public boolean enterThrowNode(final ThrowNode throwNode) { 5.1408 method._new(ECMAException.class).dup(); 5.1409 5.1410 final Node expression = throwNode.getExpression(); 5.1411 @@ -1943,15 +1952,11 @@ 5.1412 5.1413 method.athrow(); 5.1414 5.1415 - return null; 5.1416 + return false; 5.1417 } 5.1418 5.1419 @Override 5.1420 - public Node enterTryNode(final TryNode tryNode) { 5.1421 - if (tryNode.testResolved()) { 5.1422 - return null; 5.1423 - } 5.1424 - 5.1425 + public boolean enterTryNode(final TryNode tryNode) { 5.1426 final Block body = tryNode.getBody(); 5.1427 final List<Block> catchBlocks = tryNode.getCatchBlocks(); 5.1428 final Symbol symbol = tryNode.getException(); 5.1429 @@ -1974,74 +1979,68 @@ 5.1430 method.store(symbol); 5.1431 5.1432 for (int i = 0; i < catchBlocks.size(); i++) { 5.1433 - final Block saveBlock = getCurrentBlock(); 5.1434 final Block catchBlock = catchBlocks.get(i); 5.1435 5.1436 - setCurrentBlock(catchBlock); 5.1437 - 5.1438 - try { 5.1439 - enterBlock(catchBlock); 5.1440 - 5.1441 - final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); 5.1442 - final IdentNode exception = catchNode.getException(); 5.1443 - final Node exceptionCondition = catchNode.getExceptionCondition(); 5.1444 - final Block catchBody = catchNode.getBody(); 5.1445 - 5.1446 - if (catchNode.isSyntheticRethrow()) { 5.1447 - // Generate catch body (inlined finally) and rethrow exception 5.1448 - catchBody.accept(this); 5.1449 + //TODO this is very ugly - try not to call enter/leave methods directly 5.1450 + //better to use the implicit lexical context scoping given by the visitor's 5.1451 + //accept method. 5.1452 + getLexicalContext().push(catchBlock); 5.1453 + enterBlock(catchBlock); 5.1454 + 5.1455 + final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0); 5.1456 + final IdentNode exception = catchNode.getException(); 5.1457 + final Node exceptionCondition = catchNode.getExceptionCondition(); 5.1458 + final Block catchBody = catchNode.getBody(); 5.1459 + 5.1460 + new Store<IdentNode>(exception) { 5.1461 + @Override 5.1462 + protected void storeNonDiscard() { 5.1463 + return; 5.1464 + } 5.1465 + @Override 5.1466 + protected void evaluate() { 5.1467 + /* 5.1468 + * If caught object is an instance of ECMAException, then 5.1469 + * bind obj.thrown to the script catch var. Or else bind the 5.1470 + * caught object itself to the script catch var. 5.1471 + */ 5.1472 + final Label notEcmaException = new Label("no_ecma_exception"); 5.1473 + 5.1474 + method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException); 5.1475 + method.checkcast(ECMAException.class); //TODO is this necessary? 5.1476 + method.getField(ECMAException.THROWN); 5.1477 + method.label(notEcmaException); 5.1478 + } 5.1479 + }.store(); 5.1480 + 5.1481 + final Label next; 5.1482 + 5.1483 + if (exceptionCondition != null) { 5.1484 + next = new Label("next"); 5.1485 + load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next); 5.1486 + } else { 5.1487 + next = null; 5.1488 + } 5.1489 + 5.1490 + catchBody.accept(this); 5.1491 + 5.1492 + if (i + 1 != catchBlocks.size() && !catchBody.hasTerminalFlags()) { 5.1493 + method._goto(skip); 5.1494 + } 5.1495 + 5.1496 + if (next != null) { 5.1497 + if (i + 1 == catchBlocks.size()) { 5.1498 + // no next catch block - rethrow if condition failed 5.1499 + method._goto(skip); 5.1500 + method.label(next); 5.1501 method.load(symbol).athrow(); 5.1502 - lexicalContext.pop(catchBlock); 5.1503 - continue; 5.1504 + } else { 5.1505 + method.label(next); 5.1506 } 5.1507 - 5.1508 - new Store<IdentNode>(exception) { 5.1509 - @Override 5.1510 - protected void evaluate() { 5.1511 - /* 5.1512 - * If caught object is an instance of ECMAException, then 5.1513 - * bind obj.thrown to the script catch var. Or else bind the 5.1514 - * caught object itself to the script catch var. 5.1515 - */ 5.1516 - final Label notEcmaException = new Label("no_ecma_exception"); 5.1517 - 5.1518 - method.load(symbol).dup()._instanceof(ECMAException.class).ifeq(notEcmaException); 5.1519 - method.checkcast(ECMAException.class); //TODO is this necessary? 5.1520 - method.getField(ECMAException.THROWN); 5.1521 - method.label(notEcmaException); 5.1522 - } 5.1523 - }.store(); 5.1524 - 5.1525 - final Label next; 5.1526 - 5.1527 - if (exceptionCondition != null) { 5.1528 - next = new Label("next"); 5.1529 - load(exceptionCondition).convert(Type.BOOLEAN).ifeq(next); 5.1530 - } else { 5.1531 - next = null; 5.1532 - } 5.1533 - 5.1534 - catchBody.accept(this); 5.1535 - 5.1536 - if (i + 1 != catchBlocks.size() && !catchBody.hasTerminalFlags()) { 5.1537 - method._goto(skip); 5.1538 - } 5.1539 - 5.1540 - if (next != null) { 5.1541 - if (i + 1 == catchBlocks.size()) { 5.1542 - // no next catch block - rethrow if condition failed 5.1543 - method._goto(skip); 5.1544 - method.label(next); 5.1545 - method.load(symbol).athrow(); 5.1546 - } else { 5.1547 - method.label(next); 5.1548 - } 5.1549 - } 5.1550 - 5.1551 - leaveBlock(catchBlock); 5.1552 - } finally { 5.1553 - setCurrentBlock(saveBlock); 5.1554 } 5.1555 + 5.1556 + leaveBlock(catchBlock); 5.1557 + getLexicalContext().pop(catchBlock); 5.1558 } 5.1559 5.1560 method.label(skip); 5.1561 @@ -2049,15 +2048,15 @@ 5.1562 5.1563 // Finally body is always inlined elsewhere so it doesn't need to be emitted 5.1564 5.1565 - return null; 5.1566 + return false; 5.1567 } 5.1568 5.1569 @Override 5.1570 - public Node enterVarNode(final VarNode varNode) { 5.1571 + public boolean enterVarNode(final VarNode varNode) { 5.1572 final Node init = varNode.getInit(); 5.1573 5.1574 - if (varNode.testResolved() || init == null) { 5.1575 - return null; 5.1576 + if (init == null) { 5.1577 + return false; 5.1578 } 5.1579 5.1580 final Symbol varSymbol = varNode.getSymbol(); 5.1581 @@ -2067,7 +2066,7 @@ 5.1582 5.1583 final boolean needsScope = varSymbol.isScope(); 5.1584 if (needsScope) { 5.1585 - method.loadScope(); 5.1586 + method.loadCompilerConstant(SCOPE); 5.1587 } 5.1588 load(init); 5.1589 5.1590 @@ -2087,22 +2086,18 @@ 5.1591 method.store(varSymbol); 5.1592 } 5.1593 5.1594 - return null; 5.1595 + return false; 5.1596 } 5.1597 5.1598 @Override 5.1599 - public Node enterWhileNode(final WhileNode whileNode) { 5.1600 - if (whileNode.testResolved()) { 5.1601 - return null; 5.1602 - } 5.1603 - 5.1604 + public boolean enterWhileNode(final WhileNode whileNode) { 5.1605 final Node test = whileNode.getTest(); 5.1606 final Block body = whileNode.getBody(); 5.1607 final Label breakLabel = whileNode.getBreakLabel(); 5.1608 final Label continueLabel = whileNode.getContinueLabel(); 5.1609 final Label loopLabel = new Label("loop"); 5.1610 5.1611 - if (!(whileNode instanceof DoWhileNode)) { 5.1612 + if (!whileNode.isDoWhile()) { 5.1613 method._goto(continueLabel); 5.1614 } 5.1615 5.1616 @@ -2114,21 +2109,17 @@ 5.1617 method.label(breakLabel); 5.1618 } 5.1619 5.1620 - return null; 5.1621 + return false; 5.1622 } 5.1623 5.1624 private void closeWith() { 5.1625 - method.loadScope(); 5.1626 + method.loadCompilerConstant(SCOPE); 5.1627 method.invoke(ScriptRuntime.CLOSE_WITH); 5.1628 - method.storeScope(); 5.1629 + method.storeCompilerConstant(SCOPE); 5.1630 } 5.1631 5.1632 @Override 5.1633 - public Node enterWithNode(final WithNode withNode) { 5.1634 - if (withNode.testResolved()) { 5.1635 - return null; 5.1636 - } 5.1637 - 5.1638 + public boolean enterWithNode(final WithNode withNode) { 5.1639 final Node expression = withNode.getExpression(); 5.1640 final Node body = withNode.getBody(); 5.1641 5.1642 @@ -2139,13 +2130,13 @@ 5.1643 5.1644 method.label(tryLabel); 5.1645 5.1646 - method.loadScope(); 5.1647 + method.loadCompilerConstant(SCOPE); 5.1648 load(expression); 5.1649 5.1650 assert expression.getType().isObject() : "with expression needs to be object: " + expression; 5.1651 5.1652 method.invoke(ScriptRuntime.OPEN_WITH); 5.1653 - method.storeScope(); 5.1654 + method.storeCompilerConstant(SCOPE); 5.1655 5.1656 body.accept(this); 5.1657 5.1658 @@ -2164,40 +2155,27 @@ 5.1659 5.1660 method._try(tryLabel, endLabel, catchLabel); 5.1661 5.1662 - return null; 5.1663 + return false; 5.1664 } 5.1665 5.1666 @Override 5.1667 - public Node enterADD(final UnaryNode unaryNode) { 5.1668 - if (unaryNode.testResolved()) { 5.1669 - return null; 5.1670 - } 5.1671 - 5.1672 + public boolean enterADD(final UnaryNode unaryNode) { 5.1673 load(unaryNode.rhs()); 5.1674 assert unaryNode.rhs().getType().isNumber(); 5.1675 method.store(unaryNode.getSymbol()); 5.1676 5.1677 - return null; 5.1678 + return false; 5.1679 } 5.1680 5.1681 @Override 5.1682 - public Node enterBIT_NOT(final UnaryNode unaryNode) { 5.1683 - if (unaryNode.testResolved()) { 5.1684 - return null; 5.1685 - } 5.1686 - 5.1687 + public boolean enterBIT_NOT(final UnaryNode unaryNode) { 5.1688 load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol()); 5.1689 - 5.1690 - return null; 5.1691 + return false; 5.1692 } 5.1693 5.1694 // do this better with convert calls to method. TODO 5.1695 @Override 5.1696 - public Node enterCONVERT(final UnaryNode unaryNode) { 5.1697 - if (unaryNode.testResolved()) { 5.1698 - return null; 5.1699 - } 5.1700 - 5.1701 + public boolean enterCONVERT(final UnaryNode unaryNode) { 5.1702 final Node rhs = unaryNode.rhs(); 5.1703 final Type to = unaryNode.getType(); 5.1704 5.1705 @@ -2230,15 +2208,11 @@ 5.1706 5.1707 method.store(unaryNode.getSymbol()); 5.1708 5.1709 - return null; 5.1710 + return false; 5.1711 } 5.1712 5.1713 @Override 5.1714 - public Node enterDECINC(final UnaryNode unaryNode) { 5.1715 - if (unaryNode.testResolved()) { 5.1716 - return null; 5.1717 - } 5.1718 - 5.1719 + public boolean enterDECINC(final UnaryNode unaryNode) { 5.1720 final Node rhs = unaryNode.rhs(); 5.1721 final Type type = unaryNode.getType(); 5.1722 final TokenType tokenType = unaryNode.tokenType(); 5.1723 @@ -2282,32 +2256,28 @@ 5.1724 } 5.1725 }.store(); 5.1726 5.1727 - return null; 5.1728 + return false; 5.1729 } 5.1730 5.1731 @Override 5.1732 - public Node enterDISCARD(final UnaryNode unaryNode) { 5.1733 - if (unaryNode.testResolved()) { 5.1734 - return null; 5.1735 + public boolean enterDISCARD(final UnaryNode unaryNode) { 5.1736 + final Node rhs = unaryNode.rhs(); 5.1737 + 5.1738 + // System.err.println("**** Enter discard " + unaryNode); 5.1739 + discard.push(rhs); 5.1740 + load(rhs); 5.1741 + 5.1742 + if (discard.peek() == rhs) { 5.1743 + assert !rhs.isAssignment(); 5.1744 + method.pop(); 5.1745 + discard.pop(); 5.1746 } 5.1747 - 5.1748 - final Node rhs = unaryNode.rhs(); 5.1749 - 5.1750 - load(rhs); 5.1751 - 5.1752 - if (rhs.shouldDiscard()) { 5.1753 - method.pop(); 5.1754 - } 5.1755 - 5.1756 - return null; 5.1757 + // System.err.println("**** Leave discard " + unaryNode); 5.1758 + return false; 5.1759 } 5.1760 5.1761 @Override 5.1762 - public Node enterNEW(final UnaryNode unaryNode) { 5.1763 - if (unaryNode.testResolved()) { 5.1764 - return null; 5.1765 - } 5.1766 - 5.1767 + public boolean enterNEW(final UnaryNode unaryNode) { 5.1768 final CallNode callNode = (CallNode)unaryNode.rhs(); 5.1769 final List<Node> args = callNode.getArgs(); 5.1770 5.1771 @@ -2317,15 +2287,11 @@ 5.1772 method.dynamicNew(1 + loadArgs(args), getCallSiteFlags()); 5.1773 method.store(unaryNode.getSymbol()); 5.1774 5.1775 - return null; 5.1776 + return false; 5.1777 } 5.1778 5.1779 @Override 5.1780 - public Node enterNOT(final UnaryNode unaryNode) { 5.1781 - if (unaryNode.testResolved()) { 5.1782 - return null; 5.1783 - } 5.1784 - 5.1785 + public boolean enterNOT(final UnaryNode unaryNode) { 5.1786 final Node rhs = unaryNode.rhs(); 5.1787 5.1788 load(rhs); 5.1789 @@ -2342,18 +2308,14 @@ 5.1790 method.label(afterLabel); 5.1791 method.store(unaryNode.getSymbol()); 5.1792 5.1793 - return null; 5.1794 + return false; 5.1795 } 5.1796 5.1797 @Override 5.1798 - public Node enterSUB(final UnaryNode unaryNode) { 5.1799 - if (unaryNode.testResolved()) { 5.1800 - return null; 5.1801 - } 5.1802 - 5.1803 + public boolean enterSUB(final UnaryNode unaryNode) { 5.1804 load(unaryNode.rhs()).neg().store(unaryNode.getSymbol()); 5.1805 5.1806 - return null; 5.1807 + return false; 5.1808 } 5.1809 5.1810 private Node enterNumericAdd(final Node lhs, final Node rhs, final Type type, final Symbol symbol) { 5.1811 @@ -2366,11 +2328,7 @@ 5.1812 } 5.1813 5.1814 @Override 5.1815 - public Node enterADD(final BinaryNode binaryNode) { 5.1816 - if (binaryNode.testResolved()) { 5.1817 - return null; 5.1818 - } 5.1819 - 5.1820 + public boolean enterADD(final BinaryNode binaryNode) { 5.1821 final Node lhs = binaryNode.lhs(); 5.1822 final Node rhs = binaryNode.rhs(); 5.1823 5.1824 @@ -2384,14 +2342,10 @@ 5.1825 method.store(binaryNode.getSymbol()); 5.1826 } 5.1827 5.1828 - return null; 5.1829 + return false; 5.1830 } 5.1831 5.1832 - private Node enterAND_OR(final BinaryNode binaryNode) { 5.1833 - if (binaryNode.testResolved()) { 5.1834 - return null; 5.1835 - } 5.1836 - 5.1837 + private boolean enterAND_OR(final BinaryNode binaryNode) { 5.1838 final Node lhs = binaryNode.lhs(); 5.1839 final Node rhs = binaryNode.rhs(); 5.1840 5.1841 @@ -2410,20 +2364,16 @@ 5.1842 method.label(skip); 5.1843 method.store(binaryNode.getSymbol()); 5.1844 5.1845 - return null; 5.1846 + return false; 5.1847 } 5.1848 5.1849 @Override 5.1850 - public Node enterAND(final BinaryNode binaryNode) { 5.1851 + public boolean enterAND(final BinaryNode binaryNode) { 5.1852 return enterAND_OR(binaryNode); 5.1853 } 5.1854 5.1855 @Override 5.1856 - public Node enterASSIGN(final BinaryNode binaryNode) { 5.1857 - if (binaryNode.testResolved()) { 5.1858 - return null; 5.1859 - } 5.1860 - 5.1861 + public boolean enterASSIGN(final BinaryNode binaryNode) { 5.1862 final Node lhs = binaryNode.lhs(); 5.1863 final Node rhs = binaryNode.rhs(); 5.1864 5.1865 @@ -2442,7 +2392,7 @@ 5.1866 } 5.1867 }.store(); 5.1868 5.1869 - return null; 5.1870 + return false; 5.1871 } 5.1872 5.1873 /** 5.1874 @@ -2473,14 +2423,6 @@ 5.1875 this.opType = opType; 5.1876 } 5.1877 5.1878 - @Override 5.1879 - public void store() { 5.1880 - if (assignNode.testResolved()) { 5.1881 - return; 5.1882 - } 5.1883 - super.store(); 5.1884 - } 5.1885 - 5.1886 protected abstract void op(); 5.1887 5.1888 @Override 5.1889 @@ -2493,35 +2435,43 @@ 5.1890 } 5.1891 5.1892 @Override 5.1893 - public Node enterASSIGN_ADD(final BinaryNode binaryNode) { 5.1894 + public boolean enterASSIGN_ADD(final BinaryNode binaryNode) { 5.1895 assert RuntimeNode.Request.ADD.canSpecialize(); 5.1896 + final Type lhsType = binaryNode.lhs().getType(); 5.1897 + final Type rhsType = binaryNode.rhs().getType(); 5.1898 final boolean specialize = binaryNode.getType() == Type.OBJECT; 5.1899 5.1900 new AssignOp(binaryNode) { 5.1901 - @Override 5.1902 - protected boolean isSelfModifying() { 5.1903 - return !specialize; 5.1904 - } 5.1905 5.1906 @Override 5.1907 protected void op() { 5.1908 - method.add(); 5.1909 + if (specialize) { 5.1910 + method.dynamicRuntimeCall( 5.1911 + new SpecializedRuntimeNode( 5.1912 + Request.ADD, 5.1913 + new Type[] { 5.1914 + lhsType, 5.1915 + rhsType, 5.1916 + }, 5.1917 + Type.OBJECT).getInitialName(), 5.1918 + Type.OBJECT, 5.1919 + Request.ADD); 5.1920 + } else { 5.1921 + method.add(); 5.1922 + } 5.1923 } 5.1924 5.1925 @Override 5.1926 protected void evaluate() { 5.1927 - if (specialize && specializationCheck(Request.ADD, assignNode, Arrays.asList(assignNode.lhs(), assignNode.rhs()))) { 5.1928 - return; 5.1929 - } 5.1930 super.evaluate(); 5.1931 } 5.1932 }.store(); 5.1933 5.1934 - return null; 5.1935 + return false; 5.1936 } 5.1937 5.1938 @Override 5.1939 - public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 5.1940 + public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 5.1941 new AssignOp(Type.INT, binaryNode) { 5.1942 @Override 5.1943 protected void op() { 5.1944 @@ -2529,11 +2479,11 @@ 5.1945 } 5.1946 }.store(); 5.1947 5.1948 - return null; 5.1949 + return false; 5.1950 } 5.1951 5.1952 @Override 5.1953 - public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 5.1954 + public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 5.1955 new AssignOp(Type.INT, binaryNode) { 5.1956 @Override 5.1957 protected void op() { 5.1958 @@ -2541,11 +2491,11 @@ 5.1959 } 5.1960 }.store(); 5.1961 5.1962 - return null; 5.1963 + return false; 5.1964 } 5.1965 5.1966 @Override 5.1967 - public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 5.1968 + public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 5.1969 new AssignOp(Type.INT, binaryNode) { 5.1970 @Override 5.1971 protected void op() { 5.1972 @@ -2553,11 +2503,11 @@ 5.1973 } 5.1974 }.store(); 5.1975 5.1976 - return null; 5.1977 + return false; 5.1978 } 5.1979 5.1980 @Override 5.1981 - public Node enterASSIGN_DIV(final BinaryNode binaryNode) { 5.1982 + public boolean enterASSIGN_DIV(final BinaryNode binaryNode) { 5.1983 new AssignOp(binaryNode) { 5.1984 @Override 5.1985 protected void op() { 5.1986 @@ -2565,11 +2515,11 @@ 5.1987 } 5.1988 }.store(); 5.1989 5.1990 - return null; 5.1991 + return false; 5.1992 } 5.1993 5.1994 @Override 5.1995 - public Node enterASSIGN_MOD(final BinaryNode binaryNode) { 5.1996 + public boolean enterASSIGN_MOD(final BinaryNode binaryNode) { 5.1997 new AssignOp(binaryNode) { 5.1998 @Override 5.1999 protected void op() { 5.2000 @@ -2577,11 +2527,11 @@ 5.2001 } 5.2002 }.store(); 5.2003 5.2004 - return null; 5.2005 + return false; 5.2006 } 5.2007 5.2008 @Override 5.2009 - public Node enterASSIGN_MUL(final BinaryNode binaryNode) { 5.2010 + public boolean enterASSIGN_MUL(final BinaryNode binaryNode) { 5.2011 new AssignOp(binaryNode) { 5.2012 @Override 5.2013 protected void op() { 5.2014 @@ -2589,11 +2539,11 @@ 5.2015 } 5.2016 }.store(); 5.2017 5.2018 - return null; 5.2019 + return false; 5.2020 } 5.2021 5.2022 @Override 5.2023 - public Node enterASSIGN_SAR(final BinaryNode binaryNode) { 5.2024 + public boolean enterASSIGN_SAR(final BinaryNode binaryNode) { 5.2025 new AssignOp(Type.INT, binaryNode) { 5.2026 @Override 5.2027 protected void op() { 5.2028 @@ -2601,11 +2551,11 @@ 5.2029 } 5.2030 }.store(); 5.2031 5.2032 - return null; 5.2033 + return false; 5.2034 } 5.2035 5.2036 @Override 5.2037 - public Node enterASSIGN_SHL(final BinaryNode binaryNode) { 5.2038 + public boolean enterASSIGN_SHL(final BinaryNode binaryNode) { 5.2039 new AssignOp(Type.INT, binaryNode) { 5.2040 @Override 5.2041 protected void op() { 5.2042 @@ -2613,11 +2563,11 @@ 5.2043 } 5.2044 }.store(); 5.2045 5.2046 - return null; 5.2047 + return false; 5.2048 } 5.2049 5.2050 @Override 5.2051 - public Node enterASSIGN_SHR(final BinaryNode binaryNode) { 5.2052 + public boolean enterASSIGN_SHR(final BinaryNode binaryNode) { 5.2053 new AssignOp(Type.INT, binaryNode) { 5.2054 @Override 5.2055 protected void op() { 5.2056 @@ -2626,11 +2576,11 @@ 5.2057 } 5.2058 }.store(); 5.2059 5.2060 - return null; 5.2061 + return false; 5.2062 } 5.2063 5.2064 @Override 5.2065 - public Node enterASSIGN_SUB(final BinaryNode binaryNode) { 5.2066 + public boolean enterASSIGN_SUB(final BinaryNode binaryNode) { 5.2067 new AssignOp(binaryNode) { 5.2068 @Override 5.2069 protected void op() { 5.2070 @@ -2638,7 +2588,7 @@ 5.2071 } 5.2072 }.store(); 5.2073 5.2074 - return null; 5.2075 + return false; 5.2076 } 5.2077 5.2078 /** 5.2079 @@ -2649,9 +2599,6 @@ 5.2080 protected abstract void op(); 5.2081 5.2082 protected void evaluate(final BinaryNode node) { 5.2083 - if (node.testResolved()) { 5.2084 - return; 5.2085 - } 5.2086 load(node.lhs()); 5.2087 load(node.rhs()); 5.2088 op(); 5.2089 @@ -2660,7 +2607,7 @@ 5.2090 } 5.2091 5.2092 @Override 5.2093 - public Node enterBIT_AND(final BinaryNode binaryNode) { 5.2094 + public boolean enterBIT_AND(final BinaryNode binaryNode) { 5.2095 new BinaryArith() { 5.2096 @Override 5.2097 protected void op() { 5.2098 @@ -2668,11 +2615,11 @@ 5.2099 } 5.2100 }.evaluate(binaryNode); 5.2101 5.2102 - return null; 5.2103 + return false; 5.2104 } 5.2105 5.2106 @Override 5.2107 - public Node enterBIT_OR(final BinaryNode binaryNode) { 5.2108 + public boolean enterBIT_OR(final BinaryNode binaryNode) { 5.2109 new BinaryArith() { 5.2110 @Override 5.2111 protected void op() { 5.2112 @@ -2680,11 +2627,11 @@ 5.2113 } 5.2114 }.evaluate(binaryNode); 5.2115 5.2116 - return null; 5.2117 + return false; 5.2118 } 5.2119 5.2120 @Override 5.2121 - public Node enterBIT_XOR(final BinaryNode binaryNode) { 5.2122 + public boolean enterBIT_XOR(final BinaryNode binaryNode) { 5.2123 new BinaryArith() { 5.2124 @Override 5.2125 protected void op() { 5.2126 @@ -2692,14 +2639,10 @@ 5.2127 } 5.2128 }.evaluate(binaryNode); 5.2129 5.2130 - return null; 5.2131 + return false; 5.2132 } 5.2133 5.2134 - private Node enterComma(final BinaryNode binaryNode) { 5.2135 - if (binaryNode.testResolved()) { 5.2136 - return null; 5.2137 - } 5.2138 - 5.2139 + private boolean enterComma(final BinaryNode binaryNode) { 5.2140 final Node lhs = binaryNode.lhs(); 5.2141 final Node rhs = binaryNode.rhs(); 5.2142 5.2143 @@ -2707,21 +2650,21 @@ 5.2144 load(rhs); 5.2145 method.store(binaryNode.getSymbol()); 5.2146 5.2147 - return null; 5.2148 + return false; 5.2149 } 5.2150 5.2151 @Override 5.2152 - public Node enterCOMMARIGHT(final BinaryNode binaryNode) { 5.2153 + public boolean enterCOMMARIGHT(final BinaryNode binaryNode) { 5.2154 return enterComma(binaryNode); 5.2155 } 5.2156 5.2157 @Override 5.2158 - public Node enterCOMMALEFT(final BinaryNode binaryNode) { 5.2159 + public boolean enterCOMMALEFT(final BinaryNode binaryNode) { 5.2160 return enterComma(binaryNode); 5.2161 } 5.2162 5.2163 @Override 5.2164 - public Node enterDIV(final BinaryNode binaryNode) { 5.2165 + public boolean enterDIV(final BinaryNode binaryNode) { 5.2166 new BinaryArith() { 5.2167 @Override 5.2168 protected void op() { 5.2169 @@ -2729,10 +2672,10 @@ 5.2170 } 5.2171 }.evaluate(binaryNode); 5.2172 5.2173 - return null; 5.2174 + return false; 5.2175 } 5.2176 5.2177 - private Node enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) { 5.2178 + private boolean enterCmp(final Node lhs, final Node rhs, final Condition cond, final Type type, final Symbol symbol) { 5.2179 final Type lhsType = lhs.getType(); 5.2180 final Type rhsType = rhs.getType(); 5.2181 5.2182 @@ -2758,48 +2701,45 @@ 5.2183 method.convert(type); 5.2184 method.store(symbol); 5.2185 5.2186 - return null; 5.2187 + return false; 5.2188 } 5.2189 5.2190 - private Node enterCmp(final BinaryNode binaryNode, final Condition cond) { 5.2191 - if (binaryNode.testResolved()) { 5.2192 - return null; 5.2193 - } 5.2194 + private boolean enterCmp(final BinaryNode binaryNode, final Condition cond) { 5.2195 return enterCmp(binaryNode.lhs(), binaryNode.rhs(), cond, binaryNode.getType(), binaryNode.getSymbol()); 5.2196 } 5.2197 5.2198 @Override 5.2199 - public Node enterEQ(final BinaryNode binaryNode) { 5.2200 + public boolean enterEQ(final BinaryNode binaryNode) { 5.2201 return enterCmp(binaryNode, Condition.EQ); 5.2202 } 5.2203 5.2204 @Override 5.2205 - public Node enterEQ_STRICT(final BinaryNode binaryNode) { 5.2206 + public boolean enterEQ_STRICT(final BinaryNode binaryNode) { 5.2207 return enterCmp(binaryNode, Condition.EQ); 5.2208 } 5.2209 5.2210 @Override 5.2211 - public Node enterGE(final BinaryNode binaryNode) { 5.2212 + public boolean enterGE(final BinaryNode binaryNode) { 5.2213 return enterCmp(binaryNode, Condition.GE); 5.2214 } 5.2215 5.2216 @Override 5.2217 - public Node enterGT(final BinaryNode binaryNode) { 5.2218 + public boolean enterGT(final BinaryNode binaryNode) { 5.2219 return enterCmp(binaryNode, Condition.GT); 5.2220 } 5.2221 5.2222 @Override 5.2223 - public Node enterLE(final BinaryNode binaryNode) { 5.2224 + public boolean enterLE(final BinaryNode binaryNode) { 5.2225 return enterCmp(binaryNode, Condition.LE); 5.2226 } 5.2227 5.2228 @Override 5.2229 - public Node enterLT(final BinaryNode binaryNode) { 5.2230 + public boolean enterLT(final BinaryNode binaryNode) { 5.2231 return enterCmp(binaryNode, Condition.LT); 5.2232 } 5.2233 5.2234 @Override 5.2235 - public Node enterMOD(final BinaryNode binaryNode) { 5.2236 + public boolean enterMOD(final BinaryNode binaryNode) { 5.2237 new BinaryArith() { 5.2238 @Override 5.2239 protected void op() { 5.2240 @@ -2807,11 +2747,11 @@ 5.2241 } 5.2242 }.evaluate(binaryNode); 5.2243 5.2244 - return null; 5.2245 + return false; 5.2246 } 5.2247 5.2248 @Override 5.2249 - public Node enterMUL(final BinaryNode binaryNode) { 5.2250 + public boolean enterMUL(final BinaryNode binaryNode) { 5.2251 new BinaryArith() { 5.2252 @Override 5.2253 protected void op() { 5.2254 @@ -2819,26 +2759,26 @@ 5.2255 } 5.2256 }.evaluate(binaryNode); 5.2257 5.2258 - return null; 5.2259 + return false; 5.2260 } 5.2261 5.2262 @Override 5.2263 - public Node enterNE(final BinaryNode binaryNode) { 5.2264 + public boolean enterNE(final BinaryNode binaryNode) { 5.2265 return enterCmp(binaryNode, Condition.NE); 5.2266 } 5.2267 5.2268 @Override 5.2269 - public Node enterNE_STRICT(final BinaryNode binaryNode) { 5.2270 + public boolean enterNE_STRICT(final BinaryNode binaryNode) { 5.2271 return enterCmp(binaryNode, Condition.NE); 5.2272 } 5.2273 5.2274 @Override 5.2275 - public Node enterOR(final BinaryNode binaryNode) { 5.2276 + public boolean enterOR(final BinaryNode binaryNode) { 5.2277 return enterAND_OR(binaryNode); 5.2278 } 5.2279 5.2280 @Override 5.2281 - public Node enterSAR(final BinaryNode binaryNode) { 5.2282 + public boolean enterSAR(final BinaryNode binaryNode) { 5.2283 new BinaryArith() { 5.2284 @Override 5.2285 protected void op() { 5.2286 @@ -2846,11 +2786,11 @@ 5.2287 } 5.2288 }.evaluate(binaryNode); 5.2289 5.2290 - return null; 5.2291 + return false; 5.2292 } 5.2293 5.2294 @Override 5.2295 - public Node enterSHL(final BinaryNode binaryNode) { 5.2296 + public boolean enterSHL(final BinaryNode binaryNode) { 5.2297 new BinaryArith() { 5.2298 @Override 5.2299 protected void op() { 5.2300 @@ -2858,11 +2798,11 @@ 5.2301 } 5.2302 }.evaluate(binaryNode); 5.2303 5.2304 - return null; 5.2305 + return false; 5.2306 } 5.2307 5.2308 @Override 5.2309 - public Node enterSHR(final BinaryNode binaryNode) { 5.2310 + public boolean enterSHR(final BinaryNode binaryNode) { 5.2311 new BinaryArith() { 5.2312 @Override 5.2313 protected void op() { 5.2314 @@ -2871,11 +2811,11 @@ 5.2315 } 5.2316 }.evaluate(binaryNode); 5.2317 5.2318 - return null; 5.2319 + return false; 5.2320 } 5.2321 5.2322 @Override 5.2323 - public Node enterSUB(final BinaryNode binaryNode) { 5.2324 + public boolean enterSUB(final BinaryNode binaryNode) { 5.2325 new BinaryArith() { 5.2326 @Override 5.2327 protected void op() { 5.2328 @@ -2883,18 +2823,11 @@ 5.2329 } 5.2330 }.evaluate(binaryNode); 5.2331 5.2332 - return null; 5.2333 + return false; 5.2334 } 5.2335 5.2336 - /* 5.2337 - * Ternary visits. 5.2338 - */ 5.2339 @Override 5.2340 - public Node enterTernaryNode(final TernaryNode ternaryNode) { 5.2341 - if (ternaryNode.testResolved()) { 5.2342 - return null; 5.2343 - } 5.2344 - 5.2345 + public boolean enterTernaryNode(final TernaryNode ternaryNode) { 5.2346 final Node lhs = ternaryNode.lhs(); 5.2347 final Node rhs = ternaryNode.rhs(); 5.2348 final Node third = ternaryNode.third(); 5.2349 @@ -2926,7 +2859,7 @@ 5.2350 method.label(exitLabel); 5.2351 method.store(symbol); 5.2352 5.2353 - return null; 5.2354 + return false; 5.2355 } 5.2356 5.2357 /** 5.2358 @@ -2955,7 +2888,7 @@ 5.2359 if (scopeCalls.containsKey(scopeCall)) { 5.2360 return scopeCalls.get(scopeCall); 5.2361 } 5.2362 - scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall")); 5.2363 + scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); 5.2364 scopeCalls.put(scopeCall, scopeCall); 5.2365 return scopeCall; 5.2366 } 5.2367 @@ -2974,7 +2907,7 @@ 5.2368 if (scopeCalls.containsKey(scopeCall)) { 5.2369 return scopeCalls.get(scopeCall); 5.2370 } 5.2371 - scopeCall.setClassAndName(getCurrentCompileUnit(), getCurrentFunctionNode().uniqueName("scopeCall")); 5.2372 + scopeCall.setClassAndName(unit, getLexicalContext().getCurrentFunction().uniqueName("scopeCall")); 5.2373 scopeCalls.put(scopeCall, scopeCall); 5.2374 return scopeCall; 5.2375 } 5.2376 @@ -3037,9 +2970,6 @@ 5.2377 /** The target node to store to, e.g. x */ 5.2378 private final Node target; 5.2379 5.2380 - /** Should the result always be discarded, no matter what? */ 5.2381 - private final boolean alwaysDiscard; 5.2382 - 5.2383 /** How deep on the stack do the arguments go if this generates an indy call */ 5.2384 private int depth; 5.2385 5.2386 @@ -3055,7 +2985,6 @@ 5.2387 protected Store(final T assignNode, final Node target) { 5.2388 this.assignNode = assignNode; 5.2389 this.target = target; 5.2390 - this.alwaysDiscard = assignNode == target; 5.2391 } 5.2392 5.2393 /** 5.2394 @@ -3077,21 +3006,21 @@ 5.2395 5.2396 private void prologue() { 5.2397 final Symbol targetSymbol = target.getSymbol(); 5.2398 - final Symbol scopeSymbol = getCurrentFunctionNode().getScopeNode().getSymbol(); 5.2399 + final Symbol scopeSymbol = getLexicalContext().getCurrentFunction().compilerConstant(SCOPE); 5.2400 5.2401 /** 5.2402 * This loads the parts of the target, e.g base and index. they are kept 5.2403 * on the stack throughout the store and used at the end to execute it 5.2404 */ 5.2405 5.2406 - target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 5.2407 + target.accept(new NodeVisitor() { 5.2408 @Override 5.2409 - public Node enterIdentNode(final IdentNode node) { 5.2410 + public boolean enterIdentNode(final IdentNode node) { 5.2411 if (targetSymbol.isScope()) { 5.2412 method.load(scopeSymbol); 5.2413 depth++; 5.2414 } 5.2415 - return null; 5.2416 + return false; 5.2417 } 5.2418 5.2419 private void enterBaseNode() { 5.2420 @@ -3109,13 +3038,13 @@ 5.2421 } 5.2422 5.2423 @Override 5.2424 - public Node enterAccessNode(final AccessNode node) { 5.2425 + public boolean enterAccessNode(final AccessNode node) { 5.2426 enterBaseNode(); 5.2427 - return null; 5.2428 + return false; 5.2429 } 5.2430 5.2431 @Override 5.2432 - public Node enterIndexNode(final IndexNode node) { 5.2433 + public boolean enterIndexNode(final IndexNode node) { 5.2434 enterBaseNode(); 5.2435 5.2436 final Node index = node.getIndex(); 5.2437 @@ -3131,14 +3060,14 @@ 5.2438 method.dup(1); 5.2439 } 5.2440 5.2441 - return null; 5.2442 + return false; 5.2443 } 5.2444 5.2445 }); 5.2446 } 5.2447 5.2448 private Symbol quickSymbol(final Type type) { 5.2449 - return quickSymbol(type, QUICK_PREFIX.tag()); 5.2450 + return quickSymbol(type, QUICK_PREFIX.symbolName()); 5.2451 } 5.2452 5.2453 /** 5.2454 @@ -3151,22 +3080,28 @@ 5.2455 * @return the quick symbol 5.2456 */ 5.2457 private Symbol quickSymbol(final Type type, final String prefix) { 5.2458 - final String name = getCurrentFunctionNode().uniqueName(prefix); 5.2459 - final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL, null, null); 5.2460 + final String name = getLexicalContext().getCurrentFunction().uniqueName(prefix); 5.2461 + final Symbol symbol = new Symbol(name, IS_TEMP | IS_INTERNAL); 5.2462 5.2463 symbol.setType(type); 5.2464 - symbol.setSlot(getCurrentBlock().getFrame().getSlotCount()); 5.2465 + final int quickSlot = nextFreeSlots[nextFreeSlotsSize - 1]; 5.2466 + nextFreeSlots[nextFreeSlotsSize - 1] = quickSlot + symbol.slotCount(); 5.2467 + symbol.setSlot(quickSlot); 5.2468 5.2469 return symbol; 5.2470 } 5.2471 5.2472 // store the result that "lives on" after the op, e.g. "i" in i++ postfix. 5.2473 protected void storeNonDiscard() { 5.2474 - if (assignNode.shouldDiscard() || alwaysDiscard) { 5.2475 - assignNode.setDiscard(false); 5.2476 + if (discard.peek() == assignNode) { 5.2477 + assert assignNode.isAssignment(); 5.2478 + discard.pop(); 5.2479 return; 5.2480 } 5.2481 5.2482 + //System.err.println("Store with out discard that shouldn't just return " + assignNode); 5.2483 + //new Throwable().printStackTrace(); 5.2484 + 5.2485 final Symbol symbol = assignNode.getSymbol(); 5.2486 if (symbol.hasSlot()) { 5.2487 method.dup().store(symbol); 5.2488 @@ -3191,22 +3126,22 @@ 5.2489 */ 5.2490 method.convert(target.getType()); 5.2491 5.2492 - target.accept(new NodeVisitor(getCurrentCompileUnit(), method) { 5.2493 + target.accept(new NodeVisitor() { 5.2494 @Override 5.2495 - protected Node enterDefault(Node node) { 5.2496 + protected boolean enterDefault(Node node) { 5.2497 throw new AssertionError("Unexpected node " + node + " in store epilogue"); 5.2498 } 5.2499 5.2500 @Override 5.2501 - public Node enterUnaryNode(final UnaryNode node) { 5.2502 - if(node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { 5.2503 + public boolean enterUnaryNode(final UnaryNode node) { 5.2504 + if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { 5.2505 method.convert(node.rhs().getType()); 5.2506 } 5.2507 - return node; 5.2508 + return true; 5.2509 } 5.2510 5.2511 @Override 5.2512 - public Node enterIdentNode(final IdentNode node) { 5.2513 + public boolean enterIdentNode(final IdentNode node) { 5.2514 final Symbol symbol = node.getSymbol(); 5.2515 assert symbol != null; 5.2516 if (symbol.isScope()) { 5.2517 @@ -3218,20 +3153,20 @@ 5.2518 } else { 5.2519 method.store(symbol); 5.2520 } 5.2521 - return null; 5.2522 + return false; 5.2523 5.2524 } 5.2525 5.2526 @Override 5.2527 - public Node enterAccessNode(final AccessNode node) { 5.2528 + public boolean enterAccessNode(final AccessNode node) { 5.2529 method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); 5.2530 - return null; 5.2531 + return false; 5.2532 } 5.2533 5.2534 @Override 5.2535 - public Node enterIndexNode(final IndexNode node) { 5.2536 + public boolean enterIndexNode(final IndexNode node) { 5.2537 method.dynamicSetIndex(getCallSiteFlags()); 5.2538 - return null; 5.2539 + return false; 5.2540 } 5.2541 }); 5.2542 5.2543 @@ -3250,10 +3185,23 @@ 5.2544 method.load(quick); 5.2545 } 5.2546 } 5.2547 - 5.2548 } 5.2549 5.2550 - private void newFunctionObject(final FunctionNode functionNode) { 5.2551 + private void newFunctionObject(final FunctionNode functionNode, final FunctionNode originalFunctionNode) { 5.2552 + final LexicalContext lc = getLexicalContext(); 5.2553 + assert lc.peek() == functionNode; 5.2554 + // We don't emit a ScriptFunction on stack for: 5.2555 + // 1. the outermost compiled function (as there's no code being generated in its outer context that'd need it 5.2556 + // as a callee), and 5.2557 + // 2. for functions that are immediately called upon definition and they don't need a callee, e.g. (function(){})(). 5.2558 + // Such immediately-called functions are invoked using INVOKESTATIC (see enterFunctionNode() of the embedded 5.2559 + // visitor of enterCallNode() for details), and if they don't need a callee, they don't have it on their 5.2560 + // static method's parameter list. 5.2561 + if(lc.getOutermostFunction() == functionNode || 5.2562 + (!functionNode.needsCallee()) && lc.isFunctionDefinedInCurrentCall(originalFunctionNode)) { 5.2563 + return; 5.2564 + } 5.2565 + 5.2566 final boolean isLazy = functionNode.isLazy(); 5.2567 5.2568 new ObjectCreator(this, new ArrayList<String>(), new ArrayList<Symbol>(), false, false) { 5.2569 @@ -3265,7 +3213,7 @@ 5.2570 loadConstant(new RecompilableScriptFunctionData(functionNode, compiler.getCodeInstaller(), Compiler.binaryName(getClassName()), makeMap())); 5.2571 5.2572 if (isLazy || functionNode.needsParentScope()) { 5.2573 - m.loadScope(); 5.2574 + m.loadCompilerConstant(SCOPE); 5.2575 } else { 5.2576 m.loadNull(); 5.2577 }
6.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri Apr 19 18:23:00 2013 +0530 6.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri Apr 19 16:11:16 2013 +0200 6.3 @@ -15,6 +15,7 @@ 6.4 import java.util.HashSet; 6.5 import java.util.Set; 6.6 import jdk.nashorn.internal.codegen.types.Type; 6.7 +import jdk.nashorn.internal.ir.Block; 6.8 import jdk.nashorn.internal.ir.CallNode; 6.9 import jdk.nashorn.internal.ir.FunctionNode; 6.10 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 6.11 @@ -29,8 +30,8 @@ 6.12 import jdk.nashorn.internal.runtime.Timing; 6.13 6.14 /** 6.15 - * A compilation phase is a step in the processes of turning a JavaScript FunctionNode 6.16 - * into bytecode. It has an optional return value. 6.17 + * A compilation phase is a step in the processes of turning a JavaScript 6.18 + * FunctionNode into bytecode. It has an optional return value. 6.19 */ 6.20 enum CompilationPhase { 6.21 6.22 @@ -41,77 +42,87 @@ 6.23 */ 6.24 LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { 6.25 @Override 6.26 - void transform(final Compiler compiler, final FunctionNode fn) { 6.27 + FunctionNode transform(final Compiler compiler, final FunctionNode fn0) { 6.28 6.29 /* 6.30 - * For lazy compilation, we might be given a node previously marked as lazy 6.31 - * to compile as the outermost function node in the compiler. Unmark it 6.32 - * so it can be compiled and not cause recursion. Make sure the return type 6.33 - * is unknown so it can be correctly deduced. Return types are always 6.34 - * Objects in Lazy nodes as we haven't got a change to generate code for 6.35 - * them and decude its parameter specialization 6.36 + * For lazy compilation, we might be given a node previously marked 6.37 + * as lazy to compile as the outermost function node in the 6.38 + * compiler. Unmark it so it can be compiled and not cause 6.39 + * recursion. Make sure the return type is unknown so it can be 6.40 + * correctly deduced. Return types are always Objects in Lazy nodes 6.41 + * as we haven't got a change to generate code for them and decude 6.42 + * its parameter specialization 6.43 * 6.44 - * TODO: in the future specializations from a callsite will be passed here 6.45 - * so we can generate a better non-lazy version of a function from a trampoline 6.46 + * TODO: in the future specializations from a callsite will be 6.47 + * passed here so we can generate a better non-lazy version of a 6.48 + * function from a trampoline 6.49 */ 6.50 - //compute the signature from the callsite - todo - now just clone object params 6.51 + 6.52 final FunctionNode outermostFunctionNode = compiler.getFunctionNode(); 6.53 - outermostFunctionNode.setIsLazy(false); 6.54 - outermostFunctionNode.setReturnType(Type.UNKNOWN); 6.55 + assert outermostFunctionNode == fn0; 6.56 6.57 final Set<FunctionNode> neverLazy = new HashSet<>(); 6.58 - final Set<FunctionNode> lazy = new HashSet<>(); 6.59 + final Set<FunctionNode> lazy = new HashSet<>(); 6.60 6.61 - outermostFunctionNode.accept(new NodeVisitor() { 6.62 - // self references are done with invokestatic and thus cannot have trampolines - never lazy 6.63 + FunctionNode newFunctionNode = outermostFunctionNode; 6.64 + 6.65 + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeVisitor() { 6.66 + // self references are done with invokestatic and thus cannot 6.67 + // have trampolines - never lazy 6.68 @Override 6.69 - public Node enterCallNode(final CallNode node) { 6.70 + public boolean enterCallNode(final CallNode node) { 6.71 final Node callee = node.getFunction(); 6.72 if (callee instanceof FunctionNode) { 6.73 neverLazy.add(((FunctionNode)callee)); 6.74 - return null; 6.75 + return false; 6.76 } 6.77 - return node; 6.78 + return true; 6.79 } 6.80 6.81 + //any function that isn't the outermost one must be marked as lazy 6.82 @Override 6.83 - public Node enterFunctionNode(final FunctionNode node) { 6.84 - if (node == outermostFunctionNode) { 6.85 - return node; 6.86 - } 6.87 + public boolean enterFunctionNode(final FunctionNode node) { 6.88 assert compiler.isLazy(); 6.89 lazy.add(node); 6.90 - 6.91 - //also needs scope, potentially needs arguments etc etc 6.92 - 6.93 - return node; 6.94 + return true; 6.95 } 6.96 }); 6.97 6.98 + //at least one method is non lazy - the outermost one 6.99 + neverLazy.add(newFunctionNode); 6.100 + 6.101 for (final FunctionNode node : neverLazy) { 6.102 - Compiler.LOG.fine("Marking " + node.getName() + " as non lazy, as it's a self reference"); 6.103 - node.setIsLazy(false); 6.104 + Compiler.LOG.fine( 6.105 + "Marking ", 6.106 + node.getName(), 6.107 + " as non lazy, as it's a self reference"); 6.108 lazy.remove(node); 6.109 } 6.110 6.111 - outermostFunctionNode.accept(new NodeOperatorVisitor() { 6.112 - private final LexicalContext lexicalContext = new LexicalContext(); 6.113 + newFunctionNode = (FunctionNode)newFunctionNode.accept(new NodeOperatorVisitor() { 6.114 @Override 6.115 - public Node enterFunctionNode(FunctionNode functionNode) { 6.116 - lexicalContext.push(functionNode); 6.117 - if(lazy.contains(functionNode)) { 6.118 - Compiler.LOG.fine("Marking " + functionNode.getName() + " as lazy"); 6.119 - functionNode.setIsLazy(true); 6.120 - lexicalContext.getParentFunction(functionNode).setHasLazyChildren(); 6.121 + public Node leaveFunctionNode(final FunctionNode functionNode) { 6.122 + final LexicalContext lc = getLexicalContext(); 6.123 + if (lazy.contains(functionNode)) { 6.124 + Compiler.LOG.fine( 6.125 + "Marking ", 6.126 + functionNode.getName(), 6.127 + " as lazy"); 6.128 + final FunctionNode parent = lc.getParentFunction(functionNode); 6.129 + assert parent != null; 6.130 + lc.setFlag(parent, FunctionNode.HAS_LAZY_CHILDREN); 6.131 + lc.setFlag(parent.getBody(), Block.NEEDS_SCOPE); 6.132 + lc.setFlag(functionNode, FunctionNode.IS_LAZY); 6.133 + return functionNode; 6.134 } 6.135 - return functionNode; 6.136 - } 6.137 - @Override 6.138 - public Node leaveFunctionNode(FunctionNode functionNode) { 6.139 - lexicalContext.pop(functionNode); 6.140 - return functionNode; 6.141 + 6.142 + return functionNode. 6.143 + clearFlag(lc, FunctionNode.IS_LAZY). 6.144 + setReturnType(lc, Type.UNKNOWN); 6.145 } 6.146 }); 6.147 + 6.148 + return newFunctionNode; 6.149 } 6.150 6.151 @Override 6.152 @@ -121,13 +132,13 @@ 6.153 }, 6.154 6.155 /* 6.156 - * Constant folding pass 6.157 - * Simple constant folding that will make elementary constructs go away 6.158 + * Constant folding pass Simple constant folding that will make elementary 6.159 + * constructs go away 6.160 */ 6.161 CONSTANT_FOLDING_PHASE(EnumSet.of(INITIALIZED, PARSED)) { 6.162 @Override 6.163 - void transform(final Compiler compiler, final FunctionNode fn) { 6.164 - fn.accept(new FoldConstants()); 6.165 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.166 + return (FunctionNode)fn.accept(new FoldConstants()); 6.167 } 6.168 6.169 @Override 6.170 @@ -137,18 +148,16 @@ 6.171 }, 6.172 6.173 /* 6.174 - * Lower (Control flow pass) 6.175 - * Finalizes the control flow. Clones blocks for finally constructs and 6.176 - * similar things. Establishes termination criteria for nodes 6.177 - * Guarantee return instructions to method making sure control flow 6.178 - * cannot fall off the end. Replacing high level nodes with lower such 6.179 - * as runtime nodes where applicable. 6.180 - * 6.181 + * Lower (Control flow pass) Finalizes the control flow. Clones blocks for 6.182 + * finally constructs and similar things. Establishes termination criteria 6.183 + * for nodes Guarantee return instructions to method making sure control 6.184 + * flow cannot fall off the end. Replacing high level nodes with lower such 6.185 + * as runtime nodes where applicable. 6.186 */ 6.187 LOWERING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED)) { 6.188 @Override 6.189 - void transform(final Compiler compiler, final FunctionNode fn) { 6.190 - fn.accept(new Lower()); 6.191 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.192 + return (FunctionNode)fn.accept(new Lower()); 6.193 } 6.194 6.195 @Override 6.196 @@ -158,13 +167,27 @@ 6.197 }, 6.198 6.199 /* 6.200 - * Attribution 6.201 - * Assign symbols and types to all nodes. 6.202 + * Attribution Assign symbols and types to all nodes. 6.203 */ 6.204 ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { 6.205 @Override 6.206 - void transform(final Compiler compiler, final FunctionNode fn) { 6.207 - fn.accept(new Attr()); 6.208 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.209 + return (FunctionNode)initReturnTypes(fn).accept(new Attr()); 6.210 + } 6.211 + 6.212 + /** 6.213 + * Pessimistically set all lazy functions' return types to Object 6.214 + * @param functionNode node where to start iterating 6.215 + */ 6.216 + private FunctionNode initReturnTypes(final FunctionNode functionNode) { 6.217 + return (FunctionNode)functionNode.accept(new NodeVisitor() { 6.218 + @Override 6.219 + public Node leaveFunctionNode(final FunctionNode node) { 6.220 + return node.isLazy() ? 6.221 + node.setReturnType(getLexicalContext(), Type.OBJECT) : 6.222 + node.setReturnType(getLexicalContext(), Type.UNKNOWN); 6.223 + } 6.224 + }); 6.225 } 6.226 6.227 @Override 6.228 @@ -174,25 +197,35 @@ 6.229 }, 6.230 6.231 /* 6.232 - * Splitter 6.233 - * Split the AST into several compile units based on a size heuristic 6.234 - * Splitter needs attributed AST for weight calculations (e.g. is 6.235 - * a + b a ScriptRuntime.ADD with call overhead or a dadd with much 6.236 - * less). Split IR can lead to scope information being changed. 6.237 + * Splitter Split the AST into several compile units based on a size 6.238 + * heuristic Splitter needs attributed AST for weight calculations (e.g. is 6.239 + * a + b a ScriptRuntime.ADD with call overhead or a dadd with much less). 6.240 + * Split IR can lead to scope information being changed. 6.241 */ 6.242 SPLITTING_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR)) { 6.243 @Override 6.244 - void transform(final Compiler compiler, final FunctionNode fn) { 6.245 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.246 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); 6.247 6.248 - new Splitter(compiler, fn, outermostCompileUnit).split(); 6.249 + final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); 6.250 6.251 - assert fn.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + fn.getCompileUnit() + ") != " + outermostCompileUnit; 6.252 + assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; 6.253 6.254 - if (fn.isStrictMode()) { 6.255 + if (newFunctionNode.isStrict()) { 6.256 assert compiler.getStrictMode(); 6.257 compiler.setStrictMode(true); 6.258 } 6.259 + 6.260 + /* 6.261 + newFunctionNode.accept(new NodeVisitor() { 6.262 + @Override 6.263 + public boolean enterFunctionNode(final FunctionNode functionNode) { 6.264 + assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit"; 6.265 + return true; 6.266 + } 6.267 + });*/ 6.268 + 6.269 + return newFunctionNode; 6.270 } 6.271 6.272 @Override 6.273 @@ -204,30 +237,32 @@ 6.274 /* 6.275 * FinalizeTypes 6.276 * 6.277 - * This pass finalizes the types for nodes. If Attr created wider types than 6.278 - * known during the first pass, convert nodes are inserted or access nodes 6.279 - * are specialized where scope accesses. 6.280 + * This pass finalizes the types for nodes. If Attr created wider types than 6.281 + * known during the first pass, convert nodes are inserted or access nodes 6.282 + * are specialized where scope accesses. 6.283 * 6.284 - * Runtime nodes may be removed and primitivized or reintroduced depending 6.285 - * on information that was established in Attr. 6.286 + * Runtime nodes may be removed and primitivized or reintroduced depending 6.287 + * on information that was established in Attr. 6.288 * 6.289 * Contract: all variables must have slot assignments and scope assignments 6.290 * before type finalization. 6.291 */ 6.292 TYPE_FINALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT)) { 6.293 @Override 6.294 - void transform(final Compiler compiler, final FunctionNode fn) { 6.295 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.296 final ScriptEnvironment env = compiler.getEnv(); 6.297 6.298 - fn.accept(new FinalizeTypes()); 6.299 + final FunctionNode newFunctionNode = (FunctionNode)fn.accept(new FinalizeTypes()); 6.300 6.301 if (env._print_lower_ast) { 6.302 - env.getErr().println(new ASTWriter(fn)); 6.303 + env.getErr().println(new ASTWriter(newFunctionNode)); 6.304 } 6.305 6.306 if (env._print_lower_parse) { 6.307 - env.getErr().println(new PrintVisitor(fn)); 6.308 - } 6.309 + env.getErr().println(new PrintVisitor(newFunctionNode)); 6.310 + } 6.311 + 6.312 + return newFunctionNode; 6.313 } 6.314 6.315 @Override 6.316 @@ -239,31 +274,21 @@ 6.317 /* 6.318 * Bytecode generation: 6.319 * 6.320 - * Generate the byte code class(es) resulting from the compiled FunctionNode 6.321 + * Generate the byte code class(es) resulting from the compiled FunctionNode 6.322 */ 6.323 BYTECODE_GENERATION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED, ATTR, SPLIT, FINALIZED)) { 6.324 @Override 6.325 - void transform(final Compiler compiler, final FunctionNode fn) { 6.326 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 6.327 final ScriptEnvironment env = compiler.getEnv(); 6.328 + FunctionNode newFunctionNode = fn; 6.329 6.330 try { 6.331 final CodeGenerator codegen = new CodeGenerator(compiler); 6.332 - fn.accept(codegen); 6.333 + newFunctionNode = (FunctionNode)newFunctionNode.accept(codegen); 6.334 codegen.generateScopeCalls(); 6.335 - fn.accept(new NodeOperatorVisitor() { 6.336 - @Override 6.337 - public Node enterFunctionNode(FunctionNode functionNode) { 6.338 - if(functionNode.isLazy()) { 6.339 - functionNode.resetResolved(); 6.340 - return null; 6.341 - } 6.342 - return fn; 6.343 - } 6.344 - }); 6.345 - 6.346 } catch (final VerifyError e) { 6.347 if (env._verify_code || env._print_code) { 6.348 - env.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage()); 6.349 + env.getErr().println(e.getClass().getSimpleName() + ": " + e.getMessage()); 6.350 if (env._dump_on_error) { 6.351 e.printStackTrace(env.getErr()); 6.352 } 6.353 @@ -283,25 +308,25 @@ 6.354 6.355 compiler.addClass(className, bytecode); 6.356 6.357 - //should could be printed to stderr for generate class? 6.358 + // should could be printed to stderr for generate class? 6.359 if (env._print_code) { 6.360 final StringBuilder sb = new StringBuilder(); 6.361 - sb.append("class: " + className). 6.362 - append('\n'). 6.363 - append(ClassEmitter.disassemble(bytecode)). 6.364 - append("====="); 6.365 + sb.append("class: " + className).append('\n') 6.366 + .append(ClassEmitter.disassemble(bytecode)) 6.367 + .append("====="); 6.368 env.getErr().println(sb); 6.369 } 6.370 6.371 - //should we verify the generated code? 6.372 + // should we verify the generated code? 6.373 if (env._verify_code) { 6.374 compiler.getCodeInstaller().verify(bytecode); 6.375 } 6.376 6.377 - //should code be dumped to disk - only valid in compile_only mode? 6.378 + // should code be dumped to disk - only valid in compile_only 6.379 + // mode? 6.380 if (env._dest_dir != null && env._compile_only) { 6.381 final String fileName = className.replace('.', File.separatorChar) + ".class"; 6.382 - final int index = fileName.lastIndexOf(File.separatorChar); 6.383 + final int index = fileName.lastIndexOf(File.separatorChar); 6.384 6.385 if (index != -1) { 6.386 final File dir = new File(fileName.substring(0, index)); 6.387 @@ -314,11 +339,18 @@ 6.388 fos.write(bytecode); 6.389 } 6.390 } catch (final IOException e) { 6.391 - Compiler.LOG.warning("Skipping class dump for " + className + ": " + ECMAErrors.getMessage("io.error.cant.write", dir.toString())); 6.392 + Compiler.LOG.warning("Skipping class dump for ", 6.393 + className, 6.394 + ": ", 6.395 + ECMAErrors.getMessage( 6.396 + "io.error.cant.write", 6.397 + dir.toString())); 6.398 } 6.399 } 6.400 } 6.401 } 6.402 + 6.403 + return newFunctionNode; 6.404 } 6.405 6.406 @Override 6.407 @@ -340,26 +372,28 @@ 6.408 return functionNode.hasState(pre); 6.409 } 6.410 6.411 - protected void begin(final FunctionNode functionNode) { 6.412 + protected FunctionNode begin(final FunctionNode functionNode) { 6.413 if (pre != null) { 6.414 - //check that everything in pre is present 6.415 + // check that everything in pre is present 6.416 for (final CompilationState state : pre) { 6.417 assert functionNode.hasState(state); 6.418 } 6.419 - //check that nothing else is present 6.420 + // check that nothing else is present 6.421 for (final CompilationState state : CompilationState.values()) { 6.422 assert !(functionNode.hasState(state) && !pre.contains(state)); 6.423 } 6.424 } 6.425 6.426 startTime = System.currentTimeMillis(); 6.427 + return functionNode; 6.428 } 6.429 6.430 - protected void end(final FunctionNode functionNode) { 6.431 + protected FunctionNode end(final FunctionNode functionNode) { 6.432 endTime = System.currentTimeMillis(); 6.433 Timing.accumulateTime(toString(), endTime - startTime); 6.434 6.435 isFinished = true; 6.436 + return functionNode; 6.437 } 6.438 6.439 boolean isFinished() { 6.440 @@ -374,15 +408,13 @@ 6.441 return endTime; 6.442 } 6.443 6.444 - abstract void transform(final Compiler compiler, final FunctionNode functionNode) throws CompilationException; 6.445 + abstract FunctionNode transform(final Compiler compiler, final FunctionNode functionNode) throws CompilationException; 6.446 6.447 - final void apply(final Compiler compiler, final FunctionNode functionNode) throws CompilationException { 6.448 + final FunctionNode apply(final Compiler compiler, final FunctionNode functionNode) throws CompilationException { 6.449 if (!isApplicable(functionNode)) { 6.450 - throw new CompilationException("compile phase not applicable: " + this); 6.451 + throw new CompilationException("compile phase not applicable: " + this + " to " + functionNode.getName() + " state=" + functionNode.getState()); 6.452 } 6.453 - begin(functionNode); 6.454 - transform(compiler, functionNode); 6.455 - end(functionNode); 6.456 + return end(transform(compiler, begin(functionNode))); 6.457 } 6.458 6.459 }
7.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Fri Apr 19 18:23:00 2013 +0530 7.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Fri Apr 19 16:11:16 2013 +0200 7.3 @@ -25,12 +25,16 @@ 7.4 7.5 package jdk.nashorn.internal.codegen; 7.6 7.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 7.8 +import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 7.9 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; 7.10 import static jdk.nashorn.internal.codegen.CompilerConstants.DEFAULT_SCRIPT_NAME; 7.11 import static jdk.nashorn.internal.codegen.CompilerConstants.LAZY; 7.12 +import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 7.13 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 7.14 import static jdk.nashorn.internal.codegen.CompilerConstants.SOURCE; 7.15 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 7.16 +import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 7.17 7.18 import java.io.File; 7.19 import java.lang.reflect.Field; 7.20 @@ -46,13 +50,12 @@ 7.21 import java.util.Map.Entry; 7.22 import java.util.Set; 7.23 import java.util.logging.Level; 7.24 + 7.25 import jdk.internal.dynalink.support.NameCodec; 7.26 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 7.27 import jdk.nashorn.internal.codegen.types.Type; 7.28 import jdk.nashorn.internal.ir.FunctionNode; 7.29 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 7.30 -import jdk.nashorn.internal.ir.Node; 7.31 -import jdk.nashorn.internal.ir.visitor.NodeVisitor; 7.32 import jdk.nashorn.internal.runtime.CodeInstaller; 7.33 import jdk.nashorn.internal.runtime.DebugLogger; 7.34 import jdk.nashorn.internal.runtime.ScriptEnvironment; 7.35 @@ -80,8 +83,6 @@ 7.36 7.37 private final ConstantData constantData; 7.38 7.39 - private final FunctionNode functionNode; 7.40 - 7.41 private final CompilationSequence sequence; 7.42 7.43 private final ScriptEnvironment env; 7.44 @@ -90,6 +91,8 @@ 7.45 7.46 private boolean strict; 7.47 7.48 + private FunctionNode functionNode; 7.49 + 7.50 private CodeInstaller<ScriptEnvironment> installer; 7.51 7.52 /** logger for compiler, trampolines, splits and related code generation events 7.53 @@ -103,8 +106,12 @@ 7.54 * during a compile. 7.55 */ 7.56 private static String[] RESERVED_NAMES = { 7.57 - SCOPE.tag(), 7.58 - THIS.tag() 7.59 + SCOPE.symbolName(), 7.60 + THIS.symbolName(), 7.61 + RETURN.symbolName(), 7.62 + CALLEE.symbolName(), 7.63 + VARARGS.symbolName(), 7.64 + ARGUMENTS.symbolName() 7.65 }; 7.66 7.67 /** 7.68 @@ -186,7 +193,7 @@ 7.69 7.70 private static String lazyTag(final FunctionNode functionNode) { 7.71 if (functionNode.isLazy()) { 7.72 - return '$' + LAZY.tag() + '$' + functionNode.getName(); 7.73 + return '$' + LAZY.symbolName() + '$' + functionNode.getName(); 7.74 } 7.75 return ""; 7.76 } 7.77 @@ -205,13 +212,13 @@ 7.78 this.functionNode = functionNode; 7.79 this.sequence = sequence; 7.80 this.installer = installer; 7.81 - this.strict = strict || functionNode.isStrictMode(); 7.82 + this.strict = strict || functionNode.isStrict(); 7.83 this.constantData = new ConstantData(); 7.84 this.compileUnits = new HashSet<>(); 7.85 this.bytecode = new HashMap<>(); 7.86 7.87 final StringBuilder sb = new StringBuilder(); 7.88 - sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.tag() + lazyTag(functionNode))). 7.89 + sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))). 7.90 append('$'). 7.91 append(safeSourceName(functionNode.getSource())); 7.92 7.93 @@ -253,9 +260,9 @@ 7.94 * Execute the compilation this Compiler was created with 7.95 * @params param types if known, for specialization 7.96 * @throws CompilationException if something goes wrong 7.97 - * @return this compiler, for possible chaining 7.98 + * @return function node that results from code transforms 7.99 */ 7.100 - public Compiler compile() throws CompilationException { 7.101 + public FunctionNode compile() throws CompilationException { 7.102 return compile(null); 7.103 } 7.104 7.105 @@ -263,9 +270,9 @@ 7.106 * Execute the compilation this Compiler was created with 7.107 * @param paramTypes param types if known, for specialization 7.108 * @throws CompilationException if something goes wrong 7.109 - * @return this compiler, for possible chaining 7.110 + * @return function node that results from code transforms 7.111 */ 7.112 - public Compiler compile(final Class<?> paramTypes) throws CompilationException { 7.113 + public FunctionNode compile(final Class<?> paramTypes) throws CompilationException { 7.114 for (final String reservedName : RESERVED_NAMES) { 7.115 functionNode.uniqueName(reservedName); 7.116 } 7.117 @@ -276,7 +283,7 @@ 7.118 long time = 0L; 7.119 7.120 for (final CompilationPhase phase : sequence) { 7.121 - phase.apply(this, functionNode); 7.122 + this.functionNode = phase.apply(this, functionNode); 7.123 7.124 final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; 7.125 time += duration; 7.126 @@ -295,7 +302,7 @@ 7.127 append(" ms "); 7.128 } 7.129 7.130 - LOG.fine(sb.toString()); 7.131 + LOG.fine(sb); 7.132 } 7.133 } 7.134 7.135 @@ -311,14 +318,14 @@ 7.136 append(" ms"); 7.137 } 7.138 7.139 - LOG.info(sb.toString()); 7.140 + LOG.info(sb); 7.141 } 7.142 7.143 - return this; 7.144 + return functionNode; 7.145 } 7.146 7.147 private Class<?> install(final String className, final byte[] code) { 7.148 - LOG.fine("Installing class " + className); 7.149 + LOG.fine("Installing class ", className); 7.150 7.151 final Class<?> clazz = installer.install(Compiler.binaryName(className), code); 7.152 7.153 @@ -330,8 +337,8 @@ 7.154 @Override 7.155 public Void run() throws Exception { 7.156 //use reflection to write source and constants table to installed classes 7.157 - final Field sourceField = clazz.getDeclaredField(SOURCE.tag()); 7.158 - final Field constantsField = clazz.getDeclaredField(CONSTANTS.tag()); 7.159 + final Field sourceField = clazz.getDeclaredField(SOURCE.symbolName()); 7.160 + final Field constantsField = clazz.getDeclaredField(CONSTANTS.symbolName()); 7.161 sourceField.setAccessible(true); 7.162 constantsField.setAccessible(true); 7.163 sourceField.set(null, source); 7.164 @@ -380,17 +387,6 @@ 7.165 unit.setCode(installedClasses.get(unit.getUnitClassName())); 7.166 } 7.167 7.168 - functionNode.accept(new NodeVisitor() { 7.169 - @Override 7.170 - public Node enterFunctionNode(final FunctionNode node) { 7.171 - if (node.isLazy()) { 7.172 - return null; 7.173 - } 7.174 - node.setState(CompilationState.INSTALLED); 7.175 - return node; 7.176 - } 7.177 - }); 7.178 - 7.179 final StringBuilder sb; 7.180 if (LOG.isEnabled()) { 7.181 sb = new StringBuilder(); 7.182 @@ -416,7 +412,7 @@ 7.183 } 7.184 7.185 if (sb != null) { 7.186 - LOG.info(sb.toString()); 7.187 + LOG.info(sb); 7.188 } 7.189 7.190 return rootClass; 7.191 @@ -495,7 +491,7 @@ 7.192 private CompileUnit addCompileUnit(final String unitClassName, final long initialWeight) { 7.193 final CompileUnit compileUnit = initCompileUnit(unitClassName, initialWeight); 7.194 compileUnits.add(compileUnit); 7.195 - LOG.fine("Added compile unit " + compileUnit); 7.196 + LOG.fine("Added compile unit ", compileUnit); 7.197 return compileUnit; 7.198 } 7.199
8.1 --- a/src/jdk/nashorn/internal/codegen/CompilerConstants.java Fri Apr 19 18:23:00 2013 +0530 8.2 +++ b/src/jdk/nashorn/internal/codegen/CompilerConstants.java Fri Apr 19 16:11:16 2013 +0200 8.3 @@ -52,9 +52,6 @@ 8.4 /** lazy prefix for classes of jitted methods */ 8.5 LAZY("Lazy"), 8.6 8.7 - /** leaf tag used for functions that require no scope */ 8.8 - LEAF("__leaf__"), 8.9 - 8.10 /** constructor name */ 8.11 INIT("<init>"), 8.12 8.13 @@ -96,7 +93,7 @@ 8.14 SCOPE("__scope__", ScriptObject.class, 2), 8.15 8.16 /** the return value variable name were intermediate results are stored for scripts */ 8.17 - SCRIPT_RETURN("__return__"), 8.18 + RETURN("__return__"), 8.19 8.20 /** the callee value variable when necessary */ 8.21 CALLEE("__callee__", ScriptFunction.class), 8.22 @@ -167,30 +164,30 @@ 8.23 /** get array suffix */ 8.24 GET_ARRAY_SUFFIX("$array"); 8.25 8.26 - private final String tag; 8.27 + private final String symbolName; 8.28 private final Class<?> type; 8.29 private final int slot; 8.30 8.31 private CompilerConstants() { 8.32 - this.tag = name(); 8.33 + this.symbolName = name(); 8.34 this.type = null; 8.35 this.slot = -1; 8.36 } 8.37 8.38 - private CompilerConstants(final String tag) { 8.39 - this(tag, -1); 8.40 + private CompilerConstants(final String symbolName) { 8.41 + this(symbolName, -1); 8.42 } 8.43 8.44 - private CompilerConstants(final String tag, final int slot) { 8.45 - this(tag, null, slot); 8.46 + private CompilerConstants(final String symbolName, final int slot) { 8.47 + this(symbolName, null, slot); 8.48 } 8.49 8.50 - private CompilerConstants(final String tag, final Class<?> type) { 8.51 - this(tag, type, -1); 8.52 + private CompilerConstants(final String symbolName, final Class<?> type) { 8.53 + this(symbolName, type, -1); 8.54 } 8.55 8.56 - private CompilerConstants(final String tag, final Class<?> type, final int slot) { 8.57 - this.tag = tag; 8.58 + private CompilerConstants(final String symbolName, final Class<?> type, final int slot) { 8.59 + this.symbolName = symbolName; 8.60 this.type = type; 8.61 this.slot = slot; 8.62 } 8.63 @@ -202,8 +199,8 @@ 8.64 * 8.65 * @return the tag 8.66 */ 8.67 - public final String tag() { 8.68 - return tag; 8.69 + public final String symbolName() { 8.70 + return symbolName; 8.71 } 8.72 8.73 /** 8.74 @@ -277,7 +274,7 @@ 8.75 * @return Call representing void constructor for type 8.76 */ 8.77 public static Call constructorNoLookup(final Class<?> clazz) { 8.78 - return specialCallNoLookup(clazz, INIT.tag(), void.class); 8.79 + return specialCallNoLookup(clazz, INIT.symbolName(), void.class); 8.80 } 8.81 8.82 /** 8.83 @@ -290,7 +287,7 @@ 8.84 * @return Call representing constructor for type 8.85 */ 8.86 public static Call constructorNoLookup(final String className, final Class<?>... ptypes) { 8.87 - return specialCallNoLookup(className, INIT.tag(), methodDescriptor(void.class, ptypes)); 8.88 + return specialCallNoLookup(className, INIT.symbolName(), methodDescriptor(void.class, ptypes)); 8.89 } 8.90 8.91 /** 8.92 @@ -303,7 +300,7 @@ 8.93 * @return Call representing constructor for type 8.94 */ 8.95 public static Call constructorNoLookup(final Class<?> clazz, final Class<?>... ptypes) { 8.96 - return specialCallNoLookup(clazz, INIT.tag(), void.class, ptypes); 8.97 + return specialCallNoLookup(clazz, INIT.symbolName(), void.class, ptypes); 8.98 } 8.99 8.100 /**
9.1 --- a/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java Fri Apr 19 18:23:00 2013 +0530 9.2 +++ b/src/jdk/nashorn/internal/codegen/FieldObjectCreator.java Fri Apr 19 16:11:16 2013 +0200 9.3 @@ -26,6 +26,7 @@ 9.4 package jdk.nashorn.internal.codegen; 9.5 9.6 import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 9.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 9.8 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; 9.9 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; 9.10 import static jdk.nashorn.internal.codegen.types.Type.OBJECT; 9.11 @@ -86,7 +87,7 @@ 9.12 * @param method the method emitter to use 9.13 */ 9.14 protected void loadScope(final MethodEmitter method) { 9.15 - method.loadScope(); 9.16 + method.loadCompilerConstant(SCOPE); 9.17 } 9.18 9.19 /** 9.20 @@ -105,7 +106,7 @@ 9.21 loadScope(method); 9.22 9.23 if (hasArguments()) { 9.24 - method.loadArguments(); 9.25 + method.loadCompilerConstant(ARGUMENTS); 9.26 method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class, ARGUMENTS.type())); 9.27 } else { 9.28 method.invoke(constructorNoLookup(getClassName(), PropertyMap.class, ScriptObject.class));
10.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Fri Apr 19 18:23:00 2013 +0530 10.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Fri Apr 19 16:11:16 2013 +0200 10.3 @@ -25,18 +25,22 @@ 10.4 10.5 package jdk.nashorn.internal.codegen; 10.6 10.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 10.8 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 10.9 + 10.10 +import java.util.ArrayList; 10.11 import java.util.HashSet; 10.12 +import java.util.Iterator; 10.13 import java.util.List; 10.14 + 10.15 import jdk.nashorn.internal.codegen.types.Type; 10.16 import jdk.nashorn.internal.ir.AccessNode; 10.17 import jdk.nashorn.internal.ir.Assignment; 10.18 import jdk.nashorn.internal.ir.BinaryNode; 10.19 import jdk.nashorn.internal.ir.Block; 10.20 import jdk.nashorn.internal.ir.CallNode; 10.21 -import jdk.nashorn.internal.ir.CallNode.EvalArgs; 10.22 import jdk.nashorn.internal.ir.CaseNode; 10.23 import jdk.nashorn.internal.ir.CatchNode; 10.24 -import jdk.nashorn.internal.ir.DoWhileNode; 10.25 import jdk.nashorn.internal.ir.ExecuteNode; 10.26 import jdk.nashorn.internal.ir.ForNode; 10.27 import jdk.nashorn.internal.ir.FunctionNode; 10.28 @@ -85,18 +89,11 @@ 10.29 10.30 private static final DebugLogger LOG = new DebugLogger("finalize"); 10.31 10.32 - private final LexicalContext lexicalContext = new LexicalContext(); 10.33 - 10.34 FinalizeTypes() { 10.35 } 10.36 10.37 @Override 10.38 public Node leaveCallNode(final CallNode callNode) { 10.39 - final EvalArgs evalArgs = callNode.getEvalArgs(); 10.40 - if (evalArgs != null) { 10.41 - evalArgs.setCode(evalArgs.getCode().accept(this)); 10.42 - } 10.43 - 10.44 // AccessSpecializer - call return type may change the access for this location 10.45 final Node function = callNode.getFunction(); 10.46 if (function instanceof FunctionNode) { 10.47 @@ -133,8 +130,7 @@ 10.48 @Override 10.49 public Node leaveNEW(final UnaryNode unaryNode) { 10.50 assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject(); 10.51 - ((CallNode)unaryNode.rhs()).setIsNew(); 10.52 - return unaryNode; 10.53 + return unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew()); 10.54 } 10.55 10.56 @Override 10.57 @@ -254,7 +250,7 @@ 10.58 @Override 10.59 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 10.60 assert binaryNode.getSymbol() != null; 10.61 - final BinaryNode newBinaryNode = (BinaryNode)binaryNode.setRHS(discard(binaryNode.rhs())); 10.62 + final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs())); 10.63 // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed 10.64 // in that case, update the node type as well 10.65 propagateType(newBinaryNode, newBinaryNode.lhs().getType()); 10.66 @@ -354,41 +350,30 @@ 10.67 } 10.68 10.69 @Override 10.70 - public Node enterBlock(final Block block) { 10.71 - lexicalContext.push(block); 10.72 + public boolean enterBlock(final Block block) { 10.73 updateSymbols(block); 10.74 - return block; 10.75 + return true; 10.76 } 10.77 10.78 + /* 10.79 @Override 10.80 - public Node leaveBlock(Block block) { 10.81 - lexicalContext.pop(block); 10.82 - return super.leaveBlock(block); 10.83 - } 10.84 + public Node leaveBlock(final Block block) { 10.85 + final LexicalContext lc = getLexicalContext(); 10.86 + return block;//.setFlag(lc, lc.getFlags(block)); 10.87 + }*/ 10.88 10.89 @Override 10.90 public Node leaveCatchNode(final CatchNode catchNode) { 10.91 final Node exceptionCondition = catchNode.getExceptionCondition(); 10.92 if (exceptionCondition != null) { 10.93 - catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); 10.94 + return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); 10.95 } 10.96 return catchNode; 10.97 } 10.98 10.99 @Override 10.100 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 10.101 - return enterWhileNode(doWhileNode); 10.102 - } 10.103 - 10.104 - @Override 10.105 - public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 10.106 - return leaveWhileNode(doWhileNode); 10.107 - } 10.108 - 10.109 - @Override 10.110 public Node leaveExecuteNode(final ExecuteNode executeNode) { 10.111 - executeNode.setExpression(discard(executeNode.getExpression())); 10.112 - return executeNode; 10.113 + return executeNode.setExpression(discard(executeNode.getExpression())); 10.114 } 10.115 10.116 @Override 10.117 @@ -397,69 +382,54 @@ 10.118 final Node test = forNode.getTest(); 10.119 final Node modify = forNode.getModify(); 10.120 10.121 + final LexicalContext lc = getLexicalContext(); 10.122 + 10.123 if (forNode.isForIn()) { 10.124 - forNode.setModify(convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 10.125 - return forNode; 10.126 + return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 10.127 } 10.128 + assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getLexicalContext().getCurrentFunction(); 10.129 10.130 - if (init != null) { 10.131 - forNode.setInit(discard(init)); 10.132 - } 10.133 - 10.134 - if (test != null) { 10.135 - forNode.setTest(convert(test, Type.BOOLEAN)); 10.136 - } else { 10.137 - assert forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + getCurrentFunctionNode(); 10.138 - } 10.139 - 10.140 - if (modify != null) { 10.141 - forNode.setModify(discard(modify)); 10.142 - } 10.143 - 10.144 - return forNode; 10.145 + return forNode. 10.146 + setInit(lc, init == null ? null : discard(init)). 10.147 + setTest(lc, test == null ? null : convert(test, Type.BOOLEAN)). 10.148 + setModify(lc, modify == null ? null : discard(modify)); 10.149 } 10.150 10.151 @Override 10.152 - public Node enterFunctionNode(final FunctionNode functionNode) { 10.153 + public boolean enterFunctionNode(final FunctionNode functionNode) { 10.154 if (functionNode.isLazy()) { 10.155 - return null; 10.156 + return false; 10.157 } 10.158 10.159 - lexicalContext.push(functionNode); 10.160 // If the function doesn't need a callee, we ensure its __callee__ symbol doesn't get a slot. We can't do 10.161 // this earlier, as access to scoped variables, self symbol, etc. in previous phases can all trigger the 10.162 // need for the callee. 10.163 if (!functionNode.needsCallee()) { 10.164 - functionNode.getCalleeNode().getSymbol().setNeedsSlot(false); 10.165 + functionNode.compilerConstant(CALLEE).setNeedsSlot(false); 10.166 } 10.167 // Similar reasoning applies to __scope__ symbol: if the function doesn't need either parent scope or its 10.168 // own scope, we ensure it doesn't get a slot, but we can't determine whether it needs a scope earlier than 10.169 // this phase. 10.170 - if (!(functionNode.needsScope() || functionNode.needsParentScope())) { 10.171 - functionNode.getScopeNode().getSymbol().setNeedsSlot(false); 10.172 + if (!(functionNode.getBody().needsScope() || functionNode.needsParentScope())) { 10.173 + functionNode.compilerConstant(SCOPE).setNeedsSlot(false); 10.174 } 10.175 10.176 - updateSymbols(functionNode); 10.177 - functionNode.setState(CompilationState.FINALIZED); 10.178 - 10.179 - return functionNode; 10.180 + return true; 10.181 } 10.182 10.183 @Override 10.184 - public Node leaveFunctionNode(FunctionNode functionNode) { 10.185 - lexicalContext.pop(functionNode); 10.186 - return super.leaveFunctionNode(functionNode); 10.187 + public Node leaveFunctionNode(final FunctionNode functionNode) { 10.188 + return functionNode.setState(getLexicalContext(), CompilationState.FINALIZED); 10.189 } 10.190 10.191 @Override 10.192 public Node leaveIfNode(final IfNode ifNode) { 10.193 - ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); 10.194 - return ifNode; 10.195 + return ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); 10.196 } 10.197 10.198 @SuppressWarnings("rawtypes") 10.199 @Override 10.200 - public Node enterLiteralNode(final LiteralNode literalNode) { 10.201 + public boolean enterLiteralNode(final LiteralNode literalNode) { 10.202 if (literalNode instanceof ArrayLiteralNode) { 10.203 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; 10.204 final Node[] array = arrayLiteralNode.getValue(); 10.205 @@ -473,14 +443,14 @@ 10.206 } 10.207 } 10.208 10.209 - return null; 10.210 + return false; 10.211 } 10.212 10.213 @Override 10.214 public Node leaveReturnNode(final ReturnNode returnNode) { 10.215 final Node expr = returnNode.getExpression(); 10.216 if (expr != null) { 10.217 - returnNode.setExpression(convert(expr, getCurrentFunctionNode().getReturnType())); 10.218 + return returnNode.setExpression(convert(expr, getLexicalContext().getCurrentFunction().getReturnType())); 10.219 } 10.220 return returnNode; 10.221 } 10.222 @@ -496,21 +466,24 @@ 10.223 10.224 @Override 10.225 public Node leaveSwitchNode(final SwitchNode switchNode) { 10.226 + final boolean allInteger = switchNode.getTag().getSymbolType().isInteger(); 10.227 + 10.228 + if (allInteger) { 10.229 + return switchNode; 10.230 + } 10.231 + 10.232 final Node expression = switchNode.getExpression(); 10.233 final List<CaseNode> cases = switchNode.getCases(); 10.234 - final boolean allInteger = switchNode.getTag().getSymbolType().isInteger(); 10.235 + final List<CaseNode> newCases = new ArrayList<>(); 10.236 10.237 - if (!allInteger) { 10.238 - switchNode.setExpression(convert(expression, Type.OBJECT)); 10.239 - for (final CaseNode caseNode : cases) { 10.240 - final Node test = caseNode.getTest(); 10.241 - if (test != null) { 10.242 - caseNode.setTest(convert(test, Type.OBJECT)); 10.243 - } 10.244 - } 10.245 + for (final CaseNode caseNode : cases) { 10.246 + final Node test = caseNode.getTest(); 10.247 + newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode); 10.248 } 10.249 10.250 - return switchNode; 10.251 + return switchNode. 10.252 + setExpression(getLexicalContext(), convert(expression, Type.OBJECT)). 10.253 + setCases(getLexicalContext(), newCases); 10.254 } 10.255 10.256 @Override 10.257 @@ -520,8 +493,7 @@ 10.258 10.259 @Override 10.260 public Node leaveThrowNode(final ThrowNode throwNode) { 10.261 - throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT)); 10.262 - return throwNode; 10.263 + return throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT)); 10.264 } 10.265 10.266 @Override 10.267 @@ -544,23 +516,24 @@ 10.268 public Node leaveWhileNode(final WhileNode whileNode) { 10.269 final Node test = whileNode.getTest(); 10.270 if (test != null) { 10.271 - whileNode.setTest(convert(test, Type.BOOLEAN)); 10.272 + return whileNode.setTest(getLexicalContext(), convert(test, Type.BOOLEAN)); 10.273 } 10.274 return whileNode; 10.275 } 10.276 10.277 @Override 10.278 public Node leaveWithNode(final WithNode withNode) { 10.279 - withNode.setExpression(convert(withNode.getExpression(), Type.OBJECT)); 10.280 - return withNode; 10.281 + return withNode.setExpression(getLexicalContext(), convert(withNode.getExpression(), Type.OBJECT)); 10.282 } 10.283 10.284 private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) { 10.285 - if (!symbol.isScope()) { 10.286 - LOG.finest("updateSymbols: " + symbol + " => scope, because all vars in " + functionNode.getName() + " are in scope"); 10.287 - } 10.288 - if (loseSlot && symbol.hasSlot()) { 10.289 - LOG.finest("updateSymbols: " + symbol + " => no slot, because all vars in " + functionNode.getName() + " are in scope"); 10.290 + if (LOG.isEnabled()) { 10.291 + if (!symbol.isScope()) { 10.292 + LOG.finest("updateSymbols: ", symbol, " => scope, because all vars in ", functionNode.getName(), " are in scope"); 10.293 + } 10.294 + if (loseSlot && symbol.hasSlot()) { 10.295 + LOG.finest("updateSymbols: ", symbol, " => no slot, because all vars in ", functionNode.getName(), " are in scope"); 10.296 + } 10.297 } 10.298 } 10.299 10.300 @@ -574,29 +547,28 @@ 10.301 return; // nothing to do 10.302 } 10.303 10.304 - final FunctionNode functionNode = lexicalContext.getFunction(block); 10.305 - assert !(block instanceof FunctionNode) || functionNode == block; 10.306 + final LexicalContext lc = getLexicalContext(); 10.307 + final FunctionNode functionNode = lc.getFunction(block); 10.308 + final boolean allVarsInScope = functionNode.allVarsInScope(); 10.309 + final boolean isVarArg = functionNode.isVarArg(); 10.310 10.311 - final List<Symbol> symbols = block.getFrame().getSymbols(); 10.312 - final boolean allVarsInScope = functionNode.allVarsInScope(); 10.313 - final boolean isVarArg = functionNode.isVarArg(); 10.314 - 10.315 - for (final Symbol symbol : symbols) { 10.316 - if (symbol.isInternal() || symbol.isThis()) { 10.317 + for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 10.318 + final Symbol symbol = iter.next(); 10.319 + if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { 10.320 continue; 10.321 } 10.322 10.323 if (symbol.isVar()) { 10.324 if (allVarsInScope || symbol.isScope()) { 10.325 updateSymbolsLog(functionNode, symbol, true); 10.326 - symbol.setIsScope(); 10.327 + Symbol.setSymbolIsScope(lc, symbol); 10.328 symbol.setNeedsSlot(false); 10.329 } else { 10.330 assert symbol.hasSlot() : symbol + " should have a slot only, no scope"; 10.331 } 10.332 } else if (symbol.isParam() && (allVarsInScope || isVarArg || symbol.isScope())) { 10.333 updateSymbolsLog(functionNode, symbol, isVarArg); 10.334 - symbol.setIsScope(); 10.335 + Symbol.setSymbolIsScope(lc, symbol); 10.336 symbol.setNeedsSlot(!isVarArg); 10.337 } 10.338 } 10.339 @@ -636,11 +608,7 @@ 10.340 //fallthru 10.341 default: 10.342 if (newRuntimeNode || widest.isObject()) { 10.343 - final RuntimeNode runtimeNode = new RuntimeNode(binaryNode, request); 10.344 - if (finalized) { 10.345 - runtimeNode.setIsFinal(); 10.346 - } 10.347 - return runtimeNode; 10.348 + return new RuntimeNode(binaryNode, request).setIsFinal(finalized); 10.349 } 10.350 break; 10.351 } 10.352 @@ -667,7 +635,8 @@ 10.353 } 10.354 10.355 private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) { 10.356 - return binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType)); 10.357 + Node b = binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType)); 10.358 + return b; 10.359 } 10.360 10.361 /** 10.362 @@ -683,28 +652,28 @@ 10.363 10.364 node.accept(new NodeVisitor() { 10.365 private void setCanBePrimitive(final Symbol symbol) { 10.366 - LOG.info("*** can be primitive symbol " + symbol + " " + Debug.id(symbol)); 10.367 + LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol)); 10.368 symbol.setCanBePrimitive(to); 10.369 } 10.370 10.371 @Override 10.372 - public Node enterIdentNode(final IdentNode identNode) { 10.373 + public boolean enterIdentNode(final IdentNode identNode) { 10.374 if (!exclude.contains(identNode)) { 10.375 setCanBePrimitive(identNode.getSymbol()); 10.376 } 10.377 - return null; 10.378 + return false; 10.379 } 10.380 10.381 @Override 10.382 - public Node enterAccessNode(final AccessNode accessNode) { 10.383 + public boolean enterAccessNode(final AccessNode accessNode) { 10.384 setCanBePrimitive(accessNode.getProperty().getSymbol()); 10.385 - return null; 10.386 + return false; 10.387 } 10.388 10.389 @Override 10.390 - public Node enterIndexNode(final IndexNode indexNode) { 10.391 + public boolean enterIndexNode(final IndexNode indexNode) { 10.392 exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine 10.393 - return indexNode; 10.394 + return true; 10.395 } 10.396 }); 10.397 } 10.398 @@ -785,12 +754,12 @@ 10.399 private static <T extends Node> T setTypeOverride(final T node, final Type to) { 10.400 final Type from = node.getType(); 10.401 if (!node.getType().equals(to)) { 10.402 - LOG.info("Changing call override type for '" + node + "' from " + node.getType() + " to " + to); 10.403 + LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to); 10.404 if (!to.isObject() && from.isObject()) { 10.405 setCanBePrimitive(node, to); 10.406 } 10.407 } 10.408 - LOG.info("Type override for lhs in '" + node + "' => " + to); 10.409 + LOG.info("Type override for lhs in '", node, "' => ", to); 10.410 return ((TypeOverride<T>)node).setType(to); 10.411 } 10.412 10.413 @@ -814,8 +783,8 @@ 10.414 private Node convert(final Node node, final Type to) { 10.415 assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); 10.416 assert node != null : "node is null"; 10.417 - assert node.getSymbol() != null : "node " + node + " has no symbol!"; 10.418 - assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getCurrentFunctionNode(); 10.419 + assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + getLexicalContext().getCurrentFunction() + " " + node.getSource(); 10.420 + assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + getLexicalContext().getCurrentFunction(); 10.421 10.422 final Type from = node.getType(); 10.423 10.424 @@ -842,23 +811,23 @@ 10.425 resultNode = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.CONVERT), node); 10.426 } 10.427 10.428 - LOG.info("CONVERT('" + node + "', " + to + ") => '" + resultNode + "'"); 10.429 + LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'"); 10.430 10.431 + final LexicalContext lc = getLexicalContext(); 10.432 //This is the only place in this file that can create new temporaries 10.433 //FinalizeTypes may not introduce ANY node that is not a conversion. 10.434 - getCurrentFunctionNode().newTemporary(getCurrentBlock().getFrame(), to, resultNode); 10.435 - resultNode.copyTerminalFlags(node); 10.436 + lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode); 10.437 + 10.438 + assert !node.isTerminal(); 10.439 10.440 return resultNode; 10.441 } 10.442 10.443 private static Node discard(final Node node) { 10.444 - node.setDiscard(true); 10.445 - 10.446 if (node.getSymbol() != null) { 10.447 final Node discard = new UnaryNode(node.getSource(), Token.recast(node.getToken(), TokenType.DISCARD), node); 10.448 //discard never has a symbol in the discard node - then it would be a nop 10.449 - discard.copyTerminalFlags(node); 10.450 + assert !node.isTerminal(); 10.451 return discard; 10.452 } 10.453 10.454 @@ -883,7 +852,7 @@ 10.455 final Symbol symbol = node.getSymbol(); 10.456 if (symbol.isTemp()) { 10.457 symbol.setTypeOverride(to); 10.458 - LOG.info("Type override for temporary in '" + node + "' => " + to); 10.459 + LOG.info("Type override for temporary in '", node, "' => ", to); 10.460 } 10.461 } 10.462
11.1 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Fri Apr 19 18:23:00 2013 +0530 11.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Fri Apr 19 16:11:16 2013 +0200 11.3 @@ -57,7 +57,7 @@ 11.4 public Node leaveUnaryNode(final UnaryNode unaryNode) { 11.5 final LiteralNode<?> literalNode = new UnaryNodeConstantEvaluator(unaryNode).eval(); 11.6 if (literalNode != null) { 11.7 - LOG.info("Unary constant folded " + unaryNode + " to " + literalNode); 11.8 + LOG.info("Unary constant folded ", unaryNode, " to ", literalNode); 11.9 return literalNode; 11.10 } 11.11 return unaryNode; 11.12 @@ -67,24 +67,20 @@ 11.13 public Node leaveBinaryNode(final BinaryNode binaryNode) { 11.14 final LiteralNode<?> literalNode = new BinaryNodeConstantEvaluator(binaryNode).eval(); 11.15 if (literalNode != null) { 11.16 - LOG.info("Binary constant folded " + binaryNode + " to " + literalNode); 11.17 + LOG.info("Binary constant folded ", binaryNode, " to ", literalNode); 11.18 return literalNode; 11.19 } 11.20 return binaryNode; 11.21 } 11.22 11.23 @Override 11.24 - public Node enterFunctionNode(final FunctionNode functionNode) { 11.25 - if (functionNode.isLazy()) { 11.26 - return null; 11.27 - } 11.28 - return functionNode; 11.29 + public boolean enterFunctionNode(final FunctionNode functionNode) { 11.30 + return !functionNode.isLazy(); 11.31 } 11.32 11.33 @Override 11.34 public Node leaveFunctionNode(final FunctionNode functionNode) { 11.35 - functionNode.setState(CompilationState.CONSTANT_FOLDED); 11.36 - return functionNode; 11.37 + return functionNode.setState(getLexicalContext(), CompilationState.CONSTANT_FOLDED); 11.38 } 11.39 11.40 @Override
12.1 --- a/src/jdk/nashorn/internal/codegen/Frame.java Fri Apr 19 18:23:00 2013 +0530 12.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 12.3 @@ -1,196 +0,0 @@ 12.4 -/* 12.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 12.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 - * 12.8 - * This code is free software; you can redistribute it and/or modify it 12.9 - * under the terms of the GNU General Public License version 2 only, as 12.10 - * published by the Free Software Foundation. Oracle designates this 12.11 - * particular file as subject to the "Classpath" exception as provided 12.12 - * by Oracle in the LICENSE file that accompanied this code. 12.13 - * 12.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 12.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.17 - * version 2 for more details (a copy is included in the LICENSE file that 12.18 - * accompanied this code). 12.19 - * 12.20 - * You should have received a copy of the GNU General Public License version 12.21 - * 2 along with this work; if not, write to the Free Software Foundation, 12.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.23 - * 12.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.25 - * or visit www.oracle.com if you need additional information or have any 12.26 - * questions. 12.27 - */ 12.28 - 12.29 -package jdk.nashorn.internal.codegen; 12.30 - 12.31 -import java.util.ArrayList; 12.32 -import java.util.Collections; 12.33 -import java.util.List; 12.34 -import jdk.nashorn.internal.ir.Symbol; 12.35 - 12.36 -/** 12.37 - * Tracks the variable area state. 12.38 - * 12.39 - */ 12.40 -public final class Frame { 12.41 - /** Previous frame. */ 12.42 - private Frame previous; 12.43 - 12.44 - /** Current variables. */ 12.45 - private final ArrayList<Symbol> symbols; 12.46 - 12.47 - /** Number of slots in previous frame. */ 12.48 - private int baseCount; 12.49 - 12.50 - /** Number of slots in this frame. */ 12.51 - private int count; 12.52 - 12.53 - /** 12.54 - * Constructor. 12.55 - * 12.56 - * @param previous frame, the parent variable frame 12.57 - */ 12.58 - public Frame(final Frame previous) { 12.59 - this.previous = previous; 12.60 - this.symbols = new ArrayList<>(); 12.61 - this.baseCount = getBaseCount(); 12.62 - this.count = 0; 12.63 - } 12.64 - 12.65 - /** 12.66 - * Copy constructor 12.67 - * @param frame 12.68 - * @param symbols 12.69 - */ 12.70 - private Frame(final Frame frame, final List<Symbol> symbols) { 12.71 - this.previous = frame.getPrevious() == null ? null : new Frame(frame.getPrevious(), frame.getPrevious().getSymbols()); 12.72 - this.symbols = new ArrayList<>(frame.getSymbols()); 12.73 - this.baseCount = frame.getBaseCount(); 12.74 - this.count = frame.getCount(); 12.75 - } 12.76 - 12.77 - /** 12.78 - * Copy the frame 12.79 - * 12.80 - * @return a new frame with the identical contents 12.81 - */ 12.82 - public Frame copy() { 12.83 - return new Frame(this, getSymbols()); 12.84 - } 12.85 - 12.86 - /** 12.87 - * Add a new variable to the frame. 12.88 - * @param symbol Symbol representing variable. 12.89 - */ 12.90 - public void addSymbol(final Symbol symbol) { 12.91 - final int slot = symbol.getSlot(); 12.92 - if (slot < 0) { 12.93 - symbols.add(symbol); 12.94 - count += symbol.slotCount(); 12.95 - } 12.96 - } 12.97 - 12.98 - /** 12.99 - * Realign slot numbering prior to code generation. 12.100 - * @return Number of slots in frame. 12.101 - */ 12.102 - public int realign() { 12.103 - baseCount = getBaseCount(); 12.104 - count = 0; 12.105 - 12.106 - for (final Symbol symbol : symbols) { 12.107 - if (symbol.hasSlot()) { 12.108 - symbol.setSlot(baseCount + count); 12.109 - count += symbol.slotCount(); 12.110 - } 12.111 - } 12.112 - 12.113 - return count; 12.114 - } 12.115 - 12.116 - /** 12.117 - * Return the slot count of previous frames. 12.118 - * @return Number of slots in previous frames. 12.119 - */ 12.120 - private int getBaseCount() { 12.121 - return previous != null ? previous.getSlotCount() : 0; 12.122 - } 12.123 - 12.124 - /** 12.125 - * Determine the number of slots to top of frame. 12.126 - * @return Number of slots in total. 12.127 - */ 12.128 - public int getSlotCount() { 12.129 - return baseCount + count; 12.130 - } 12.131 - 12.132 - @Override 12.133 - public String toString() { 12.134 - final StringBuilder sb = new StringBuilder(); 12.135 - Frame f = this; 12.136 - boolean hasPrev = false; 12.137 - int pos = 0; 12.138 - 12.139 - do { 12.140 - if (hasPrev) { 12.141 - sb.append("\n"); 12.142 - } 12.143 - 12.144 - sb.append("#"). 12.145 - append(pos++). 12.146 - append(" {baseCount:"). 12.147 - append(baseCount). 12.148 - append(", "). 12.149 - append("count:"). 12.150 - append(count). 12.151 - append("} "); 12.152 - 12.153 - for (final Symbol var : f.getSymbols()) { 12.154 - sb.append('['). 12.155 - append(var.toString()). 12.156 - append(' '). 12.157 - append(var.hashCode()). 12.158 - append("] "); 12.159 - } 12.160 - 12.161 - f = f.getPrevious(); 12.162 - hasPrev = true; 12.163 - } while (f != null); 12.164 - 12.165 - return sb.toString(); 12.166 - } 12.167 - 12.168 - /** 12.169 - * Get variable count for this frame 12.170 - * @return variable count 12.171 - */ 12.172 - public int getCount() { 12.173 - return count; 12.174 - } 12.175 - 12.176 - /** 12.177 - * Get previous frame 12.178 - * @return previous frame 12.179 - */ 12.180 - public Frame getPrevious() { 12.181 - return previous; 12.182 - } 12.183 - 12.184 - /** 12.185 - * Set previous frame 12.186 - * @param previous previous frame 12.187 - */ 12.188 - public void setPrevious(final Frame previous) { 12.189 - this.previous = previous; 12.190 - } 12.191 - 12.192 - /** 12.193 - * Get symbols in frame 12.194 - * @return a list of symbols in this frame 12.195 - */ 12.196 - public List<Symbol> getSymbols() { 12.197 - return Collections.unmodifiableList(symbols); 12.198 - } 12.199 - }
13.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java Fri Apr 19 18:23:00 2013 +0530 13.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Fri Apr 19 16:11:16 2013 +0200 13.3 @@ -25,29 +25,21 @@ 13.4 13.5 package jdk.nashorn.internal.codegen; 13.6 13.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 13.8 -import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 13.9 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL; 13.10 -import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 13.11 -import static jdk.nashorn.internal.codegen.CompilerConstants.SCRIPT_RETURN; 13.12 +import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 13.13 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 13.14 -import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 13.15 13.16 -import java.util.ArrayDeque; 13.17 import java.util.ArrayList; 13.18 import java.util.Arrays; 13.19 -import java.util.Deque; 13.20 -import java.util.Iterator; 13.21 import java.util.List; 13.22 import jdk.nashorn.internal.ir.BaseNode; 13.23 import jdk.nashorn.internal.ir.BinaryNode; 13.24 import jdk.nashorn.internal.ir.Block; 13.25 +import jdk.nashorn.internal.ir.BlockLexicalContext; 13.26 import jdk.nashorn.internal.ir.BreakNode; 13.27 import jdk.nashorn.internal.ir.CallNode; 13.28 -import jdk.nashorn.internal.ir.CaseNode; 13.29 import jdk.nashorn.internal.ir.CatchNode; 13.30 import jdk.nashorn.internal.ir.ContinueNode; 13.31 -import jdk.nashorn.internal.ir.DoWhileNode; 13.32 import jdk.nashorn.internal.ir.EmptyNode; 13.33 import jdk.nashorn.internal.ir.ExecuteNode; 13.34 import jdk.nashorn.internal.ir.ForNode; 13.35 @@ -56,10 +48,10 @@ 13.36 import jdk.nashorn.internal.ir.IdentNode; 13.37 import jdk.nashorn.internal.ir.IfNode; 13.38 import jdk.nashorn.internal.ir.LabelNode; 13.39 -import jdk.nashorn.internal.ir.LabeledNode; 13.40 import jdk.nashorn.internal.ir.LexicalContext; 13.41 import jdk.nashorn.internal.ir.LineNumberNode; 13.42 import jdk.nashorn.internal.ir.LiteralNode; 13.43 +import jdk.nashorn.internal.ir.LoopNode; 13.44 import jdk.nashorn.internal.ir.Node; 13.45 import jdk.nashorn.internal.ir.ReturnNode; 13.46 import jdk.nashorn.internal.ir.SwitchNode; 13.47 @@ -90,356 +82,167 @@ 13.48 13.49 final class Lower extends NodeOperatorVisitor { 13.50 13.51 - /** 13.52 - * Nesting level stack. Currently just used for loops to avoid the problem 13.53 - * with terminal bodies that end with throw/return but still do continues to 13.54 - * outer loops or same loop. 13.55 - */ 13.56 - private final Deque<Node> nesting; 13.57 - 13.58 private static final DebugLogger LOG = new DebugLogger("lower"); 13.59 13.60 - private Node lastStatement; 13.61 - 13.62 - private List<Node> statements; 13.63 - 13.64 - private LexicalContext lexicalContext = new LexicalContext(); 13.65 - 13.66 /** 13.67 * Constructor. 13.68 * 13.69 * @param compiler the compiler 13.70 */ 13.71 Lower() { 13.72 - this.nesting = new ArrayDeque<>(); 13.73 - this.statements = new ArrayList<>(); 13.74 + super(new BlockLexicalContext() { 13.75 + 13.76 + @Override 13.77 + public List<Node> popStatements() { 13.78 + List<Node> newStatements = new ArrayList<>(); 13.79 + boolean terminated = false; 13.80 + 13.81 + final List<Node> statements = super.popStatements(); 13.82 + for (final Node statement : statements) { 13.83 + if (!terminated) { 13.84 + newStatements.add(statement); 13.85 + if (statement.isTerminal()) { 13.86 + terminated = true; 13.87 + } 13.88 + } else { 13.89 + if (statement instanceof VarNode) { 13.90 + newStatements.add(((VarNode)statement).setInit(null)); 13.91 + } 13.92 + } 13.93 + } 13.94 + return newStatements; 13.95 + } 13.96 + }); 13.97 } 13.98 13.99 @Override 13.100 - public Node enterBlock(final Block block) { 13.101 - final Node savedLastStatement = lastStatement; 13.102 - final List<Node> savedStatements = statements; 13.103 - lexicalContext.push(block); 13.104 - try { 13.105 - this.statements = new ArrayList<>(); 13.106 - NodeVisitor visitor = this; 13.107 - for (final Node statement : block.getStatements()) { 13.108 - statement.accept(visitor); 13.109 - /* 13.110 - * This is slightly unsound, for example if we have a loop with 13.111 - * a guarded statement like if (x) continue in the body and the 13.112 - * body ends with TERMINAL, e.g. return; we removed the continue 13.113 - * before we had the loop stack, as all we cared about was a 13.114 - * return last in the loop. 13.115 - * 13.116 - * @see NASHORN-285 13.117 - */ 13.118 - if (lastStatement != null && lastStatement.isTerminal()) { 13.119 - copyTerminal(block, lastStatement); 13.120 - visitor = new DeadCodeVarDeclarationVisitor(); 13.121 - } 13.122 - } 13.123 - block.setStatements(statements); 13.124 - 13.125 - } finally { 13.126 - this.statements = savedStatements; 13.127 - this.lastStatement = savedLastStatement; 13.128 - lexicalContext.pop(block); 13.129 + public boolean enterBlock(final Block block) { 13.130 + final LexicalContext lc = getLexicalContext(); 13.131 + if (lc.isFunctionBody() && lc.getCurrentFunction().isProgram() && !lc.getCurrentFunction().hasDeclaredFunctions()) { 13.132 + new ExecuteNode(block.getSource(), block.getToken(), block.getFinish(), LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)).accept(this); 13.133 } 13.134 - 13.135 - return null; 13.136 + return true; 13.137 } 13.138 13.139 @Override 13.140 - public Node enterBreakNode(final BreakNode breakNode) { 13.141 - return enterBreakOrContinue(breakNode); 13.142 + public Node leaveBlock(final Block block) { 13.143 + //now we have committed the entire statement list to the block, but we need to truncate 13.144 + //whatever is after the last terminal. block append won't append past it 13.145 + 13.146 + final BlockLexicalContext lc = (BlockLexicalContext)getLexicalContext(); 13.147 + 13.148 + Node last = lc.getLastStatement(); 13.149 + 13.150 + if (lc.isFunctionBody()) { 13.151 + final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); 13.152 + final boolean isProgram = currentFunction.isProgram(); 13.153 + final ReturnNode returnNode = new ReturnNode( 13.154 + currentFunction.getSource(), 13.155 + currentFunction.getToken(), 13.156 + currentFunction.getFinish(), 13.157 + isProgram ? 13.158 + compilerConstant(RETURN) : 13.159 + LiteralNode.newInstance(block, ScriptRuntime.UNDEFINED)); 13.160 + 13.161 + last = returnNode.accept(this); 13.162 + } 13.163 + 13.164 + if (last != null && last.isTerminal()) { 13.165 + return block.setIsTerminal(lc, true); 13.166 + } 13.167 + 13.168 + return block; 13.169 } 13.170 13.171 @Override 13.172 - public Node enterCallNode(final CallNode callNode) { 13.173 - final Node function = markerFunction(callNode.getFunction()); 13.174 - callNode.setFunction(function); 13.175 - checkEval(callNode); //check if this is an eval call and store the information 13.176 - return callNode; 13.177 + public boolean enterBreakNode(final BreakNode breakNode) { 13.178 + addStatement(breakNode); 13.179 + return false; 13.180 } 13.181 13.182 @Override 13.183 - public Node leaveCaseNode(final CaseNode caseNode) { 13.184 - caseNode.copyTerminalFlags(caseNode.getBody()); 13.185 - return caseNode; 13.186 + public Node leaveCallNode(final CallNode callNode) { 13.187 + return checkEval(callNode.setFunction(markerFunction(callNode.getFunction()))); 13.188 } 13.189 13.190 @Override 13.191 public Node leaveCatchNode(final CatchNode catchNode) { 13.192 - catchNode.copyTerminalFlags(catchNode.getBody()); 13.193 - addStatement(catchNode); 13.194 - return catchNode; 13.195 + return addStatement(catchNode); 13.196 } 13.197 13.198 @Override 13.199 - public Node enterContinueNode(final ContinueNode continueNode) { 13.200 - return enterBreakOrContinue(continueNode); 13.201 + public boolean enterContinueNode(final ContinueNode continueNode) { 13.202 + addStatement(continueNode); 13.203 + return false; 13.204 } 13.205 13.206 @Override 13.207 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 13.208 - return enterWhileNode(doWhileNode); 13.209 - } 13.210 - 13.211 - @Override 13.212 - public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 13.213 - return leaveWhileNode(doWhileNode); 13.214 - } 13.215 - 13.216 - @Override 13.217 - public Node enterEmptyNode(final EmptyNode emptyNode) { 13.218 - return null; 13.219 + public boolean enterEmptyNode(final EmptyNode emptyNode) { 13.220 + return false; 13.221 } 13.222 13.223 @Override 13.224 public Node leaveExecuteNode(final ExecuteNode executeNode) { 13.225 final Node expr = executeNode.getExpression(); 13.226 + ExecuteNode node = executeNode; 13.227 13.228 - if (getCurrentFunctionNode().isProgram()) { 13.229 + final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); 13.230 + 13.231 + if (currentFunction.isProgram()) { 13.232 if (!(expr instanceof Block) || expr instanceof FunctionNode) { // it's not a block, but can be a function 13.233 if (!isInternalExpression(expr) && !isEvalResultAssignment(expr)) { 13.234 - executeNode.setExpression(new BinaryNode(executeNode.getSource(), Token.recast(executeNode.getToken(), TokenType.ASSIGN), 13.235 - getCurrentFunctionNode().getResultNode(), 13.236 - expr)); 13.237 + node = executeNode.setExpression( 13.238 + new BinaryNode( 13.239 + executeNode.getSource(), 13.240 + Token.recast( 13.241 + executeNode.getToken(), 13.242 + TokenType.ASSIGN), 13.243 + compilerConstant(RETURN), 13.244 + expr)); 13.245 } 13.246 } 13.247 } 13.248 13.249 - copyTerminal(executeNode, executeNode.getExpression()); 13.250 - addStatement(executeNode); 13.251 - 13.252 - return executeNode; 13.253 - } 13.254 - 13.255 - @Override 13.256 - public Node enterForNode(final ForNode forNode) { 13.257 - nest(forNode); 13.258 - return forNode; 13.259 + return addStatement(node); 13.260 } 13.261 13.262 @Override 13.263 public Node leaveForNode(final ForNode forNode) { 13.264 + ForNode newForNode = forNode; 13.265 + 13.266 final Node test = forNode.getTest(); 13.267 - final Block body = forNode.getBody(); 13.268 - 13.269 - if (!forNode.isForIn() && test == null) { 13.270 - setHasGoto(forNode); 13.271 + if (!forNode.isForIn() && conservativeAlwaysTrue(test)) { 13.272 + newForNode = forNode.setTest(getLexicalContext(), null); 13.273 } 13.274 13.275 - final boolean escapes = controlFlowEscapes(body); 13.276 - if (escapes) { 13.277 - setTerminal(body, false); 13.278 - } 13.279 - 13.280 - // pop the loop from the loop context 13.281 - unnest(forNode); 13.282 - 13.283 - if (!forNode.isForIn() && conservativeAlwaysTrue(test)) { 13.284 - forNode.setTest(null); 13.285 - setHasGoto(forNode); 13.286 - setTerminal(forNode, !escapes); 13.287 - } 13.288 - 13.289 - addStatement(forNode); 13.290 - 13.291 - return forNode; 13.292 + return addStatement(checkEscape(newForNode)); 13.293 } 13.294 13.295 @Override 13.296 - public Node enterFunctionNode(final FunctionNode functionNode) { 13.297 - LOG.info("START FunctionNode: " + functionNode.getName()); 13.298 - 13.299 - if (functionNode.isLazy()) { 13.300 - LOG.info("LAZY: " + functionNode.getName()); 13.301 - return null; 13.302 - } 13.303 - lexicalContext.push(functionNode); 13.304 - initFunctionNode(functionNode); 13.305 - 13.306 - nest(functionNode); 13.307 - 13.308 - /* 13.309 - * As we are evaluating a nested structure, we need to store the 13.310 - * statement list for the surrounding block and restore it when the 13.311 - * function is done 13.312 - */ 13.313 - final List<Node> savedStatements = statements; 13.314 - final Node savedLastStatement = lastStatement; 13.315 - 13.316 - statements = new ArrayList<>(); 13.317 - lastStatement = null; 13.318 - 13.319 - if (functionNode.needsSelfSymbol()) { 13.320 - //function needs to start with var funcIdent = __callee_; 13.321 - statements.add(functionNode.getSelfSymbolInit().accept(this)); 13.322 - } 13.323 - 13.324 - NodeVisitor visitor = this; 13.325 - try { 13.326 - //do the statements - this fills the block with code 13.327 - boolean needsInitialEvalResult = functionNode.isProgram(); 13.328 - for (final Node statement : functionNode.getStatements()) { 13.329 - // If this function is a program, then insert an assignment to the initial eval result after all 13.330 - // function declarations. 13.331 - if(needsInitialEvalResult && !(statement instanceof LineNumberNode || (statement instanceof VarNode && ((VarNode)statement).isFunctionDeclaration()))) { 13.332 - addInitialEvalResult(functionNode); 13.333 - needsInitialEvalResult = false; 13.334 - } 13.335 - statement.accept(visitor); 13.336 - //If there are unused terminated endpoints in the function, we need 13.337 - // to add a "return undefined" in those places for correct semantics 13.338 - LOG.info("Checking lastStatement="+lastStatement+" for terminal flags"); 13.339 - if (lastStatement != null && lastStatement.hasTerminalFlags()) { 13.340 - copyTerminal(functionNode, lastStatement); 13.341 - assert !needsInitialEvalResult; 13.342 - visitor = new DeadCodeVarDeclarationVisitor(); 13.343 - } 13.344 - } 13.345 - if(needsInitialEvalResult) { 13.346 - addInitialEvalResult(functionNode); 13.347 - } 13.348 - functionNode.setStatements(statements); 13.349 - 13.350 - if (!functionNode.isTerminal()) { 13.351 - guaranteeReturn(functionNode); 13.352 - } 13.353 - } finally { 13.354 - statements = savedStatements; 13.355 - lastStatement = savedLastStatement; 13.356 - } 13.357 - 13.358 - LOG.info("END FunctionNode: " + functionNode.getName()); 13.359 - unnest(functionNode); 13.360 - lexicalContext.pop(functionNode); 13.361 - 13.362 - functionNode.setState(CompilationState.LOWERED); 13.363 - 13.364 - return null; 13.365 - } 13.366 - 13.367 - /** 13.368 - * This visitor is used to go over statements after a terminal statement. Those statements are dead code, but the 13.369 - * var declarations in them still have the effect of declaring a local variable on the function level. Therefore, 13.370 - * they aren't really dead code and must be preserved. Note that they're only preserved as no-op declarations; their 13.371 - * initializers are wiped out as those are, in fact, dead code. 13.372 - */ 13.373 - private class DeadCodeVarDeclarationVisitor extends NodeOperatorVisitor { 13.374 - DeadCodeVarDeclarationVisitor() { 13.375 - } 13.376 - 13.377 - @Override 13.378 - public Node enterVarNode(VarNode varNode) { 13.379 - // Can't ever see a function declaration, as this visitor is only ever used after a terminal statement was 13.380 - // encountered, and all function declarations precede any terminal statements. 13.381 - assert !varNode.isFunctionDeclaration(); 13.382 - if(varNode.getInit() == null) { 13.383 - // No initializer, just pass it to Lower. 13.384 - return varNode.accept(Lower.this); 13.385 - } 13.386 - // Wipe out the initializer and then pass it to Lower. 13.387 - return varNode.setInit(null).accept(Lower.this); 13.388 - } 13.389 - } 13.390 - 13.391 - private void addInitialEvalResult(final FunctionNode functionNode) { 13.392 - new ExecuteNode(functionNode.getSource(), functionNode.getFirstToken(), functionNode.getFinish(), 13.393 - getInitialEvalResult(functionNode)).accept(this); 13.394 - } 13.395 - 13.396 - /** 13.397 - * Result of initial result of evaluating a particular program, which is either the last function it declares, or 13.398 - * undefined if it doesn't declare any functions. 13.399 - * @param program 13.400 - * @return the initial result of evaluating the program 13.401 - */ 13.402 - private static Node getInitialEvalResult(final FunctionNode program) { 13.403 - IdentNode lastFnName = null; 13.404 - for (final FunctionNode fn : program.getDeclaredFunctions()) { 13.405 - assert fn.isDeclared(); 13.406 - final IdentNode fnName = fn.getIdent(); 13.407 - if(fnName != null) { 13.408 - lastFnName = fnName; 13.409 - } 13.410 - } 13.411 - return lastFnName != null ? new IdentNode(lastFnName) : LiteralNode.newInstance(program, ScriptRuntime.UNDEFINED); 13.412 + public boolean enterFunctionNode(final FunctionNode functionNode) { 13.413 + return !functionNode.isLazy(); 13.414 } 13.415 13.416 @Override 13.417 - public Node enterIfNode(final IfNode ifNode) { 13.418 - return nest(ifNode); 13.419 + public Node leaveFunctionNode(final FunctionNode functionNode) { 13.420 + LOG.info("END FunctionNode: ", functionNode.getName()); 13.421 + return functionNode.setState(getLexicalContext(), CompilationState.LOWERED); 13.422 } 13.423 13.424 @Override 13.425 public Node leaveIfNode(final IfNode ifNode) { 13.426 - final Node pass = ifNode.getPass(); 13.427 - final Node fail = ifNode.getFail(); 13.428 - 13.429 - if (pass.isTerminal() && fail != null && fail.isTerminal()) { 13.430 - setTerminal(ifNode, true); 13.431 - } 13.432 - 13.433 - addStatement(ifNode); 13.434 - unnest(ifNode); 13.435 - 13.436 - return ifNode; 13.437 + return addStatement(ifNode); 13.438 } 13.439 13.440 @Override 13.441 - public Node enterLabelNode(LabelNode labelNode) { 13.442 - final Block body = labelNode.getBody(); 13.443 - body.accept(this); 13.444 - copyTerminal(labelNode, body); 13.445 - addStatement(labelNode); 13.446 - return null; 13.447 + public Node leaveLabelNode(final LabelNode labelNode) { 13.448 + return addStatement(labelNode); 13.449 } 13.450 13.451 @Override 13.452 - public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 13.453 - addStatement(lineNumberNode, false); // don't put it in lastStatement cache 13.454 - return null; 13.455 - } 13.456 - 13.457 - @Override 13.458 - public Node enterReturnNode(final ReturnNode returnNode) { 13.459 - final TryNode tryNode = returnNode.getTryChain(); 13.460 - final Node expr = returnNode.getExpression(); 13.461 - 13.462 - if (tryNode != null) { 13.463 - //we are inside a try block - we don't necessarily have a result node yet. attr will do that. 13.464 - if (expr != null) { 13.465 - final Source source = getCurrentFunctionNode().getSource(); 13.466 - 13.467 - //we need to evaluate the result of the return in case it is complex while 13.468 - //still in the try block, store it in a result value and return it afterwards 13.469 - final long token = returnNode.getToken(); 13.470 - final Node resultNode = new IdentNode(getCurrentFunctionNode().getResultNode()); 13.471 - final Node assignResult = new BinaryNode(source, Token.recast(token, TokenType.ASSIGN), resultNode, expr); 13.472 - 13.473 - //add return_in_try = expr; to try block 13.474 - new ExecuteNode(source, token, Token.descPosition(token), assignResult).accept(this); 13.475 - 13.476 - //splice in the finally code, inlining it here 13.477 - if (copyFinally(tryNode, null)) { 13.478 - return null; 13.479 - } 13.480 - 13.481 - //make sure that the return node now returns 'return_in_try' 13.482 - returnNode.setExpression(resultNode); 13.483 - } else if (copyFinally(tryNode, null)) { 13.484 - return null; 13.485 - } 13.486 - } else if (expr != null) { 13.487 - returnNode.setExpression(expr.accept(this)); 13.488 - } 13.489 - 13.490 - addStatement(returnNode); 13.491 - 13.492 - return null; 13.493 + public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { 13.494 + addStatement(lineNumberNode); // don't put it in lastStatement cache 13.495 + return false; 13.496 } 13.497 13.498 @Override 13.499 @@ -448,31 +251,10 @@ 13.500 return returnNode; 13.501 } 13.502 13.503 - @Override 13.504 - public Node enterSwitchNode(final SwitchNode switchNode) { 13.505 - nest(switchNode); 13.506 - return switchNode; 13.507 - } 13.508 13.509 @Override 13.510 public Node leaveSwitchNode(final SwitchNode switchNode) { 13.511 - unnest(switchNode); 13.512 - 13.513 - final List<CaseNode> cases = switchNode.getCases(); 13.514 - final CaseNode defaultCase = switchNode.getDefaultCase(); 13.515 - 13.516 - boolean allTerminal = !cases.isEmpty(); 13.517 - for (final CaseNode caseNode : switchNode.getCases()) { 13.518 - allTerminal &= caseNode.isTerminal(); 13.519 - } 13.520 - 13.521 - if (allTerminal && defaultCase != null && defaultCase.isTerminal()) { 13.522 - setTerminal(switchNode, true); 13.523 - } 13.524 - 13.525 - addStatement(switchNode); 13.526 - 13.527 - return switchNode; 13.528 + return addStatement(switchNode); 13.529 } 13.530 13.531 @Override 13.532 @@ -481,208 +263,234 @@ 13.533 return throwNode; 13.534 } 13.535 13.536 - @Override 13.537 - public Node enterTryNode(final TryNode tryNode) { 13.538 - final Block finallyBody = tryNode.getFinallyBody(); 13.539 - final long token = tryNode.getToken(); 13.540 - final int finish = tryNode.getFinish(); 13.541 + private static Node ensureUniqueLabelsIn(final Node node) { 13.542 + return node.accept(new NodeVisitor() { 13.543 + @Override 13.544 + public Node leaveDefault(final Node labelledNode) { 13.545 + return labelledNode.ensureUniqueLabels(getLexicalContext()); 13.546 + } 13.547 + }); 13.548 + } 13.549 13.550 - nest(tryNode); 13.551 + private static List<Node> copyFinally(final Block finallyBody) { 13.552 + final List<Node> newStatements = new ArrayList<>(); 13.553 + for (final Node statement : finallyBody.getStatements()) { 13.554 + newStatements.add(ensureUniqueLabelsIn(statement)); 13.555 + if (statement.hasTerminalFlags()) { 13.556 + return newStatements; 13.557 + } 13.558 + } 13.559 + return newStatements; 13.560 + } 13.561 13.562 - if (finallyBody == null) { 13.563 - //do nothing if no finally exists 13.564 - return tryNode; 13.565 + private Block catchAllBlock(final TryNode tryNode) { 13.566 + final Source source = tryNode.getSource(); 13.567 + final long token = tryNode.getToken(); 13.568 + final int finish = tryNode.getFinish(); 13.569 + 13.570 + final IdentNode exception = new IdentNode(source, token, finish, getLexicalContext().getCurrentFunction().uniqueName("catch_all")); 13.571 + 13.572 + final Block catchBody = new Block(source, token, finish, new ThrowNode(source, token, finish, new IdentNode(exception))). 13.573 + setIsTerminal(getLexicalContext(), true); //ends with throw, so terminal 13.574 + 13.575 + final CatchNode catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody); 13.576 + final Block catchAllBlock = new Block(source, token, finish, catchAllNode); 13.577 + 13.578 + //catchallblock -> catchallnode (catchnode) -> exception -> throw 13.579 + 13.580 + return (Block)catchAllBlock.accept(this); //not accepted. has to be accepted by lower 13.581 + } 13.582 + 13.583 + private IdentNode compilerConstant(final CompilerConstants cc) { 13.584 + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 13.585 + return new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); 13.586 + } 13.587 + 13.588 + private static boolean isTerminal(final List<Node> statements) { 13.589 + return !statements.isEmpty() && statements.get(statements.size() - 1).hasTerminalFlags(); 13.590 + } 13.591 + 13.592 + /** 13.593 + * Splice finally code into all endpoints of a trynode 13.594 + * @param tryNode the try node 13.595 + * @param list of rethrowing throw nodes from synthetic catch blocks 13.596 + * @param finallyBody the code in the original finally block 13.597 + * @return new try node after splicing finally code (same if nop) 13.598 + */ 13.599 + private Node spliceFinally(final TryNode tryNode, final List<ThrowNode> rethrows, final Block finallyBody) { 13.600 + final Source source = tryNode.getSource(); 13.601 + final int finish = tryNode.getFinish(); 13.602 + 13.603 + assert tryNode.getFinallyBody() == null; 13.604 + 13.605 + final TryNode newTryNode = (TryNode)tryNode.accept(new NodeVisitor() { 13.606 + final List<Node> insideTry = new ArrayList<>(); 13.607 + 13.608 + @Override 13.609 + public boolean enterDefault(final Node node) { 13.610 + insideTry.add(node); 13.611 + return true; 13.612 + } 13.613 + 13.614 + @Override 13.615 + public boolean enterFunctionNode(final FunctionNode functionNode) { 13.616 + // do not enter function nodes - finally code should not be inlined into them 13.617 + return false; 13.618 + } 13.619 + 13.620 + @Override 13.621 + public Node leaveThrowNode(final ThrowNode throwNode) { 13.622 + if (rethrows.contains(throwNode)) { 13.623 + final List<Node> newStatements = copyFinally(finallyBody); 13.624 + if (!isTerminal(newStatements)) { 13.625 + newStatements.add(throwNode); 13.626 + } 13.627 + return new Block(source, throwNode.getToken(), throwNode.getFinish(), newStatements); 13.628 + } 13.629 + return throwNode; 13.630 + } 13.631 + 13.632 + @Override 13.633 + public Node leaveBreakNode(final BreakNode breakNode) { 13.634 + return copy(breakNode, Lower.this.getLexicalContext().getBreakable(breakNode.getLabel())); 13.635 + } 13.636 + 13.637 + @Override 13.638 + public Node leaveContinueNode(final ContinueNode continueNode) { 13.639 + return copy(continueNode, Lower.this.getLexicalContext().getContinueTo(continueNode.getLabel())); 13.640 + } 13.641 + 13.642 + @Override 13.643 + public Node leaveReturnNode(final ReturnNode returnNode) { 13.644 + final Node expr = returnNode.getExpression(); 13.645 + final List<Node> newStatements = new ArrayList<>(); 13.646 + 13.647 + final Node resultNode; 13.648 + if (expr != null) { 13.649 + //we need to evaluate the result of the return in case it is complex while 13.650 + //still in the try block, store it in a result value and return it afterwards 13.651 + resultNode = new IdentNode(Lower.this.compilerConstant(RETURN)); 13.652 + newStatements.add(new ExecuteNode(new BinaryNode(source, Token.recast(returnNode.getToken(), TokenType.ASSIGN), resultNode, expr))); 13.653 + } else { 13.654 + resultNode = null; 13.655 + } 13.656 + 13.657 + newStatements.addAll(copyFinally(finallyBody)); 13.658 + if (!isTerminal(newStatements)) { 13.659 + newStatements.add(expr == null ? returnNode : returnNode.setExpression(resultNode)); 13.660 + } 13.661 + 13.662 + return new ExecuteNode(new Block(source, returnNode.getToken(), getLexicalContext().getCurrentBlock().getFinish(), newStatements)); 13.663 + } 13.664 + 13.665 + private Node copy(final Node endpoint, final Node targetNode) { 13.666 + if (!insideTry.contains(targetNode)) { 13.667 + final List<Node> newStatements = copyFinally(finallyBody); 13.668 + if (!isTerminal(newStatements)) { 13.669 + newStatements.add(endpoint); 13.670 + } 13.671 + return new ExecuteNode(new Block(source, endpoint.getToken(), finish, newStatements)); 13.672 + } 13.673 + return endpoint; 13.674 + } 13.675 + }); 13.676 + 13.677 + addStatement(newTryNode); 13.678 + for (final Node statement : finallyBody.getStatements()) { 13.679 + addStatement(statement); 13.680 } 13.681 13.682 - /* 13.683 - * We have a finally clause. 13.684 - * 13.685 - * Transform to do finally tail duplication as follows: 13.686 - * 13.687 - * <pre> 13.688 - * try { 13.689 - * try_body 13.690 - * } catch e1 { 13.691 - * catchbody_1 13.692 - * } 13.693 - * ... 13.694 - * } catch en { 13.695 - * catchbody_n 13.696 - * } finally { 13.697 - * finally_body 13.698 - * } 13.699 - * 13.700 - * (where e1 ... en are optional) 13.701 - * 13.702 - * turns into 13.703 - * 13.704 - * try { 13.705 - * try { 13.706 - * try_body 13.707 - * } catch e1 { 13.708 - * catchbody1 13.709 - * //nothing inlined explicitly here, return, break other 13.710 - * //terminals may inline the finally body 13.711 - * ... 13.712 - * } catch en { 13.713 - * catchbody2 13.714 - * //nothing inlined explicitly here, return, break other 13.715 - * //terminals may inline the finally body 13.716 - * } 13.717 - * } catch all ex { 13.718 - * finally_body_inlined 13.719 - * rethrow ex 13.720 - * } 13.721 - * finally_body_inlined 13.722 - * </pre> 13.723 - * 13.724 - * If tries are catches are terminal, visitors for return, break & 13.725 - * continue will handle the tail duplications. Throw needs to be 13.726 - * treated specially with the catchall as described in the above 13.727 - * ASCII art. 13.728 - * 13.729 - * If the try isn't terminal we do the finally_body_inlined at the 13.730 - * end. If the try is terminated with continue/break/return the 13.731 - * existing visitor logic will inline the finally before that 13.732 - * operation. if the try is terminated with a throw, the catches e1 13.733 - * ... en will have a chance to process the exception. If the 13.734 - * appropriate catch e1..en is non terminal we fall through to the 13.735 - * last finally_body_inlined. if the catch e1...en IS terminal with 13.736 - * continue/break/return existing visitor logic will fix it. If they 13.737 - * are terminal with another throw it goes to the catchall and the 13.738 - * finally_body_inlined marked (*) will fix it before rethrowing 13.739 - * whatever problem there was for identical semantic. 13.740 - */ 13.741 - final Source source = getCurrentFunctionNode().getSource(); 13.742 - 13.743 - // if try node does not contain a catch we can skip creation of a new 13.744 - // try node and just append our synthetic catch to the existing try node. 13.745 - if (!tryNode.getCatchBlocks().isEmpty()) { 13.746 - // insert an intermediate try-catch* node, where we move the body and all catch blocks. 13.747 - // the original try node become a try-finally container for the new try-catch* node. 13.748 - // because we don't clone (to avoid deep copy), we have to fix the block chain in the end. 13.749 - final TryNode innerTryNode; 13.750 - innerTryNode = new TryNode(source, token, finish, tryNode.getNext()); 13.751 - innerTryNode.setBody(tryNode.getBody()); 13.752 - innerTryNode.setCatchBlocks(tryNode.getCatchBlocks()); 13.753 - 13.754 - // set outer tryNode's body to innerTryNode 13.755 - final Block outerBody; 13.756 - outerBody = new Block(source, token, finish); 13.757 - outerBody.setStatements(new ArrayList<Node>(Arrays.asList(innerTryNode))); 13.758 - tryNode.setBody(outerBody); 13.759 - tryNode.setCatchBlocks(null); 13.760 - } 13.761 - 13.762 - // create a catch-all that inlines finally and rethrows 13.763 - 13.764 - final Block catchBlock = new Block(source, token, finish); 13.765 - //this catch block should get define symbol 13.766 - 13.767 - final Block catchBody = new Block(source, token, finish); 13.768 - final Node catchAllFinally = finallyBody.copy(); 13.769 - 13.770 - catchBody.addStatement(new ExecuteNode(source, finallyBody.getToken(), finallyBody.getFinish(), catchAllFinally)); 13.771 - setTerminal(catchBody, true); 13.772 - 13.773 - final CatchNode catchAllNode; 13.774 - final IdentNode exception; 13.775 - 13.776 - exception = new IdentNode(source, token, finish, getCurrentFunctionNode().uniqueName("catch_all")); 13.777 - catchAllNode = new CatchNode(source, token, finish, new IdentNode(exception), null, catchBody); 13.778 - catchAllNode.setIsSyntheticRethrow(); 13.779 - 13.780 - catchBlock.addStatement(catchAllNode); 13.781 - 13.782 - // replace all catches of outer tryNode with the catch-all 13.783 - tryNode.setCatchBlocks(new ArrayList<>(Arrays.asList(catchBlock))); 13.784 - 13.785 - /* 13.786 - * We leave the finally block for the original try in place for now 13.787 - * so that children visitations will work. It is removed and placed 13.788 - * afterwards in the else case below, after all children are visited 13.789 - */ 13.790 - 13.791 - return tryNode; 13.792 + return newTryNode; 13.793 } 13.794 13.795 @Override 13.796 public Node leaveTryNode(final TryNode tryNode) { 13.797 - final Block finallyBody = tryNode.getFinallyBody(); 13.798 + final Block finallyBody = tryNode.getFinallyBody(); 13.799 13.800 - boolean allTerminal = tryNode.getBody().isTerminal() && (finallyBody == null || finallyBody.isTerminal()); 13.801 - 13.802 - for (final Block catchBlock : tryNode.getCatchBlocks()) { 13.803 - allTerminal &= catchBlock.isTerminal(); 13.804 + if (finallyBody == null) { 13.805 + return addStatement(tryNode); 13.806 } 13.807 13.808 - tryNode.setIsTerminal(allTerminal); 13.809 + /* 13.810 + * create a new trynode 13.811 + * if we have catches: 13.812 + * 13.813 + * try try 13.814 + * x try 13.815 + * catch x 13.816 + * y catch 13.817 + * finally z y 13.818 + * catchall 13.819 + * rethrow 13.820 + * 13.821 + * otheriwse 13.822 + * 13.823 + * try try 13.824 + * x x 13.825 + * finally catchall 13.826 + * y rethrow 13.827 + * 13.828 + * 13.829 + * now splice in finally code wherever needed 13.830 + * 13.831 + */ 13.832 + TryNode newTryNode; 13.833 13.834 - addStatement(tryNode); 13.835 - unnest(tryNode); 13.836 + final Block catchAll = catchAllBlock(tryNode); 13.837 13.838 - // if finally body is present, place it after the tryNode 13.839 - if (finallyBody != null) { 13.840 - tryNode.setFinallyBody(null); 13.841 - addStatement(finallyBody); 13.842 + final List<ThrowNode> rethrows = new ArrayList<>(); 13.843 + catchAll.accept(new NodeVisitor() { 13.844 + @Override 13.845 + public boolean enterThrowNode(final ThrowNode throwNode) { 13.846 + rethrows.add(throwNode); 13.847 + return true; 13.848 + } 13.849 + }); 13.850 + assert rethrows.size() == 1; 13.851 + 13.852 + if (tryNode.getCatchBlocks().isEmpty()) { 13.853 + newTryNode = tryNode.setFinallyBody(null); 13.854 + } else { 13.855 + Block outerBody = new Block(tryNode.getSource(), tryNode.getToken(), tryNode.getFinish(), new ArrayList<Node>(Arrays.asList(tryNode.setFinallyBody(null)))); 13.856 + newTryNode = tryNode.setBody(outerBody).setCatchBlocks(null); 13.857 } 13.858 13.859 - return tryNode; 13.860 + newTryNode = newTryNode.setCatchBlocks(Arrays.asList(catchAll)).setFinallyBody(null); 13.861 + 13.862 + /* 13.863 + * Now that the transform is done, we have to go into the try and splice 13.864 + * the finally block in front of any statement that is outside the try 13.865 + */ 13.866 + return spliceFinally(newTryNode, rethrows, finallyBody); 13.867 } 13.868 13.869 @Override 13.870 public Node leaveVarNode(final VarNode varNode) { 13.871 addStatement(varNode); 13.872 + if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION) && getLexicalContext().getCurrentFunction().isProgram()) { 13.873 + new ExecuteNode(varNode.getSource(), varNode.getToken(), varNode.getFinish(), new IdentNode(varNode.getName())).accept(this); 13.874 + } 13.875 return varNode; 13.876 } 13.877 13.878 @Override 13.879 - public Node enterWhileNode(final WhileNode whileNode) { 13.880 - return nest(whileNode); 13.881 - } 13.882 - 13.883 - @Override 13.884 public Node leaveWhileNode(final WhileNode whileNode) { 13.885 final Node test = whileNode.getTest(); 13.886 + final Block body = whileNode.getBody(); 13.887 13.888 - if (test == null) { 13.889 - setHasGoto(whileNode); 13.890 + if (conservativeAlwaysTrue(test)) { 13.891 + //turn it into a for node without a test. 13.892 + final ForNode forNode = (ForNode)new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish(), null, null, body, null, ForNode.IS_FOR).accept(this); 13.893 + getLexicalContext().replace(whileNode, forNode); 13.894 + return forNode; 13.895 } 13.896 13.897 - final Block body = whileNode.getBody(); 13.898 - final boolean escapes = controlFlowEscapes(body); 13.899 - if (escapes) { 13.900 - setTerminal(body, false); 13.901 - } 13.902 - 13.903 - Node node = whileNode; 13.904 - 13.905 - if (body.isTerminal()) { 13.906 - if (whileNode instanceof DoWhileNode) { 13.907 - setTerminal(whileNode, true); 13.908 - } else if (conservativeAlwaysTrue(test)) { 13.909 - node = new ForNode(whileNode.getSource(), whileNode.getToken(), whileNode.getFinish()); 13.910 - ((ForNode)node).setBody(body); 13.911 - node.accept(this); 13.912 - setTerminal(node, !escapes); 13.913 - } 13.914 - } 13.915 - 13.916 - // pop the loop from the loop context 13.917 - unnest(whileNode); 13.918 - addStatement(node); 13.919 - 13.920 - return node; 13.921 + return addStatement(checkEscape(whileNode)); 13.922 } 13.923 13.924 @Override 13.925 public Node leaveWithNode(final WithNode withNode) { 13.926 - if (withNode.getBody().isTerminal()) { 13.927 - setTerminal(withNode, true); 13.928 - } 13.929 - addStatement(withNode); 13.930 - 13.931 - return withNode; 13.932 + return addStatement(withNode); 13.933 } 13.934 13.935 @Override 13.936 @@ -741,23 +549,25 @@ 13.937 * 13.938 * @param callNode call node to check if it's an eval 13.939 */ 13.940 - private void checkEval(final CallNode callNode) { 13.941 + private CallNode checkEval(final CallNode callNode) { 13.942 if (callNode.getFunction() instanceof IdentNode) { 13.943 13.944 final List<Node> args = callNode.getArgs(); 13.945 final IdentNode callee = (IdentNode)callNode.getFunction(); 13.946 13.947 // 'eval' call with at least one argument 13.948 - if (args.size() >= 1 && EVAL.tag().equals(callee.getName())) { 13.949 - final CallNode.EvalArgs evalArgs = 13.950 + if (args.size() >= 1 && EVAL.symbolName().equals(callee.getName())) { 13.951 + final FunctionNode currentFunction = getLexicalContext().getCurrentFunction(); 13.952 + return callNode.setEvalArgs( 13.953 new CallNode.EvalArgs( 13.954 - args.get(0).copy().accept(this), //clone as we use this for the "is eval case". original evaluated separately for "is not eval case" 13.955 - getCurrentFunctionNode().getThisNode(), 13.956 + ensureUniqueLabelsIn(args.get(0)).accept(this), 13.957 + compilerConstant(THIS), 13.958 evalLocation(callee), 13.959 - getCurrentFunctionNode().isStrictMode()); 13.960 - callNode.setEvalArgs(evalArgs); 13.961 + currentFunction.isStrict())); 13.962 } 13.963 } 13.964 + 13.965 + return callNode; 13.966 } 13.967 13.968 private static boolean conservativeAlwaysTrue(final Node node) { 13.969 @@ -773,7 +583,7 @@ 13.970 * @param loopBody the loop body to check 13.971 * @return true if control flow may escape the loop 13.972 */ 13.973 - private boolean controlFlowEscapes(final Node loopBody) { 13.974 + private static boolean controlFlowEscapes(final LexicalContext lex, final Block loopBody) { 13.975 final List<Node> escapes = new ArrayList<>(); 13.976 13.977 loopBody.accept(new NodeVisitor() { 13.978 @@ -786,7 +596,7 @@ 13.979 @Override 13.980 public Node leaveContinueNode(final ContinueNode node) { 13.981 // all inner loops have been popped. 13.982 - if (nesting.contains(node.getTargetNode())) { 13.983 + if (lex.contains(lex.getContinueTo(node.getLabel()))) { 13.984 escapes.add(node); 13.985 } 13.986 return node; 13.987 @@ -796,135 +606,23 @@ 13.988 return !escapes.isEmpty(); 13.989 } 13.990 13.991 - private void guaranteeReturn(final FunctionNode functionNode) { 13.992 - Node resultNode; 13.993 - 13.994 - if (functionNode.isProgram()) { 13.995 - resultNode = functionNode.getResultNode(); // the eval result, symbol assigned in Attr 13.996 - } else { 13.997 - if (lastStatement != null && lastStatement.isTerminal() || lastStatement instanceof ReturnNode) { 13.998 - return; //already in place or not needed, as it should be for a non-undefined returning function 13.999 - } 13.1000 - resultNode = LiteralNode.newInstance(functionNode, ScriptRuntime.UNDEFINED); 13.1001 + private LoopNode checkEscape(final LoopNode loopNode) { 13.1002 + final LexicalContext lc = getLexicalContext(); 13.1003 + final boolean escapes = controlFlowEscapes(lc, loopNode.getBody()); 13.1004 + if (escapes) { 13.1005 + return loopNode. 13.1006 + setBody(lc, loopNode.getBody().setIsTerminal(lc, false)). 13.1007 + setControlFlowEscapes(lc, escapes); 13.1008 } 13.1009 - 13.1010 - //create a return statement 13.1011 - final Node returnNode = new ReturnNode(functionNode.getSource(), functionNode.getLastToken(), functionNode.getFinish(), resultNode, null); 13.1012 - returnNode.accept(this); 13.1013 + return loopNode; 13.1014 } 13.1015 13.1016 13.1017 - private Node nest(final Node node) { 13.1018 - LOG.info("Nesting: " + node); 13.1019 - LOG.indent(); 13.1020 - nesting.push(node); 13.1021 - return node; 13.1022 + private Node addStatement(final Node statement) { 13.1023 + ((BlockLexicalContext)getLexicalContext()).appendStatement(statement); 13.1024 + return statement; 13.1025 } 13.1026 13.1027 - private void unnest(final Node node) { 13.1028 - LOG.unindent(); 13.1029 - assert nesting.getFirst() == node : "inconsistent nesting order : " + nesting.getFirst() + " != " + node; 13.1030 - LOG.info("Unnesting: " + nesting); 13.1031 - nesting.pop(); 13.1032 - } 13.1033 - 13.1034 - private static void setTerminal(final Node node, final boolean isTerminal) { 13.1035 - LOG.info("terminal = " + isTerminal + " for " + node); 13.1036 - node.setIsTerminal(isTerminal); 13.1037 - } 13.1038 - 13.1039 - private static void setHasGoto(final Node node) { //, final boolean hasGoto) { 13.1040 - LOG.info("hasGoto = true for " + node); 13.1041 - node.setHasGoto(); 13.1042 - } 13.1043 - 13.1044 - private static void copyTerminal(final Node node, final Node sourceNode) { 13.1045 - LOG.info("copy terminal flags " + sourceNode + " -> " + node); 13.1046 - node.copyTerminalFlags(sourceNode); 13.1047 - } 13.1048 - 13.1049 - private void addStatement(final Node statement, final boolean storeInLastStatement) { 13.1050 - LOG.info("add statement = " + statement + " (lastStatement = " + lastStatement + ")"); 13.1051 - statements.add(statement); 13.1052 - if (storeInLastStatement) { 13.1053 - lastStatement = statement; 13.1054 - } 13.1055 - } 13.1056 - 13.1057 - private void addStatement(final Node statement) { 13.1058 - addStatement(statement, true); 13.1059 - } 13.1060 - 13.1061 - /** 13.1062 - * Determine if Try block is inside target block. 13.1063 - * 13.1064 - * @param tryNode Try node to test. 13.1065 - * @param target Target block. 13.1066 - * 13.1067 - * @return true if try block is inside the target, false otherwise. 13.1068 - */ 13.1069 - private boolean isNestedTry(final TryNode tryNode, final Block target) { 13.1070 - for(Iterator<Block> blocks = lexicalContext.getBlocks(getCurrentBlock()); blocks.hasNext();) { 13.1071 - final Block block = blocks.next(); 13.1072 - if(block == target) { 13.1073 - return false; 13.1074 - } 13.1075 - if(tryNode.isChildBlock(block)) { 13.1076 - return true; 13.1077 - } 13.1078 - } 13.1079 - return false; 13.1080 - } 13.1081 - 13.1082 - /** 13.1083 - * Clones the body of the try finallys up to the target block. 13.1084 - * 13.1085 - * @param node first try node in the chain. 13.1086 - * @param targetNode target block of the break/continue statement or null for return 13.1087 - * 13.1088 - * @return true if terminates. 13.1089 - */ 13.1090 - private boolean copyFinally(final TryNode node, final Node targetNode) { 13.1091 - Block target = null; 13.1092 - 13.1093 - if (targetNode instanceof Block) { 13.1094 - target = (Block)targetNode; 13.1095 - } 13.1096 - 13.1097 - for (TryNode tryNode = node; tryNode != null; tryNode = tryNode.getNext()) { 13.1098 - if (target != null && !isNestedTry(tryNode, target)) { 13.1099 - return false; 13.1100 - } 13.1101 - 13.1102 - Block finallyBody = tryNode.getFinallyBody(); 13.1103 - if (finallyBody == null) { 13.1104 - continue; 13.1105 - } 13.1106 - 13.1107 - finallyBody = (Block)finallyBody.copy(); 13.1108 - final boolean hasTerminalFlags = finallyBody.hasTerminalFlags(); 13.1109 - 13.1110 - new ExecuteNode(finallyBody.getSource(), finallyBody.getToken(), finallyBody.getFinish(), finallyBody).accept(this); 13.1111 - 13.1112 - if (hasTerminalFlags) { 13.1113 - getCurrentBlock().copyTerminalFlags(finallyBody); 13.1114 - return true; 13.1115 - } 13.1116 - } 13.1117 - 13.1118 - return false; 13.1119 - } 13.1120 - 13.1121 - private Node enterBreakOrContinue(final LabeledNode labeledNode) { 13.1122 - final TryNode tryNode = labeledNode.getTryChain(); 13.1123 - if (tryNode != null && copyFinally(tryNode, labeledNode.getTargetNode())) { 13.1124 - return null; 13.1125 - } 13.1126 - addStatement(labeledNode); 13.1127 - return null; 13.1128 - } 13.1129 - 13.1130 - 13.1131 /** 13.1132 * An internal expression has a symbol that is tagged internal. Check if 13.1133 * this is such a node 13.1134 @@ -939,40 +637,21 @@ 13.1135 13.1136 /** 13.1137 * Is this an assignment to the special variable that hosts scripting eval 13.1138 - * results? 13.1139 + * results, i.e. __return__? 13.1140 * 13.1141 * @param expression expression to check whether it is $evalresult = X 13.1142 * @return true if an assignment to eval result, false otherwise 13.1143 */ 13.1144 - private boolean isEvalResultAssignment(final Node expression) { 13.1145 + private static boolean isEvalResultAssignment(final Node expression) { 13.1146 Node e = expression; 13.1147 - if (e.tokenType() == TokenType.DISCARD) { 13.1148 - e = ((UnaryNode)expression).rhs(); 13.1149 - } 13.1150 - final Node resultNode = getCurrentFunctionNode().getResultNode(); 13.1151 - return e instanceof BinaryNode && ((BinaryNode)e).lhs().equals(resultNode); 13.1152 - } 13.1153 - 13.1154 - /** 13.1155 - * Prepare special function nodes. 13.1156 - * TODO : only create those that are needed. 13.1157 - * TODO : make sure slot numbering is not hardcoded in {@link CompilerConstants} - now creation order is significant 13.1158 - */ 13.1159 - private static void initFunctionNode(final FunctionNode functionNode) { 13.1160 - final Source source = functionNode.getSource(); 13.1161 - final long token = functionNode.getToken(); 13.1162 - final int finish = functionNode.getFinish(); 13.1163 - 13.1164 - functionNode.setThisNode(new IdentNode(source, token, finish, THIS.tag())); 13.1165 - functionNode.setScopeNode(new IdentNode(source, token, finish, SCOPE.tag())); 13.1166 - functionNode.setResultNode(new IdentNode(source, token, finish, SCRIPT_RETURN.tag())); 13.1167 - functionNode.setCalleeNode(new IdentNode(source, token, finish, CALLEE.tag())); 13.1168 - if (functionNode.isVarArg()) { 13.1169 - functionNode.setVarArgsNode(new IdentNode(source, token, finish, VARARGS.tag())); 13.1170 - if (functionNode.needsArguments()) { 13.1171 - functionNode.setArgumentsNode(new IdentNode(source, token, finish, ARGUMENTS.tag())); 13.1172 + assert e.tokenType() != TokenType.DISCARD; //there are no discards this early anymore 13.1173 + if (e instanceof BinaryNode) { 13.1174 + final Node lhs = ((BinaryNode)e).lhs(); 13.1175 + if (lhs instanceof IdentNode) { 13.1176 + return ((IdentNode)lhs).getName().equals(RETURN.symbolName()); 13.1177 } 13.1178 } 13.1179 + return false; 13.1180 } 13.1181 13.1182 }
14.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Fri Apr 19 18:23:00 2013 +0530 14.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Fri Apr 19 16:11:16 2013 +0200 14.3 @@ -53,9 +53,12 @@ 14.4 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 14.5 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; 14.6 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 14.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.ARGUMENTS; 14.8 import static jdk.nashorn.internal.codegen.CompilerConstants.CONSTANTS; 14.9 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 14.10 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 14.11 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS_DEBUGGER; 14.12 +import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 14.13 import static jdk.nashorn.internal.codegen.CompilerConstants.className; 14.14 import static jdk.nashorn.internal.codegen.CompilerConstants.constructorNoLookup; 14.15 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; 14.16 @@ -67,6 +70,8 @@ 14.17 import java.util.ArrayDeque; 14.18 import java.util.EnumSet; 14.19 import java.util.Iterator; 14.20 +import java.util.List; 14.21 + 14.22 import jdk.internal.dynalink.support.NameCodec; 14.23 import jdk.internal.org.objectweb.asm.Handle; 14.24 import jdk.internal.org.objectweb.asm.MethodVisitor; 14.25 @@ -79,14 +84,14 @@ 14.26 import jdk.nashorn.internal.codegen.types.Type; 14.27 import jdk.nashorn.internal.ir.FunctionNode; 14.28 import jdk.nashorn.internal.ir.IdentNode; 14.29 +import jdk.nashorn.internal.ir.LexicalContext; 14.30 import jdk.nashorn.internal.ir.LiteralNode; 14.31 import jdk.nashorn.internal.ir.RuntimeNode; 14.32 -import jdk.nashorn.internal.ir.SplitNode; 14.33 import jdk.nashorn.internal.ir.Symbol; 14.34 import jdk.nashorn.internal.runtime.ArgumentSetter; 14.35 +import jdk.nashorn.internal.runtime.Debug; 14.36 import jdk.nashorn.internal.runtime.DebugLogger; 14.37 import jdk.nashorn.internal.runtime.JSType; 14.38 -import jdk.nashorn.internal.runtime.Scope; 14.39 import jdk.nashorn.internal.runtime.ScriptEnvironment; 14.40 import jdk.nashorn.internal.runtime.ScriptObject; 14.41 import jdk.nashorn.internal.runtime.linker.Bootstrap; 14.42 @@ -116,10 +121,10 @@ 14.43 private final ClassEmitter classEmitter; 14.44 14.45 /** FunctionNode representing this method, or null if none exists */ 14.46 - private FunctionNode functionNode; 14.47 + protected FunctionNode functionNode; 14.48 14.49 - /** SplitNode representing the current split, or null if none exists */ 14.50 - private SplitNode splitNode; 14.51 + /** Check whether this emitter ever has a function return point */ 14.52 + private boolean hasReturn; 14.53 14.54 /** The script environment */ 14.55 private final ScriptEnvironment env; 14.56 @@ -203,7 +208,7 @@ 14.57 14.58 @Override 14.59 public String toString() { 14.60 - return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + stack; 14.61 + return "methodEmitter: " + (functionNode == null ? method : functionNode.getName()).toString() + ' ' + Debug.id(this); 14.62 } 14.63 14.64 /** 14.65 @@ -476,8 +481,8 @@ 14.66 14.67 String name = symbol.getName(); 14.68 14.69 - if (name.equals(THIS.tag())) { 14.70 - name = THIS_DEBUGGER.tag(); 14.71 + if (name.equals(THIS.symbolName())) { 14.72 + name = THIS_DEBUGGER.symbolName(); 14.73 } 14.74 14.75 method.visitLocalVariable(name, symbol.getSymbolType().getDescriptor(), null, start, end, symbol.getSlot()); 14.76 @@ -654,7 +659,7 @@ 14.77 * @return this method emitter 14.78 */ 14.79 MethodEmitter loadConstants() { 14.80 - getStatic(classEmitter.getUnitClassName(), CONSTANTS.tag(), CONSTANTS.descriptor()); 14.81 + getStatic(classEmitter.getUnitClassName(), CONSTANTS.symbolName(), CONSTANTS.descriptor()); 14.82 assert peekType().isArray() : peekType(); 14.83 return this; 14.84 } 14.85 @@ -835,13 +840,13 @@ 14.86 if (functionNode.needsArguments()) { 14.87 // ScriptObject.getArgument(int) on arguments 14.88 debug("load symbol", symbol.getName(), " arguments index=", index); 14.89 - loadArguments(); 14.90 + loadCompilerConstant(ARGUMENTS); 14.91 load(index); 14.92 ScriptObject.GET_ARGUMENT.invoke(this); 14.93 } else { 14.94 // array load from __varargs__ 14.95 debug("load symbol", symbol.getName(), " array index=", index); 14.96 - loadVarArgs(); 14.97 + loadCompilerConstant(VARARGS); 14.98 load(symbol.getFieldIndex()); 14.99 arrayload(); 14.100 } 14.101 @@ -870,48 +875,13 @@ 14.102 if(functionNode == null) { 14.103 return slot == CompilerConstants.JAVA_THIS.slot(); 14.104 } 14.105 - final int thisSlot = functionNode.getThisNode().getSymbol().getSlot(); 14.106 + final int thisSlot = compilerConstant(THIS).getSlot(); 14.107 assert !functionNode.needsCallee() || thisSlot == 1; // needsCallee -> thisSlot == 1 14.108 assert functionNode.needsCallee() || thisSlot == 0; // !needsCallee -> thisSlot == 0 14.109 return slot == thisSlot; 14.110 } 14.111 14.112 /** 14.113 - * Push the this object to the stack. 14.114 - * 14.115 - * @return the method emitter 14.116 - */ 14.117 - MethodEmitter loadThis() { 14.118 - load(functionNode.getThisNode().getSymbol()); 14.119 - return this; 14.120 - } 14.121 - 14.122 - /** 14.123 - * Push the scope object to the stack. 14.124 - * 14.125 - * @return the method emitter 14.126 - */ 14.127 - MethodEmitter loadScope() { 14.128 - if (peekType() == Type.SCOPE) { 14.129 - dup(); 14.130 - return this; 14.131 - } 14.132 - load(functionNode.getScopeNode().getSymbol()); 14.133 - return this; 14.134 - } 14.135 - 14.136 - /** 14.137 - * Push the return object to the stack. 14.138 - * 14.139 - * @return the method emitter 14.140 - */ 14.141 - MethodEmitter loadResult() { 14.142 - load(functionNode.getResultNode().getSymbol()); 14.143 - return this; 14.144 - } 14.145 - 14.146 - 14.147 - /** 14.148 * Push a method handle to the stack 14.149 * 14.150 * @param className class name 14.151 @@ -927,62 +897,24 @@ 14.152 return this; 14.153 } 14.154 14.155 - /** 14.156 - * Push the varargs object to the stack 14.157 - * 14.158 - * @return the method emitter 14.159 - */ 14.160 - MethodEmitter loadVarArgs() { 14.161 - debug("load var args " + functionNode.getVarArgsNode().getSymbol()); 14.162 - return load(functionNode.getVarArgsNode().getSymbol()); 14.163 + private Symbol compilerConstant(final CompilerConstants cc) { 14.164 + return functionNode.getBody().getExistingSymbol(cc.symbolName()); 14.165 } 14.166 14.167 - /** 14.168 - * Push the arguments array to the stack 14.169 - * 14.170 - * @return the method emitter 14.171 - */ 14.172 - MethodEmitter loadArguments() { 14.173 - debug("load arguments ", functionNode.getArgumentsNode().getSymbol()); 14.174 - assert functionNode.getArgumentsNode().getSymbol().getSlot() != 0; 14.175 - return load(functionNode.getArgumentsNode().getSymbol()); 14.176 + MethodEmitter loadCompilerConstant(final CompilerConstants cc) { 14.177 + final Symbol symbol = compilerConstant(cc); 14.178 + if (cc == SCOPE && peekType() == Type.SCOPE) { 14.179 + dup(); 14.180 + return this; 14.181 + } 14.182 + debug("load compiler constant ", symbol); 14.183 + return load(symbol); 14.184 } 14.185 14.186 - /** 14.187 - * Push the callee object to the stack 14.188 - * 14.189 - * @return the method emitter 14.190 - */ 14.191 - MethodEmitter loadCallee() { 14.192 - final Symbol calleeSymbol = functionNode.getCalleeNode().getSymbol(); 14.193 - debug("load callee ", calleeSymbol); 14.194 - assert calleeSymbol.getSlot() == 0 : "callee has wrong slot " + calleeSymbol.getSlot() + " in " + functionNode.getName(); 14.195 - 14.196 - return load(calleeSymbol); 14.197 - } 14.198 - 14.199 - /** 14.200 - * Pop the scope from the stack and store it in its predefined slot 14.201 - */ 14.202 - void storeScope() { 14.203 - debug("store scope"); 14.204 - store(functionNode.getScopeNode().getSymbol()); 14.205 - } 14.206 - 14.207 - /** 14.208 - * Pop the return from the stack and store it in its predefined slot 14.209 - */ 14.210 - void storeResult() { 14.211 - debug("store result"); 14.212 - store(functionNode.getResultNode().getSymbol()); 14.213 - } 14.214 - 14.215 - /** 14.216 - * Pop the arguments array from the stack and store it in its predefined slot 14.217 - */ 14.218 - void storeArguments() { 14.219 - debug("store arguments"); 14.220 - store(functionNode.getArgumentsNode().getSymbol()); 14.221 + void storeCompilerConstant(final CompilerConstants cc) { 14.222 + final Symbol symbol = compilerConstant(cc); 14.223 + debug("store compiler constant ", symbol); 14.224 + store(symbol); 14.225 } 14.226 14.227 /** 14.228 @@ -1030,13 +962,13 @@ 14.229 final int index = symbol.getFieldIndex(); 14.230 if (functionNode.needsArguments()) { 14.231 debug("store symbol", symbol.getName(), " arguments index=", index); 14.232 - loadArguments(); 14.233 + loadCompilerConstant(ARGUMENTS); 14.234 load(index); 14.235 ArgumentSetter.SET_ARGUMENT.invoke(this); 14.236 } else { 14.237 // varargs without arguments object - just do array store to __varargs__ 14.238 debug("store symbol", symbol.getName(), " array index=", index); 14.239 - loadVarArgs(); 14.240 + loadCompilerConstant(VARARGS); 14.241 load(index); 14.242 ArgumentSetter.SET_ARRAY_ELEMENT.invoke(this); 14.243 } 14.244 @@ -1345,6 +1277,11 @@ 14.245 } 14.246 } 14.247 14.248 + MethodEmitter registerReturn() { 14.249 + this.hasReturn = true; 14.250 + return this; 14.251 + } 14.252 + 14.253 /** 14.254 * Perform a non void return, popping the type from the stack 14.255 * 14.256 @@ -1385,22 +1322,7 @@ 14.257 * 14.258 * @param label destination label 14.259 */ 14.260 - void splitAwareGoto(final Label label) { 14.261 - 14.262 - if (splitNode != null) { 14.263 - final int index = splitNode.getExternalTargets().indexOf(label); 14.264 - 14.265 - if (index > -1) { 14.266 - loadScope(); 14.267 - checkcast(Scope.class); 14.268 - load(index + 1); 14.269 - invoke(Scope.SET_SPLIT_STATE); 14.270 - loadUndefined(Type.OBJECT); 14.271 - _return(functionNode.getReturnType()); 14.272 - return; 14.273 - } 14.274 - } 14.275 - 14.276 + void splitAwareGoto(final LexicalContext lc, final Label label) { 14.277 _goto(label); 14.278 } 14.279 14.280 @@ -2237,7 +2159,7 @@ 14.281 } 14.282 14.283 if (env != null) { //early bootstrap code doesn't have inited context yet 14.284 - LOG.info(sb.toString()); 14.285 + LOG.info(sb); 14.286 if (DEBUG_TRACE_LINE == linePrefix) { 14.287 new Throwable().printStackTrace(LOG.getOutputStream()); 14.288 } 14.289 @@ -2254,21 +2176,12 @@ 14.290 this.functionNode = functionNode; 14.291 } 14.292 14.293 - /** 14.294 - * Get the split node for this method emitter, if this is code 14.295 - * generation due to splitting large methods 14.296 - * 14.297 - * @return split node 14.298 - */ 14.299 - SplitNode getSplitNode() { 14.300 - return splitNode; 14.301 + boolean hasReturn() { 14.302 + return hasReturn; 14.303 } 14.304 14.305 - /** 14.306 - * Set the split node for this method emitter 14.307 - * @param splitNode split node 14.308 - */ 14.309 - void setSplitNode(final SplitNode splitNode) { 14.310 - this.splitNode = splitNode; 14.311 + List<Label> getExternalTargets() { 14.312 + return null; 14.313 } 14.314 + 14.315 }
15.1 --- a/src/jdk/nashorn/internal/codegen/Namespace.java Fri Apr 19 18:23:00 2013 +0530 15.2 +++ b/src/jdk/nashorn/internal/codegen/Namespace.java Fri Apr 19 16:11:16 2013 +0200 15.3 @@ -53,7 +53,7 @@ 15.4 */ 15.5 public Namespace(final Namespace parent) { 15.6 this.parent = parent; 15.7 - directory = new HashMap<>(); 15.8 + this.directory = new HashMap<>(); 15.9 } 15.10 15.11 /** 15.12 @@ -65,10 +65,6 @@ 15.13 return parent; 15.14 } 15.15 15.16 - private HashMap<String, Integer> getDirectory() { 15.17 - return directory; 15.18 - } 15.19 - 15.20 /** 15.21 * Create a uniqueName name in the namespace in the form base$n where n varies 15.22 * . 15.23 @@ -78,7 +74,7 @@ 15.24 */ 15.25 public String uniqueName(final String base) { 15.26 for (Namespace namespace = this; namespace != null; namespace = namespace.getParent()) { 15.27 - final HashMap<String, Integer> namespaceDirectory = namespace.getDirectory(); 15.28 + final HashMap<String, Integer> namespaceDirectory = namespace.directory; 15.29 final Integer counter = namespaceDirectory.get(base); 15.30 15.31 if (counter != null) {
16.1 --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Fri Apr 19 18:23:00 2013 +0530 16.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Fri Apr 19 16:11:16 2013 +0200 16.3 @@ -204,8 +204,8 @@ 16.4 * @return The class name. 16.5 */ 16.6 public static String getClassName(final int fieldCount) { 16.7 - return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount : 16.8 - SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag(); 16.9 + return fieldCount != 0 ? SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount : 16.10 + SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName(); 16.11 } 16.12 16.13 /** 16.14 @@ -218,7 +218,7 @@ 16.15 * @return The class name. 16.16 */ 16.17 public static String getClassName(final int fieldCount, final int paramCount) { 16.18 - return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.tag() + fieldCount + SCOPE_MARKER + paramCount; 16.19 + return SCRIPTS_PACKAGE + '/' + JS_OBJECT_PREFIX.symbolName() + fieldCount + SCOPE_MARKER + paramCount; 16.20 } 16.21 16.22 /** 16.23 @@ -449,7 +449,7 @@ 16.24 * @param className Name of JavaScript class. 16.25 */ 16.26 private static void newAllocate(final ClassEmitter classEmitter, final String className) { 16.27 - final MethodEmitter allocate = classEmitter.method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), ALLOCATE.tag(), ScriptObject.class, PropertyMap.class); 16.28 + final MethodEmitter allocate = classEmitter.method(EnumSet.of(Flag.PUBLIC, Flag.STATIC), ALLOCATE.symbolName(), ScriptObject.class, PropertyMap.class); 16.29 allocate.begin(); 16.30 allocate._new(className); 16.31 allocate.dup();
17.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java Fri Apr 19 18:23:00 2013 +0530 17.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java Fri Apr 19 16:11:16 2013 +0200 17.3 @@ -36,7 +36,7 @@ 17.4 public abstract class ObjectCreator { 17.5 17.6 /** Compile unit for this ObjectCreator, see CompileUnit */ 17.7 - protected final CompileUnit compileUnit; 17.8 + //protected final CompileUnit compileUnit; 17.9 17.10 /** List of keys to initiate in this ObjectCreator */ 17.11 protected final List<String> keys; 17.12 @@ -66,7 +66,6 @@ 17.13 */ 17.14 protected ObjectCreator(final CodeGenerator codegen, final List<String> keys, final List<Symbol> symbols, final boolean isScope, final boolean hasArguments) { 17.15 this.codegen = codegen; 17.16 - this.compileUnit = codegen.getCurrentCompileUnit(); 17.17 this.keys = keys; 17.18 this.symbols = symbols; 17.19 this.isScope = isScope;
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 18.2 +++ b/src/jdk/nashorn/internal/codegen/SplitMethodEmitter.java Fri Apr 19 16:11:16 2013 +0200 18.3 @@ -0,0 +1,100 @@ 18.4 +/* 18.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 18.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 18.7 + * 18.8 + * This code is free software; you can redistribute it and/or modify it 18.9 + * under the terms of the GNU General Public License version 2 only, as 18.10 + * published by the Free Software Foundation. Oracle designates this 18.11 + * particular file as subject to the "Classpath" exception as provided 18.12 + * by Oracle in the LICENSE file that accompanied this code. 18.13 + * 18.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 18.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 18.17 + * version 2 for more details (a copy is included in the LICENSE file that 18.18 + * accompanied this code). 18.19 + * 18.20 + * You should have received a copy of the GNU General Public License version 18.21 + * 2 along with this work; if not, write to the Free Software Foundation, 18.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18.23 + * 18.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 18.25 + * or visit www.oracle.com if you need additional information or have any 18.26 + * questions. 18.27 + */ 18.28 + 18.29 +package jdk.nashorn.internal.codegen; 18.30 + 18.31 +import java.util.ArrayList; 18.32 +import java.util.List; 18.33 + 18.34 +import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 18.35 + 18.36 +import jdk.internal.org.objectweb.asm.MethodVisitor; 18.37 +import jdk.nashorn.internal.codegen.types.Type; 18.38 +import jdk.nashorn.internal.ir.LexicalContext; 18.39 +import jdk.nashorn.internal.ir.SplitNode; 18.40 +import jdk.nashorn.internal.runtime.Scope; 18.41 + 18.42 +/** 18.43 + * Emitter used for splitting methods. Needs to keep track of if there are jump targets 18.44 + * outside the current split node. All external jump targets encountered at method 18.45 + * emission are logged, and {@code CodeGenerator#leaveSplitNode(SplitNode)} creates 18.46 + * an appropriate jump table when the SplitNode has been iterated through 18.47 + */ 18.48 +public class SplitMethodEmitter extends MethodEmitter { 18.49 + 18.50 + private final SplitNode splitNode; 18.51 + 18.52 + private final List<Label> externalTargets = new ArrayList<>(); 18.53 + 18.54 + SplitMethodEmitter(final ClassEmitter classEmitter, final MethodVisitor mv, SplitNode splitNode) { 18.55 + super(classEmitter, mv); 18.56 + this.splitNode = splitNode; 18.57 + } 18.58 + 18.59 + @Override 18.60 + void splitAwareGoto(final LexicalContext lc, final Label label) { 18.61 + assert splitNode != null; 18.62 + final int index = findExternalTarget(lc, label); 18.63 + if (index >= 0) { 18.64 + loadCompilerConstant(SCOPE); 18.65 + checkcast(Scope.class); 18.66 + load(index + 1); 18.67 + invoke(Scope.SET_SPLIT_STATE); 18.68 + loadUndefined(Type.OBJECT); 18.69 + _return(functionNode.getReturnType()); 18.70 + return; 18.71 + } 18.72 + super.splitAwareGoto(lc, label); 18.73 + } 18.74 + 18.75 + private int findExternalTarget(final LexicalContext lc, final Label label) { 18.76 + final int index = externalTargets.indexOf(label); 18.77 + 18.78 + if (index >= 0) { 18.79 + return index; 18.80 + } 18.81 + 18.82 + if (lc.isExternalTarget(splitNode, label)) { 18.83 + externalTargets.add(label); 18.84 + return externalTargets.size() - 1; 18.85 + } 18.86 + return -1; 18.87 + } 18.88 + 18.89 + @Override 18.90 + MethodEmitter registerReturn() { 18.91 + super.registerReturn(); 18.92 + loadCompilerConstant(SCOPE); 18.93 + checkcast(Scope.class); 18.94 + load(0); 18.95 + invoke(Scope.SET_SPLIT_STATE); 18.96 + return this; 18.97 + } 18.98 + 18.99 + @Override 18.100 + final List<Label> getExternalTargets() { 18.101 + return externalTargets; 18.102 + } 18.103 +}
19.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java Fri Apr 19 18:23:00 2013 +0530 19.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Fri Apr 19 16:11:16 2013 +0200 19.3 @@ -28,29 +28,18 @@ 19.4 import static jdk.nashorn.internal.codegen.CompilerConstants.SPLIT_PREFIX; 19.5 19.6 import java.util.ArrayList; 19.7 -import java.util.Deque; 19.8 import java.util.HashMap; 19.9 -import java.util.LinkedList; 19.10 import java.util.List; 19.11 import java.util.Map; 19.12 import jdk.nashorn.internal.ir.Block; 19.13 -import jdk.nashorn.internal.ir.BreakNode; 19.14 -import jdk.nashorn.internal.ir.ContinueNode; 19.15 -import jdk.nashorn.internal.ir.DoWhileNode; 19.16 -import jdk.nashorn.internal.ir.ForNode; 19.17 import jdk.nashorn.internal.ir.FunctionNode; 19.18 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 19.19 -import jdk.nashorn.internal.ir.LabelNode; 19.20 import jdk.nashorn.internal.ir.LexicalContext; 19.21 import jdk.nashorn.internal.ir.LiteralNode; 19.22 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 19.23 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode.ArrayUnit; 19.24 import jdk.nashorn.internal.ir.Node; 19.25 -import jdk.nashorn.internal.ir.ReturnNode; 19.26 import jdk.nashorn.internal.ir.SplitNode; 19.27 -import jdk.nashorn.internal.ir.SwitchNode; 19.28 -import jdk.nashorn.internal.ir.WhileNode; 19.29 -import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 19.30 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 19.31 import jdk.nashorn.internal.runtime.DebugLogger; 19.32 import jdk.nashorn.internal.runtime.Source; 19.33 @@ -64,7 +53,7 @@ 19.34 private final Compiler compiler; 19.35 19.36 /** IR to be broken down. */ 19.37 - private final FunctionNode functionNode; 19.38 + private FunctionNode outermost; 19.39 19.40 /** Compile unit for the main script. */ 19.41 private final CompileUnit outermostCompileUnit; 19.42 @@ -72,8 +61,6 @@ 19.43 /** Cache for calculated block weights. */ 19.44 private final Map<Node, Long> weightCache = new HashMap<>(); 19.45 19.46 - private final LexicalContext lexicalContext = new LexicalContext(); 19.47 - 19.48 /** Weight threshold for when to start a split. */ 19.49 public static final long SPLIT_THRESHOLD = Options.getIntProperty("nashorn.compiler.splitter.threshold", 32 * 1024); 19.50 19.51 @@ -88,70 +75,92 @@ 19.52 */ 19.53 public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { 19.54 this.compiler = compiler; 19.55 - this.functionNode = functionNode; 19.56 + this.outermost = functionNode; 19.57 this.outermostCompileUnit = outermostCompileUnit; 19.58 } 19.59 19.60 /** 19.61 * Execute the split 19.62 */ 19.63 - void split() { 19.64 + FunctionNode split(final FunctionNode fn) { 19.65 + FunctionNode functionNode = fn; 19.66 + 19.67 if (functionNode.isLazy()) { 19.68 - LOG.finest("Postponing split of '" + functionNode.getName() + "' as it's lazy"); 19.69 - return; 19.70 + LOG.finest("Postponing split of '", functionNode.getName(), "' as it's lazy"); 19.71 + return functionNode; 19.72 } 19.73 19.74 - LOG.finest("Initiating split of '" + functionNode.getName() + "'"); 19.75 + LOG.finest("Initiating split of '", functionNode.getName(), "'"); 19.76 + 19.77 + final LexicalContext lc = getLexicalContext(); 19.78 19.79 long weight = WeighNodes.weigh(functionNode); 19.80 + final boolean top = compiler.getFunctionNode() == outermost; 19.81 19.82 if (weight >= SPLIT_THRESHOLD) { 19.83 - LOG.finest("Splitting '" + functionNode.getName() + "' as its weight " + weight + " exceeds split threshold " + SPLIT_THRESHOLD); 19.84 - 19.85 - functionNode.accept(this); 19.86 + LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD); 19.87 + functionNode = (FunctionNode)functionNode.accept(this); 19.88 19.89 if (functionNode.isSplit()) { 19.90 // Weight has changed so weigh again, this time using block weight cache 19.91 weight = WeighNodes.weigh(functionNode, weightCache); 19.92 + functionNode = functionNode.setBody(lc, functionNode.getBody().setNeedsScope(lc)); 19.93 } 19.94 19.95 if (weight >= SPLIT_THRESHOLD) { 19.96 - weight = splitBlock(functionNode, functionNode); 19.97 - } 19.98 - 19.99 - if (functionNode.isSplit()) { 19.100 - functionNode.accept(new SplitFlowAnalyzer()); 19.101 + functionNode = functionNode.setBody(lc, splitBlock(functionNode.getBody(), functionNode)); 19.102 + weight = WeighNodes.weigh(functionNode.getBody(), weightCache); 19.103 } 19.104 } 19.105 19.106 - assert functionNode.getCompileUnit() == null : "compile unit already set"; 19.107 + assert functionNode.getCompileUnit() == null : "compile unit already set for " + functionNode.getName(); 19.108 19.109 - if (compiler.getFunctionNode() == functionNode) { //functionNode.isScript()) { 19.110 + if (top) { 19.111 assert outermostCompileUnit != null : "outermost compile unit is null"; 19.112 - 19.113 - functionNode.setCompileUnit(outermostCompileUnit); 19.114 + functionNode = functionNode.setCompileUnit(lc, outermostCompileUnit); 19.115 outermostCompileUnit.addWeight(weight + WeighNodes.FUNCTION_WEIGHT); 19.116 } else { 19.117 - functionNode.setCompileUnit(findUnit(weight)); 19.118 + functionNode = functionNode.setCompileUnit(lc, findUnit(weight)); 19.119 } 19.120 19.121 - // Recursively split nested functions 19.122 - functionNode.accept(new NodeOperatorVisitor() { 19.123 + final Block body = functionNode.getBody(); 19.124 + final List<FunctionNode> dc = directChildren(functionNode); 19.125 + 19.126 + final Block newBody = (Block)body.accept(new NodeVisitor() { 19.127 + @Override 19.128 + public boolean enterFunctionNode(final FunctionNode nestedFunction) { 19.129 + return dc.contains(nestedFunction); 19.130 + } 19.131 + 19.132 + @Override 19.133 + public Node leaveFunctionNode(final FunctionNode nestedFunction) { 19.134 + FunctionNode split = new Splitter(compiler, nestedFunction, outermostCompileUnit).split(nestedFunction); 19.135 + getLexicalContext().replace(nestedFunction, split); 19.136 + return split; 19.137 + } 19.138 + }); 19.139 + functionNode = functionNode.setBody(lc, newBody); 19.140 + 19.141 + assert functionNode.getCompileUnit() != null; 19.142 + 19.143 + return functionNode.setState(lc, CompilationState.SPLIT); 19.144 + } 19.145 + 19.146 + private static List<FunctionNode> directChildren(final FunctionNode functionNode) { 19.147 + final List<FunctionNode> dc = new ArrayList<>(); 19.148 + functionNode.accept(new NodeVisitor() { 19.149 @Override 19.150 - public Node enterFunctionNode(FunctionNode function) { 19.151 - if(function == functionNode) { 19.152 - // Don't process outermost function (it was already processed) but descend into it to find nested 19.153 - // functions. 19.154 - return function; 19.155 + public boolean enterFunctionNode(final FunctionNode child) { 19.156 + if (child == functionNode) { 19.157 + return true; 19.158 } 19.159 - // Process a nested function 19.160 - new Splitter(compiler, function, outermostCompileUnit).split(); 19.161 - // Don't descend into a a nested function; Splitter.split() has taken care of nested-in-nested functions. 19.162 - return null; 19.163 + if (getLexicalContext().getParentFunction(child) == functionNode) { 19.164 + dc.add(child); 19.165 + } 19.166 + return false; 19.167 } 19.168 }); 19.169 - 19.170 - functionNode.setState(CompilationState.SPLIT); 19.171 + return dc; 19.172 } 19.173 19.174 /** 19.175 @@ -170,8 +179,8 @@ 19.176 * 19.177 * @return new weight for the resulting block. 19.178 */ 19.179 - private long splitBlock(final Block block, final FunctionNode function) { 19.180 - functionNode.setIsSplit(); 19.181 + private Block splitBlock(final Block block, final FunctionNode function) { 19.182 + getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); 19.183 19.184 final List<Node> splits = new ArrayList<>(); 19.185 List<Node> statements = new ArrayList<>(); 19.186 @@ -186,7 +195,6 @@ 19.187 statements = new ArrayList<>(); 19.188 statementsWeight = 0; 19.189 } 19.190 - 19.191 } 19.192 19.193 if (statement.isTerminal()) { 19.194 @@ -201,9 +209,7 @@ 19.195 splits.add(createBlockSplitNode(block, function, statements, statementsWeight)); 19.196 } 19.197 19.198 - block.setStatements(splits); 19.199 - 19.200 - return WeighNodes.weigh(block, weightCache); 19.201 + return block.setStatements(getLexicalContext(), splits); 19.202 } 19.203 19.204 /** 19.205 @@ -218,51 +224,44 @@ 19.206 final Source source = parent.getSource(); 19.207 final long token = parent.getToken(); 19.208 final int finish = parent.getFinish(); 19.209 - final String name = function.uniqueName(SPLIT_PREFIX.tag()); 19.210 + final String name = function.uniqueName(SPLIT_PREFIX.symbolName()); 19.211 19.212 - final Block newBlock = new Block(source, token, finish); 19.213 - newBlock.setFrame(new Frame(parent.getFrame())); 19.214 - newBlock.setStatements(statements); 19.215 + final Block newBlock = new Block(source, token, finish, statements); 19.216 19.217 - final SplitNode splitNode = new SplitNode(name, functionNode, newBlock); 19.218 - 19.219 - splitNode.setCompileUnit(compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT)); 19.220 - 19.221 - return splitNode; 19.222 + return new SplitNode(name, newBlock, compiler.findUnit(weight + WeighNodes.FUNCTION_WEIGHT)); 19.223 } 19.224 19.225 @Override 19.226 - public Node enterBlock(final Block block) { 19.227 + public boolean enterBlock(final Block block) { 19.228 if (block.isCatchBlock()) { 19.229 - return null; 19.230 + return false; 19.231 } 19.232 - lexicalContext.push(block); 19.233 19.234 final long weight = WeighNodes.weigh(block, weightCache); 19.235 19.236 if (weight < SPLIT_THRESHOLD) { 19.237 weightCache.put(block, weight); 19.238 - lexicalContext.pop(block); 19.239 - return null; 19.240 + return false; 19.241 } 19.242 19.243 - return block; 19.244 + return true; 19.245 } 19.246 19.247 @Override 19.248 public Node leaveBlock(final Block block) { 19.249 assert !block.isCatchBlock(); 19.250 19.251 + Block newBlock = block; 19.252 + 19.253 // Block was heavier than SLIT_THRESHOLD in enter, but a sub-block may have 19.254 // been split already, so weigh again before splitting. 19.255 long weight = WeighNodes.weigh(block, weightCache); 19.256 if (weight >= SPLIT_THRESHOLD) { 19.257 - weight = splitBlock(block, lexicalContext.getFunction(block)); 19.258 + newBlock = splitBlock(block, getLexicalContext().getFunction(block)); 19.259 + weight = WeighNodes.weigh(newBlock, weightCache); 19.260 } 19.261 - weightCache.put(block, weight); 19.262 - 19.263 - lexicalContext.pop(block); 19.264 - return block; 19.265 + weightCache.put(newBlock, weight); 19.266 + return newBlock; 19.267 } 19.268 19.269 @SuppressWarnings("rawtypes") 19.270 @@ -274,7 +273,7 @@ 19.271 return literal; 19.272 } 19.273 19.274 - functionNode.setIsSplit(); 19.275 + getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); 19.276 19.277 if (literal instanceof ArrayLiteralNode) { 19.278 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal; 19.279 @@ -312,123 +311,12 @@ 19.280 } 19.281 19.282 @Override 19.283 - public Node enterFunctionNode(final FunctionNode node) { 19.284 - if(node == functionNode && !node.isLazy()) { 19.285 - lexicalContext.push(node); 19.286 - node.visitStatements(this); 19.287 - lexicalContext.pop(node); 19.288 + public boolean enterFunctionNode(final FunctionNode node) { 19.289 + //only go into the function node for this splitter. any subfunctions are rejected 19.290 + if (node == outermost && !node.isLazy()) { 19.291 + return true; 19.292 } 19.293 - return null; 19.294 - } 19.295 - 19.296 - static class SplitFlowAnalyzer extends NodeVisitor { 19.297 - 19.298 - /** Stack of visited Split nodes, deepest node first. */ 19.299 - private final Deque<SplitNode> splitStack; 19.300 - 19.301 - /** Map of possible jump targets to containing split node */ 19.302 - private final Map<Node,SplitNode> targetNodes = new HashMap<>(); 19.303 - 19.304 - SplitFlowAnalyzer() { 19.305 - this.splitStack = new LinkedList<>(); 19.306 - } 19.307 - 19.308 - @Override 19.309 - public Node enterLabelNode(final LabelNode labelNode) { 19.310 - registerJumpTarget(labelNode.getBreakNode()); 19.311 - registerJumpTarget(labelNode.getContinueNode()); 19.312 - return labelNode; 19.313 - } 19.314 - 19.315 - @Override 19.316 - public Node enterWhileNode(final WhileNode whileNode) { 19.317 - registerJumpTarget(whileNode); 19.318 - return whileNode; 19.319 - } 19.320 - 19.321 - @Override 19.322 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 19.323 - registerJumpTarget(doWhileNode); 19.324 - return doWhileNode; 19.325 - } 19.326 - 19.327 - @Override 19.328 - public Node enterForNode(final ForNode forNode) { 19.329 - registerJumpTarget(forNode); 19.330 - return forNode; 19.331 - } 19.332 - 19.333 - @Override 19.334 - public Node enterSwitchNode(final SwitchNode switchNode) { 19.335 - registerJumpTarget(switchNode); 19.336 - return switchNode; 19.337 - } 19.338 - 19.339 - @Override 19.340 - public Node enterReturnNode(final ReturnNode returnNode) { 19.341 - for (final SplitNode split : splitStack) { 19.342 - split.setHasReturn(true); 19.343 - } 19.344 - return returnNode; 19.345 - } 19.346 - 19.347 - @Override 19.348 - public Node enterContinueNode(final ContinueNode continueNode) { 19.349 - searchJumpTarget(continueNode.getTargetNode(), continueNode.getTargetLabel()); 19.350 - return continueNode; 19.351 - } 19.352 - 19.353 - @Override 19.354 - public Node enterBreakNode(final BreakNode breakNode) { 19.355 - searchJumpTarget(breakNode.getTargetNode(), breakNode.getTargetLabel()); 19.356 - return breakNode; 19.357 - } 19.358 - 19.359 - @Override 19.360 - public Node enterSplitNode(final SplitNode splitNode) { 19.361 - splitStack.addFirst(splitNode); 19.362 - return splitNode; 19.363 - } 19.364 - 19.365 - @Override 19.366 - public Node leaveSplitNode(final SplitNode splitNode) { 19.367 - assert splitNode == splitStack.peekFirst(); 19.368 - splitStack.removeFirst(); 19.369 - return splitNode; 19.370 - } 19.371 - 19.372 - /** 19.373 - * Register the split node containing a potential jump target. 19.374 - * @param targetNode a potential target node. 19.375 - */ 19.376 - private void registerJumpTarget(final Node targetNode) { 19.377 - final SplitNode splitNode = splitStack.peekFirst(); 19.378 - if (splitNode != null) { 19.379 - targetNodes.put(targetNode, splitNode); 19.380 - } 19.381 - } 19.382 - 19.383 - /** 19.384 - * Check if a jump target is outside the current split node and its parent split nodes. 19.385 - * @param targetNode the jump target node. 19.386 - * @param targetLabel the jump target label. 19.387 - */ 19.388 - private void searchJumpTarget(final Node targetNode, final Label targetLabel) { 19.389 - 19.390 - final SplitNode targetSplit = targetNodes.get(targetNode); 19.391 - // Note that targetSplit may be null, indicating that targetNode is in top level method. 19.392 - // In this case we have to add the external jump target to all split nodes. 19.393 - 19.394 - for (final SplitNode split : splitStack) { 19.395 - if (split == targetSplit) { 19.396 - break; 19.397 - } 19.398 - final List<Label> externalTargets = split.getExternalTargets(); 19.399 - if (!externalTargets.contains(targetLabel)) { 19.400 - split.addExternalTarget(targetLabel); 19.401 - } 19.402 - } 19.403 - } 19.404 + return false; 19.405 } 19.406 } 19.407
20.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java Fri Apr 19 18:23:00 2013 +0530 20.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java Fri Apr 19 16:11:16 2013 +0200 20.3 @@ -35,7 +35,6 @@ 20.4 import jdk.nashorn.internal.ir.CallNode; 20.5 import jdk.nashorn.internal.ir.CatchNode; 20.6 import jdk.nashorn.internal.ir.ContinueNode; 20.7 -import jdk.nashorn.internal.ir.DoWhileNode; 20.8 import jdk.nashorn.internal.ir.ExecuteNode; 20.9 import jdk.nashorn.internal.ir.ForNode; 20.10 import jdk.nashorn.internal.ir.FunctionNode; 20.11 @@ -101,7 +100,7 @@ 20.12 * @param weightCache cache of already calculated block weights 20.13 */ 20.14 private WeighNodes(FunctionNode topFunction, final Map<Node, Long> weightCache) { 20.15 - super(null, null); 20.16 + super(); 20.17 this.topFunction = topFunction; 20.18 this.weightCache = weightCache; 20.19 } 20.20 @@ -123,13 +122,13 @@ 20.21 } 20.22 20.23 @Override 20.24 - public Node enterBlock(final Block block) { 20.25 + public boolean enterBlock(final Block block) { 20.26 if (weightCache != null && weightCache.containsKey(block)) { 20.27 weight += weightCache.get(block); 20.28 - return null; 20.29 + return false; 20.30 } 20.31 20.32 - return block; 20.33 + return true; 20.34 } 20.35 20.36 @Override 20.37 @@ -157,12 +156,6 @@ 20.38 } 20.39 20.40 @Override 20.41 - public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 20.42 - weight += LOOP_WEIGHT; 20.43 - return doWhileNode; 20.44 - } 20.45 - 20.46 - @Override 20.47 public Node leaveExecuteNode(final ExecuteNode executeNode) { 20.48 return executeNode; 20.49 } 20.50 @@ -174,15 +167,15 @@ 20.51 } 20.52 20.53 @Override 20.54 - public Node enterFunctionNode(final FunctionNode functionNode) { 20.55 - if(functionNode == topFunction) { 20.56 + public boolean enterFunctionNode(final FunctionNode functionNode) { 20.57 + if (functionNode == topFunction) { 20.58 // the function being weighted; descend into its statements 20.59 - functionNode.visitStatements(this); 20.60 - } else { 20.61 - // just a reference to inner function from outer function 20.62 - weight += FUNC_EXPR_WEIGHT; 20.63 + return true; 20.64 +// functionNode.visitStatements(this); 20.65 } 20.66 - return null; 20.67 + // just a reference to inner function from outer function 20.68 + weight += FUNC_EXPR_WEIGHT; 20.69 + return false; 20.70 } 20.71 20.72 @Override 20.73 @@ -205,7 +198,7 @@ 20.74 20.75 @SuppressWarnings("rawtypes") 20.76 @Override 20.77 - public Node enterLiteralNode(final LiteralNode literalNode) { 20.78 + public boolean enterLiteralNode(final LiteralNode literalNode) { 20.79 weight += LITERAL_WEIGHT; 20.80 20.81 if (literalNode instanceof ArrayLiteralNode) { 20.82 @@ -224,10 +217,10 @@ 20.83 } 20.84 } 20.85 20.86 - return null; 20.87 + return false; 20.88 } 20.89 20.90 - return literalNode; 20.91 + return true; 20.92 } 20.93 20.94 @Override 20.95 @@ -249,9 +242,9 @@ 20.96 } 20.97 20.98 @Override 20.99 - public Node enterSplitNode(final SplitNode splitNode) { 20.100 + public boolean enterSplitNode(final SplitNode splitNode) { 20.101 weight += SPLIT_WEIGHT; 20.102 - return null; 20.103 + return false; 20.104 } 20.105 20.106 @Override
21.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java Fri Apr 19 18:23:00 2013 +0530 21.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Fri Apr 19 16:11:16 2013 +0200 21.3 @@ -25,23 +25,18 @@ 21.4 21.5 package jdk.nashorn.internal.ir; 21.6 21.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; 21.8 - 21.9 -import jdk.nashorn.internal.codegen.ObjectClassGenerator; 21.10 import jdk.nashorn.internal.codegen.types.Type; 21.11 +import jdk.nashorn.internal.ir.annotations.Immutable; 21.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 21.13 import jdk.nashorn.internal.runtime.Source; 21.14 21.15 /** 21.16 * IR representation of a property access (period operator.) 21.17 - * 21.18 */ 21.19 -public class AccessNode extends BaseNode implements TypeOverride<AccessNode> { 21.20 +@Immutable 21.21 +public final class AccessNode extends BaseNode { 21.22 /** Property ident. */ 21.23 - private IdentNode property; 21.24 - 21.25 - /** Does this node have a type override */ 21.26 - private boolean hasCallSiteType; 21.27 + private final IdentNode property; 21.28 21.29 /** 21.30 * Constructor 21.31 @@ -53,49 +48,13 @@ 21.32 * @param property property 21.33 */ 21.34 public AccessNode(final Source source, final long token, final int finish, final Node base, final IdentNode property) { 21.35 - super(source, token, finish, base); 21.36 - 21.37 - this.start = base.getStart(); 21.38 + super(source, token, finish, base, false, false); 21.39 this.property = property.setIsPropertyName(); 21.40 } 21.41 21.42 - /** 21.43 - * Copy constructor 21.44 - * 21.45 - * @param accessNode source node 21.46 - */ 21.47 - public AccessNode(final AccessNode accessNode) { 21.48 - this(accessNode, new CopyState()); 21.49 - } 21.50 - 21.51 - /** 21.52 - * Internal copy constructor 21.53 - * 21.54 - * @param accessNode source node 21.55 - * @param cs copy state 21.56 - */ 21.57 - protected AccessNode(final AccessNode accessNode, final CopyState cs) { 21.58 - super(accessNode, cs); 21.59 - this.property = (IdentNode)cs.existingOrCopy(accessNode.getProperty()); 21.60 - } 21.61 - 21.62 - @Override 21.63 - protected Node copy(final CopyState cs) { 21.64 - return new AccessNode(this, cs); 21.65 - } 21.66 - 21.67 - @Override 21.68 - public boolean equals(final Object other) { 21.69 - if (!super.equals(other)) { 21.70 - return false; 21.71 - } 21.72 - final AccessNode accessNode = (AccessNode)other; 21.73 - return property.equals(accessNode.getProperty()); 21.74 - } 21.75 - 21.76 - @Override 21.77 - public int hashCode() { 21.78 - return super.hashCode() ^ property.hashCode(); 21.79 + private AccessNode(final AccessNode accessNode, final Node base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) { 21.80 + super(accessNode, base, isFunction, hasCallSiteType); 21.81 + this.property = property; 21.82 } 21.83 21.84 /** 21.85 @@ -104,12 +63,11 @@ 21.86 */ 21.87 @Override 21.88 public Node accept(final NodeVisitor visitor) { 21.89 - if (visitor.enterAccessNode(this) != null) { 21.90 - base = base.accept(visitor); 21.91 - property = (IdentNode)property.accept(visitor); 21.92 - return visitor.leaveAccessNode(this); 21.93 + if (visitor.enterAccessNode(this)) { 21.94 + return visitor.leaveAccessNode( 21.95 + setBase(base.accept(visitor)). 21.96 + setProperty((IdentNode)property.accept(visitor))); 21.97 } 21.98 - 21.99 return this; 21.100 } 21.101 21.102 @@ -117,7 +75,7 @@ 21.103 public void toString(final StringBuilder sb) { 21.104 final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true); 21.105 21.106 - if (hasCallSiteType) { 21.107 + if (hasCallSiteType()) { 21.108 sb.append('{'); 21.109 final String desc = getType().getDescriptor(); 21.110 sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 21.111 @@ -147,19 +105,34 @@ 21.112 return property; 21.113 } 21.114 21.115 - @Override 21.116 - public AccessNode setType(final Type type) { 21.117 - if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 21.118 - ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 21.119 + private AccessNode setBase(final Node base) { 21.120 + if (this.base == base) { 21.121 + return this; 21.122 } 21.123 - property = property.setType(type); 21.124 - getSymbol().setTypeOverride(type); //always a temp so this is fine. 21.125 - hasCallSiteType = true; 21.126 - return this; 21.127 + return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); 21.128 + } 21.129 + 21.130 + 21.131 + private AccessNode setProperty(final IdentNode property) { 21.132 + if (this.property == property) { 21.133 + return this; 21.134 + } 21.135 + return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); 21.136 } 21.137 21.138 @Override 21.139 - public boolean canHaveCallSiteType() { 21.140 - return true; //carried by the symbol and always the same nodetype==symboltype 21.141 + public AccessNode setType(final Type type) { 21.142 + logTypeChange(type); 21.143 + getSymbol().setTypeOverride(type); //always a temp so this is fine. 21.144 + return new AccessNode(this, base, property.setType(type), isFunction(), hasCallSiteType()); 21.145 } 21.146 + 21.147 + @Override 21.148 + public BaseNode setIsFunction() { 21.149 + if (isFunction()) { 21.150 + return this; 21.151 + } 21.152 + return new AccessNode(this, base, property, true, hasCallSiteType()); 21.153 + } 21.154 + 21.155 }
22.1 --- a/src/jdk/nashorn/internal/ir/BaseNode.java Fri Apr 19 18:23:00 2013 +0530 22.2 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java Fri Apr 19 16:11:16 2013 +0200 22.3 @@ -25,6 +25,10 @@ 22.4 22.5 package jdk.nashorn.internal.ir; 22.6 22.7 +import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; 22.8 +import jdk.nashorn.internal.codegen.ObjectClassGenerator; 22.9 +import jdk.nashorn.internal.codegen.types.Type; 22.10 +import jdk.nashorn.internal.ir.annotations.Immutable; 22.11 import jdk.nashorn.internal.runtime.Source; 22.12 22.13 /** 22.14 @@ -33,12 +37,15 @@ 22.15 * @see AccessNode 22.16 * @see IndexNode 22.17 */ 22.18 -public abstract class BaseNode extends Node implements FunctionCall { 22.19 +@Immutable 22.20 +public abstract class BaseNode extends Node implements FunctionCall, TypeOverride<BaseNode> { 22.21 22.22 /** Base Node. */ 22.23 - protected Node base; 22.24 + protected final Node base; 22.25 22.26 - private boolean function; 22.27 + private final boolean isFunction; 22.28 + 22.29 + private final boolean hasCallSiteType; 22.30 22.31 /** 22.32 * Constructor 22.33 @@ -47,37 +54,28 @@ 22.34 * @param token token 22.35 * @param finish finish 22.36 * @param base base node 22.37 + * @param isFunction is this a function 22.38 + * @param hasCallSiteType does this access have a callsite type 22.39 */ 22.40 - public BaseNode(final Source source, final long token, final int finish, final Node base) { 22.41 - super(source, token, finish); 22.42 - this.base = base; 22.43 - setStart(base.getStart()); 22.44 + public BaseNode(final Source source, final long token, final int finish, final Node base, final boolean isFunction, final boolean hasCallSiteType) { 22.45 + super(source, token, base.getStart(), finish); 22.46 + this.base = base; 22.47 + this.isFunction = isFunction; 22.48 + this.hasCallSiteType = hasCallSiteType; 22.49 } 22.50 22.51 /** 22.52 - * Copy constructor 22.53 - * 22.54 - * @param baseNode the base node 22.55 - * @param cs a copy state 22.56 + * Copy constructor for immutable nodes 22.57 + * @param baseNode node to inherit from 22.58 + * @param base base 22.59 + * @param isFunction is this a function 22.60 + * @param hasCallSiteType does this access have a callsite type 22.61 */ 22.62 - protected BaseNode(final BaseNode baseNode, final CopyState cs) { 22.63 + protected BaseNode(final BaseNode baseNode, final Node base, final boolean isFunction, final boolean hasCallSiteType) { 22.64 super(baseNode); 22.65 - this.base = cs.existingOrCopy(baseNode.getBase()); 22.66 - setStart(base.getStart()); 22.67 - } 22.68 - 22.69 - @Override 22.70 - public boolean equals(final Object other) { 22.71 - if (!super.equals(other)) { 22.72 - return false; 22.73 - } 22.74 - final BaseNode baseNode = (BaseNode)other; 22.75 - return base.equals(baseNode.getBase()); 22.76 - } 22.77 - 22.78 - @Override 22.79 - public int hashCode() { 22.80 - return base.hashCode(); 22.81 + this.base = base; 22.82 + this.isFunction = isFunction; 22.83 + this.hasCallSiteType = hasCallSiteType; 22.84 } 22.85 22.86 /** 22.87 @@ -88,25 +86,37 @@ 22.88 return base; 22.89 } 22.90 22.91 - /** 22.92 - * Reset the base node for this access 22.93 - * @param base new base node 22.94 - */ 22.95 - public void setBase(final Node base) { 22.96 - this.base = base; 22.97 - } 22.98 - 22.99 @Override 22.100 public boolean isFunction() { 22.101 - return function; 22.102 + return isFunction; 22.103 } 22.104 22.105 /** 22.106 * Mark this node as being the callee operand of a {@link CallNode}. 22.107 * @return a base node identical to this one in all aspects except with its function flag set. 22.108 */ 22.109 - public BaseNode setIsFunction() { 22.110 - function = true; 22.111 - return this; 22.112 + public abstract BaseNode setIsFunction(); 22.113 + 22.114 + @Override 22.115 + public boolean canHaveCallSiteType() { 22.116 + return true; //carried by the symbol and always the same nodetype==symboltype 22.117 + } 22.118 + 22.119 + /** 22.120 + * Does the access have a call site type override? 22.121 + * @return true if overridden 22.122 + */ 22.123 + protected boolean hasCallSiteType() { 22.124 + return hasCallSiteType; 22.125 + } 22.126 + 22.127 + /** 22.128 + * Debug type change 22.129 + * @param type new type 22.130 + */ 22.131 + protected final void logTypeChange(final Type type) { 22.132 + if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 22.133 + ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType()); 22.134 + } 22.135 } 22.136 }
23.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Fri Apr 19 18:23:00 2013 +0530 23.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Fri Apr 19 16:11:16 2013 +0200 23.3 @@ -26,6 +26,7 @@ 23.4 package jdk.nashorn.internal.ir; 23.5 23.6 import jdk.nashorn.internal.codegen.types.Type; 23.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 23.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 23.9 import jdk.nashorn.internal.parser.TokenType; 23.10 import jdk.nashorn.internal.runtime.Source; 23.11 @@ -33,9 +34,12 @@ 23.12 /** 23.13 * BinaryNode nodes represent two operand operations. 23.14 */ 23.15 -public class BinaryNode extends UnaryNode { 23.16 +@Immutable 23.17 +public final class BinaryNode extends Node implements Assignment<Node> { 23.18 /** Left hand side argument. */ 23.19 - private Node lhs; 23.20 + private final Node lhs; 23.21 + 23.22 + private final Node rhs; 23.23 23.24 /** 23.25 * Constructor 23.26 @@ -46,28 +50,15 @@ 23.27 * @param rhs right hand side 23.28 */ 23.29 public BinaryNode(final Source source, final long token, final Node lhs, final Node rhs) { 23.30 - super(source, token, rhs); 23.31 - 23.32 - start = lhs.getStart(); 23.33 - finish = rhs.getFinish(); 23.34 - 23.35 - this.lhs = lhs; 23.36 + super(source, token, lhs.getStart(), rhs.getFinish()); 23.37 + this.lhs = lhs; 23.38 + this.rhs = rhs; 23.39 } 23.40 23.41 - /** 23.42 - * Copy constructor 23.43 - * 23.44 - * @param binaryNode the binary node 23.45 - * @param cs copy state 23.46 - */ 23.47 - protected BinaryNode(final BinaryNode binaryNode, final CopyState cs) { 23.48 - super(binaryNode, cs); 23.49 - lhs = cs.existingOrCopy(binaryNode.lhs); 23.50 - } 23.51 - 23.52 - @Override 23.53 - protected Node copy(final CopyState cs) { 23.54 - return new BinaryNode(this, cs); 23.55 + private BinaryNode(final BinaryNode binaryNode, final Node lhs, final Node rhs) { 23.56 + super(binaryNode); 23.57 + this.lhs = lhs; 23.58 + this.rhs = rhs; 23.59 } 23.60 23.61 /** 23.62 @@ -149,28 +140,14 @@ 23.63 return rhs(); 23.64 } 23.65 23.66 - @Override 23.67 - public boolean equals(final Object other) { 23.68 - if (!super.equals(other)) { 23.69 - return false; 23.70 - } 23.71 - return lhs.equals(((BinaryNode)other).lhs()); 23.72 - } 23.73 - 23.74 - @Override 23.75 - public int hashCode() { 23.76 - return super.hashCode() ^ lhs().hashCode(); 23.77 - } 23.78 - 23.79 /** 23.80 * Assist in IR navigation. 23.81 * @param visitor IR navigating visitor. 23.82 */ 23.83 @Override 23.84 public Node accept(final NodeVisitor visitor) { 23.85 - if (visitor.enterBinaryNode(this) != null) { 23.86 - // TODO: good cause for a separate visitMembers: we could delegate to UnaryNode.visitMembers 23.87 - return visitor.leaveBinaryNode((BinaryNode)setLHS(lhs.accept(visitor)).setRHS(rhs().accept(visitor))); 23.88 + if (visitor.enterBinaryNode(this)) { 23.89 + return visitor.leaveBinaryNode(setLHS(lhs.accept(visitor)).setRHS(rhs.accept(visitor))); 23.90 } 23.91 23.92 return this; 23.93 @@ -231,14 +208,35 @@ 23.94 } 23.95 23.96 /** 23.97 + * Get the right hand side expression for this node 23.98 + * @return the left hand side expression 23.99 + */ 23.100 + public Node rhs() { 23.101 + return rhs; 23.102 + } 23.103 + 23.104 + /** 23.105 * Set the left hand side expression for this node 23.106 * @param lhs new left hand side expression 23.107 * @return a node equivalent to this one except for the requested change. 23.108 */ 23.109 public BinaryNode setLHS(final Node lhs) { 23.110 - if(this.lhs == lhs) return this; 23.111 - final BinaryNode n = (BinaryNode)clone(); 23.112 - n.lhs = lhs; 23.113 - return n; 23.114 + if (this.lhs == lhs) { 23.115 + return this; 23.116 + } 23.117 + return new BinaryNode(this, lhs, rhs); 23.118 } 23.119 + 23.120 + /** 23.121 + * Set the right hand side expression for this node 23.122 + * @param rhs new left hand side expression 23.123 + * @return a node equivalent to this one except for the requested change. 23.124 + */ 23.125 + public BinaryNode setRHS(final Node rhs) { 23.126 + if (this.rhs == rhs) { 23.127 + return this; 23.128 + } 23.129 + return new BinaryNode(this, lhs, rhs); 23.130 + } 23.131 + 23.132 }
24.1 --- a/src/jdk/nashorn/internal/ir/Block.java Fri Apr 19 18:23:00 2013 +0530 24.2 +++ b/src/jdk/nashorn/internal/ir/Block.java Fri Apr 19 16:11:16 2013 +0200 24.3 @@ -27,14 +27,15 @@ 24.4 24.5 import java.io.PrintWriter; 24.6 import java.util.ArrayList; 24.7 +import java.util.Arrays; 24.8 import java.util.Collections; 24.9 import java.util.Comparator; 24.10 -import java.util.HashMap; 24.11 import java.util.Iterator; 24.12 +import java.util.LinkedHashMap; 24.13 import java.util.List; 24.14 -import java.util.ListIterator; 24.15 -import jdk.nashorn.internal.codegen.Frame; 24.16 +import java.util.Map; 24.17 import jdk.nashorn.internal.codegen.Label; 24.18 +import jdk.nashorn.internal.ir.annotations.Immutable; 24.19 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 24.20 import jdk.nashorn.internal.runtime.Source; 24.21 24.22 @@ -42,97 +43,79 @@ 24.23 * IR representation for a list of statements and functions. All provides the 24.24 * basis for script body. 24.25 */ 24.26 -public class Block extends Node { 24.27 +@Immutable 24.28 +public class Block extends BreakableNode implements Flags<Block> { 24.29 /** List of statements */ 24.30 - protected List<Node> statements; 24.31 + protected final List<Node> statements; 24.32 24.33 - /** Symbol table. */ 24.34 - protected final HashMap<String, Symbol> symbols; 24.35 - 24.36 - /** Variable frame. */ 24.37 - protected Frame frame; 24.38 + /** Symbol table - keys must be returned in the order they were put in. */ 24.39 + protected final Map<String, Symbol> symbols; 24.40 24.41 /** Entry label. */ 24.42 protected final Label entryLabel; 24.43 24.44 - /** Break label. */ 24.45 - protected final Label breakLabel; 24.46 + /** Does the block/function need a new scope? */ 24.47 + protected final int flags; 24.48 24.49 - /** Does the block/function need a new scope? */ 24.50 - protected boolean needsScope; 24.51 + /** Flag indicating that this block needs scope */ 24.52 + public static final int NEEDS_SCOPE = 1 << 0; 24.53 + 24.54 + /** 24.55 + * Flag indicating whether this block needs 24.56 + * self symbol assignment at the start. This is used only for 24.57 + * blocks that are the bodies of function nodes who refer to themselves 24.58 + * by name. It causes codegen to insert a var [fn_name] = __callee__ 24.59 + * at the start of the body 24.60 + */ 24.61 + public static final int NEEDS_SELF_SYMBOL = 1 << 1; 24.62 + 24.63 + /** 24.64 + * Is this block tagged as terminal based on its contents 24.65 + * (usually the last statement) 24.66 + */ 24.67 + public static final int IS_TERMINAL = 1 << 2; 24.68 24.69 /** 24.70 * Constructor 24.71 * 24.72 - * @param source source code 24.73 - * @param token token 24.74 - * @param finish finish 24.75 + * @param source source code 24.76 + * @param token token 24.77 + * @param finish finish 24.78 + * @param statements statements 24.79 */ 24.80 - public Block(final Source source, final long token, final int finish) { 24.81 - super(source, token, finish); 24.82 + public Block(final Source source, final long token, final int finish, final Node... statements) { 24.83 + super(source, token, finish, new Label("block_break")); 24.84 24.85 - this.statements = new ArrayList<>(); 24.86 - this.symbols = new HashMap<>(); 24.87 + this.statements = Arrays.asList(statements); 24.88 + this.symbols = new LinkedHashMap<>(); 24.89 this.entryLabel = new Label("block_entry"); 24.90 - this.breakLabel = new Label("block_break"); 24.91 + this.flags = 0; 24.92 } 24.93 24.94 /** 24.95 - * Internal copy constructor 24.96 + * Constructor 24.97 * 24.98 - * @param block the source block 24.99 - * @param cs the copy state 24.100 + * @param source source code 24.101 + * @param token token 24.102 + * @param finish finish 24.103 + * @param statements statements 24.104 */ 24.105 - protected Block(final Block block, final CopyState cs) { 24.106 + public Block(final Source source, final long token, final int finish, final List<Node> statements) { 24.107 + this(source, token, finish, statements.toArray(new Node[statements.size()])); 24.108 + } 24.109 + 24.110 + private Block(final Block block, final int finish, final List<Node> statements, final int flags) { 24.111 super(block); 24.112 - 24.113 - this.statements = new ArrayList<>(); 24.114 - for (final Node statement : block.getStatements()) { 24.115 - statements.add(cs.existingOrCopy(statement)); 24.116 - } 24.117 - this.symbols = new HashMap<>(); 24.118 - this.frame = block.frame == null ? null : block.frame.copy(); 24.119 + this.statements = statements; 24.120 + this.flags = flags; 24.121 + this.symbols = block.symbols; //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now 24.122 this.entryLabel = new Label(block.entryLabel); 24.123 - this.breakLabel = new Label(block.breakLabel); 24.124 - 24.125 - assert block.symbols.isEmpty() : "must not clone with symbols"; 24.126 + this.finish = finish; 24.127 } 24.128 24.129 @Override 24.130 - protected Node copy(final CopyState cs) { 24.131 - return new Block(this, cs); 24.132 - } 24.133 - 24.134 - /** 24.135 - * Add a new statement to the statement list. 24.136 - * 24.137 - * @param statement Statement node to add. 24.138 - */ 24.139 - public void addStatement(final Node statement) { 24.140 - if (statement != null) { 24.141 - statements.add(statement); 24.142 - if (getFinish() < statement.getFinish()) { 24.143 - setFinish(statement.getFinish()); 24.144 - } 24.145 - } 24.146 - } 24.147 - 24.148 - /** 24.149 - * Prepend statements to the statement list 24.150 - * 24.151 - * @param prepended statement to add 24.152 - */ 24.153 - public void prependStatements(final List<Node> prepended) { 24.154 - statements.addAll(0, prepended); 24.155 - } 24.156 - 24.157 - /** 24.158 - * Add a list of statements to the statement list. 24.159 - * 24.160 - * @param statementList Statement nodes to add. 24.161 - */ 24.162 - public void addStatements(final List<Node> statementList) { 24.163 - statements.addAll(statementList); 24.164 + public Node ensureUniqueLabels(final LexicalContext lc) { 24.165 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); 24.166 } 24.167 24.168 /** 24.169 @@ -142,19 +125,9 @@ 24.170 * @return new or same node 24.171 */ 24.172 @Override 24.173 - public Node accept(final NodeVisitor visitor) { 24.174 - final Block saveBlock = visitor.getCurrentBlock(); 24.175 - visitor.setCurrentBlock(this); 24.176 - 24.177 - try { 24.178 - // Ignore parent to avoid recursion. 24.179 - 24.180 - if (visitor.enterBlock(this) != null) { 24.181 - visitStatements(visitor); 24.182 - return visitor.leaveBlock(this); 24.183 - } 24.184 - } finally { 24.185 - visitor.setCurrentBlock(saveBlock); 24.186 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 24.187 + if (visitor.enterBlock(this)) { 24.188 + return visitor.leaveBlock(setStatements(lc, Node.accept(visitor, Node.class, statements))); 24.189 } 24.190 24.191 return this; 24.192 @@ -222,11 +195,18 @@ 24.193 } 24.194 24.195 /** 24.196 - * Get the break label for this block 24.197 - * @return the break label 24.198 + * Tag block as terminal or non terminal 24.199 + * @param lc lexical context 24.200 + * @param isTerminal is block terminal 24.201 + * @return same block, or new if flag changed 24.202 */ 24.203 - public Label getBreakLabel() { 24.204 - return breakLabel; 24.205 + public Block setIsTerminal(final LexicalContext lc, final boolean isTerminal) { 24.206 + return isTerminal ? setFlag(lc, IS_TERMINAL) : clearFlag(lc, IS_TERMINAL); 24.207 + } 24.208 + 24.209 + @Override 24.210 + public boolean isTerminal() { 24.211 + return getFlag(IS_TERMINAL); 24.212 } 24.213 24.214 /** 24.215 @@ -238,23 +218,6 @@ 24.216 } 24.217 24.218 /** 24.219 - * Get the frame for this block 24.220 - * @return the frame 24.221 - */ 24.222 - public Frame getFrame() { 24.223 - return frame; 24.224 - } 24.225 - 24.226 - /** 24.227 - * Reset the frame for this block 24.228 - * 24.229 - * @param frame the new frame 24.230 - */ 24.231 - public void setFrame(final Frame frame) { 24.232 - this.frame = frame; 24.233 - } 24.234 - 24.235 - /** 24.236 * Get the list of statements in this block 24.237 * 24.238 * @return a list of statements 24.239 @@ -264,21 +227,21 @@ 24.240 } 24.241 24.242 /** 24.243 - * Applies the specified visitor to all statements in the block. 24.244 - * @param visitor the visitor. 24.245 - */ 24.246 - public void visitStatements(NodeVisitor visitor) { 24.247 - for (ListIterator<Node> stmts = statements.listIterator(); stmts.hasNext();) { 24.248 - stmts.set(stmts.next().accept(visitor)); 24.249 - } 24.250 - } 24.251 - /** 24.252 * Reset the statement list for this block 24.253 * 24.254 - * @param statements new statement list 24.255 + * @param lc lexical context 24.256 + * @param statements new statement list 24.257 + * @return new block if statements changed, identity of statements == block.statements 24.258 */ 24.259 - public void setStatements(final List<Node> statements) { 24.260 - this.statements = statements; 24.261 + public Block setStatements(final LexicalContext lc, final List<Node> statements) { 24.262 + if (this.statements == statements) { 24.263 + return this; 24.264 + } 24.265 + int lastFinish = 0; 24.266 + if (!statements.isEmpty()) { 24.267 + lastFinish = statements.get(statements.size() - 1).getFinish(); 24.268 + } 24.269 + return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags)); 24.270 } 24.271 24.272 /** 24.273 @@ -297,39 +260,65 @@ 24.274 * @return true if this function needs a scope 24.275 */ 24.276 public boolean needsScope() { 24.277 - return needsScope; 24.278 + return (flags & NEEDS_SCOPE) == NEEDS_SCOPE; 24.279 + } 24.280 + 24.281 + @Override 24.282 + public Block setFlags(final LexicalContext lc, int flags) { 24.283 + if (this.flags == flags) { 24.284 + return this; 24.285 + } 24.286 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); 24.287 + } 24.288 + 24.289 + @Override 24.290 + public Block clearFlag(final LexicalContext lc, int flag) { 24.291 + return setFlags(lc, flags & ~flag); 24.292 + } 24.293 + 24.294 + @Override 24.295 + public Block setFlag(final LexicalContext lc, int flag) { 24.296 + return setFlags(lc, flags | flag); 24.297 + } 24.298 + 24.299 + @Override 24.300 + public boolean getFlag(final int flag) { 24.301 + return (flags & flag) == flag; 24.302 } 24.303 24.304 /** 24.305 * Set the needs scope flag. 24.306 + * @param lc lexicalContext 24.307 + * @return new block if state changed, otherwise this 24.308 */ 24.309 - public void setNeedsScope() { 24.310 - needsScope = true; 24.311 + public Block setNeedsScope(final LexicalContext lc) { 24.312 + if (needsScope()) { 24.313 + return this; 24.314 + } 24.315 + 24.316 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE)); 24.317 } 24.318 24.319 /** 24.320 - * Marks this block as using a specified scoped symbol. The block and its parent blocks up to but not 24.321 - * including the block defining the symbol will be marked as needing parent scope. The block defining the symbol 24.322 - * will be marked as one that needs to have its own scope. 24.323 - * @param symbol the symbol being used. 24.324 - * @param ancestors the iterator over block's containing lexical context 24.325 + * Computationally determine the next slot for this block, 24.326 + * indexed from 0. Use this as a relative base when computing 24.327 + * frames 24.328 + * @return next slot 24.329 */ 24.330 - public void setUsesScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { 24.331 - if(symbol.getBlock() == this) { 24.332 - setNeedsScope(); 24.333 - } else { 24.334 - setUsesParentScopeSymbol(symbol, ancestors); 24.335 + public int nextSlot() { 24.336 + final Iterator<Symbol> iter = symbolIterator(); 24.337 + int next = 0; 24.338 + while (iter.hasNext()) { 24.339 + final Symbol symbol = iter.next(); 24.340 + if (symbol.hasSlot()) { 24.341 + next += symbol.slotCount(); 24.342 } 24.343 + } 24.344 + return next; 24.345 } 24.346 24.347 - /** 24.348 - * Invoked when this block uses a scope symbol defined in one of its ancestors. 24.349 - * @param symbol the scope symbol being used 24.350 - * @param ancestors iterator over ancestor blocks 24.351 - */ 24.352 - void setUsesParentScopeSymbol(final Symbol symbol, Iterator<Block> ancestors) { 24.353 - if(ancestors.hasNext()) { 24.354 - ancestors.next().setUsesScopeSymbol(symbol, ancestors); 24.355 - } 24.356 + @Override 24.357 + protected boolean isBreakableWithoutLabel() { 24.358 + return false; 24.359 } 24.360 }
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/src/jdk/nashorn/internal/ir/BlockLexicalContext.java Fri Apr 19 16:11:16 2013 +0200 25.3 @@ -0,0 +1,120 @@ 25.4 +/* 25.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 25.7 + * 25.8 + * This code is free software; you can redistribute it and/or modify it 25.9 + * under the terms of the GNU General Public License version 2 only, as 25.10 + * published by the Free Software Foundation. Oracle designates this 25.11 + * particular file as subject to the "Classpath" exception as provided 25.12 + * by Oracle in the LICENSE file that accompanied this code. 25.13 + * 25.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 25.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 25.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25.17 + * version 2 for more details (a copy is included in the LICENSE file that 25.18 + * accompanied this code). 25.19 + * 25.20 + * You should have received a copy of the GNU General Public License version 25.21 + * 2 along with this work; if not, write to the Free Software Foundation, 25.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 25.23 + * 25.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 25.25 + * or visit www.oracle.com if you need additional information or have any 25.26 + * questions. 25.27 + */ 25.28 + 25.29 +package jdk.nashorn.internal.ir; 25.30 + 25.31 +import java.util.ArrayDeque; 25.32 +import java.util.ArrayList; 25.33 +import java.util.Deque; 25.34 +import java.util.List; 25.35 +import java.util.ListIterator; 25.36 + 25.37 +/** 25.38 + * This is a subclass of lexical context used for filling 25.39 + * blocks (and function nodes) with statements. When popping 25.40 + * a block from the lexical context, any statements that have 25.41 + * been generated in it are commited to the block. This saves 25.42 + * unnecessary object mutations and lexical context replacement 25.43 + */ 25.44 +public class BlockLexicalContext extends LexicalContext { 25.45 + /** statement stack, each block on the lexical context maintains one of these, which is 25.46 + * committed to the block on pop */ 25.47 + private Deque<List<Node>> sstack = new ArrayDeque<>(); 25.48 + 25.49 + /** Last non debug statement emitted in this context */ 25.50 + protected Node lastStatement; 25.51 + 25.52 + @Override 25.53 + public <T extends LexicalContextNode> T push(final T node) { 25.54 + T pushed = super.push(node); 25.55 + if (node instanceof Block) { 25.56 + sstack.push(new ArrayList<Node>()); 25.57 + } 25.58 + return pushed; 25.59 + } 25.60 + 25.61 + /** 25.62 + * Get the statement list from the stack, possibly filtered 25.63 + * @return statement list 25.64 + */ 25.65 + protected List<Node> popStatements() { 25.66 + return sstack.pop(); 25.67 + } 25.68 + 25.69 + @Override 25.70 + @SuppressWarnings("unchecked") 25.71 + public <T extends LexicalContextNode> T pop(final T node) { 25.72 + T expected = node; 25.73 + if (node instanceof Block) { 25.74 + final List<Node> newStatements = popStatements(); 25.75 + expected = (T)((Block)node).setStatements(this, newStatements); 25.76 + if (!sstack.isEmpty()) { 25.77 + lastStatement = lastStatement(sstack.peek()); 25.78 + } 25.79 + } 25.80 + return super.pop(expected); 25.81 + } 25.82 + 25.83 + /** 25.84 + * Append a statement to the block being generated 25.85 + * @param statement statement to add 25.86 + */ 25.87 + public void appendStatement(final Node statement) { 25.88 + assert statement != null; 25.89 + sstack.peek().add(statement); 25.90 + if (!statement.isDebug()) { 25.91 + lastStatement = statement; 25.92 + } 25.93 + } 25.94 + 25.95 + /** 25.96 + * Prepend a statement to the block being generated 25.97 + * @param statement statement to prepend 25.98 + * @return the prepended statement 25.99 + */ 25.100 + public Node prependStatement(final Node statement) { 25.101 + assert statement != null; 25.102 + sstack.peek().add(0, statement); 25.103 + return statement; 25.104 + } 25.105 + 25.106 + /** 25.107 + * Get the last (non debug) statement that was emitted into a block 25.108 + * @return the last statement emitted 25.109 + */ 25.110 + public Node getLastStatement() { 25.111 + return lastStatement; 25.112 + } 25.113 + 25.114 + private static Node lastStatement(final List<Node> statements) { 25.115 + for (final ListIterator<Node> iter = statements.listIterator(statements.size()); iter.hasPrevious(); ) { 25.116 + final Node node = iter.previous(); 25.117 + if (!node.isDebug()) { 25.118 + return node; 25.119 + } 25.120 + } 25.121 + return null; 25.122 + } 25.123 +}
26.1 --- a/src/jdk/nashorn/internal/ir/BreakNode.java Fri Apr 19 18:23:00 2013 +0530 26.2 +++ b/src/jdk/nashorn/internal/ir/BreakNode.java Fri Apr 19 16:11:16 2013 +0200 26.3 @@ -25,37 +25,34 @@ 26.4 26.5 package jdk.nashorn.internal.ir; 26.6 26.7 -import jdk.nashorn.internal.codegen.Label; 26.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 26.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 26.10 import jdk.nashorn.internal.runtime.Source; 26.11 26.12 /** 26.13 * IR representation for {@code break} statements. 26.14 */ 26.15 -public class BreakNode extends LabeledNode { 26.16 +@Immutable 26.17 +public final class BreakNode extends Node { 26.18 26.19 - /** 26.20 + private final IdentNode label; 26.21 + 26.22 + /** 26.23 * Constructor 26.24 * 26.25 - * @param source source code 26.26 - * @param token token 26.27 - * @param finish finish 26.28 - * @param labelNode break label 26.29 - * @param targetNode node to break to 26.30 - * @param tryChain surrounding try chain 26.31 + * @param source source code 26.32 + * @param token token 26.33 + * @param finish finish 26.34 + * @param label label for break or null if none 26.35 */ 26.36 - public BreakNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) { 26.37 - super(source, token, finish, labelNode, targetNode, tryChain); 26.38 - setHasGoto(); 26.39 - } 26.40 - 26.41 - private BreakNode(final BreakNode breakNode, final CopyState cs) { 26.42 - super(breakNode, cs); 26.43 + public BreakNode(final Source source, final long token, final int finish, final IdentNode label) { 26.44 + super(source, token, finish); 26.45 + this.label = label; 26.46 } 26.47 26.48 @Override 26.49 - protected Node copy(final CopyState cs) { 26.50 - return new BreakNode(this, cs); 26.51 + public boolean hasGoto() { 26.52 + return true; 26.53 } 26.54 26.55 /** 26.56 @@ -64,7 +61,7 @@ 26.57 */ 26.58 @Override 26.59 public Node accept(final NodeVisitor visitor) { 26.60 - if (visitor.enterBreakNode(this) != null) { 26.61 + if (visitor.enterBreakNode(this)) { 26.62 return visitor.leaveBreakNode(this); 26.63 } 26.64 26.65 @@ -72,26 +69,20 @@ 26.66 } 26.67 26.68 /** 26.69 - * Return the target label of this break node. 26.70 - * @return the target label. 26.71 + * Get the label for this break node 26.72 + * @return label, or null if none 26.73 */ 26.74 - public Label getTargetLabel() { 26.75 - if (targetNode instanceof BreakableNode) { 26.76 - return ((BreakableNode)targetNode).getBreakLabel(); 26.77 - } else if (targetNode instanceof Block) { 26.78 - return ((Block)targetNode).getBreakLabel(); 26.79 - } 26.80 - 26.81 - throw new AssertionError("Invalid break target " + targetNode.getClass()); 26.82 + public IdentNode getLabel() { 26.83 + return label; 26.84 } 26.85 26.86 @Override 26.87 public void toString(final StringBuilder sb) { 26.88 sb.append("break"); 26.89 26.90 - if (labelNode != null) { 26.91 + if (label != null) { 26.92 sb.append(' '); 26.93 - labelNode.getLabel().toString(sb); 26.94 + label.toString(sb); 26.95 } 26.96 } 26.97 }
27.1 --- a/src/jdk/nashorn/internal/ir/BreakableNode.java Fri Apr 19 18:23:00 2013 +0530 27.2 +++ b/src/jdk/nashorn/internal/ir/BreakableNode.java Fri Apr 19 16:11:16 2013 +0200 27.3 @@ -25,27 +25,34 @@ 27.4 27.5 package jdk.nashorn.internal.ir; 27.6 27.7 +import java.util.Arrays; 27.8 +import java.util.List; 27.9 + 27.10 import jdk.nashorn.internal.codegen.Label; 27.11 +import jdk.nashorn.internal.ir.annotations.Immutable; 27.12 import jdk.nashorn.internal.runtime.Source; 27.13 27.14 /** 27.15 * This class represents a node from which control flow can execute 27.16 * a {@code break} statement 27.17 */ 27.18 -public abstract class BreakableNode extends Node { 27.19 +@Immutable 27.20 +public abstract class BreakableNode extends LexicalContextNode { 27.21 27.22 /** break label. */ 27.23 - protected Label breakLabel; 27.24 + protected final Label breakLabel; 27.25 27.26 /** 27.27 * Constructor 27.28 * 27.29 - * @param source source code 27.30 - * @param token token 27.31 - * @param finish finish 27.32 + * @param source source code 27.33 + * @param token token 27.34 + * @param finish finish 27.35 + * @param breakLabel break label 27.36 */ 27.37 - public BreakableNode(final Source source, final long token, final int finish) { 27.38 + protected BreakableNode(final Source source, final long token, final int finish, final Label breakLabel) { 27.39 super(source, token, finish); 27.40 + this.breakLabel = breakLabel; 27.41 } 27.42 27.43 /** 27.44 @@ -55,6 +62,19 @@ 27.45 */ 27.46 protected BreakableNode(final BreakableNode breakableNode) { 27.47 super(breakableNode); 27.48 + this.breakLabel = new Label(breakableNode.getBreakLabel()); 27.49 + } 27.50 + 27.51 + @Override 27.52 + public abstract Node ensureUniqueLabels(final LexicalContext lc); 27.53 + 27.54 + /** 27.55 + * Check whether this can be broken out from without using a label, 27.56 + * e.g. everything but Blocks, basically 27.57 + * @return true if breakable without label 27.58 + */ 27.59 + protected boolean isBreakableWithoutLabel() { 27.60 + return true; 27.61 } 27.62 27.63 /** 27.64 @@ -65,4 +85,14 @@ 27.65 return breakLabel; 27.66 } 27.67 27.68 + /** 27.69 + * Return the labels associated with this node. Breakable nodes that 27.70 + * aren't LoopNodes only have a break label -> the location immediately 27.71 + * afterwards the node in code 27.72 + * @return list of labels representing locations around this node 27.73 + */ 27.74 + public List<Label> getLabels() { 27.75 + return Arrays.asList(breakLabel); 27.76 + } 27.77 + 27.78 }
28.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java Fri Apr 19 18:23:00 2013 +0530 28.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java Fri Apr 19 16:11:16 2013 +0200 28.3 @@ -25,49 +25,51 @@ 28.4 28.5 package jdk.nashorn.internal.ir; 28.6 28.7 -import java.util.ArrayList; 28.8 import java.util.Collections; 28.9 import java.util.List; 28.10 import jdk.nashorn.internal.codegen.types.Type; 28.11 import jdk.nashorn.internal.ir.annotations.Ignore; 28.12 +import jdk.nashorn.internal.ir.annotations.Immutable; 28.13 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 28.14 import jdk.nashorn.internal.runtime.Source; 28.15 28.16 /** 28.17 * IR representation for a function call. 28.18 - * 28.19 */ 28.20 -public class CallNode extends Node implements TypeOverride<CallNode> { 28.21 +@Immutable 28.22 +public final class CallNode extends LexicalContextNode implements TypeOverride<CallNode> { 28.23 28.24 - private Type type; 28.25 + private final Type type; 28.26 28.27 /** Function identifier or function body. */ 28.28 - private Node function; 28.29 + private final Node function; 28.30 28.31 /** Call arguments. */ 28.32 - private List<Node> args; 28.33 + private final List<Node> args; 28.34 28.35 - /** flag - is new expression */ 28.36 - private boolean isNew; 28.37 + /** Is this a "new" operation */ 28.38 + public static final int IS_NEW = 0x1; 28.39 28.40 - /** flag - is in with block */ 28.41 - private boolean inWithBlock; 28.42 + /** Is this call tagged as inside a with block */ 28.43 + public static final int IN_WITH_BLOCK = 0x2; 28.44 + 28.45 + private final int flags; 28.46 28.47 /** 28.48 * Arguments to be passed to builtin {@code eval} function 28.49 */ 28.50 public static class EvalArgs { 28.51 /** evaluated code */ 28.52 - private Node code; 28.53 + private final Node code; 28.54 28.55 /** 'this' passed to evaluated code */ 28.56 - private IdentNode evalThis; 28.57 + private final IdentNode evalThis; 28.58 28.59 /** location string for the eval call */ 28.60 - final private String location; 28.61 + private final String location; 28.62 28.63 /** is this call from a strict context? */ 28.64 - final private boolean strictMode; 28.65 + private final boolean strictMode; 28.66 28.67 /** 28.68 * Constructor 28.69 @@ -92,12 +94,11 @@ 28.70 return code; 28.71 } 28.72 28.73 - /** 28.74 - * Set the code that is to be eval.ed by this eval function 28.75 - * @param code the code as an AST node 28.76 - */ 28.77 - public void setCode(final Node code) { 28.78 - this.code = code; 28.79 + private EvalArgs setCode(final Node code) { 28.80 + if (this.code == code) { 28.81 + return this; 28.82 + } 28.83 + return new EvalArgs(code, evalThis, location, strictMode); 28.84 } 28.85 28.86 /** 28.87 @@ -108,12 +109,11 @@ 28.88 return this.evalThis; 28.89 } 28.90 28.91 - /** 28.92 - * Set the {@code this} symbol used to invoke this eval call 28.93 - * @param evalThis the {@code this} symbol 28.94 - */ 28.95 - public void setThis(final IdentNode evalThis) { 28.96 - this.evalThis = evalThis; 28.97 + private EvalArgs setThis(final IdentNode evalThis) { 28.98 + if (this.evalThis == evalThis) { 28.99 + return this; 28.100 + } 28.101 + return new EvalArgs(code, evalThis, location, strictMode); 28.102 } 28.103 28.104 /** 28.105 @@ -135,7 +135,7 @@ 28.106 28.107 /** arguments for 'eval' call. Non-null only if this call node is 'eval' */ 28.108 @Ignore 28.109 - private EvalArgs evalArgs; 28.110 + private final EvalArgs evalArgs; 28.111 28.112 /** 28.113 * Constructors 28.114 @@ -145,32 +145,27 @@ 28.115 * @param finish finish 28.116 * @param function the function to call 28.117 * @param args args to the call 28.118 + * @param flags flags 28.119 */ 28.120 - public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args) { 28.121 + public CallNode(final Source source, final long token, final int finish, final Node function, final List<Node> args, final int flags) { 28.122 super(source, token, finish); 28.123 28.124 - setStart(function.getStart()); 28.125 - 28.126 - this.function = function; 28.127 - this.args = args; 28.128 + this.function = function; 28.129 + this.args = args; 28.130 + this.flags = flags; 28.131 + this.type = null; 28.132 + this.evalArgs = null; 28.133 } 28.134 28.135 - private CallNode(final CallNode callNode, final CopyState cs) { 28.136 + private CallNode(final CallNode callNode, final Node function, final List<Node> args, final int flags, final Type type, final EvalArgs evalArgs) { 28.137 super(callNode); 28.138 - 28.139 - final List<Node> newArgs = new ArrayList<>(); 28.140 - 28.141 - for (final Node arg : callNode.args) { 28.142 - newArgs.add(cs.existingOrCopy(arg)); 28.143 - } 28.144 - 28.145 - this.function = cs.existingOrCopy(callNode.function); //TODO existing or same? 28.146 - this.args = newArgs; 28.147 - this.isNew = callNode.isNew; 28.148 - this.inWithBlock = callNode.inWithBlock; 28.149 + this.function = function; 28.150 + this.args = args; 28.151 + this.flags = flags; 28.152 + this.type = type; 28.153 + this.evalArgs = evalArgs; 28.154 } 28.155 28.156 - 28.157 @Override 28.158 public Type getType() { 28.159 if (hasCallSiteType()) { 28.160 @@ -181,8 +176,10 @@ 28.161 28.162 @Override 28.163 public CallNode setType(final Type type) { 28.164 - this.type = type; 28.165 - return this; 28.166 + if (this.type == type) { 28.167 + return this; 28.168 + } 28.169 + return new CallNode(this, function, args, flags, type, evalArgs); 28.170 } 28.171 28.172 private boolean hasCallSiteType() { 28.173 @@ -194,11 +191,6 @@ 28.174 return true; 28.175 } 28.176 28.177 - @Override 28.178 - protected Node copy(final CopyState cs) { 28.179 - return new CallNode(this, cs); 28.180 - } 28.181 - 28.182 /** 28.183 * Assist in IR navigation. 28.184 * 28.185 @@ -207,15 +199,22 @@ 28.186 * @return node or replacement 28.187 */ 28.188 @Override 28.189 - public Node accept(final NodeVisitor visitor) { 28.190 - if (visitor.enterCallNode(this) != null) { 28.191 - function = function.accept(visitor); 28.192 - 28.193 - for (int i = 0, count = args.size(); i < count; i++) { 28.194 - args.set(i, args.get(i).accept(visitor)); 28.195 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 28.196 + if (visitor.enterCallNode(this)) { 28.197 + final CallNode newCallNode = (CallNode)visitor.leaveCallNode( 28.198 + setFunction(function.accept(visitor)). 28.199 + setArgs(Node.accept(visitor, Node.class, args)). 28.200 + setFlags(flags). 28.201 + setType(type). 28.202 + setEvalArgs(evalArgs == null ? 28.203 + null : 28.204 + evalArgs.setCode(evalArgs.getCode().accept(visitor)). 28.205 + setThis((IdentNode)evalArgs.getThis().accept(visitor)))); 28.206 + // Theoretically, we'd need to instead pass lc to every setter and do a replacement on each. In practice, 28.207 + // setType from TypeOverride can't accept a lc, and we don't necessarily want to go there now. 28.208 + if(this != newCallNode) { 28.209 + return Node.replaceInLexicalContext(lc, this, newCallNode); 28.210 } 28.211 - 28.212 - return visitor.leaveCallNode(this); 28.213 } 28.214 28.215 return this; 28.216 @@ -226,7 +225,7 @@ 28.217 if (hasCallSiteType()) { 28.218 sb.append('{'); 28.219 final String desc = getType().getDescriptor(); 28.220 - sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 28.221 + sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor()); 28.222 sb.append('}'); 28.223 } 28.224 28.225 @@ -261,8 +260,11 @@ 28.226 * Reset the arguments for the call 28.227 * @param args new arguments list 28.228 */ 28.229 - public void setArgs(final List<Node> args) { 28.230 - this.args = args; 28.231 + private CallNode setArgs(final List<Node> args) { 28.232 + if (this.args == args) { 28.233 + return this; 28.234 + } 28.235 + return new CallNode(this, function, args, flags, type, evalArgs); 28.236 } 28.237 28.238 /** 28.239 @@ -278,9 +280,13 @@ 28.240 * {@code eval} 28.241 * 28.242 * @param evalArgs eval args 28.243 + * @return same node or new one on state change 28.244 */ 28.245 - public void setEvalArgs(final EvalArgs evalArgs) { 28.246 - this.evalArgs = evalArgs; 28.247 + public CallNode setEvalArgs(final EvalArgs evalArgs) { 28.248 + if (this.evalArgs == evalArgs) { 28.249 + return this; 28.250 + } 28.251 + return new CallNode(this, function, args, flags, type, evalArgs); 28.252 } 28.253 28.254 /** 28.255 @@ -301,10 +307,14 @@ 28.256 28.257 /** 28.258 * Reset the function expression that this call invokes 28.259 - * @param node the function 28.260 + * @param function the function 28.261 + * @return same node or new one on state change 28.262 */ 28.263 - public void setFunction(final Node node) { 28.264 - function = node; 28.265 + public CallNode setFunction(final Node function) { 28.266 + if (this.function == function) { 28.267 + return this; 28.268 + } 28.269 + return new CallNode(this, function, args, flags, type, evalArgs); 28.270 } 28.271 28.272 /** 28.273 @@ -312,14 +322,15 @@ 28.274 * @return true if this a new operation 28.275 */ 28.276 public boolean isNew() { 28.277 - return isNew; 28.278 + return (flags & IS_NEW) == IS_NEW; 28.279 } 28.280 28.281 /** 28.282 * Flag this call as a new operation 28.283 + * @return same node or new one on state change 28.284 */ 28.285 - public void setIsNew() { 28.286 - this.isNew = true; 28.287 + public CallNode setIsNew() { 28.288 + return setFlags(IS_NEW); 28.289 } 28.290 28.291 /** 28.292 @@ -327,13 +338,13 @@ 28.293 * @return true if the call is inside a {@code with} block 28.294 */ 28.295 public boolean inWithBlock() { 28.296 - return inWithBlock; 28.297 + return (flags & IN_WITH_BLOCK) == IN_WITH_BLOCK; 28.298 } 28.299 28.300 - /** 28.301 - * Flag this call to be inside a {@code with} block 28.302 - */ 28.303 - public void setInWithBlock() { 28.304 - this.inWithBlock = true; 28.305 + private CallNode setFlags(final int flags) { 28.306 + if (this.flags == flags) { 28.307 + return this; 28.308 + } 28.309 + return new CallNode(this, function, args, flags, type, evalArgs); 28.310 } 28.311 }
29.1 --- a/src/jdk/nashorn/internal/ir/CaseNode.java Fri Apr 19 18:23:00 2013 +0530 29.2 +++ b/src/jdk/nashorn/internal/ir/CaseNode.java Fri Apr 19 16:11:16 2013 +0200 29.3 @@ -26,19 +26,21 @@ 29.4 package jdk.nashorn.internal.ir; 29.5 29.6 import jdk.nashorn.internal.codegen.Label; 29.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 29.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 29.9 import jdk.nashorn.internal.runtime.Source; 29.10 29.11 /** 29.12 * IR representation of CASE clause. 29.13 - * 29.14 + * Case nodes are not BreakableNodes, but the SwitchNode is 29.15 */ 29.16 -public class CaseNode extends BreakableNode { 29.17 +@Immutable 29.18 +public final class CaseNode extends Node { 29.19 /** Test expression. */ 29.20 - private Node test; 29.21 + private final Node test; 29.22 29.23 /** Statements. */ 29.24 - private Block body; 29.25 + private final Block body; 29.26 29.27 /** Case entry label. */ 29.28 private final Label entry; 29.29 @@ -60,17 +62,17 @@ 29.30 this.entry = new Label("entry"); 29.31 } 29.32 29.33 - private CaseNode(final CaseNode caseNode, final CopyState cs) { 29.34 + CaseNode(final CaseNode caseNode, final Node test, final Block body) { 29.35 super(caseNode); 29.36 29.37 - this.test = cs.existingOrCopy(caseNode.test); 29.38 - this.body = (Block)cs.existingOrCopy(caseNode.body); 29.39 + this.test = test; 29.40 + this.body = body; 29.41 this.entry = new Label(caseNode.entry); 29.42 } 29.43 29.44 @Override 29.45 - protected Node copy(final CopyState cs) { 29.46 - return new CaseNode(this, cs); 29.47 + public boolean isTerminal() { 29.48 + return body.isTerminal(); 29.49 } 29.50 29.51 /** 29.52 @@ -79,15 +81,11 @@ 29.53 */ 29.54 @Override 29.55 public Node accept(final NodeVisitor visitor) { 29.56 - if (visitor.enterCaseNode(this) != null) { 29.57 - if (test != null) { 29.58 - test = test.accept(visitor); 29.59 - } 29.60 - if (body != null) { 29.61 - body = (Block)body.accept(visitor); 29.62 - } 29.63 + if (visitor.enterCaseNode(this)) { 29.64 + final Node newTest = test == null ? null : test.accept(visitor); 29.65 + final Block newBody = body == null ? null : (Block)body.accept(visitor); 29.66 29.67 - return visitor.leaveCaseNode(this); 29.68 + return visitor.leaveCaseNode(setTest(newTest).setBody(newBody)); 29.69 } 29.70 29.71 return this; 29.72 @@ -131,8 +129,19 @@ 29.73 /** 29.74 * Reset the test expression for this case node 29.75 * @param test new test expression 29.76 + * @return new or same CaseNode 29.77 */ 29.78 - public void setTest(final Node test) { 29.79 - this.test = test; 29.80 + public CaseNode setTest(final Node test) { 29.81 + if (this.test == test) { 29.82 + return this; 29.83 + } 29.84 + return new CaseNode(this, test, body); 29.85 + } 29.86 + 29.87 + private CaseNode setBody(final Block body) { 29.88 + if (this.body == body) { 29.89 + return this; 29.90 + } 29.91 + return new CaseNode(this, test, body); 29.92 } 29.93 }
30.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java Fri Apr 19 18:23:00 2013 +0530 30.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Fri Apr 19 16:11:16 2013 +0200 30.3 @@ -25,26 +25,23 @@ 30.4 30.5 package jdk.nashorn.internal.ir; 30.6 30.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 30.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 30.9 import jdk.nashorn.internal.runtime.Source; 30.10 30.11 /** 30.12 * IR representation of a catch clause. 30.13 - * 30.14 */ 30.15 -public class CatchNode extends Node { 30.16 +@Immutable 30.17 +public final class CatchNode extends Node { 30.18 /** Exception identifier. */ 30.19 - private IdentNode exception; 30.20 + private final IdentNode exception; 30.21 30.22 /** Exception condition. */ 30.23 - private Node exceptionCondition; 30.24 + private final Node exceptionCondition; 30.25 30.26 /** Catch body. */ 30.27 - private Block body; 30.28 - 30.29 - /** Is rethrow - e.g. synthetic catch block for e.g. finallies, the parser case where 30.30 - * there has to be at least on catch for syntactic validity */ 30.31 - private boolean isSyntheticRethrow; 30.32 + private final Block body; 30.33 30.34 /** 30.35 * Constructors 30.36 @@ -64,18 +61,12 @@ 30.37 this.body = body; 30.38 } 30.39 30.40 - private CatchNode(final CatchNode catchNode, final CopyState cs) { 30.41 + private CatchNode(final CatchNode catchNode, final IdentNode exception, final Node exceptionCondition, final Block body) { 30.42 super(catchNode); 30.43 30.44 - this.exception = (IdentNode)cs.existingOrCopy(catchNode.exception); 30.45 - this.exceptionCondition = cs.existingOrCopy(catchNode.exceptionCondition); 30.46 - this.body = (Block)cs.existingOrCopy(catchNode.body); 30.47 - this.isSyntheticRethrow = catchNode.isSyntheticRethrow; 30.48 - } 30.49 - 30.50 - @Override 30.51 - protected Node copy(final CopyState cs) { 30.52 - return new CatchNode(this, cs); 30.53 + this.exception = exception; 30.54 + this.exceptionCondition = exceptionCondition; 30.55 + this.body = body; 30.56 } 30.57 30.58 /** 30.59 @@ -84,21 +75,22 @@ 30.60 */ 30.61 @Override 30.62 public Node accept(final NodeVisitor visitor) { 30.63 - if (visitor.enterCatchNode(this) != null) { 30.64 - exception = (IdentNode)exception.accept(visitor); 30.65 - 30.66 - if (exceptionCondition != null) { 30.67 - exceptionCondition = exceptionCondition.accept(visitor); 30.68 - } 30.69 - 30.70 - body = (Block)body.accept(visitor); 30.71 - return visitor.leaveCatchNode(this); 30.72 + if (visitor.enterCatchNode(this)) { 30.73 + return visitor.leaveCatchNode( 30.74 + setException((IdentNode)exception.accept(visitor)). 30.75 + setExceptionCondition(exceptionCondition == null ? null : exceptionCondition.accept(visitor)). 30.76 + setBody((Block)body.accept(visitor))); 30.77 } 30.78 30.79 return this; 30.80 } 30.81 30.82 @Override 30.83 + public boolean isTerminal() { 30.84 + return body.isTerminal(); 30.85 + } 30.86 + 30.87 + @Override 30.88 public void toString(final StringBuilder sb) { 30.89 sb.append(" catch ("); 30.90 exception.toString(sb); 30.91 @@ -111,23 +103,6 @@ 30.92 } 30.93 30.94 /** 30.95 - * Check if this catch is a synthetic rethrow 30.96 - * @return true if this is a synthetic rethrow 30.97 - */ 30.98 - public boolean isSyntheticRethrow() { 30.99 - return isSyntheticRethrow; 30.100 - } 30.101 - 30.102 - /** 30.103 - * Flag this as deliberatly generated catch all that rethrows the 30.104 - * caught exception. This is used for example for generating finally 30.105 - * expressions 30.106 - */ 30.107 - public void setIsSyntheticRethrow() { 30.108 - this.isSyntheticRethrow = true; 30.109 - } 30.110 - 30.111 - /** 30.112 * Get the identifier representing the exception thrown 30.113 * @return the exception identifier 30.114 */ 30.115 @@ -146,9 +121,13 @@ 30.116 /** 30.117 * Reset the exception condition for this catch block 30.118 * @param exceptionCondition the new exception condition 30.119 + * @return new or same CatchNode 30.120 */ 30.121 - public void setExceptionCondition(final Node exceptionCondition) { 30.122 - this.exceptionCondition = exceptionCondition; 30.123 + public CatchNode setExceptionCondition(final Node exceptionCondition) { 30.124 + if (this.exceptionCondition == exceptionCondition) { 30.125 + return this; 30.126 + } 30.127 + return new CatchNode(this, exception, exceptionCondition, body); 30.128 } 30.129 30.130 /** 30.131 @@ -158,4 +137,18 @@ 30.132 public Block getBody() { 30.133 return body; 30.134 } 30.135 + 30.136 + private CatchNode setException(final IdentNode exception) { 30.137 + if (this.exception == exception) { 30.138 + return this; 30.139 + } 30.140 + return new CatchNode(this, exception, exceptionCondition, body); 30.141 + } 30.142 + 30.143 + private CatchNode setBody(final Block body) { 30.144 + if (this.body == body) { 30.145 + return this; 30.146 + } 30.147 + return new CatchNode(this, exception, exceptionCondition, body); 30.148 + } 30.149 }
31.1 --- a/src/jdk/nashorn/internal/ir/ContinueNode.java Fri Apr 19 18:23:00 2013 +0530 31.2 +++ b/src/jdk/nashorn/internal/ir/ContinueNode.java Fri Apr 19 16:11:16 2013 +0200 31.3 @@ -25,43 +25,39 @@ 31.4 31.5 package jdk.nashorn.internal.ir; 31.6 31.7 -import jdk.nashorn.internal.codegen.Label; 31.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 31.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 31.10 import jdk.nashorn.internal.runtime.Source; 31.11 31.12 /** 31.13 * IR representation for CONTINUE statements. 31.14 - * 31.15 */ 31.16 -public class ContinueNode extends LabeledNode { 31.17 +@Immutable 31.18 +public class ContinueNode extends Node { 31.19 + 31.20 + private IdentNode label; 31.21 31.22 /** 31.23 * Constructor 31.24 * 31.25 - * @param source the source 31.26 - * @param token token 31.27 - * @param finish finish 31.28 - * @param labelNode the continue label 31.29 - * @param targetNode node to continue to 31.30 - * @param tryChain surrounding try chain 31.31 + * @param source source code 31.32 + * @param token token 31.33 + * @param finish finish 31.34 + * @param label label for break or null if none 31.35 */ 31.36 - public ContinueNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) { 31.37 - super(source, token, finish, labelNode, targetNode, tryChain); 31.38 - setHasGoto(); 31.39 - } 31.40 - 31.41 - private ContinueNode(final ContinueNode continueNode, final CopyState cs) { 31.42 - super(continueNode, cs); 31.43 + public ContinueNode(final Source source, final long token, final int finish, final IdentNode label) { 31.44 + super(source, token, finish); 31.45 + this.label = label; 31.46 } 31.47 31.48 @Override 31.49 - protected Node copy(final CopyState cs) { 31.50 - return new ContinueNode(this, cs); 31.51 + public boolean hasGoto() { 31.52 + return true; 31.53 } 31.54 31.55 @Override 31.56 public Node accept(final NodeVisitor visitor) { 31.57 - if (visitor.enterContinueNode(this) != null) { 31.58 + if (visitor.enterContinueNode(this)) { 31.59 return visitor.leaveContinueNode(this); 31.60 } 31.61 31.62 @@ -69,21 +65,20 @@ 31.63 } 31.64 31.65 /** 31.66 - * Return the target label of this continue node. 31.67 - * @return the target label. 31.68 + * Get the label for this break node 31.69 + * @return label, or null if none 31.70 */ 31.71 - public Label getTargetLabel() { 31.72 - assert targetNode instanceof WhileNode : "continue target must be a while node"; 31.73 - return ((WhileNode)targetNode).getContinueLabel(); 31.74 + public IdentNode getLabel() { 31.75 + return label; 31.76 } 31.77 31.78 @Override 31.79 public void toString(final StringBuilder sb) { 31.80 sb.append("continue"); 31.81 31.82 - if (labelNode != null) { 31.83 + if (label != null) { 31.84 sb.append(' '); 31.85 - labelNode.getLabel().toString(sb); 31.86 + label.toString(sb); 31.87 } 31.88 } 31.89 }
32.1 --- a/src/jdk/nashorn/internal/ir/DoWhileNode.java Fri Apr 19 18:23:00 2013 +0530 32.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 32.3 @@ -1,82 +0,0 @@ 32.4 -/* 32.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 32.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 32.7 - * 32.8 - * This code is free software; you can redistribute it and/or modify it 32.9 - * under the terms of the GNU General Public License version 2 only, as 32.10 - * published by the Free Software Foundation. Oracle designates this 32.11 - * particular file as subject to the "Classpath" exception as provided 32.12 - * by Oracle in the LICENSE file that accompanied this code. 32.13 - * 32.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 32.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 32.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32.17 - * version 2 for more details (a copy is included in the LICENSE file that 32.18 - * accompanied this code). 32.19 - * 32.20 - * You should have received a copy of the GNU General Public License version 32.21 - * 2 along with this work; if not, write to the Free Software Foundation, 32.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 32.23 - * 32.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 32.25 - * or visit www.oracle.com if you need additional information or have any 32.26 - * questions. 32.27 - */ 32.28 - 32.29 -package jdk.nashorn.internal.ir; 32.30 - 32.31 -import jdk.nashorn.internal.ir.visitor.NodeVisitor; 32.32 -import jdk.nashorn.internal.runtime.Source; 32.33 - 32.34 -/** 32.35 - * Loop representing do while loops. This is mostly split from WhileNode 32.36 - * because of the different order of the Phi Traversals 32.37 - * 32.38 - */ 32.39 -public class DoWhileNode extends WhileNode { 32.40 - 32.41 - /** 32.42 - * Constructor 32.43 - * 32.44 - * @param source the source 32.45 - * @param token token 32.46 - * @param finish finish 32.47 - */ 32.48 - public DoWhileNode(final Source source, final long token, final int finish) { 32.49 - super(source, token, finish); 32.50 - } 32.51 - 32.52 - /** 32.53 - * Copy constructor 32.54 - * 32.55 - * @param doWhileNode source node 32.56 - * @param cs copy state 32.57 - */ 32.58 - protected DoWhileNode(final DoWhileNode doWhileNode, final CopyState cs) { 32.59 - super(doWhileNode, cs); 32.60 - } 32.61 - 32.62 - @Override 32.63 - protected Node copy(final CopyState cs) { 32.64 - return new DoWhileNode(this, cs); 32.65 - } 32.66 - 32.67 - @Override 32.68 - public Node accept(final NodeVisitor visitor) { 32.69 - if (visitor.enterDoWhileNode(this) != null) { 32.70 - body = (Block)body.accept(visitor); 32.71 - test = test.accept(visitor); 32.72 - 32.73 - return visitor.leaveDoWhileNode(this); 32.74 - } 32.75 - 32.76 - return this; 32.77 - } 32.78 - 32.79 - @Override 32.80 - public void toString(final StringBuilder sb) { 32.81 - sb.append("while ("); 32.82 - test.toString(sb); 32.83 - sb.append(')'); 32.84 - } 32.85 -}
33.1 --- a/src/jdk/nashorn/internal/ir/EmptyNode.java Fri Apr 19 18:23:00 2013 +0530 33.2 +++ b/src/jdk/nashorn/internal/ir/EmptyNode.java Fri Apr 19 16:11:16 2013 +0200 33.3 @@ -25,14 +25,15 @@ 33.4 33.5 package jdk.nashorn.internal.ir; 33.6 33.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 33.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 33.9 import jdk.nashorn.internal.runtime.Source; 33.10 33.11 /** 33.12 * IR representation for an empty statement. 33.13 - * 33.14 */ 33.15 -public class EmptyNode extends Node { 33.16 +@Immutable 33.17 +public final class EmptyNode extends Node { 33.18 33.19 /** 33.20 * Constructor 33.21 @@ -57,7 +58,7 @@ 33.22 33.23 @Override 33.24 public Node accept(final NodeVisitor visitor) { 33.25 - if (visitor.enterEmptyNode(this) != null) { 33.26 + if (visitor.enterEmptyNode(this)) { 33.27 return visitor.leaveEmptyNode(this); 33.28 } 33.29 return this;
34.1 --- a/src/jdk/nashorn/internal/ir/ExecuteNode.java Fri Apr 19 18:23:00 2013 +0530 34.2 +++ b/src/jdk/nashorn/internal/ir/ExecuteNode.java Fri Apr 19 16:11:16 2013 +0200 34.3 @@ -25,6 +25,7 @@ 34.4 34.5 package jdk.nashorn.internal.ir; 34.6 34.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 34.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 34.9 import jdk.nashorn.internal.runtime.Source; 34.10 34.11 @@ -33,9 +34,10 @@ 34.12 * node means "this code will be executed" and evaluating it results in 34.13 * statements being added to the IR 34.14 */ 34.15 -public class ExecuteNode extends Node { 34.16 +@Immutable 34.17 +public final class ExecuteNode extends Node { 34.18 /** Expression to execute. */ 34.19 - private Node expression; 34.20 + private final Node expression; 34.21 34.22 /** 34.23 * Constructor 34.24 @@ -50,6 +52,11 @@ 34.25 this.expression = expression; 34.26 } 34.27 34.28 + private ExecuteNode(final ExecuteNode executeNode, final Node expression) { 34.29 + super(executeNode); 34.30 + this.expression = expression; 34.31 + } 34.32 + 34.33 /** 34.34 * Constructor 34.35 * 34.36 @@ -60,34 +67,15 @@ 34.37 this.expression = expression; 34.38 } 34.39 34.40 - private ExecuteNode(final ExecuteNode executeNode, final CopyState cs) { 34.41 - super(executeNode); 34.42 - this.expression = cs.existingOrCopy(executeNode.expression); 34.43 - } 34.44 - 34.45 @Override 34.46 - protected Node copy(final CopyState cs) { 34.47 - return new ExecuteNode(this, cs); 34.48 - } 34.49 - 34.50 - @Override 34.51 - public boolean equals(final Object other) { 34.52 - if (!super.equals(other)) { 34.53 - return false; 34.54 - } 34.55 - return expression.equals(((ExecuteNode)other).getExpression()); 34.56 - } 34.57 - 34.58 - @Override 34.59 - public int hashCode() { 34.60 - return super.hashCode() ^ expression.hashCode(); 34.61 + public boolean isTerminal() { 34.62 + return expression.isTerminal(); 34.63 } 34.64 34.65 @Override 34.66 public Node accept(final NodeVisitor visitor) { 34.67 - if (visitor.enterExecuteNode(this) != null) { 34.68 - setExpression(expression.accept(visitor)); 34.69 - return visitor.leaveExecuteNode(this); 34.70 + if (visitor.enterExecuteNode(this)) { 34.71 + return visitor.leaveExecuteNode(setExpression(expression.accept(visitor))); 34.72 } 34.73 34.74 return this; 34.75 @@ -109,8 +97,12 @@ 34.76 /** 34.77 * Reset the expression to be executed 34.78 * @param expression the expression 34.79 + * @return new or same execute node 34.80 */ 34.81 - public void setExpression(final Node expression) { 34.82 - this.expression = expression; 34.83 + public ExecuteNode setExpression(final Node expression) { 34.84 + if (this.expression == expression) { 34.85 + return this; 34.86 + } 34.87 + return new ExecuteNode(this, expression); 34.88 } 34.89 }
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/src/jdk/nashorn/internal/ir/Flags.java Fri Apr 19 16:11:16 2013 +0200 35.3 @@ -0,0 +1,69 @@ 35.4 +/* 35.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 35.7 + * 35.8 + * This code is free software; you can redistribute it and/or modify it 35.9 + * under the terms of the GNU General Public License version 2 only, as 35.10 + * published by the Free Software Foundation. Oracle designates this 35.11 + * particular file as subject to the "Classpath" exception as provided 35.12 + * by Oracle in the LICENSE file that accompanied this code. 35.13 + * 35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 35.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 35.17 + * version 2 for more details (a copy is included in the LICENSE file that 35.18 + * accompanied this code). 35.19 + * 35.20 + * You should have received a copy of the GNU General Public License version 35.21 + * 2 along with this work; if not, write to the Free Software Foundation, 35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 35.23 + * 35.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 35.25 + * or visit www.oracle.com if you need additional information or have any 35.26 + * questions. 35.27 + */ 35.28 + 35.29 +package jdk.nashorn.internal.ir; 35.30 + 35.31 +/** 35.32 + * Interface implemented by all nodes that have flags in 35.33 + * a lexical context. This is needed as we sometimes have to save 35.34 + * the setting of flags in the lexical context until a block 35.35 + * is completely finished and its final version (after multiple 35.36 + * copy on writes) is placed in the lexical context 35.37 + * 35.38 + * @param <T> lexical context node that can have flags set during code generation 35.39 + */ 35.40 +public interface Flags<T extends LexicalContextNode> { 35.41 + 35.42 + /** 35.43 + * Check if a flag is set in a lexical context node 35.44 + * @param flag flag to check 35.45 + * @return flags 35.46 + */ 35.47 + public boolean getFlag(int flag); 35.48 + 35.49 + /** 35.50 + * Clear a flag of a LexicalContextNode 35.51 + * @param lc lexical context 35.52 + * @param flag flag to clear 35.53 + * @return the new LexicalContext node if flags were changed, same otherwise 35.54 + */ 35.55 + public T clearFlag(final LexicalContext lc, int flag); 35.56 + 35.57 + /** 35.58 + * Set a flag of a LexicalContextNode 35.59 + * @param lc lexical context 35.60 + * @param flag flag to set 35.61 + * @return the new LexicalContext node if flags were changed, same otherwise 35.62 + */ 35.63 + public T setFlag(final LexicalContext lc, int flag); 35.64 + 35.65 + /** 35.66 + * Set all flags of a LexicalContextNode, overwriting previous flags 35.67 + * @param lc lexical context 35.68 + * @param flags new flags value 35.69 + * @return the new LexicalContext node if flags were changed, same otherwise 35.70 + */ 35.71 + public T setFlags(final LexicalContext lc, int flags); 35.72 +}
36.1 --- a/src/jdk/nashorn/internal/ir/ForNode.java Fri Apr 19 18:23:00 2013 +0530 36.2 +++ b/src/jdk/nashorn/internal/ir/ForNode.java Fri Apr 19 16:11:16 2013 +0200 36.3 @@ -25,73 +25,75 @@ 36.4 36.5 package jdk.nashorn.internal.ir; 36.6 36.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 36.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 36.9 import jdk.nashorn.internal.runtime.Source; 36.10 36.11 /** 36.12 * IR representing a FOR statement. 36.13 - * 36.14 */ 36.15 -public class ForNode extends WhileNode { 36.16 +@Immutable 36.17 +public final class ForNode extends LoopNode { 36.18 /** Initialize expression. */ 36.19 - private Node init; 36.20 + private final Node init; 36.21 36.22 /** Test expression. */ 36.23 - private Node modify; 36.24 + private final Node modify; 36.25 36.26 /** Iterator symbol. */ 36.27 private Symbol iterator; 36.28 36.29 - /** is for in */ 36.30 - private boolean isForIn; 36.31 + /** Is this a normal for loop? */ 36.32 + public static final int IS_FOR = 1 << 0; 36.33 36.34 - /** is for each */ 36.35 - private boolean isForEach; 36.36 + /** Is this a normal for in loop? */ 36.37 + public static final int IS_FOR_IN = 1 << 1; 36.38 + 36.39 + /** Is this a normal for each in loop? */ 36.40 + public static final int IS_FOR_EACH = 1 << 2; 36.41 + 36.42 + private final int flags; 36.43 36.44 /** 36.45 * Constructor 36.46 * 36.47 - * @param source the source 36.48 - * @param token token 36.49 - * @param finish finish 36.50 + * @param source the source 36.51 + * @param token token 36.52 + * @param finish finish 36.53 + * @param init init 36.54 + * @param test test 36.55 + * @param body body 36.56 + * @param modify modify 36.57 + * @param flags flags 36.58 */ 36.59 - public ForNode(final Source source, final long token, final int finish) { 36.60 - super(source, token, finish); 36.61 + public ForNode(final Source source, final long token, final int finish, final Node init, final Node test, final Block body, final Node modify, final int flags) { 36.62 + super(source, token, finish, test, body, false); 36.63 + this.init = init; 36.64 + this.modify = modify; 36.65 + this.flags = flags; 36.66 } 36.67 36.68 - private ForNode(final ForNode forNode, final CopyState cs) { 36.69 - super(forNode, cs); 36.70 - 36.71 - this.init = cs.existingOrCopy(forNode.init); 36.72 - this.modify = cs.existingOrCopy(forNode.modify); 36.73 - this.iterator = forNode.iterator; 36.74 - this.isForIn = forNode.isForIn; 36.75 - this.isForEach = forNode.isForEach; 36.76 + private ForNode(final ForNode forNode, final Node init, final Node test, final Block body, final Node modify, final int flags, final boolean controlFlowEscapes) { 36.77 + super(forNode, test, body, controlFlowEscapes); 36.78 + this.init = init; 36.79 + this.modify = modify; 36.80 + this.flags = flags; 36.81 + this.iterator = forNode.iterator; //TODO is this acceptable? symbols are never cloned, just copied as references 36.82 } 36.83 36.84 @Override 36.85 - protected Node copy(final CopyState cs) { 36.86 - return new ForNode(this, cs); 36.87 + public Node ensureUniqueLabels(LexicalContext lc) { 36.88 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.89 } 36.90 36.91 @Override 36.92 - public Node accept(final NodeVisitor visitor) { 36.93 - if (visitor.enterForNode(this) != null) { 36.94 - if (init != null) { 36.95 - init = init.accept(visitor); 36.96 - } 36.97 - 36.98 - if (test != null) { 36.99 - test = test.accept(visitor); 36.100 - } 36.101 - 36.102 - if (modify != null) { 36.103 - modify = modify.accept(visitor); 36.104 - } 36.105 - 36.106 - body = (Block)body.accept(visitor); 36.107 - 36.108 - return visitor.leaveForNode(this); 36.109 + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { 36.110 + if (visitor.enterForNode(this)) { 36.111 + return visitor.leaveForNode( 36.112 + setInit(lc, init == null ? null : init.accept(visitor)). 36.113 + setTest(lc, test == null ? null : test.accept(visitor)). 36.114 + setModify(lc, modify == null ? null : modify.accept(visitor)). 36.115 + setBody(lc, (Block)body.accept(visitor))); 36.116 } 36.117 36.118 return this; 36.119 @@ -122,6 +124,19 @@ 36.120 sb.append(')'); 36.121 } 36.122 36.123 + @Override 36.124 + public boolean hasGoto() { 36.125 + return !isForIn() && test == null; 36.126 + } 36.127 + 36.128 + @Override 36.129 + public boolean mustEnter() { 36.130 + if (isForIn()) { 36.131 + return false; //may be an empty set to iterate over, then we skip the loop 36.132 + } 36.133 + return test == null; 36.134 + } 36.135 + 36.136 /** 36.137 * Get the initialization expression for this for loop 36.138 * @return the initialization expression 36.139 @@ -132,10 +147,15 @@ 36.140 36.141 /** 36.142 * Reset the initialization expression for this for loop 36.143 + * @param lc lexical context 36.144 * @param init new initialization expression 36.145 + * @return new for node if changed or existing if not 36.146 */ 36.147 - public void setInit(final Node init) { 36.148 - this.init = init; 36.149 + public ForNode setInit(final LexicalContext lc, final Node init) { 36.150 + if (this.init == init) { 36.151 + return this; 36.152 + } 36.153 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.154 } 36.155 36.156 /** 36.157 @@ -143,14 +163,16 @@ 36.158 * @return true if this is a for in constructor 36.159 */ 36.160 public boolean isForIn() { 36.161 - return isForIn; 36.162 + return (flags & IS_FOR_IN) != 0; 36.163 } 36.164 36.165 /** 36.166 * Flag this to be a for in construct 36.167 + * @param lc lexical context 36.168 + * @return new for node if changed or existing if not 36.169 */ 36.170 - public void setIsForIn() { 36.171 - this.isForIn = true; 36.172 + public ForNode setIsForIn(final LexicalContext lc) { 36.173 + return setFlags(lc, flags | IS_FOR_IN); 36.174 } 36.175 36.176 /** 36.177 @@ -159,14 +181,16 @@ 36.178 * @return true if this is a for each construct 36.179 */ 36.180 public boolean isForEach() { 36.181 - return isForEach; 36.182 + return (flags & IS_FOR_EACH) != 0; 36.183 } 36.184 36.185 /** 36.186 * Flag this to be a for each construct 36.187 + * @param lc lexical context 36.188 + * @return new for node if changed or existing if not 36.189 */ 36.190 - public void setIsForEach() { 36.191 - this.isForEach = true; 36.192 + public ForNode setIsForEach(final LexicalContext lc) { 36.193 + return setFlags(lc, flags | IS_FOR_EACH); 36.194 } 36.195 36.196 /** 36.197 @@ -195,10 +219,15 @@ 36.198 36.199 /** 36.200 * Reset the modification expression for this ForNode 36.201 + * @param lc lexical context 36.202 * @param modify new modification expression 36.203 + * @return new for node if changed or existing if not 36.204 */ 36.205 - public void setModify(final Node modify) { 36.206 - this.modify = modify; 36.207 + public ForNode setModify(final LexicalContext lc, final Node modify) { 36.208 + if (this.modify == modify) { 36.209 + return this; 36.210 + } 36.211 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.212 } 36.213 36.214 @Override 36.215 @@ -207,7 +236,39 @@ 36.216 } 36.217 36.218 @Override 36.219 - public void setTest(final Node test) { 36.220 - this.test = test; 36.221 + public ForNode setTest(final LexicalContext lc, final Node test) { 36.222 + if (this.test == test) { 36.223 + return this; 36.224 + } 36.225 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.226 } 36.227 + 36.228 + @Override 36.229 + public Block getBody() { 36.230 + return body; 36.231 + } 36.232 + 36.233 + @Override 36.234 + public ForNode setBody(final LexicalContext lc, final Block body) { 36.235 + if (this.body == body) { 36.236 + return this; 36.237 + } 36.238 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.239 + } 36.240 + 36.241 + @Override 36.242 + public ForNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes) { 36.243 + if (this.controlFlowEscapes == controlFlowEscapes) { 36.244 + return this; 36.245 + } 36.246 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.247 + } 36.248 + 36.249 + private ForNode setFlags(final LexicalContext lc, final int flags) { 36.250 + if (this.flags == flags) { 36.251 + return this; 36.252 + } 36.253 + return Node.replaceInLexicalContext(lc, this, new ForNode(this, init, test, body, modify, flags, controlFlowEscapes)); 36.254 + } 36.255 + 36.256 }
37.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Fri Apr 19 18:23:00 2013 +0530 37.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Fri Apr 19 16:11:16 2013 +0200 37.3 @@ -30,23 +30,19 @@ 37.4 import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; 37.5 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; 37.6 37.7 -import java.util.ArrayList; 37.8 import java.util.Collections; 37.9 import java.util.EnumSet; 37.10 -import java.util.HashMap; 37.11 -import java.util.Iterator; 37.12 +import java.util.HashSet; 37.13 import java.util.List; 37.14 -import java.util.Map; 37.15 -import java.util.Stack; 37.16 +import java.util.Set; 37.17 import jdk.nashorn.internal.codegen.CompileUnit; 37.18 import jdk.nashorn.internal.codegen.Compiler; 37.19 -import jdk.nashorn.internal.codegen.Frame; 37.20 -import jdk.nashorn.internal.codegen.MethodEmitter; 37.21 +import jdk.nashorn.internal.codegen.CompilerConstants; 37.22 import jdk.nashorn.internal.codegen.Namespace; 37.23 import jdk.nashorn.internal.codegen.types.Type; 37.24 import jdk.nashorn.internal.ir.annotations.Ignore; 37.25 +import jdk.nashorn.internal.ir.annotations.Immutable; 37.26 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 37.27 -import jdk.nashorn.internal.parser.Parser; 37.28 import jdk.nashorn.internal.runtime.ScriptFunction; 37.29 import jdk.nashorn.internal.runtime.Source; 37.30 import jdk.nashorn.internal.runtime.UserAccessorProperty; 37.31 @@ -55,9 +51,11 @@ 37.32 /** 37.33 * IR representation for function (or script.) 37.34 */ 37.35 -public class FunctionNode extends Block { 37.36 +@Immutable 37.37 +public final class FunctionNode extends LexicalContextNode implements Flags<FunctionNode> { 37.38 37.39 - private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class); 37.40 + /** Type used for all FunctionNodes */ 37.41 + public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class); 37.42 37.43 /** Function kinds */ 37.44 public enum Kind { 37.45 @@ -90,131 +88,105 @@ 37.46 /** method has had its types finalized */ 37.47 FINALIZED, 37.48 /** method has been emitted to bytecode */ 37.49 - EMITTED, 37.50 - /** code installed in a class loader */ 37.51 - INSTALLED 37.52 + EMITTED 37.53 } 37.54 37.55 /** External function identifier. */ 37.56 @Ignore 37.57 - private IdentNode ident; 37.58 + private final IdentNode ident; 37.59 + 37.60 + /** The body of the function node */ 37.61 + private final Block body; 37.62 37.63 /** Internal function name. */ 37.64 - private String name; 37.65 + private final String name; 37.66 37.67 /** Compilation unit. */ 37.68 - private CompileUnit compileUnit; 37.69 - 37.70 - /** Method emitter for current method. */ 37.71 - private MethodEmitter method; 37.72 + private final CompileUnit compileUnit; 37.73 37.74 /** Function kind. */ 37.75 - private Kind kind; 37.76 + private final Kind kind; 37.77 37.78 /** List of parameters. */ 37.79 - private List<IdentNode> parameters; 37.80 + private final List<IdentNode> parameters; 37.81 37.82 /** First token of function. **/ 37.83 - private long firstToken; 37.84 + private final long firstToken; 37.85 37.86 /** Last token of function. **/ 37.87 - private long lastToken; 37.88 + private final long lastToken; 37.89 37.90 - /** Variable frames. */ 37.91 - private Frame frames; 37.92 + /** Declared symbols in this function node */ 37.93 + @Ignore 37.94 + private final Set<Symbol> declaredSymbols; 37.95 37.96 /** Method's namespace. */ 37.97 private final Namespace namespace; 37.98 37.99 - /** Node representing current this. */ 37.100 - @Ignore 37.101 - private IdentNode thisNode; 37.102 - 37.103 - /** Node representing current scope. */ 37.104 - @Ignore 37.105 - private IdentNode scopeNode; 37.106 - 37.107 - /** Node representing return value. */ 37.108 - @Ignore 37.109 - private IdentNode resultNode; 37.110 - 37.111 - /** Node representing current arguments. */ 37.112 - @Ignore 37.113 - private IdentNode argumentsNode; 37.114 - 37.115 - /** Node representing callee */ 37.116 - @Ignore 37.117 - private IdentNode calleeNode; 37.118 - 37.119 - /** Node representing varargs */ 37.120 - @Ignore 37.121 - private IdentNode varArgsNode; 37.122 - 37.123 - /** Pending label list. */ 37.124 - private final Stack<LabelNode> labelStack; 37.125 - 37.126 - /** Pending control list. */ 37.127 - private final Stack<Node> controlStack; 37.128 - 37.129 - /** VarNode for this function statement */ 37.130 - @Ignore //this is explicit code anyway and should not be traversed after lower 37.131 - private VarNode funcVarNode; 37.132 - 37.133 - /** Line number for function declaration */ 37.134 - @Ignore 37.135 - private LineNumberNode funcVarLineNumberNode; 37.136 - 37.137 - /** Initializer var func = __callee__, where applicable */ 37.138 - @Ignore 37.139 - private Node selfSymbolInit; 37.140 - 37.141 /** Current compilation state */ 37.142 @Ignore 37.143 private final EnumSet<CompilationState> compilationState; 37.144 37.145 - /** Type hints, e.g based on parameters at call site */ 37.146 - private final Map<IdentNode, Type> specializedTypes; 37.147 - 37.148 /** Function flags. */ 37.149 - private int flags; 37.150 + private final int flags; 37.151 37.152 /** Is anonymous function flag. */ 37.153 - private static final int IS_ANONYMOUS = 1 << 0; 37.154 + public static final int IS_ANONYMOUS = 1 << 0; 37.155 + 37.156 /** Is the function created in a function declaration (as opposed to a function expression) */ 37.157 - private static final int IS_DECLARED = 1 << 1; 37.158 + public static final int IS_DECLARED = 1 << 1; 37.159 + 37.160 /** is this a strict mode function? */ 37.161 - private static final int IS_STRICT_MODE = 1 << 2; 37.162 + public static final int IS_STRICT = 1 << 2; 37.163 + 37.164 /** Does the function use the "arguments" identifier ? */ 37.165 - private static final int USES_ARGUMENTS = 1 << 3; 37.166 - /** Are we lowered ? */ 37.167 - private static final int IS_LOWERED = 1 << 4; 37.168 + public static final int USES_ARGUMENTS = 1 << 3; 37.169 + 37.170 /** Has this node been split because it was too large? */ 37.171 - private static final int IS_SPLIT = 1 << 5; 37.172 + public static final int IS_SPLIT = 1 << 4; 37.173 + 37.174 /** Does the function call eval? */ 37.175 - private static final int HAS_EVAL = 1 << 6; 37.176 + public static final int HAS_EVAL = 1 << 5; 37.177 + 37.178 /** Does the function contain a with block ? */ 37.179 - private static final int HAS_WITH = 1 << 7; 37.180 + public static final int HAS_WITH = 1 << 6; 37.181 + 37.182 /** Does a descendant function contain a with or eval? */ 37.183 - private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8; 37.184 - /** Does the function define "arguments" identifier as a parameter of nested function name? */ 37.185 - private static final int DEFINES_ARGUMENTS = 1 << 9; 37.186 - /** Does the function need a self symbol? */ 37.187 - private static final int NEEDS_SELF_SYMBOL = 1 << 10; 37.188 + public static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 7; 37.189 + 37.190 + /** 37.191 + * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function 37.192 + * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that 37.193 + * defining a local variable named "arguments" still requires construction of the Arguments object (see 37.194 + * ECMAScript 5.1 Chapter 10.5). 37.195 + * @see #needsArguments() 37.196 + */ 37.197 + public static final int DEFINES_ARGUMENTS = 1 << 8; 37.198 + 37.199 /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */ 37.200 - private static final int USES_ANCESTOR_SCOPE = 1 << 11; 37.201 + public static final int USES_ANCESTOR_SCOPE = 1 << 9; 37.202 + 37.203 /** Is this function lazily compiled? */ 37.204 - private static final int IS_LAZY = 1 << 12; 37.205 + public static final int IS_LAZY = 1 << 10; 37.206 + 37.207 /** Does this function have lazy, yet uncompiled children */ 37.208 - private static final int HAS_LAZY_CHILDREN = 1 << 13; 37.209 + public static final int HAS_LAZY_CHILDREN = 1 << 11; 37.210 + 37.211 /** Does this function have lazy, yet uncompiled children */ 37.212 - private static final int IS_PROGRAM = 1 << 14; 37.213 + public static final int IS_PROGRAM = 1 << 12; 37.214 + 37.215 + /** Does this function have nested declarations? */ 37.216 + public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13; 37.217 37.218 /** Does this function or any nested functions contain a with or an eval? */ 37.219 private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL; 37.220 + 37.221 /** Does this function need to store all its variables in scope? */ 37.222 private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN; 37.223 + 37.224 /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */ 37.225 private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL; 37.226 + 37.227 /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval. 37.228 * We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */ 37.229 private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN; 37.230 @@ -225,107 +197,77 @@ 37.231 /** 37.232 * Constructor 37.233 * 37.234 - * @param source the source 37.235 - * @param token token 37.236 - * @param finish finish 37.237 - * @param namespace the namespace 37.238 - * @param ident the identifier 37.239 - * @param name the name of the function 37.240 + * @param source the source 37.241 + * @param token token 37.242 + * @param finish finish 37.243 + * @param firstToken first token of the funtion node (including the function declaration) 37.244 + * @param namespace the namespace 37.245 + * @param ident the identifier 37.246 + * @param name the name of the function 37.247 + * @param parameters parameter list 37.248 + * @param kind kind of function as in {@link FunctionNode.Kind} 37.249 + * @param flags initial flags 37.250 */ 37.251 - public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) { 37.252 + public FunctionNode( 37.253 + final Source source, 37.254 + final long token, 37.255 + final int finish, 37.256 + final long firstToken, 37.257 + final Namespace namespace, 37.258 + final IdentNode ident, 37.259 + final String name, 37.260 + final List<IdentNode> parameters, 37.261 + final FunctionNode.Kind kind, 37.262 + final int flags) { 37.263 super(source, token, finish); 37.264 37.265 this.ident = ident; 37.266 this.name = name; 37.267 - this.kind = Kind.NORMAL; 37.268 - this.parameters = new ArrayList<>(); 37.269 - this.firstToken = token; 37.270 + this.kind = kind; 37.271 + this.parameters = parameters; 37.272 + this.firstToken = firstToken; 37.273 this.lastToken = token; 37.274 this.namespace = namespace; 37.275 - this.labelStack = new Stack<>(); 37.276 - this.controlStack = new Stack<>(); 37.277 this.compilationState = EnumSet.of(CompilationState.INITIALIZED); 37.278 - this.specializedTypes = new HashMap<>(); 37.279 + this.declaredSymbols = new HashSet<>(); 37.280 + this.flags = flags; 37.281 + this.compileUnit = null; 37.282 + this.body = null; 37.283 } 37.284 37.285 - private FunctionNode(final FunctionNode functionNode, final CopyState cs) { 37.286 - super(functionNode, cs); 37.287 + private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) { 37.288 + super(functionNode); 37.289 + this.flags = flags; 37.290 + this.returnType = returnType; 37.291 + this.compileUnit = compileUnit; 37.292 + this.lastToken = lastToken; 37.293 + this.compilationState = compilationState; 37.294 + this.body = body; 37.295 37.296 - this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident); 37.297 - this.name = functionNode.name; 37.298 + // the fields below never change - they are final and assigned in constructor 37.299 + this.name = functionNode.name; 37.300 + this.ident = functionNode.ident; 37.301 + this.namespace = functionNode.namespace; 37.302 + this.declaredSymbols = functionNode.declaredSymbols; 37.303 this.kind = functionNode.kind; 37.304 - 37.305 - this.parameters = new ArrayList<>(); 37.306 - for (final IdentNode param : functionNode.getParameters()) { 37.307 - this.parameters.add((IdentNode)cs.existingOrCopy(param)); 37.308 - } 37.309 - 37.310 - this.firstToken = functionNode.firstToken; 37.311 - this.lastToken = functionNode.lastToken; 37.312 - this.namespace = functionNode.getNamespace(); 37.313 - this.thisNode = (IdentNode)cs.existingOrCopy(functionNode.thisNode); 37.314 - this.scopeNode = (IdentNode)cs.existingOrCopy(functionNode.scopeNode); 37.315 - this.resultNode = (IdentNode)cs.existingOrCopy(functionNode.resultNode); 37.316 - this.argumentsNode = (IdentNode)cs.existingOrCopy(functionNode.argumentsNode); 37.317 - this.varArgsNode = (IdentNode)cs.existingOrCopy(functionNode.varArgsNode); 37.318 - this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode); 37.319 - this.labelStack = new Stack<>(); 37.320 - this.controlStack = new Stack<>(); 37.321 - 37.322 - this.flags = functionNode.flags; 37.323 - 37.324 - this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode); 37.325 - /** VarNode for this function statement */ 37.326 - 37.327 - this.compilationState = EnumSet.copyOf(functionNode.compilationState); 37.328 - this.specializedTypes = new HashMap<>(); 37.329 + this.parameters = functionNode.parameters; 37.330 + this.firstToken = functionNode.firstToken; 37.331 } 37.332 37.333 @Override 37.334 - protected Node copy(final CopyState cs) { 37.335 - // deep clone all parent blocks 37.336 - return new FunctionNode(this, cs); 37.337 - } 37.338 - 37.339 - @Override 37.340 - public Node accept(final NodeVisitor visitor) { 37.341 - final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode(); 37.342 - final Block saveBlock = visitor.getCurrentBlock(); 37.343 - final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter(); 37.344 - final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit(); 37.345 - 37.346 - visitor.setCurrentFunctionNode(this); 37.347 - visitor.setCurrentBlock(this); 37.348 - 37.349 - try { 37.350 - if (visitor.enterFunctionNode(this) != null) { 37.351 - if (ident != null) { 37.352 - ident = (IdentNode)ident.accept(visitor); 37.353 - } 37.354 - 37.355 - for (int i = 0, count = parameters.size(); i < count; i++) { 37.356 - parameters.set(i, (IdentNode)parameters.get(i).accept(visitor)); 37.357 - } 37.358 - 37.359 - for (int i = 0, count = statements.size(); i < count; i++) { 37.360 - statements.set(i, statements.get(i).accept(visitor)); 37.361 - } 37.362 - 37.363 - return visitor.leaveFunctionNode(this); 37.364 - } 37.365 - } finally { 37.366 - visitor.setCurrentBlock(saveBlock); 37.367 - visitor.setCurrentFunctionNode(saveFunctionNode); 37.368 - visitor.setCurrentCompileUnit(saveCompileUnit); 37.369 - visitor.setCurrentMethodEmitter(saveMethodEmitter); 37.370 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 37.371 + if (visitor.enterFunctionNode(this)) { 37.372 + return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor))); 37.373 } 37.374 - 37.375 return this; 37.376 } 37.377 37.378 - @Override 37.379 - public boolean needsScope() { 37.380 - return super.needsScope() || isProgram(); 37.381 + /** 37.382 + * Get the compilation state of this function 37.383 + * @return the compilation state 37.384 + */ 37.385 + public EnumSet<CompilationState> getState() { 37.386 + return compilationState; 37.387 } 37.388 37.389 /** 37.390 @@ -357,62 +299,17 @@ 37.391 * FunctionNode has been lowered, the compiler will add 37.392 * {@code CompilationState#LOWERED} to the state vector 37.393 * 37.394 + * @param lc lexical context 37.395 * @param state {@link CompilationState} to add 37.396 + * @return function node or a new one if state was changed 37.397 */ 37.398 - public void setState(final CompilationState state) { 37.399 - compilationState.add(state); 37.400 - } 37.401 - 37.402 - /* 37.403 - * Frame management. 37.404 - */ 37.405 - 37.406 - /** 37.407 - * Push a new block frame. 37.408 - * 37.409 - * @return the new frame 37.410 - */ 37.411 - public final Frame pushFrame() { 37.412 - frames = new Frame(frames); 37.413 - return frames; 37.414 - } 37.415 - 37.416 - /** 37.417 - * Pop a block frame. 37.418 - */ 37.419 - public final void popFrame() { 37.420 - frames = frames.getPrevious(); 37.421 - } 37.422 - 37.423 - /** 37.424 - * Create a temporary variable to the current frame. 37.425 - * 37.426 - * @param currentFrame Frame to add to - defaults to current function frame 37.427 - * @param type Strong type of symbol. 37.428 - * @param node Primary node to use symbol. 37.429 - * 37.430 - * @return Symbol used. 37.431 - */ 37.432 - public Symbol newTemporary(final Frame currentFrame, final Type type, final Node node) { 37.433 - assert currentFrame != null; 37.434 - Symbol symbol = node.getSymbol(); 37.435 - 37.436 - // If no symbol already present. 37.437 - if (symbol == null) { 37.438 - final String uname = uniqueName(TEMP_PREFIX.tag()); 37.439 - symbol = new Symbol(uname, IS_TEMP, type); 37.440 - symbol.setNode(node); 37.441 + public FunctionNode setState(final LexicalContext lc, final CompilationState state) { 37.442 + if (this.compilationState.equals(state)) { 37.443 + return this; 37.444 } 37.445 - 37.446 - // Assign a slot if it doesn't have one. 37.447 - if (!symbol.hasSlot()) { 37.448 - currentFrame.addSymbol(symbol); 37.449 - } 37.450 - 37.451 - // Set symbol to node. 37.452 - node.setSymbol(symbol); 37.453 - 37.454 - return symbol; 37.455 + final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState); 37.456 + newState.add(state); 37.457 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body)); 37.458 } 37.459 37.460 /** 37.461 @@ -425,18 +322,6 @@ 37.462 } 37.463 37.464 /** 37.465 - * Add a new temporary variable to the current frame 37.466 - * 37.467 - * @param type Strong type of symbol 37.468 - * @param node Primary node to use symbol 37.469 - * 37.470 - * @return symbol used 37.471 - */ 37.472 - public Symbol newTemporary(final Type type, final Node node) { 37.473 - return newTemporary(frames, type, node); 37.474 - } 37.475 - 37.476 - /** 37.477 * Create a virtual symbol for a literal. 37.478 * 37.479 * @param literalNode Primary node to use symbol. 37.480 @@ -444,9 +329,8 @@ 37.481 * @return Symbol used. 37.482 */ 37.483 public Symbol newLiteral(final LiteralNode<?> literalNode) { 37.484 - final String uname = uniqueName(LITERAL_PREFIX.tag()); 37.485 + final String uname = uniqueName(LITERAL_PREFIX.symbolName()); 37.486 final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType()); 37.487 - symbol.setNode(literalNode); 37.488 literalNode.setSymbol(symbol); 37.489 37.490 return symbol; 37.491 @@ -482,29 +366,35 @@ 37.492 sb.append(')'); 37.493 } 37.494 37.495 + @Override 37.496 + public boolean getFlag(final int flag) { 37.497 + return (flags & flag) != 0; 37.498 + } 37.499 + 37.500 + @Override 37.501 + public FunctionNode setFlags(final LexicalContext lc, int flags) { 37.502 + if (this.flags == flags) { 37.503 + return this; 37.504 + } 37.505 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 37.506 + } 37.507 + 37.508 + @Override 37.509 + public FunctionNode clearFlag(final LexicalContext lc, final int flag) { 37.510 + return setFlags(lc, flags & ~flag); 37.511 + } 37.512 + 37.513 + @Override 37.514 + public FunctionNode setFlag(final LexicalContext lc, final int flag) { 37.515 + return setFlags(lc, flags | flag); 37.516 + } 37.517 + 37.518 /** 37.519 * Returns true if the function is the top-level program. 37.520 * @return True if this function node represents the top-level program. 37.521 */ 37.522 public boolean isProgram() { 37.523 - return (flags & IS_PROGRAM) != 0; 37.524 - } 37.525 - 37.526 - /** 37.527 - * Marks the function as representing the top-level program. 37.528 - */ 37.529 - public void setProgram() { 37.530 - flags |= IS_PROGRAM; 37.531 - } 37.532 - 37.533 - /** 37.534 - * Get the control stack. Used when parsing to establish nesting depths of 37.535 - * different control structures 37.536 - * 37.537 - * @return the control stack 37.538 - */ 37.539 - public Stack<Node> getControlStack() { 37.540 - return controlStack; 37.541 + return getFlag(IS_PROGRAM); 37.542 } 37.543 37.544 /** 37.545 @@ -512,15 +402,7 @@ 37.546 * @return true if lazy 37.547 */ 37.548 public boolean isLazy() { 37.549 - return (flags & IS_LAZY) != 0; 37.550 - } 37.551 - 37.552 - /** 37.553 - * Set if this function should be lazily generated 37.554 - * @param isLazy is lazy 37.555 - */ 37.556 - public void setIsLazy(final boolean isLazy) { 37.557 - this.flags = isLazy ? flags | IS_LAZY : flags & ~IS_LAZY; 37.558 + return getFlag(IS_LAZY); 37.559 } 37.560 37.561 /** 37.562 @@ -529,37 +411,7 @@ 37.563 * @return true if {@code with} is used 37.564 */ 37.565 public boolean hasWith() { 37.566 - return (flags & HAS_WITH) != 0; 37.567 - } 37.568 - 37.569 - /** 37.570 - * Flag this function as using the {@code with} keyword 37.571 - * @param ancestors the iterator over functions in this functions's containing lexical context 37.572 - */ 37.573 - public void setHasWith(final Iterator<FunctionNode> ancestors) { 37.574 - if(!hasWith()) { 37.575 - this.flags |= HAS_WITH; 37.576 - // with requires scope in parents. 37.577 - // TODO: refine this. with should not force all variables in parents to be in scope, only those that are 37.578 - // actually referenced as identifiers by name 37.579 - markParentForWithOrEval(ancestors); 37.580 - } 37.581 - } 37.582 - 37.583 - private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) { 37.584 - // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope. 37.585 - setNeedsScope(); 37.586 - 37.587 - if(ancestors.hasNext()) { 37.588 - ancestors.next().setDescendantHasWithOrEval(ancestors); 37.589 - } 37.590 - } 37.591 - 37.592 - private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) { 37.593 - if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) { 37.594 - flags |= HAS_DESCENDANT_WITH_OR_EVAL; 37.595 - markParentForWithOrEval(ancestors); 37.596 - } 37.597 + return getFlag(HAS_WITH); 37.598 } 37.599 37.600 /** 37.601 @@ -568,18 +420,7 @@ 37.602 * @return true if {@code eval} is used 37.603 */ 37.604 public boolean hasEval() { 37.605 - return (flags & HAS_EVAL) != 0; 37.606 - } 37.607 - 37.608 - /** 37.609 - * Flag this function as calling the {@code eval} function 37.610 - * @param ancestors the iterator over functions in this functions's containing lexical context 37.611 - */ 37.612 - public void setHasEval(final Iterator<FunctionNode> ancestors) { 37.613 - if(!hasEval()) { 37.614 - this.flags |= HAS_EVAL; 37.615 - markParentForWithOrEval(ancestors); 37.616 - } 37.617 + return getFlag(HAS_EVAL); 37.618 } 37.619 37.620 /** 37.621 @@ -591,7 +432,7 @@ 37.622 * @return true if this or a nested function contains with or eval 37.623 */ 37.624 public boolean hasDeepWithOrEval() { 37.625 - return (flags & HAS_DEEP_WITH_OR_EVAL) != 0; 37.626 + return getFlag(HAS_DEEP_WITH_OR_EVAL); 37.627 } 37.628 37.629 /** 37.630 @@ -603,90 +444,11 @@ 37.631 } 37.632 37.633 /** 37.634 - * Set the first token for this function 37.635 - * @param firstToken the first token 37.636 + * Check whether this function has nested function declarations 37.637 + * @return true if nested function declarations exist 37.638 */ 37.639 - public void setFirstToken(final long firstToken) { 37.640 - this.firstToken = firstToken; 37.641 - } 37.642 - 37.643 - /** 37.644 - * Returns a list of functions declared by this function. Only includes declared functions, and does not include any 37.645 - * function expressions that might occur in its body. 37.646 - * @return a list of functions declared by this function. 37.647 - */ 37.648 - public List<FunctionNode> getDeclaredFunctions() { 37.649 - // Note that the function does not have a dedicated list of declared functions, but rather relies on the 37.650 - // invariant that all function declarations are at the beginning of the statement list as VarNode with a 37.651 - // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a 37.652 - // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors. 37.653 - final List<FunctionNode> fns = new ArrayList<>(); 37.654 - for (final Node stmt : statements) { 37.655 - if(stmt instanceof LineNumberNode) { 37.656 - continue; 37.657 - } else if(stmt instanceof VarNode) { 37.658 - final Node init = ((VarNode)stmt).getInit(); 37.659 - if(init instanceof FunctionNode) { 37.660 - final FunctionNode fn = (FunctionNode)init; 37.661 - if(fn.isDeclared()) { 37.662 - fns.add(fn); 37.663 - continue; 37.664 - } 37.665 - } 37.666 - } 37.667 - // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are 37.668 - // at the start of the function, we've reached the end of function declarations. 37.669 - break; 37.670 - } 37.671 - return fns; 37.672 - } 37.673 - 37.674 - /** 37.675 - * Get the label stack. This is used by the parser to establish 37.676 - * label nesting depth 37.677 - * 37.678 - * @return the label stack 37.679 - */ 37.680 - public Stack<LabelNode> getLabelStack() { 37.681 - return labelStack; 37.682 - } 37.683 - 37.684 - /** 37.685 - * If this function needs to use var args, return the identifier to the node used 37.686 - * for the var args structure 37.687 - * 37.688 - * @return IdentNode representing the var args structure 37.689 - */ 37.690 - public IdentNode getVarArgsNode() { 37.691 - return varArgsNode; 37.692 - } 37.693 - 37.694 - /** 37.695 - * Set the identifier to the node used for the var args structure 37.696 - * 37.697 - * @param varArgsNode IdentNode representing the var args 37.698 - */ 37.699 - public void setVarArgsNode(final IdentNode varArgsNode) { 37.700 - this.varArgsNode = varArgsNode; 37.701 - } 37.702 - 37.703 - /** 37.704 - * If this function uses the {@code callee} variable, return the node used 37.705 - * as this variable 37.706 - * 37.707 - * @return an IdentNode representing the {@code callee} variable 37.708 - */ 37.709 - public IdentNode getCalleeNode() { 37.710 - return calleeNode; 37.711 - } 37.712 - 37.713 - /** 37.714 - * If this function uses the {@code callee} variable, set the node representing the 37.715 - * callee 37.716 - * @param calleeNode an IdentNode representing the callee 37.717 - */ 37.718 - public void setCalleeNode(final IdentNode calleeNode) { 37.719 - this.calleeNode = calleeNode; 37.720 + public boolean hasDeclaredFunctions() { 37.721 + return getFlag(HAS_FUNCTION_DECLARATIONS); 37.722 } 37.723 37.724 /** 37.725 @@ -697,26 +459,7 @@ 37.726 * @return true if the function's generated Java method needs a {@code callee} parameter. 37.727 */ 37.728 public boolean needsCallee() { 37.729 - return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode()); 37.730 - } 37.731 - 37.732 - /** 37.733 - * If this is a function where {@code arguments} is used, return the node used as the {@code arguments} 37.734 - * variable 37.735 - * @return an IdentNode representing {@code arguments} 37.736 - */ 37.737 - public IdentNode getArgumentsNode() { 37.738 - return argumentsNode; 37.739 - } 37.740 - 37.741 - /** 37.742 - * If this is a Function where {@code arguments} is used, an identifier to the node representing 37.743 - * the {@code arguments} value has to be supplied by the compiler 37.744 - * 37.745 - * @param argumentsNode IdentNode that represents {@code arguments} 37.746 - */ 37.747 - public void setArgumentsNode(final IdentNode argumentsNode) { 37.748 - this.argumentsNode = argumentsNode; 37.749 + return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrict()); 37.750 } 37.751 37.752 /** 37.753 @@ -728,11 +471,42 @@ 37.754 } 37.755 37.756 /** 37.757 - * Reset the identifier for this function 37.758 - * @param ident IdentNode for new identifier 37.759 + * Return a set of symbols declared in this function node. This 37.760 + * is only relevant after Attr, otherwise it will be an empty 37.761 + * set as no symbols have been introduced 37.762 + * @return set of declared symbols in function 37.763 */ 37.764 - public void setIdent(final IdentNode ident) { 37.765 - this.ident = ident; 37.766 + public Set<Symbol> getDeclaredSymbols() { 37.767 + return Collections.unmodifiableSet(declaredSymbols); 37.768 + } 37.769 + 37.770 + /** 37.771 + * Add a declared symbol to this function node 37.772 + * @param symbol symbol that is declared 37.773 + */ 37.774 + public void addDeclaredSymbol(final Symbol symbol) { 37.775 + declaredSymbols.add(symbol); 37.776 + } 37.777 + 37.778 + /** 37.779 + * Get the function body 37.780 + * @return the function body 37.781 + */ 37.782 + public Block getBody() { 37.783 + return body; 37.784 + } 37.785 + 37.786 + /** 37.787 + * Reset the function body 37.788 + * @param lc lexical context 37.789 + * @param body new body 37.790 + * @return new function node if body changed, same if not 37.791 + */ 37.792 + public FunctionNode setBody(final LexicalContext lc, final Block body) { 37.793 + if(this.body == body) { 37.794 + return this; 37.795 + } 37.796 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 37.797 } 37.798 37.799 /** 37.800 @@ -748,17 +522,6 @@ 37.801 } 37.802 37.803 /** 37.804 - * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function 37.805 - * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that 37.806 - * defining a local variable named "arguments" still requires construction of the Arguments object (see 37.807 - * ECMAScript 5.1 Chapter 10.5). 37.808 - * @see #needsArguments() 37.809 - */ 37.810 - public void setDefinesArguments() { 37.811 - this.flags |= DEFINES_ARGUMENTS; 37.812 - } 37.813 - 37.814 - /** 37.815 * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments". 37.816 * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function 37.817 * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that 37.818 @@ -770,15 +533,7 @@ 37.819 public boolean needsArguments() { 37.820 // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since 37.821 // for top-level script, "arguments" is picked up from Context by Global.init() instead. 37.822 - return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram(); 37.823 - } 37.824 - 37.825 - /** 37.826 - * Flags this function as one that uses the "arguments" identifier. 37.827 - * @see #needsArguments() 37.828 - */ 37.829 - public void setUsesArguments() { 37.830 - flags |= USES_ARGUMENTS; 37.831 + return getFlag(MAYBE_NEEDS_ARGUMENTS) && !getFlag(DEFINES_ARGUMENTS) && !isProgram(); 37.832 } 37.833 37.834 /** 37.835 @@ -789,7 +544,7 @@ 37.836 * @return true if the function needs parent scope. 37.837 */ 37.838 public boolean needsParentScope() { 37.839 - return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram(); 37.840 + return getFlag(NEEDS_PARENT_SCOPE) || isProgram(); 37.841 } 37.842 37.843 /** 37.844 @@ -802,15 +557,6 @@ 37.845 } 37.846 37.847 /** 37.848 - * Set the kind of this function 37.849 - * @see FunctionNode.Kind 37.850 - * @param kind the kind 37.851 - */ 37.852 - public void setKind(final Kind kind) { 37.853 - this.kind = kind; 37.854 - } 37.855 - 37.856 - /** 37.857 * Return the last token for this function's code 37.858 * @return last token 37.859 */ 37.860 @@ -820,10 +566,15 @@ 37.861 37.862 /** 37.863 * Set the last token for this function's code 37.864 + * @param lc lexical context 37.865 * @param lastToken the last token 37.866 + * @return function node or a new one if state was changed 37.867 */ 37.868 - public void setLastToken(final long lastToken) { 37.869 - this.lastToken = lastToken; 37.870 + public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) { 37.871 + if (this.lastToken == lastToken) { 37.872 + return this; 37.873 + } 37.874 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 37.875 } 37.876 37.877 /** 37.878 @@ -835,21 +586,13 @@ 37.879 } 37.880 37.881 /** 37.882 - * Set the name of this function 37.883 - * @param name the name 37.884 - */ 37.885 - public void setName(final String name) { 37.886 - this.name = name; 37.887 - } 37.888 - 37.889 - /** 37.890 * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and 37.891 * functions having with and/or eval blocks are such. 37.892 * 37.893 * @return true if all variables should be in scope 37.894 */ 37.895 public boolean allVarsInScope() { 37.896 - return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0; 37.897 + return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE); 37.898 } 37.899 37.900 /** 37.901 @@ -858,15 +601,7 @@ 37.902 * @return true if this function is split from a larger one 37.903 */ 37.904 public boolean isSplit() { 37.905 - return (flags & IS_SPLIT) != 0; 37.906 - } 37.907 - 37.908 - /** 37.909 - * Flag this function node as being a sub-function generated by the splitter 37.910 - */ 37.911 - public void setIsSplit() { 37.912 - this.flags |= IS_SPLIT; 37.913 - setNeedsScope(); 37.914 + return getFlag(IS_SPLIT); 37.915 } 37.916 37.917 /** 37.918 @@ -875,15 +610,7 @@ 37.919 * @return true if there are lazy child functions 37.920 */ 37.921 public boolean hasLazyChildren() { 37.922 - return (flags & HAS_LAZY_CHILDREN) != 0; 37.923 - } 37.924 - 37.925 - /** 37.926 - * Flag this function node as having yet-to-be-generated child functions 37.927 - */ 37.928 - public void setHasLazyChildren() { 37.929 - this.flags |= HAS_LAZY_CHILDREN; 37.930 - setNeedsScope(); 37.931 + return getFlag(HAS_LAZY_CHILDREN); 37.932 } 37.933 37.934 /** 37.935 @@ -895,66 +622,13 @@ 37.936 } 37.937 37.938 /** 37.939 - * Set the paremeters to this function 37.940 - * @param parameters a list of IdentNodes representing parameters in left to right order 37.941 - */ 37.942 - public void setParameters(final List<IdentNode> parameters) { 37.943 - this.parameters = parameters; 37.944 - } 37.945 - 37.946 - /** 37.947 * Get a specialized type for an identity, if one exists 37.948 * @param node node to check specialized type for 37.949 * @return null if no specialization exists, otherwise type 37.950 */ 37.951 + @SuppressWarnings("static-method") 37.952 public Type getSpecializedType(final IdentNode node) { 37.953 - return specializedTypes.get(node); 37.954 - } 37.955 - 37.956 - /** 37.957 - * Set parameter type hints for specialization. 37.958 - * @param types types array of length equal to parameter list size 37.959 - */ 37.960 - public void setParameterTypes(final Class<?>[] types) { 37.961 - assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types"; 37.962 - //diff - skip the callee and this etc, they are not explicit params in the parse tree 37.963 - for (int i = 0; i < types.length ; i++) { 37.964 - specializedTypes.put(parameters.get(i), Type.typeFor(types[i])); 37.965 - } 37.966 - } 37.967 - 37.968 - /** 37.969 - * Get the identifier for the variable in which the function return value 37.970 - * should be stored 37.971 - * @return an IdentNode representing the return value 37.972 - */ 37.973 - public IdentNode getResultNode() { 37.974 - return resultNode; 37.975 - } 37.976 - 37.977 - /** 37.978 - * Set the identifier representing the variable in which the function return 37.979 - * value should be stored 37.980 - * @param resultNode an IdentNode representing the return value 37.981 - */ 37.982 - public void setResultNode(final IdentNode resultNode) { 37.983 - this.resultNode = resultNode; 37.984 - } 37.985 - 37.986 - /** 37.987 - * Get the identifier representing this function's scope 37.988 - * @return an IdentNode representing this function's scope 37.989 - */ 37.990 - public IdentNode getScopeNode() { 37.991 - return scopeNode; 37.992 - } 37.993 - 37.994 - /** 37.995 - * Set the identifier representing this function's scope 37.996 - * @param scopeNode an IdentNode representing this function's scope 37.997 - */ 37.998 - public void setScopeNode(final IdentNode scopeNode) { 37.999 - this.scopeNode = scopeNode; 37.1000 + return null; //TODO implement specialized types later 37.1001 } 37.1002 37.1003 /** 37.1004 @@ -962,15 +636,7 @@ 37.1005 * @return true if function is declared. 37.1006 */ 37.1007 public boolean isDeclared() { 37.1008 - return (flags & IS_DECLARED) != 0; 37.1009 - } 37.1010 - 37.1011 - /** 37.1012 - * Flag this function as being created as a function declaration (as opposed to a function expression). 37.1013 - * @see Parser 37.1014 - */ 37.1015 - public void setIsDeclared() { 37.1016 - this.flags |= IS_DECLARED; 37.1017 + return getFlag(IS_DECLARED); 37.1018 } 37.1019 37.1020 /** 37.1021 @@ -978,15 +644,7 @@ 37.1022 * @return true if function is anonymous 37.1023 */ 37.1024 public boolean isAnonymous() { 37.1025 - return (flags & IS_ANONYMOUS) != 0; 37.1026 - } 37.1027 - 37.1028 - /** 37.1029 - * Flag this function as an anonymous function. 37.1030 - * @see Parser 37.1031 - */ 37.1032 - public void setIsAnonymous() { 37.1033 - this.flags |= IS_ANONYMOUS; 37.1034 + return getFlag(IS_ANONYMOUS); 37.1035 } 37.1036 37.1037 /** 37.1038 @@ -995,109 +653,7 @@ 37.1039 * @return true if function needs a symbol for self 37.1040 */ 37.1041 public boolean needsSelfSymbol() { 37.1042 - return (flags & NEEDS_SELF_SYMBOL) != 0; 37.1043 - } 37.1044 - 37.1045 - /** 37.1046 - * Get the initializer statement for the __callee__ variable, where applicable 37.1047 - * for self references 37.1048 - * @return initialization 37.1049 - */ 37.1050 - public Node getSelfSymbolInit() { 37.1051 - return this.selfSymbolInit; 37.1052 - } 37.1053 - 37.1054 - /** 37.1055 - * Flag the function as needing a self symbol. This is needed only for 37.1056 - * self referring functions 37.1057 - * @param selfSymbolInit initialization expression for self symbol 37.1058 - */ 37.1059 - public void setNeedsSelfSymbol(final Node selfSymbolInit) { 37.1060 - this.flags |= NEEDS_SELF_SYMBOL; 37.1061 - this.selfSymbolInit = selfSymbolInit; 37.1062 - } 37.1063 - 37.1064 - /** 37.1065 - * Marks this function as using any of its ancestors' scopes. 37.1066 - */ 37.1067 - public void setUsesAncestorScope() { 37.1068 - this.flags |= USES_ANCESTOR_SCOPE; 37.1069 - } 37.1070 - 37.1071 - @Override 37.1072 - void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) { 37.1073 - setUsesAncestorScope(); 37.1074 - super.setUsesParentScopeSymbol(symbol, ancestors); 37.1075 - } 37.1076 - 37.1077 - /** 37.1078 - * Return the node representing {@code this} in this function 37.1079 - * @return IdentNode representing {@code this} 37.1080 - */ 37.1081 - public IdentNode getThisNode() { 37.1082 - return thisNode; 37.1083 - } 37.1084 - 37.1085 - /** 37.1086 - * Set the node representing {@code this} in this function 37.1087 - * @param thisNode identifier representing {@code this} 37.1088 - */ 37.1089 - public void setThisNode(final IdentNode thisNode) { 37.1090 - this.thisNode = thisNode; 37.1091 - } 37.1092 - 37.1093 - /** 37.1094 - * Every function declared as {@code function x()} is internally hoisted 37.1095 - * and represented as {@code var x = function() ... }. This getter returns 37.1096 - * the VarNode representing this virtual assignment 37.1097 - * 37.1098 - * @return the var node emitted for setting this function symbol 37.1099 - */ 37.1100 - public VarNode getFunctionVarNode() { 37.1101 - return funcVarNode; 37.1102 - } 37.1103 - 37.1104 - /** 37.1105 - * Set the virtual VarNode assignment for this function. 37.1106 - * @see FunctionNode#getFunctionVarNode() 37.1107 - * 37.1108 - * @param varNode the virtual var node assignment 37.1109 - */ 37.1110 - public void setFunctionVarNode(final VarNode varNode) { 37.1111 - funcVarNode = varNode; 37.1112 - } 37.1113 - 37.1114 - /** 37.1115 - * The line number information where the function was declared must be propagated 37.1116 - * to the virtual {@code var x = function() ... } assignment described in 37.1117 - * {@link FunctionNode#getFunctionVarNode()} 37.1118 - * This maintains the line number of the declaration 37.1119 - * 37.1120 - * @return a line number node representing the line this function was declared 37.1121 - */ 37.1122 - public LineNumberNode getFunctionVarLineNumberNode() { 37.1123 - return funcVarLineNumberNode; 37.1124 - } 37.1125 - 37.1126 - /** 37.1127 - * Set the virtual VarNode assignment for this function, along with 37.1128 - * a line number node for tracking the original start line of the function 37.1129 - * declaration 37.1130 - * 37.1131 - * @param varNode the virtual var node assignment 37.1132 - * @param lineNumber the line number node for the function declaration 37.1133 - */ 37.1134 - public void setFunctionVarNode(final VarNode varNode, final LineNumberNode lineNumber) { 37.1135 - funcVarNode = varNode; 37.1136 - funcVarLineNumberNode = lineNumber; 37.1137 - } 37.1138 - 37.1139 - /** 37.1140 - * Get the namespace this function uses for its symbols 37.1141 - * @return the namespace 37.1142 - */ 37.1143 - public Namespace getNamespace() { 37.1144 - return namespace; 37.1145 + return body.getFlag(Block.NEEDS_SELF_SYMBOL); 37.1146 } 37.1147 37.1148 @Override 37.1149 @@ -1118,47 +674,38 @@ 37.1150 37.1151 /** 37.1152 * Set the function return type 37.1153 - * 37.1154 + * @param lc lexical context 37.1155 * @param returnType new return type 37.1156 + * @return function node or a new one if state was changed 37.1157 */ 37.1158 - public void setReturnType(final Type returnType) { 37.1159 + public FunctionNode setReturnType(final LexicalContext lc, final Type returnType) { 37.1160 //we never bother with object types narrower than objects, that will lead to byte code verification errors 37.1161 //as for instance even if we know we are returning a string from a method, the code generator will always 37.1162 //treat it as an object, at least for now 37.1163 - this.returnType = Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType); 37.1164 - } 37.1165 - 37.1166 - /** 37.1167 - * Set strict mode on or off for this function 37.1168 - * 37.1169 - * @param isStrictMode true if strict mode should be enabled 37.1170 - */ 37.1171 - public void setStrictMode(final boolean isStrictMode) { 37.1172 - flags = isStrictMode ? flags | IS_STRICT_MODE : flags & ~IS_STRICT_MODE; 37.1173 + if (this.returnType == returnType) { 37.1174 + return this; 37.1175 + } 37.1176 + return Node.replaceInLexicalContext( 37.1177 + lc, 37.1178 + this, 37.1179 + new FunctionNode( 37.1180 + this, 37.1181 + lastToken, 37.1182 + flags, 37.1183 + Type.widest(this.returnType, returnType.isObject() ? 37.1184 + Type.OBJECT : 37.1185 + returnType), 37.1186 + compileUnit, 37.1187 + compilationState, 37.1188 + body)); 37.1189 } 37.1190 37.1191 /** 37.1192 * Check if the function is generated in strict mode 37.1193 * @return true if strict mode enabled for function 37.1194 */ 37.1195 - public boolean isStrictMode() { 37.1196 - return (flags & IS_STRICT_MODE) != 0; 37.1197 - } 37.1198 - 37.1199 - /** 37.1200 - * Set the lowered state 37.1201 - */ 37.1202 - public void setIsLowered() { 37.1203 - flags |= IS_LOWERED; 37.1204 - } 37.1205 - 37.1206 - /** 37.1207 - * Get the lowered state 37.1208 - * 37.1209 - * @return true if function is lowered 37.1210 - */ 37.1211 - public boolean isLowered() { 37.1212 - return (flags & IS_LOWERED) != 0; 37.1213 + public boolean isStrict() { 37.1214 + return getFlag(IS_STRICT); 37.1215 } 37.1216 37.1217 /** 37.1218 @@ -1173,25 +720,47 @@ 37.1219 /** 37.1220 * Reset the compile unit used to compile this function 37.1221 * @see Compiler 37.1222 + * @param lc lexical context 37.1223 * @param compileUnit the compile unit 37.1224 + * @return function node or a new one if state was changed 37.1225 */ 37.1226 - public void setCompileUnit(final CompileUnit compileUnit) { 37.1227 - this.compileUnit = compileUnit; 37.1228 + public FunctionNode setCompileUnit(final LexicalContext lc, final CompileUnit compileUnit) { 37.1229 + if (this.compileUnit == compileUnit) { 37.1230 + return this; 37.1231 + } 37.1232 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 37.1233 } 37.1234 37.1235 /** 37.1236 - * Return the method emitter used to write bytecode for this function 37.1237 - * @return the method emitter 37.1238 + * Create a temporary variable to the current frame. 37.1239 + * 37.1240 + * @param block that needs the temporary 37.1241 + * @param type Strong type of symbol. 37.1242 + * @param node Primary node to use symbol. 37.1243 + * 37.1244 + * @return Symbol used. 37.1245 */ 37.1246 - public MethodEmitter getMethodEmitter() { 37.1247 - return method; 37.1248 + public Symbol ensureSymbol(final Block block, final Type type, final Node node) { 37.1249 + Symbol symbol = node.getSymbol(); 37.1250 + 37.1251 + // If no symbol already present. 37.1252 + if (symbol == null) { 37.1253 + final String uname = uniqueName(TEMP_PREFIX.symbolName()); 37.1254 + symbol = new Symbol(uname, IS_TEMP, type); 37.1255 + block.putSymbol(uname, symbol); 37.1256 + node.setSymbol(symbol); 37.1257 + } 37.1258 + 37.1259 + return symbol; 37.1260 } 37.1261 37.1262 /** 37.1263 - * Set the method emitter that is to be used to write bytecode for this function 37.1264 - * @param method a method emitter 37.1265 + * Get the symbol for a compiler constant, or null if not available (yet) 37.1266 + * @param cc compiler constant 37.1267 + * @return symbol for compiler constant, or null if not defined yet (for example in Lower) 37.1268 */ 37.1269 - public void setMethodEmitter(final MethodEmitter method) { 37.1270 - this.method = method; 37.1271 + public Symbol compilerConstant(final CompilerConstants cc) { 37.1272 + return body.getExistingSymbol(cc.symbolName()); 37.1273 } 37.1274 + 37.1275 }
38.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java Fri Apr 19 18:23:00 2013 +0530 38.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Fri Apr 19 16:11:16 2013 +0200 38.3 @@ -32,13 +32,15 @@ 38.4 38.5 import jdk.nashorn.internal.codegen.ObjectClassGenerator; 38.6 import jdk.nashorn.internal.codegen.types.Type; 38.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 38.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 38.9 import jdk.nashorn.internal.runtime.Source; 38.10 38.11 /** 38.12 * IR representation for an identifier. 38.13 */ 38.14 -public class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall { 38.15 +@Immutable 38.16 +public final class IdentNode extends Node implements PropertyKey, TypeOverride<IdentNode>, FunctionCall { 38.17 private static final int PROPERTY_NAME = 1 << 0; 38.18 private static final int INITIALIZED_HERE = 1 << 1; 38.19 private static final int FUNCTION = 1 << 2; 38.20 @@ -47,9 +49,9 @@ 38.21 private final String name; 38.22 38.23 /** Type for a callsite, e.g. X in a get()X or a set(X)V */ 38.24 - private Type callSiteType; 38.25 + private final Type callSiteType; 38.26 38.27 - private byte flags; 38.28 + private final int flags; 38.29 38.30 /** 38.31 * Constructor 38.32 @@ -62,6 +64,15 @@ 38.33 public IdentNode(final Source source, final long token, final int finish, final String name) { 38.34 super(source, token, finish); 38.35 this.name = name; 38.36 + this.callSiteType = null; 38.37 + this.flags = 0; 38.38 + } 38.39 + 38.40 + private IdentNode(final IdentNode identNode, final String name, final Type callSiteType, final int flags) { 38.41 + super(identNode); 38.42 + this.name = name; 38.43 + this.callSiteType = callSiteType; 38.44 + this.flags = flags; 38.45 } 38.46 38.47 /** 38.48 @@ -71,8 +82,9 @@ 38.49 */ 38.50 public IdentNode(final IdentNode identNode) { 38.51 super(identNode); 38.52 - this.name = identNode.getName(); 38.53 - this.flags = identNode.flags; 38.54 + this.name = identNode.getName(); 38.55 + this.callSiteType = null; 38.56 + this.flags = identNode.flags; 38.57 } 38.58 38.59 @Override 38.60 @@ -92,40 +104,15 @@ 38.61 38.62 @Override 38.63 public IdentNode setType(final Type type) { 38.64 - if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 38.65 - ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 38.66 - } 38.67 // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't 38.68 - if(this.callSiteType == type) { 38.69 + if (this.callSiteType == type) { 38.70 return this; 38.71 } 38.72 - final IdentNode n = (IdentNode)clone(); 38.73 - n.callSiteType = type; 38.74 - return n; 38.75 - } 38.76 + if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 38.77 + ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType()); 38.78 + } 38.79 38.80 - @Override 38.81 - protected Node copy(final CopyState cs) { 38.82 - return new IdentNode(this); 38.83 - } 38.84 - 38.85 - /** 38.86 - * Test to see if two IdentNode are the same. 38.87 - * 38.88 - * @param other Other ident. 38.89 - * @return true if the idents are the same. 38.90 - */ 38.91 - @Override 38.92 - public boolean equals(final Object other) { 38.93 - if (other instanceof IdentNode) { 38.94 - return name.equals(((IdentNode)other).name); 38.95 - } 38.96 - return false; 38.97 - } 38.98 - 38.99 - @Override 38.100 - public int hashCode() { 38.101 - return name.hashCode(); 38.102 + return new IdentNode(this, name, type, flags); 38.103 } 38.104 38.105 /** 38.106 @@ -135,7 +122,7 @@ 38.107 */ 38.108 @Override 38.109 public Node accept(final NodeVisitor visitor) { 38.110 - if (visitor.enterIdentNode(this) != null) { 38.111 + if (visitor.enterIdentNode(this)) { 38.112 return visitor.leaveIdentNode(this); 38.113 } 38.114 38.115 @@ -147,7 +134,7 @@ 38.116 if (hasCallSiteType()) { 38.117 sb.append('{'); 38.118 final String desc = getType().getDescriptor(); 38.119 - sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 38.120 + sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor()); 38.121 sb.append('}'); 38.122 } 38.123 38.124 @@ -191,10 +178,10 @@ 38.125 * @return a node equivalent to this one except for the requested change. 38.126 */ 38.127 public IdentNode setIsPropertyName() { 38.128 - if(isPropertyName()) return this; 38.129 - final IdentNode n = (IdentNode)clone(); 38.130 - n.flags |= PROPERTY_NAME; 38.131 - return n; 38.132 + if (isPropertyName()) { 38.133 + return this; 38.134 + } 38.135 + return new IdentNode(this, name, callSiteType, flags | PROPERTY_NAME); 38.136 } 38.137 38.138 /** 38.139 @@ -210,10 +197,10 @@ 38.140 * @return a node equivalent to this one except for the requested change. 38.141 */ 38.142 public IdentNode setIsInitializedHere() { 38.143 - if(isInitializedHere()) return this; 38.144 - final IdentNode n = (IdentNode)clone(); 38.145 - n.flags |= INITIALIZED_HERE; 38.146 - return n; 38.147 + if (isInitializedHere()) { 38.148 + return this; 38.149 + } 38.150 + return new IdentNode(this, name, callSiteType, flags | INITIALIZED_HERE); 38.151 } 38.152 38.153 /** 38.154 @@ -223,7 +210,7 @@ 38.155 * @return true if this IdentNode is special 38.156 */ 38.157 public boolean isSpecialIdentity() { 38.158 - return name.equals(__DIR__.tag()) || name.equals(__FILE__.tag()) || name.equals(__LINE__.tag()); 38.159 + return name.equals(__DIR__.symbolName()) || name.equals(__FILE__.symbolName()) || name.equals(__LINE__.symbolName()); 38.160 } 38.161 38.162 @Override 38.163 @@ -236,9 +223,9 @@ 38.164 * @return an ident node identical to this one in all aspects except with its function flag set. 38.165 */ 38.166 public IdentNode setIsFunction() { 38.167 - if(isFunction()) return this; 38.168 - final IdentNode n = (IdentNode)clone(); 38.169 - n.flags |= FUNCTION; 38.170 - return n; 38.171 + if (isFunction()) { 38.172 + return this; 38.173 + } 38.174 + return new IdentNode(this, name, callSiteType, flags | FUNCTION); 38.175 } 38.176 }
39.1 --- a/src/jdk/nashorn/internal/ir/IfNode.java Fri Apr 19 18:23:00 2013 +0530 39.2 +++ b/src/jdk/nashorn/internal/ir/IfNode.java Fri Apr 19 16:11:16 2013 +0200 39.3 @@ -25,22 +25,23 @@ 39.4 39.5 package jdk.nashorn.internal.ir; 39.6 39.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 39.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 39.9 import jdk.nashorn.internal.runtime.Source; 39.10 39.11 /** 39.12 * IR representation for an IF statement. 39.13 - * 39.14 */ 39.15 -public class IfNode extends Node { 39.16 +@Immutable 39.17 +public final class IfNode extends Node { 39.18 /** Test expression. */ 39.19 - private Node test; 39.20 + private final Node test; 39.21 39.22 /** Pass statements. */ 39.23 - private Block pass; 39.24 + private final Block pass; 39.25 39.26 /** Fail statements. */ 39.27 - private Block fail; 39.28 + private final Block fail; 39.29 39.30 /** 39.31 * Constructor 39.32 @@ -54,37 +55,30 @@ 39.33 */ 39.34 public IfNode(final Source source, final long token, final int finish, final Node test, final Block pass, final Block fail) { 39.35 super(source, token, finish); 39.36 - 39.37 this.test = test; 39.38 this.pass = pass; 39.39 this.fail = fail; 39.40 } 39.41 39.42 - private IfNode(final IfNode ifNode, final CopyState cs) { 39.43 + private IfNode(final IfNode ifNode, final Node test, final Block pass, final Block fail) { 39.44 super(ifNode); 39.45 - 39.46 - this.test = cs.existingOrCopy(ifNode.test); 39.47 - this.pass = (Block)cs.existingOrCopy(ifNode.pass); 39.48 - this.fail = (Block)cs.existingOrCopy(ifNode.fail); 39.49 + this.test = test; 39.50 + this.pass = pass; 39.51 + this.fail = fail; 39.52 } 39.53 39.54 @Override 39.55 - protected Node copy(final CopyState cs) { 39.56 - return new IfNode(this, cs); 39.57 + public boolean isTerminal() { 39.58 + return pass.isTerminal() && fail != null && fail.isTerminal(); 39.59 } 39.60 39.61 @Override 39.62 public Node accept(final NodeVisitor visitor) { 39.63 - if (visitor.enterIfNode(this) != null) { 39.64 - test = test.accept(visitor); 39.65 - 39.66 - pass = (Block)pass.accept(visitor); 39.67 - 39.68 - if (fail != null) { 39.69 - fail = (Block)fail.accept(visitor); 39.70 - } 39.71 - 39.72 - return visitor.leaveIfNode(this); 39.73 + if (visitor.enterIfNode(this)) { 39.74 + return visitor.leaveIfNode( 39.75 + setTest(test.accept(visitor)). 39.76 + setPass((Block)pass.accept(visitor)). 39.77 + setFail(fail == null ? null : (Block)fail.accept(visitor))); 39.78 } 39.79 39.80 return this; 39.81 @@ -105,6 +99,13 @@ 39.82 return fail; 39.83 } 39.84 39.85 + private IfNode setFail(final Block fail) { 39.86 + if (this.fail == fail) { 39.87 + return this; 39.88 + } 39.89 + return new IfNode(this, test, pass, fail); 39.90 + } 39.91 + 39.92 /** 39.93 * Get the then block for this IfNode 39.94 * @return the then block 39.95 @@ -113,6 +114,13 @@ 39.96 return pass; 39.97 } 39.98 39.99 + private IfNode setPass(final Block pass) { 39.100 + if (this.pass == pass) { 39.101 + return this; 39.102 + } 39.103 + return new IfNode(this, test, pass, fail); 39.104 + } 39.105 + 39.106 /** 39.107 * Get the test expression for this IfNode 39.108 * @return the test expression 39.109 @@ -124,8 +132,12 @@ 39.110 /** 39.111 * Reset the test expression for this IfNode 39.112 * @param test a new test expression 39.113 + * @return new or same IfNode 39.114 */ 39.115 - public void setTest(final Node test) { 39.116 - this.test = test; 39.117 + public IfNode setTest(final Node test) { 39.118 + if (this.test == test) { 39.119 + return this; 39.120 + } 39.121 + return new IfNode(this, test, pass, fail); 39.122 } 39.123 }
40.1 --- a/src/jdk/nashorn/internal/ir/IndexNode.java Fri Apr 19 18:23:00 2013 +0530 40.2 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java Fri Apr 19 16:11:16 2013 +0200 40.3 @@ -25,22 +25,18 @@ 40.4 40.5 package jdk.nashorn.internal.ir; 40.6 40.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; 40.8 - 40.9 -import jdk.nashorn.internal.codegen.ObjectClassGenerator; 40.10 import jdk.nashorn.internal.codegen.types.Type; 40.11 +import jdk.nashorn.internal.ir.annotations.Immutable; 40.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 40.13 import jdk.nashorn.internal.runtime.Source; 40.14 40.15 /** 40.16 * IR representation of an indexed access (brackets operator.) 40.17 - * 40.18 */ 40.19 -public class IndexNode extends BaseNode implements TypeOverride<IndexNode> { 40.20 - /** Property ident. */ 40.21 - private Node index; 40.22 - 40.23 - private boolean hasCallSiteType; 40.24 +@Immutable 40.25 +public final class IndexNode extends BaseNode { 40.26 + /** Property index. */ 40.27 + private final Node index; 40.28 40.29 /** 40.30 * Constructors 40.31 @@ -52,50 +48,27 @@ 40.32 * @param index index for access 40.33 */ 40.34 public IndexNode(final Source source, final long token, final int finish, final Node base, final Node index) { 40.35 - super(source, token, finish, base); 40.36 - 40.37 + super(source, token, finish, base, false, false); 40.38 this.index = index; 40.39 } 40.40 40.41 - /** 40.42 - * Copy constructor 40.43 - * 40.44 - * @param indexNode source node 40.45 - */ 40.46 - public IndexNode(final IndexNode indexNode) { 40.47 - this(indexNode, new CopyState()); 40.48 - } 40.49 - 40.50 - private IndexNode(final IndexNode indexNode, final CopyState cs) { 40.51 - super(indexNode, cs); 40.52 - 40.53 - index = cs.existingOrCopy(indexNode.index); 40.54 - } 40.55 - 40.56 - @Override 40.57 - protected Node copy(final CopyState cs) { 40.58 - return new IndexNode(this, cs); 40.59 - } 40.60 - 40.61 - @Override 40.62 - public boolean equals(final Object other) { 40.63 - if (!super.equals(other)) { 40.64 - return false; 40.65 - } 40.66 - return index.equals(((IndexNode)other).getIndex()); 40.67 - } 40.68 - 40.69 - @Override 40.70 - public int hashCode() { 40.71 - return super.hashCode() ^ getIndex().hashCode(); 40.72 + private IndexNode(final IndexNode indexNode, final Node base, final Node index, final boolean isFunction, final boolean hasCallSiteType) { 40.73 + super(indexNode, base, isFunction, hasCallSiteType); 40.74 + this.index = index; 40.75 } 40.76 40.77 @Override 40.78 public Node accept(final NodeVisitor visitor) { 40.79 - if (visitor.enterIndexNode(this) != null) { 40.80 - base = base.accept(visitor); 40.81 - index = index.accept(visitor); 40.82 - return visitor.leaveIndexNode(this); 40.83 + if (visitor.enterIndexNode(this)) { 40.84 + final Node newBase = base.accept(visitor); 40.85 + final Node newIndex = index.accept(visitor); 40.86 + final IndexNode newNode; 40.87 + if (newBase != base || newIndex != index) { 40.88 + newNode = new IndexNode(this, newBase, newIndex, isFunction(), hasCallSiteType()); 40.89 + } else { 40.90 + newNode = this; 40.91 + } 40.92 + return visitor.leaveIndexNode(newNode); 40.93 } 40.94 40.95 return this; 40.96 @@ -105,7 +78,7 @@ 40.97 public void toString(final StringBuilder sb) { 40.98 final boolean needsParen = tokenType().needsParens(base.tokenType(), true); 40.99 40.100 - if (hasCallSiteType) { 40.101 + if (hasCallSiteType()) { 40.102 sb.append('{'); 40.103 final String desc = getType().getDescriptor(); 40.104 sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 40.105 @@ -135,27 +108,19 @@ 40.106 return index; 40.107 } 40.108 40.109 - /** 40.110 - * Reset the index expression for this IndexNode 40.111 - * @param index a new index expression 40.112 - */ 40.113 - public void setIndex(final Node index) { 40.114 - this.index = index; 40.115 + @Override 40.116 + public BaseNode setIsFunction() { 40.117 + if (isFunction()) { 40.118 + return this; 40.119 + } 40.120 + return new IndexNode(this, base, index, true, hasCallSiteType()); 40.121 } 40.122 40.123 @Override 40.124 public IndexNode setType(final Type type) { 40.125 - if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 40.126 - ObjectClassGenerator.LOG.info(getClass().getName() + " " + this + " => " + type + " instead of " + getType()); 40.127 - } 40.128 - hasCallSiteType = true; 40.129 - getSymbol().setTypeOverride(type); 40.130 - return this; 40.131 - } 40.132 - 40.133 - @Override 40.134 - public boolean canHaveCallSiteType() { 40.135 - return true; //carried by the symbol and always the same nodetype==symboltype 40.136 + logTypeChange(type); 40.137 + getSymbol().setTypeOverride(type); //always a temp so this is fine. 40.138 + return new IndexNode(this, base, index, isFunction(), true); 40.139 } 40.140 40.141 }
41.1 --- a/src/jdk/nashorn/internal/ir/LabelNode.java Fri Apr 19 18:23:00 2013 +0530 41.2 +++ b/src/jdk/nashorn/internal/ir/LabelNode.java Fri Apr 19 16:11:16 2013 +0200 41.3 @@ -25,29 +25,20 @@ 41.4 41.5 package jdk.nashorn.internal.ir; 41.6 41.7 -import jdk.nashorn.internal.ir.annotations.Ignore; 41.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 41.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 41.10 import jdk.nashorn.internal.runtime.Source; 41.11 41.12 /** 41.13 * IR representation for a labeled statement. 41.14 - * 41.15 */ 41.16 - 41.17 -public class LabelNode extends Node { 41.18 +@Immutable 41.19 +public final class LabelNode extends LexicalContextNode { 41.20 /** Label ident. */ 41.21 - private IdentNode label; 41.22 + private final IdentNode label; 41.23 41.24 /** Statements. */ 41.25 - private Block body; 41.26 - 41.27 - /** Node to break from. */ 41.28 - @Ignore 41.29 - private Node breakNode; 41.30 - 41.31 - /** Node to continue. */ 41.32 - @Ignore 41.33 - private Node continueNode; 41.34 + private final Block body; 41.35 41.36 /** 41.37 * Constructor 41.38 @@ -65,26 +56,23 @@ 41.39 this.body = body; 41.40 } 41.41 41.42 - private LabelNode(final LabelNode labelNode, final CopyState cs) { 41.43 + private LabelNode(final LabelNode labelNode, final IdentNode label, final Block body) { 41.44 super(labelNode); 41.45 - 41.46 - this.label = (IdentNode)cs.existingOrCopy(labelNode.label); 41.47 - this.body = (Block)cs.existingOrCopy(labelNode.body); 41.48 - this.breakNode = cs.existingOrSame(labelNode.breakNode); 41.49 - this.continueNode = cs.existingOrSame(labelNode.continueNode); 41.50 + this.label = label; 41.51 + this.body = body; 41.52 } 41.53 41.54 @Override 41.55 - protected Node copy(final CopyState cs) { 41.56 - return new LabelNode(this, cs); 41.57 + public boolean isTerminal() { 41.58 + return body.isTerminal(); 41.59 } 41.60 41.61 @Override 41.62 - public Node accept(final NodeVisitor visitor) { 41.63 - if (visitor.enterLabelNode(this) != null) { 41.64 - label = (IdentNode)label.accept(visitor); 41.65 - body = (Block)body.accept(visitor); 41.66 - return visitor.leaveLabelNode(this); 41.67 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 41.68 + if (visitor.enterLabelNode(this)) { 41.69 + return visitor.leaveLabelNode( 41.70 + setLabel(visitor.getLexicalContext(), (IdentNode)label.accept(visitor)). 41.71 + setBody(visitor.getLexicalContext(), (Block)body.accept(visitor))); 41.72 } 41.73 41.74 return this; 41.75 @@ -106,44 +94,15 @@ 41.76 41.77 /** 41.78 * Reset the body of the node 41.79 + * @param lc lexical context 41.80 * @param body new body 41.81 + * @return new for node if changed or existing if not 41.82 */ 41.83 - public void setBody(final Block body) { 41.84 - this.body = body; 41.85 - } 41.86 - 41.87 - /** 41.88 - * Get the break node for this node 41.89 - * @return the break node 41.90 - */ 41.91 - public Node getBreakNode() { 41.92 - return breakNode; 41.93 - } 41.94 - 41.95 - /** 41.96 - * Reset the break node for this node 41.97 - * @param breakNode the break node 41.98 - */ 41.99 - public void setBreakNode(final Node breakNode) { 41.100 - assert breakNode instanceof BreakableNode || breakNode instanceof Block : "Invalid break node: " + breakNode; 41.101 - this.breakNode = breakNode; 41.102 - } 41.103 - 41.104 - /** 41.105 - * Get the continue node for this node 41.106 - * @return the continue node 41.107 - */ 41.108 - public Node getContinueNode() { 41.109 - return continueNode; 41.110 - } 41.111 - 41.112 - /** 41.113 - * Reset the continue node for this node 41.114 - * @param continueNode the continue node 41.115 - */ 41.116 - public void setContinueNode(final Node continueNode) { 41.117 - assert continueNode instanceof WhileNode : "invalid continue node: " + continueNode; 41.118 - this.continueNode = continueNode; 41.119 + public LabelNode setBody(final LexicalContext lc, final Block body) { 41.120 + if (this.body == body) { 41.121 + return this; 41.122 + } 41.123 + return Node.replaceInLexicalContext(lc, this, new LabelNode(this, label, body)); 41.124 } 41.125 41.126 /** 41.127 @@ -154,4 +113,11 @@ 41.128 return label; 41.129 } 41.130 41.131 + private LabelNode setLabel(final LexicalContext lc, final IdentNode label) { 41.132 + if (this.label == label) { 41.133 + return this; 41.134 + } 41.135 + return Node.replaceInLexicalContext(lc, this, new LabelNode(this, label, body)); 41.136 + } 41.137 + 41.138 }
42.1 --- a/src/jdk/nashorn/internal/ir/LabeledNode.java Fri Apr 19 18:23:00 2013 +0530 42.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 42.3 @@ -1,123 +0,0 @@ 42.4 -/* 42.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 42.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42.7 - * 42.8 - * This code is free software; you can redistribute it and/or modify it 42.9 - * under the terms of the GNU General Public License version 2 only, as 42.10 - * published by the Free Software Foundation. Oracle designates this 42.11 - * particular file as subject to the "Classpath" exception as provided 42.12 - * by Oracle in the LICENSE file that accompanied this code. 42.13 - * 42.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 42.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 42.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 42.17 - * version 2 for more details (a copy is included in the LICENSE file that 42.18 - * accompanied this code). 42.19 - * 42.20 - * You should have received a copy of the GNU General Public License version 42.21 - * 2 along with this work; if not, write to the Free Software Foundation, 42.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 42.23 - * 42.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 42.25 - * or visit www.oracle.com if you need additional information or have any 42.26 - * questions. 42.27 - */ 42.28 - 42.29 -package jdk.nashorn.internal.ir; 42.30 - 42.31 -import jdk.nashorn.internal.ir.annotations.Ignore; 42.32 -import jdk.nashorn.internal.runtime.Source; 42.33 - 42.34 -/** 42.35 - * IR base class for break and continue. 42.36 - * 42.37 - */ 42.38 -public abstract class LabeledNode extends Node { 42.39 - /** Optional label. */ 42.40 - @Ignore 42.41 - protected final LabelNode labelNode; 42.42 - 42.43 - /** Target control node. */ 42.44 - @Ignore 42.45 - protected final Node targetNode; 42.46 - 42.47 - /** Try chain. */ 42.48 - @Ignore 42.49 - protected final TryNode tryChain; 42.50 - 42.51 - /** scope nesting level */ 42.52 - protected int scopeNestingLevel; 42.53 - 42.54 - /** 42.55 - * Constructor 42.56 - * 42.57 - * @param source the source 42.58 - * @param token token 42.59 - * @param finish finish 42.60 - * @param labelNode the label node 42.61 - * @param targetNode the place to break to 42.62 - * @param tryChain the try chain 42.63 - */ 42.64 - public LabeledNode(final Source source, final long token, final int finish, final LabelNode labelNode, final Node targetNode, final TryNode tryChain) { 42.65 - super(source, token, finish); 42.66 - 42.67 - this.labelNode = labelNode; 42.68 - this.targetNode = targetNode; 42.69 - this.tryChain = tryChain; 42.70 - } 42.71 - 42.72 - /** 42.73 - * Copy constructor 42.74 - * 42.75 - * @param labeledNode source node 42.76 - * @param cs copy state 42.77 - */ 42.78 - protected LabeledNode(final LabeledNode labeledNode, final CopyState cs) { 42.79 - super(labeledNode); 42.80 - 42.81 - this.labelNode = (LabelNode)cs.existingOrCopy(labeledNode.labelNode); 42.82 - this.targetNode = cs.existingOrSame(labeledNode.targetNode); 42.83 - this.tryChain = (TryNode)cs.existingOrSame(labeledNode.tryChain); 42.84 - this.scopeNestingLevel = labeledNode.scopeNestingLevel; 42.85 - } 42.86 - 42.87 - /** 42.88 - * Get the label 42.89 - * @return the label 42.90 - */ 42.91 - public LabelNode getLabel() { 42.92 - return labelNode; 42.93 - } 42.94 - 42.95 - /** 42.96 - * Get the target node 42.97 - * @return the target node 42.98 - */ 42.99 - public Node getTargetNode() { 42.100 - return targetNode; 42.101 - } 42.102 - 42.103 - /** 42.104 - * Get the surrounding try chain 42.105 - * @return the try chain 42.106 - */ 42.107 - public TryNode getTryChain() { 42.108 - return tryChain; 42.109 - } 42.110 - 42.111 - /** 42.112 - * Get the scope nesting level 42.113 - * @return nesting level 42.114 - */ 42.115 - public int getScopeNestingLevel() { 42.116 - return scopeNestingLevel; 42.117 - } 42.118 - 42.119 - /** 42.120 - * Set scope nesting level 42.121 - * @param level the new level 42.122 - */ 42.123 - public void setScopeNestingLevel(final int level) { 42.124 - scopeNestingLevel = level; 42.125 - } 42.126 -}
43.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java Fri Apr 19 18:23:00 2013 +0530 43.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Fri Apr 19 16:11:16 2013 +0200 43.3 @@ -1,40 +1,224 @@ 43.4 +/* 43.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 43.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 43.7 + * 43.8 + * This code is free software; you can redistribute it and/or modify it 43.9 + * under the terms of the GNU General Public License version 2 only, as 43.10 + * published by the Free Software Foundation. Oracle designates this 43.11 + * particular file as subject to the "Classpath" exception as provided 43.12 + * by Oracle in the LICENSE file that accompanied this code. 43.13 + * 43.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 43.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 43.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 43.17 + * version 2 for more details (a copy is included in the LICENSE file that 43.18 + * accompanied this code). 43.19 + * 43.20 + * You should have received a copy of the GNU General Public License version 43.21 + * 2 along with this work; if not, write to the Free Software Foundation, 43.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 43.23 + * 43.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 43.25 + * or visit www.oracle.com if you need additional information or have any 43.26 + * questions. 43.27 + */ 43.28 package jdk.nashorn.internal.ir; 43.29 43.30 -import java.util.ArrayDeque; 43.31 -import java.util.Deque; 43.32 +import java.io.File; 43.33 import java.util.Iterator; 43.34 import java.util.NoSuchElementException; 43.35 43.36 +import jdk.nashorn.internal.codegen.Label; 43.37 +import jdk.nashorn.internal.runtime.Debug; 43.38 +import jdk.nashorn.internal.runtime.Source; 43.39 + 43.40 /** 43.41 * A class that tracks the current lexical context of node visitation as a stack of {@link Block} nodes. Has special 43.42 * methods to retrieve useful subsets of the context. 43.43 + * 43.44 + * This is implemented with a primitive array and a stack pointer, because it really makes a difference 43.45 + * performance wise. None of the collection classes were optimal 43.46 */ 43.47 -public class LexicalContext implements Cloneable { 43.48 - private final Deque<Block> lexicalContext; 43.49 +public class LexicalContext { 43.50 + private LexicalContextNode[] stack; 43.51 + 43.52 + private int[] flags; 43.53 + private int sp; 43.54 43.55 /** 43.56 * Creates a new empty lexical context. 43.57 */ 43.58 public LexicalContext() { 43.59 - lexicalContext = new ArrayDeque<>(); 43.60 + stack = new LexicalContextNode[16]; 43.61 + flags = new int[16]; 43.62 } 43.63 43.64 /** 43.65 - * Pushes a new block on top of the context, making it the innermost open block. 43.66 - * @param block the new block 43.67 + * Set the flags for a lexical context node on the stack. Does not 43.68 + * replace the flags, but rather adds to them 43.69 + * 43.70 + * @param node node 43.71 + * @param flag new flag to set 43.72 */ 43.73 - public void push(Block block) { 43.74 - //new Exception(block.toString()).printStackTrace(); 43.75 - lexicalContext.push(block); 43.76 + public void setFlag(final LexicalContextNode node, final int flag) { 43.77 + if (flag != 0) { 43.78 + for (int i = sp - 1; i >= 0; i--) { 43.79 + if (stack[i] == node) { 43.80 + flags[i] |= flag; 43.81 + //System.err.println("Setting flag " + node + " " + flag); 43.82 + return; 43.83 + } 43.84 + } 43.85 + } 43.86 + assert false; 43.87 } 43.88 43.89 /** 43.90 - * Pops the innermost block off the context. 43.91 - * @param the block expected to be popped, used to detect unbalanced pushes/pops 43.92 + * Get the flags for a lexical context node on the stack 43.93 + * @param node node 43.94 + * @return the flags for the node 43.95 */ 43.96 - public void pop(Block block) { 43.97 - final Block popped = lexicalContext.pop(); 43.98 - assert popped == block; 43.99 + public int getFlags(final LexicalContextNode node) { 43.100 + for (int i = sp - 1; i >= 0; i--) { 43.101 + if (stack[i] == node) { 43.102 + return flags[i]; 43.103 + } 43.104 + } 43.105 + throw new AssertionError("flag node not on context stack"); 43.106 + } 43.107 + 43.108 + /** 43.109 + * Get the function body of a function node on the lexical context 43.110 + * stack. This will trigger an assertion if node isn't present 43.111 + * @param functionNode function node 43.112 + * @return body of function node 43.113 + */ 43.114 + public Block getFunctionBody(final FunctionNode functionNode) { 43.115 + for (int i = sp - 1; i >= 0 ; i--) { 43.116 + if (stack[i] == functionNode) { 43.117 + return (Block)stack[i + 1]; 43.118 + } 43.119 + } 43.120 + throw new AssertionError(functionNode.getName() + " not on context stack"); 43.121 + } 43.122 + 43.123 + /** 43.124 + * Return all nodes in the LexicalContext 43.125 + * @return all nodes 43.126 + */ 43.127 + public Iterator<LexicalContextNode> getAllNodes() { 43.128 + return new NodeIterator<>(LexicalContextNode.class); 43.129 + } 43.130 + 43.131 + /** 43.132 + * Returns the outermost function in this context. It is either the program, or a lazily compiled function. 43.133 + * @return the outermost function in this context. 43.134 + */ 43.135 + public FunctionNode getOutermostFunction() { 43.136 + return (FunctionNode)stack[0]; 43.137 + } 43.138 + 43.139 + 43.140 + 43.141 + /** 43.142 + * Pushes a new block on top of the context, making it the innermost open block. 43.143 + * @param node the new node 43.144 + * @return the node that was pushed 43.145 + */ 43.146 + public <T extends LexicalContextNode> T push(final T node) { 43.147 + if (sp == stack.length) { 43.148 + final LexicalContextNode[] newStack = new LexicalContextNode[sp * 2]; 43.149 + System.arraycopy(stack, 0, newStack, 0, sp); 43.150 + stack = newStack; 43.151 + 43.152 + final int[] newFlags = new int[sp * 2]; 43.153 + System.arraycopy(flags, 0, newFlags, 0, sp); 43.154 + flags = newFlags; 43.155 + 43.156 + } 43.157 + stack[sp] = node; 43.158 + flags[sp] = 0; 43.159 + 43.160 + sp++; 43.161 + 43.162 + return node; 43.163 + } 43.164 + 43.165 + /** 43.166 + * Is the context empty? 43.167 + * @return true if empty 43.168 + */ 43.169 + public boolean isEmpty() { 43.170 + return sp == 0; 43.171 + } 43.172 + 43.173 + /** 43.174 + * The depth of the lexical context 43.175 + * @return depth 43.176 + */ 43.177 + public int size() { 43.178 + return sp; 43.179 + } 43.180 + 43.181 + /** 43.182 + * Pops the innermost block off the context and all nodes that has been contributed 43.183 + * since it was put there 43.184 + * 43.185 + * @param node the node expected to be popped, used to detect unbalanced pushes/pops 43.186 + * @return the node that was popped 43.187 + */ 43.188 + @SuppressWarnings("unchecked") 43.189 + public <T extends LexicalContextNode> T pop(final T node) { 43.190 + --sp; 43.191 + final LexicalContextNode popped = stack[sp]; 43.192 + if (popped instanceof Flags) { 43.193 + return (T)((Flags<?>)popped).setFlag(this, flags[sp]); 43.194 + } 43.195 + 43.196 + return (T)popped; 43.197 + } 43.198 + 43.199 + 43.200 + /** 43.201 + * Return the top element in the context 43.202 + * @return the node that was pushed last 43.203 + */ 43.204 + public LexicalContextNode peek() { 43.205 + return stack[sp - 1]; 43.206 + } 43.207 + 43.208 + /** 43.209 + * Check if a node is in the lexical context 43.210 + * @param node node to check for 43.211 + * @return true if in the context 43.212 + */ 43.213 + public boolean contains(final LexicalContextNode node) { 43.214 + for (int i = 0; i < sp; i++) { 43.215 + if (stack[i] == node) { 43.216 + return true; 43.217 + } 43.218 + } 43.219 + return false; 43.220 + } 43.221 + 43.222 + /** 43.223 + * Replace a node on the lexical context with a new one. Normally 43.224 + * you should try to engineer IR traversals so this isn't needed 43.225 + * 43.226 + * @param oldNode old node 43.227 + * @param newNode new node 43.228 + * @return the new node 43.229 + */ 43.230 + public LexicalContextNode replace(final LexicalContextNode oldNode, final LexicalContextNode newNode) { 43.231 + //System.err.println("REPLACE old=" + Debug.id(oldNode) + " new=" + Debug.id(newNode)); 43.232 + for (int i = sp - 1; i >= 0; i--) { 43.233 + if (stack[i] == oldNode) { 43.234 + assert i == (sp - 1) : "violation of contract - we always expect to find the replacement node on top of the lexical context stack: " + newNode + " has " + stack[i + 1].getClass() + " above it"; 43.235 + stack[i] = newNode; 43.236 + break; 43.237 + } 43.238 + } 43.239 + return newNode; 43.240 } 43.241 43.242 /** 43.243 @@ -42,7 +226,7 @@ 43.244 * @return an iterator over all blocks in the context. 43.245 */ 43.246 public Iterator<Block> getBlocks() { 43.247 - return lexicalContext.iterator(); 43.248 + return new NodeIterator<>(Block.class); 43.249 } 43.250 43.251 /** 43.252 @@ -50,47 +234,17 @@ 43.253 * @return an iterator over all functions in the context. 43.254 */ 43.255 public Iterator<FunctionNode> getFunctions() { 43.256 - return new FunctionIterator(getBlocks()); 43.257 + return new NodeIterator<>(FunctionNode.class); 43.258 } 43.259 43.260 - private static final class FunctionIterator implements Iterator<FunctionNode> { 43.261 - private final Iterator<Block> it; 43.262 - private FunctionNode next; 43.263 - 43.264 - FunctionIterator(Iterator<Block> it) { 43.265 - this.it = it; 43.266 - next = findNext(); 43.267 - } 43.268 - 43.269 - @Override 43.270 - public boolean hasNext() { 43.271 - return next != null; 43.272 - } 43.273 - 43.274 - @Override 43.275 - public FunctionNode next() { 43.276 - if(next == null) { 43.277 - throw new NoSuchElementException(); 43.278 - } 43.279 - FunctionNode lnext = next; 43.280 - next = findNext(); 43.281 - return lnext; 43.282 - } 43.283 - 43.284 - private FunctionNode findNext() { 43.285 - while(it.hasNext()) { 43.286 - final Block block = it.next(); 43.287 - if(block instanceof FunctionNode) { 43.288 - return ((FunctionNode)block); 43.289 - } 43.290 - } 43.291 - return null; 43.292 - } 43.293 - 43.294 - @Override 43.295 - public void remove() { 43.296 - throw new UnsupportedOperationException(); 43.297 - } 43.298 + /** 43.299 + * Get the parent block for the current lexical context block 43.300 + * @return parent block 43.301 + */ 43.302 + public Block getParentBlock() { 43.303 + final Iterator<Block> iter = new NodeIterator<>(Block.class, getCurrentFunction()); 43.304 + iter.next(); 43.305 + return iter.hasNext() ? iter.next() : null; 43.306 } 43.307 43.308 /** 43.309 @@ -98,12 +252,12 @@ 43.310 * @param block the block whose ancestors are returned 43.311 * @return an iterator over all ancestors block of the given block. 43.312 */ 43.313 - public Iterator<Block> getAncestorBlocks(Block block) { 43.314 - final Iterator<Block> it = getBlocks(); 43.315 - while(it.hasNext()) { 43.316 - final Block b = it.next(); 43.317 - if(block == b) { 43.318 - return it; 43.319 + public Iterator<Block> getAncestorBlocks(final Block block) { 43.320 + final Iterator<Block> iter = getBlocks(); 43.321 + while (iter.hasNext()) { 43.322 + final Block b = iter.next(); 43.323 + if (block == b) { 43.324 + return iter; 43.325 } 43.326 } 43.327 throw new AssertionError("Block is not on the current lexical context stack"); 43.328 @@ -115,17 +269,17 @@ 43.329 * @return an iterator over a block and all its ancestors. 43.330 */ 43.331 public Iterator<Block> getBlocks(final Block block) { 43.332 - final Iterator<Block> it = getAncestorBlocks(block); 43.333 + final Iterator<Block> iter = getAncestorBlocks(block); 43.334 return new Iterator<Block>() { 43.335 boolean blockReturned = false; 43.336 @Override 43.337 public boolean hasNext() { 43.338 - return it.hasNext() || !blockReturned; 43.339 + return iter.hasNext() || !blockReturned; 43.340 } 43.341 @Override 43.342 public Block next() { 43.343 - if(blockReturned) { 43.344 - return it.next(); 43.345 + if (blockReturned) { 43.346 + return iter.next(); 43.347 } 43.348 blockReturned = true; 43.349 return block; 43.350 @@ -138,45 +292,25 @@ 43.351 } 43.352 43.353 /** 43.354 - * Returns the closest function node to the block. If the block is itself a function, it is returned. 43.355 - * @param block the block 43.356 - * @return the function closest to the block. 43.357 - * @see #getParentFunction(Block) 43.358 + * Get the function for this block. If the block is itself a function 43.359 + * this returns identity 43.360 + * @param block block for which to get function 43.361 + * @return function for block 43.362 */ 43.363 - public FunctionNode getFunction(Block block) { 43.364 - if(block instanceof FunctionNode) { 43.365 - return (FunctionNode)block; 43.366 - } 43.367 - return getParentFunction(block); 43.368 - } 43.369 - 43.370 - /** 43.371 - * Returns the closest function node to the block and all its ancestor functions. If the block is itself a function, 43.372 - * it is returned too. 43.373 - * @param block the block 43.374 - * @return the closest function node to the block and all its ancestor functions. 43.375 - */ 43.376 - public Iterator<FunctionNode> getFunctions(final Block block) { 43.377 - return new FunctionIterator(getBlocks(block)); 43.378 - } 43.379 - 43.380 - /** 43.381 - * Returns the containing function of the block. If the block is itself a function, its parent function is returned. 43.382 - * @param block the block 43.383 - * @return the containing function of the block. 43.384 - * @see #getFunction(Block) 43.385 - */ 43.386 - public FunctionNode getParentFunction(Block block) { 43.387 - return getFirstFunction(getAncestorBlocks(block)); 43.388 - } 43.389 - 43.390 - private static FunctionNode getFirstFunction(Iterator<Block> it) { 43.391 - while(it.hasNext()) { 43.392 - final Block ancestor = it.next(); 43.393 - if(ancestor instanceof FunctionNode) { 43.394 - return (FunctionNode)ancestor; 43.395 + public FunctionNode getFunction(final Block block) { 43.396 + final Iterator<LexicalContextNode> iter = new NodeIterator<>(LexicalContextNode.class); 43.397 + while (iter.hasNext()) { 43.398 + final LexicalContextNode next = iter.next(); 43.399 + if (next == block) { 43.400 + while (iter.hasNext()) { 43.401 + final LexicalContextNode next2 = iter.next(); 43.402 + if (next2 instanceof FunctionNode) { 43.403 + return (FunctionNode)next2; 43.404 + } 43.405 + } 43.406 } 43.407 } 43.408 + assert false; 43.409 return null; 43.410 } 43.411 43.412 @@ -185,7 +319,7 @@ 43.413 * @return the innermost block in the context. 43.414 */ 43.415 public Block getCurrentBlock() { 43.416 - return lexicalContext.element(); 43.417 + return getBlocks().next(); 43.418 } 43.419 43.420 /** 43.421 @@ -193,6 +327,292 @@ 43.422 * @return the innermost function in the context. 43.423 */ 43.424 public FunctionNode getCurrentFunction() { 43.425 - return getFirstFunction(getBlocks()); 43.426 + if (isEmpty()) { 43.427 + return null; 43.428 + } 43.429 + return new NodeIterator<>(FunctionNode.class).next(); 43.430 + } 43.431 + 43.432 + /** 43.433 + * Get the block in which a symbol is defined 43.434 + * @param symbol symbol 43.435 + * @return block in which the symbol is defined, assert if no such block in context 43.436 + */ 43.437 + public Block getDefiningBlock(final Symbol symbol) { 43.438 + if (symbol.isTemp()) { 43.439 + return null; 43.440 + } 43.441 + final String name = symbol.getName(); 43.442 + for (final Iterator<Block> it = getBlocks(); it.hasNext();) { 43.443 + final Block next = it.next(); 43.444 + if (next.getExistingSymbol(name) == symbol) { 43.445 + return next; 43.446 + } 43.447 + } 43.448 + throw new AssertionError("Couldn't find symbol " + name + " in the context"); 43.449 + } 43.450 + 43.451 + /** 43.452 + * Get the function in which a symbol is defined 43.453 + * @param symbol symbol 43.454 + * @return function node in which this symbol is defined, assert if no such symbol exists in context 43.455 + */ 43.456 + public FunctionNode getDefiningFunction(Symbol symbol) { 43.457 + if (symbol.isTemp()) { 43.458 + return null; 43.459 + } 43.460 + final String name = symbol.getName(); 43.461 + for (final Iterator<LexicalContextNode> iter = new NodeIterator<>(LexicalContextNode.class); iter.hasNext();) { 43.462 + final LexicalContextNode next = iter.next(); 43.463 + if (next instanceof Block && ((Block)next).getExistingSymbol(name) == symbol) { 43.464 + while (iter.hasNext()) { 43.465 + final LexicalContextNode next2 = iter.next(); 43.466 + if (next2 instanceof FunctionNode) { 43.467 + return ((FunctionNode)next2); 43.468 + } 43.469 + } 43.470 + throw new AssertionError("Defining block for symbol " + name + " has no function in the context"); 43.471 + } 43.472 + } 43.473 + throw new AssertionError("Couldn't find symbol " + name + " in the context"); 43.474 + } 43.475 + 43.476 + /** 43.477 + * Is the topmost lexical context element a function body? 43.478 + * @return true if function body 43.479 + */ 43.480 + public boolean isFunctionBody() { 43.481 + return getParentBlock() == null; 43.482 + } 43.483 + 43.484 + /** 43.485 + * Returns true if the expression defining the function is a callee of a CallNode that should be the second 43.486 + * element on the stack, e.g. <code>(function(){})()</code>. That is, if the stack ends with 43.487 + * {@code [..., CallNode, FunctionNode]} then {@code callNode.getFunction()} should be equal to 43.488 + * {@code functionNode}, and the top of the stack should itself be a variant of {@code functionNode}. 43.489 + * @param functionNode the function node being tested 43.490 + * @return true if the expression defining the current function is a callee of a call expression. 43.491 + */ 43.492 + public boolean isFunctionDefinedInCurrentCall(FunctionNode functionNode) { 43.493 + final LexicalContextNode parent = stack[sp - 2]; 43.494 + if(parent instanceof CallNode && ((CallNode)parent).getFunction() == functionNode) { 43.495 + assert functionNode.getSource() == peek().getSource(); 43.496 + return true; 43.497 + } 43.498 + return false; 43.499 + } 43.500 + 43.501 + /** 43.502 + * Get the parent function for a function in the lexical context 43.503 + * @param functionNode function for which to get parent 43.504 + * @return parent function of functionNode or null if none (e.g. if functionNode is the program) 43.505 + */ 43.506 + public FunctionNode getParentFunction(final FunctionNode functionNode) { 43.507 + final Iterator<FunctionNode> iter = new NodeIterator<>(FunctionNode.class); 43.508 + while (iter.hasNext()) { 43.509 + final FunctionNode next = iter.next(); 43.510 + if (next == functionNode) { 43.511 + return iter.hasNext() ? iter.next() : null; 43.512 + } 43.513 + } 43.514 + assert false; 43.515 + return null; 43.516 + } 43.517 + 43.518 + /** 43.519 + * Check if lexical context is currently inside a with block 43.520 + * @return true if in a with block 43.521 + */ 43.522 + public boolean inWith() { 43.523 + return getScopeNestingLevelTo(null) > 0; 43.524 + } 43.525 + 43.526 + /** 43.527 + * Count the number of with scopes until a given node 43.528 + * @param until node to stop counting at, or null if all nodes should be counted 43.529 + * @return number of with scopes encountered in the context 43.530 + */ 43.531 + public int getScopeNestingLevelTo(final LexicalContextNode until) { 43.532 + //count the number of with nodes until "until" is hit 43.533 + int n = 0; 43.534 + for (final Iterator<WithNode> iter = new NodeIterator<>(WithNode.class, until); iter.hasNext(); iter.next()) { 43.535 + n++; 43.536 + } 43.537 + return n; 43.538 + } 43.539 + 43.540 + private BreakableNode getBreakable() { 43.541 + for (final NodeIterator<BreakableNode> iter = new NodeIterator<>(BreakableNode.class, getCurrentFunction()); iter.hasNext(); ) { 43.542 + final BreakableNode next = iter.next(); 43.543 + if (next.isBreakableWithoutLabel()) { 43.544 + return next; 43.545 + } 43.546 + } 43.547 + return null; 43.548 + } 43.549 + 43.550 + /** 43.551 + * Find the breakable node corresponding to this label. 43.552 + * @param label label to search for, if null the closest breakable node will be returned unconditionally, e.g. a while loop with no label 43.553 + * @return closest breakable node 43.554 + */ 43.555 + public BreakableNode getBreakable(final IdentNode label) { 43.556 + if (label != null) { 43.557 + final LabelNode foundLabel = findLabel(label.getName()); 43.558 + if (foundLabel != null) { 43.559 + // iterate to the nearest breakable to the foundLabel 43.560 + BreakableNode breakable = null; 43.561 + for (final NodeIterator<BreakableNode> iter = new NodeIterator<>(BreakableNode.class, foundLabel); iter.hasNext(); ) { 43.562 + breakable = iter.next(); 43.563 + } 43.564 + return breakable; 43.565 + } 43.566 + return null; 43.567 + } 43.568 + return getBreakable(); 43.569 + } 43.570 + 43.571 + private LoopNode getContinueTo() { 43.572 + final Iterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, getCurrentFunction()); 43.573 + return iter.hasNext() ? iter.next() : null; 43.574 + } 43.575 + 43.576 + /** 43.577 + * Find the continue target node corresponding to this label. 43.578 + * @param label label to search for, if null the closest loop node will be returned unconditionally, e.g. a while loop with no label 43.579 + * @return closest continue target node 43.580 + */ 43.581 + public LoopNode getContinueTo(final IdentNode label) { 43.582 + if (label != null) { 43.583 + final LabelNode foundLabel = findLabel(label.getName()); 43.584 + if (foundLabel != null) { 43.585 + // iterate to the nearest loop to the foundLabel 43.586 + LoopNode loop = null; 43.587 + for (final NodeIterator<LoopNode> iter = new NodeIterator<>(LoopNode.class, foundLabel); iter.hasNext(); ) { 43.588 + loop = iter.next(); 43.589 + } 43.590 + return loop; 43.591 + } 43.592 + return null; 43.593 + } 43.594 + return getContinueTo(); 43.595 + } 43.596 + 43.597 + /** 43.598 + * Check the lexical context for a given label node by name 43.599 + * @param name name of the label 43.600 + * @return LabelNode if found, null otherwise 43.601 + */ 43.602 + public LabelNode findLabel(final String name) { 43.603 + for (final Iterator<LabelNode> iter = new NodeIterator<>(LabelNode.class, getCurrentFunction()); iter.hasNext(); ) { 43.604 + final LabelNode next = iter.next(); 43.605 + if (next.getLabel().getName().equals(name)) { 43.606 + return next; 43.607 + } 43.608 + } 43.609 + return null; 43.610 + } 43.611 + 43.612 + /** 43.613 + * Checks whether a given label is a jump destination that lies outside a given 43.614 + * split node 43.615 + * @param splitNode the split node 43.616 + * @param label the label 43.617 + * @return true if label resides outside the split node 43.618 + */ 43.619 + public boolean isExternalTarget(final SplitNode splitNode, final Label label) { 43.620 + boolean targetFound = false; 43.621 + for (int i = sp - 1; i >= 0; i--) { 43.622 + final LexicalContextNode next = stack[i]; 43.623 + if (next == splitNode) { 43.624 + return !targetFound; 43.625 + } 43.626 + 43.627 + if (next instanceof BreakableNode) { 43.628 + for (final Label l : ((BreakableNode)next).getLabels()) { 43.629 + if (l == label) { 43.630 + targetFound = true; 43.631 + break; 43.632 + } 43.633 + } 43.634 + } 43.635 + } 43.636 + assert false : label + " was expected in lexical context " + LexicalContext.this + " but wasn't"; 43.637 + return false; 43.638 + } 43.639 + 43.640 + @Override 43.641 + public String toString() { 43.642 + final StringBuffer sb = new StringBuffer(); 43.643 + sb.append("[ "); 43.644 + for (int i = 0; i < sp; i++) { 43.645 + final Node node = stack[i]; 43.646 + sb.append(node.getClass().getSimpleName()); 43.647 + sb.append('@'); 43.648 + sb.append(Debug.id(node)); 43.649 + sb.append(':'); 43.650 + final Source source = node.getSource(); 43.651 + String src = source.toString(); 43.652 + if (src.indexOf(File.pathSeparator) != -1) { 43.653 + src = src.substring(src.lastIndexOf(File.pathSeparator)); 43.654 + } 43.655 + src += ' '; 43.656 + src += source.getLine(node.getStart()); 43.657 + sb.append(' '); 43.658 + } 43.659 + sb.append(" ==> ]"); 43.660 + return sb.toString(); 43.661 + } 43.662 + 43.663 + private class NodeIterator <T extends LexicalContextNode> implements Iterator<T> { 43.664 + private int index; 43.665 + private T next; 43.666 + private final Class<T> clazz; 43.667 + private LexicalContextNode until; 43.668 + 43.669 + NodeIterator(final Class<T> clazz) { 43.670 + this(clazz, null); 43.671 + } 43.672 + 43.673 + NodeIterator(final Class<T> clazz, final LexicalContextNode until) { 43.674 + this.index = sp - 1; 43.675 + this.clazz = clazz; 43.676 + this.until = until; 43.677 + this.next = findNext(); 43.678 + } 43.679 + 43.680 + @Override 43.681 + public boolean hasNext() { 43.682 + return next != null; 43.683 + } 43.684 + 43.685 + @Override 43.686 + public T next() { 43.687 + if (next == null) { 43.688 + throw new NoSuchElementException(); 43.689 + } 43.690 + T lnext = next; 43.691 + next = findNext(); 43.692 + return lnext; 43.693 + } 43.694 + 43.695 + private T findNext() { 43.696 + for (int i = index; i >= 0; i--) { 43.697 + final Node node = stack[i]; 43.698 + if (node == until) { 43.699 + return null; 43.700 + } 43.701 + if (clazz.isAssignableFrom(node.getClass())) { 43.702 + index = i - 1; 43.703 + return clazz.cast(node); 43.704 + } 43.705 + } 43.706 + return null; 43.707 + } 43.708 + 43.709 + @Override 43.710 + public void remove() { 43.711 + throw new UnsupportedOperationException(); 43.712 + } 43.713 } 43.714 }
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 44.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java Fri Apr 19 16:11:16 2013 +0200 44.3 @@ -0,0 +1,73 @@ 44.4 +/* 44.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 44.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 44.7 + * 44.8 + * This code is free software; you can redistribute it and/or modify it 44.9 + * under the terms of the GNU General Public License version 2 only, as 44.10 + * published by the Free Software Foundation. Oracle designates this 44.11 + * particular file as subject to the "Classpath" exception as provided 44.12 + * by Oracle in the LICENSE file that accompanied this code. 44.13 + * 44.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 44.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 44.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 44.17 + * version 2 for more details (a copy is included in the LICENSE file that 44.18 + * accompanied this code). 44.19 + * 44.20 + * You should have received a copy of the GNU General Public License version 44.21 + * 2 along with this work; if not, write to the Free Software Foundation, 44.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 44.23 + * 44.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 44.25 + * or visit www.oracle.com if you need additional information or have any 44.26 + * questions. 44.27 + */ 44.28 +package jdk.nashorn.internal.ir; 44.29 + 44.30 +import jdk.nashorn.internal.ir.visitor.NodeVisitor; 44.31 +import jdk.nashorn.internal.runtime.Source; 44.32 + 44.33 +/** 44.34 + * Superclass for nodes that can be part of the lexical context 44.35 + * @see LexicalContext 44.36 + */ 44.37 +public abstract class LexicalContextNode extends Node { 44.38 + /** 44.39 + * Constructor 44.40 + * 44.41 + * @param source source 44.42 + * @param token token 44.43 + * @param finish finish 44.44 + */ 44.45 + protected LexicalContextNode(final Source source, final long token, final int finish) { 44.46 + super(source, token, finish); 44.47 + } 44.48 + 44.49 + /** 44.50 + * Copy constructor 44.51 + * 44.52 + * @param node source node 44.53 + */ 44.54 + protected LexicalContextNode(final LexicalContextNode node) { 44.55 + super(node); 44.56 + } 44.57 + 44.58 + /** 44.59 + * Accept function for the node given a lexical context. It must be prepared 44.60 + * to replace itself if present in the lexical context 44.61 + * 44.62 + * @param lc lexical context 44.63 + * @param visitor node visitor 44.64 + * 44.65 + * @return new node or same node depending on state change 44.66 + */ 44.67 + protected abstract Node accept(final LexicalContext lc, final NodeVisitor visitor); 44.68 + 44.69 + @Override 44.70 + public Node accept(final NodeVisitor visitor) { 44.71 + final LexicalContext lc = visitor.getLexicalContext(); 44.72 + lc.push(this); 44.73 + final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); 44.74 + return lc.pop(newNode); 44.75 + } 44.76 +}
45.1 --- a/src/jdk/nashorn/internal/ir/LineNumberNode.java Fri Apr 19 18:23:00 2013 +0530 45.2 +++ b/src/jdk/nashorn/internal/ir/LineNumberNode.java Fri Apr 19 16:11:16 2013 +0200 45.3 @@ -25,6 +25,7 @@ 45.4 45.5 package jdk.nashorn.internal.ir; 45.6 45.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 45.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 45.9 import jdk.nashorn.internal.parser.Token; 45.10 import jdk.nashorn.internal.runtime.Source; 45.11 @@ -32,8 +33,8 @@ 45.12 /** 45.13 * IR Node representing a line number 45.14 */ 45.15 - 45.16 -public class LineNumberNode extends Node { 45.17 +@Immutable 45.18 +public final class LineNumberNode extends Node { 45.19 /** Line number */ 45.20 private final int lineNumber; 45.21 45.22 @@ -46,24 +47,17 @@ 45.23 */ 45.24 public LineNumberNode(final Source source, final long token, final int lineNumber) { 45.25 super(source, token, Token.descPosition(token)); 45.26 - 45.27 this.lineNumber = lineNumber; 45.28 } 45.29 45.30 - private LineNumberNode(final LineNumberNode lineNumberNode) { 45.31 + private LineNumberNode(final LineNumberNode lineNumberNode) { 45.32 super(lineNumberNode); 45.33 - 45.34 this.lineNumber = lineNumberNode.getLineNumber(); 45.35 } 45.36 45.37 @Override 45.38 - protected Node copy(final CopyState cs) { 45.39 - return new LineNumberNode(this); 45.40 - } 45.41 - 45.42 - @Override 45.43 public Node accept(final NodeVisitor visitor) { 45.44 - if (visitor.enterLineNumberNode(this) != null) { 45.45 + if (visitor.enterLineNumberNode(this)) { 45.46 return visitor.leaveLineNumberNode(this); 45.47 } 45.48
46.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Fri Apr 19 18:23:00 2013 +0530 46.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Fri Apr 19 16:11:16 2013 +0200 46.3 @@ -30,6 +30,7 @@ 46.4 import java.util.List; 46.5 import jdk.nashorn.internal.codegen.CompileUnit; 46.6 import jdk.nashorn.internal.codegen.types.Type; 46.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 46.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 46.9 import jdk.nashorn.internal.parser.Lexer.LexerToken; 46.10 import jdk.nashorn.internal.parser.Token; 46.11 @@ -44,6 +45,7 @@ 46.12 * 46.13 * @param <T> the literal type 46.14 */ 46.15 +@Immutable 46.16 public abstract class LiteralNode<T> extends Node implements PropertyKey { 46.17 /** Literal value */ 46.18 protected final T value; 46.19 @@ -93,23 +95,6 @@ 46.20 return value == null; 46.21 } 46.22 46.23 - @Override 46.24 - public int hashCode() { 46.25 - return value == null ? 0 : value.hashCode(); 46.26 - } 46.27 - 46.28 - @Override 46.29 - public boolean equals(final Object other) { 46.30 - if (!(other instanceof LiteralNode<?>)) { 46.31 - return false; 46.32 - } 46.33 - final LiteralNode<?> otherNode = (LiteralNode<?>)other; 46.34 - if (otherNode.isNull()) { 46.35 - return isNull(); 46.36 - } 46.37 - return ((LiteralNode<?>)other).getValue().equals(value); 46.38 - } 46.39 - 46.40 /** 46.41 * Check if the literal value is boolean true 46.42 * @return true if literal value is boolean true 46.43 @@ -226,7 +211,7 @@ 46.44 */ 46.45 @Override 46.46 public Node accept(final NodeVisitor visitor) { 46.47 - if (visitor.enterLiteralNode(this) != null) { 46.48 + if (visitor.enterLiteralNode(this)) { 46.49 return visitor.leaveLiteralNode(this); 46.50 } 46.51 46.52 @@ -274,7 +259,8 @@ 46.53 return new NodeLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish()); 46.54 } 46.55 46.56 - private static class BooleanLiteralNode extends LiteralNode<Boolean> { 46.57 + @Immutable 46.58 + private static final class BooleanLiteralNode extends LiteralNode<Boolean> { 46.59 46.60 private BooleanLiteralNode(final Source source, final long token, final int finish, final boolean value) { 46.61 super(source, Token.recast(token, value ? TokenType.TRUE : TokenType.FALSE), finish, value); 46.62 @@ -285,11 +271,6 @@ 46.63 } 46.64 46.65 @Override 46.66 - protected Node copy(final CopyState cs) { 46.67 - return new BooleanLiteralNode(this); 46.68 - } 46.69 - 46.70 - @Override 46.71 public boolean isTrue() { 46.72 return value; 46.73 } 46.74 @@ -331,7 +312,8 @@ 46.75 return new BooleanLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 46.76 } 46.77 46.78 - private static class NumberLiteralNode extends LiteralNode<Number> { 46.79 + @Immutable 46.80 + private static final class NumberLiteralNode extends LiteralNode<Number> { 46.81 46.82 private final Type type = numberGetType(value); 46.83 46.84 @@ -358,11 +340,6 @@ 46.85 } 46.86 46.87 @Override 46.88 - protected Node copy(final CopyState cs) { 46.89 - return new NumberLiteralNode(this); 46.90 - } 46.91 - 46.92 - @Override 46.93 public Type getType() { 46.94 return type; 46.95 } 46.96 @@ -407,11 +384,6 @@ 46.97 private UndefinedLiteralNode(final UndefinedLiteralNode literalNode) { 46.98 super(literalNode); 46.99 } 46.100 - 46.101 - @Override 46.102 - protected Node copy(final CopyState cs) { 46.103 - return new UndefinedLiteralNode(this); 46.104 - } 46.105 } 46.106 46.107 /** 46.108 @@ -440,6 +412,7 @@ 46.109 return new UndefinedLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish()); 46.110 } 46.111 46.112 + @Immutable 46.113 private static class StringLiteralNode extends LiteralNode<String> { 46.114 private StringLiteralNode(final Source source, final long token, final int finish, final String value) { 46.115 super(source, Token.recast(token, TokenType.STRING), finish, value); 46.116 @@ -450,11 +423,6 @@ 46.117 } 46.118 46.119 @Override 46.120 - protected Node copy(final CopyState cs) { 46.121 - return new StringLiteralNode(this); 46.122 - } 46.123 - 46.124 - @Override 46.125 public void toString(final StringBuilder sb) { 46.126 sb.append('\"'); 46.127 sb.append(value); 46.128 @@ -488,6 +456,7 @@ 46.129 return new StringLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 46.130 } 46.131 46.132 + @Immutable 46.133 private static class LexerTokenLiteralNode extends LiteralNode<LexerToken> { 46.134 private LexerTokenLiteralNode(final Source source, final long token, final int finish, final LexerToken value) { 46.135 super(source, Token.recast(token, TokenType.STRING), finish, value); //TODO is string the correct token type here? 46.136 @@ -498,11 +467,6 @@ 46.137 } 46.138 46.139 @Override 46.140 - protected Node copy(final CopyState cs) { 46.141 - return new LexerTokenLiteralNode(this); 46.142 - } 46.143 - 46.144 - @Override 46.145 public Type getType() { 46.146 return Type.OBJECT; 46.147 } 46.148 @@ -539,7 +503,7 @@ 46.149 return new LexerTokenLiteralNode(parent.getSource(), parent.getToken(), parent.getFinish(), value); 46.150 } 46.151 46.152 - private static class NodeLiteralNode extends LiteralNode<Node> { 46.153 + private static final class NodeLiteralNode extends LiteralNode<Node> { 46.154 46.155 private NodeLiteralNode(final Source source, final long token, final int finish) { 46.156 this(source, token, finish, null); 46.157 @@ -558,13 +522,8 @@ 46.158 } 46.159 46.160 @Override 46.161 - protected Node copy(final CopyState cs) { 46.162 - return new NodeLiteralNode(this); 46.163 - } 46.164 - 46.165 - @Override 46.166 public Node accept(final NodeVisitor visitor) { 46.167 - if (visitor.enterLiteralNode(this) != null) { 46.168 + if (visitor.enterLiteralNode(this)) { 46.169 if (value != null) { 46.170 final Node newValue = value.accept(visitor); 46.171 if(value != newValue) { 46.172 @@ -617,7 +576,7 @@ 46.173 /** 46.174 * Array literal node class. 46.175 */ 46.176 - public static class ArrayLiteralNode extends LiteralNode<Node[]> { 46.177 + public static final class ArrayLiteralNode extends LiteralNode<Node[]> { 46.178 private static class PostsetMarker { 46.179 //empty 46.180 } 46.181 @@ -705,11 +664,6 @@ 46.182 this.elementType = node.elementType; 46.183 } 46.184 46.185 - @Override 46.186 - protected Node copy(final CopyState cs) { 46.187 - return new ArrayLiteralNode(this); 46.188 - } 46.189 - 46.190 /** 46.191 * Compute things like widest element type needed. Internal use from compiler only 46.192 */ 46.193 @@ -894,7 +848,7 @@ 46.194 46.195 @Override 46.196 public Node accept(final NodeVisitor visitor) { 46.197 - if (visitor.enterLiteralNode(this) != null) { 46.198 + if (visitor.enterLiteralNode(this)) { 46.199 for (int i = 0; i < value.length; i++) { 46.200 final Node element = value[i]; 46.201 if (element != null) {
47.1 --- a/src/jdk/nashorn/internal/ir/Location.java Fri Apr 19 18:23:00 2013 +0530 47.2 +++ b/src/jdk/nashorn/internal/ir/Location.java Fri Apr 19 16:11:16 2013 +0200 47.3 @@ -25,16 +25,13 @@ 47.4 47.5 package jdk.nashorn.internal.ir; 47.6 47.7 -import java.util.Objects; 47.8 import jdk.nashorn.internal.parser.Token; 47.9 import jdk.nashorn.internal.parser.TokenType; 47.10 import jdk.nashorn.internal.runtime.Source; 47.11 47.12 /** 47.13 * Used to locate an entity back to it's source file. 47.14 - * 47.15 */ 47.16 - 47.17 public class Location implements Cloneable { 47.18 /** Source of entity. */ 47.19 private final Source source; 47.20 @@ -73,22 +70,13 @@ 47.21 } 47.22 47.23 @Override 47.24 - public boolean equals(final Object other) { 47.25 - if (other == null) { 47.26 - return false; 47.27 - } 47.28 - 47.29 - if (other.getClass() != this.getClass()) { 47.30 - return false; 47.31 - } 47.32 - 47.33 - final Location loc = (Location)other; 47.34 - return token == loc.token && Objects.equals(source, loc.source); 47.35 + public final boolean equals(final Object other) { 47.36 + return super.equals(other); 47.37 } 47.38 47.39 @Override 47.40 - public int hashCode() { 47.41 - return Token.hashCode(token) ^ Objects.hashCode(source); 47.42 + public final int hashCode() { 47.43 + return super.hashCode(); 47.44 } 47.45 47.46 /**
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 48.2 +++ b/src/jdk/nashorn/internal/ir/LoopNode.java Fri Apr 19 16:11:16 2013 +0200 48.3 @@ -0,0 +1,176 @@ 48.4 +/* 48.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 48.7 + * 48.8 + * This code is free software; you can redistribute it and/or modify it 48.9 + * under the terms of the GNU General Public License version 2 only, as 48.10 + * published by the Free Software Foundation. Oracle designates this 48.11 + * particular file as subject to the "Classpath" exception as provided 48.12 + * by Oracle in the LICENSE file that accompanied this code. 48.13 + * 48.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 48.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 48.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 48.17 + * version 2 for more details (a copy is included in the LICENSE file that 48.18 + * accompanied this code). 48.19 + * 48.20 + * You should have received a copy of the GNU General Public License version 48.21 + * 2 along with this work; if not, write to the Free Software Foundation, 48.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 48.23 + * 48.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 48.25 + * or visit www.oracle.com if you need additional information or have any 48.26 + * questions. 48.27 + */ 48.28 + 48.29 +package jdk.nashorn.internal.ir; 48.30 + 48.31 +import java.util.Arrays; 48.32 +import java.util.List; 48.33 + 48.34 +import jdk.nashorn.internal.codegen.Label; 48.35 +import jdk.nashorn.internal.runtime.Source; 48.36 + 48.37 +/** 48.38 + * A loop node, for example a while node, do while node or for node 48.39 + */ 48.40 +public abstract class LoopNode extends BreakableNode { 48.41 + /** loop continue label. */ 48.42 + protected final Label continueLabel; 48.43 + 48.44 + /** Loop test node, null if infinite */ 48.45 + protected final Node test; 48.46 + 48.47 + /** Loop body */ 48.48 + protected final Block body; 48.49 + 48.50 + /** Can control flow escape from loop, e.g. through breaks or continues to outer loops? */ 48.51 + protected final boolean controlFlowEscapes; 48.52 + 48.53 + /** 48.54 + * Constructor 48.55 + * 48.56 + * @param source source 48.57 + * @param token token 48.58 + * @param finish finish 48.59 + * @param test test, or null if infinite loop 48.60 + * @param body loop body 48.61 + * @param controlFlowEscapes controlFlowEscapes 48.62 + */ 48.63 + protected LoopNode(final Source source, final long token, final int finish, final Node test, final Block body, final boolean controlFlowEscapes) { 48.64 + super(source, token, finish, new Label("while_break")); 48.65 + this.continueLabel = new Label("while_continue"); 48.66 + this.test = test; 48.67 + this.body = body; 48.68 + this.controlFlowEscapes = controlFlowEscapes; 48.69 + } 48.70 + 48.71 + /** 48.72 + * Constructor 48.73 + * 48.74 + * @param loopNode loop node 48.75 + * @param test new test 48.76 + * @param body new body 48.77 + * @param controlFlowEscapes controlFlowEscapes 48.78 + */ 48.79 + protected LoopNode(final LoopNode loopNode, final Node test, final Block body, final boolean controlFlowEscapes) { 48.80 + super(loopNode); 48.81 + this.continueLabel = new Label(loopNode.continueLabel); 48.82 + this.test = test; 48.83 + this.body = body; 48.84 + this.controlFlowEscapes = controlFlowEscapes; 48.85 + } 48.86 + 48.87 + @Override 48.88 + public abstract Node ensureUniqueLabels(final LexicalContext lc); 48.89 + 48.90 + /** 48.91 + * Does the control flow escape from this loop, i.e. through breaks or 48.92 + * continues to outer loops? 48.93 + * @return true if control flow escapes 48.94 + */ 48.95 + public boolean controlFlowEscapes() { 48.96 + return controlFlowEscapes; 48.97 + } 48.98 + 48.99 + 48.100 + @Override 48.101 + public boolean isTerminal() { 48.102 + if (!mustEnter()) { 48.103 + return false; 48.104 + } 48.105 + //must enter but control flow may escape - then not terminal 48.106 + if (controlFlowEscapes) { 48.107 + return false; 48.108 + } 48.109 + //must enter, but body ends with return - then terminal 48.110 + if (body.isTerminal()) { 48.111 + return true; 48.112 + } 48.113 + //no breaks or returns, it is still terminal if we can never exit 48.114 + return test == null; 48.115 + } 48.116 + 48.117 + /** 48.118 + * Conservative check: does this loop have to be entered? 48.119 + * @return true if body will execute at least once 48.120 + */ 48.121 + public abstract boolean mustEnter(); 48.122 + 48.123 + /** 48.124 + * Get the continue label for this while node, i.e. location to go to on continue 48.125 + * @return continue label 48.126 + */ 48.127 + public Label getContinueLabel() { 48.128 + return continueLabel; 48.129 + } 48.130 + 48.131 + @Override 48.132 + public List<Label> getLabels() { 48.133 + return Arrays.asList(breakLabel, continueLabel); 48.134 + } 48.135 + 48.136 + @Override 48.137 + public boolean isLoop() { 48.138 + return true; 48.139 + } 48.140 + 48.141 + /** 48.142 + * Get the body for this for node 48.143 + * @return the body 48.144 + */ 48.145 + public abstract Block getBody(); 48.146 + 48.147 + /** 48.148 + * @param lc lexical context 48.149 + * @param body new body 48.150 + * @return new for node if changed or existing if not 48.151 + */ 48.152 + public abstract LoopNode setBody(final LexicalContext lc, final Block body); 48.153 + 48.154 + /** 48.155 + * Get the test for this for node 48.156 + * @return the test 48.157 + */ 48.158 + public abstract Node getTest(); 48.159 + 48.160 + /** 48.161 + * Set the test for this for node 48.162 + * 48.163 + * @param lc lexical context 48.164 + * @param test new test 48.165 + * @return same or new node depending on if test was changed 48.166 + */ 48.167 + public abstract LoopNode setTest(final LexicalContext lc, final Node test); 48.168 + 48.169 + /** 48.170 + * Set the control flow escapes flag for this node. 48.171 + * TODO - integrate this with Lowering in a better way 48.172 + * 48.173 + * @param lc lexical context 48.174 + * @param controlFlowEscapes control flow escapes value 48.175 + * @return new loop node if changed otherwise the same 48.176 + */ 48.177 + public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes); 48.178 + 48.179 +}
49.1 --- a/src/jdk/nashorn/internal/ir/Node.java Fri Apr 19 18:23:00 2013 +0530 49.2 +++ b/src/jdk/nashorn/internal/ir/Node.java Fri Apr 19 16:11:16 2013 +0200 49.3 @@ -25,7 +25,9 @@ 49.4 49.5 package jdk.nashorn.internal.ir; 49.6 49.7 -import java.util.IdentityHashMap; 49.8 +import java.util.ArrayList; 49.9 +import java.util.List; 49.10 + 49.11 import jdk.nashorn.internal.codegen.types.Type; 49.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 49.13 import jdk.nashorn.internal.parser.Token; 49.14 @@ -33,30 +35,17 @@ 49.15 49.16 /** 49.17 * Nodes are used to compose Abstract Syntax Trees. 49.18 - * 49.19 */ 49.20 public abstract class Node extends Location { 49.21 /** Node symbol. */ 49.22 private Symbol symbol; 49.23 49.24 /** Start of source range. */ 49.25 - protected int start; 49.26 + protected final int start; 49.27 49.28 /** End of source range. */ 49.29 protected int finish; 49.30 49.31 - /** Has this node been resolved - i.e. emitted code already */ 49.32 - private boolean isResolved; 49.33 - 49.34 - /** Is this node terminal */ 49.35 - private boolean isTerminal; 49.36 - 49.37 - /** Is this a goto node */ 49.38 - private boolean hasGoto; 49.39 - 49.40 - /** Is this a discard */ 49.41 - private boolean shouldDiscard; 49.42 - 49.43 /** 49.44 * Constructor 49.45 * 49.46 @@ -72,6 +61,21 @@ 49.47 } 49.48 49.49 /** 49.50 + * Constructor 49.51 + * 49.52 + * @param source source 49.53 + * @param token token 49.54 + * @param start start 49.55 + * @param finish finish 49.56 + */ 49.57 + protected Node(final Source source, final long token, final int start, final int finish) { 49.58 + super(source, token); 49.59 + 49.60 + this.start = start; 49.61 + this.finish = finish; 49.62 + } 49.63 + 49.64 + /** 49.65 * Copy constructor 49.66 * 49.67 * @param node source node 49.68 @@ -79,13 +83,9 @@ 49.69 protected Node(final Node node) { 49.70 super(node); 49.71 49.72 - this.symbol = node.symbol; 49.73 - this.isResolved = node.isResolved; 49.74 - this.isTerminal = node.isTerminal; 49.75 - this.hasGoto = node.hasGoto; 49.76 - this.shouldDiscard = node.shouldDiscard; 49.77 - this.start = node.start; 49.78 - this.finish = node.finish; 49.79 + this.symbol = node.symbol; 49.80 + this.start = node.start; 49.81 + this.finish = node.finish; 49.82 } 49.83 49.84 /** 49.85 @@ -156,28 +156,6 @@ 49.86 } 49.87 49.88 /** 49.89 - * Test to see if code been generated for this node. Set isResolved if not. 49.90 - * 49.91 - * @return True if node has already been resolved. 49.92 - */ 49.93 - public boolean testResolved() { 49.94 - if (isResolved()) { 49.95 - return true; 49.96 - } 49.97 - 49.98 - setIsResolved(true); 49.99 - 49.100 - return false; 49.101 - } 49.102 - 49.103 - /** 49.104 - * Reset the resolved flag. 49.105 - */ 49.106 - public void resetResolved() { 49.107 - setIsResolved(false); 49.108 - } 49.109 - 49.110 - /** 49.111 * Is this a debug info node like LineNumberNode etc? 49.112 * 49.113 * @return true if this is a debug node 49.114 @@ -187,72 +165,13 @@ 49.115 } 49.116 49.117 /** 49.118 - * Helper class used for node cloning 49.119 + * For reference copies - ensure that labels in the copy node are unique 49.120 + * using an appropriate copy constructor 49.121 + * @param lc lexical context 49.122 + * @return new node or same of no labels 49.123 */ 49.124 - public static final class CopyState { 49.125 - private final IdentityHashMap<Node, Node> cloneMap = new IdentityHashMap<>(); 49.126 - 49.127 - /** 49.128 - * Find existing or create new copy of the node. 49.129 - * 49.130 - * @param node Node to copy. 49.131 - * 49.132 - * @return New object. 49.133 - */ 49.134 - public Node existingOrCopy(final Node node) { 49.135 - if (node != null) { 49.136 - Node copy = cloneMap.get(node); 49.137 - 49.138 - if (copy == null) { 49.139 - copy = node.copy(this); 49.140 - cloneMap.put(node, copy); 49.141 - } 49.142 - 49.143 - return copy; 49.144 - } 49.145 - 49.146 - return node; 49.147 - } 49.148 - 49.149 - /** 49.150 - * Find existing or use old copy of the node. 49.151 - * 49.152 - * @param node Node to copy. 49.153 - * 49.154 - * @return new object. 49.155 - */ 49.156 - public Node existingOrSame(final Node node) { 49.157 - if (node != null) { 49.158 - Node copy = cloneMap.get(node); 49.159 - 49.160 - if (copy == null) { 49.161 - copy = node; 49.162 - } 49.163 - 49.164 - return copy; 49.165 - } 49.166 - 49.167 - return node; 49.168 - } 49.169 - } 49.170 - 49.171 - /** 49.172 - * Deep copy the node. 49.173 - * 49.174 - * @return Deep copy of the Node. 49.175 - */ 49.176 - public final Node copy() { 49.177 - return copy(new CopyState()); 49.178 - } 49.179 - 49.180 - /** 49.181 - * Deep copy the node. 49.182 - * 49.183 - * @param cs CopyState passed around to re-use certain nodes. 49.184 - * @return Deep copy of the Node. 49.185 - */ 49.186 - protected Node copy(final CopyState cs) { 49.187 - return cs.existingOrCopy(this); 49.188 + public Node ensureUniqueLabels(final LexicalContext lc) { 49.189 + return this; 49.190 } 49.191 49.192 /** 49.193 @@ -283,35 +202,7 @@ 49.194 * @return true if terminal 49.195 */ 49.196 public boolean hasTerminalFlags() { 49.197 - return isTerminal || hasGoto; 49.198 - } 49.199 - 49.200 - /** 49.201 - * Copy the terminal flags state of a node to another node 49.202 - * 49.203 - * @param other source node 49.204 - */ 49.205 - public void copyTerminalFlags(final Node other) { 49.206 - isTerminal = other.isTerminal; 49.207 - hasGoto = other.hasGoto; 49.208 - } 49.209 - 49.210 - /** 49.211 - * Check if the return value of this expression should be discarded 49.212 - * @return true if return value is discarded 49.213 - */ 49.214 - public boolean shouldDiscard() { 49.215 - return shouldDiscard; 49.216 - } 49.217 - 49.218 - /** 49.219 - * Setter that determines whether this node's return value should be discarded 49.220 - * or not 49.221 - * 49.222 - * @param shouldDiscard true if return value is discarded, false otherwise 49.223 - */ 49.224 - public void setDiscard(final boolean shouldDiscard) { 49.225 - this.shouldDiscard = shouldDiscard; 49.226 + return isTerminal() || hasGoto(); 49.227 } 49.228 49.229 /** 49.230 @@ -336,29 +227,7 @@ 49.231 * @return true if node has goto semantics 49.232 */ 49.233 public boolean hasGoto() { 49.234 - return hasGoto; 49.235 - } 49.236 - 49.237 - /** 49.238 - * Flag this node as having goto semantics as described in {@link Node#hasGoto()} 49.239 - */ 49.240 - public void setHasGoto() { 49.241 - this.hasGoto = true; 49.242 - } 49.243 - 49.244 - /** 49.245 - * Check whether this node is resolved, i.e. code has been generated for it 49.246 - * @return true if node is resolved 49.247 - */ 49.248 - public boolean isResolved() { 49.249 - return isResolved; 49.250 - } 49.251 - 49.252 - /** 49.253 - * Flag this node as resolved or not, i.e. code has been generated for it 49.254 - */ 49.255 - private void setIsResolved(boolean isResolved) { 49.256 - this.isResolved = isResolved; 49.257 + return false; 49.258 } 49.259 49.260 /** 49.261 @@ -370,14 +239,6 @@ 49.262 } 49.263 49.264 /** 49.265 - * Set start position for node 49.266 - * @param start start position 49.267 - */ 49.268 - public void setStart(final int start) { 49.269 - this.start = start; 49.270 - } 49.271 - 49.272 - /** 49.273 * Return the Symbol the compiler has assigned to this Node. The symbol 49.274 * is the place where it's expression value is stored after evaluation 49.275 * 49.276 @@ -404,17 +265,29 @@ 49.277 * @return true if this node is terminal 49.278 */ 49.279 public boolean isTerminal() { 49.280 - return isTerminal; 49.281 + return false; 49.282 } 49.283 49.284 - /** 49.285 - * Set this to be a terminal node, i.e. it terminates control flow as described 49.286 - * in {@link Node#isTerminal()} 49.287 - * 49.288 - * @param isTerminal true if this is a terminal node, false otherwise 49.289 - */ 49.290 - public void setIsTerminal(final boolean isTerminal) { 49.291 - this.isTerminal = isTerminal; 49.292 + //on change, we have to replace the entire list, that's we can't simple do ListIterator.set 49.293 + static <T extends Node> List<T> accept(final NodeVisitor visitor, final Class<T> clazz, final List<T> list) { 49.294 + boolean changed = false; 49.295 + final List<T> newList = new ArrayList<>(); 49.296 + 49.297 + for (final Node node : list) { 49.298 + final T newNode = clazz.cast(node.accept(visitor)); 49.299 + if (newNode != node) { 49.300 + changed = true; 49.301 + } 49.302 + newList.add(newNode); 49.303 + } 49.304 + 49.305 + return changed ? newList : list; 49.306 } 49.307 49.308 + static <T extends LexicalContextNode> T replaceInLexicalContext(final LexicalContext lc, final T oldNode, final T newNode) { 49.309 + if (lc != null) { 49.310 + lc.replace(oldNode, newNode); 49.311 + } 49.312 + return newNode; 49.313 + } 49.314 }
50.1 --- a/src/jdk/nashorn/internal/ir/ObjectNode.java Fri Apr 19 18:23:00 2013 +0530 50.2 +++ b/src/jdk/nashorn/internal/ir/ObjectNode.java Fri Apr 19 16:11:16 2013 +0200 50.3 @@ -25,16 +25,18 @@ 50.4 50.5 package jdk.nashorn.internal.ir; 50.6 50.7 -import java.util.ArrayList; 50.8 import java.util.Collections; 50.9 import java.util.List; 50.10 + 50.11 +import jdk.nashorn.internal.ir.annotations.Immutable; 50.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 50.13 import jdk.nashorn.internal.runtime.Source; 50.14 50.15 /** 50.16 * IR representation of an object literal. 50.17 */ 50.18 -public class ObjectNode extends Node { 50.19 +@Immutable 50.20 +public final class ObjectNode extends Node { 50.21 50.22 /** Literal elements. */ 50.23 private final List<Node> elements; 50.24 @@ -49,35 +51,18 @@ 50.25 */ 50.26 public ObjectNode(final Source source, final long token, final int finish, final List<Node> elements) { 50.27 super(source, token, finish); 50.28 - 50.29 this.elements = elements; 50.30 } 50.31 50.32 - private ObjectNode(final ObjectNode objectNode, final CopyState cs) { 50.33 + private ObjectNode(final ObjectNode objectNode, final List<Node> elements) { 50.34 super(objectNode); 50.35 - 50.36 - final List<Node> newElements = new ArrayList<>(); 50.37 - 50.38 - for (final Node element : objectNode.elements) { 50.39 - newElements.add(cs.existingOrCopy(element)); 50.40 - } 50.41 - 50.42 - this.elements = newElements; 50.43 - } 50.44 - 50.45 - @Override 50.46 - protected Node copy(final CopyState cs) { 50.47 - return new ObjectNode(this, cs); 50.48 + this.elements = elements; 50.49 } 50.50 50.51 @Override 50.52 public Node accept(final NodeVisitor visitor) { 50.53 - if (visitor.enterObjectNode(this) != null) { 50.54 - for (int i = 0, count = elements.size(); i < count; i++) { 50.55 - elements.set(i, elements.get(i).accept(visitor)); 50.56 - } 50.57 - 50.58 - return visitor.leaveObjectNode(this); 50.59 + if (visitor.enterObjectNode(this)) { 50.60 + return visitor.leaveObjectNode(setElements(Node.accept(visitor, Node.class, elements))); 50.61 } 50.62 50.63 return this; 50.64 @@ -112,4 +97,11 @@ 50.65 public List<Node> getElements() { 50.66 return Collections.unmodifiableList(elements); 50.67 } 50.68 + 50.69 + private ObjectNode setElements(final List<Node> elements) { 50.70 + if (this.elements == elements) { 50.71 + return this; 50.72 + } 50.73 + return new ObjectNode(this, elements); 50.74 + } 50.75 }
51.1 --- a/src/jdk/nashorn/internal/ir/PropertyNode.java Fri Apr 19 18:23:00 2013 +0530 51.2 +++ b/src/jdk/nashorn/internal/ir/PropertyNode.java Fri Apr 19 16:11:16 2013 +0200 51.3 @@ -25,28 +25,27 @@ 51.4 51.5 package jdk.nashorn.internal.ir; 51.6 51.7 -import jdk.nashorn.internal.ir.annotations.Reference; 51.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 51.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 51.10 import jdk.nashorn.internal.runtime.Source; 51.11 51.12 /** 51.13 * IR representation of an object literal property. 51.14 */ 51.15 -public class PropertyNode extends Node { 51.16 +@Immutable 51.17 +public final class PropertyNode extends Node { 51.18 51.19 /** Property key. */ 51.20 - private PropertyKey key; 51.21 + private final PropertyKey key; 51.22 51.23 /** Property value. */ 51.24 - private Node value; 51.25 + private final Node value; 51.26 51.27 /** Property getter. */ 51.28 - @Reference 51.29 - private Node getter; 51.30 + private final FunctionNode getter; 51.31 51.32 /** Property getter. */ 51.33 - @Reference 51.34 - private Node setter; 51.35 + private final FunctionNode setter; 51.36 51.37 /** 51.38 * Constructor 51.39 @@ -56,26 +55,23 @@ 51.40 * @param finish finish 51.41 * @param key the key of this property 51.42 * @param value the value of this property 51.43 + * @param getter getter function body 51.44 + * @param setter setter function body 51.45 */ 51.46 - public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value) { 51.47 + public PropertyNode(final Source source, final long token, final int finish, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) { 51.48 super(source, token, finish); 51.49 - 51.50 this.key = key; 51.51 this.value = value; 51.52 + this.getter = getter; 51.53 + this.setter = setter; 51.54 } 51.55 51.56 - private PropertyNode(final PropertyNode propertyNode, final CopyState cs) { 51.57 + private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Node value, final FunctionNode getter, final FunctionNode setter) { 51.58 super(propertyNode); 51.59 - 51.60 - this.key = (PropertyKey)cs.existingOrCopy((Node)propertyNode.key); 51.61 - this.value = cs.existingOrCopy(propertyNode.value); 51.62 - this.getter = cs.existingOrSame(propertyNode.getter); 51.63 - this.setter = cs.existingOrSame(propertyNode.setter); 51.64 - } 51.65 - 51.66 - @Override 51.67 - protected Node copy(final CopyState cs) { 51.68 - return new PropertyNode(this, cs); 51.69 + this.key = key; 51.70 + this.value = value; 51.71 + this.getter = getter; 51.72 + this.setter = setter; 51.73 } 51.74 51.75 /** 51.76 @@ -88,22 +84,12 @@ 51.77 51.78 @Override 51.79 public Node accept(final NodeVisitor visitor) { 51.80 - if (visitor.enterPropertyNode(this) != null) { 51.81 - key = (PropertyKey)((Node)key).accept(visitor); 51.82 - 51.83 - if (value != null) { 51.84 - value = value.accept(visitor); 51.85 - } 51.86 - 51.87 - if (getter != null) { 51.88 - getter = getter.accept(visitor); 51.89 - } 51.90 - 51.91 - if (setter != null) { 51.92 - setter = setter.accept(visitor); 51.93 - } 51.94 - 51.95 - return visitor.leavePropertyNode(this); 51.96 + if (visitor.enterPropertyNode(this)) { 51.97 + return visitor.leavePropertyNode( 51.98 + setKey((PropertyKey)((Node)key).accept(visitor)). 51.99 + setValue(value == null ? null : value.accept(visitor)). 51.100 + setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)). 51.101 + setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor))); 51.102 } 51.103 51.104 return this; 51.105 @@ -136,16 +122,20 @@ 51.106 * Get the getter for this property 51.107 * @return getter or null if none exists 51.108 */ 51.109 - public Node getGetter() { 51.110 + public FunctionNode getGetter() { 51.111 return getter; 51.112 } 51.113 51.114 /** 51.115 * Set the getter of this property, null if none 51.116 * @param getter getter 51.117 + * @return same node or new node if state changed 51.118 */ 51.119 - public void setGetter(final Node getter) { 51.120 - this.getter = getter; 51.121 + public PropertyNode setGetter(final FunctionNode getter) { 51.122 + if (this.getter == getter) { 51.123 + return this; 51.124 + } 51.125 + return new PropertyNode(this, key, value, getter, setter); 51.126 } 51.127 51.128 /** 51.129 @@ -156,20 +146,31 @@ 51.130 return (Node)key; 51.131 } 51.132 51.133 + private PropertyNode setKey(final PropertyKey key) { 51.134 + if (this.key == key) { 51.135 + return this; 51.136 + } 51.137 + return new PropertyNode(this, key, value, getter, setter); 51.138 + } 51.139 + 51.140 /** 51.141 * Get the setter for this property 51.142 * @return setter or null if none exists 51.143 */ 51.144 - public Node getSetter() { 51.145 + public FunctionNode getSetter() { 51.146 return setter; 51.147 } 51.148 51.149 /** 51.150 * Set the setter for this property, null if none 51.151 * @param setter setter 51.152 + * @return same node or new node if state changed 51.153 */ 51.154 - public void setSetter(final Node setter) { 51.155 - this.setter = setter; 51.156 + public PropertyNode setSetter(final FunctionNode setter) { 51.157 + if (this.setter == setter) { 51.158 + return this; 51.159 + } 51.160 + return new PropertyNode(this, key, value, getter, setter); 51.161 } 51.162 51.163 /** 51.164 @@ -183,8 +184,12 @@ 51.165 /** 51.166 * Set the value of this property 51.167 * @param value new value 51.168 + * @return same node or new node if state changed 51.169 */ 51.170 - public void setValue(final Node value) { 51.171 - this.value = value; 51.172 - } 51.173 + public PropertyNode setValue(final Node value) { 51.174 + if (this.value == value) { 51.175 + return this; 51.176 + } 51.177 + return new PropertyNode(this, key, value, getter, setter); 51.178 + } 51.179 }
52.1 --- a/src/jdk/nashorn/internal/ir/ReturnNode.java Fri Apr 19 18:23:00 2013 +0530 52.2 +++ b/src/jdk/nashorn/internal/ir/ReturnNode.java Fri Apr 19 16:11:16 2013 +0200 52.3 @@ -27,22 +27,17 @@ 52.4 52.5 import static jdk.nashorn.internal.parser.TokenType.RETURN; 52.6 import static jdk.nashorn.internal.parser.TokenType.YIELD; 52.7 - 52.8 -import jdk.nashorn.internal.ir.annotations.Ignore; 52.9 +import jdk.nashorn.internal.ir.annotations.Immutable; 52.10 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 52.11 import jdk.nashorn.internal.runtime.Source; 52.12 52.13 /** 52.14 * IR representation for RETURN or YIELD statements. 52.15 - * 52.16 */ 52.17 +@Immutable 52.18 public class ReturnNode extends Node { 52.19 /** Optional expression. */ 52.20 - private Node expression; 52.21 - 52.22 - /** Try chain. */ 52.23 - @Ignore 52.24 - private final TryNode tryChain; 52.25 + private final Node expression; 52.26 52.27 /** 52.28 * Constructor 52.29 @@ -51,27 +46,20 @@ 52.30 * @param token token 52.31 * @param finish finish 52.32 * @param expression expression to return 52.33 - * @param tryChain surrounding try chain. 52.34 */ 52.35 - public ReturnNode(final Source source, final long token, final int finish, final Node expression, final TryNode tryChain) { 52.36 + public ReturnNode(final Source source, final long token, final int finish, final Node expression) { 52.37 super(source, token, finish); 52.38 - 52.39 this.expression = expression; 52.40 - this.tryChain = tryChain; 52.41 - 52.42 - setIsTerminal(true); 52.43 } 52.44 52.45 - private ReturnNode(final ReturnNode returnNode, final CopyState cs) { 52.46 + private ReturnNode(final ReturnNode returnNode, final Node expression) { 52.47 super(returnNode); 52.48 - 52.49 - this.expression = cs.existingOrCopy(returnNode.expression); 52.50 - this.tryChain = (TryNode)cs.existingOrSame(returnNode.tryChain); 52.51 + this.expression = expression; 52.52 } 52.53 52.54 @Override 52.55 - protected Node copy(final CopyState cs) { 52.56 - return new ReturnNode(this, cs); 52.57 + public boolean isTerminal() { 52.58 + return true; 52.59 } 52.60 52.61 /** 52.62 @@ -100,11 +88,10 @@ 52.63 52.64 @Override 52.65 public Node accept(final NodeVisitor visitor) { 52.66 - if (visitor.enterReturnNode(this) != null) { 52.67 + if (visitor.enterReturnNode(this)) { 52.68 if (expression != null) { 52.69 - expression = expression.accept(visitor); 52.70 + return visitor.leaveReturnNode(setExpression(expression.accept(visitor))); 52.71 } 52.72 - 52.73 return visitor.leaveReturnNode(this); 52.74 } 52.75 52.76 @@ -121,25 +108,6 @@ 52.77 } 52.78 } 52.79 52.80 - @Override 52.81 - public boolean equals(final Object other) { 52.82 - if (other instanceof ReturnNode) { 52.83 - final ReturnNode otherReturn = (ReturnNode)other; 52.84 - if (hasExpression() != otherReturn.hasExpression()) { 52.85 - return false; 52.86 - } else if (hasExpression()) { 52.87 - return otherReturn.getExpression().equals(getExpression()); 52.88 - } 52.89 - return true; 52.90 - } 52.91 - return false; 52.92 - } 52.93 - 52.94 - @Override 52.95 - public int hashCode() { 52.96 - return 0x4711_17 ^ (expression == null ? 0 : expression.hashCode()); 52.97 - } 52.98 - 52.99 /** 52.100 * Get the expression this node returns 52.101 * @return return expression, or null if void return 52.102 @@ -151,16 +119,13 @@ 52.103 /** 52.104 * Reset the expression this node returns 52.105 * @param expression new expression, or null if void return 52.106 + * @return new or same return node 52.107 */ 52.108 - public void setExpression(final Node expression) { 52.109 - this.expression = expression; 52.110 + public ReturnNode setExpression(final Node expression) { 52.111 + if (this.expression == expression) { 52.112 + return this; 52.113 + } 52.114 + return new ReturnNode(this, expression); 52.115 } 52.116 52.117 - /** 52.118 - * Get the surrounding try chain for this return node 52.119 - * @return try chain 52.120 - */ 52.121 - public TryNode getTryChain() { 52.122 - return tryChain; 52.123 - } 52.124 }
53.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Fri Apr 19 18:23:00 2013 +0530 53.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Fri Apr 19 16:11:16 2013 +0200 53.3 @@ -30,14 +30,15 @@ 53.4 import java.util.Collections; 53.5 import java.util.List; 53.6 import jdk.nashorn.internal.codegen.types.Type; 53.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 53.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 53.9 import jdk.nashorn.internal.parser.TokenType; 53.10 import jdk.nashorn.internal.runtime.Source; 53.11 53.12 /** 53.13 * IR representation for a runtime call. 53.14 - * 53.15 */ 53.16 +@Immutable 53.17 public class RuntimeNode extends Node implements TypeOverride<RuntimeNode> { 53.18 53.19 /** 53.20 @@ -271,10 +272,10 @@ 53.21 private final List<Node> args; 53.22 53.23 /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */ 53.24 - private Type callSiteType; 53.25 + private final Type callSiteType; 53.26 53.27 /** is final - i.e. may not be removed again, lower in the code pipeline */ 53.28 - private boolean isFinal; 53.29 + private final boolean isFinal; 53.30 53.31 /** 53.32 * Constructor 53.33 @@ -290,6 +291,17 @@ 53.34 53.35 this.request = request; 53.36 this.args = args; 53.37 + this.callSiteType = null; 53.38 + this.isFinal = false; 53.39 + } 53.40 + 53.41 + private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Node> args) { 53.42 + super(runtimeNode); 53.43 + 53.44 + this.request = request; 53.45 + this.args = args; 53.46 + this.callSiteType = callSiteType; 53.47 + this.isFinal = isFinal; 53.48 } 53.49 53.50 /** 53.51 @@ -326,8 +338,10 @@ 53.52 public RuntimeNode(final Node parent, final Request request, final List<Node> args) { 53.53 super(parent); 53.54 53.55 - this.request = request; 53.56 - this.args = args; 53.57 + this.request = request; 53.58 + this.args = args; 53.59 + this.callSiteType = null; 53.60 + this.isFinal = false; 53.61 } 53.62 53.63 /** 53.64 @@ -350,20 +364,6 @@ 53.65 this(parent, request, parent.lhs(), parent.rhs()); 53.66 } 53.67 53.68 - private RuntimeNode(final RuntimeNode runtimeNode, final CopyState cs) { 53.69 - super(runtimeNode); 53.70 - 53.71 - final List<Node> newArgs = new ArrayList<>(); 53.72 - 53.73 - for (final Node arg : runtimeNode.args) { 53.74 - newArgs.add(cs.existingOrCopy(arg)); 53.75 - } 53.76 - 53.77 - this.request = runtimeNode.request; 53.78 - this.args = newArgs; 53.79 - this.callSiteType = runtimeNode.callSiteType; 53.80 - } 53.81 - 53.82 /** 53.83 * Is this node final - i.e. it can never be replaced with other nodes again 53.84 * @return true if final 53.85 @@ -374,14 +374,14 @@ 53.86 53.87 /** 53.88 * Flag this node as final - i.e it may never be replaced with other nodes again 53.89 + * @param isFinal is the node final, i.e. can not be removed and replaced by a less generic one later in codegen 53.90 + * @return same runtime node if already final, otherwise a new one 53.91 */ 53.92 - public void setIsFinal() { 53.93 - this.isFinal = true; 53.94 - } 53.95 - 53.96 - @Override 53.97 - protected Node copy(final CopyState cs) { 53.98 - return new RuntimeNode(this, cs); 53.99 + public RuntimeNode setIsFinal(final boolean isFinal) { 53.100 + if (this.isFinal == isFinal) { 53.101 + return this; 53.102 + } 53.103 + return new RuntimeNode(this, request, callSiteType, isFinal, args); 53.104 } 53.105 53.106 /** 53.107 @@ -394,8 +394,10 @@ 53.108 53.109 @Override 53.110 public RuntimeNode setType(final Type type) { 53.111 - this.callSiteType = type; 53.112 - return this; 53.113 + if (this.callSiteType == type) { 53.114 + return this; 53.115 + } 53.116 + return new RuntimeNode(this, request, type, isFinal, args); 53.117 } 53.118 53.119 @Override 53.120 @@ -409,12 +411,12 @@ 53.121 53.122 @Override 53.123 public Node accept(final NodeVisitor visitor) { 53.124 - if (visitor.enterRuntimeNode(this) != null) { 53.125 - for (int i = 0, count = args.size(); i < count; i++) { 53.126 - args.set(i, args.get(i).accept(visitor)); 53.127 + if (visitor.enterRuntimeNode(this)) { 53.128 + final List<Node> newArgs = new ArrayList<>(); 53.129 + for (final Node arg : args) { 53.130 + newArgs.add(arg.accept(visitor)); 53.131 } 53.132 - 53.133 - return visitor.leaveRuntimeNode(this); 53.134 + return visitor.leaveRuntimeNode(setArgs(newArgs)); 53.135 } 53.136 53.137 return this; 53.138 @@ -449,6 +451,13 @@ 53.139 return Collections.unmodifiableList(args); 53.140 } 53.141 53.142 + private RuntimeNode setArgs(final List<Node> args) { 53.143 + if (this.args == args) { 53.144 + return this; 53.145 + } 53.146 + return new RuntimeNode(this, request, callSiteType, isFinal, args); 53.147 + } 53.148 + 53.149 /** 53.150 * Get the request that this runtime node implements 53.151 * @return the request
54.1 --- a/src/jdk/nashorn/internal/ir/SplitNode.java Fri Apr 19 18:23:00 2013 +0530 54.2 +++ b/src/jdk/nashorn/internal/ir/SplitNode.java Fri Apr 19 16:11:16 2013 +0200 54.3 @@ -25,99 +25,65 @@ 54.4 54.5 package jdk.nashorn.internal.ir; 54.6 54.7 -import java.util.ArrayList; 54.8 -import java.util.Collections; 54.9 -import java.util.List; 54.10 import jdk.nashorn.internal.codegen.CompileUnit; 54.11 -import jdk.nashorn.internal.codegen.Label; 54.12 -import jdk.nashorn.internal.codegen.MethodEmitter; 54.13 -import jdk.nashorn.internal.ir.annotations.Ignore; 54.14 -import jdk.nashorn.internal.ir.annotations.Reference; 54.15 +import jdk.nashorn.internal.ir.annotations.Immutable; 54.16 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 54.17 54.18 - 54.19 /** 54.20 * Node indicating code is split across classes. 54.21 */ 54.22 -public class SplitNode extends Node { 54.23 +@Immutable 54.24 +public class SplitNode extends LexicalContextNode { 54.25 /** Split node method name. */ 54.26 private final String name; 54.27 54.28 /** Compilation unit. */ 54.29 - private CompileUnit compileUnit; 54.30 - 54.31 - /** Method emitter for current method. */ 54.32 - private MethodEmitter method; 54.33 - 54.34 - /** Method emitter for caller method. */ 54.35 - private MethodEmitter caller; 54.36 - 54.37 - /** Containing function. */ 54.38 - @Reference 54.39 - private final FunctionNode functionNode; 54.40 - 54.41 - /** A list of target labels in parent methods this split node may encounter. */ 54.42 - @Ignore 54.43 - private final List<Label> externalTargets; 54.44 - 54.45 - /** True if this split node or any of its children contain a return statement. */ 54.46 - private boolean hasReturn; 54.47 + private final CompileUnit compileUnit; 54.48 54.49 /** Body of split code. */ 54.50 - @Ignore 54.51 - private Node body; 54.52 + private final Node body; 54.53 54.54 /** 54.55 * Constructor 54.56 * 54.57 - * @param name name of split node 54.58 - * @param functionNode function node to split in 54.59 - * @param body body of split code 54.60 + * @param name name of split node 54.61 + * @param body body of split code 54.62 + * @param compileUnit compile unit to use for the body 54.63 */ 54.64 - public SplitNode(final String name, final FunctionNode functionNode, final Node body) { 54.65 + public SplitNode(final String name, final Node body, final CompileUnit compileUnit) { 54.66 super(body.getSource(), body.getToken(), body.getFinish()); 54.67 - 54.68 - this.name = name; 54.69 - this.functionNode = functionNode; 54.70 - this.body = body; 54.71 - this.externalTargets = new ArrayList<>(); 54.72 + this.name = name; 54.73 + this.body = body; 54.74 + this.compileUnit = compileUnit; 54.75 } 54.76 54.77 - private SplitNode(final SplitNode splitNode, final CopyState cs) { 54.78 + private SplitNode(final SplitNode splitNode, final Node body) { 54.79 super(splitNode); 54.80 + this.name = splitNode.name; 54.81 + this.body = body; 54.82 + this.compileUnit = splitNode.compileUnit; 54.83 + } 54.84 54.85 - this.name = splitNode.name; 54.86 - this.functionNode = (FunctionNode)cs.existingOrSame(splitNode.functionNode); 54.87 - this.body = cs.existingOrCopy(splitNode.body); 54.88 - this.externalTargets = new ArrayList<>(); 54.89 + /** 54.90 + * Get the body for this split node - i.e. the actual code it encloses 54.91 + * @return body for split node 54.92 + */ 54.93 + public Node getBody() { 54.94 + return body; 54.95 + } 54.96 + 54.97 + private SplitNode setBody(final LexicalContext lc, final Node body) { 54.98 + if (this.body == body) { 54.99 + return this; 54.100 + } 54.101 + return Node.replaceInLexicalContext(lc, this, new SplitNode(this, body)); 54.102 } 54.103 54.104 @Override 54.105 - protected Node copy(final CopyState cs) { 54.106 - return new SplitNode(this, cs); 54.107 - } 54.108 - 54.109 - @Override 54.110 - public Node accept(final NodeVisitor visitor) { 54.111 - final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit(); 54.112 - final MethodEmitter saveMethod = visitor.getCurrentMethodEmitter(); 54.113 - 54.114 - setCaller(saveMethod); 54.115 - 54.116 - visitor.setCurrentCompileUnit(getCompileUnit()); 54.117 - visitor.setCurrentMethodEmitter(getMethodEmitter()); 54.118 - 54.119 - try { 54.120 - if (visitor.enterSplitNode(this) != null) { 54.121 - body = body.accept(visitor); 54.122 - 54.123 - return visitor.leaveSplitNode(this); 54.124 - } 54.125 - } finally { 54.126 - visitor.setCurrentCompileUnit(saveCompileUnit); 54.127 - visitor.setCurrentMethodEmitter(saveMethod); 54.128 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 54.129 + if (visitor.enterSplitNode(this)) { 54.130 + return visitor.leaveSplitNode(setBody(lc, body.accept(visitor))); 54.131 } 54.132 - 54.133 return this; 54.134 } 54.135 54.136 @@ -130,22 +96,6 @@ 54.137 } 54.138 54.139 /** 54.140 - * Get the method emitter of the caller for this split node 54.141 - * @return caller method emitter 54.142 - */ 54.143 - public MethodEmitter getCaller() { 54.144 - return caller; 54.145 - } 54.146 - 54.147 - /** 54.148 - * Set the caller method emitter for this split node 54.149 - * @param caller method emitter 54.150 - */ 54.151 - public void setCaller(final MethodEmitter caller) { 54.152 - this.caller = caller; 54.153 - } 54.154 - 54.155 - /** 54.156 * Get the name for this split node 54.157 * @return name 54.158 */ 54.159 @@ -161,67 +111,4 @@ 54.160 return compileUnit; 54.161 } 54.162 54.163 - /** 54.164 - * Set the compile unit for this split node 54.165 - * @param compileUnit compile unit 54.166 - */ 54.167 - public void setCompileUnit(final CompileUnit compileUnit) { 54.168 - this.compileUnit = compileUnit; 54.169 - } 54.170 - 54.171 - /** 54.172 - * Get the method emitter for this split node 54.173 - * @return method emitter 54.174 - */ 54.175 - public MethodEmitter getMethodEmitter() { 54.176 - return method; 54.177 - } 54.178 - 54.179 - /** 54.180 - * Set the method emitter for this split node 54.181 - * @param method method emitter 54.182 - */ 54.183 - public void setMethodEmitter(final MethodEmitter method) { 54.184 - this.method = method; 54.185 - } 54.186 - 54.187 - /** 54.188 - * Get the function node this SplitNode splits 54.189 - * @return function node reference 54.190 - */ 54.191 - public FunctionNode getFunctionNode() { 54.192 - return functionNode; 54.193 - } 54.194 - 54.195 - /** 54.196 - * Get the external targets for this SplitNode 54.197 - * @return list of external targets 54.198 - */ 54.199 - public List<Label> getExternalTargets() { 54.200 - return Collections.unmodifiableList(externalTargets); 54.201 - } 54.202 - 54.203 - /** 54.204 - * Add an external target for this SplitNode 54.205 - * @param targetLabel target label 54.206 - */ 54.207 - public void addExternalTarget(final Label targetLabel) { 54.208 - externalTargets.add(targetLabel); 54.209 - } 54.210 - 54.211 - /** 54.212 - * Check whether this SplitNode returns a value 54.213 - * @return true if return 54.214 - */ 54.215 - public boolean hasReturn() { 54.216 - return hasReturn; 54.217 - } 54.218 - 54.219 - /** 54.220 - * Set whether this SplitNode returns a value or not 54.221 - * @param hasReturn true if return exists, false otherwise 54.222 - */ 54.223 - public void setHasReturn(final boolean hasReturn) { 54.224 - this.hasReturn = hasReturn; 54.225 - } 54.226 }
55.1 --- a/src/jdk/nashorn/internal/ir/SwitchNode.java Fri Apr 19 18:23:00 2013 +0530 55.2 +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java Fri Apr 19 16:11:16 2013 +0200 55.3 @@ -28,73 +28,84 @@ 55.4 import java.util.ArrayList; 55.5 import java.util.Collections; 55.6 import java.util.List; 55.7 + 55.8 import jdk.nashorn.internal.codegen.Label; 55.9 -import jdk.nashorn.internal.ir.annotations.Ignore; 55.10 +import jdk.nashorn.internal.ir.annotations.Immutable; 55.11 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 55.12 import jdk.nashorn.internal.runtime.Source; 55.13 55.14 /** 55.15 * IR representation of a SWITCH statement. 55.16 */ 55.17 -public class SwitchNode extends BreakableNode { 55.18 +@Immutable 55.19 +public final class SwitchNode extends BreakableNode { 55.20 /** Switch expression. */ 55.21 - private Node expression; 55.22 + private final Node expression; 55.23 + 55.24 + /** Switch cases. */ 55.25 + private final List<CaseNode> cases; 55.26 + 55.27 + /** Switch default index. */ 55.28 + private final int defaultCaseIndex; 55.29 55.30 /** Tag symbol. */ 55.31 private Symbol tag; 55.32 55.33 - /** Switch cases. */ 55.34 - private List<CaseNode> cases; 55.35 - 55.36 - /** Switch default. */ 55.37 - @Ignore //points to one of the members in the list above, don't traverse twice 55.38 - private CaseNode defaultCase; 55.39 - 55.40 /** 55.41 * Constructor 55.42 * 55.43 - * @param source the source 55.44 - * @param token token 55.45 - * @param finish finish 55.46 + * @param source the source 55.47 + * @param token token 55.48 + * @param finish finish 55.49 + * @param expression switch expression 55.50 + * @param cases cases 55.51 + * @param defaultCase the default case node - null if none, otherwise has to be present in cases list 55.52 */ 55.53 - public SwitchNode(final Source source, final long token, final int finish) { 55.54 - super(source, token, finish); 55.55 - this.breakLabel = new Label("switch_break"); 55.56 + public SwitchNode(final Source source, final long token, final int finish, final Node expression, final List<CaseNode> cases, final CaseNode defaultCase) { 55.57 + super(source, token, finish, new Label("switch_break")); 55.58 + this.expression = expression; 55.59 + this.cases = cases; 55.60 + this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase); 55.61 } 55.62 55.63 - private SwitchNode(final SwitchNode switchNode, final CopyState cs) { 55.64 + private SwitchNode(final SwitchNode switchNode, final Node expression, final List<CaseNode> cases, final int defaultCase) { 55.65 super(switchNode); 55.66 - 55.67 - final List<CaseNode> newCases = new ArrayList<>(); 55.68 - 55.69 - for (final CaseNode caseNode : switchNode.getCases()) { 55.70 - newCases.add((CaseNode)cs.existingOrCopy(caseNode)); 55.71 - } 55.72 - 55.73 - this.expression = cs.existingOrCopy(switchNode.getExpression()); 55.74 - this.tag = switchNode.getTag(); 55.75 - this.cases = newCases; 55.76 - this.defaultCase = (CaseNode)cs.existingOrCopy(switchNode.getDefaultCase()); 55.77 - this.breakLabel = new Label(switchNode.getBreakLabel()); 55.78 + this.expression = expression; 55.79 + this.cases = cases; 55.80 + this.defaultCaseIndex = defaultCase; 55.81 + this.tag = switchNode.getTag(); //TODO are symbols inhereted as references? 55.82 } 55.83 55.84 @Override 55.85 - protected Node copy(final CopyState cs) { 55.86 - return new SwitchNode(this, cs); 55.87 + public Node ensureUniqueLabels(final LexicalContext lc) { 55.88 + final List<CaseNode> newCases = new ArrayList<>(); 55.89 + for (final CaseNode caseNode : cases) { 55.90 + newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody())); 55.91 + } 55.92 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex)); 55.93 } 55.94 55.95 @Override 55.96 - public Node accept(final NodeVisitor visitor) { 55.97 - if (visitor.enterSwitchNode(this) != null) { 55.98 - expression = expression.accept(visitor); 55.99 + public boolean isTerminal() { 55.100 + //there must be a default case, and that including all other cases must terminate 55.101 + if (!cases.isEmpty() && defaultCaseIndex != -1) { 55.102 + for (final CaseNode caseNode : cases) { 55.103 + if (!caseNode.isTerminal()) { 55.104 + return false; 55.105 + } 55.106 + } 55.107 + return true; 55.108 + } 55.109 + return false; 55.110 55.111 - for (int i = 0, count = cases.size(); i < count; i++) { 55.112 - cases.set(i, (CaseNode)cases.get(i).accept(visitor)); 55.113 - } 55.114 + } 55.115 55.116 - //the default case is in the cases list and should not be explicitly traversed! 55.117 - 55.118 - return visitor.leaveSwitchNode(this); 55.119 + @Override 55.120 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 55.121 + if (visitor.enterSwitchNode(this)) { 55.122 + return visitor.leaveSwitchNode( 55.123 + setExpression(visitor.getLexicalContext(), expression.accept(visitor)). 55.124 + setCases(visitor.getLexicalContext(), Node.accept(visitor, CaseNode.class, cases), defaultCaseIndex)); 55.125 } 55.126 55.127 return this; 55.128 @@ -108,6 +119,14 @@ 55.129 } 55.130 55.131 /** 55.132 + * Return the case node that is default case 55.133 + * @return default case or null if none 55.134 + */ 55.135 + public CaseNode getDefaultCase() { 55.136 + return defaultCaseIndex == -1 ? null : cases.get(defaultCaseIndex); 55.137 + } 55.138 + 55.139 + /** 55.140 * Get the cases in this switch 55.141 * @return a list of case nodes 55.142 */ 55.143 @@ -116,27 +135,33 @@ 55.144 } 55.145 55.146 /** 55.147 - * Set or reset the list of cases in this switch 55.148 - * @param cases a list of cases, case nodes 55.149 + * Replace case nodes with new list. the cases have to be the same 55.150 + * and the default case index the same. This is typically used 55.151 + * by NodeVisitors who perform operations on every case node 55.152 + * @param lc lexical context 55.153 + * @param cases list of cases 55.154 + * @return new switcy node or same if no state was changed 55.155 */ 55.156 - public void setCases(final List<CaseNode> cases) { 55.157 - this.cases = cases; 55.158 + public SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases) { 55.159 + return setCases(lc, cases, defaultCaseIndex); 55.160 + } 55.161 + 55.162 + private SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases, final int defaultCaseIndex) { 55.163 + if (this.cases == cases) { 55.164 + return this; 55.165 + } 55.166 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex)); 55.167 } 55.168 55.169 /** 55.170 - * Get the default case for this switch 55.171 - * @return default case node 55.172 + * Set or reset the list of cases in this switch 55.173 + * @param lc lexical context 55.174 + * @param cases a list of cases, case nodes 55.175 + * @param defaultCase a case in the list that is the default - must be in the list or class will assert 55.176 + * @return new switch node or same if no state was changed 55.177 */ 55.178 - public CaseNode getDefaultCase() { 55.179 - return defaultCase; 55.180 - } 55.181 - 55.182 - /** 55.183 - * Set the default case for this switch 55.184 - * @param defaultCase default case node 55.185 - */ 55.186 - public void setDefaultCase(final CaseNode defaultCase) { 55.187 - this.defaultCase = defaultCase; 55.188 + public SwitchNode setCases(final LexicalContext lc, final List<CaseNode> cases, final CaseNode defaultCase) { 55.189 + return setCases(lc, cases, defaultCase == null ? -1 : cases.indexOf(defaultCase)); 55.190 } 55.191 55.192 /** 55.193 @@ -149,10 +174,15 @@ 55.194 55.195 /** 55.196 * Set or reset the expression to switch on 55.197 + * @param lc lexical context 55.198 * @param expression switch expression 55.199 + * @return new switch node or same if no state was changed 55.200 */ 55.201 - public void setExpression(final Node expression) { 55.202 - this.expression = expression; 55.203 + public SwitchNode setExpression(final LexicalContext lc, final Node expression) { 55.204 + if (this.expression == expression) { 55.205 + return this; 55.206 + } 55.207 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex)); 55.208 } 55.209 55.210 /**
56.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java Fri Apr 19 18:23:00 2013 +0530 56.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Fri Apr 19 16:11:16 2013 +0200 56.3 @@ -29,8 +29,10 @@ 56.4 import java.util.HashSet; 56.5 import java.util.Set; 56.6 import java.util.StringTokenizer; 56.7 + 56.8 import jdk.nashorn.internal.codegen.types.Type; 56.9 import jdk.nashorn.internal.runtime.Context; 56.10 +import jdk.nashorn.internal.runtime.Debug; 56.11 import jdk.nashorn.internal.runtime.options.Options; 56.12 56.13 /** 56.14 @@ -63,6 +65,8 @@ 56.15 public static final int IS_LET = 1 << 8; 56.16 /** Is this an internal symbol, never represented explicitly in source code */ 56.17 public static final int IS_INTERNAL = 1 << 9; 56.18 + /** Is this a function self-reference symbol */ 56.19 + public static final int IS_FUNCTION_SELF = 1 << 10; 56.20 56.21 /** Null or name identifying symbol. */ 56.22 private final String name; 56.23 @@ -70,12 +74,6 @@ 56.24 /** Symbol flags. */ 56.25 private int flags; 56.26 56.27 - /** Defining node. */ 56.28 - private Node node; 56.29 - 56.30 - /** Definition block. */ 56.31 - private final Block block; 56.32 - 56.33 /** Type of symbol. */ 56.34 private Type type; 56.35 56.36 @@ -121,16 +119,12 @@ 56.37 * 56.38 * @param name name of symbol 56.39 * @param flags symbol flags 56.40 - * @param node node this symbol is in 56.41 - * @param block block this symbol is in 56.42 * @param type type of this symbol 56.43 * @param slot bytecode slot for this symbol 56.44 */ 56.45 - protected Symbol(final String name, final int flags, final Node node, final Block block, final Type type, final int slot) { 56.46 + protected Symbol(final String name, final int flags, final Type type, final int slot) { 56.47 this.name = name; 56.48 this.flags = flags; 56.49 - this.node = node; 56.50 - this.block = block; 56.51 this.type = type; 56.52 this.slot = slot; 56.53 this.fieldIndex = -1; 56.54 @@ -142,11 +136,9 @@ 56.55 * 56.56 * @param name name of symbol 56.57 * @param flags symbol flags 56.58 - * @param node node this symbol is in 56.59 - * @param block block this symbol is in 56.60 */ 56.61 - public Symbol(final String name, final int flags, final Node node, final Block block) { 56.62 - this(name, flags, node, block, Type.UNKNOWN, -1); 56.63 + public Symbol(final String name, final int flags) { 56.64 + this(name, flags, Type.UNKNOWN, -1); 56.65 } 56.66 56.67 /** 56.68 @@ -157,7 +149,7 @@ 56.69 * @param type type of this symbol 56.70 */ 56.71 public Symbol(final String name, final int flags, final Type type) { 56.72 - this(name, flags, null, null, type, -1); 56.73 + this(name, flags, type, -1); 56.74 } 56.75 56.76 private static String align(final String string, final int max) { 56.77 @@ -269,20 +261,6 @@ 56.78 return type.isCategory2() ? 2 : 1; 56.79 } 56.80 56.81 - @Override 56.82 - public boolean equals(final Object other) { 56.83 - if (!(other instanceof Symbol)) { 56.84 - return false; 56.85 - } 56.86 - final Symbol symbol = (Symbol) other; 56.87 - return name.equals(symbol.name) && block.equals(symbol.block); 56.88 - } 56.89 - 56.90 - @Override 56.91 - public int hashCode() { 56.92 - return name.hashCode() ^ block.hashCode(); 56.93 - } 56.94 - 56.95 private static String type(final String desc) { 56.96 switch (desc.charAt(desc.length() - 1)) { 56.97 case ';': 56.98 @@ -371,14 +349,14 @@ 56.99 /** 56.100 * Flag this symbol as scope as described in {@link Symbol#isScope()} 56.101 */ 56.102 - public void setIsScope() { 56.103 + /** 56.104 + * Flag this symbol as scope as described in {@link Symbol#isScope()} 56.105 + */ 56.106 + public void setIsScope() { 56.107 if (!isScope()) { 56.108 trace("SET IS SCOPE"); 56.109 } 56.110 flags |= IS_SCOPE; 56.111 - if(!isGlobal()) { 56.112 - getBlock().setNeedsScope(); 56.113 - } 56.114 } 56.115 56.116 /** 56.117 @@ -478,11 +456,11 @@ 56.118 } 56.119 56.120 /** 56.121 - * Get the block in which the symbol is defined 56.122 - * @return a block 56.123 + * Flag this symbol as a function's self-referencing symbol. 56.124 + * @return true if this symbol as a function's self-referencing symbol. 56.125 */ 56.126 - public Block getBlock() { 56.127 - return block; 56.128 + public boolean isFunctionSelf() { 56.129 + return (flags & IS_FUNCTION_SELF) == IS_FUNCTION_SELF; 56.130 } 56.131 56.132 /** 56.133 @@ -492,7 +470,7 @@ 56.134 * @return field index 56.135 */ 56.136 public int getFieldIndex() { 56.137 - assert fieldIndex != -1 : "fieldIndex must be initialized"; 56.138 + assert fieldIndex != -1 : "fieldIndex must be initialized " + fieldIndex; 56.139 return fieldIndex; 56.140 } 56.141 56.142 @@ -503,7 +481,6 @@ 56.143 * @param fieldIndex field index - a positive integer 56.144 */ 56.145 public void setFieldIndex(final int fieldIndex) { 56.146 - assert this.fieldIndex == -1 : "fieldIndex must be initialized only once"; 56.147 this.fieldIndex = fieldIndex; 56.148 } 56.149 56.150 @@ -524,22 +501,6 @@ 56.151 } 56.152 56.153 /** 56.154 - * Get the node this symbol stores the result for 56.155 - * @return node 56.156 - */ 56.157 - public Node getNode() { 56.158 - return node; 56.159 - } 56.160 - 56.161 - /** 56.162 - * Set the node this symbol stores the result for 56.163 - * @param node node 56.164 - */ 56.165 - public void setNode(final Node node) { 56.166 - this.node = node; 56.167 - } 56.168 - 56.169 - /** 56.170 * Get the name of this symbol 56.171 * @return symbol name 56.172 */ 56.173 @@ -616,18 +577,25 @@ 56.174 } 56.175 56.176 /** 56.177 - * Check if this symbol is in the global scope, i.e. it is on the outermost level 56.178 - * in the script 56.179 - * @return true if this this is a global scope symbol 56.180 + * From a lexical context, set this symbol as needing scope, which 56.181 + * will set flags for the defining block that will be written when 56.182 + * block is popped from the lexical context stack, used by codegen 56.183 + * when flags need to be tagged, but block is in the 56.184 + * middle of evaluation and cannot be modified. 56.185 + * 56.186 + * @param lc lexical context 56.187 + * @param symbol symbol 56.188 */ 56.189 - public boolean isTopLevel() { 56.190 - return block instanceof FunctionNode && ((FunctionNode) block).isProgram(); 56.191 + public static void setSymbolIsScope(final LexicalContext lc, final Symbol symbol) { 56.192 + symbol.setIsScope(); 56.193 + if (!symbol.isGlobal()) { 56.194 + lc.setFlag(lc.getDefiningBlock(symbol), Block.NEEDS_SCOPE); 56.195 + } 56.196 } 56.197 56.198 - 56.199 private void trace(final String desc) { 56.200 if (TRACE_SYMBOLS != null && (TRACE_SYMBOLS.isEmpty() || TRACE_SYMBOLS.contains(name))) { 56.201 - Context.err("SYMBOL: '" + name + "' " + desc); 56.202 + Context.err(Debug.id(this) + " SYMBOL: '" + name + "' " + desc); 56.203 if (TRACE_SYMBOLS_STACKTRACE != null && (TRACE_SYMBOLS_STACKTRACE.isEmpty() || TRACE_SYMBOLS_STACKTRACE.contains(name))) { 56.204 new Throwable().printStackTrace(Context.getCurrentErr()); 56.205 }
57.1 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java Fri Apr 19 18:23:00 2013 +0530 57.2 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java Fri Apr 19 16:11:16 2013 +0200 57.3 @@ -25,15 +25,21 @@ 57.4 57.5 package jdk.nashorn.internal.ir; 57.6 57.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 57.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 57.9 import jdk.nashorn.internal.runtime.Source; 57.10 57.11 /** 57.12 * TernaryNode nodes represent three operand operations (?:). 57.13 */ 57.14 -public class TernaryNode extends BinaryNode { 57.15 +@Immutable 57.16 +public final class TernaryNode extends Node { 57.17 + private final Node lhs; 57.18 + 57.19 + private final Node rhs; 57.20 + 57.21 /** Third argument. */ 57.22 - private Node third; 57.23 + private final Node third; 57.24 57.25 /** 57.26 * Constructor 57.27 @@ -45,43 +51,26 @@ 57.28 * @param third third node 57.29 */ 57.30 public TernaryNode(final Source source, final long token, final Node lhs, final Node rhs, final Node third) { 57.31 - super(source, token, lhs, rhs); 57.32 - 57.33 - this.finish = third.getFinish(); 57.34 + super(source, token, third.getFinish()); 57.35 + this.lhs = lhs; 57.36 + this.rhs = rhs; 57.37 this.third = third; 57.38 } 57.39 57.40 - private TernaryNode(final TernaryNode ternaryNode, final CopyState cs) { 57.41 - super(ternaryNode, cs); 57.42 - 57.43 - this.third = cs.existingOrCopy(ternaryNode.third); 57.44 - } 57.45 - 57.46 - @Override 57.47 - protected Node copy(final CopyState cs) { 57.48 - return new TernaryNode(this, cs); 57.49 - } 57.50 - 57.51 - @Override 57.52 - public boolean equals(final Object other) { 57.53 - if (!super.equals(other)) { 57.54 - return false; 57.55 - } 57.56 - return third.equals(((TernaryNode)other).third()); 57.57 - } 57.58 - 57.59 - @Override 57.60 - public int hashCode() { 57.61 - return super.hashCode() ^ third().hashCode(); 57.62 + private TernaryNode(final TernaryNode ternaryNode, final Node lhs, final Node rhs, final Node third) { 57.63 + super(ternaryNode); 57.64 + this.lhs = lhs; 57.65 + this.rhs = rhs; 57.66 + this.third = third; 57.67 } 57.68 57.69 @Override 57.70 public Node accept(final NodeVisitor visitor) { 57.71 - if (visitor.enterTernaryNode(this) != null) { 57.72 + if (visitor.enterTernaryNode(this)) { 57.73 final Node newLhs = lhs().accept(visitor); 57.74 final Node newRhs = rhs().accept(visitor); 57.75 final Node newThird = third.accept(visitor); 57.76 - return visitor.leaveTernaryNode((TernaryNode)setThird(newThird).setLHS(newLhs).setRHS(newRhs)); 57.77 + return visitor.leaveTernaryNode(setThird(newThird).setLHS(newLhs).setRHS(newRhs)); 57.78 } 57.79 57.80 return this; 57.81 @@ -123,6 +112,22 @@ 57.82 } 57.83 57.84 /** 57.85 + * Get the lhs node for this ternary expression, i.e. "x" in x ? y : z 57.86 + * @return a node 57.87 + */ 57.88 + public Node lhs() { 57.89 + return lhs; 57.90 + } 57.91 + 57.92 + /** 57.93 + * Get the rhs node for this ternary expression, i.e. "y" in x ? y : z 57.94 + * @return a node 57.95 + */ 57.96 + public Node rhs() { 57.97 + return rhs; 57.98 + } 57.99 + 57.100 + /** 57.101 * Get the "third" node for this ternary expression, i.e. "z" in x ? y : z 57.102 * @return a node 57.103 */ 57.104 @@ -131,14 +136,38 @@ 57.105 } 57.106 57.107 /** 57.108 + * Set the left hand side expression for this node 57.109 + * @param lhs new left hand side expression 57.110 + * @return a node equivalent to this one except for the requested change. 57.111 + */ 57.112 + public TernaryNode setLHS(final Node lhs) { 57.113 + if (this.lhs == lhs) { 57.114 + return this; 57.115 + } 57.116 + return new TernaryNode(this, lhs, rhs, third); 57.117 + } 57.118 + 57.119 + /** 57.120 + * Set the right hand side expression for this node 57.121 + * @param rhs new left hand side expression 57.122 + * @return a node equivalent to this one except for the requested change. 57.123 + */ 57.124 + public TernaryNode setRHS(final Node rhs) { 57.125 + if (this.rhs == rhs) { 57.126 + return this; 57.127 + } 57.128 + return new TernaryNode(this, lhs, rhs, third); 57.129 + } 57.130 + 57.131 + /** 57.132 * Reset the "third" node for this ternary expression, i.e. "z" in x ? y : z 57.133 * @param third a node 57.134 * @return a node equivalent to this one except for the requested change. 57.135 */ 57.136 public TernaryNode setThird(final Node third) { 57.137 - if(this.third == third) return this; 57.138 - final TernaryNode n = (TernaryNode)clone(); 57.139 - n.third = third; 57.140 - return n; 57.141 + if (this.third == third) { 57.142 + return this; 57.143 + } 57.144 + return new TernaryNode(this, lhs, rhs, third); 57.145 } 57.146 }
58.1 --- a/src/jdk/nashorn/internal/ir/ThrowNode.java Fri Apr 19 18:23:00 2013 +0530 58.2 +++ b/src/jdk/nashorn/internal/ir/ThrowNode.java Fri Apr 19 16:11:16 2013 +0200 58.3 @@ -25,20 +25,17 @@ 58.4 58.5 package jdk.nashorn.internal.ir; 58.6 58.7 -import jdk.nashorn.internal.ir.annotations.Ignore; 58.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 58.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 58.10 import jdk.nashorn.internal.runtime.Source; 58.11 58.12 /** 58.13 * IR representation for THROW statements. 58.14 */ 58.15 -public class ThrowNode extends Node { 58.16 +@Immutable 58.17 +public final class ThrowNode extends Node { 58.18 /** Exception expression. */ 58.19 - private Node expression; 58.20 - 58.21 - /** Try chain. */ 58.22 - @Ignore 58.23 - private final TryNode tryChain; 58.24 + private final Node expression; 58.25 58.26 /** 58.27 * Constructor 58.28 @@ -47,26 +44,21 @@ 58.29 * @param token token 58.30 * @param finish finish 58.31 * @param expression expression to throw 58.32 - * @param tryChain surrounding try chain 58.33 */ 58.34 - public ThrowNode(final Source source, final long token, final int finish, final Node expression, final TryNode tryChain) { 58.35 + public ThrowNode(final Source source, final long token, final int finish, final Node expression) { 58.36 super(source, token, finish); 58.37 58.38 this.expression = expression; 58.39 - this.tryChain = tryChain; 58.40 - setIsTerminal(true); 58.41 } 58.42 58.43 - private ThrowNode(final ThrowNode throwNode, final CopyState cs) { 58.44 - super(throwNode); 58.45 - 58.46 - this.expression = cs.existingOrCopy(throwNode.expression); 58.47 - this.tryChain = (TryNode)cs.existingOrSame(throwNode.tryChain); 58.48 + private ThrowNode(final Node node, final Node expression) { 58.49 + super(node); 58.50 + this.expression = expression; 58.51 } 58.52 58.53 @Override 58.54 - protected Node copy(final CopyState cs) { 58.55 - return new ThrowNode(this, cs); 58.56 + public boolean isTerminal() { 58.57 + return true; 58.58 } 58.59 58.60 /** 58.61 @@ -75,9 +67,8 @@ 58.62 */ 58.63 @Override 58.64 public Node accept(final NodeVisitor visitor) { 58.65 - if (visitor.enterThrowNode(this) != null) { 58.66 - setExpression(expression.accept(visitor)); 58.67 - return visitor.leaveThrowNode(this); 58.68 + if (visitor.enterThrowNode(this)) { 58.69 + return visitor.leaveThrowNode(setExpression(expression.accept(visitor))); 58.70 } 58.71 58.72 return this; 58.73 @@ -103,16 +94,13 @@ 58.74 /** 58.75 * Reset the expression being thrown by this node 58.76 * @param expression new expression 58.77 + * @return new or same thrownode 58.78 */ 58.79 - public void setExpression(final Node expression) { 58.80 - this.expression = expression; 58.81 + public ThrowNode setExpression(final Node expression) { 58.82 + if (this.expression == expression) { 58.83 + return this; 58.84 + } 58.85 + return new ThrowNode(this, expression); 58.86 } 58.87 58.88 - /** 58.89 - * Get surrounding tryChain for this node 58.90 - * @return try chain 58.91 - */ 58.92 - public TryNode getTryChain() { 58.93 - return tryChain; 58.94 - } 58.95 }
59.1 --- a/src/jdk/nashorn/internal/ir/TryNode.java Fri Apr 19 18:23:00 2013 +0530 59.2 +++ b/src/jdk/nashorn/internal/ir/TryNode.java Fri Apr 19 16:11:16 2013 +0200 59.3 @@ -28,30 +28,28 @@ 59.4 import java.util.ArrayList; 59.5 import java.util.Collections; 59.6 import java.util.List; 59.7 + 59.8 import jdk.nashorn.internal.codegen.Label; 59.9 -import jdk.nashorn.internal.ir.annotations.Ignore; 59.10 +import jdk.nashorn.internal.ir.annotations.Immutable; 59.11 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 59.12 import jdk.nashorn.internal.runtime.Source; 59.13 59.14 /** 59.15 * IR representation of a TRY statement. 59.16 */ 59.17 -public class TryNode extends Node { 59.18 - /** Try chain. */ 59.19 - @Ignore //don't print, will be apparent from the AST 59.20 - private TryNode next; 59.21 - 59.22 +@Immutable 59.23 +public final class TryNode extends Node { 59.24 /** Try statements. */ 59.25 - private Block body; 59.26 + private final Block body; 59.27 59.28 /** List of catch clauses. */ 59.29 - private List<Block> catchBlocks; 59.30 + private final List<Block> catchBlocks; 59.31 59.32 /** Finally clause. */ 59.33 - private Block finallyBody; 59.34 + private final Block finallyBody; 59.35 59.36 /** Exit label. */ 59.37 - private Label exit; 59.38 + private final Label exit; 59.39 59.40 /** Exception symbol. */ 59.41 private Symbol exception; 59.42 @@ -62,37 +60,46 @@ 59.43 /** 59.44 * Constructor 59.45 * 59.46 - * @param source the source 59.47 - * @param token token 59.48 - * @param finish finish 59.49 - * @param next next try node in chain 59.50 + * @param source the source 59.51 + * @param token token 59.52 + * @param finish finish 59.53 + * @param body try node body 59.54 + * @param catchBlocks list of catch blocks in order 59.55 + * @param finallyBody body of finally block or null if none 59.56 */ 59.57 - public TryNode(final Source source, final long token, final int finish, final TryNode next) { 59.58 + public TryNode(final Source source, final long token, final int finish, final Block body, final List<Block> catchBlocks, final Block finallyBody) { 59.59 super(source, token, finish); 59.60 - 59.61 - this.next = next; 59.62 + this.body = body; 59.63 + this.catchBlocks = catchBlocks; 59.64 + this.finallyBody = finallyBody; 59.65 this.exit = new Label("exit"); 59.66 } 59.67 59.68 - private TryNode(final TryNode tryNode, final CopyState cs) { 59.69 + private TryNode(final TryNode tryNode, final Block body, final List<Block> catchBlocks, final Block finallyBody) { 59.70 super(tryNode); 59.71 - 59.72 - final List<Block> newCatchBlocks = new ArrayList<>(); 59.73 - 59.74 - for (final Block block : tryNode.catchBlocks) { 59.75 - newCatchBlocks.add((Block)cs.existingOrCopy(block)); 59.76 - } 59.77 - 59.78 - this.next = (TryNode)cs.existingOrSame(tryNode.getNext()); 59.79 - this.body = (Block)cs.existingOrCopy(tryNode.getBody()); 59.80 - this.catchBlocks = newCatchBlocks; 59.81 - this.finallyBody = (Block)cs.existingOrCopy(tryNode.getFinallyBody()); 59.82 - this.exit = new Label(tryNode.getExit()); 59.83 + this.body = body; 59.84 + this.catchBlocks = catchBlocks; 59.85 + this.finallyBody = finallyBody; 59.86 + this.exit = new Label(tryNode.exit); 59.87 } 59.88 59.89 @Override 59.90 - protected Node copy(final CopyState cs) { 59.91 - return new TryNode(this, cs); 59.92 + public Node ensureUniqueLabels(final LexicalContext lc) { 59.93 + //try nodes are never in lex context 59.94 + return new TryNode(this, body, catchBlocks, finallyBody); 59.95 + } 59.96 + 59.97 + @Override 59.98 + public boolean isTerminal() { 59.99 + if (body.isTerminal()) { 59.100 + for (final Block catchBlock : getCatchBlocks()) { 59.101 + if (!catchBlock.isTerminal()) { 59.102 + return false; 59.103 + } 59.104 + } 59.105 + return true; 59.106 + } 59.107 + return false; 59.108 } 59.109 59.110 /** 59.111 @@ -101,21 +108,16 @@ 59.112 */ 59.113 @Override 59.114 public Node accept(final NodeVisitor visitor) { 59.115 - if (visitor.enterTryNode(this) != null) { 59.116 - // Need to do first for termination analysis. 59.117 - if (finallyBody != null) { 59.118 - finallyBody = (Block)finallyBody.accept(visitor); 59.119 - } 59.120 - 59.121 - body = (Block)body.accept(visitor); 59.122 - 59.123 - final List<Block> newCatchBlocks = new ArrayList<>(catchBlocks.size()); 59.124 - for (final Block catchBlock : catchBlocks) { 59.125 - newCatchBlocks.add((Block)catchBlock.accept(visitor)); 59.126 - } 59.127 - this.catchBlocks = newCatchBlocks; 59.128 - 59.129 - return visitor.leaveTryNode(this); 59.130 + if (visitor.enterTryNode(this)) { 59.131 + // Need to do finallybody first for termination analysis. TODO still necessary? 59.132 + final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor); 59.133 + final Block newBody = (Block)body.accept(visitor); 59.134 + return visitor.leaveTryNode( 59.135 + setBody(newBody). 59.136 + setFinallyBody(newFinallyBody). 59.137 + setCatchBlocks(Node.accept(visitor, Block.class, catchBlocks)). 59.138 + setException(exception). 59.139 + setFinallyCatchAll(finallyCatchAll)); 59.140 } 59.141 59.142 return this; 59.143 @@ -123,7 +125,7 @@ 59.144 59.145 @Override 59.146 public void toString(final StringBuilder sb) { 59.147 - sb.append("try"); 59.148 + sb.append("try "); 59.149 } 59.150 59.151 /** 59.152 @@ -137,9 +139,13 @@ 59.153 /** 59.154 * Reset the body of this try block 59.155 * @param body new body 59.156 + * @return new TryNode or same if unchanged 59.157 */ 59.158 - public void setBody(final Block body) { 59.159 - this.body = body; 59.160 + public TryNode setBody(final Block body) { 59.161 + if (this.body == body) { 59.162 + return this; 59.163 + } 59.164 + return new TryNode(this, body, catchBlocks, finallyBody); 59.165 } 59.166 59.167 /** 59.168 @@ -151,16 +157,7 @@ 59.169 for (final Block catchBlock : catchBlocks) { 59.170 catches.add((CatchNode)catchBlock.getStatements().get(0)); 59.171 } 59.172 - return catches; 59.173 - } 59.174 - 59.175 - /** 59.176 - * Returns true if the specified block is the body of this try block, or any of its catch blocks. 59.177 - * @param block the block 59.178 - * @return true if the specified block is the body of this try block, or any of its catch blocks. 59.179 - */ 59.180 - public boolean isChildBlock(Block block) { 59.181 - return body == block || catchBlocks.contains(block); 59.182 + return Collections.unmodifiableList(catches); 59.183 } 59.184 59.185 /** 59.186 @@ -174,9 +171,13 @@ 59.187 /** 59.188 * Set the catch blocks of this try 59.189 * @param catchBlocks list of catch blocks 59.190 + * @return new TryNode or same if unchanged 59.191 */ 59.192 - public void setCatchBlocks(final List<Block> catchBlocks) { 59.193 - this.catchBlocks = catchBlocks; 59.194 + public TryNode setCatchBlocks(final List<Block> catchBlocks) { 59.195 + if (this.catchBlocks == catchBlocks) { 59.196 + return this; 59.197 + } 59.198 + return new TryNode(this, body, catchBlocks, finallyBody); 59.199 } 59.200 59.201 /** 59.202 @@ -190,9 +191,11 @@ 59.203 /** 59.204 * Set the exception symbol for this try block 59.205 * @param exception a symbol for the compiler to store the exception in 59.206 + * @return new TryNode or same if unchanged 59.207 */ 59.208 - public void setException(final Symbol exception) { 59.209 + public TryNode setException(final Symbol exception) { 59.210 this.exception = exception; 59.211 + return this; 59.212 } 59.213 59.214 /** 59.215 @@ -207,9 +210,13 @@ 59.216 * If a finally block exists, the synthetic catchall needs another symbol to 59.217 * store its throwable 59.218 * @param finallyCatchAll a symbol for the finally catch all exception 59.219 + * @return new TryNode or same if unchanged 59.220 + * 59.221 + * TODO can this still be stateful? 59.222 */ 59.223 - public void setFinallyCatchAll(final Symbol finallyCatchAll) { 59.224 + public TryNode setFinallyCatchAll(final Symbol finallyCatchAll) { 59.225 this.finallyCatchAll = finallyCatchAll; 59.226 + return this; 59.227 } 59.228 59.229 /** 59.230 @@ -221,14 +228,6 @@ 59.231 } 59.232 59.233 /** 59.234 - * Set the exit label for this try block 59.235 - * @param exit label 59.236 - */ 59.237 - public void setExit(final Label exit) { 59.238 - this.exit = exit; 59.239 - } 59.240 - 59.241 - /** 59.242 * Get the body of the finally clause for this try 59.243 * @return finally body, or null if no finally 59.244 */ 59.245 @@ -239,24 +238,12 @@ 59.246 /** 59.247 * Set the finally body of this try 59.248 * @param finallyBody new finally body 59.249 + * @return new TryNode or same if unchanged 59.250 */ 59.251 - public void setFinallyBody(final Block finallyBody) { 59.252 - this.finallyBody = finallyBody; 59.253 - } 59.254 - 59.255 - /** 59.256 - * Get next try node in try chain 59.257 - * @return next try node 59.258 - */ 59.259 - public TryNode getNext() { 59.260 - return next; 59.261 - } 59.262 - 59.263 - /** 59.264 - * Set next try node in try chain 59.265 - * @param next next try node 59.266 - */ 59.267 - public void setNext(final TryNode next) { 59.268 - this.next = next; 59.269 + public TryNode setFinallyBody(final Block finallyBody) { 59.270 + if (this.finallyBody == finallyBody) { 59.271 + return this; 59.272 + } 59.273 + return new TryNode(this, body, catchBlocks, finallyBody); 59.274 } 59.275 }
60.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Fri Apr 19 18:23:00 2013 +0530 60.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Fri Apr 19 16:11:16 2013 +0200 60.3 @@ -31,6 +31,7 @@ 60.4 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; 60.5 60.6 import jdk.nashorn.internal.codegen.types.Type; 60.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 60.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 60.9 import jdk.nashorn.internal.parser.Token; 60.10 import jdk.nashorn.internal.parser.TokenType; 60.11 @@ -39,9 +40,10 @@ 60.12 /** 60.13 * UnaryNode nodes represent single operand operations. 60.14 */ 60.15 -public class UnaryNode extends Node implements Assignment<Node> { 60.16 +@Immutable 60.17 +public final class UnaryNode extends Node implements Assignment<Node> { 60.18 /** Right hand side argument. */ 60.19 - private Node rhs; 60.20 + private final Node rhs; 60.21 60.22 /** 60.23 * Constructor 60.24 @@ -51,23 +53,26 @@ 60.25 * @param rhs expression 60.26 */ 60.27 public UnaryNode(final Source source, final long token, final Node rhs) { 60.28 - super(source, token, Token.descPosition(token)); 60.29 - 60.30 - this.start = Math.min(rhs.getStart(), Token.descPosition(token)); 60.31 - this.finish = Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()); 60.32 - this.rhs = rhs; 60.33 + this(source, token, Math.min(rhs.getStart(), Token.descPosition(token)), Math.max(Token.descPosition(token) + Token.descLength(token), rhs.getFinish()), rhs); 60.34 } 60.35 60.36 /** 60.37 - * Copy constructor 60.38 - * 60.39 - * @param unaryNode source node 60.40 - * @param cs copy state 60.41 + * Constructor 60.42 + * @param source the source 60.43 + * @param token token 60.44 + * @param start start 60.45 + * @param finish finish 60.46 + * @param rhs expression 60.47 */ 60.48 - protected UnaryNode(final UnaryNode unaryNode, final CopyState cs) { 60.49 + public UnaryNode(final Source source, final long token, final int start, final int finish, final Node rhs) { 60.50 + super(source, token, start, finish); 60.51 + this.rhs = rhs; 60.52 + } 60.53 + 60.54 + 60.55 + private UnaryNode(final UnaryNode unaryNode, final Node rhs) { 60.56 super(unaryNode); 60.57 - 60.58 - this.rhs = cs.existingOrCopy(unaryNode.rhs); 60.59 + this.rhs = rhs; 60.60 } 60.61 60.62 /** 60.63 @@ -113,31 +118,13 @@ 60.64 return getAssignmentDest(); 60.65 } 60.66 60.67 - @Override 60.68 - public boolean equals(final Object other) { 60.69 - if (!super.equals(other)) { 60.70 - return false; 60.71 - } 60.72 - return rhs.equals(((UnaryNode)other).rhs()); 60.73 - } 60.74 - 60.75 - @Override 60.76 - public int hashCode() { 60.77 - return super.hashCode() ^ rhs().hashCode(); 60.78 - } 60.79 - 60.80 - @Override 60.81 - protected Node copy(final CopyState cs) { 60.82 - return new UnaryNode(this, cs); 60.83 - } 60.84 - 60.85 /** 60.86 * Assist in IR navigation. 60.87 * @param visitor IR navigating visitor. 60.88 */ 60.89 @Override 60.90 public Node accept(final NodeVisitor visitor) { 60.91 - if (visitor.enterUnaryNode(this) != null) { 60.92 + if (visitor.enterUnaryNode(this)) { 60.93 return visitor.leaveUnaryNode(setRHS(rhs.accept(visitor))); 60.94 } 60.95 60.96 @@ -219,9 +206,9 @@ 60.97 * @return a node equivalent to this one except for the requested change. 60.98 */ 60.99 public UnaryNode setRHS(final Node rhs) { 60.100 - if(this.rhs == rhs) return this; 60.101 - final UnaryNode n = (UnaryNode)clone(); 60.102 - n.rhs = rhs; 60.103 - return n; 60.104 + if (this.rhs == rhs) { 60.105 + return this; 60.106 + } 60.107 + return new UnaryNode(this, rhs); 60.108 } 60.109 }
61.1 --- a/src/jdk/nashorn/internal/ir/VarNode.java Fri Apr 19 18:23:00 2013 +0530 61.2 +++ b/src/jdk/nashorn/internal/ir/VarNode.java Fri Apr 19 16:11:16 2013 +0200 61.3 @@ -25,21 +25,31 @@ 61.4 61.5 package jdk.nashorn.internal.ir; 61.6 61.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 61.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 61.9 import jdk.nashorn.internal.runtime.Source; 61.10 61.11 /** 61.12 * Node represents a var/let declaration. 61.13 */ 61.14 -public class VarNode extends Node implements Assignment<IdentNode> { 61.15 +@Immutable 61.16 +public final class VarNode extends Node implements Assignment<IdentNode> { 61.17 /** Var name. */ 61.18 - private IdentNode name; 61.19 + private final IdentNode name; 61.20 61.21 /** Initialization expression. */ 61.22 - private Node init; 61.23 + private final Node init; 61.24 61.25 /** Is this a var statement (as opposed to a "var" in a for loop statement) */ 61.26 - private final boolean isStatement; 61.27 + private final int flags; 61.28 + 61.29 + /** Flag that determines if this function node is a statement */ 61.30 + public static final int IS_STATEMENT = 1 << 0; 61.31 + 61.32 + /** Flag that determines if this is the last function declaration in a function 61.33 + * This is used to micro optimize the placement of return value assignments for 61.34 + * a program node */ 61.35 + public static final int IS_LAST_FUNCTION_DECLARATION = 1 << 1; 61.36 61.37 /** 61.38 * Constructor 61.39 @@ -51,7 +61,14 @@ 61.40 * @param init init node or null if just a declaration 61.41 */ 61.42 public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init) { 61.43 - this(source, token, finish, name, init, true); 61.44 + this(source, token, finish, name, init, IS_STATEMENT); 61.45 + } 61.46 + 61.47 + private VarNode(final VarNode varNode, final IdentNode name, final Node init, final int flags) { 61.48 + super(varNode); 61.49 + this.name = init == null ? name : name.setIsInitializedHere(); 61.50 + this.init = init; 61.51 + this.flags = flags; 61.52 } 61.53 61.54 /** 61.55 @@ -62,28 +79,14 @@ 61.56 * @param finish finish 61.57 * @param name name of variable 61.58 * @param init init node or null if just a declaration 61.59 - * @param isStatement if this is a var statement (true), or a for-loop initializer (false) 61.60 + * @param flags flags 61.61 */ 61.62 - public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, boolean isStatement) { 61.63 + public VarNode(final Source source, final long token, final int finish, final IdentNode name, final Node init, final int flags) { 61.64 super(source, token, finish); 61.65 61.66 this.name = init == null ? name : name.setIsInitializedHere(); 61.67 this.init = init; 61.68 - this.isStatement = isStatement; 61.69 - } 61.70 - 61.71 - 61.72 - private VarNode(final VarNode varNode, final CopyState cs) { 61.73 - super(varNode); 61.74 - 61.75 - this.name = (IdentNode)cs.existingOrCopy(varNode.name); 61.76 - this.init = cs.existingOrCopy(varNode.init); 61.77 - this.isStatement = varNode.isStatement; 61.78 - } 61.79 - 61.80 - @Override 61.81 - protected Node copy(final CopyState cs) { 61.82 - return new VarNode(this, cs); 61.83 + this.flags = flags; 61.84 } 61.85 61.86 @Override 61.87 @@ -115,45 +118,17 @@ 61.88 } 61.89 61.90 /** 61.91 - * Test to see if two VarNodes are the same. 61.92 - * @param other Other VarNode. 61.93 - * @return True if the VarNodes are the same. 61.94 - */ 61.95 - @Override 61.96 - public boolean equals(final Object other) { 61.97 - if (other instanceof VarNode) { 61.98 - final VarNode otherNode = (VarNode)other; 61.99 - final boolean nameMatches = name.equals(otherNode.name); 61.100 - if (hasInit() != otherNode.hasInit()) { 61.101 - return false; 61.102 - } else if (init == null) { 61.103 - return nameMatches; 61.104 - } else { 61.105 - return nameMatches && init.equals(otherNode.init); 61.106 - } 61.107 - } 61.108 - return false; 61.109 - } 61.110 - 61.111 - @Override 61.112 - public int hashCode() { 61.113 - return name.hashCode() ^ (init == null ? 0 : init.hashCode()); 61.114 - } 61.115 - 61.116 - /** 61.117 * Assist in IR navigation. 61.118 * @param visitor IR navigating visitor. 61.119 */ 61.120 @Override 61.121 public Node accept(final NodeVisitor visitor) { 61.122 - if (visitor.enterVarNode(this) != null) { 61.123 + if (visitor.enterVarNode(this)) { 61.124 final IdentNode newName = (IdentNode)name.accept(visitor); 61.125 - final Node newInit = init == null ? null : init.accept(visitor); 61.126 - final VarNode newThis; 61.127 - if(name != newName || init != newInit) { 61.128 - newThis = (VarNode)clone(); 61.129 - newThis.init = newInit; 61.130 - newThis.name = newInit == null ? newName : newName.setIsInitializedHere(); 61.131 + final Node newInit = init == null ? null : init.accept(visitor); 61.132 + final VarNode newThis; 61.133 + if (name != newName || init != newInit) { 61.134 + newThis = new VarNode(this, newName, newInit, flags); 61.135 } else { 61.136 newThis = this; 61.137 } 61.138 @@ -187,10 +162,10 @@ 61.139 * @return a node equivalent to this one except for the requested change. 61.140 */ 61.141 public VarNode setInit(final Node init) { 61.142 - if(this.init == init) return this; 61.143 - final VarNode n = (VarNode)clone(); 61.144 - n.init = init; 61.145 - return n; 61.146 + if (this.init == init) { 61.147 + return this; 61.148 + } 61.149 + return new VarNode(this, name, init, flags); 61.150 } 61.151 61.152 /** 61.153 @@ -204,12 +179,38 @@ 61.154 /** 61.155 * Reset the identifier for this VarNode 61.156 * @param name new IdentNode representing the variable being set or declared 61.157 + * @return a node equivalent to this one except for the requested change. 61.158 */ 61.159 - private VarNode setName(final IdentNode name) { 61.160 - if(this.name == name) return this; 61.161 - final VarNode n = (VarNode)clone(); 61.162 - n.name = name; 61.163 - return n; 61.164 + public VarNode setName(final IdentNode name) { 61.165 + if (this.name == name) { 61.166 + return this; 61.167 + } 61.168 + return new VarNode(this, name, init, flags); 61.169 + } 61.170 + 61.171 + private VarNode setFlags(final int flags) { 61.172 + if (this.flags == flags) { 61.173 + return this; 61.174 + } 61.175 + return new VarNode(this, name, init, flags); 61.176 + } 61.177 + 61.178 + /** 61.179 + * Check if a flag is set for this var node 61.180 + * @param flag flag 61.181 + * @return true if flag is set 61.182 + */ 61.183 + public boolean getFlag(final int flag) { 61.184 + return (flags & flag) == flag; 61.185 + } 61.186 + 61.187 + /** 61.188 + * Set a flag for this var node 61.189 + * @param flag flag 61.190 + * @return new node if flags changed, same otherwise 61.191 + */ 61.192 + public VarNode setFlag(final int flag) { 61.193 + return setFlags(flags | flag); 61.194 } 61.195 61.196 /** 61.197 @@ -217,7 +218,7 @@ 61.198 * @return true if this is a var statement (as opposed to a var initializer in a for loop). 61.199 */ 61.200 public boolean isStatement() { 61.201 - return isStatement; 61.202 + return (flags & IS_STATEMENT) != 0; 61.203 } 61.204 61.205 /**
62.1 --- a/src/jdk/nashorn/internal/ir/WhileNode.java Fri Apr 19 18:23:00 2013 +0530 62.2 +++ b/src/jdk/nashorn/internal/ir/WhileNode.java Fri Apr 19 16:11:16 2013 +0200 62.3 @@ -25,7 +25,7 @@ 62.4 62.5 package jdk.nashorn.internal.ir; 62.6 62.7 -import jdk.nashorn.internal.codegen.Label; 62.8 +import jdk.nashorn.internal.ir.annotations.Immutable; 62.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 62.10 import jdk.nashorn.internal.runtime.Source; 62.11 62.12 @@ -33,130 +33,126 @@ 62.13 * IR representation for a WHILE statement. This is the superclass of all 62.14 * loop nodes 62.15 */ 62.16 -public class WhileNode extends BreakableNode { 62.17 - /** Test expression. */ 62.18 - protected Node test; 62.19 +@Immutable 62.20 +public final class WhileNode extends LoopNode { 62.21 62.22 - /** For body. */ 62.23 - protected Block body; 62.24 - 62.25 - /** loop continue label. */ 62.26 - protected Label continueLabel; 62.27 + /** is this a do while node ? */ 62.28 + private final boolean isDoWhile; 62.29 62.30 /** 62.31 * Constructor 62.32 * 62.33 - * @param source the source 62.34 - * @param token token 62.35 - * @param finish finish 62.36 + * @param source the source 62.37 + * @param token token 62.38 + * @param finish finish 62.39 + * @param isDoWhile is this a do while loop? 62.40 */ 62.41 - public WhileNode(final Source source, final long token, final int finish) { 62.42 - super(source, token, finish); 62.43 - 62.44 - this.breakLabel = new Label("while_break"); 62.45 - this.continueLabel = new Label("while_continue"); 62.46 + public WhileNode(final Source source, final long token, final int finish, final boolean isDoWhile) { 62.47 + super(source, token, finish, null, null, false); 62.48 + this.isDoWhile = isDoWhile; 62.49 } 62.50 62.51 /** 62.52 - * Copy constructor 62.53 + * Internal copy constructor 62.54 * 62.55 - * @param whileNode source node 62.56 - * @param cs copy state 62.57 + * @param whileNode while node 62.58 + * @param test test 62.59 + * @param body body 62.60 + * @param controlFlowEscapes control flow escapes? 62.61 */ 62.62 - protected WhileNode(final WhileNode whileNode, final CopyState cs) { 62.63 - super(whileNode); 62.64 - 62.65 - this.test = cs.existingOrCopy(whileNode.test); 62.66 - this.body = (Block)cs.existingOrCopy(whileNode.body); 62.67 - this.breakLabel = new Label(whileNode.breakLabel); 62.68 - this.continueLabel = new Label(whileNode.continueLabel); 62.69 + protected WhileNode(final WhileNode whileNode, final Node test, final Block body, final boolean controlFlowEscapes) { 62.70 + super(whileNode, test, body, controlFlowEscapes); 62.71 + this.isDoWhile = whileNode.isDoWhile; 62.72 } 62.73 62.74 @Override 62.75 - protected Node copy(final CopyState cs) { 62.76 - return new WhileNode(this, cs); 62.77 + public Node ensureUniqueLabels(final LexicalContext lc) { 62.78 + return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes)); 62.79 } 62.80 62.81 @Override 62.82 - public boolean isLoop() { 62.83 - return true; 62.84 + public boolean hasGoto() { 62.85 + return test == null; 62.86 } 62.87 62.88 - /** 62.89 - * Assist in IR navigation. 62.90 - * @param visitor IR navigating visitor. 62.91 - */ 62.92 @Override 62.93 - public Node accept(final NodeVisitor visitor) { 62.94 - if (visitor.enterWhileNode(this) != null) { 62.95 - test = test.accept(visitor); 62.96 - body = (Block)body.accept(visitor); 62.97 + protected Node accept(final LexicalContext lc, final NodeVisitor visitor) { 62.98 + if (visitor.enterWhileNode(this)) { 62.99 + if (isDoWhile()) { 62.100 + return visitor.leaveWhileNode( 62.101 + setTest(lc, test.accept(visitor)). 62.102 + setBody(lc, (Block)body.accept(visitor))); 62.103 + } 62.104 + return visitor.leaveWhileNode( 62.105 + setBody(lc, (Block)body.accept(visitor)). 62.106 + setTest(lc, test.accept(visitor))); 62.107 62.108 - return visitor.leaveWhileNode(this); 62.109 } 62.110 return this; 62.111 } 62.112 62.113 @Override 62.114 - public void toString(final StringBuilder sb) { 62.115 - sb.append("while ("); 62.116 - test.toString(sb); 62.117 - sb.append(')'); 62.118 + public Node getTest() { 62.119 + return test; 62.120 } 62.121 62.122 - /** 62.123 - * Get the loop body 62.124 - * @return body 62.125 - */ 62.126 + @Override 62.127 + public WhileNode setTest(final LexicalContext lc, final Node test) { 62.128 + if (this.test == test) { 62.129 + return this; 62.130 + } 62.131 + return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes)); 62.132 + } 62.133 + 62.134 + @Override 62.135 public Block getBody() { 62.136 return body; 62.137 } 62.138 62.139 - /** 62.140 - * Reset the loop body 62.141 - * @param body new body 62.142 - */ 62.143 - public void setBody(final Block body) { 62.144 - this.body = body; 62.145 + @Override 62.146 + public WhileNode setBody(final LexicalContext lc, final Block body) { 62.147 + if (this.body == body) { 62.148 + return this; 62.149 + } 62.150 + return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes)); 62.151 + } 62.152 + 62.153 + @Override 62.154 + public WhileNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes) { 62.155 + if (this.controlFlowEscapes == controlFlowEscapes) { 62.156 + return this; 62.157 + } 62.158 + return Node.replaceInLexicalContext(lc, this, new WhileNode(this, test, body, controlFlowEscapes)); 62.159 } 62.160 62.161 /** 62.162 - * Set the break label (described in {@link WhileNode#getBreakLabel()} for this while node 62.163 - * @param breakLabel break label 62.164 + * Check if this is a do while loop or a normal while loop 62.165 + * @return true if do while 62.166 */ 62.167 - public void setBreakLabel(final Label breakLabel) { 62.168 - this.breakLabel = breakLabel; 62.169 + public boolean isDoWhile() { 62.170 + return isDoWhile; 62.171 } 62.172 62.173 - /** 62.174 - * Get the continue label for this while node, i.e. location to go to on continue 62.175 - * @return continue label 62.176 - */ 62.177 - public Label getContinueLabel() { 62.178 - return continueLabel; 62.179 + @Override 62.180 + public void toString(final StringBuilder sb) { 62.181 + if (isDoWhile()) { 62.182 + sb.append("do {"); 62.183 + body.toString(sb); 62.184 + sb.append("} while ("); 62.185 + test.toString(sb); 62.186 + sb.append(')'); 62.187 + } else { 62.188 + sb.append("while ("); 62.189 + test.toString(sb); 62.190 + sb.append(')'); 62.191 + } 62.192 } 62.193 62.194 - /** 62.195 - * Set the continue label (described in {@link WhileNode#getContinueLabel()} for this while node 62.196 - * @param continueLabel continue label 62.197 - */ 62.198 - public void setContinueLabel(final Label continueLabel) { 62.199 - this.continueLabel = continueLabel; 62.200 - } 62.201 - 62.202 - /** 62.203 - * Get the test expression for this loop, that upon evaluation to true does another iteration 62.204 - * @return test expression 62.205 - */ 62.206 - public Node getTest() { 62.207 - return test; 62.208 - } 62.209 - 62.210 - /** 62.211 - * Set the test expression for this loop 62.212 - * @param test test expression, null if infinite loop 62.213 - */ 62.214 - public void setTest(final Node test) { 62.215 - this.test = test; 62.216 + @Override 62.217 + public boolean mustEnter() { 62.218 + if (isDoWhile()) { 62.219 + return true; 62.220 + } 62.221 + return test == null; 62.222 } 62.223 }
63.1 --- a/src/jdk/nashorn/internal/ir/WithNode.java Fri Apr 19 18:23:00 2013 +0530 63.2 +++ b/src/jdk/nashorn/internal/ir/WithNode.java Fri Apr 19 16:11:16 2013 +0200 63.3 @@ -25,18 +25,20 @@ 63.4 63.5 package jdk.nashorn.internal.ir; 63.6 63.7 +import jdk.nashorn.internal.ir.annotations.Immutable; 63.8 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 63.9 import jdk.nashorn.internal.runtime.Source; 63.10 63.11 /** 63.12 * IR representation for {@code with} statements. 63.13 */ 63.14 -public class WithNode extends Node { 63.15 +@Immutable 63.16 +public final class WithNode extends LexicalContextNode { 63.17 /** This expression. */ 63.18 - private Node expression; 63.19 + private final Node expression; 63.20 63.21 /** Statements. */ 63.22 - private Block body; 63.23 + private final Block body; 63.24 63.25 /** 63.26 * Constructor 63.27 @@ -44,42 +46,39 @@ 63.28 * @param source the source 63.29 * @param token token 63.30 * @param finish finish 63.31 - * @param expression expression in parenthesis 63.32 - * @param body with node body 63.33 */ 63.34 - public WithNode(final Source source, final long token, final int finish, final Node expression, final Block body) { 63.35 + public WithNode(final Source source, final long token, final int finish) { 63.36 super(source, token, finish); 63.37 63.38 + this.expression = null; 63.39 + this.body = null; 63.40 + } 63.41 + 63.42 + private WithNode(final WithNode node, final Node expression, final Block body) { 63.43 + super(node); 63.44 + 63.45 this.expression = expression; 63.46 this.body = body; 63.47 } 63.48 63.49 - private WithNode(final WithNode withNode, final CopyState cs) { 63.50 - super(withNode); 63.51 - 63.52 - this.expression = cs.existingOrCopy(withNode.expression); 63.53 - this.body = (Block)cs.existingOrCopy(withNode.body); 63.54 - } 63.55 - 63.56 - @Override 63.57 - protected Node copy(final CopyState cs) { 63.58 - return new WithNode(this, cs); 63.59 - } 63.60 - 63.61 /** 63.62 * Assist in IR navigation. 63.63 * 63.64 * @param visitor IR navigating visitor. 63.65 */ 63.66 @Override 63.67 - public Node accept(final NodeVisitor visitor) { 63.68 - if (visitor.enterWithNode(this) != null) { 63.69 - expression = expression.accept(visitor); 63.70 - body = (Block)body.accept(visitor); 63.71 - return visitor.leaveWithNode(this); 63.72 + public Node accept(final LexicalContext lc, final NodeVisitor visitor) { 63.73 + if (visitor.enterWithNode(this)) { 63.74 + return visitor.leaveWithNode( 63.75 + setExpression(lc, expression.accept(visitor)). 63.76 + setBody(lc, (Block)body.accept(visitor))); 63.77 } 63.78 + return this; 63.79 + } 63.80 63.81 - return this; 63.82 + @Override 63.83 + public boolean isTerminal() { 63.84 + return body.isTerminal(); 63.85 } 63.86 63.87 @Override 63.88 @@ -99,10 +98,15 @@ 63.89 63.90 /** 63.91 * Reset the body of this with node 63.92 + * @param lc lexical context 63.93 * @param body new body 63.94 + * @return new or same withnode 63.95 */ 63.96 - public void setBody(final Block body) { 63.97 - this.body = body; 63.98 + public WithNode setBody(final LexicalContext lc, final Block body) { 63.99 + if (this.body == body) { 63.100 + return this; 63.101 + } 63.102 + return Node.replaceInLexicalContext(lc, this, new WithNode(this, expression, body)); 63.103 } 63.104 63.105 /** 63.106 @@ -115,10 +119,15 @@ 63.107 63.108 /** 63.109 * Reset the expression of this with node 63.110 + * @param lc lexical context 63.111 * @param expression new expression 63.112 + * @return new or same withnode 63.113 */ 63.114 - public void setExpression(final Node expression) { 63.115 - this.expression = expression; 63.116 + public WithNode setExpression(final LexicalContext lc, final Node expression) { 63.117 + if (this.expression == expression) { 63.118 + return this; 63.119 + } 63.120 + return Node.replaceInLexicalContext(lc, this, new WithNode(this, expression, body)); 63.121 } 63.122 } 63.123
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 64.2 +++ b/src/jdk/nashorn/internal/ir/annotations/Immutable.java Fri Apr 19 16:11:16 2013 +0200 64.3 @@ -0,0 +1,34 @@ 64.4 +/* 64.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 64.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 64.7 + * 64.8 + * This code is free software; you can redistribute it and/or modify it 64.9 + * under the terms of the GNU General Public License version 2 only, as 64.10 + * published by the Free Software Foundation. Oracle designates this 64.11 + * particular file as subject to the "Classpath" exception as provided 64.12 + * by Oracle in the LICENSE file that accompanied this code. 64.13 + * 64.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 64.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 64.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 64.17 + * version 2 for more details (a copy is included in the LICENSE file that 64.18 + * accompanied this code). 64.19 + * 64.20 + * You should have received a copy of the GNU General Public License version 64.21 + * 2 along with this work; if not, write to the Free Software Foundation, 64.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 64.23 + * 64.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 64.25 + * or visit www.oracle.com if you need additional information or have any 64.26 + * questions. 64.27 + */ 64.28 + 64.29 +package jdk.nashorn.internal.ir.annotations; 64.30 + 64.31 +/** 64.32 + * Tag for nodes that are immutable. To be immutable all fields must be 64.33 + * final and copy on write semantics must be in place 64.34 + */ 64.35 +public @interface Immutable { 64.36 + //empty 64.37 +}
65.1 --- a/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Fri Apr 19 18:23:00 2013 +0530 65.2 +++ b/src/jdk/nashorn/internal/ir/debug/ASTWriter.java Fri Apr 19 16:11:16 2013 +0200 65.3 @@ -33,7 +33,9 @@ 65.4 import java.util.Iterator; 65.5 import java.util.LinkedList; 65.6 import java.util.List; 65.7 + 65.8 import jdk.nashorn.internal.ir.BinaryNode; 65.9 +import jdk.nashorn.internal.ir.Block; 65.10 import jdk.nashorn.internal.ir.Node; 65.11 import jdk.nashorn.internal.ir.TernaryNode; 65.12 import jdk.nashorn.internal.ir.annotations.Ignore; 65.13 @@ -113,6 +115,10 @@ 65.14 type += "#" + node.getSymbol(); 65.15 } 65.16 65.17 + if (node instanceof Block && ((Block)node).needsScope()) { 65.18 + type += " <scope>"; 65.19 + } 65.20 + 65.21 final List<Field> children = new LinkedList<>(); 65.22 65.23 if (!isReference) { 65.24 @@ -121,10 +127,6 @@ 65.25 65.26 String status = ""; 65.27 65.28 - if (node.shouldDiscard()) { 65.29 - status += " Discard"; 65.30 - } 65.31 - 65.32 if (node.isTerminal()) { 65.33 status += " Terminal"; 65.34 }
66.1 --- a/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Fri Apr 19 18:23:00 2013 +0530 66.2 +++ b/src/jdk/nashorn/internal/ir/debug/JSONWriter.java Fri Apr 19 16:11:16 2013 +0200 66.3 @@ -36,7 +36,6 @@ 66.4 import jdk.nashorn.internal.ir.CaseNode; 66.5 import jdk.nashorn.internal.ir.CatchNode; 66.6 import jdk.nashorn.internal.ir.ContinueNode; 66.7 -import jdk.nashorn.internal.ir.DoWhileNode; 66.8 import jdk.nashorn.internal.ir.EmptyNode; 66.9 import jdk.nashorn.internal.ir.ExecuteNode; 66.10 import jdk.nashorn.internal.ir.ForNode; 66.11 @@ -88,7 +87,7 @@ 66.12 final Parser parser = new Parser(env, new Source(name, code), new Context.ThrowErrorManager(), env._strict); 66.13 final JSONWriter jsonWriter = new JSONWriter(includeLoc); 66.14 try { 66.15 - final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.tag()); 66.16 + final FunctionNode functionNode = parser.parse(CompilerConstants.RUN_SCRIPT.symbolName()); 66.17 functionNode.accept(jsonWriter); 66.18 return jsonWriter.getString(); 66.19 } catch (final ParserException e) { 66.20 @@ -98,11 +97,16 @@ 66.21 } 66.22 66.23 @Override 66.24 - protected Node enterDefault(final Node node) { 66.25 + protected boolean enterDefault(final Node node) { 66.26 objectStart(); 66.27 location(node); 66.28 66.29 - return node; 66.30 + return true; 66.31 + } 66.32 + 66.33 + private boolean leave() { 66.34 + objectEnd(); 66.35 + return false; 66.36 } 66.37 66.38 @Override 66.39 @@ -112,7 +116,7 @@ 66.40 } 66.41 66.42 @Override 66.43 - public Node enterAccessNode(final AccessNode accessNode) { 66.44 + public boolean enterAccessNode(final AccessNode accessNode) { 66.45 enterDefault(accessNode); 66.46 66.47 type("MemberExpression"); 66.48 @@ -128,11 +132,11 @@ 66.49 66.50 property("computed", false); 66.51 66.52 - return leaveDefault(accessNode); 66.53 + return leave(); 66.54 } 66.55 66.56 @Override 66.57 - public Node enterBlock(final Block block) { 66.58 + public boolean enterBlock(final Block block) { 66.59 enterDefault(block); 66.60 66.61 type("BlockStatement"); 66.62 @@ -140,21 +144,21 @@ 66.63 66.64 array("body", block.getStatements()); 66.65 66.66 - return leaveDefault(block); 66.67 + return leave(); 66.68 } 66.69 66.70 private static boolean isLogical(final TokenType tt) { 66.71 switch (tt) { 66.72 - case AND: 66.73 - case OR: 66.74 - return true; 66.75 - default: 66.76 - return false; 66.77 + case AND: 66.78 + case OR: 66.79 + return true; 66.80 + default: 66.81 + return false; 66.82 } 66.83 } 66.84 66.85 @Override 66.86 - public Node enterBinaryNode(final BinaryNode binaryNode) { 66.87 + public boolean enterBinaryNode(final BinaryNode binaryNode) { 66.88 enterDefault(binaryNode); 66.89 66.90 final String name; 66.91 @@ -179,29 +183,29 @@ 66.92 property("right"); 66.93 binaryNode.rhs().accept(this); 66.94 66.95 - return leaveDefault(binaryNode); 66.96 + return leave(); 66.97 } 66.98 66.99 @Override 66.100 - public Node enterBreakNode(final BreakNode breakNode) { 66.101 + public boolean enterBreakNode(final BreakNode breakNode) { 66.102 enterDefault(breakNode); 66.103 66.104 type("BreakStatement"); 66.105 comma(); 66.106 66.107 - final LabelNode label = breakNode.getLabel(); 66.108 + final IdentNode label = breakNode.getLabel(); 66.109 if (label != null) { 66.110 - property("label", label.getLabel().getName()); 66.111 + property("label", label.getName()); 66.112 } else { 66.113 property("label"); 66.114 nullValue(); 66.115 } 66.116 66.117 - return leaveDefault(breakNode); 66.118 + return leave(); 66.119 } 66.120 66.121 @Override 66.122 - public Node enterCallNode(final CallNode callNode) { 66.123 + public boolean enterCallNode(final CallNode callNode) { 66.124 enterDefault(callNode); 66.125 66.126 type("CallExpression"); 66.127 @@ -213,11 +217,11 @@ 66.128 66.129 array("arguments", callNode.getArgs()); 66.130 66.131 - return leaveDefault(callNode); 66.132 + return leave(); 66.133 } 66.134 66.135 @Override 66.136 - public Node enterCaseNode(final CaseNode caseNode) { 66.137 + public boolean enterCaseNode(final CaseNode caseNode) { 66.138 enterDefault(caseNode); 66.139 66.140 type("SwitchCase"); 66.141 @@ -234,11 +238,11 @@ 66.142 66.143 array("consequent", caseNode.getBody().getStatements()); 66.144 66.145 - return leaveDefault(caseNode); 66.146 + return leave(); 66.147 } 66.148 66.149 @Override 66.150 - public Node enterCatchNode(final CatchNode catchNode) { 66.151 + public boolean enterCatchNode(final CatchNode catchNode) { 66.152 enterDefault(catchNode); 66.153 66.154 type("CatchClause"); 66.155 @@ -260,55 +264,38 @@ 66.156 property("body"); 66.157 catchNode.getBody().accept(this); 66.158 66.159 - return leaveDefault(catchNode); 66.160 + return leave(); 66.161 } 66.162 66.163 @Override 66.164 - public Node enterContinueNode(final ContinueNode continueNode) { 66.165 + public boolean enterContinueNode(final ContinueNode continueNode) { 66.166 enterDefault(continueNode); 66.167 66.168 type("ContinueStatement"); 66.169 comma(); 66.170 66.171 - final LabelNode label = continueNode.getLabel(); 66.172 + final IdentNode label = continueNode.getLabel(); 66.173 if (label != null) { 66.174 - property("label", label.getLabel().getName()); 66.175 + property("label", label.getName()); 66.176 } else { 66.177 property("label"); 66.178 nullValue(); 66.179 } 66.180 66.181 - return leaveDefault(continueNode); 66.182 + return leave(); 66.183 } 66.184 66.185 @Override 66.186 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 66.187 - enterDefault(doWhileNode); 66.188 - 66.189 - type("DoWhileStatement"); 66.190 - comma(); 66.191 - 66.192 - property("body"); 66.193 - doWhileNode.getBody().accept(this); 66.194 - comma(); 66.195 - 66.196 - property("test"); 66.197 - doWhileNode.getTest().accept(this); 66.198 - 66.199 - return leaveDefault(doWhileNode); 66.200 - } 66.201 - 66.202 - @Override 66.203 - public Node enterEmptyNode(final EmptyNode emptyNode) { 66.204 + public boolean enterEmptyNode(final EmptyNode emptyNode) { 66.205 enterDefault(emptyNode); 66.206 66.207 type("EmptyStatement"); 66.208 66.209 - return leaveDefault(emptyNode); 66.210 + return leave(); 66.211 } 66.212 66.213 @Override 66.214 - public Node enterExecuteNode(final ExecuteNode executeNode) { 66.215 + public boolean enterExecuteNode(final ExecuteNode executeNode) { 66.216 enterDefault(executeNode); 66.217 66.218 type("ExpressionStatement"); 66.219 @@ -317,11 +304,11 @@ 66.220 property("expression"); 66.221 executeNode.getExpression().accept(this); 66.222 66.223 - return leaveDefault(executeNode); 66.224 + return leave(); 66.225 } 66.226 66.227 @Override 66.228 - public Node enterForNode(final ForNode forNode) { 66.229 + public boolean enterForNode(final ForNode forNode) { 66.230 enterDefault(forNode); 66.231 66.232 if (forNode.isForIn() || (forNode.isForEach() && forNode.getInit() != null)) { 66.233 @@ -380,11 +367,11 @@ 66.234 forNode.getBody().accept(this); 66.235 } 66.236 66.237 - return leaveDefault(forNode); 66.238 + return leave(); 66.239 } 66.240 66.241 @Override 66.242 - public Node enterFunctionNode(final FunctionNode functionNode) { 66.243 + public boolean enterFunctionNode(final FunctionNode functionNode) { 66.244 enterDefault(functionNode); 66.245 66.246 final boolean program = functionNode.isProgram(); 66.247 @@ -419,7 +406,7 @@ 66.248 } 66.249 66.250 // body consists of nested functions and statements 66.251 - final List<Node> stats = functionNode.getStatements(); 66.252 + final List<Node> stats = functionNode.getBody().getStatements(); 66.253 final int size = stats.size(); 66.254 int idx = 0; 66.255 arrayStart("body"); 66.256 @@ -435,11 +422,11 @@ 66.257 } 66.258 arrayEnd(); 66.259 66.260 - return leaveDefault(functionNode); 66.261 + return leave(); 66.262 } 66.263 66.264 @Override 66.265 - public Node enterIdentNode(final IdentNode identNode) { 66.266 + public boolean enterIdentNode(final IdentNode identNode) { 66.267 enterDefault(identNode); 66.268 66.269 final String name = identNode.getName(); 66.270 @@ -451,11 +438,11 @@ 66.271 property("name", identNode.getName()); 66.272 } 66.273 66.274 - return leaveDefault(identNode); 66.275 + return leave(); 66.276 } 66.277 66.278 @Override 66.279 - public Node enterIfNode(final IfNode ifNode) { 66.280 + public boolean enterIfNode(final IfNode ifNode) { 66.281 enterDefault(ifNode); 66.282 66.283 type("IfStatement"); 66.284 @@ -477,11 +464,11 @@ 66.285 nullValue(); 66.286 } 66.287 66.288 - return leaveDefault(ifNode); 66.289 + return leave(); 66.290 } 66.291 66.292 @Override 66.293 - public Node enterIndexNode(final IndexNode indexNode) { 66.294 + public boolean enterIndexNode(final IndexNode indexNode) { 66.295 enterDefault(indexNode); 66.296 66.297 type("MemberExpression"); 66.298 @@ -497,11 +484,11 @@ 66.299 66.300 property("computed", true); 66.301 66.302 - return leaveDefault(indexNode); 66.303 + return leave(); 66.304 } 66.305 66.306 @Override 66.307 - public Node enterLabelNode(final LabelNode labelNode) { 66.308 + public boolean enterLabelNode(final LabelNode labelNode) { 66.309 enterDefault(labelNode); 66.310 66.311 type("LabeledStatement"); 66.312 @@ -514,17 +501,17 @@ 66.313 property("body"); 66.314 labelNode.getBody().accept(this); 66.315 66.316 - return leaveDefault(labelNode); 66.317 + return leave(); 66.318 } 66.319 66.320 @Override 66.321 - public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 66.322 - return null; 66.323 + public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { 66.324 + return false; 66.325 } 66.326 66.327 @SuppressWarnings("rawtypes") 66.328 @Override 66.329 - public Node enterLiteralNode(final LiteralNode literalNode) { 66.330 + public boolean enterLiteralNode(final LiteralNode literalNode) { 66.331 enterDefault(literalNode); 66.332 66.333 if (literalNode instanceof LiteralNode.ArrayLiteralNode) { 66.334 @@ -556,11 +543,11 @@ 66.335 } 66.336 } 66.337 66.338 - return leaveDefault(literalNode); 66.339 + return leave(); 66.340 } 66.341 66.342 @Override 66.343 - public Node enterObjectNode(final ObjectNode objectNode) { 66.344 + public boolean enterObjectNode(final ObjectNode objectNode) { 66.345 enterDefault(objectNode); 66.346 66.347 type("ObjectExpression"); 66.348 @@ -568,11 +555,11 @@ 66.349 66.350 array("properties", objectNode.getElements()); 66.351 66.352 - return leaveDefault(objectNode); 66.353 + return leave(); 66.354 } 66.355 66.356 @Override 66.357 - public Node enterPropertyNode(final PropertyNode propertyNode) { 66.358 + public boolean enterPropertyNode(final PropertyNode propertyNode) { 66.359 final Node key = propertyNode.getKey(); 66.360 66.361 final Node value = propertyNode.getValue(); 66.362 @@ -634,11 +621,11 @@ 66.363 } 66.364 } 66.365 66.366 - return null; 66.367 + return false; 66.368 } 66.369 66.370 @Override 66.371 - public Node enterReturnNode(final ReturnNode returnNode) { 66.372 + public boolean enterReturnNode(final ReturnNode returnNode) { 66.373 enterDefault(returnNode); 66.374 66.375 type("ReturnStatement"); 66.376 @@ -652,31 +639,29 @@ 66.377 nullValue(); 66.378 } 66.379 66.380 - return leaveDefault(returnNode); 66.381 + return leave(); 66.382 } 66.383 66.384 @Override 66.385 - public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 66.386 + public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 66.387 final RuntimeNode.Request req = runtimeNode.getRequest(); 66.388 66.389 if (req == RuntimeNode.Request.DEBUGGER) { 66.390 enterDefault(runtimeNode); 66.391 - 66.392 type("DebuggerStatement"); 66.393 - 66.394 - return leaveDefault(runtimeNode); 66.395 + return leave(); 66.396 } 66.397 66.398 - return null; 66.399 + return false; 66.400 } 66.401 66.402 @Override 66.403 - public Node enterSplitNode(final SplitNode splitNode) { 66.404 - return null; 66.405 + public boolean enterSplitNode(final SplitNode splitNode) { 66.406 + return false; 66.407 } 66.408 66.409 @Override 66.410 - public Node enterSwitchNode(final SwitchNode switchNode) { 66.411 + public boolean enterSwitchNode(final SwitchNode switchNode) { 66.412 enterDefault(switchNode); 66.413 66.414 type("SwitchStatement"); 66.415 @@ -688,11 +673,11 @@ 66.416 66.417 array("cases", switchNode.getCases()); 66.418 66.419 - return leaveDefault(switchNode); 66.420 + return leave(); 66.421 } 66.422 66.423 @Override 66.424 - public Node enterTernaryNode(final TernaryNode ternaryNode) { 66.425 + public boolean enterTernaryNode(final TernaryNode ternaryNode) { 66.426 enterDefault(ternaryNode); 66.427 66.428 type("ConditionalExpression"); 66.429 @@ -709,11 +694,11 @@ 66.430 property("alternate"); 66.431 ternaryNode.third().accept(this); 66.432 66.433 - return leaveDefault(ternaryNode); 66.434 + return leave(); 66.435 } 66.436 66.437 @Override 66.438 - public Node enterThrowNode(final ThrowNode throwNode) { 66.439 + public boolean enterThrowNode(final ThrowNode throwNode) { 66.440 enterDefault(throwNode); 66.441 66.442 type("ThrowStatement"); 66.443 @@ -722,11 +707,11 @@ 66.444 property("argument"); 66.445 throwNode.getExpression().accept(this); 66.446 66.447 - return leaveDefault(throwNode); 66.448 + return leave(); 66.449 } 66.450 66.451 @Override 66.452 - public Node enterTryNode(final TryNode tryNode) { 66.453 + public boolean enterTryNode(final TryNode tryNode) { 66.454 enterDefault(tryNode); 66.455 66.456 type("TryStatement"); 66.457 @@ -747,11 +732,11 @@ 66.458 nullValue(); 66.459 } 66.460 66.461 - return leaveDefault(tryNode); 66.462 + return leave(); 66.463 } 66.464 66.465 @Override 66.466 - public Node enterUnaryNode(final UnaryNode unaryNode) { 66.467 + public boolean enterUnaryNode(final UnaryNode unaryNode) { 66.468 enterDefault(unaryNode); 66.469 66.470 final TokenType tokenType = unaryNode.tokenType(); 66.471 @@ -769,25 +754,25 @@ 66.472 final boolean prefix; 66.473 final String operator; 66.474 switch (tokenType) { 66.475 - case INCPOSTFIX: 66.476 - prefix = false; 66.477 - operator = "++"; 66.478 - break; 66.479 - case DECPOSTFIX: 66.480 - prefix = false; 66.481 - operator = "--"; 66.482 - break; 66.483 - case INCPREFIX: 66.484 - operator = "++"; 66.485 - prefix = true; 66.486 - break; 66.487 - case DECPREFIX: 66.488 - operator = "--"; 66.489 - prefix = true; 66.490 - break; 66.491 - default: 66.492 - prefix = false; 66.493 - operator = tokenType.getName(); 66.494 + case INCPOSTFIX: 66.495 + prefix = false; 66.496 + operator = "++"; 66.497 + break; 66.498 + case DECPOSTFIX: 66.499 + prefix = false; 66.500 + operator = "--"; 66.501 + break; 66.502 + case INCPREFIX: 66.503 + operator = "++"; 66.504 + prefix = true; 66.505 + break; 66.506 + case DECPREFIX: 66.507 + operator = "--"; 66.508 + prefix = true; 66.509 + break; 66.510 + default: 66.511 + prefix = false; 66.512 + operator = tokenType.getName(); 66.513 } 66.514 66.515 type(unaryNode.isAssignment()? "UpdateExpression" : "UnaryExpression"); 66.516 @@ -803,11 +788,11 @@ 66.517 unaryNode.rhs().accept(this); 66.518 } 66.519 66.520 - return leaveDefault(unaryNode); 66.521 + return leave(); 66.522 } 66.523 66.524 @Override 66.525 - public Node enterVarNode(final VarNode varNode) { 66.526 + public boolean enterVarNode(final VarNode varNode) { 66.527 enterDefault(varNode); 66.528 66.529 type("VariableDeclaration"); 66.530 @@ -839,28 +824,37 @@ 66.531 // declarations 66.532 arrayEnd(); 66.533 66.534 - return leaveDefault(varNode); 66.535 + return leave(); 66.536 } 66.537 66.538 @Override 66.539 - public Node enterWhileNode(final WhileNode whileNode) { 66.540 + public boolean enterWhileNode(final WhileNode whileNode) { 66.541 enterDefault(whileNode); 66.542 66.543 - type("WhileStatement"); 66.544 + type(whileNode.isDoWhile() ? "DoWhileStatement" : "WhileStatement"); 66.545 comma(); 66.546 66.547 - property("test"); 66.548 - whileNode.getTest().accept(this); 66.549 - comma(); 66.550 + if (whileNode.isDoWhile()) { 66.551 + property("body"); 66.552 + whileNode.getBody().accept(this); 66.553 + comma(); 66.554 66.555 - property("block"); 66.556 - whileNode.getBody().accept(this); 66.557 + property("test"); 66.558 + whileNode.getTest().accept(this); 66.559 + } else { 66.560 + property("test"); 66.561 + whileNode.getTest().accept(this); 66.562 + comma(); 66.563 66.564 - return leaveDefault(whileNode); 66.565 + property("block"); 66.566 + whileNode.getBody().accept(this); 66.567 + } 66.568 + 66.569 + return leave(); 66.570 } 66.571 66.572 @Override 66.573 - public Node enterWithNode(final WithNode withNode) { 66.574 + public boolean enterWithNode(final WithNode withNode) { 66.575 enterDefault(withNode); 66.576 66.577 type("WithStatement"); 66.578 @@ -873,8 +867,8 @@ 66.579 property("body"); 66.580 withNode.getBody().accept(this); 66.581 66.582 - return leaveDefault(withNode); 66.583 - } 66.584 + return leave(); 66.585 + } 66.586 66.587 // Internals below 66.588
67.1 --- a/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Fri Apr 19 18:23:00 2013 +0530 67.2 +++ b/src/jdk/nashorn/internal/ir/debug/PrintVisitor.java Fri Apr 19 16:11:16 2013 +0200 67.3 @@ -26,30 +26,22 @@ 67.4 package jdk.nashorn.internal.ir.debug; 67.5 67.6 import java.util.List; 67.7 -import jdk.nashorn.internal.ir.AccessNode; 67.8 + 67.9 +import jdk.nashorn.internal.ir.BinaryNode; 67.10 import jdk.nashorn.internal.ir.Block; 67.11 -import jdk.nashorn.internal.ir.BreakNode; 67.12 -import jdk.nashorn.internal.ir.CallNode; 67.13 import jdk.nashorn.internal.ir.CaseNode; 67.14 import jdk.nashorn.internal.ir.CatchNode; 67.15 -import jdk.nashorn.internal.ir.ContinueNode; 67.16 -import jdk.nashorn.internal.ir.DoWhileNode; 67.17 import jdk.nashorn.internal.ir.ExecuteNode; 67.18 import jdk.nashorn.internal.ir.ForNode; 67.19 import jdk.nashorn.internal.ir.FunctionNode; 67.20 import jdk.nashorn.internal.ir.IfNode; 67.21 -import jdk.nashorn.internal.ir.IndexNode; 67.22 import jdk.nashorn.internal.ir.LabelNode; 67.23 import jdk.nashorn.internal.ir.LineNumberNode; 67.24 import jdk.nashorn.internal.ir.Node; 67.25 -import jdk.nashorn.internal.ir.ReturnNode; 67.26 -import jdk.nashorn.internal.ir.RuntimeNode; 67.27 import jdk.nashorn.internal.ir.SplitNode; 67.28 import jdk.nashorn.internal.ir.SwitchNode; 67.29 import jdk.nashorn.internal.ir.Symbol; 67.30 -import jdk.nashorn.internal.ir.ThrowNode; 67.31 import jdk.nashorn.internal.ir.TryNode; 67.32 -import jdk.nashorn.internal.ir.UnaryNode; 67.33 import jdk.nashorn.internal.ir.VarNode; 67.34 import jdk.nashorn.internal.ir.WhileNode; 67.35 import jdk.nashorn.internal.ir.WithNode; 67.36 @@ -136,21 +128,20 @@ 67.37 /* 67.38 * Visits. 67.39 */ 67.40 + 67.41 @Override 67.42 - public Node enterAccessNode(final AccessNode accessNode) { 67.43 - accessNode.toString(sb); 67.44 - return null; 67.45 + public boolean enterDefault(final Node node) { 67.46 + node.toString(sb); 67.47 + return false; 67.48 } 67.49 67.50 @Override 67.51 - public Node enterBlock(final Block block) { 67.52 + public boolean enterBlock(final Block block) { 67.53 sb.append(' '); 67.54 sb.append('{'); 67.55 67.56 indent += TABWIDTH; 67.57 67.58 - final boolean isFunction = block instanceof FunctionNode; 67.59 - 67.60 final List<Node> statements = block.getStatements(); 67.61 67.62 boolean lastLineNumber = false; 67.63 @@ -161,14 +152,14 @@ 67.64 indent(); 67.65 } 67.66 67.67 - if (statement instanceof UnaryNode) { 67.68 - statement.toString(sb); 67.69 - } else { 67.70 - statement.accept(this); 67.71 - } 67.72 + statement.accept(this); 67.73 67.74 lastLineNumber = statement instanceof LineNumberNode; 67.75 67.76 + if (statement instanceof FunctionNode) { 67.77 + continue; 67.78 + } 67.79 + 67.80 final Symbol symbol = statement.getSymbol(); 67.81 67.82 if (symbol != null) { 67.83 @@ -200,72 +191,42 @@ 67.84 indent(); 67.85 sb.append("}"); 67.86 67.87 - if (isFunction) { 67.88 - sb.append(EOLN); 67.89 - } 67.90 - 67.91 - return null; 67.92 + return false; 67.93 } 67.94 67.95 @Override 67.96 - public Node enterBreakNode(final BreakNode breakNode) { 67.97 - breakNode.toString(sb); 67.98 - return null; 67.99 + public boolean enterBinaryNode(final BinaryNode binaryNode) { 67.100 + binaryNode.lhs().accept(this); 67.101 + sb.append(' '); 67.102 + sb.append(binaryNode.tokenType()); 67.103 + sb.append(' '); 67.104 + binaryNode.rhs().accept(this); 67.105 + return false; 67.106 } 67.107 67.108 @Override 67.109 - public Node enterCallNode(final CallNode callNode) { 67.110 - callNode.toString(sb); 67.111 - return null; 67.112 + public boolean enterExecuteNode(final ExecuteNode executeNode) { 67.113 + executeNode.getExpression().accept(this); 67.114 + return false; 67.115 } 67.116 67.117 @Override 67.118 - public Node enterContinueNode(final ContinueNode continueNode) { 67.119 - continueNode.toString(sb); 67.120 - return null; 67.121 + public boolean enterForNode(final ForNode forNode) { 67.122 + forNode.toString(sb); 67.123 + forNode.getBody().accept(this); 67.124 + return false; 67.125 } 67.126 67.127 @Override 67.128 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 67.129 - sb.append("do"); 67.130 - doWhileNode.getBody().accept(this); 67.131 - sb.append(' '); 67.132 - doWhileNode.toString(sb); 67.133 - 67.134 - return null; 67.135 + public boolean enterFunctionNode(final FunctionNode functionNode) { 67.136 + functionNode.toString(sb); 67.137 + enterBlock(functionNode.getBody()); 67.138 + sb.append(EOLN); 67.139 + return false; 67.140 } 67.141 67.142 @Override 67.143 - public Node enterExecuteNode(final ExecuteNode executeNode) { 67.144 - final Node expression = executeNode.getExpression(); 67.145 - 67.146 - if (expression instanceof UnaryNode) { 67.147 - expression.toString(sb); 67.148 - } else { 67.149 - expression.accept(this); 67.150 - } 67.151 - 67.152 - return null; 67.153 - } 67.154 - 67.155 - @Override 67.156 - public Node enterForNode(final ForNode forNode) { 67.157 - forNode.toString(sb); 67.158 - forNode.getBody().accept(this); 67.159 - 67.160 - return null; 67.161 - } 67.162 - 67.163 - @Override 67.164 - public Node enterFunctionNode(final FunctionNode functionNode) { 67.165 - functionNode.toString(sb); 67.166 - enterBlock(functionNode); 67.167 - 67.168 - return null; 67.169 - } 67.170 - 67.171 - @Override 67.172 - public Node enterIfNode(final IfNode ifNode) { 67.173 + public boolean enterIfNode(final IfNode ifNode) { 67.174 ifNode.toString(sb); 67.175 ifNode.getPass().accept(this); 67.176 67.177 @@ -276,55 +237,36 @@ 67.178 fail.accept(this); 67.179 } 67.180 67.181 - return null; 67.182 + return false; 67.183 } 67.184 67.185 @Override 67.186 - public Node enterIndexNode(final IndexNode indexNode) { 67.187 - indexNode.toString(sb); 67.188 - return null; 67.189 - } 67.190 - 67.191 - @Override 67.192 - public Node enterLabelNode(final LabelNode labeledNode) { 67.193 + public boolean enterLabelNode(final LabelNode labeledNode) { 67.194 indent -= TABWIDTH; 67.195 indent(); 67.196 indent += TABWIDTH; 67.197 labeledNode.toString(sb); 67.198 labeledNode.getBody().accept(this); 67.199 67.200 - return null; 67.201 + return false; 67.202 } 67.203 67.204 @Override 67.205 - public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 67.206 + public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { 67.207 if (printLineNumbers) { 67.208 lineNumberNode.toString(sb); 67.209 } 67.210 67.211 - return null; 67.212 - } 67.213 - 67.214 - 67.215 - @Override 67.216 - public Node enterReturnNode(final ReturnNode returnNode) { 67.217 - returnNode.toString(sb); 67.218 - return null; 67.219 + return false; 67.220 } 67.221 67.222 @Override 67.223 - public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 67.224 - runtimeNode.toString(sb); 67.225 - return null; 67.226 - } 67.227 - 67.228 - @Override 67.229 - public Node enterSplitNode(final SplitNode splitNode) { 67.230 + public boolean enterSplitNode(final SplitNode splitNode) { 67.231 splitNode.toString(sb); 67.232 sb.append(EOLN); 67.233 indent += TABWIDTH; 67.234 indent(); 67.235 - return splitNode; 67.236 + return true; 67.237 } 67.238 67.239 @Override 67.240 @@ -337,7 +279,7 @@ 67.241 } 67.242 67.243 @Override 67.244 - public Node enterSwitchNode(final SwitchNode switchNode) { 67.245 + public boolean enterSwitchNode(final SwitchNode switchNode) { 67.246 switchNode.toString(sb); 67.247 sb.append(" {"); 67.248 67.249 @@ -357,24 +299,18 @@ 67.250 indent(); 67.251 sb.append("}"); 67.252 67.253 - return null; 67.254 - } 67.255 - 67.256 - @Override 67.257 - public Node enterThrowNode(final ThrowNode throwNode) { 67.258 - throwNode.toString(sb); 67.259 - return null; 67.260 + return false; 67.261 } 67.262 67.263 @Override 67.264 - public Node enterTryNode(final TryNode tryNode) { 67.265 + public boolean enterTryNode(final TryNode tryNode) { 67.266 tryNode.toString(sb); 67.267 tryNode.getBody().accept(this); 67.268 67.269 final List<Block> catchBlocks = tryNode.getCatchBlocks(); 67.270 67.271 for (final Block catchBlock : catchBlocks) { 67.272 - final CatchNode catchNode = (CatchNode) catchBlock.getStatements().get(0); 67.273 + final CatchNode catchNode = (CatchNode)catchBlock.getStatements().get(0); 67.274 catchNode.toString(sb); 67.275 catchNode.getBody().accept(this); 67.276 } 67.277 @@ -386,35 +322,42 @@ 67.278 finallyBody.accept(this); 67.279 } 67.280 67.281 - return null; 67.282 + return false; 67.283 } 67.284 67.285 @Override 67.286 - public Node enterVarNode(final VarNode varNode) { 67.287 + public boolean enterVarNode(final VarNode varNode) { 67.288 sb.append("var "); 67.289 varNode.getName().toString(sb); 67.290 final Node init = varNode.getInit(); 67.291 - if(init != null) { 67.292 + if (init != null) { 67.293 sb.append(" = "); 67.294 init.accept(this); 67.295 } 67.296 - return null; 67.297 + return false; 67.298 } 67.299 67.300 @Override 67.301 - public Node enterWhileNode(final WhileNode whileNode) { 67.302 - whileNode.toString(sb); 67.303 - whileNode.getBody().accept(this); 67.304 + public boolean enterWhileNode(final WhileNode whileNode) { 67.305 + if (whileNode.isDoWhile()) { 67.306 + sb.append("do"); 67.307 + whileNode.getBody().accept(this); 67.308 + sb.append(' '); 67.309 + whileNode.toString(sb); 67.310 + } else { 67.311 + whileNode.toString(sb); 67.312 + whileNode.getBody().accept(this); 67.313 + } 67.314 67.315 - return null; 67.316 + return false; 67.317 } 67.318 67.319 @Override 67.320 - public Node enterWithNode(final WithNode withNode) { 67.321 + public boolean enterWithNode(final WithNode withNode) { 67.322 withNode.toString(sb); 67.323 withNode.getBody().accept(this); 67.324 67.325 - return null; 67.326 + return false; 67.327 } 67.328 67.329 }
68.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Fri Apr 19 18:23:00 2013 +0530 68.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Fri Apr 19 16:11:16 2013 +0200 68.3 @@ -25,9 +25,8 @@ 68.4 68.5 package jdk.nashorn.internal.ir.visitor; 68.6 68.7 -import jdk.nashorn.internal.codegen.CompileUnit; 68.8 -import jdk.nashorn.internal.codegen.MethodEmitter; 68.9 import jdk.nashorn.internal.ir.BinaryNode; 68.10 +import jdk.nashorn.internal.ir.LexicalContext; 68.11 import jdk.nashorn.internal.ir.Node; 68.12 import jdk.nashorn.internal.ir.UnaryNode; 68.13 68.14 @@ -45,15 +44,14 @@ 68.15 /** 68.16 * Constructor 68.17 * 68.18 - * @param compileUnit compile unit 68.19 - * @param method method emitter 68.20 + * @param lc a custom lexical context 68.21 */ 68.22 - public NodeOperatorVisitor(final CompileUnit compileUnit, final MethodEmitter method) { 68.23 - super(compileUnit, method); 68.24 + public NodeOperatorVisitor(final LexicalContext lc) { 68.25 + super(lc); 68.26 } 68.27 68.28 @Override 68.29 - public final Node enterUnaryNode(final UnaryNode unaryNode) { 68.30 + public final boolean enterUnaryNode(final UnaryNode unaryNode) { 68.31 switch (unaryNode.tokenType()) { 68.32 case ADD: 68.33 return enterADD(unaryNode); 68.34 @@ -119,7 +117,7 @@ 68.35 } 68.36 68.37 @Override 68.38 - public final Node enterBinaryNode(final BinaryNode binaryNode) { 68.39 + public final boolean enterBinaryNode(final BinaryNode binaryNode) { 68.40 switch (binaryNode.tokenType()) { 68.41 case ADD: 68.42 return enterADD(binaryNode); 68.43 @@ -287,17 +285,6 @@ 68.44 } 68.45 68.46 /* 68.47 - @Override 68.48 - public Node enter(final TernaryNode ternaryNode) { 68.49 - return enterDefault(ternaryNode); 68.50 - } 68.51 - 68.52 - @Override 68.53 - public Node leave(final TernaryNode ternaryNode) { 68.54 - return leaveDefault(ternaryNode); 68.55 - }*/ 68.56 - 68.57 - /* 68.58 * Unary entries and exists. 68.59 */ 68.60 68.61 @@ -305,9 +292,9 @@ 68.62 * Unary enter - callback for entering a unary + 68.63 * 68.64 * @param unaryNode the node 68.65 - * @return processed node 68.66 + * @return true if traversal should continue and node children be traversed, false otherwise 68.67 */ 68.68 - public Node enterADD(final UnaryNode unaryNode) { 68.69 + public boolean enterADD(final UnaryNode unaryNode) { 68.70 return enterDefault(unaryNode); 68.71 } 68.72 68.73 @@ -325,9 +312,9 @@ 68.74 * Unary enter - callback for entering a ~ operator 68.75 * 68.76 * @param unaryNode the node 68.77 - * @return processed node 68.78 + * @return true if traversal should continue and node children be traversed, false otherwise 68.79 */ 68.80 - public Node enterBIT_NOT(final UnaryNode unaryNode) { 68.81 + public boolean enterBIT_NOT(final UnaryNode unaryNode) { 68.82 return enterDefault(unaryNode); 68.83 } 68.84 68.85 @@ -345,9 +332,9 @@ 68.86 * Unary enter - callback for entering a conversion 68.87 * 68.88 * @param unaryNode the node 68.89 - * @return processed node 68.90 + * @return true if traversal should continue and node children be traversed, false otherwise 68.91 */ 68.92 - public Node enterCONVERT(final UnaryNode unaryNode) { 68.93 + public boolean enterCONVERT(final UnaryNode unaryNode) { 68.94 return enterDefault(unaryNode); 68.95 } 68.96 68.97 @@ -365,9 +352,9 @@ 68.98 * Unary enter - callback for entering a ++ or -- operator 68.99 * 68.100 * @param unaryNode the node 68.101 - * @return processed node 68.102 + * @return true if traversal should continue and node children be traversed, false otherwise 68.103 */ 68.104 - public Node enterDECINC(final UnaryNode unaryNode) { 68.105 + public boolean enterDECINC(final UnaryNode unaryNode) { 68.106 return enterDefault(unaryNode); 68.107 } 68.108 68.109 @@ -387,7 +374,7 @@ 68.110 * @param unaryNode the node 68.111 * @return processed node 68.112 */ 68.113 - public Node enterDELETE(final UnaryNode unaryNode) { 68.114 + public boolean enterDELETE(final UnaryNode unaryNode) { 68.115 return enterDefault(unaryNode); 68.116 } 68.117 68.118 @@ -405,9 +392,9 @@ 68.119 * Unary enter - callback for entering a discard operator 68.120 * 68.121 * @param unaryNode the node 68.122 - * @return processed node 68.123 + * @return true if traversal should continue and node children be traversed, false otherwise 68.124 */ 68.125 - public Node enterDISCARD(final UnaryNode unaryNode) { 68.126 + public boolean enterDISCARD(final UnaryNode unaryNode) { 68.127 return enterDefault(unaryNode); 68.128 } 68.129 68.130 @@ -425,9 +412,9 @@ 68.131 * Unary enter - callback for entering a new operator 68.132 * 68.133 * @param unaryNode the node 68.134 - * @return processed node 68.135 + * @return true if traversal should continue and node children be traversed, false otherwise 68.136 */ 68.137 - public Node enterNEW(final UnaryNode unaryNode) { 68.138 + public boolean enterNEW(final UnaryNode unaryNode) { 68.139 return enterDefault(unaryNode); 68.140 } 68.141 68.142 @@ -445,9 +432,9 @@ 68.143 * Unary enter - callback for entering a ! operator 68.144 * 68.145 * @param unaryNode the node 68.146 - * @return processed node 68.147 + * @return true if traversal should continue and node children be traversed, false otherwise 68.148 */ 68.149 - public Node enterNOT(final UnaryNode unaryNode) { 68.150 + public boolean enterNOT(final UnaryNode unaryNode) { 68.151 return enterDefault(unaryNode); 68.152 } 68.153 68.154 @@ -465,9 +452,9 @@ 68.155 * Unary enter - callback for entering a unary - 68.156 * 68.157 * @param unaryNode the node 68.158 - * @return processed node 68.159 + * @return true if traversal should continue and node children be traversed, false otherwise 68.160 */ 68.161 - public Node enterSUB(final UnaryNode unaryNode) { 68.162 + public boolean enterSUB(final UnaryNode unaryNode) { 68.163 return enterDefault(unaryNode); 68.164 } 68.165 68.166 @@ -485,9 +472,9 @@ 68.167 * Unary enter - callback for entering a typeof 68.168 * 68.169 * @param unaryNode the node 68.170 - * @return processed node 68.171 + * @return true if traversal should continue and node children be traversed, false otherwise 68.172 */ 68.173 - public Node enterTYPEOF(final UnaryNode unaryNode) { 68.174 + public boolean enterTYPEOF(final UnaryNode unaryNode) { 68.175 return enterDefault(unaryNode); 68.176 } 68.177 68.178 @@ -505,9 +492,9 @@ 68.179 * Unary enter - callback for entering a void 68.180 * 68.181 * @param unaryNode the node 68.182 - * @return processed node 68.183 + * @return true if traversal should continue and node children be traversed, false otherwise 68.184 */ 68.185 - public Node enterVOID(final UnaryNode unaryNode) { 68.186 + public boolean enterVOID(final UnaryNode unaryNode) { 68.187 return enterDefault(unaryNode); 68.188 } 68.189 68.190 @@ -525,9 +512,9 @@ 68.191 * Binary enter - callback for entering + operator 68.192 * 68.193 * @param binaryNode the node 68.194 - * @return processed node 68.195 + * @return true if traversal should continue and node children be traversed, false otherwise 68.196 */ 68.197 - public Node enterADD(final BinaryNode binaryNode) { 68.198 + public boolean enterADD(final BinaryNode binaryNode) { 68.199 return enterDefault(binaryNode); 68.200 } 68.201 68.202 @@ -545,9 +532,9 @@ 68.203 * Binary enter - callback for entering {@literal &&} operator 68.204 * 68.205 * @param binaryNode the node 68.206 - * @return processed node 68.207 + * @return true if traversal should continue and node children be traversed, false otherwise 68.208 */ 68.209 - public Node enterAND(final BinaryNode binaryNode) { 68.210 + public boolean enterAND(final BinaryNode binaryNode) { 68.211 return enterDefault(binaryNode); 68.212 } 68.213 68.214 @@ -565,9 +552,9 @@ 68.215 * Binary enter - callback for entering an assignment 68.216 * 68.217 * @param binaryNode the node 68.218 - * @return processed node 68.219 + * @return true if traversal should continue and node children be traversed, false otherwise 68.220 */ 68.221 - public Node enterASSIGN(final BinaryNode binaryNode) { 68.222 + public boolean enterASSIGN(final BinaryNode binaryNode) { 68.223 return enterDefault(binaryNode); 68.224 } 68.225 68.226 @@ -585,9 +572,9 @@ 68.227 * Binary enter - callback for entering += operator 68.228 * 68.229 * @param binaryNode the node 68.230 - * @return processed node 68.231 + * @return true if traversal should continue and node children be traversed, false otherwise 68.232 */ 68.233 - public Node enterASSIGN_ADD(final BinaryNode binaryNode) { 68.234 + public boolean enterASSIGN_ADD(final BinaryNode binaryNode) { 68.235 return enterDefault(binaryNode); 68.236 } 68.237 68.238 @@ -605,9 +592,9 @@ 68.239 * Binary enter - callback for entering {@literal &=} operator 68.240 * 68.241 * @param binaryNode the node 68.242 - * @return processed node 68.243 + * @return true if traversal should continue and node children be traversed, false otherwise 68.244 */ 68.245 - public Node enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 68.246 + public boolean enterASSIGN_BIT_AND(final BinaryNode binaryNode) { 68.247 return enterDefault(binaryNode); 68.248 } 68.249 68.250 @@ -625,9 +612,9 @@ 68.251 * Binary enter - callback for entering |= operator 68.252 * 68.253 * @param binaryNode the node 68.254 - * @return processed node 68.255 + * @return true if traversal should continue and node children be traversed, false otherwise 68.256 */ 68.257 - public Node enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 68.258 + public boolean enterASSIGN_BIT_OR(final BinaryNode binaryNode) { 68.259 return enterDefault(binaryNode); 68.260 } 68.261 68.262 @@ -645,9 +632,9 @@ 68.263 * Binary enter - callback for entering ^= operator 68.264 * 68.265 * @param binaryNode the node 68.266 - * @return processed node 68.267 + * @return true if traversal should continue and node children be traversed, false otherwise 68.268 */ 68.269 - public Node enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 68.270 + public boolean enterASSIGN_BIT_XOR(final BinaryNode binaryNode) { 68.271 return enterDefault(binaryNode); 68.272 } 68.273 68.274 @@ -665,9 +652,9 @@ 68.275 * Binary enter - callback for entering /= operator 68.276 * 68.277 * @param binaryNode the node 68.278 - * @return processed node 68.279 + * @return true if traversal should continue and node children be traversed, false otherwise 68.280 */ 68.281 - public Node enterASSIGN_DIV(final BinaryNode binaryNode) { 68.282 + public boolean enterASSIGN_DIV(final BinaryNode binaryNode) { 68.283 return enterDefault(binaryNode); 68.284 } 68.285 68.286 @@ -685,9 +672,9 @@ 68.287 * Binary enter - callback for entering %= operator 68.288 * 68.289 * @param binaryNode the node 68.290 - * @return processed node 68.291 + * @return true if traversal should continue and node children be traversed, false otherwise 68.292 */ 68.293 - public Node enterASSIGN_MOD(final BinaryNode binaryNode) { 68.294 + public boolean enterASSIGN_MOD(final BinaryNode binaryNode) { 68.295 return enterDefault(binaryNode); 68.296 } 68.297 68.298 @@ -705,9 +692,9 @@ 68.299 * Binary enter - callback for entering *= operator 68.300 * 68.301 * @param binaryNode the node 68.302 - * @return processed node 68.303 + * @return true if traversal should continue and node children be traversed, false otherwise 68.304 */ 68.305 - public Node enterASSIGN_MUL(final BinaryNode binaryNode) { 68.306 + public boolean enterASSIGN_MUL(final BinaryNode binaryNode) { 68.307 return enterDefault(binaryNode); 68.308 } 68.309 68.310 @@ -725,9 +712,9 @@ 68.311 * Binary enter - callback for entering {@literal >>=} operator 68.312 * 68.313 * @param binaryNode the node 68.314 - * @return processed node 68.315 + * @return true if traversal should continue and node children be traversed, false otherwise 68.316 */ 68.317 - public Node enterASSIGN_SAR(final BinaryNode binaryNode) { 68.318 + public boolean enterASSIGN_SAR(final BinaryNode binaryNode) { 68.319 return enterDefault(binaryNode); 68.320 } 68.321 68.322 @@ -745,9 +732,9 @@ 68.323 * Binary enter - callback for entering a {@literal <<=} operator 68.324 * 68.325 * @param binaryNode the node 68.326 - * @return processed node 68.327 + * @return true if traversal should continue and node children be traversed, false otherwise 68.328 */ 68.329 - public Node enterASSIGN_SHL(final BinaryNode binaryNode) { 68.330 + public boolean enterASSIGN_SHL(final BinaryNode binaryNode) { 68.331 return enterDefault(binaryNode); 68.332 } 68.333 68.334 @@ -765,9 +752,9 @@ 68.335 * Binary enter - callback for entering {@literal >>>=} operator 68.336 * 68.337 * @param binaryNode the node 68.338 - * @return processed node 68.339 + * @return true if traversal should continue and node children be traversed, false otherwise 68.340 */ 68.341 - public Node enterASSIGN_SHR(final BinaryNode binaryNode) { 68.342 + public boolean enterASSIGN_SHR(final BinaryNode binaryNode) { 68.343 return enterDefault(binaryNode); 68.344 } 68.345 68.346 @@ -785,9 +772,9 @@ 68.347 * Binary enter - callback for entering -= operator 68.348 * 68.349 * @param binaryNode the node 68.350 - * @return processed node 68.351 + * @return true if traversal should continue and node children be traversed, false otherwise 68.352 */ 68.353 - public Node enterASSIGN_SUB(final BinaryNode binaryNode) { 68.354 + public boolean enterASSIGN_SUB(final BinaryNode binaryNode) { 68.355 return enterDefault(binaryNode); 68.356 } 68.357 68.358 @@ -805,9 +792,9 @@ 68.359 * Binary enter - callback for entering a bind operator 68.360 * 68.361 * @param binaryNode the node 68.362 - * @return processed node 68.363 + * @return true if traversal should continue and node children be traversed, false otherwise 68.364 */ 68.365 - public Node enterBIND(final BinaryNode binaryNode) { 68.366 + public boolean enterBIND(final BinaryNode binaryNode) { 68.367 return enterDefault(binaryNode); 68.368 } 68.369 68.370 @@ -825,9 +812,9 @@ 68.371 * Binary enter - callback for entering {@literal &} operator 68.372 * 68.373 * @param binaryNode the node 68.374 - * @return processed node 68.375 + * @return true if traversal should continue and node children be traversed, false otherwise 68.376 */ 68.377 - public Node enterBIT_AND(final BinaryNode binaryNode) { 68.378 + public boolean enterBIT_AND(final BinaryNode binaryNode) { 68.379 return enterDefault(binaryNode); 68.380 } 68.381 68.382 @@ -845,9 +832,9 @@ 68.383 * Binary enter - callback for entering | operator 68.384 * 68.385 * @param binaryNode the node 68.386 - * @return processed node 68.387 + * @return true if traversal should continue and node children be traversed, false otherwise 68.388 */ 68.389 - public Node enterBIT_OR(final BinaryNode binaryNode) { 68.390 + public boolean enterBIT_OR(final BinaryNode binaryNode) { 68.391 return enterDefault(binaryNode); 68.392 } 68.393 68.394 @@ -865,9 +852,9 @@ 68.395 * Binary enter - callback for entering ^ operator 68.396 * 68.397 * @param binaryNode the node 68.398 - * @return processed node 68.399 + * @return true if traversal should continue and node children be traversed, false otherwise 68.400 */ 68.401 - public Node enterBIT_XOR(final BinaryNode binaryNode) { 68.402 + public boolean enterBIT_XOR(final BinaryNode binaryNode) { 68.403 return enterDefault(binaryNode); 68.404 } 68.405 68.406 @@ -886,9 +873,9 @@ 68.407 * (a, b) where the result is a 68.408 * 68.409 * @param binaryNode the node 68.410 - * @return processed node 68.411 + * @return true if traversal should continue and node children be traversed, false otherwise 68.412 */ 68.413 - public Node enterCOMMALEFT(final BinaryNode binaryNode) { 68.414 + public boolean enterCOMMALEFT(final BinaryNode binaryNode) { 68.415 return enterDefault(binaryNode); 68.416 } 68.417 68.418 @@ -908,9 +895,9 @@ 68.419 * (a, b) where the result is b 68.420 * 68.421 * @param binaryNode the node 68.422 - * @return processed node 68.423 + * @return true if traversal should continue and node children be traversed, false otherwise 68.424 */ 68.425 - public Node enterCOMMARIGHT(final BinaryNode binaryNode) { 68.426 + public boolean enterCOMMARIGHT(final BinaryNode binaryNode) { 68.427 return enterDefault(binaryNode); 68.428 } 68.429 68.430 @@ -929,9 +916,9 @@ 68.431 * Binary enter - callback for entering a division 68.432 * 68.433 * @param binaryNode the node 68.434 - * @return processed node 68.435 + * @return true if traversal should continue and node children be traversed, false otherwise 68.436 */ 68.437 - public Node enterDIV(final BinaryNode binaryNode) { 68.438 + public boolean enterDIV(final BinaryNode binaryNode) { 68.439 return enterDefault(binaryNode); 68.440 } 68.441 68.442 @@ -949,9 +936,9 @@ 68.443 * Binary enter - callback for entering == operator 68.444 * 68.445 * @param binaryNode the node 68.446 - * @return processed node 68.447 + * @return true if traversal should continue and node children be traversed, false otherwise 68.448 */ 68.449 - public Node enterEQ(final BinaryNode binaryNode) { 68.450 + public boolean enterEQ(final BinaryNode binaryNode) { 68.451 return enterDefault(binaryNode); 68.452 } 68.453 68.454 @@ -969,9 +956,9 @@ 68.455 * Binary enter - callback for entering === operator 68.456 * 68.457 * @param binaryNode the node 68.458 - * @return processed node 68.459 + * @return true if traversal should continue and node children be traversed, false otherwise 68.460 */ 68.461 - public Node enterEQ_STRICT(final BinaryNode binaryNode) { 68.462 + public boolean enterEQ_STRICT(final BinaryNode binaryNode) { 68.463 return enterDefault(binaryNode); 68.464 } 68.465 68.466 @@ -989,9 +976,9 @@ 68.467 * Binary enter - callback for entering {@literal >=} operator 68.468 * 68.469 * @param binaryNode the node 68.470 - * @return processed node 68.471 + * @return true if traversal should continue and node children be traversed, false otherwise 68.472 */ 68.473 - public Node enterGE(final BinaryNode binaryNode) { 68.474 + public boolean enterGE(final BinaryNode binaryNode) { 68.475 return enterDefault(binaryNode); 68.476 } 68.477 68.478 @@ -1009,9 +996,9 @@ 68.479 * Binary enter - callback for entering {@literal >} operator 68.480 * 68.481 * @param binaryNode the node 68.482 - * @return processed node 68.483 + * @return true if traversal should continue and node children be traversed, false otherwise 68.484 */ 68.485 - public Node enterGT(final BinaryNode binaryNode) { 68.486 + public boolean enterGT(final BinaryNode binaryNode) { 68.487 return enterDefault(binaryNode); 68.488 } 68.489 68.490 @@ -1029,9 +1016,9 @@ 68.491 * Binary enter - callback for entering in operator 68.492 * 68.493 * @param binaryNode the node 68.494 - * @return processed node 68.495 + * @return true if traversal should continue and node children be traversed, false otherwise 68.496 */ 68.497 - public Node enterIN(final BinaryNode binaryNode) { 68.498 + public boolean enterIN(final BinaryNode binaryNode) { 68.499 return enterDefault(binaryNode); 68.500 } 68.501 68.502 @@ -1049,9 +1036,9 @@ 68.503 * Binary enter - callback for entering instanceof operator 68.504 * 68.505 * @param binaryNode the node 68.506 - * @return processed node 68.507 + * @return true if traversal should continue and node children be traversed, false otherwise 68.508 */ 68.509 - public Node enterINSTANCEOF(final BinaryNode binaryNode) { 68.510 + public boolean enterINSTANCEOF(final BinaryNode binaryNode) { 68.511 return enterDefault(binaryNode); 68.512 } 68.513 68.514 @@ -1069,9 +1056,9 @@ 68.515 * Binary enter - callback for entering {@literal <=} operator 68.516 * 68.517 * @param binaryNode the node 68.518 - * @return processed node 68.519 + * @return true if traversal should continue and node children be traversed, false otherwise 68.520 */ 68.521 - public Node enterLE(final BinaryNode binaryNode) { 68.522 + public boolean enterLE(final BinaryNode binaryNode) { 68.523 return enterDefault(binaryNode); 68.524 } 68.525 68.526 @@ -1089,9 +1076,9 @@ 68.527 * Binary enter - callback for entering {@literal <} operator 68.528 * 68.529 * @param binaryNode the node 68.530 - * @return processed node 68.531 + * @return true if traversal should continue and node children be traversed, false otherwise 68.532 */ 68.533 - public Node enterLT(final BinaryNode binaryNode) { 68.534 + public boolean enterLT(final BinaryNode binaryNode) { 68.535 return enterDefault(binaryNode); 68.536 } 68.537 68.538 @@ -1108,9 +1095,9 @@ 68.539 * Binary enter - callback for entering % operator 68.540 * 68.541 * @param binaryNode the node 68.542 - * @return processed node 68.543 + * @return true if traversal should continue and node children be traversed, false otherwise 68.544 */ 68.545 - public Node enterMOD(final BinaryNode binaryNode) { 68.546 + public boolean enterMOD(final BinaryNode binaryNode) { 68.547 return enterDefault(binaryNode); 68.548 } 68.549 68.550 @@ -1128,9 +1115,9 @@ 68.551 * Binary enter - callback for entering * operator 68.552 * 68.553 * @param binaryNode the node 68.554 - * @return processed node 68.555 + * @return true if traversal should continue and node children be traversed, false otherwise 68.556 */ 68.557 - public Node enterMUL(final BinaryNode binaryNode) { 68.558 + public boolean enterMUL(final BinaryNode binaryNode) { 68.559 return enterDefault(binaryNode); 68.560 } 68.561 68.562 @@ -1148,9 +1135,9 @@ 68.563 * Binary enter - callback for entering != operator 68.564 * 68.565 * @param binaryNode the node 68.566 - * @return processed node 68.567 + * @return true if traversal should continue and node children be traversed, false otherwise 68.568 */ 68.569 - public Node enterNE(final BinaryNode binaryNode) { 68.570 + public boolean enterNE(final BinaryNode binaryNode) { 68.571 return enterDefault(binaryNode); 68.572 } 68.573 68.574 @@ -1168,9 +1155,9 @@ 68.575 * Binary enter - callback for entering a !== operator 68.576 * 68.577 * @param binaryNode the node 68.578 - * @return processed node 68.579 + * @return true if traversal should continue and node children be traversed, false otherwise 68.580 */ 68.581 - public Node enterNE_STRICT(final BinaryNode binaryNode) { 68.582 + public boolean enterNE_STRICT(final BinaryNode binaryNode) { 68.583 return enterDefault(binaryNode); 68.584 } 68.585 68.586 @@ -1188,9 +1175,9 @@ 68.587 * Binary enter - callback for entering || operator 68.588 * 68.589 * @param binaryNode the node 68.590 - * @return processed node 68.591 + * @return true if traversal should continue and node children be traversed, false otherwise 68.592 */ 68.593 - public Node enterOR(final BinaryNode binaryNode) { 68.594 + public boolean enterOR(final BinaryNode binaryNode) { 68.595 return enterDefault(binaryNode); 68.596 } 68.597 68.598 @@ -1208,9 +1195,9 @@ 68.599 * Binary enter - callback for entering {@literal >>} operator 68.600 * 68.601 * @param binaryNode the node 68.602 - * @return processed node 68.603 + * @return true if traversal should continue and node children be traversed, false otherwise 68.604 */ 68.605 - public Node enterSAR(final BinaryNode binaryNode) { 68.606 + public boolean enterSAR(final BinaryNode binaryNode) { 68.607 return enterDefault(binaryNode); 68.608 } 68.609 68.610 @@ -1228,9 +1215,9 @@ 68.611 * Binary enter - callback for entering {@literal <<} operator 68.612 * 68.613 * @param binaryNode the node 68.614 - * @return processed node 68.615 + * @return true if traversal should continue and node children be traversed, false otherwise 68.616 */ 68.617 - public Node enterSHL(final BinaryNode binaryNode) { 68.618 + public boolean enterSHL(final BinaryNode binaryNode) { 68.619 return enterDefault(binaryNode); 68.620 } 68.621 68.622 @@ -1247,9 +1234,9 @@ 68.623 * Binary enter - callback for entering {@literal >>>} operator 68.624 * 68.625 * @param binaryNode the node 68.626 - * @return processed node 68.627 + * @return true if traversal should continue and node children be traversed, false otherwise 68.628 */ 68.629 - public Node enterSHR(final BinaryNode binaryNode) { 68.630 + public boolean enterSHR(final BinaryNode binaryNode) { 68.631 return enterDefault(binaryNode); 68.632 } 68.633 68.634 @@ -1267,9 +1254,9 @@ 68.635 * Binary enter - callback for entering - operator 68.636 * 68.637 * @param binaryNode the node 68.638 - * @return processed node 68.639 + * @return true if traversal should continue and node children be traversed, false otherwise 68.640 */ 68.641 - public Node enterSUB(final BinaryNode binaryNode) { 68.642 + public boolean enterSUB(final BinaryNode binaryNode) { 68.643 return enterDefault(binaryNode); 68.644 } 68.645
69.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Fri Apr 19 18:23:00 2013 +0530 69.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeVisitor.java Fri Apr 19 16:11:16 2013 +0200 69.3 @@ -25,8 +25,6 @@ 69.4 69.5 package jdk.nashorn.internal.ir.visitor; 69.6 69.7 -import jdk.nashorn.internal.codegen.CompileUnit; 69.8 -import jdk.nashorn.internal.codegen.MethodEmitter; 69.9 import jdk.nashorn.internal.ir.AccessNode; 69.10 import jdk.nashorn.internal.ir.BinaryNode; 69.11 import jdk.nashorn.internal.ir.Block; 69.12 @@ -35,7 +33,6 @@ 69.13 import jdk.nashorn.internal.ir.CaseNode; 69.14 import jdk.nashorn.internal.ir.CatchNode; 69.15 import jdk.nashorn.internal.ir.ContinueNode; 69.16 -import jdk.nashorn.internal.ir.DoWhileNode; 69.17 import jdk.nashorn.internal.ir.EmptyNode; 69.18 import jdk.nashorn.internal.ir.ExecuteNode; 69.19 import jdk.nashorn.internal.ir.ForNode; 69.20 @@ -44,6 +41,7 @@ 69.21 import jdk.nashorn.internal.ir.IfNode; 69.22 import jdk.nashorn.internal.ir.IndexNode; 69.23 import jdk.nashorn.internal.ir.LabelNode; 69.24 +import jdk.nashorn.internal.ir.LexicalContext; 69.25 import jdk.nashorn.internal.ir.LineNumberNode; 69.26 import jdk.nashorn.internal.ir.LiteralNode; 69.27 import jdk.nashorn.internal.ir.Node; 69.28 @@ -65,41 +63,30 @@ 69.29 * Visitor used to navigate the IR. 69.30 */ 69.31 public abstract class NodeVisitor { 69.32 - /** Current functionNode. */ 69.33 - private FunctionNode currentFunctionNode; 69.34 - 69.35 - /** Current compile unit used for class generation. */ 69.36 - private CompileUnit compileUnit; 69.37 + private final LexicalContext lc; 69.38 69.39 /** 69.40 - * Current method visitor used for method generation. 69.41 - * <p> 69.42 - * TODO: protected is just for convenience and readability, so that 69.43 - * subclasses can directly use 'method' - might want to change that 69.44 - */ 69.45 - protected MethodEmitter method; 69.46 - 69.47 - /** Current block. */ 69.48 - private Block currentBlock; 69.49 - 69.50 - /** 69.51 - * Constructor. 69.52 + * Constructor 69.53 */ 69.54 public NodeVisitor() { 69.55 - this(null, null); 69.56 + this(new LexicalContext()); 69.57 } 69.58 69.59 /** 69.60 * Constructor 69.61 * 69.62 - * @param compileUnit compile unit for this node visitor 69.63 - * @param method method emitter for this node visitor 69.64 + * @param lc a custom lexical context 69.65 */ 69.66 - public NodeVisitor(final CompileUnit compileUnit, final MethodEmitter method) { 69.67 - super(); 69.68 + public NodeVisitor(final LexicalContext lc) { 69.69 + this.lc = lc; 69.70 + } 69.71 69.72 - this.compileUnit = compileUnit; 69.73 - this.method = method; 69.74 + /** 69.75 + * Get the lexical context of this node visitor 69.76 + * @return lexical context 69.77 + */ 69.78 + public LexicalContext getLexicalContext() { 69.79 + return lc; 69.80 } 69.81 69.82 /** 69.83 @@ -118,10 +105,10 @@ 69.84 * 69.85 * @see NodeVisitor#leaveDefault(Node) 69.86 * @param node the node to visit 69.87 - * @return the node 69.88 + * @return true if traversal should continue and node children be traversed, false otherwise 69.89 */ 69.90 - protected Node enterDefault(final Node node) { 69.91 - return node; 69.92 + protected boolean enterDefault(final Node node) { 69.93 + return true; 69.94 } 69.95 69.96 /** 69.97 @@ -150,9 +137,9 @@ 69.98 * Callback for entering an AccessNode 69.99 * 69.100 * @param accessNode the node 69.101 - * @return processed node, null if traversal should end, null if traversal should end 69.102 + * @return true if traversal should continue and node children be traversed, false otherwise 69.103 */ 69.104 - public Node enterAccessNode(final AccessNode accessNode) { 69.105 + public boolean enterAccessNode(final AccessNode accessNode) { 69.106 return enterDefault(accessNode); 69.107 } 69.108 69.109 @@ -170,9 +157,9 @@ 69.110 * Callback for entering a Block 69.111 * 69.112 * @param block the node 69.113 - * @return processed node, null if traversal should end 69.114 + * @return true if traversal should continue and node children be traversed, false otherwise 69.115 */ 69.116 - public Node enterBlock(final Block block) { 69.117 + public boolean enterBlock(final Block block) { 69.118 return enterDefault(block); 69.119 } 69.120 69.121 @@ -192,7 +179,7 @@ 69.122 * @param binaryNode the node 69.123 * @return processed node 69.124 */ 69.125 - public Node enterBinaryNode(final BinaryNode binaryNode) { 69.126 + public boolean enterBinaryNode(final BinaryNode binaryNode) { 69.127 return enterDefault(binaryNode); 69.128 } 69.129 69.130 @@ -210,9 +197,9 @@ 69.131 * Callback for entering a BreakNode 69.132 * 69.133 * @param breakNode the node 69.134 - * @return processed node, null if traversal should end 69.135 + * @return true if traversal should continue and node children be traversed, false otherwise 69.136 */ 69.137 - public Node enterBreakNode(final BreakNode breakNode) { 69.138 + public boolean enterBreakNode(final BreakNode breakNode) { 69.139 return enterDefault(breakNode); 69.140 } 69.141 69.142 @@ -230,9 +217,9 @@ 69.143 * Callback for entering a CallNode 69.144 * 69.145 * @param callNode the node 69.146 - * @return processed node, null if traversal should end 69.147 + * @return true if traversal should continue and node children be traversed, false otherwise 69.148 */ 69.149 - public Node enterCallNode(final CallNode callNode) { 69.150 + public boolean enterCallNode(final CallNode callNode) { 69.151 return enterDefault(callNode); 69.152 } 69.153 69.154 @@ -250,9 +237,9 @@ 69.155 * Callback for entering a CaseNode 69.156 * 69.157 * @param caseNode the node 69.158 - * @return processed node, null if traversal should end 69.159 + * @return true if traversal should continue and node children be traversed, false otherwise 69.160 */ 69.161 - public Node enterCaseNode(final CaseNode caseNode) { 69.162 + public boolean enterCaseNode(final CaseNode caseNode) { 69.163 return enterDefault(caseNode); 69.164 } 69.165 69.166 @@ -270,9 +257,9 @@ 69.167 * Callback for entering a CatchNode 69.168 * 69.169 * @param catchNode the node 69.170 - * @return processed node, null if traversal should end 69.171 + * @return true if traversal should continue and node children be traversed, false otherwise 69.172 */ 69.173 - public Node enterCatchNode(final CatchNode catchNode) { 69.174 + public boolean enterCatchNode(final CatchNode catchNode) { 69.175 return enterDefault(catchNode); 69.176 } 69.177 69.178 @@ -290,9 +277,9 @@ 69.179 * Callback for entering a ContinueNode 69.180 * 69.181 * @param continueNode the node 69.182 - * @return processed node, null if traversal should end 69.183 + * @return true if traversal should continue and node children be traversed, false otherwise 69.184 */ 69.185 - public Node enterContinueNode(final ContinueNode continueNode) { 69.186 + public boolean enterContinueNode(final ContinueNode continueNode) { 69.187 return enterDefault(continueNode); 69.188 } 69.189 69.190 @@ -307,32 +294,12 @@ 69.191 } 69.192 69.193 /** 69.194 - * Callback for entering a DoWhileNode 69.195 - * 69.196 - * @param doWhileNode the node 69.197 - * @return processed node 69.198 - */ 69.199 - public Node enterDoWhileNode(final DoWhileNode doWhileNode) { 69.200 - return enterDefault(doWhileNode); 69.201 - } 69.202 - 69.203 - /** 69.204 - * Callback for leaving a DoWhileNode 69.205 - * 69.206 - * @param doWhileNode the node 69.207 - * @return processed node, which will replace the original one, or the original node 69.208 - */ 69.209 - public Node leaveDoWhileNode(final DoWhileNode doWhileNode) { 69.210 - return leaveDefault(doWhileNode); 69.211 - } 69.212 - 69.213 - /** 69.214 * Callback for entering an EmptyNode 69.215 * 69.216 * @param emptyNode the node 69.217 - * @return processed node 69.218 + * @return true if traversal should continue and node children be traversed, false otherwise 69.219 */ 69.220 - public Node enterEmptyNode(final EmptyNode emptyNode) { 69.221 + public boolean enterEmptyNode(final EmptyNode emptyNode) { 69.222 return enterDefault(emptyNode); 69.223 } 69.224 69.225 @@ -350,9 +317,9 @@ 69.226 * Callback for entering an ExecuteNode 69.227 * 69.228 * @param executeNode the node 69.229 - * @return processed node, null if traversal should end 69.230 + * @return true if traversal should continue and node children be traversed, false otherwise 69.231 */ 69.232 - public Node enterExecuteNode(final ExecuteNode executeNode) { 69.233 + public boolean enterExecuteNode(final ExecuteNode executeNode) { 69.234 return enterDefault(executeNode); 69.235 } 69.236 69.237 @@ -370,9 +337,9 @@ 69.238 * Callback for entering a ForNode 69.239 * 69.240 * @param forNode the node 69.241 - * @return processed node, null if traversal should end 69.242 + * @return true if traversal should continue and node children be traversed, false otherwise 69.243 */ 69.244 - public Node enterForNode(final ForNode forNode) { 69.245 + public boolean enterForNode(final ForNode forNode) { 69.246 return enterDefault(forNode); 69.247 } 69.248 69.249 @@ -390,9 +357,9 @@ 69.250 * Callback for entering a FunctionNode 69.251 * 69.252 * @param functionNode the node 69.253 - * @return processed node 69.254 + * @return true if traversal should continue and node children be traversed, false otherwise 69.255 */ 69.256 - public Node enterFunctionNode(final FunctionNode functionNode) { 69.257 + public boolean enterFunctionNode(final FunctionNode functionNode) { 69.258 return enterDefault(functionNode); 69.259 } 69.260 69.261 @@ -410,9 +377,9 @@ 69.262 * Callback for entering an IdentNode 69.263 * 69.264 * @param identNode the node 69.265 - * @return processed node, null if traversal should end 69.266 + * @return true if traversal should continue and node children be traversed, false otherwise 69.267 */ 69.268 - public Node enterIdentNode(final IdentNode identNode) { 69.269 + public boolean enterIdentNode(final IdentNode identNode) { 69.270 return enterDefault(identNode); 69.271 } 69.272 69.273 @@ -429,10 +396,10 @@ 69.274 /** 69.275 * Callback for entering an IfNode 69.276 * 69.277 - * @param ifNode the node 69.278 - * @return processed node, null if traversal should end 69.279 + * @param ifNode the node 69.280 + * @return true if traversal should continue and node children be traversed, false otherwise 69.281 */ 69.282 - public Node enterIfNode(final IfNode ifNode) { 69.283 + public boolean enterIfNode(final IfNode ifNode) { 69.284 return enterDefault(ifNode); 69.285 } 69.286 69.287 @@ -450,9 +417,9 @@ 69.288 * Callback for entering an IndexNode 69.289 * 69.290 * @param indexNode the node 69.291 - * @return processed node, null if traversal should end 69.292 + * @return true if traversal should continue and node children be traversed, false otherwise 69.293 */ 69.294 - public Node enterIndexNode(final IndexNode indexNode) { 69.295 + public boolean enterIndexNode(final IndexNode indexNode) { 69.296 return enterDefault(indexNode); 69.297 } 69.298 69.299 @@ -470,9 +437,9 @@ 69.300 * Callback for entering a LabelNode 69.301 * 69.302 * @param labelNode the node 69.303 - * @return processed node, null if traversal should end 69.304 + * @return true if traversal should continue and node children be traversed, false otherwise 69.305 */ 69.306 - public Node enterLabelNode(final LabelNode labelNode) { 69.307 + public boolean enterLabelNode(final LabelNode labelNode) { 69.308 return enterDefault(labelNode); 69.309 } 69.310 69.311 @@ -490,9 +457,9 @@ 69.312 * Callback for entering a LineNumberNode 69.313 * 69.314 * @param lineNumberNode the node 69.315 - * @return processed node, null if traversal should end 69.316 + * @return true if traversal should continue and node children be traversed, false otherwise 69.317 */ 69.318 - public Node enterLineNumberNode(final LineNumberNode lineNumberNode) { 69.319 + public boolean enterLineNumberNode(final LineNumberNode lineNumberNode) { 69.320 return enterDefault(lineNumberNode); 69.321 } 69.322 69.323 @@ -510,9 +477,9 @@ 69.324 * Callback for entering a LiteralNode 69.325 * 69.326 * @param literalNode the node 69.327 - * @return processed node 69.328 + * @return true if traversal should continue and node children be traversed, false otherwise 69.329 */ 69.330 - public Node enterLiteralNode(final LiteralNode<?> literalNode) { 69.331 + public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 69.332 return enterDefault(literalNode); 69.333 } 69.334 69.335 @@ -530,9 +497,9 @@ 69.336 * Callback for entering an ObjectNode 69.337 * 69.338 * @param objectNode the node 69.339 - * @return processed node 69.340 + * @return true if traversal should continue and node children be traversed, false otherwise 69.341 */ 69.342 - public Node enterObjectNode(final ObjectNode objectNode) { 69.343 + public boolean enterObjectNode(final ObjectNode objectNode) { 69.344 return enterDefault(objectNode); 69.345 } 69.346 69.347 @@ -550,9 +517,9 @@ 69.348 * Callback for entering a PropertyNode 69.349 * 69.350 * @param propertyNode the node 69.351 - * @return processed node, null if traversal should end 69.352 + * @return true if traversal should continue and node children be traversed, false otherwise 69.353 */ 69.354 - public Node enterPropertyNode(final PropertyNode propertyNode) { 69.355 + public boolean enterPropertyNode(final PropertyNode propertyNode) { 69.356 return enterDefault(propertyNode); 69.357 } 69.358 69.359 @@ -570,9 +537,9 @@ 69.360 * Callback for entering a ReturnNode 69.361 * 69.362 * @param returnNode the node 69.363 - * @return processed node, null if traversal should end 69.364 + * @return true if traversal should continue and node children be traversed, false otherwise 69.365 */ 69.366 - public Node enterReturnNode(final ReturnNode returnNode) { 69.367 + public boolean enterReturnNode(final ReturnNode returnNode) { 69.368 return enterDefault(returnNode); 69.369 } 69.370 69.371 @@ -590,9 +557,9 @@ 69.372 * Callback for entering a RuntimeNode 69.373 * 69.374 * @param runtimeNode the node 69.375 - * @return processed node, null if traversal should end 69.376 + * @return true if traversal should continue and node children be traversed, false otherwise 69.377 */ 69.378 - public Node enterRuntimeNode(final RuntimeNode runtimeNode) { 69.379 + public boolean enterRuntimeNode(final RuntimeNode runtimeNode) { 69.380 return enterDefault(runtimeNode); 69.381 } 69.382 69.383 @@ -610,9 +577,9 @@ 69.384 * Callback for entering a SplitNode 69.385 * 69.386 * @param splitNode the node 69.387 - * @return processed node, null if traversal should end 69.388 + * @return true if traversal should continue and node children be traversed, false otherwise 69.389 */ 69.390 - public Node enterSplitNode(final SplitNode splitNode) { 69.391 + public boolean enterSplitNode(final SplitNode splitNode) { 69.392 return enterDefault(splitNode); 69.393 } 69.394 69.395 @@ -630,9 +597,9 @@ 69.396 * Callback for entering a SwitchNode 69.397 * 69.398 * @param switchNode the node 69.399 - * @return processed node, null if traversal should end 69.400 + * @return true if traversal should continue and node children be traversed, false otherwise 69.401 */ 69.402 - public Node enterSwitchNode(final SwitchNode switchNode) { 69.403 + public boolean enterSwitchNode(final SwitchNode switchNode) { 69.404 return enterDefault(switchNode); 69.405 } 69.406 69.407 @@ -650,9 +617,9 @@ 69.408 * Callback for entering a TernaryNode 69.409 * 69.410 * @param ternaryNode the node 69.411 - * @return processed node, null if traversal should end 69.412 + * @return true if traversal should continue and node children be traversed, false otherwise 69.413 */ 69.414 - public Node enterTernaryNode(final TernaryNode ternaryNode) { 69.415 + public boolean enterTernaryNode(final TernaryNode ternaryNode) { 69.416 return enterDefault(ternaryNode); 69.417 } 69.418 69.419 @@ -670,9 +637,9 @@ 69.420 * Callback for entering a ThrowNode 69.421 * 69.422 * @param throwNode the node 69.423 - * @return processed node, null if traversal should end 69.424 + * @return true if traversal should continue and node children be traversed, false otherwise 69.425 */ 69.426 - public Node enterThrowNode(final ThrowNode throwNode) { 69.427 + public boolean enterThrowNode(final ThrowNode throwNode) { 69.428 return enterDefault(throwNode); 69.429 } 69.430 69.431 @@ -690,9 +657,9 @@ 69.432 * Callback for entering a TryNode 69.433 * 69.434 * @param tryNode the node 69.435 - * @return processed node, null if traversal should end 69.436 + * @return true if traversal should continue and node children be traversed, false otherwise 69.437 */ 69.438 - public Node enterTryNode(final TryNode tryNode) { 69.439 + public boolean enterTryNode(final TryNode tryNode) { 69.440 return enterDefault(tryNode); 69.441 } 69.442 69.443 @@ -710,9 +677,9 @@ 69.444 * Callback for entering a UnaryNode 69.445 * 69.446 * @param unaryNode the node 69.447 - * @return processed node, null if traversal should end 69.448 + * @return true if traversal should continue and node children be traversed, false otherwise 69.449 */ 69.450 - public Node enterUnaryNode(final UnaryNode unaryNode) { 69.451 + public boolean enterUnaryNode(final UnaryNode unaryNode) { 69.452 return enterDefault(unaryNode); 69.453 } 69.454 69.455 @@ -730,9 +697,9 @@ 69.456 * Callback for entering a VarNode 69.457 * 69.458 * @param varNode the node 69.459 - * @return processed node, null if traversal should end 69.460 + * @return true if traversal should continue and node children be traversed, false otherwise 69.461 */ 69.462 - public Node enterVarNode(final VarNode varNode) { 69.463 + public boolean enterVarNode(final VarNode varNode) { 69.464 return enterDefault(varNode); 69.465 } 69.466 69.467 @@ -750,9 +717,9 @@ 69.468 * Callback for entering a WhileNode 69.469 * 69.470 * @param whileNode the node 69.471 - * @return processed node, null if traversal should end 69.472 + * @return true if traversal should continue and node children be traversed, false otherwise 69.473 */ 69.474 - public Node enterWhileNode(final WhileNode whileNode) { 69.475 + public boolean enterWhileNode(final WhileNode whileNode) { 69.476 return enterDefault(whileNode); 69.477 } 69.478 69.479 @@ -770,9 +737,9 @@ 69.480 * Callback for entering a WithNode 69.481 * 69.482 * @param withNode the node 69.483 - * @return processed node, null if traversal should end 69.484 + * @return true if traversal should continue and node children be traversed, false otherwise 69.485 */ 69.486 - public Node enterWithNode(final WithNode withNode) { 69.487 + public boolean enterWithNode(final WithNode withNode) { 69.488 return enterDefault(withNode); 69.489 } 69.490 69.491 @@ -786,74 +753,5 @@ 69.492 return leaveDefault(withNode); 69.493 } 69.494 69.495 - /** 69.496 - * Get the current function node for this NodeVisitor 69.497 - * @see FunctionNode 69.498 - * @return the function node being visited 69.499 - */ 69.500 - public FunctionNode getCurrentFunctionNode() { 69.501 - return currentFunctionNode; 69.502 - } 69.503 - 69.504 - /** 69.505 - * Reset the current function node being visited for this NodeVisitor 69.506 - * @see FunctionNode 69.507 - * @param currentFunctionNode a new function node to traverse 69.508 - */ 69.509 - public void setCurrentFunctionNode(final FunctionNode currentFunctionNode) { 69.510 - this.currentFunctionNode = currentFunctionNode; 69.511 - } 69.512 - 69.513 - /** 69.514 - * Get the current compile unit for this NodeVisitor 69.515 - * @see CompileUnit 69.516 - * @return a compile unit, or null if not a compiling NodeVisitor 69.517 - */ 69.518 - public CompileUnit getCurrentCompileUnit() { 69.519 - return compileUnit; 69.520 - } 69.521 - 69.522 - /** 69.523 - * Set the current compile unit for this NodeVisitor 69.524 - * @see CompileUnit 69.525 - * @param compileUnit a new compile unit 69.526 - */ 69.527 - public void setCurrentCompileUnit(final CompileUnit compileUnit) { 69.528 - this.compileUnit = compileUnit; 69.529 - } 69.530 - 69.531 - /** 69.532 - * Get the current method emitter for this NodeVisitor 69.533 - * @see MethodEmitter 69.534 - * @return the method emitter 69.535 - */ 69.536 - public MethodEmitter getCurrentMethodEmitter() { 69.537 - return method; 69.538 - } 69.539 - 69.540 - /** 69.541 - * Reset the current method emitter for this NodeVisitor 69.542 - * @see MethodEmitter 69.543 - * @param method a new method emitter 69.544 - */ 69.545 - public void setCurrentMethodEmitter(final MethodEmitter method) { 69.546 - this.method = method; 69.547 - } 69.548 - 69.549 - /** 69.550 - * Get the current Block being traversed for this NodeVisitor 69.551 - * @return the current block 69.552 - */ 69.553 - public Block getCurrentBlock() { 69.554 - return currentBlock; 69.555 - } 69.556 - 69.557 - /** 69.558 - * Reset the Block to be traversed for this NodeVisitor 69.559 - * @param currentBlock the new current block 69.560 - */ 69.561 - public void setCurrentBlock(final Block currentBlock) { 69.562 - this.currentBlock = currentBlock; 69.563 - } 69.564 69.565 }
70.1 --- a/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Fri Apr 19 18:23:00 2013 +0530 70.2 +++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Fri Apr 19 16:11:16 2013 +0200 70.3 @@ -137,7 +137,7 @@ 70.4 */ 70.5 static Object traceReturn(final DebugLogger logger, final Object value) { 70.6 final String str = "\treturn: " + stripName(value) + " [type=" + (value == null ? "null" : stripName(value.getClass()) + ']'); 70.7 - logger.log(str, TRACE_LEVEL); 70.8 + logger.log(TRACE_LEVEL, str); 70.9 return value; 70.10 } 70.11 70.12 @@ -173,7 +173,7 @@ 70.13 } 70.14 70.15 assert logger != null; 70.16 - logger.log(sb.toString(), TRACE_LEVEL); 70.17 + logger.log(TRACE_LEVEL, sb); 70.18 stacktrace(logger); 70.19 } 70.20 70.21 @@ -184,7 +184,7 @@ 70.22 final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 70.23 final PrintStream ps = new PrintStream(baos); 70.24 new Throwable().printStackTrace(ps); 70.25 - logger.log(baos.toString(), TRACE_LEVEL); 70.26 + logger.log(TRACE_LEVEL, baos.toString()); 70.27 } 70.28 70.29 private static String argString(final Object arg) { 70.30 @@ -614,7 +614,7 @@ 70.31 @Override 70.32 public SwitchPoint createSwitchPoint() { 70.33 final SwitchPoint sp = super.createSwitchPoint(); 70.34 - LOG.log("createSwitchPoint " + sp, TRACE_LEVEL); 70.35 + LOG.log(TRACE_LEVEL, "createSwitchPoint ", sp); 70.36 return sp; 70.37 } 70.38 70.39 @@ -627,7 +627,7 @@ 70.40 @Override 70.41 public MethodType type(final Class<?> returnType, final Class<?>... paramTypes) { 70.42 final MethodType mt = super.type(returnType, paramTypes); 70.43 - LOG.log("methodType " + returnType + ' ' + Arrays.toString(paramTypes) + ' ' + mt, TRACE_LEVEL); 70.44 + LOG.log(TRACE_LEVEL, "methodType ", returnType, " ", Arrays.toString(paramTypes), " ", mt); 70.45 return mt; 70.46 } 70.47 } 70.48 @@ -638,7 +638,7 @@ 70.49 private static class TraceCreateMethodHandleFunctionality extends TraceMethodHandleFunctionality { 70.50 @Override 70.51 public MethodHandle debug(final MethodHandle master, final String str, final Object... args) { 70.52 - LOG.log(str + ' ' + describe(args), TRACE_LEVEL); 70.53 + LOG.log(TRACE_LEVEL, str, " ", describe(args)); 70.54 stacktrace(LOG); 70.55 return master; 70.56 }
71.1 --- a/src/jdk/nashorn/internal/objects/NativeString.java Fri Apr 19 18:23:00 2013 +0530 71.2 +++ b/src/jdk/nashorn/internal/objects/NativeString.java Fri Apr 19 16:11:16 2013 +0200 71.3 @@ -179,7 +179,6 @@ 71.4 return ((ScriptObject) Global.toObject(self)).get(key); 71.5 } 71.6 71.7 - @SuppressWarnings("unused") 71.8 private static Object get(final Object self, final int key) { 71.9 final CharSequence cs = JSType.toCharSequence(self); 71.10 if (key >= 0 && key < cs.length()) {
72.1 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java Fri Apr 19 18:23:00 2013 +0530 72.2 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java Fri Apr 19 16:11:16 2013 +0200 72.3 @@ -197,9 +197,10 @@ 72.4 * 72.5 * @param message Error message. 72.6 * @param errorToken Offending token. 72.7 + * @return ParserException upon failure. Caller should throw and not ignore 72.8 */ 72.9 - protected final void error(final String message, final long errorToken) { 72.10 - error(JSErrorType.SYNTAX_ERROR, message, errorToken); 72.11 + protected final ParserException error(final String message, final long errorToken) { 72.12 + return error(JSErrorType.SYNTAX_ERROR, message, errorToken); 72.13 } 72.14 72.15 /** 72.16 @@ -208,22 +209,24 @@ 72.17 * @param errorType The error type 72.18 * @param message Error message. 72.19 * @param errorToken Offending token. 72.20 + * @return ParserException upon failure. Caller should throw and not ignore 72.21 */ 72.22 - protected final void error(final JSErrorType errorType, final String message, final long errorToken) { 72.23 + protected final ParserException error(final JSErrorType errorType, final String message, final long errorToken) { 72.24 final int position = Token.descPosition(errorToken); 72.25 final int lineNum = source.getLine(position); 72.26 final int columnNum = source.getColumn(position); 72.27 final String formatted = ErrorManager.format(message, source, lineNum, columnNum, errorToken); 72.28 - throw new ParserException(errorType, formatted, source, lineNum, columnNum, errorToken); 72.29 + return new ParserException(errorType, formatted, source, lineNum, columnNum, errorToken); 72.30 } 72.31 72.32 /** 72.33 * Report an error. 72.34 * 72.35 * @param message Error message. 72.36 + * @return ParserException upon failure. Caller should throw and not ignore 72.37 */ 72.38 - protected final void error(final String message) { 72.39 - error(JSErrorType.SYNTAX_ERROR, message); 72.40 + protected final ParserException error(final String message) { 72.41 + return error(JSErrorType.SYNTAX_ERROR, message); 72.42 } 72.43 72.44 /** 72.45 @@ -231,13 +234,14 @@ 72.46 * 72.47 * @param errorType The error type 72.48 * @param message Error message. 72.49 + * @return ParserException upon failure. Caller should throw and not ignore 72.50 */ 72.51 - protected final void error(final JSErrorType errorType, final String message) { 72.52 + protected final ParserException error(final JSErrorType errorType, final String message) { 72.53 // TODO - column needs to account for tabs. 72.54 final int position = Token.descPosition(token); 72.55 final int column = position - linePosition; 72.56 final String formatted = ErrorManager.format(message, source, line, column, token); 72.57 - throw new ParserException(errorType, formatted, source, line, column, token); 72.58 + return new ParserException(errorType, formatted, source, line, column, token); 72.59 } 72.60 72.61 /** 72.62 @@ -270,7 +274,7 @@ 72.63 */ 72.64 protected final void expect(final TokenType expected) throws ParserException { 72.65 if (type != expected) { 72.66 - error(expectMessage(expected)); 72.67 + throw error(expectMessage(expected)); 72.68 } 72.69 72.70 next(); 72.71 @@ -285,7 +289,7 @@ 72.72 */ 72.73 protected final Object expectValue(final TokenType expected) throws ParserException { 72.74 if (type != expected) { 72.75 - error(expectMessage(expected)); 72.76 + throw error(expectMessage(expected)); 72.77 } 72.78 72.79 final Object value = getValue(); 72.80 @@ -429,7 +433,7 @@ 72.81 try { 72.82 RegExpFactory.validate(regex.getExpression(), regex.getOptions()); 72.83 } catch (final ParserException e) { 72.84 - error(e.getMessage()); 72.85 + throw error(e.getMessage()); 72.86 } 72.87 } 72.88 node = LiteralNode.newInstance(source, literalToken, finish, (LexerToken)value);
73.1 --- a/src/jdk/nashorn/internal/parser/JSONParser.java Fri Apr 19 18:23:00 2013 +0530 73.2 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java Fri Apr 19 16:11:16 2013 +0200 73.3 @@ -170,8 +170,7 @@ 73.4 } 73.5 case '"': 73.6 case '\\': 73.7 - error(AbstractParser.message("unexpected.token", str)); 73.8 - break; 73.9 + throw error(AbstractParser.message("unexpected.token", str)); 73.10 } 73.11 } 73.12 73.13 @@ -222,14 +221,12 @@ 73.14 return new UnaryNode(source, literalToken, LiteralNode.newInstance(source, realToken, finish, (Number)value)); 73.15 } 73.16 73.17 - error(AbstractParser.message("expected", "number", type.getNameOrType())); 73.18 - break; 73.19 + throw error(AbstractParser.message("expected", "number", type.getNameOrType())); 73.20 default: 73.21 break; 73.22 } 73.23 73.24 - error(AbstractParser.message("expected", "json literal", type.getNameOrType())); 73.25 - return null; 73.26 + throw error(AbstractParser.message("expected", "json literal", type.getNameOrType())); 73.27 } 73.28 73.29 /** 73.30 @@ -265,7 +262,7 @@ 73.31 elements.add(jsonLiteral()); 73.32 // Comma between array elements is mandatory in JSON. 73.33 if (type != COMMARIGHT && type != RBRACKET) { 73.34 - error(AbstractParser.message("expected", ", or ]", type.getNameOrType())); 73.35 + throw error(AbstractParser.message("expected", ", or ]", type.getNameOrType())); 73.36 } 73.37 break; 73.38 } 73.39 @@ -306,7 +303,7 @@ 73.40 73.41 // Comma between property assigments is mandatory in JSON. 73.42 if (type != RBRACE && type != COMMARIGHT) { 73.43 - error(AbstractParser.message("expected", ", or }", type.getNameOrType())); 73.44 + throw error(AbstractParser.message("expected", ", or }", type.getNameOrType())); 73.45 } 73.46 break; 73.47 } 73.48 @@ -334,13 +331,11 @@ 73.49 if (name != null) { 73.50 expect(COLON); 73.51 final Node value = jsonLiteral(); 73.52 - return new PropertyNode(source, propertyToken, value.getFinish(), name, value); 73.53 + return new PropertyNode(source, propertyToken, value.getFinish(), name, value, null, null); 73.54 } 73.55 73.56 // Raise an error. 73.57 - error(AbstractParser.message("expected", "string", type.getNameOrType())); 73.58 - 73.59 - return null; 73.60 + throw error(AbstractParser.message("expected", "string", type.getNameOrType())); 73.61 } 73.62 73.63 }
74.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Fri Apr 19 18:23:00 2013 +0530 74.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Fri Apr 19 16:11:16 2013 +0200 74.3 @@ -54,24 +54,23 @@ 74.4 import static jdk.nashorn.internal.parser.TokenType.WHILE; 74.5 74.6 import java.util.ArrayList; 74.7 -import java.util.HashMap; 74.8 import java.util.HashSet; 74.9 import java.util.Iterator; 74.10 +import java.util.LinkedHashMap; 74.11 import java.util.List; 74.12 import java.util.Map; 74.13 -import java.util.Stack; 74.14 import jdk.nashorn.internal.codegen.CompilerConstants; 74.15 import jdk.nashorn.internal.codegen.Namespace; 74.16 import jdk.nashorn.internal.ir.AccessNode; 74.17 import jdk.nashorn.internal.ir.BinaryNode; 74.18 import jdk.nashorn.internal.ir.Block; 74.19 +import jdk.nashorn.internal.ir.BlockLexicalContext; 74.20 import jdk.nashorn.internal.ir.BreakNode; 74.21 import jdk.nashorn.internal.ir.BreakableNode; 74.22 import jdk.nashorn.internal.ir.CallNode; 74.23 import jdk.nashorn.internal.ir.CaseNode; 74.24 import jdk.nashorn.internal.ir.CatchNode; 74.25 import jdk.nashorn.internal.ir.ContinueNode; 74.26 -import jdk.nashorn.internal.ir.DoWhileNode; 74.27 import jdk.nashorn.internal.ir.EmptyNode; 74.28 import jdk.nashorn.internal.ir.ExecuteNode; 74.29 import jdk.nashorn.internal.ir.ForNode; 74.30 @@ -84,6 +83,7 @@ 74.31 import jdk.nashorn.internal.ir.LexicalContext; 74.32 import jdk.nashorn.internal.ir.LineNumberNode; 74.33 import jdk.nashorn.internal.ir.LiteralNode; 74.34 +import jdk.nashorn.internal.ir.LoopNode; 74.35 import jdk.nashorn.internal.ir.Node; 74.36 import jdk.nashorn.internal.ir.ObjectNode; 74.37 import jdk.nashorn.internal.ir.PropertyKey; 74.38 @@ -117,9 +117,10 @@ 74.39 /** Is scripting mode. */ 74.40 private final boolean scripting; 74.41 74.42 - private final LexicalContext lexicalContext = new LexicalContext(); 74.43 private List<Node> functionDeclarations; 74.44 74.45 + private final BlockLexicalContext lc = new BlockLexicalContext(); 74.46 + 74.47 /** Namespace for function names where not explicitly given */ 74.48 private final Namespace namespace; 74.49 74.50 @@ -146,7 +147,7 @@ 74.51 */ 74.52 public Parser(final ScriptEnvironment env, final Source source, final ErrorManager errors, final boolean strict) { 74.53 super(source, errors, strict); 74.54 - this.env = env; 74.55 + this.env = env; 74.56 this.namespace = new Namespace(env.getNamespace()); 74.57 this.scripting = env._scripting; 74.58 } 74.59 @@ -162,7 +163,7 @@ 74.60 * @return function node resulting from successful parse 74.61 */ 74.62 public FunctionNode parse() { 74.63 - return parse(RUN_SCRIPT.tag()); 74.64 + return parse(RUN_SCRIPT.symbolName()); 74.65 } 74.66 74.67 /** 74.68 @@ -176,7 +177,7 @@ 74.69 */ 74.70 public FunctionNode parse(final String scriptName) { 74.71 final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L; 74.72 - LOG.info(this + " begin for '" + scriptName + "'"); 74.73 + LOG.info(this, " begin for '", scriptName, "'"); 74.74 74.75 try { 74.76 stream = new TokenStream(); 74.77 @@ -214,7 +215,7 @@ 74.78 final String end = this + " end '" + scriptName + "'"; 74.79 if (Timing.isEnabled()) { 74.80 Timing.accumulateTime(toString(), System.currentTimeMillis() - t0); 74.81 - LOG.info(end + "' in " + (System.currentTimeMillis() - t0) + " ms"); 74.82 + LOG.info(end, "' in ", (System.currentTimeMillis() - t0), " ms"); 74.83 } else { 74.84 LOG.info(end); 74.85 } 74.86 @@ -275,8 +276,7 @@ 74.87 */ 74.88 private Block newBlock() { 74.89 final Block block = new Block(source, token, Token.descPosition(token)); 74.90 - lexicalContext.push(block); 74.91 - return block; 74.92 + return lc.push(block); 74.93 } 74.94 74.95 /** 74.96 @@ -285,36 +285,60 @@ 74.97 * @param ident Name of function. 74.98 * @return New block. 74.99 */ 74.100 - private FunctionNode newFunctionBlock(final IdentNode ident) { 74.101 + private FunctionNode newFunctionNode(final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { 74.102 // Build function name. 74.103 final StringBuilder sb = new StringBuilder(); 74.104 74.105 - final FunctionNode parentFunction = getFunction(); 74.106 - if(parentFunction != null && !parentFunction.isProgram()) { 74.107 + final FunctionNode parentFunction = lc.getCurrentFunction(); 74.108 + if (parentFunction != null && !parentFunction.isProgram()) { 74.109 sb.append(parentFunction.getName()).append('$'); 74.110 } 74.111 74.112 - sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.tag()); 74.113 + sb.append(ident != null ? ident.getName() : FUNCTION_PREFIX.symbolName()); 74.114 final String name = namespace.uniqueName(sb.toString()); 74.115 - assert parentFunction != null || name.equals(RUN_SCRIPT.tag()) : "name = " + name;// must not rename runScript(). 74.116 + assert parentFunction != null || name.equals(RUN_SCRIPT.symbolName()) : "name = " + name;// must not rename runScript(). 74.117 + 74.118 + int flags = 0; 74.119 + if (parentFunction == null) { 74.120 + flags |= FunctionNode.IS_PROGRAM; 74.121 + } 74.122 + if (isStrictMode) { 74.123 + flags |= FunctionNode.IS_STRICT; 74.124 + } 74.125 74.126 // Start new block. 74.127 - final FunctionNode functionBlock = new FunctionNode(source, token, Token.descPosition(token), namespace, ident, name); 74.128 - if(parentFunction == null) { 74.129 - functionBlock.setProgram(); 74.130 - } 74.131 - functionBlock.setStrictMode(isStrictMode); 74.132 - functionBlock.setState(errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 74.133 - lexicalContext.push(functionBlock); 74.134 - 74.135 - return functionBlock; 74.136 + FunctionNode functionNode = 74.137 + new FunctionNode( 74.138 + source, 74.139 + token, 74.140 + Token.descPosition(token), 74.141 + startToken, 74.142 + namespace, 74.143 + ident, 74.144 + name, 74.145 + parameters, 74.146 + kind, 74.147 + flags); 74.148 + 74.149 + functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 74.150 + lc.push(functionNode); 74.151 + // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the 74.152 + // FunctionNode. 74.153 + newBlock(); 74.154 + return functionNode; 74.155 } 74.156 74.157 /** 74.158 * Restore the current block. 74.159 */ 74.160 - private void restoreBlock(Block block) { 74.161 - lexicalContext.pop(block); 74.162 + private Block restoreBlock(final Block block) { 74.163 + return lc.pop(block);//.setFlag(lc, flags); 74.164 + } 74.165 + 74.166 + private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) { 74.167 + final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); 74.168 + 74.169 + return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken); 74.170 } 74.171 74.172 /** 74.173 @@ -323,23 +347,17 @@ 74.174 */ 74.175 private Block getBlock(final boolean needsBraces) { 74.176 // Set up new block. Captures LBRACE. 74.177 - final Block newBlock = newBlock(); 74.178 + Block newBlock = newBlock(); 74.179 try { 74.180 - pushControlNode(newBlock); 74.181 - 74.182 // Block opening brace. 74.183 if (needsBraces) { 74.184 expect(LBRACE); 74.185 } 74.186 - 74.187 - try { 74.188 - // Accumulate block statements. 74.189 - statementList(); 74.190 - } finally { 74.191 - popControlNode(); 74.192 - } 74.193 + // Accumulate block statements. 74.194 + statementList(); 74.195 + 74.196 } finally { 74.197 - restoreBlock(newBlock); 74.198 + newBlock = restoreBlock(newBlock); 74.199 } 74.200 74.201 final int possibleEnd = Token.descPosition(token) + Token.descLength(token); 74.202 @@ -363,15 +381,12 @@ 74.203 return getBlock(true); 74.204 } 74.205 // Set up new block. Captures first token. 74.206 - final Block newBlock = newBlock(); 74.207 - 74.208 + Block newBlock = newBlock(); 74.209 try { 74.210 - // Accumulate statements. 74.211 statement(); 74.212 } finally { 74.213 - restoreBlock(newBlock); 74.214 + newBlock = restoreBlock(newBlock); 74.215 } 74.216 - 74.217 return newBlock; 74.218 } 74.219 74.220 @@ -382,11 +397,8 @@ 74.221 private void detectSpecialFunction(final IdentNode ident) { 74.222 final String name = ident.getName(); 74.223 74.224 - if (EVAL.tag().equals(name)) { 74.225 - final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 74.226 - if(it.hasNext()) { 74.227 - it.next().setHasEval(it); 74.228 - } 74.229 + if (EVAL.symbolName().equals(name)) { 74.230 + markWithOrEval(lc, FunctionNode.HAS_EVAL); 74.231 } 74.232 } 74.233 74.234 @@ -397,8 +409,8 @@ 74.235 private void detectSpecialProperty(final IdentNode ident) { 74.236 final String name = ident.getName(); 74.237 74.238 - if (ARGUMENTS.tag().equals(name)) { 74.239 - getFunction().setUsesArguments(); 74.240 + if (ARGUMENTS.symbolName().equals(name)) { 74.241 + lc.setFlag(lc.getCurrentFunction(), FunctionNode.USES_ARGUMENTS); 74.242 } 74.243 } 74.244 74.245 @@ -439,7 +451,7 @@ 74.246 lhs instanceof IndexNode || 74.247 lhs instanceof IdentNode)) { 74.248 if (env._early_lvalue_error) { 74.249 - error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 74.250 + throw error(JSErrorType.REFERENCE_ERROR, AbstractParser.message("invalid.lvalue"), lhs.getToken()); 74.251 } 74.252 return referenceError(lhs, rhs); 74.253 } 74.254 @@ -469,144 +481,14 @@ 74.255 * @return Reduced expression. 74.256 */ 74.257 private Node incDecExpression(final long firstToken, final TokenType tokenType, final Node expression, final boolean isPostfix) { 74.258 - long incDecToken = firstToken; 74.259 if (isPostfix) { 74.260 - incDecToken = Token.recast(incDecToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX); 74.261 + return new UnaryNode(source, Token.recast(firstToken, tokenType == DECPREFIX ? DECPOSTFIX : INCPOSTFIX), expression.getStart(), Token.descPosition(firstToken) + Token.descLength(firstToken), expression); 74.262 } 74.263 74.264 - final UnaryNode node = new UnaryNode(source, incDecToken, expression); 74.265 - if (isPostfix) { 74.266 - node.setStart(expression.getStart()); 74.267 - node.setFinish(Token.descPosition(incDecToken) + Token.descLength(incDecToken)); 74.268 - } 74.269 - 74.270 - return node; 74.271 + return new UnaryNode(source, firstToken, expression); 74.272 } 74.273 74.274 /** 74.275 - * Find a label node in the label stack. 74.276 - * @param ident Ident to find. 74.277 - * @return null or the found label node. 74.278 - */ 74.279 - private LabelNode findLabel(final IdentNode ident) { 74.280 - for (final LabelNode labelNode : getFunction().getLabelStack()) { 74.281 - if (labelNode.getLabel().equals(ident)) { 74.282 - return labelNode; 74.283 - } 74.284 - } 74.285 - 74.286 - return null; 74.287 - } 74.288 - 74.289 - /** 74.290 - * Add a label to the label stack. 74.291 - * @param labelNode Label to add. 74.292 - */ 74.293 - private void pushLabel(final LabelNode labelNode) { 74.294 - getFunction().getLabelStack().push(labelNode); 74.295 - } 74.296 - 74.297 - /** 74.298 - * Remove a label from the label stack. 74.299 - */ 74.300 - private void popLabel() { 74.301 - getFunction().getLabelStack().pop(); 74.302 - } 74.303 - 74.304 - /** 74.305 - * Track the current nesting of controls for break and continue. 74.306 - * @param node For, while, do or switch node. 74.307 - */ 74.308 - private void pushControlNode(final Node node) { 74.309 - final boolean isLoop = node instanceof WhileNode; 74.310 - final boolean isBreakable = node instanceof BreakableNode || node instanceof Block; 74.311 - final FunctionNode function = getFunction(); 74.312 - function.getControlStack().push(node); 74.313 - 74.314 - for (final LabelNode labelNode : function.getLabelStack()) { 74.315 - if (isBreakable && labelNode.getBreakNode() == null) { 74.316 - labelNode.setBreakNode(node); 74.317 - } 74.318 - 74.319 - if (isLoop && labelNode.getContinueNode() == null) { 74.320 - labelNode.setContinueNode(node); 74.321 - } 74.322 - } 74.323 - } 74.324 - 74.325 - /** 74.326 - * Finish with control. 74.327 - */ 74.328 - private void popControlNode() { 74.329 - // Get control stack. 74.330 - final Stack<Node> controlStack = getFunction().getControlStack(); 74.331 - 74.332 - // Can be empty if missing brace. 74.333 - if (!controlStack.isEmpty()) { 74.334 - controlStack.pop(); 74.335 - } 74.336 - } 74.337 - 74.338 - private void popControlNode(final Node node) { 74.339 - // Get control stack. 74.340 - final Stack<Node> controlStack = getFunction().getControlStack(); 74.341 - 74.342 - // Can be empty if missing brace. 74.343 - if (!controlStack.isEmpty() && controlStack.peek() == node) { 74.344 - controlStack.pop(); 74.345 - } 74.346 - } 74.347 - 74.348 - private boolean isInWithBlock() { 74.349 - final Stack<Node> controlStack = getFunction().getControlStack(); 74.350 - for (int i = controlStack.size() - 1; i >= 0; i--) { 74.351 - final Node node = controlStack.get(i); 74.352 - 74.353 - if (node instanceof WithNode) { 74.354 - return true; 74.355 - } 74.356 - } 74.357 - 74.358 - return false; 74.359 - } 74.360 - 74.361 - private <T extends Node> T findControl(final Class<T> ctype) { 74.362 - final Stack<Node> controlStack = getFunction().getControlStack(); 74.363 - for (int i = controlStack.size() - 1; i >= 0; i--) { 74.364 - final Node node = controlStack.get(i); 74.365 - 74.366 - if (ctype.isAssignableFrom(node.getClass())) { 74.367 - return ctype.cast(node); 74.368 - } 74.369 - } 74.370 - 74.371 - return null; 74.372 - } 74.373 - 74.374 - private <T extends Node> List<T> findControls(final Class<T> ctype, final Node to) { 74.375 - final List<T> nodes = new ArrayList<>(); 74.376 - final Stack<Node> controlStack = getFunction().getControlStack(); 74.377 - for (int i = controlStack.size() - 1; i >= 0; i--) { 74.378 - final Node node = controlStack.get(i); 74.379 - 74.380 - if (to == node) { 74.381 - break; //stop looking 74.382 - } 74.383 - 74.384 - if (ctype.isAssignableFrom(node.getClass())) { 74.385 - nodes.add(ctype.cast(node)); 74.386 - } 74.387 - } 74.388 - 74.389 - return nodes; 74.390 - } 74.391 - 74.392 - private <T extends Node> int countControls(final Class<T> ctype, final Node to) { 74.393 - return findControls(ctype, to).size(); 74.394 - } 74.395 - 74.396 - 74.397 - /** 74.398 * ----------------------------------------------------------------------- 74.399 * 74.400 * Grammar based on 74.401 @@ -630,18 +512,23 @@ 74.402 final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); 74.403 // Set up the script to append elements. 74.404 74.405 - final FunctionNode script = newFunctionBlock(new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName)); 74.406 - 74.407 - script.setKind(FunctionNode.Kind.SCRIPT); 74.408 - script.setFirstToken(functionToken); 74.409 + FunctionNode script = newFunctionNode( 74.410 + functionToken, 74.411 + new IdentNode(source, functionToken, Token.descPosition(functionToken), scriptName), 74.412 + new ArrayList<IdentNode>(), 74.413 + FunctionNode.Kind.SCRIPT); 74.414 + 74.415 functionDeclarations = new ArrayList<>(); 74.416 sourceElements(); 74.417 - script.prependStatements(functionDeclarations); 74.418 + addFunctionDeclarations(script); 74.419 functionDeclarations = null; 74.420 + 74.421 expect(EOF); 74.422 - script.setLastToken(token); 74.423 + 74.424 script.setFinish(source.getLength() - 1); 74.425 74.426 + script = restoreFunctionNode(script, token); //commit code 74.427 + script = script.setBody(lc, script.getBody().setNeedsScope(lc)); 74.428 return script; 74.429 } 74.430 74.431 @@ -670,24 +557,6 @@ 74.432 } 74.433 74.434 /** 74.435 - * Return last node in a statement list. 74.436 - * 74.437 - * @param statements Statement list. 74.438 - * 74.439 - * @return Last (non-debug) statement or null if empty block. 74.440 - */ 74.441 - private static Node lastStatement(final List<Node> statements) { 74.442 - for (int lastIndex = statements.size() - 1; lastIndex >= 0; lastIndex--) { 74.443 - final Node node = statements.get(lastIndex); 74.444 - if (!node.isDebug()) { 74.445 - return node; 74.446 - } 74.447 - } 74.448 - 74.449 - return null; 74.450 - } 74.451 - 74.452 - /** 74.453 * SourceElements : 74.454 * SourceElement 74.455 * SourceElements SourceElement 74.456 @@ -716,7 +585,7 @@ 74.457 // check for directive prologues 74.458 if (checkDirective) { 74.459 // skip any debug statement like line number to get actual first line 74.460 - final Node lastStatement = lastStatement(getBlock().getStatements()); 74.461 + final Node lastStatement = lc.getLastStatement(); 74.462 74.463 // get directive prologue, if any 74.464 final String directive = getDirective(lastStatement); 74.465 @@ -736,8 +605,8 @@ 74.466 // handle use strict directive 74.467 if ("use strict".equals(directive)) { 74.468 isStrictMode = true; 74.469 - final FunctionNode function = getFunction(); 74.470 - function.setStrictMode(true); 74.471 + final FunctionNode function = lc.getCurrentFunction(); 74.472 + lc.setFlag(lc.getCurrentFunction(), FunctionNode.IS_STRICT); 74.473 74.474 // We don't need to check these, if lexical environment is already strict 74.475 if (!oldStrictMode && directiveStmts != null) { 74.476 @@ -759,7 +628,7 @@ 74.477 } 74.478 } 74.479 } catch (final Exception e) { 74.480 - // Recover parsing. 74.481 + //recover parsing 74.482 recover(e); 74.483 } 74.484 74.485 @@ -807,13 +676,15 @@ 74.486 // As per spec (ECMA section 12), function declarations as arbitrary statement 74.487 // is not "portable". Implementation can issue a warning or disallow the same. 74.488 if (isStrictMode && !topLevel) { 74.489 - error(AbstractParser.message("strict.no.func.here"), token); 74.490 + throw error(AbstractParser.message("strict.no.func.here"), token); 74.491 } 74.492 functionExpression(true, topLevel); 74.493 return; 74.494 } 74.495 74.496 - getBlock().addStatement(lineNumberNode); 74.497 + if (lineNumberNode != null) { 74.498 + appendStatement(lineNumberNode); 74.499 + } 74.500 74.501 switch (type) { 74.502 case LBRACE: 74.503 @@ -893,13 +764,9 @@ 74.504 * Parse a statement block. 74.505 */ 74.506 private void block() { 74.507 - // Get statements in block. 74.508 final Block newBlock = getBlock(true); 74.509 - 74.510 // Force block execution. 74.511 - final ExecuteNode executeNode = new ExecuteNode(source, newBlock.getToken(), finish, newBlock); 74.512 - 74.513 - getBlock().addStatement(executeNode); 74.514 + appendStatement(new ExecuteNode(source, newBlock.getToken(), finish, newBlock)); 74.515 } 74.516 74.517 /** 74.518 @@ -942,7 +809,7 @@ 74.519 switch (ident.getName()) { 74.520 case "eval": 74.521 case "arguments": 74.522 - error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 74.523 + throw error(AbstractParser.message("strict.name", ident.getName(), contextString), ident.getToken()); 74.524 default: 74.525 break; 74.526 } 74.527 @@ -995,8 +862,7 @@ 74.528 // Allocate var node. 74.529 final VarNode var = new VarNode(source, varToken, finish, name, init); 74.530 vars.add(var); 74.531 - // Add to current block. 74.532 - getBlock().addStatement(var); 74.533 + appendStatement(var); 74.534 74.535 if (type != COMMARIGHT) { 74.536 break; 74.537 @@ -1009,7 +875,7 @@ 74.538 boolean semicolon = type == SEMICOLON; 74.539 endOfLine(); 74.540 if (semicolon) { 74.541 - getBlock().setFinish(finish); 74.542 + lc.getCurrentBlock().setFinish(finish); 74.543 } 74.544 } 74.545 74.546 @@ -1026,8 +892,7 @@ 74.547 */ 74.548 private void emptyStatement() { 74.549 if (env._empty_statements) { 74.550 - getBlock().addStatement(new EmptyNode(source, token, 74.551 - Token.descPosition(token) + Token.descLength(token))); 74.552 + appendStatement(new EmptyNode(source, token, Token.descPosition(token) + Token.descLength(token))); 74.553 } 74.554 74.555 // SEMICOLON checked in caller. 74.556 @@ -1052,7 +917,7 @@ 74.557 ExecuteNode executeNode = null; 74.558 if (expression != null) { 74.559 executeNode = new ExecuteNode(source, expressionToken, finish, expression); 74.560 - getBlock().addStatement(executeNode); 74.561 + appendStatement(executeNode); 74.562 } else { 74.563 expect(null); 74.564 } 74.565 @@ -1061,7 +926,7 @@ 74.566 74.567 if (executeNode != null) { 74.568 executeNode.setFinish(finish); 74.569 - getBlock().setFinish(finish); 74.570 + lc.getCurrentBlock().setFinish(finish); 74.571 } 74.572 } 74.573 74.574 @@ -1081,29 +946,17 @@ 74.575 next(); 74.576 74.577 expect(LPAREN); 74.578 - 74.579 - // Get the test expression. 74.580 final Node test = expression(); 74.581 - 74.582 expect(RPAREN); 74.583 - 74.584 - // Get the pass statement. 74.585 final Block pass = getStatement(); 74.586 74.587 - // Assume no else. 74.588 Block fail = null; 74.589 - 74.590 if (type == ELSE) { 74.591 next(); 74.592 - 74.593 - // Get the else block. 74.594 fail = getStatement(); 74.595 } 74.596 74.597 - // Construct and add new if node. 74.598 - final IfNode ifNode = new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail); 74.599 - 74.600 - getBlock().addStatement(ifNode); 74.601 + appendStatement(new IfNode(source, ifToken, fail != null ? fail.getFinish() : pass.getFinish(), test, pass, fail)); 74.602 } 74.603 74.604 /** 74.605 @@ -1120,12 +973,12 @@ 74.606 */ 74.607 private void forStatement() { 74.608 // Create FOR node, capturing FOR token. 74.609 - final ForNode forNode = new ForNode(source, token, Token.descPosition(token)); 74.610 - 74.611 - pushControlNode(forNode); 74.612 + ForNode forNode = new ForNode(source, token, Token.descPosition(token), null, null, null, null, ForNode.IS_FOR); 74.613 + 74.614 74.615 // Set up new block for scope of vars. Captures first token. 74.616 - final Block outer = newBlock(); 74.617 + Block outer = newBlock(); 74.618 + lc.push(forNode); 74.619 74.620 try { 74.621 // FOR tested in caller. 74.622 @@ -1134,31 +987,97 @@ 74.623 // Nashorn extension: for each expression. 74.624 // iterate property values rather than property names. 74.625 if (!env._no_syntax_extensions && type == IDENT && "each".equals(getValue())) { 74.626 - forNode.setIsForEach(); 74.627 + forNode = forNode.setIsForEach(lc); 74.628 next(); 74.629 } 74.630 74.631 expect(LPAREN); 74.632 74.633 - /// Capture control information. 74.634 - forControl(forNode); 74.635 + List<VarNode> vars = null; 74.636 + 74.637 + switch (type) { 74.638 + case VAR: 74.639 + // Var statements captured in for outer block. 74.640 + vars = variableStatement(false); 74.641 + break; 74.642 + case SEMICOLON: 74.643 + break; 74.644 + default: 74.645 + final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 74.646 + forNode = forNode.setInit(lc, expression); 74.647 + break; 74.648 + } 74.649 + 74.650 + switch (type) { 74.651 + case SEMICOLON: 74.652 + // for (init; test; modify) 74.653 + expect(SEMICOLON); 74.654 + if (type != SEMICOLON) { 74.655 + forNode = forNode.setTest(lc, expression()); 74.656 + } 74.657 + expect(SEMICOLON); 74.658 + if (type != RPAREN) { 74.659 + forNode = forNode.setModify(lc, expression()); 74.660 + } 74.661 + break; 74.662 + 74.663 + case IN: 74.664 + forNode = forNode.setIsForIn(lc); 74.665 + if (vars != null) { 74.666 + // for (var i in obj) 74.667 + if (vars.size() == 1) { 74.668 + forNode = forNode.setInit(lc, new IdentNode(vars.get(0).getName())); 74.669 + } else { 74.670 + // for (var i, j in obj) is invalid 74.671 + throw error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 74.672 + } 74.673 + 74.674 + } else { 74.675 + // for (expr in obj) 74.676 + final Node init = forNode.getInit(); 74.677 + assert init != null : "for..in init expression can not be null here"; 74.678 + 74.679 + // check if initial expression is a valid L-value 74.680 + if (!(init instanceof AccessNode || 74.681 + init instanceof IndexNode || 74.682 + init instanceof IdentNode)) { 74.683 + throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 74.684 + } 74.685 + 74.686 + if (init instanceof IdentNode) { 74.687 + if (!checkIdentLValue((IdentNode)init)) { 74.688 + throw error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 74.689 + } 74.690 + verifyStrictIdent((IdentNode)init, "for-in iterator"); 74.691 + } 74.692 + } 74.693 + 74.694 + next(); 74.695 + 74.696 + // Get the collection expression. 74.697 + forNode = forNode.setModify(lc, expression()); 74.698 + break; 74.699 + 74.700 + default: 74.701 + expect(SEMICOLON); 74.702 + break; 74.703 + } 74.704 74.705 expect(RPAREN); 74.706 74.707 // Set the for body. 74.708 final Block body = getStatement(); 74.709 - forNode.setBody(body); 74.710 + forNode = forNode.setBody(lc, body); 74.711 forNode.setFinish(body.getFinish()); 74.712 outer.setFinish(body.getFinish()); 74.713 74.714 - // Add for to current block. 74.715 - getBlock().addStatement(forNode); 74.716 + appendStatement(forNode); 74.717 } finally { 74.718 - restoreBlock(outer); 74.719 - popControlNode(); 74.720 + lc.pop(forNode); 74.721 + outer = restoreBlock(outer); 74.722 } 74.723 74.724 - getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 74.725 + appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 74.726 } 74.727 74.728 /** 74.729 @@ -1175,87 +1094,7 @@ 74.730 * comprehensions. 74.731 * @param forNode Owning FOR. 74.732 */ 74.733 - private void forControl(final ForNode forNode) { 74.734 - List<VarNode> vars = null; 74.735 - 74.736 - switch (type) { 74.737 - case VAR: 74.738 - // Var statements captured in for outer block. 74.739 - vars = variableStatement(false); 74.740 - break; 74.741 - 74.742 - case SEMICOLON: 74.743 - break; 74.744 - 74.745 - default: 74.746 - final Node expression = expression(unaryExpression(), COMMARIGHT.getPrecedence(), true); 74.747 - forNode.setInit(expression); 74.748 - } 74.749 - 74.750 - switch (type) { 74.751 - case SEMICOLON: 74.752 - // for (init; test; modify) 74.753 - expect(SEMICOLON); 74.754 - 74.755 - // Get the test expression. 74.756 - if (type != SEMICOLON) { 74.757 - forNode.setTest(expression()); 74.758 - } 74.759 - 74.760 - expect(SEMICOLON); 74.761 - 74.762 - // Get the modify expression. 74.763 - if (type != RPAREN) { 74.764 - final Node expression = expression(); 74.765 - forNode.setModify(expression); 74.766 - } 74.767 - 74.768 - break; 74.769 - 74.770 - case IN: 74.771 - forNode.setIsForIn(); 74.772 - 74.773 - if (vars != null) { 74.774 - // for (var i in obj) 74.775 - if (vars.size() == 1) { 74.776 - forNode.setInit(new IdentNode(vars.get(0).getName())); 74.777 - } else { 74.778 - // for (var i, j in obj) is invalid 74.779 - error(AbstractParser.message("many.vars.in.for.in.loop"), vars.get(1).getToken()); 74.780 - } 74.781 - 74.782 - } else { 74.783 - // for (expr in obj) 74.784 - final Node init = forNode.getInit(); 74.785 - assert init != null : "for..in init expression can not be null here"; 74.786 - 74.787 - // check if initial expression is a valid L-value 74.788 - if (!(init instanceof AccessNode || 74.789 - init instanceof IndexNode || 74.790 - init instanceof IdentNode)) { 74.791 - error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 74.792 - } 74.793 - 74.794 - if (init instanceof IdentNode) { 74.795 - if (!checkIdentLValue((IdentNode)init)) { 74.796 - error(AbstractParser.message("not.lvalue.for.in.loop"), init.getToken()); 74.797 - } 74.798 - verifyStrictIdent((IdentNode)init, "for-in iterator"); 74.799 - } 74.800 - } 74.801 - 74.802 - next(); 74.803 - 74.804 - // Get the collection expression. 74.805 - forNode.setModify(expression()); 74.806 - break; 74.807 - 74.808 - default: 74.809 - expect(SEMICOLON); 74.810 - break; 74.811 - } 74.812 - 74.813 - } 74.814 + 74.815 74.816 /** 74.817 * ...IterationStatement : 74.818 @@ -1274,27 +1113,17 @@ 74.819 next(); 74.820 74.821 // Construct WHILE node. 74.822 - final WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken)); 74.823 - pushControlNode(whileNode); 74.824 + WhileNode whileNode = new WhileNode(source, whileToken, Token.descPosition(whileToken), false); 74.825 + lc.push(whileNode); 74.826 74.827 try { 74.828 expect(LPAREN); 74.829 - 74.830 - // Get the test expression. 74.831 - final Node test = expression(); 74.832 - whileNode.setTest(test); 74.833 - 74.834 + whileNode = whileNode.setTest(lc, expression()); 74.835 expect(RPAREN); 74.836 - 74.837 - // Get WHILE body. 74.838 - final Block statements = getStatement(); 74.839 - whileNode.setBody(statements); 74.840 - whileNode.setFinish(statements.getFinish()); 74.841 - 74.842 - // Add WHILE node. 74.843 - getBlock().addStatement(whileNode); 74.844 + whileNode = whileNode.setBody(lc, getStatement()); 74.845 + appendStatement(whileNode); 74.846 } finally { 74.847 - popControlNode(); 74.848 + lc.pop(whileNode); 74.849 } 74.850 } 74.851 74.852 @@ -1314,34 +1143,25 @@ 74.853 // DO tested in the caller. 74.854 next(); 74.855 74.856 - final WhileNode doWhileNode = new DoWhileNode(source, doToken, Token.descPosition(doToken)); 74.857 - pushControlNode(doWhileNode); 74.858 + WhileNode doWhileNode = new WhileNode(source, doToken, Token.descPosition(doToken), true); 74.859 + lc.push(doWhileNode); 74.860 74.861 try { 74.862 // Get DO body. 74.863 - final Block statements = getStatement(); 74.864 - doWhileNode.setBody(statements); 74.865 + doWhileNode = doWhileNode.setBody(lc, getStatement()); 74.866 74.867 expect(WHILE); 74.868 - 74.869 expect(LPAREN); 74.870 - 74.871 - // Get the test expression. 74.872 - final Node test = expression(); 74.873 - doWhileNode.setTest(test); 74.874 - 74.875 + doWhileNode = doWhileNode.setTest(lc, expression()); 74.876 expect(RPAREN); 74.877 74.878 if (type == SEMICOLON) { 74.879 endOfLine(); 74.880 } 74.881 - 74.882 doWhileNode.setFinish(finish); 74.883 - 74.884 - // Add DO node. 74.885 - getBlock().addStatement(doWhileNode); 74.886 + appendStatement(doWhileNode); 74.887 } finally { 74.888 - popControlNode(); 74.889 + lc.pop(doWhileNode); 74.890 } 74.891 } 74.892 74.893 @@ -1370,28 +1190,26 @@ 74.894 74.895 default: 74.896 final IdentNode ident = getIdent(); 74.897 - labelNode = findLabel(ident); 74.898 + labelNode = lc.findLabel(ident.getName()); 74.899 74.900 if (labelNode == null) { 74.901 - error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 74.902 + throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 74.903 } 74.904 74.905 break; 74.906 } 74.907 74.908 - final Node targetNode = labelNode != null ? labelNode.getContinueNode() : findControl(WhileNode.class); 74.909 + final IdentNode label = labelNode == null ? null : labelNode.getLabel(); 74.910 + final LoopNode targetNode = lc.getContinueTo(label); 74.911 74.912 if (targetNode == null) { 74.913 - error(AbstractParser.message("illegal.continue.stmt"), continueToken); 74.914 + throw error(AbstractParser.message("illegal.continue.stmt"), continueToken); 74.915 } 74.916 74.917 endOfLine(); 74.918 74.919 // Construct and add CONTINUE node. 74.920 - final ContinueNode continueNode = new ContinueNode(source, continueToken, finish, labelNode, targetNode, findControl(TryNode.class)); 74.921 - continueNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); 74.922 - 74.923 - getBlock().addStatement(continueNode); 74.924 + appendStatement(new ContinueNode(source, continueToken, finish, label == null ? null : new IdentNode(label))); 74.925 } 74.926 74.927 /** 74.928 @@ -1418,28 +1236,27 @@ 74.929 74.930 default: 74.931 final IdentNode ident = getIdent(); 74.932 - labelNode = findLabel(ident); 74.933 + labelNode = lc.findLabel(ident.getName()); 74.934 74.935 if (labelNode == null) { 74.936 - error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 74.937 + throw error(AbstractParser.message("undefined.label", ident.getName()), ident.getToken()); 74.938 } 74.939 74.940 break; 74.941 } 74.942 74.943 - final Node targetNode = labelNode != null ? labelNode.getBreakNode() : findControl(BreakableNode.class); 74.944 - 74.945 + //either an explicit label - then get its node or just a "break" - get first breakable 74.946 + //targetNode is what we are breaking out from. 74.947 + final IdentNode label = labelNode == null ? null : labelNode.getLabel(); 74.948 + final BreakableNode targetNode = lc.getBreakable(label); 74.949 if (targetNode == null) { 74.950 - error(AbstractParser.message("illegal.break.stmt"), breakToken); 74.951 + throw error(AbstractParser.message("illegal.break.stmt"), breakToken); 74.952 } 74.953 74.954 endOfLine(); 74.955 74.956 // Construct and add BREAK node. 74.957 - final BreakNode breakNode = new BreakNode(source, breakToken, finish, labelNode, targetNode, findControl(TryNode.class)); 74.958 - breakNode.setScopeNestingLevel(countControls(WithNode.class, targetNode)); 74.959 - 74.960 - getBlock().addStatement(breakNode); 74.961 + appendStatement(new BreakNode(source, breakToken, finish, label == null ? null : new IdentNode(label))); 74.962 } 74.963 74.964 /** 74.965 @@ -1452,8 +1269,8 @@ 74.966 */ 74.967 private void returnStatement() { 74.968 // check for return outside function 74.969 - if (getFunction().getKind() == FunctionNode.Kind.SCRIPT) { 74.970 - error(AbstractParser.message("invalid.return")); 74.971 + if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) { 74.972 + throw error(AbstractParser.message("invalid.return")); 74.973 } 74.974 74.975 // Capture RETURN token. 74.976 @@ -1478,8 +1295,7 @@ 74.977 endOfLine(); 74.978 74.979 // Construct and add RETURN node. 74.980 - final ReturnNode returnNode = new ReturnNode(source, returnToken, finish, expression, findControl(TryNode.class)); 74.981 - getBlock().addStatement(returnNode); 74.982 + appendStatement(new ReturnNode(source, returnToken, finish, expression)); 74.983 } 74.984 74.985 /** 74.986 @@ -1513,8 +1329,7 @@ 74.987 endOfLine(); 74.988 74.989 // Construct and add YIELD node. 74.990 - final ReturnNode yieldNode = new ReturnNode(source, yieldToken, finish, expression, findControl(TryNode.class)); 74.991 - getBlock().addStatement(yieldNode); 74.992 + appendStatement(new ReturnNode(source, yieldToken, finish, expression)); 74.993 } 74.994 74.995 /** 74.996 @@ -1533,35 +1348,24 @@ 74.997 74.998 // ECMA 12.10.1 strict mode restrictions 74.999 if (isStrictMode) { 74.1000 - error(AbstractParser.message("strict.no.with"), withToken); 74.1001 + throw error(AbstractParser.message("strict.no.with"), withToken); 74.1002 } 74.1003 74.1004 // Get WITH expression. 74.1005 - final WithNode withNode = new WithNode(source, withToken, finish, null, null); 74.1006 - final Iterator<FunctionNode> it = lexicalContext.getFunctions(); 74.1007 - if(it.hasNext()) { 74.1008 - it.next().setHasWith(it); 74.1009 + WithNode withNode = new WithNode(source, withToken, finish); 74.1010 + markWithOrEval(lc, FunctionNode.HAS_WITH); 74.1011 + 74.1012 + try { 74.1013 + lc.push(withNode); 74.1014 + expect(LPAREN); 74.1015 + withNode = withNode.setExpression(lc, expression()); 74.1016 + expect(RPAREN); 74.1017 + withNode = withNode.setBody(lc, getStatement()); 74.1018 + } finally { 74.1019 + lc.pop(withNode); 74.1020 } 74.1021 74.1022 - try { 74.1023 - pushControlNode(withNode); 74.1024 - 74.1025 - expect(LPAREN); 74.1026 - 74.1027 - final Node expression = expression(); 74.1028 - withNode.setExpression(expression); 74.1029 - 74.1030 - expect(RPAREN); 74.1031 - 74.1032 - // Get WITH body. 74.1033 - final Block statements = getStatement(); 74.1034 - withNode.setBody(statements); 74.1035 - withNode.setFinish(finish); 74.1036 - } finally { 74.1037 - popControlNode(withNode); 74.1038 - } 74.1039 - 74.1040 - getBlock().addStatement(withNode); 74.1041 + appendStatement(withNode); 74.1042 } 74.1043 74.1044 /** 74.1045 @@ -1587,22 +1391,17 @@ 74.1046 * Parse SWITCH statement. 74.1047 */ 74.1048 private void switchStatement() { 74.1049 - // Capture SWITCH token. 74.1050 final long switchToken = token; 74.1051 // SWITCH tested in caller. 74.1052 next(); 74.1053 74.1054 // Create and add switch statement. 74.1055 - final SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken)); 74.1056 - pushControlNode(switchNode); 74.1057 + SwitchNode switchNode = new SwitchNode(source, switchToken, Token.descPosition(switchToken), null, new ArrayList<CaseNode>(), null); 74.1058 + lc.push(switchNode); 74.1059 74.1060 try { 74.1061 expect(LPAREN); 74.1062 - 74.1063 - // Get switch expression. 74.1064 - final Node switchExpression = expression(); 74.1065 - switchNode.setExpression(switchExpression); 74.1066 - 74.1067 + switchNode = switchNode.setExpression(lc, expression()); 74.1068 expect(RPAREN); 74.1069 74.1070 expect(LBRACE); 74.1071 @@ -1619,19 +1418,14 @@ 74.1072 switch (type) { 74.1073 case CASE: 74.1074 next(); 74.1075 - 74.1076 - // Get case expression. 74.1077 caseExpression = expression(); 74.1078 - 74.1079 break; 74.1080 74.1081 case DEFAULT: 74.1082 if (defaultCase != null) { 74.1083 - error(AbstractParser.message("duplicate.default.in.switch")); 74.1084 + throw error(AbstractParser.message("duplicate.default.in.switch")); 74.1085 } 74.1086 - 74.1087 next(); 74.1088 - 74.1089 break; 74.1090 74.1091 default: 74.1092 @@ -1654,16 +1448,13 @@ 74.1093 cases.add(caseNode); 74.1094 } 74.1095 74.1096 - switchNode.setCases(cases); 74.1097 - switchNode.setDefaultCase(defaultCase); 74.1098 - 74.1099 + switchNode = switchNode.setCases(lc, cases, defaultCase); 74.1100 next(); 74.1101 - 74.1102 switchNode.setFinish(finish); 74.1103 74.1104 - getBlock().addStatement(switchNode); 74.1105 + appendStatement(switchNode); 74.1106 } finally { 74.1107 - popControlNode(); 74.1108 + lc.pop(switchNode); 74.1109 } 74.1110 } 74.1111 74.1112 @@ -1683,23 +1474,19 @@ 74.1113 74.1114 expect(COLON); 74.1115 74.1116 - if (findLabel(ident) != null) { 74.1117 - error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 74.1118 + if (lc.findLabel(ident.getName()) != null) { 74.1119 + throw error(AbstractParser.message("duplicate.label", ident.getName()), labelToken); 74.1120 } 74.1121 74.1122 + LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); 74.1123 try { 74.1124 - // Create and add label. 74.1125 - final LabelNode labelNode = new LabelNode(source, labelToken, finish, ident, null); 74.1126 - pushLabel(labelNode); 74.1127 - // Get and save body. 74.1128 - final Block statements = getStatement(); 74.1129 - labelNode.setBody(statements); 74.1130 + lc.push(labelNode); 74.1131 + labelNode = labelNode.setBody(lc, getStatement()); 74.1132 labelNode.setFinish(finish); 74.1133 - 74.1134 - getBlock().addStatement(labelNode); 74.1135 + appendStatement(labelNode); 74.1136 } finally { 74.1137 - // Remove label. 74.1138 - popLabel(); 74.1139 + assert lc.peek() instanceof LabelNode; 74.1140 + lc.pop(labelNode); 74.1141 } 74.1142 } 74.1143 74.1144 @@ -1732,14 +1519,12 @@ 74.1145 } 74.1146 74.1147 if (expression == null) { 74.1148 - error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1149 + throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1150 } 74.1151 74.1152 endOfLine(); 74.1153 74.1154 - // Construct and add THROW node. 74.1155 - final ThrowNode throwNode = new ThrowNode(source, throwToken, finish, expression, findControl(TryNode.class)); 74.1156 - getBlock().addStatement(throwNode); 74.1157 + appendStatement(new ThrowNode(source, throwToken, finish, expression)); 74.1158 } 74.1159 74.1160 /** 74.1161 @@ -1766,28 +1551,18 @@ 74.1162 next(); 74.1163 74.1164 // Container block needed to act as target for labeled break statements 74.1165 - final Block outer = newBlock(); 74.1166 - pushControlNode(outer); 74.1167 + Block outer = newBlock(); 74.1168 74.1169 // Create try. 74.1170 - final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), findControl(TryNode.class)); 74.1171 - pushControlNode(tryNode); 74.1172 74.1173 try { 74.1174 - // Get TRY body. 74.1175 - final Block tryBody = getBlock(true); 74.1176 - 74.1177 - // Prepare to accumulate catches. 74.1178 + final Block tryBody = getBlock(true); 74.1179 final List<Block> catchBlocks = new ArrayList<>(); 74.1180 74.1181 while (type == CATCH) { 74.1182 - // Capture CATCH token. 74.1183 final long catchToken = token; 74.1184 next(); 74.1185 - 74.1186 expect(LPAREN); 74.1187 - 74.1188 - // Get exception ident. 74.1189 final IdentNode exception = getIdent(); 74.1190 74.1191 // ECMA 12.4.1 strict mode restrictions 74.1192 @@ -1795,28 +1570,23 @@ 74.1193 74.1194 // Check for conditional catch. 74.1195 Node ifExpression = null; 74.1196 - 74.1197 if (type == IF) { 74.1198 next(); 74.1199 - 74.1200 // Get the exception condition. 74.1201 ifExpression = expression(); 74.1202 } 74.1203 74.1204 expect(RPAREN); 74.1205 74.1206 - final Block catchBlock = newBlock(); 74.1207 + Block catchBlock = newBlock(); 74.1208 try { 74.1209 - 74.1210 // Get CATCH body. 74.1211 final Block catchBody = getBlock(true); 74.1212 - 74.1213 - // Create and add catch. 74.1214 final CatchNode catchNode = new CatchNode(source, catchToken, finish, exception, ifExpression, catchBody); 74.1215 - getBlock().addStatement(catchNode); 74.1216 + appendStatement(catchNode); 74.1217 + } finally { 74.1218 + catchBlock = restoreBlock(catchBlock); 74.1219 catchBlocks.add(catchBlock); 74.1220 - } finally { 74.1221 - restoreBlock(catchBlock); 74.1222 } 74.1223 74.1224 // If unconditional catch then should to be the end. 74.1225 @@ -1825,38 +1595,32 @@ 74.1226 } 74.1227 } 74.1228 74.1229 - popControlNode(); 74.1230 - 74.1231 // Prepare to capture finally statement. 74.1232 Block finallyStatements = null; 74.1233 74.1234 if (type == FINALLY) { 74.1235 next(); 74.1236 - 74.1237 - // Get FINALLY body. 74.1238 finallyStatements = getBlock(true); 74.1239 } 74.1240 74.1241 // Need at least one catch or a finally. 74.1242 if (catchBlocks.isEmpty() && finallyStatements == null) { 74.1243 - error(AbstractParser.message("missing.catch.or.finally"), tryToken); 74.1244 + throw error(AbstractParser.message("missing.catch.or.finally"), tryToken); 74.1245 } 74.1246 74.1247 - tryNode.setBody(tryBody); 74.1248 - tryNode.setCatchBlocks(catchBlocks); 74.1249 - tryNode.setFinallyBody(finallyStatements); 74.1250 + final TryNode tryNode = new TryNode(source, tryToken, Token.descPosition(tryToken), tryBody, catchBlocks, finallyStatements); 74.1251 + // Add try. 74.1252 + assert lc.peek() == outer; 74.1253 + appendStatement(tryNode); 74.1254 + 74.1255 tryNode.setFinish(finish); 74.1256 outer.setFinish(finish); 74.1257 74.1258 - // Add try. 74.1259 - outer.addStatement(tryNode); 74.1260 } finally { 74.1261 - popControlNode(tryNode); 74.1262 - restoreBlock(outer); 74.1263 - popControlNode(outer); 74.1264 + outer = restoreBlock(outer); 74.1265 } 74.1266 74.1267 - getBlock().addStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 74.1268 + appendStatement(new ExecuteNode(source, outer.getToken(), outer.getFinish(), outer)); 74.1269 } 74.1270 74.1271 /** 74.1272 @@ -1872,11 +1636,8 @@ 74.1273 final long debuggerToken = token; 74.1274 // DEBUGGER tested in caller. 74.1275 next(); 74.1276 - 74.1277 endOfLine(); 74.1278 - 74.1279 - final RuntimeNode runtimeNode = new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>()); 74.1280 - getBlock().addStatement(runtimeNode); 74.1281 + appendStatement(new RuntimeNode(source, debuggerToken, finish, RuntimeNode.Request.DEBUGGER, new ArrayList<Node>())); 74.1282 } 74.1283 74.1284 /** 74.1285 @@ -1912,7 +1673,7 @@ 74.1286 return ident; 74.1287 case OCTAL: 74.1288 if (isStrictMode) { 74.1289 - error(AbstractParser.message("strict.no.octal"), token); 74.1290 + throw error(AbstractParser.message("strict.no.octal"), token); 74.1291 } 74.1292 case STRING: 74.1293 case ESCSTRING: 74.1294 @@ -1981,7 +1742,7 @@ 74.1295 // Skip ending of edit string expression. 74.1296 expect(RBRACE); 74.1297 74.1298 - return new CallNode(source, primaryToken, finish, execIdent, arguments); 74.1299 + return new CallNode(source, primaryToken, finish, execIdent, arguments, 0); 74.1300 } 74.1301 74.1302 /** 74.1303 @@ -2036,7 +1797,7 @@ 74.1304 74.1305 default: 74.1306 if (!elision) { 74.1307 - error(AbstractParser.message("expected.comma", type.getNameOrType())); 74.1308 + throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 74.1309 } 74.1310 // Add expression element. 74.1311 final Node expression = assignmentExpression(false); 74.1312 @@ -2077,8 +1838,8 @@ 74.1313 74.1314 // Object context. 74.1315 // Prepare to accumulate elements. 74.1316 - final List<Node> elements = new ArrayList<>(); 74.1317 - final Map<Object, PropertyNode> map = new HashMap<>(); 74.1318 + // final List<Node> elements = new ArrayList<>(); 74.1319 + final Map<String, PropertyNode> map = new LinkedHashMap<>(); 74.1320 74.1321 // Create a block for the object literal. 74.1322 boolean commaSeen = true; 74.1323 @@ -2096,25 +1857,30 @@ 74.1324 74.1325 default: 74.1326 if (!commaSeen) { 74.1327 - error(AbstractParser.message("expected.comma", type.getNameOrType())); 74.1328 - } 74.1329 - 74.1330 - commaSeen = false; 74.1331 - // Get and add the next property. 74.1332 - final PropertyNode property = propertyAssignment(); 74.1333 - final Object key = property.getKeyName(); 74.1334 - final PropertyNode existingProperty = map.get(key); 74.1335 - 74.1336 - if (existingProperty != null) { 74.1337 + throw error(AbstractParser.message("expected.comma", type.getNameOrType())); 74.1338 + } 74.1339 + 74.1340 + commaSeen = false; 74.1341 + // Get and add the next property. 74.1342 + final PropertyNode property = propertyAssignment(); 74.1343 + final String key = property.getKeyName(); 74.1344 + final PropertyNode existingProperty = map.get(key); 74.1345 + 74.1346 + if (existingProperty == null) { 74.1347 + map.put(key, property); 74.1348 + // elements.add(property); 74.1349 + break; 74.1350 + } 74.1351 + 74.1352 // ECMA section 11.1.5 Object Initialiser 74.1353 // point # 4 on property assignment production 74.1354 - final Node value = property.getValue(); 74.1355 - final Node getter = property.getGetter(); 74.1356 - final Node setter = property.getSetter(); 74.1357 - 74.1358 - final Node prevValue = existingProperty.getValue(); 74.1359 - final Node prevGetter = existingProperty.getGetter(); 74.1360 - final Node prevSetter = existingProperty.getSetter(); 74.1361 + final Node value = property.getValue(); 74.1362 + final FunctionNode getter = property.getGetter(); 74.1363 + final FunctionNode setter = property.getSetter(); 74.1364 + 74.1365 + final Node prevValue = existingProperty.getValue(); 74.1366 + final FunctionNode prevGetter = existingProperty.getGetter(); 74.1367 + final FunctionNode prevSetter = existingProperty.getSetter(); 74.1368 74.1369 boolean redefinitionOk = true; 74.1370 // ECMA 11.1.5 strict mode restrictions 74.1371 @@ -2125,7 +1891,7 @@ 74.1372 } 74.1373 74.1374 final boolean isPrevAccessor = prevGetter != null || prevSetter != null; 74.1375 - final boolean isAccessor = getter != null || setter != null; 74.1376 + final boolean isAccessor = getter != null || setter != null; 74.1377 74.1378 // data property redefined as accessor property 74.1379 if (prevValue != null && isAccessor) { 74.1380 @@ -2145,40 +1911,33 @@ 74.1381 } 74.1382 74.1383 if (!redefinitionOk) { 74.1384 - error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); 74.1385 + throw error(AbstractParser.message("property.redefinition", key.toString()), property.getToken()); 74.1386 } 74.1387 74.1388 + PropertyNode newProperty = existingProperty; 74.1389 if (value != null) { 74.1390 - final Node existingValue = existingProperty.getValue(); 74.1391 - 74.1392 - if (existingValue == null) { 74.1393 - existingProperty.setValue(value); 74.1394 + if (prevValue == null) { 74.1395 + map.put(key, newProperty = newProperty.setValue(value)); 74.1396 } else { 74.1397 - final long propertyToken = Token.recast(existingProperty.getToken(), COMMARIGHT); 74.1398 - existingProperty.setValue(new BinaryNode(source, propertyToken, existingValue, value)); 74.1399 + final long propertyToken = Token.recast(newProperty.getToken(), COMMARIGHT); 74.1400 + map.put(key, newProperty = newProperty.setValue(new BinaryNode(source, propertyToken, prevValue, value))); 74.1401 } 74.1402 74.1403 - existingProperty.setGetter(null); 74.1404 - existingProperty.setSetter(null); 74.1405 + map.put(key, newProperty = newProperty.setGetter(null).setSetter(null)); 74.1406 } 74.1407 74.1408 if (getter != null) { 74.1409 - existingProperty.setGetter(getter); 74.1410 + map.put(key, newProperty = newProperty.setGetter(getter)); 74.1411 } 74.1412 74.1413 if (setter != null) { 74.1414 - existingProperty.setSetter(setter); 74.1415 + map.put(key, newProperty = newProperty.setSetter(setter)); 74.1416 } 74.1417 - } else { 74.1418 - map.put(key, property); 74.1419 - elements.add(property); 74.1420 - } 74.1421 - 74.1422 - break; 74.1423 + break; 74.1424 } 74.1425 } 74.1426 74.1427 - return new ObjectNode(source, objectToken, finish, elements); 74.1428 + return new ObjectNode(source, objectToken, finish, new ArrayList<Node>(map.values())); 74.1429 } 74.1430 74.1431 /** 74.1432 @@ -2198,7 +1957,7 @@ 74.1433 return getIdent(); 74.1434 case OCTAL: 74.1435 if (isStrictMode) { 74.1436 - error(AbstractParser.message("strict.no.octal"), token); 74.1437 + throw error(AbstractParser.message("strict.no.octal"), token); 74.1438 } 74.1439 case STRING: 74.1440 case ESCSTRING: 74.1441 @@ -2235,8 +1994,6 @@ 74.1442 final long propertyToken = token; 74.1443 74.1444 FunctionNode functionNode; 74.1445 - List<IdentNode> parameters; 74.1446 - PropertyNode propertyNode; 74.1447 PropertyKey propertyName; 74.1448 74.1449 if (type == IDENT) { 74.1450 @@ -2253,11 +2010,8 @@ 74.1451 final IdentNode getNameNode = new IdentNode(source, ((Node)getIdent).getToken(), finish, "get " + getterName); 74.1452 expect(LPAREN); 74.1453 expect(RPAREN); 74.1454 - parameters = new ArrayList<>(); 74.1455 - functionNode = functionBody(getSetToken, getNameNode, parameters, FunctionNode.Kind.GETTER); 74.1456 - propertyNode = new PropertyNode(source, propertyToken, finish, getIdent, null); 74.1457 - propertyNode.setGetter(functionNode); 74.1458 - return propertyNode; 74.1459 + functionNode = functionBody(getSetToken, getNameNode, new ArrayList<IdentNode>(), FunctionNode.Kind.GETTER); 74.1460 + return new PropertyNode(source, propertyToken, finish, getIdent, null, functionNode, null); 74.1461 74.1462 case "set": 74.1463 final PropertyKey setIdent = propertyName(); 74.1464 @@ -2267,12 +2021,10 @@ 74.1465 final IdentNode argIdent = getIdent(); 74.1466 verifyStrictIdent(argIdent, "setter argument"); 74.1467 expect(RPAREN); 74.1468 - parameters = new ArrayList<>(); 74.1469 + List<IdentNode> parameters = new ArrayList<>(); 74.1470 parameters.add(argIdent); 74.1471 functionNode = functionBody(getSetToken, setNameNode, parameters, FunctionNode.Kind.SETTER); 74.1472 - propertyNode = new PropertyNode(source, propertyToken, finish, setIdent, null); 74.1473 - propertyNode.setSetter(functionNode); 74.1474 - return propertyNode; 74.1475 + return new PropertyNode(source, propertyToken, finish, setIdent, null, null, functionNode); 74.1476 74.1477 default: 74.1478 break; 74.1479 @@ -2286,9 +2038,11 @@ 74.1480 74.1481 expect(COLON); 74.1482 74.1483 - final Node value = assignmentExpression(false); 74.1484 - propertyNode = new PropertyNode(source, propertyToken, finish, propertyName, value); 74.1485 - return propertyNode; 74.1486 + return new PropertyNode(source, propertyToken, finish, propertyName, assignmentExpression(false), null, null); 74.1487 + } 74.1488 + 74.1489 + private int callNodeFlags() { 74.1490 + return lc.inWith() ? CallNode.IN_WITH_BLOCK : 0; 74.1491 } 74.1492 74.1493 /** 74.1494 @@ -2320,10 +2074,7 @@ 74.1495 detectSpecialFunction((IdentNode)lhs); 74.1496 } 74.1497 74.1498 - lhs = new CallNode(source, callToken, finish, lhs, arguments); 74.1499 - if (isInWithBlock()) { 74.1500 - ((CallNode)lhs).setInWithBlock(); 74.1501 - } 74.1502 + lhs = new CallNode(source, callToken, finish, lhs, arguments, callNodeFlags()); 74.1503 } 74.1504 74.1505 loop: 74.1506 @@ -2337,10 +2088,7 @@ 74.1507 final List<Node> arguments = argumentList(); 74.1508 74.1509 // Create call node. 74.1510 - lhs = new CallNode(source, callToken, finish, lhs, arguments); 74.1511 - if (isInWithBlock()) { 74.1512 - ((CallNode)lhs).setInWithBlock(); 74.1513 - } 74.1514 + lhs = new CallNode(source, callToken, finish, lhs, arguments, callNodeFlags()); 74.1515 74.1516 break; 74.1517 74.1518 @@ -2419,10 +2167,7 @@ 74.1519 arguments.add(objectLiteral()); 74.1520 } 74.1521 74.1522 - final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments); 74.1523 - if (isInWithBlock()) { 74.1524 - callNode.setInWithBlock(); 74.1525 - } 74.1526 + final CallNode callNode = new CallNode(source, constructor.getToken(), finish, constructor, arguments, callNodeFlags()); 74.1527 74.1528 return new UnaryNode(source, newToken, callNode); 74.1529 } 74.1530 @@ -2482,8 +2227,7 @@ 74.1531 74.1532 case PERIOD: 74.1533 if (lhs == null) { 74.1534 - error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1535 - return null; 74.1536 + throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1537 } 74.1538 74.1539 next(); 74.1540 @@ -2585,29 +2329,27 @@ 74.1541 } 74.1542 74.1543 expect(LPAREN); 74.1544 - 74.1545 final List<IdentNode> parameters = formalParameterList(); 74.1546 - 74.1547 expect(RPAREN); 74.1548 74.1549 - final FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); 74.1550 + FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL); 74.1551 74.1552 if (isStatement) { 74.1553 - if(topLevel) { 74.1554 - functionNode.setIsDeclared(); 74.1555 + if (topLevel) { 74.1556 + functionNode = functionNode.setFlag(lc, FunctionNode.IS_DECLARED); 74.1557 } 74.1558 - if(ARGUMENTS.tag().equals(name.getName())) { 74.1559 - getFunction().setDefinesArguments(); 74.1560 + if (ARGUMENTS.symbolName().equals(name.getName())) { 74.1561 + functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 74.1562 } 74.1563 } 74.1564 74.1565 if (isAnonymous) { 74.1566 - functionNode.setIsAnonymous(); 74.1567 + functionNode = functionNode.setFlag(lc, FunctionNode.IS_ANONYMOUS); 74.1568 } 74.1569 74.1570 final int arity = parameters.size(); 74.1571 74.1572 - final boolean strict = functionNode.isStrictMode(); 74.1573 + final boolean strict = functionNode.isStrict(); 74.1574 if (arity > 1) { 74.1575 final HashSet<String> parametersSet = new HashSet<>(arity); 74.1576 74.1577 @@ -2615,39 +2357,37 @@ 74.1578 final IdentNode parameter = parameters.get(i); 74.1579 String parameterName = parameter.getName(); 74.1580 74.1581 - if (ARGUMENTS.tag().equals(parameterName)) { 74.1582 - functionNode.setDefinesArguments(); 74.1583 + if (ARGUMENTS.symbolName().equals(parameterName)) { 74.1584 + functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 74.1585 } 74.1586 74.1587 if (parametersSet.contains(parameterName)) { 74.1588 // redefinition of parameter name 74.1589 if (strict) { 74.1590 - error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 74.1591 - } else { 74.1592 - // rename in non-strict mode 74.1593 - parameterName = functionNode.uniqueName(parameterName); 74.1594 - final long parameterToken = parameter.getToken(); 74.1595 - parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 74.1596 + throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken()); 74.1597 } 74.1598 + // rename in non-strict mode 74.1599 + parameterName = functionNode.uniqueName(parameterName); 74.1600 + final long parameterToken = parameter.getToken(); 74.1601 + parameters.set(i, new IdentNode(source, parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName))); 74.1602 } 74.1603 74.1604 parametersSet.add(parameterName); 74.1605 } 74.1606 } else if (arity == 1) { 74.1607 - if (ARGUMENTS.tag().equals(parameters.get(0).getName())) { 74.1608 - functionNode.setDefinesArguments(); 74.1609 + if (ARGUMENTS.symbolName().equals(parameters.get(0).getName())) { 74.1610 + functionNode = functionNode.setFlag(lc, FunctionNode.DEFINES_ARGUMENTS); 74.1611 } 74.1612 } 74.1613 74.1614 if (isStatement) { 74.1615 - final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, true); 74.1616 - if(topLevel) { 74.1617 + final VarNode varNode = new VarNode(source, functionToken, finish, name, functionNode, VarNode.IS_STATEMENT); 74.1618 + if (topLevel) { 74.1619 functionDeclarations.add(lineNumber); 74.1620 functionDeclarations.add(varNode); 74.1621 } else { 74.1622 - final Block block = getBlock(); 74.1623 - block.addStatement(lineNumber); 74.1624 - block.addStatement(varNode); 74.1625 + appendStatement(lineNumber); 74.1626 + appendStatement(varNode); 74.1627 } 74.1628 } 74.1629 74.1630 @@ -2701,13 +2441,11 @@ 74.1631 */ 74.1632 private FunctionNode functionBody(final long firstToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind) { 74.1633 FunctionNode functionNode = null; 74.1634 + long lastToken = 0L; 74.1635 74.1636 try { 74.1637 // Create a new function block. 74.1638 - functionNode = newFunctionBlock(ident); 74.1639 - functionNode.setParameters(parameters); 74.1640 - functionNode.setKind(kind); 74.1641 - functionNode.setFirstToken(firstToken); 74.1642 + functionNode = newFunctionNode(firstToken, ident, parameters, kind); 74.1643 74.1644 // Nashorn extension: expression closures 74.1645 if (!env._no_syntax_extensions && type != LBRACE) { 74.1646 @@ -2720,14 +2458,12 @@ 74.1647 74.1648 // just expression as function body 74.1649 final Node expr = expression(); 74.1650 - 74.1651 + assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode); 74.1652 // create a return statement - this creates code in itself and does not need to be 74.1653 // wrapped into an ExecuteNode 74.1654 - final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr, null); 74.1655 - 74.1656 - // add the return statement 74.1657 - functionNode.addStatement(returnNode); 74.1658 - functionNode.setLastToken(token); 74.1659 + final ReturnNode returnNode = new ReturnNode(source, expr.getToken(), finish, expr); 74.1660 + appendStatement(returnNode); 74.1661 + lastToken = token; 74.1662 functionNode.setFinish(Token.descPosition(token) + Token.descLength(token)); 74.1663 74.1664 } else { 74.1665 @@ -2738,23 +2474,35 @@ 74.1666 functionDeclarations = new ArrayList<>(); 74.1667 try { 74.1668 sourceElements(); 74.1669 - functionNode.prependStatements(functionDeclarations); 74.1670 + addFunctionDeclarations(functionNode); 74.1671 } finally { 74.1672 functionDeclarations = prevFunctionDecls; 74.1673 } 74.1674 74.1675 - functionNode.setLastToken(token); 74.1676 + lastToken = token; 74.1677 expect(RBRACE); 74.1678 functionNode.setFinish(finish); 74.1679 74.1680 } 74.1681 } finally { 74.1682 - restoreBlock(functionNode); 74.1683 + functionNode = restoreFunctionNode(functionNode, lastToken); 74.1684 } 74.1685 - 74.1686 return functionNode; 74.1687 } 74.1688 74.1689 + private void addFunctionDeclarations(final FunctionNode functionNode) { 74.1690 + assert lc.peek() == lc.getFunctionBody(functionNode); 74.1691 + VarNode lastDecl = null; 74.1692 + for (int i = functionDeclarations.size() - 1; i >= 0; i--) { 74.1693 + Node decl = functionDeclarations.get(i); 74.1694 + if (lastDecl == null && decl instanceof VarNode) { 74.1695 + decl = lastDecl = ((VarNode)decl).setFlag(VarNode.IS_LAST_FUNCTION_DECLARATION); 74.1696 + lc.setFlag(functionNode, FunctionNode.HAS_FUNCTION_DECLARATIONS); 74.1697 + } 74.1698 + prependStatement(decl); 74.1699 + } 74.1700 + } 74.1701 + 74.1702 private RuntimeNode referenceError(final Node lhs, final Node rhs) { 74.1703 final ArrayList<Node> args = new ArrayList<>(); 74.1704 args.add(lhs); 74.1705 @@ -2764,9 +2512,7 @@ 74.1706 args.add(rhs); 74.1707 } 74.1708 args.add(LiteralNode.newInstance(source, lhs.getToken(), lhs.getFinish(), lhs.toString())); 74.1709 - final RuntimeNode runtimeNode = new RuntimeNode(source, lhs.getToken(), 74.1710 - lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 74.1711 - return runtimeNode; 74.1712 + return new RuntimeNode(source, lhs.getToken(), lhs.getFinish(), RuntimeNode.Request.REFERENCE_ERROR, args); 74.1713 } 74.1714 74.1715 /* 74.1716 @@ -2815,19 +2561,7 @@ 74.1717 case BIT_NOT: 74.1718 case NOT: 74.1719 next(); 74.1720 - 74.1721 final Node expr = unaryExpression(); 74.1722 - 74.1723 - /* 74.1724 - // Not sure if "delete <ident>" is a compile-time error or a 74.1725 - // runtime error in strict mode. 74.1726 - 74.1727 - if (isStrictMode) { 74.1728 - if (unaryTokenType == DELETE && expr instanceof IdentNode) { 74.1729 - error(message("strict.cant.delete.ident", ((IdentNode)expr).getName()), expr.getToken()); 74.1730 - } 74.1731 - } 74.1732 - */ 74.1733 return new UnaryNode(source, unaryToken, expr); 74.1734 74.1735 case INCPREFIX: 74.1736 @@ -2890,7 +2624,7 @@ 74.1737 } 74.1738 74.1739 if (expression == null) { 74.1740 - error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1741 + throw error(AbstractParser.message("expected.operand", type.getNameOrType())); 74.1742 } 74.1743 74.1744 return expression; 74.1745 @@ -2992,6 +2726,7 @@ 74.1746 // Include commas in expression parsing. 74.1747 return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false); 74.1748 } 74.1749 + 74.1750 private Node expression(final Node exprLhs, final int minPrecedence, final boolean noIn) { 74.1751 // Get the precedence of the next operator. 74.1752 int precedence = type.getPrecedence(); 74.1753 @@ -3087,11 +2822,26 @@ 74.1754 return "[JavaScript Parsing]"; 74.1755 } 74.1756 74.1757 - private Block getBlock() { 74.1758 - return lexicalContext.getCurrentBlock(); 74.1759 + private static void markWithOrEval(final LexicalContext lc, int flag) { 74.1760 + final Iterator<FunctionNode> iter = lc.getFunctions(); 74.1761 + boolean flaggedCurrentFn = false; 74.1762 + while (iter.hasNext()) { 74.1763 + final FunctionNode fn = iter.next(); 74.1764 + if (!flaggedCurrentFn) { 74.1765 + lc.setFlag(fn, flag); 74.1766 + flaggedCurrentFn = true; 74.1767 + } else { 74.1768 + lc.setFlag(fn, FunctionNode.HAS_DESCENDANT_WITH_OR_EVAL); 74.1769 + } 74.1770 + lc.setFlag(lc.getFunctionBody(fn), Block.NEEDS_SCOPE); 74.1771 + } 74.1772 } 74.1773 74.1774 - private FunctionNode getFunction() { 74.1775 - return lexicalContext.getCurrentFunction(); 74.1776 + private void prependStatement(final Node statement) { 74.1777 + lc.prependStatement(statement); 74.1778 + } 74.1779 + 74.1780 + private void appendStatement(final Node statement) { 74.1781 + lc.appendStatement(statement); 74.1782 } 74.1783 }
75.1 --- a/src/jdk/nashorn/internal/parser/TokenType.java Fri Apr 19 18:23:00 2013 +0530 75.2 +++ b/src/jdk/nashorn/internal/parser/TokenType.java Fri Apr 19 16:11:16 2013 +0200 75.3 @@ -280,6 +280,11 @@ 75.4 return values; 75.5 } 75.6 75.7 + @Override 75.8 + public String toString() { 75.9 + return name; 75.10 + } 75.11 + 75.12 static { 75.13 // Avoid cloning of enumeration. 75.14 values = TokenType.values();
76.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Fri Apr 19 18:23:00 2013 +0530 76.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Fri Apr 19 16:11:16 2013 +0200 76.3 @@ -382,7 +382,7 @@ 76.4 // We need to get strict mode flag from compiled class. This is 76.5 // because eval code may start with "use strict" directive. 76.6 try { 76.7 - strictFlag = clazz.getField(STRICT_MODE.tag()).getBoolean(null); 76.8 + strictFlag = clazz.getField(STRICT_MODE.symbolName()).getBoolean(null); 76.9 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 76.10 //ignored 76.11 strictFlag = false; 76.12 @@ -696,7 +696,7 @@ 76.13 MH.findStatic( 76.14 MethodHandles.lookup(), 76.15 script, 76.16 - RUN_SCRIPT.tag(), 76.17 + RUN_SCRIPT.symbolName(), 76.18 MH.type( 76.19 Object.class, 76.20 ScriptFunction.class, 76.21 @@ -705,13 +705,13 @@ 76.22 boolean strict; 76.23 76.24 try { 76.25 - strict = script.getField(STRICT_MODE.tag()).getBoolean(null); 76.26 + strict = script.getField(STRICT_MODE.symbolName()).getBoolean(null); 76.27 } catch (final NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { 76.28 strict = false; 76.29 } 76.30 76.31 // Package as a JavaScript function and pass function back to shell. 76.32 - return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.tag(), runMethodHandle, scope, strict); 76.33 + return ((GlobalObject)Context.getGlobalTrusted()).newScriptFunction(RUN_SCRIPT.symbolName(), runMethodHandle, scope, strict); 76.34 } 76.35 76.36 private ScriptFunction compileScript(final Source source, final ScriptObject scope, final ErrorManager errMan) { 76.37 @@ -729,13 +729,13 @@ 76.38 global = (GlobalObject)Context.getGlobalTrusted(); 76.39 script = global.findCachedClass(source); 76.40 if (script != null) { 76.41 - Compiler.LOG.fine("Code cache hit for " + source + " avoiding recompile."); 76.42 + Compiler.LOG.fine("Code cache hit for ", source, " avoiding recompile."); 76.43 return script; 76.44 } 76.45 } 76.46 76.47 final FunctionNode functionNode = new Parser(env, source, errMan, strict).parse(); 76.48 - if (errors.hasErrors() || env._parse_only) { 76.49 + if (errors.hasErrors()) { 76.50 return null; 76.51 } 76.52 76.53 @@ -747,6 +747,10 @@ 76.54 getErr().println(new PrintVisitor(functionNode)); 76.55 } 76.56 76.57 + if (env._parse_only) { 76.58 + return null; 76.59 + } 76.60 + 76.61 final URL url = source.getURL(); 76.62 final ScriptLoader loader = env._loader_per_compile ? createNewLoader() : scriptLoader; 76.63 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null);
77.1 --- a/src/jdk/nashorn/internal/runtime/DebugLogger.java Fri Apr 19 18:23:00 2013 +0530 77.2 +++ b/src/jdk/nashorn/internal/runtime/DebugLogger.java Fri Apr 19 16:11:16 2013 +0200 77.3 @@ -135,7 +135,16 @@ 77.4 * @param str the string to log 77.5 */ 77.6 public void finest(final String str) { 77.7 - log(str, Level.FINEST); 77.8 + log(Level.FINEST, str); 77.9 + } 77.10 + 77.11 + /** 77.12 + * Shorthand for outputting a log string as log level 77.13 + * {@link java.util.logging.Level#FINEST} on this logger 77.14 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.15 + */ 77.16 + public void finest(final Object... objs) { 77.17 + log(Level.FINEST, objs); 77.18 } 77.19 77.20 /** 77.21 @@ -144,7 +153,16 @@ 77.22 * @param str the string to log 77.23 */ 77.24 public void finer(final String str) { 77.25 - log(str, Level.FINER); 77.26 + log(Level.FINER, str); 77.27 + } 77.28 + 77.29 + /** 77.30 + * Shorthand for outputting a log string as log level 77.31 + * {@link java.util.logging.Level#FINER} on this logger 77.32 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.33 + */ 77.34 + public void finer(final Object... objs) { 77.35 + log(Level.FINER, objs); 77.36 } 77.37 77.38 /** 77.39 @@ -153,7 +171,16 @@ 77.40 * @param str the string to log 77.41 */ 77.42 public void fine(final String str) { 77.43 - log(str, Level.FINE); 77.44 + log(Level.FINE, str); 77.45 + } 77.46 + 77.47 + /** 77.48 + * Shorthand for outputting a log string as log level 77.49 + * {@link java.util.logging.Level#FINE} on this logger 77.50 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.51 + */ 77.52 + public void fine(final Object... objs) { 77.53 + log(Level.FINE, objs); 77.54 } 77.55 77.56 /** 77.57 @@ -162,7 +189,16 @@ 77.58 * @param str the string to log 77.59 */ 77.60 public void config(final String str) { 77.61 - log(str, Level.CONFIG); 77.62 + log(Level.CONFIG, str); 77.63 + } 77.64 + 77.65 + /** 77.66 + * Shorthand for outputting a log string as log level 77.67 + * {@link java.util.logging.Level#CONFIG} on this logger 77.68 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.69 + */ 77.70 + public void config(final Object... objs) { 77.71 + log(Level.CONFIG, objs); 77.72 } 77.73 77.74 /** 77.75 @@ -171,7 +207,16 @@ 77.76 * @param str the string to log 77.77 */ 77.78 public void info(final String str) { 77.79 - log(str, Level.INFO); 77.80 + log(Level.INFO, str); 77.81 + } 77.82 + 77.83 + /** 77.84 + * Shorthand for outputting a log string as log level 77.85 + * {@link java.util.logging.Level#FINE} on this logger 77.86 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.87 + */ 77.88 + public void info(final Object... objs) { 77.89 + log(Level.INFO, objs); 77.90 } 77.91 77.92 /** 77.93 @@ -180,7 +225,16 @@ 77.94 * @param str the string to log 77.95 */ 77.96 public void warning(final String str) { 77.97 - log(str, Level.WARNING); 77.98 + log(Level.WARNING, str); 77.99 + } 77.100 + 77.101 + /** 77.102 + * Shorthand for outputting a log string as log level 77.103 + * {@link java.util.logging.Level#FINE} on this logger 77.104 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.105 + */ 77.106 + public void warning(final Object... objs) { 77.107 + log(Level.WARNING, objs); 77.108 } 77.109 77.110 /** 77.111 @@ -189,20 +243,28 @@ 77.112 * @param str the string to log 77.113 */ 77.114 public void severe(final String str) { 77.115 - log(str, Level.SEVERE); 77.116 + log(Level.SEVERE, str); 77.117 + } 77.118 + 77.119 + /** 77.120 + * Shorthand for outputting a log string as log level 77.121 + * {@link java.util.logging.Level#FINE} on this logger 77.122 + * @param objs object array to log - use this to perform lazy concatenation to avoid unconditional toString overhead 77.123 + */ 77.124 + public void severe(final Object... objs) { 77.125 + log(Level.SEVERE, objs); 77.126 } 77.127 77.128 /** 77.129 * Output log line on this logger at a given level of verbosity 77.130 * @see java.util.logging.Level 77.131 * 77.132 + * @param level minimum log level required for logging to take place 77.133 * @param str string to log 77.134 - * @param level minimum log level required for logging to take place 77.135 */ 77.136 - public void log(final String str, final Level level) { 77.137 + public void log(final Level level, final String str) { 77.138 if (isEnabled) { 77.139 final StringBuilder sb = new StringBuilder(); 77.140 - 77.141 for (int i = 0 ; i < indent ; i++) { 77.142 sb.append(' '); 77.143 } 77.144 @@ -210,4 +272,24 @@ 77.145 logger.log(level, sb.toString()); 77.146 } 77.147 } 77.148 + 77.149 + /** 77.150 + * Output log line on this logger at a given level of verbosity 77.151 + * @see java.util.logging.Level 77.152 + * 77.153 + * @param level minimum log level required for logging to take place 77.154 + * @param objs objects for which to invoke toString and concatenate to log 77.155 + */ 77.156 + public void log(final Level level, final Object... objs) { 77.157 + if (isEnabled) { 77.158 + final StringBuilder sb = new StringBuilder(); 77.159 + for (int i = 0 ; i < indent ; i++) { 77.160 + sb.append(' '); 77.161 + } 77.162 + for (final Object obj : objs) { 77.163 + sb.append(obj); 77.164 + } 77.165 + logger.log(level, sb.toString()); 77.166 + } 77.167 + } 77.168 }
78.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri Apr 19 18:23:00 2013 +0530 78.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri Apr 19 16:11:16 2013 +0200 78.3 @@ -25,10 +25,11 @@ 78.4 78.5 package jdk.nashorn.internal.runtime; 78.6 78.7 +import static jdk.nashorn.internal.lookup.Lookup.MH; 78.8 + 78.9 import java.lang.invoke.MethodHandle; 78.10 import java.lang.invoke.MethodHandles; 78.11 import java.lang.invoke.MethodType; 78.12 - 78.13 import jdk.nashorn.internal.codegen.Compiler; 78.14 import jdk.nashorn.internal.codegen.CompilerConstants; 78.15 import jdk.nashorn.internal.codegen.FunctionSignature; 78.16 @@ -37,8 +38,6 @@ 78.17 import jdk.nashorn.internal.parser.Token; 78.18 import jdk.nashorn.internal.parser.TokenType; 78.19 78.20 -import static jdk.nashorn.internal.lookup.Lookup.MH; 78.21 - 78.22 /** 78.23 * This is a subclass that represents a script function that may be regenerated, 78.24 * for example with specialization based on call site types, or lazily generated. 78.25 @@ -47,7 +46,7 @@ 78.26 */ 78.27 public final class RecompilableScriptFunctionData extends ScriptFunctionData { 78.28 78.29 - private final FunctionNode functionNode; 78.30 + private FunctionNode functionNode; 78.31 private final PropertyMap allocatorMap; 78.32 private final CodeInstaller<ScriptEnvironment> installer; 78.33 private final String allocatorClassName; 78.34 @@ -70,7 +69,7 @@ 78.35 "" : 78.36 functionNode.getIdent().getName(), 78.37 functionNode.getParameters().size(), 78.38 - functionNode.isStrictMode(), 78.39 + functionNode.isStrict(), 78.40 false, 78.41 true); 78.42 78.43 @@ -129,7 +128,7 @@ 78.44 78.45 private void ensureHasAllocator() throws ClassNotFoundException { 78.46 if (allocator == null && allocatorClassName != null) { 78.47 - this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.tag(), MH.type(ScriptObject.class, PropertyMap.class)); 78.48 + this.allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName), CompilerConstants.ALLOCATE.symbolName(), MH.type(ScriptObject.class, PropertyMap.class)); 78.49 } 78.50 } 78.51 78.52 @@ -148,8 +147,11 @@ 78.53 // therefore, currently method specialization is disabled. TODO 78.54 78.55 if (functionNode.isLazy()) { 78.56 - Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '" + functionNode.getName() + "'"); 78.57 - new Compiler(installer, functionNode).compile().install(); 78.58 + Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); 78.59 + final Compiler compiler = new Compiler(installer, functionNode); 78.60 + functionNode = compiler.compile(); 78.61 + assert !functionNode.isLazy(); 78.62 + compiler.install(); 78.63 78.64 // we don't need to update any flags - varArgs and needsCallee are instrincic 78.65 // in the function world we need to get a destination node from the compile instead 78.66 @@ -159,7 +161,7 @@ 78.67 // we can't get here unless we have bytecode, either from eager compilation or from 78.68 // running a lazy compile on the lines above 78.69 78.70 - assert functionNode.hasState(CompilationState.INSTALLED); 78.71 + assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); 78.72 78.73 // code exists - look it up and add it into the automatically sorted invoker list 78.74 code.add(
79.1 --- a/src/jdk/nashorn/internal/runtime/StructureLoader.java Fri Apr 19 18:23:00 2013 +0530 79.2 +++ b/src/jdk/nashorn/internal/runtime/StructureLoader.java Fri Apr 19 16:11:16 2013 +0200 79.3 @@ -47,7 +47,7 @@ 79.4 * 79.5 */ 79.6 final class StructureLoader extends NashornLoader { 79.7 - private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.tag(); 79.8 + private static final String JS_OBJECT_PREFIX_EXTERNAL = binaryName(SCRIPTS_PACKAGE) + '.' + JS_OBJECT_PREFIX.symbolName(); 79.9 private static final String OBJECTS_PACKAGE_EXTERNAL = binaryName(OBJECTS_PACKAGE); 79.10 79.11 /** 79.12 @@ -110,7 +110,7 @@ 79.13 @Override 79.14 protected Class<?> findClass(final String name) throws ClassNotFoundException { 79.15 if (name.startsWith(JS_OBJECT_PREFIX_EXTERNAL)) { 79.16 - final int start = name.indexOf(JS_OBJECT_PREFIX.tag()) + JS_OBJECT_PREFIX.tag().length(); 79.17 + final int start = name.indexOf(JS_OBJECT_PREFIX.symbolName()) + JS_OBJECT_PREFIX.symbolName().length(); 79.18 return generateClass(name, name.substring(start, name.length())); 79.19 } 79.20 return super.findClass(name);
80.1 --- a/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java Fri Apr 19 18:23:00 2013 +0530 80.2 +++ b/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java Fri Apr 19 16:11:16 2013 +0200 80.3 @@ -185,4 +185,4 @@ 80.4 } 80.5 return classesAndLoaders.keySet(); 80.6 } 80.7 -} 80.8 \ No newline at end of file 80.9 +}
81.1 --- a/src/jdk/nashorn/tools/Shell.java Fri Apr 19 18:23:00 2013 +0530 81.2 +++ b/src/jdk/nashorn/tools/Shell.java Fri Apr 19 16:11:16 2013 +0200 81.3 @@ -42,6 +42,8 @@ 81.4 import jdk.nashorn.api.scripting.NashornException; 81.5 import jdk.nashorn.internal.codegen.Compiler; 81.6 import jdk.nashorn.internal.ir.FunctionNode; 81.7 +import jdk.nashorn.internal.ir.debug.ASTWriter; 81.8 +import jdk.nashorn.internal.ir.debug.PrintVisitor; 81.9 import jdk.nashorn.internal.parser.Parser; 81.10 import jdk.nashorn.internal.runtime.Context; 81.11 import jdk.nashorn.internal.runtime.ErrorManager; 81.12 @@ -254,6 +256,14 @@ 81.13 return COMPILATION_ERROR; 81.14 } 81.15 81.16 + if (env._print_ast) { 81.17 + context.getErr().println(new ASTWriter(functionNode)); 81.18 + } 81.19 + 81.20 + if (env._print_parse) { 81.21 + context.getErr().println(new PrintVisitor(functionNode)); 81.22 + } 81.23 + 81.24 //null - pass no code installer - this is compile only 81.25 new Compiler(env, functionNode).compile(); 81.26 }
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 82.2 +++ b/test/script/basic/try2.js Fri Apr 19 16:11:16 2013 +0200 82.3 @@ -0,0 +1,49 @@ 82.4 +/* 82.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 82.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 82.7 + * 82.8 + * This code is free software; you can redistribute it and/or modify it 82.9 + * under the terms of the GNU General Public License version 2 only, as 82.10 + * published by the Free Software Foundation. 82.11 + * 82.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 82.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 82.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 82.15 + * version 2 for more details (a copy is included in the LICENSE file that 82.16 + * accompanied this code). 82.17 + * 82.18 + * You should have received a copy of the GNU General Public License version 82.19 + * 2 along with this work; if not, write to the Free Software Foundation, 82.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 82.21 + * 82.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 82.23 + * or visit www.oracle.com if you need additional information or have any 82.24 + * questions. 82.25 + */ 82.26 + 82.27 +/** 82.28 + * Try throw test - nest finally 82.29 + * 82.30 + * @test 82.31 + * @run 82.32 + */ 82.33 + 82.34 +function f() { 82.35 + print("a"); 82.36 + try { 82.37 + print("b"); 82.38 + } finally { 82.39 + print("c"); 82.40 + try { 82.41 + print("d"); 82.42 + } finally { 82.43 + print("e"); 82.44 + } 82.45 + print("f"); 82.46 + } 82.47 + print("g"); 82.48 +} 82.49 + 82.50 +f(); 82.51 + 82.52 +print("done");
83.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 83.2 +++ b/test/script/basic/try2.js.EXPECTED Fri Apr 19 16:11:16 2013 +0200 83.3 @@ -0,0 +1,8 @@ 83.4 +a 83.5 +b 83.6 +c 83.7 +d 83.8 +e 83.9 +f 83.10 +g 83.11 +done