Fri, 03 May 2013 15:33:54 +0200
8013477: Node.setSymbol needs to be copy on write - enable IR snapshots for recompilation based on callsite type specialization. [not enabled by default, hidden by a flag for now]
Reviewed-by: jlaskey, hannesw
1.1 --- a/bin/jjs Thu May 02 15:01:16 2013 -0300 1.2 +++ b/bin/jjs Fri May 03 15:33:54 2013 +0200 1.3 @@ -26,4 +26,4 @@ 1.4 1.5 [ -z "$JAVA_HOME" ] && echo "Please set JAVA_HOME" && exit 1; 1.6 1.7 -$JAVA_HOME/bin/java -server -XX:-TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $* 1.8 +$JAVA_HOME/bin/java -server -XX:+TieredCompilation -Xms2G -Xmx2G -esa -ea -Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+HeapDumpOnOutOfMemoryError -Djava.lang.invoke.MethodHandle.DEBUG_NAMES=false -Dnashorn.debug=true jdk.nashorn.tools.Shell $*
2.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Thu May 02 15:01:16 2013 -0300 2.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java Fri May 03 15:33:54 2013 +0200 2.3 @@ -31,7 +31,6 @@ 2.4 import javax.script.ScriptEngine; 2.5 import javax.script.ScriptEngineFactory; 2.6 import jdk.nashorn.internal.runtime.Version; 2.7 -import sun.reflect.Reflection; 2.8 2.9 /** 2.10 * JSR-223 compliant script engine factory for Nashorn. The engine answers for:
3.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Thu May 02 15:01:16 2013 -0300 3.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Fri May 03 15:33:54 2013 +0200 3.3 @@ -29,17 +29,21 @@ 3.4 import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 3.5 import static jdk.nashorn.internal.codegen.CompilerConstants.EXCEPTION_PREFIX; 3.6 import static jdk.nashorn.internal.codegen.CompilerConstants.ITERATOR_PREFIX; 3.7 +import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX; 3.8 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 3.9 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 3.10 import static jdk.nashorn.internal.codegen.CompilerConstants.SWITCH_TAG_PREFIX; 3.11 +import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; 3.12 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 3.13 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 3.14 +import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; 3.15 import static jdk.nashorn.internal.ir.Symbol.IS_FUNCTION_SELF; 3.16 import static jdk.nashorn.internal.ir.Symbol.IS_GLOBAL; 3.17 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; 3.18 import static jdk.nashorn.internal.ir.Symbol.IS_LET; 3.19 import static jdk.nashorn.internal.ir.Symbol.IS_PARAM; 3.20 import static jdk.nashorn.internal.ir.Symbol.IS_SCOPE; 3.21 +import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; 3.22 import static jdk.nashorn.internal.ir.Symbol.IS_THIS; 3.23 import static jdk.nashorn.internal.ir.Symbol.IS_VAR; 3.24 import static jdk.nashorn.internal.ir.Symbol.KINDMASK; 3.25 @@ -51,6 +55,7 @@ 3.26 import java.util.Iterator; 3.27 import java.util.List; 3.28 import java.util.Set; 3.29 + 3.30 import jdk.nashorn.internal.codegen.types.Type; 3.31 import jdk.nashorn.internal.ir.AccessNode; 3.32 import jdk.nashorn.internal.ir.BinaryNode; 3.33 @@ -90,7 +95,6 @@ 3.34 import jdk.nashorn.internal.runtime.JSType; 3.35 import jdk.nashorn.internal.runtime.Property; 3.36 import jdk.nashorn.internal.runtime.PropertyMap; 3.37 -import jdk.nashorn.internal.runtime.ScriptFunction; 3.38 import jdk.nashorn.internal.runtime.ScriptObject; 3.39 3.40 /** 3.41 @@ -133,9 +137,9 @@ 3.42 * Constructor. 3.43 */ 3.44 Attr() { 3.45 - localDefs = new ArrayDeque<>(); 3.46 - localUses = new ArrayDeque<>(); 3.47 - returnTypes = new ArrayDeque<>(); 3.48 + this.localDefs = new ArrayDeque<>(); 3.49 + this.localUses = new ArrayDeque<>(); 3.50 + this.returnTypes = new ArrayDeque<>(); 3.51 } 3.52 3.53 @Override 3.54 @@ -150,67 +154,48 @@ 3.55 3.56 @Override 3.57 public Node leaveAccessNode(final AccessNode accessNode) { 3.58 - ensureSymbol(Type.OBJECT, accessNode); //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this 3.59 - end(accessNode); 3.60 - return accessNode; 3.61 + //While Object type is assigned here, Access Specialization in FinalizeTypes may narrow this 3.62 + return end(ensureSymbol(Type.OBJECT, accessNode)); 3.63 } 3.64 3.65 - private void enterFunctionBody() { 3.66 + private void initFunctionWideVariables(final FunctionNode functionNode, final Block body) { 3.67 + initCompileConstant(CALLEE, body, IS_PARAM | IS_INTERNAL, FunctionNode.FUNCTION_TYPE); 3.68 + initCompileConstant(THIS, body, IS_PARAM | IS_THIS, Type.OBJECT); 3.69 3.70 - final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 3.71 - final Block body = getLexicalContext().getCurrentBlock(); 3.72 - initCallee(body); 3.73 - initThis(body); 3.74 if (functionNode.isVarArg()) { 3.75 - initVarArg(body, functionNode.needsArguments()); 3.76 + initCompileConstant(VARARGS, body, IS_PARAM | IS_INTERNAL, Type.OBJECT_ARRAY); 3.77 + if (functionNode.needsArguments()) { 3.78 + initCompileConstant(ARGUMENTS, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); 3.79 + addLocalDef(ARGUMENTS.symbolName()); 3.80 + } 3.81 } 3.82 3.83 initParameters(functionNode, body); 3.84 - initScope(body); 3.85 - initReturn(body); 3.86 + initCompileConstant(SCOPE, body, IS_VAR | IS_INTERNAL, Type.typeFor(ScriptObject.class)); 3.87 + initCompileConstant(RETURN, body, IS_VAR | IS_INTERNAL, Type.OBJECT); 3.88 + } 3.89 3.90 - if (functionNode.isProgram()) { 3.91 - initFromPropertyMap(body); 3.92 - } else if(!functionNode.isDeclared()) { 3.93 - // It's neither declared nor program - it's a function expression then; assign it a self-symbol. 3.94 3.95 - if (functionNode.getSymbol() != null) { 3.96 - // a temporary left over from an earlier pass when the function was lazy 3.97 - assert functionNode.getSymbol().isTemp(); 3.98 - // remove it 3.99 - functionNode.setSymbol(null); 3.100 - } 3.101 - final boolean anonymous = functionNode.isAnonymous(); 3.102 - final String name = anonymous ? null : functionNode.getIdent().getName(); 3.103 - if (anonymous || body.getExistingSymbol(name) != null) { 3.104 - // The function is either anonymous, or another local identifier already trumps its name on entry: 3.105 - // either it has the same name as one of its parameters, or is named "arguments" and also references the 3.106 - // "arguments" identifier in its body. 3.107 - ensureSymbol(functionNode, Type.typeFor(ScriptFunction.class), functionNode); 3.108 - } else { 3.109 - final Symbol selfSymbol = defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF, functionNode); 3.110 - assert selfSymbol.isFunctionSelf(); 3.111 - newType(selfSymbol, Type.OBJECT); 3.112 - } 3.113 - } 3.114 - 3.115 - /* 3.116 - * This pushes all declarations (except for non-statements, i.e. for 3.117 - * node temporaries) to the top of the function scope. This way we can 3.118 - * get around problems like 3.119 - * 3.120 - * while (true) { 3.121 - * break; 3.122 - * if (true) { 3.123 - * var s; 3.124 - * } 3.125 - * } 3.126 - * 3.127 - * to an arbitrary nesting depth. 3.128 - * 3.129 - * @see NASHORN-73 3.130 - */ 3.131 - 3.132 + /** 3.133 + * This pushes all declarations (except for non-statements, i.e. for 3.134 + * node temporaries) to the top of the function scope. This way we can 3.135 + * get around problems like 3.136 + * 3.137 + * while (true) { 3.138 + * break; 3.139 + * if (true) { 3.140 + * var s; 3.141 + * } 3.142 + * } 3.143 + * 3.144 + * to an arbitrary nesting depth. 3.145 + * 3.146 + * see NASHORN-73 3.147 + * 3.148 + * @param functionNode the FunctionNode we are entering 3.149 + * @param body the body of the FunctionNode we are entering 3.150 + */ 3.151 + private void acceptDeclarations(final FunctionNode functionNode, final Block body) { 3.152 // This visitor will assign symbol to all declared variables, except function declarations (which are taken care 3.153 // in a separate step above) and "var" declarations in for loop initializers. 3.154 body.accept(new NodeOperatorVisitor() { 3.155 @@ -220,27 +205,52 @@ 3.156 } 3.157 3.158 @Override 3.159 - public boolean enterVarNode(final VarNode varNode) { 3.160 - 3.161 + public Node leaveVarNode(final VarNode varNode) { 3.162 // any declared symbols that aren't visited need to be typed as well, hence the list 3.163 - 3.164 if (varNode.isStatement()) { 3.165 - 3.166 - final IdentNode ident = varNode.getName(); 3.167 - final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR, new IdentNode(ident)); 3.168 + final IdentNode ident = varNode.getName(); 3.169 + final Symbol symbol = defineSymbol(body, ident.getName(), IS_VAR); 3.170 functionNode.addDeclaredSymbol(symbol); 3.171 if (varNode.isFunctionDeclaration()) { 3.172 newType(symbol, FunctionNode.FUNCTION_TYPE); 3.173 } 3.174 + return varNode.setName((IdentNode)ident.setSymbol(getLexicalContext(), symbol)); 3.175 } 3.176 - return false; 3.177 + return varNode; 3.178 } 3.179 }); 3.180 } 3.181 3.182 + private void enterFunctionBody() { 3.183 + 3.184 + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 3.185 + final Block body = getLexicalContext().getCurrentBlock(); 3.186 + 3.187 + initFunctionWideVariables(functionNode, body); 3.188 + 3.189 + if (functionNode.isProgram()) { 3.190 + initFromPropertyMap(body); 3.191 + } else if (!functionNode.isDeclared()) { 3.192 + // It's neither declared nor program - it's a function expression then; assign it a self-symbol. 3.193 + assert functionNode.getSymbol() == null; 3.194 + 3.195 + final boolean anonymous = functionNode.isAnonymous(); 3.196 + final String name = anonymous ? null : functionNode.getIdent().getName(); 3.197 + if (!(anonymous || body.getExistingSymbol(name) != null)) { 3.198 + assert !anonymous && name != null; 3.199 + newType(defineSymbol(body, name, IS_VAR | IS_FUNCTION_SELF), Type.OBJECT); 3.200 + } 3.201 + } 3.202 + 3.203 + acceptDeclarations(functionNode, body); 3.204 + } 3.205 + 3.206 @Override 3.207 public boolean enterBlock(final Block block) { 3.208 start(block); 3.209 + //ensure that we don't use information from a previous compile. This is very ugly TODO 3.210 + //the symbols in the block should really be stateless 3.211 + block.clearSymbols(); 3.212 3.213 if (getLexicalContext().isFunctionBody()) { 3.214 enterFunctionBody(); 3.215 @@ -257,14 +267,13 @@ 3.216 } 3.217 3.218 @Override 3.219 - public Node leaveCallNode(final CallNode callNode) { 3.220 - ensureSymbol(callNode.getType(), callNode); 3.221 - return end(callNode); 3.222 + public boolean enterCallNode(final CallNode callNode) { 3.223 + return start(callNode); 3.224 } 3.225 3.226 @Override 3.227 - public boolean enterCallNode(final CallNode callNode) { 3.228 - return start(callNode); 3.229 + public Node leaveCallNode(final CallNode callNode) { 3.230 + return end(ensureSymbol(callNode.getType(), callNode)); 3.231 } 3.232 3.233 @Override 3.234 @@ -275,23 +284,31 @@ 3.235 start(catchNode); 3.236 3.237 // define block-local exception variable 3.238 - final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET, exception); 3.239 + final Symbol def = defineSymbol(block, exception.getName(), IS_VAR | IS_LET); 3.240 newType(def, Type.OBJECT); 3.241 addLocalDef(exception.getName()); 3.242 3.243 return true; 3.244 } 3.245 3.246 + @Override 3.247 + public Node leaveCatchNode(final CatchNode catchNode) { 3.248 + final IdentNode exception = catchNode.getException(); 3.249 + final Block block = getLexicalContext().getCurrentBlock(); 3.250 + final Symbol symbol = findSymbol(block, exception.getName()); 3.251 + assert symbol != null; 3.252 + return end(catchNode.setException((IdentNode)exception.setSymbol(getLexicalContext(), symbol))); 3.253 + } 3.254 + 3.255 /** 3.256 * Declare the definition of a new symbol. 3.257 * 3.258 * @param name Name of symbol. 3.259 * @param symbolFlags Symbol flags. 3.260 - * @param node Defining Node. 3.261 * 3.262 * @return Symbol for given name or null for redefinition. 3.263 */ 3.264 - private Symbol defineSymbol(final Block block, final String name, final int symbolFlags, final Node node) { 3.265 + private Symbol defineSymbol(final Block block, final String name, final int symbolFlags) { 3.266 int flags = symbolFlags; 3.267 Symbol symbol = findSymbol(block, name); // Locate symbol. 3.268 3.269 @@ -337,7 +354,7 @@ 3.270 3.271 // Create and add to appropriate block. 3.272 symbol = new Symbol(name, flags); 3.273 - symbolBlock.putSymbol(name, symbol); 3.274 + symbolBlock.putSymbol(getLexicalContext(), symbol); 3.275 3.276 if ((flags & Symbol.KINDMASK) != IS_GLOBAL) { 3.277 symbol.setNeedsSlot(true); 3.278 @@ -346,10 +363,6 @@ 3.279 symbol.setFlags(flags); 3.280 } 3.281 3.282 - if (node != null) { 3.283 - node.setSymbol(symbol); 3.284 - } 3.285 - 3.286 return symbol; 3.287 } 3.288 3.289 @@ -357,30 +370,22 @@ 3.290 public boolean enterFunctionNode(final FunctionNode functionNode) { 3.291 start(functionNode, false); 3.292 3.293 + if (functionNode.isLazy()) { 3.294 + return false; 3.295 + } 3.296 + 3.297 + //an outermost function in our lexical context that is not a program (runScript) 3.298 + //is possible - it is a function being compiled lazily 3.299 if (functionNode.isDeclared()) { 3.300 final Iterator<Block> blocks = getLexicalContext().getBlocks(); 3.301 if (blocks.hasNext()) { 3.302 - defineSymbol( 3.303 - blocks.next(), 3.304 - functionNode.getIdent().getName(), 3.305 - IS_VAR, 3.306 - functionNode); 3.307 - } else { 3.308 - // Q: What's an outermost function in a lexical context that is not a program? 3.309 - // A: It's a function being compiled lazily! 3.310 - assert getLexicalContext().getOutermostFunction() == functionNode && !functionNode.isProgram(); 3.311 + defineSymbol(blocks.next(), functionNode.getIdent().getName(), IS_VAR); 3.312 } 3.313 } 3.314 3.315 - if (functionNode.isLazy()) { 3.316 - LOG.info("LAZY: ", functionNode.getName(), " => Promoting to OBJECT"); 3.317 - ensureSymbol(getLexicalContext().getCurrentFunction(), Type.OBJECT, functionNode); 3.318 - end(functionNode); 3.319 - return false; 3.320 - } 3.321 - 3.322 returnTypes.push(functionNode.getReturnType()); 3.323 pushLocalsFunction(); 3.324 + 3.325 return true; 3.326 } 3.327 3.328 @@ -390,8 +395,29 @@ 3.329 3.330 final LexicalContext lc = getLexicalContext(); 3.331 3.332 + final Block body = newFunctionNode.getBody(); 3.333 + 3.334 + //look for this function in the parent block 3.335 + if (functionNode.isDeclared()) { 3.336 + final Iterator<Block> blocks = getLexicalContext().getBlocks(); 3.337 + if (blocks.hasNext()) { 3.338 + newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, findSymbol(blocks.next(), functionNode.getIdent().getName())); 3.339 + } 3.340 + } else if (!functionNode.isProgram()) { 3.341 + final boolean anonymous = functionNode.isAnonymous(); 3.342 + final String name = anonymous ? null : functionNode.getIdent().getName(); 3.343 + if (anonymous || body.getExistingSymbol(name) != null) { 3.344 + newFunctionNode = (FunctionNode)Attr.ensureSymbol(lc, body, FunctionNode.FUNCTION_TYPE, newFunctionNode); 3.345 + } else { 3.346 + assert name != null; 3.347 + final Symbol self = body.getExistingSymbol(name); 3.348 + assert self != null && self.isFunctionSelf(); 3.349 + newFunctionNode = (FunctionNode)newFunctionNode.setSymbol(lc, body.getExistingSymbol(name)); 3.350 + } 3.351 + } 3.352 + 3.353 //unknown parameters are promoted to object type. 3.354 - finalizeParameters(newFunctionNode); 3.355 + newFunctionNode = finalizeParameters(newFunctionNode); 3.356 finalizeTypes(newFunctionNode); 3.357 for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) { 3.358 if (symbol.getSymbolType().isUnknown()) { 3.359 @@ -400,8 +426,6 @@ 3.360 } 3.361 } 3.362 3.363 - final Block body = newFunctionNode.getBody(); 3.364 - 3.365 if (newFunctionNode.hasLazyChildren()) { 3.366 //the final body has already been assigned as we have left the function node block body by now 3.367 objectifySymbols(body); 3.368 @@ -409,7 +433,7 @@ 3.369 3.370 if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) { 3.371 final IdentNode callee = compilerConstant(CALLEE); 3.372 - final VarNode selfInit = 3.373 + VarNode selfInit = 3.374 new VarNode( 3.375 newFunctionNode.getSource(), 3.376 newFunctionNode.getToken(), 3.377 @@ -420,7 +444,6 @@ 3.378 LOG.info("Accepting self symbol init ", selfInit, " for ", newFunctionNode.getName()); 3.379 3.380 final List<Node> newStatements = new ArrayList<>(); 3.381 - newStatements.add(selfInit); 3.382 assert callee.getSymbol() != null && callee.getSymbol().hasSlot(); 3.383 3.384 final IdentNode name = selfInit.getName(); 3.385 @@ -428,9 +451,10 @@ 3.386 3.387 assert nameSymbol != null; 3.388 3.389 - name.setSymbol(nameSymbol); 3.390 - selfInit.setSymbol(nameSymbol); 3.391 + selfInit = selfInit.setName((IdentNode)name.setSymbol(lc, nameSymbol)); 3.392 + selfInit = (VarNode)selfInit.setSymbol(lc, nameSymbol); 3.393 3.394 + newStatements.add(selfInit); 3.395 newStatements.addAll(body.getStatements()); 3.396 newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements)); 3.397 } 3.398 @@ -447,34 +471,32 @@ 3.399 3.400 end(newFunctionNode, false); 3.401 3.402 - return newFunctionNode; //.setFlag(lc, lc.getFlags(functionNode)); 3.403 + return newFunctionNode; 3.404 } 3.405 3.406 @Override 3.407 public Node leaveCONVERT(final UnaryNode unaryNode) { 3.408 assert false : "There should be no convert operators in IR during Attribution"; 3.409 - end(unaryNode); 3.410 - return unaryNode; 3.411 + return end(unaryNode); 3.412 } 3.413 3.414 @Override 3.415 - public boolean enterIdentNode(final IdentNode identNode) { 3.416 + public Node leaveIdentNode(final IdentNode identNode) { 3.417 final String name = identNode.getName(); 3.418 3.419 start(identNode); 3.420 3.421 + final LexicalContext lc = getLexicalContext(); 3.422 + 3.423 if (identNode.isPropertyName()) { 3.424 // assign a pseudo symbol to property name 3.425 final Symbol pseudoSymbol = pseudoSymbol(name); 3.426 LOG.info("IdentNode is property name -> assigning pseudo symbol ", pseudoSymbol); 3.427 LOG.unindent(); 3.428 - identNode.setSymbol(pseudoSymbol); 3.429 - return false; 3.430 + return identNode.setSymbol(lc, pseudoSymbol); 3.431 } 3.432 3.433 - final LexicalContext lc = getLexicalContext(); 3.434 - final Block block = lc.getCurrentBlock(); 3.435 - final Symbol oldSymbol = identNode.getSymbol(); 3.436 + final Block block = lc.getCurrentBlock(); 3.437 3.438 Symbol symbol = findSymbol(block, name); 3.439 3.440 @@ -495,12 +517,11 @@ 3.441 } 3.442 } 3.443 3.444 - identNode.setSymbol(symbol); 3.445 // if symbol is non-local or we're in a with block, we need to put symbol in scope (if it isn't already) 3.446 maybeForceScope(symbol); 3.447 } else { 3.448 LOG.info("No symbol exists. Declare undefined: ", symbol); 3.449 - symbol = defineSymbol(block, name, IS_GLOBAL, identNode); 3.450 + symbol = defineSymbol(block, name, IS_GLOBAL); 3.451 // we have never seen this before, it can be undefined 3.452 newType(symbol, Type.OBJECT); // TODO unknown -we have explicit casts anyway? 3.453 symbol.setCanBeUndefined(); 3.454 @@ -509,14 +530,14 @@ 3.455 3.456 setBlockScope(name, symbol); 3.457 3.458 - if (symbol != oldSymbol && !identNode.isInitializedHere()) { 3.459 + if (symbol != null && !identNode.isInitializedHere()) { 3.460 symbol.increaseUseCount(); 3.461 } 3.462 addLocalUse(identNode.getName()); 3.463 3.464 end(identNode); 3.465 3.466 - return false; 3.467 + return identNode.setSymbol(lc, symbol); 3.468 } 3.469 3.470 /** 3.471 @@ -525,7 +546,7 @@ 3.472 * @param symbol the symbol that might be scoped 3.473 */ 3.474 private void maybeForceScope(final Symbol symbol) { 3.475 - if(!symbol.isScope() && symbolNeedsToBeScope(symbol)) { 3.476 + if (!symbol.isScope() && symbolNeedsToBeScope(symbol)) { 3.477 Symbol.setSymbolIsScope(getLexicalContext(), symbol); 3.478 } 3.479 } 3.480 @@ -612,11 +633,11 @@ 3.481 private Symbol findSymbol(final Block block, final String name) { 3.482 // Search up block chain to locate symbol. 3.483 3.484 - for(final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { 3.485 + for (final Iterator<Block> blocks = getLexicalContext().getBlocks(block); blocks.hasNext();) { 3.486 // Find name. 3.487 final Symbol symbol = blocks.next().getExistingSymbol(name); 3.488 // If found then we are good. 3.489 - if(symbol != null) { 3.490 + if (symbol != null) { 3.491 return symbol; 3.492 } 3.493 } 3.494 @@ -625,39 +646,19 @@ 3.495 3.496 @Override 3.497 public Node leaveIndexNode(final IndexNode indexNode) { 3.498 - ensureSymbol(Type.OBJECT, indexNode); //TODO 3.499 - return indexNode; 3.500 + return end(ensureSymbol(Type.OBJECT, indexNode)); 3.501 } 3.502 3.503 @SuppressWarnings("rawtypes") 3.504 @Override 3.505 - public boolean enterLiteralNode(final LiteralNode literalNode) { 3.506 - try { 3.507 - start(literalNode); 3.508 - assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens 3.509 - 3.510 - if (literalNode instanceof ArrayLiteralNode) { 3.511 - final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; 3.512 - final Node[] array = arrayLiteralNode.getValue(); 3.513 - 3.514 - for (int i = 0; i < array.length; i++) { 3.515 - final Node element = array[i]; 3.516 - if (element != null) { 3.517 - array[i] = element.accept(this); 3.518 - } 3.519 - } 3.520 - arrayLiteralNode.analyze(); 3.521 - //array literal node now has an element type and all elements are attributed 3.522 - } else { 3.523 - assert !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; 3.524 - } 3.525 - 3.526 - getLexicalContext().getCurrentFunction().newLiteral(literalNode); 3.527 - } finally { 3.528 - end(literalNode); 3.529 + public Node leaveLiteralNode(final LiteralNode literalNode) { 3.530 + assert !literalNode.isTokenType(TokenType.THIS) : "tokentype for " + literalNode + " is this"; //guard against old dead code case. literal nodes should never inherit tokens 3.531 + assert literalNode instanceof ArrayLiteralNode || !(literalNode.getValue() instanceof Node) : "literals with Node values not supported"; 3.532 + final Symbol symbol = new Symbol(getLexicalContext().getCurrentFunction().uniqueName(LITERAL_PREFIX.symbolName()), IS_CONSTANT, literalNode.getType()); 3.533 + if (literalNode instanceof ArrayLiteralNode) { 3.534 + ((ArrayLiteralNode)literalNode).analyze(); 3.535 } 3.536 - 3.537 - return false; 3.538 + return literalNode.setSymbol(getLexicalContext(), symbol); 3.539 } 3.540 3.541 @Override 3.542 @@ -667,18 +668,13 @@ 3.543 3.544 @Override 3.545 public Node leaveObjectNode(final ObjectNode objectNode) { 3.546 - ensureSymbol(Type.OBJECT, objectNode); 3.547 - return end(objectNode); 3.548 + return end(ensureSymbol(Type.OBJECT, objectNode)); 3.549 } 3.550 3.551 - //TODO is this correct why not leave? 3.552 @Override 3.553 - public boolean enterPropertyNode(final PropertyNode propertyNode) { 3.554 + public Node leavePropertyNode(final PropertyNode propertyNode) { 3.555 // assign a pseudo symbol to property name, see NASHORN-710 3.556 - start(propertyNode); 3.557 - propertyNode.setSymbol(new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); 3.558 - end(propertyNode); 3.559 - return true; 3.560 + return propertyNode.setSymbol(getLexicalContext(), new Symbol(propertyNode.getKeyName(), 0, Type.OBJECT)); 3.561 } 3.562 3.563 @Override 3.564 @@ -763,12 +759,9 @@ 3.565 final IdentNode ident = varNode.getName(); 3.566 final String name = ident.getName(); 3.567 3.568 - final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR, ident); 3.569 + final Symbol symbol = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR); 3.570 assert symbol != null; 3.571 3.572 - LOG.info("VarNode ", varNode, " set symbol ", symbol); 3.573 - varNode.setSymbol(symbol); 3.574 - 3.575 // NASHORN-467 - use before definition of vars - conservative 3.576 if (isLocalUse(ident.getName())) { 3.577 newType(symbol, Type.OBJECT); 3.578 @@ -780,22 +773,31 @@ 3.579 3.580 @Override 3.581 public Node leaveVarNode(final VarNode varNode) { 3.582 - final Node init = varNode.getInit(); 3.583 - final IdentNode ident = varNode.getName(); 3.584 + VarNode newVarNode = varNode; 3.585 + 3.586 + final Node init = newVarNode.getInit(); 3.587 + final IdentNode ident = newVarNode.getName(); 3.588 final String name = ident.getName(); 3.589 3.590 if (init == null) { 3.591 // var x; with no init will be treated like a use of x by 3.592 - // visit(IdentNode) unless we remove the name 3.593 - // from the localdef list. 3.594 + // leaveIdentNode unless we remove the name from the localdef list. 3.595 removeLocalDef(name); 3.596 - return varNode; 3.597 + return newVarNode; 3.598 } 3.599 3.600 addLocalDef(name); 3.601 3.602 - final Symbol symbol = varNode.getSymbol(); 3.603 - final boolean isScript = getLexicalContext().getDefiningFunction(symbol).isProgram(); //see NASHORN-56 3.604 + final LexicalContext lc = getLexicalContext(); 3.605 + final Symbol symbol = findSymbol(lc.getCurrentBlock(), ident.getName()); 3.606 + assert symbol != null; 3.607 + 3.608 + final IdentNode newIdent = (IdentNode)ident.setSymbol(lc, symbol); 3.609 + 3.610 + newVarNode = newVarNode.setName(newIdent); 3.611 + newVarNode = (VarNode)newVarNode.setSymbol(lc, symbol); 3.612 + 3.613 + final boolean isScript = lc.getDefiningFunction(symbol).isProgram(); //see NASHORN-56 3.614 if ((init.getType().isNumeric() || init.getType().isBoolean()) && !isScript) { 3.615 // Forbid integers as local vars for now as we have no way to treat them as undefined 3.616 newType(symbol, init.getType()); 3.617 @@ -803,25 +805,19 @@ 3.618 newType(symbol, Type.OBJECT); 3.619 } 3.620 3.621 - assert varNode.hasType() : varNode; 3.622 + assert newVarNode.hasType() : newVarNode + " has no type"; 3.623 3.624 - end(varNode); 3.625 - 3.626 - return varNode; 3.627 + return end(newVarNode); 3.628 } 3.629 3.630 @Override 3.631 public Node leaveADD(final UnaryNode unaryNode) { 3.632 - ensureSymbol(arithType(), unaryNode); 3.633 - end(unaryNode); 3.634 - return unaryNode; 3.635 + return end(ensureSymbol(arithType(), unaryNode)); 3.636 } 3.637 3.638 @Override 3.639 public Node leaveBIT_NOT(final UnaryNode unaryNode) { 3.640 - ensureSymbol(Type.INT, unaryNode); 3.641 - end(unaryNode); 3.642 - return unaryNode; 3.643 + return end(ensureSymbol(Type.INT, unaryNode)); 3.644 } 3.645 3.646 @Override 3.647 @@ -830,9 +826,7 @@ 3.648 ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), unaryNode.rhs()); 3.649 final Type type = arithType(); 3.650 newType(unaryNode.rhs().getSymbol(), type); 3.651 - ensureSymbol(type, unaryNode); 3.652 - end(unaryNode); 3.653 - return unaryNode; 3.654 + return end(ensureSymbol(type, unaryNode)); 3.655 } 3.656 3.657 @Override 3.658 @@ -908,23 +902,25 @@ 3.659 3.660 @Override 3.661 public Node leaveNEW(final UnaryNode unaryNode) { 3.662 - ensureSymbol(Type.OBJECT, unaryNode); 3.663 - end(unaryNode); 3.664 - return unaryNode; 3.665 + return end(ensureSymbol(Type.OBJECT, unaryNode)); 3.666 } 3.667 3.668 @Override 3.669 public Node leaveNOT(final UnaryNode unaryNode) { 3.670 - ensureSymbol(Type.BOOLEAN, unaryNode); 3.671 - end(unaryNode); 3.672 - return unaryNode; 3.673 + return end(ensureSymbol(Type.BOOLEAN, unaryNode)); 3.674 } 3.675 3.676 private IdentNode compilerConstant(CompilerConstants cc) { 3.677 final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 3.678 - final IdentNode node = new IdentNode(functionNode.getSource(), functionNode.getToken(), functionNode.getFinish(), cc.symbolName()); 3.679 - node.setSymbol(functionNode.compilerConstant(cc)); 3.680 - return node; 3.681 + return (IdentNode) 3.682 + new IdentNode( 3.683 + functionNode.getSource(), 3.684 + functionNode.getToken(), 3.685 + functionNode.getFinish(), 3.686 + cc.symbolName()). 3.687 + setSymbol( 3.688 + getLexicalContext(), 3.689 + functionNode.compilerConstant(cc)); 3.690 } 3.691 3.692 @Override 3.693 @@ -952,15 +948,12 @@ 3.694 3.695 @Override 3.696 public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 3.697 - ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode); 3.698 - return runtimeNode; 3.699 + return end(ensureSymbol(runtimeNode.getRequest().getReturnType(), runtimeNode)); 3.700 } 3.701 3.702 @Override 3.703 public Node leaveSUB(final UnaryNode unaryNode) { 3.704 - ensureSymbol(arithType(), unaryNode); 3.705 - end(unaryNode); 3.706 - return unaryNode; 3.707 + return end(ensureSymbol(arithType(), unaryNode)); 3.708 } 3.709 3.710 @Override 3.711 @@ -982,18 +975,16 @@ 3.712 3.713 ensureTypeNotUnknown(lhs); 3.714 ensureTypeNotUnknown(rhs); 3.715 - ensureSymbol(Type.widest(lhs.getType(), rhs.getType()), binaryNode); 3.716 - 3.717 - end(binaryNode); 3.718 - 3.719 - return binaryNode; 3.720 + //even if we are adding two known types, this can overflow. i.e. 3.721 + //int and number -> number. 3.722 + //int and int are also number though. 3.723 + //something and object is object 3.724 + return end(ensureSymbol(Type.widest(arithType(), Type.widest(lhs.getType(), rhs.getType())), binaryNode)); 3.725 } 3.726 3.727 @Override 3.728 public Node leaveAND(final BinaryNode binaryNode) { 3.729 - ensureSymbol(Type.OBJECT, binaryNode); 3.730 - end(binaryNode); 3.731 - return binaryNode; 3.732 + return end(ensureSymbol(Type.OBJECT, binaryNode)); 3.733 } 3.734 3.735 /** 3.736 @@ -1013,8 +1004,7 @@ 3.737 Symbol symbol = findSymbol(block, name); 3.738 3.739 if (symbol == null) { 3.740 - symbol = defineSymbol(block, name, IS_GLOBAL, ident); 3.741 - binaryNode.setSymbol(symbol); 3.742 + symbol = defineSymbol(block, name, IS_GLOBAL); 3.743 } else { 3.744 maybeForceScope(symbol); 3.745 } 3.746 @@ -1025,6 +1015,31 @@ 3.747 return true; 3.748 } 3.749 3.750 + 3.751 + /** 3.752 + * This assign helper is called after an assignment, when all children of 3.753 + * the assign has been processed. It fixes the types and recursively makes 3.754 + * sure that everyhing has slots that should have them in the chain. 3.755 + * 3.756 + * @param binaryNode assignment node 3.757 + */ 3.758 + private Node leaveAssignmentNode(final BinaryNode binaryNode) { 3.759 + BinaryNode newBinaryNode = binaryNode; 3.760 + 3.761 + final Node lhs = binaryNode.lhs(); 3.762 + final Node rhs = binaryNode.rhs(); 3.763 + final Type type; 3.764 + 3.765 + if (rhs.getType().isNumeric()) { 3.766 + type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 3.767 + } else { 3.768 + type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. 3.769 + } 3.770 + 3.771 + newType(lhs.getSymbol(), type); 3.772 + return end(ensureSymbol(type, newBinaryNode)); 3.773 + } 3.774 + 3.775 private boolean isLocal(FunctionNode function, Symbol symbol) { 3.776 final FunctionNode definingFn = getLexicalContext().getDefiningFunction(symbol); 3.777 // Temp symbols are not assigned to a block, so their defining fn is null; those can be assumed local 3.778 @@ -1173,14 +1188,12 @@ 3.779 3.780 @Override 3.781 public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { 3.782 - ensureSymbol(binaryNode.rhs().getType(), binaryNode); 3.783 - return binaryNode; 3.784 + return end(ensureSymbol(binaryNode.rhs().getType(), binaryNode)); 3.785 } 3.786 3.787 @Override 3.788 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 3.789 - ensureSymbol(binaryNode.lhs().getType(), binaryNode); 3.790 - return binaryNode; 3.791 + return end(ensureSymbol(binaryNode.lhs().getType(), binaryNode)); 3.792 } 3.793 3.794 @Override 3.795 @@ -1189,15 +1202,10 @@ 3.796 } 3.797 3.798 private Node leaveCmp(final BinaryNode binaryNode) { 3.799 - final Node lhs = binaryNode.lhs(); 3.800 - final Node rhs = binaryNode.rhs(); 3.801 + ensureTypeNotUnknown(binaryNode.lhs()); 3.802 + ensureTypeNotUnknown(binaryNode.rhs()); 3.803 3.804 - ensureSymbol(Type.BOOLEAN, binaryNode); 3.805 - ensureTypeNotUnknown(lhs); 3.806 - ensureTypeNotUnknown(rhs); 3.807 - 3.808 - end(binaryNode); 3.809 - return binaryNode; 3.810 + return end(ensureSymbol(Type.BOOLEAN, binaryNode)); 3.811 } 3.812 3.813 private Node coerce(final BinaryNode binaryNode, final Type operandType, final Type destType) { 3.814 @@ -1207,11 +1215,9 @@ 3.815 // as, say, an int : function(x) { return x & 4711 }, and x is not defined in 3.816 // the function. to make this work, uncomment the following two type inferences 3.817 // and debug. 3.818 - 3.819 //newType(binaryNode.lhs().getSymbol(), operandType); 3.820 //newType(binaryNode.rhs().getSymbol(), operandType); 3.821 - ensureSymbol(destType, binaryNode); 3.822 - return binaryNode; 3.823 + return ensureSymbol(destType, binaryNode); 3.824 } 3.825 3.826 private Node coerce(final BinaryNode binaryNode, final Type type) { 3.827 @@ -1295,9 +1301,7 @@ 3.828 3.829 @Override 3.830 public Node leaveOR(final BinaryNode binaryNode) { 3.831 - ensureSymbol(Type.OBJECT, binaryNode); 3.832 - end(binaryNode); 3.833 - return binaryNode; 3.834 + return end(ensureSymbol(Type.OBJECT, binaryNode)); 3.835 } 3.836 3.837 @Override 3.838 @@ -1346,50 +1350,13 @@ 3.839 ensureTypeNotUnknown(rhs); 3.840 3.841 final Type type = Type.widest(lhs.getType(), rhs.getType()); 3.842 - ensureSymbol(type, ternaryNode); 3.843 - 3.844 - end(ternaryNode); 3.845 - assert ternaryNode.getSymbol() != null; 3.846 - 3.847 - return ternaryNode; 3.848 + return end(ensureSymbol(type, ternaryNode)); 3.849 } 3.850 3.851 - private void initThis(final Block block) { 3.852 - final Symbol thisSymbol = defineSymbol(block, THIS.symbolName(), IS_PARAM | IS_THIS, null); 3.853 - newType(thisSymbol, Type.OBJECT); 3.854 - thisSymbol.setNeedsSlot(true); 3.855 - } 3.856 - 3.857 - private void initScope(final Block block) { 3.858 - final Symbol scopeSymbol = defineSymbol(block, SCOPE.symbolName(), IS_VAR | IS_INTERNAL, null); 3.859 - newType(scopeSymbol, Type.typeFor(ScriptObject.class)); 3.860 - scopeSymbol.setNeedsSlot(true); 3.861 - } 3.862 - 3.863 - private void initReturn(final Block block) { 3.864 - final Symbol returnSymbol = defineSymbol(block, RETURN.symbolName(), IS_VAR | IS_INTERNAL, null); 3.865 - newType(returnSymbol, Type.OBJECT); 3.866 - returnSymbol.setNeedsSlot(true); 3.867 - //return symbol is always object as it's the __return__ thing. What returnType is is another matter though 3.868 - } 3.869 - 3.870 - private void initVarArg(final Block block, final boolean needsArguments) { 3.871 - final Symbol varArgsSymbol = defineSymbol(block, VARARGS.symbolName(), IS_PARAM | IS_INTERNAL, null); 3.872 - varArgsSymbol.setTypeOverride(Type.OBJECT_ARRAY); 3.873 - varArgsSymbol.setNeedsSlot(true); 3.874 - 3.875 - if (needsArguments) { 3.876 - final Symbol argumentsSymbol = defineSymbol(block, ARGUMENTS.symbolName(), IS_VAR | IS_INTERNAL, null); 3.877 - newType(argumentsSymbol, Type.typeFor(ScriptObject.class)); 3.878 - argumentsSymbol.setNeedsSlot(true); 3.879 - addLocalDef(ARGUMENTS.symbolName()); 3.880 - } 3.881 - } 3.882 - 3.883 - private void initCallee(final Block block) { 3.884 - final Symbol calleeSymbol = defineSymbol(block, CALLEE.symbolName(), IS_PARAM | IS_INTERNAL, null); 3.885 - newType(calleeSymbol, FunctionNode.FUNCTION_TYPE); 3.886 - calleeSymbol.setNeedsSlot(true); 3.887 + private void initCompileConstant(final CompilerConstants cc, final Block block, final int flags, final Type type) { 3.888 + final Symbol symbol = defineSymbol(block, cc.symbolName(), flags); 3.889 + newType(symbol, type); 3.890 + symbol.setNeedsSlot(true); 3.891 } 3.892 3.893 /** 3.894 @@ -1399,19 +1366,28 @@ 3.895 * @param functionNode the function node 3.896 */ 3.897 private void initParameters(final FunctionNode functionNode, final Block body) { 3.898 + int pos = 0; 3.899 for (final IdentNode param : functionNode.getParameters()) { 3.900 addLocalDef(param.getName()); 3.901 - final Symbol paramSymbol = defineSymbol(body, param.getName(), IS_PARAM, param); 3.902 + 3.903 + final Type callSiteParamType = functionNode.getHints().getParameterType(pos); 3.904 + int flags = IS_PARAM; 3.905 + if (callSiteParamType != null) { 3.906 + LOG.info("Param ", param, " has a callsite type ", callSiteParamType, ". Using that."); 3.907 + flags |= Symbol.IS_SPECIALIZED_PARAM; 3.908 + } 3.909 + 3.910 + final Symbol paramSymbol = defineSymbol(body, param.getName(), flags); 3.911 + assert paramSymbol != null; 3.912 + 3.913 if (paramSymbol != null) { 3.914 - final Type callSiteParamType = functionNode.getSpecializedType(param); 3.915 - if (callSiteParamType != null) { 3.916 - LOG.info("Param ", paramSymbol, " has a callsite type ", callSiteParamType, ". Using that."); 3.917 - } 3.918 newType(paramSymbol, callSiteParamType == null ? Type.UNKNOWN : callSiteParamType); 3.919 } 3.920 3.921 - LOG.info("Initialized param ", paramSymbol); 3.922 + LOG.info("Initialized param ", pos, "=", paramSymbol); 3.923 + pos++; 3.924 } 3.925 + 3.926 } 3.927 3.928 /** 3.929 @@ -1420,14 +1396,19 @@ 3.930 * 3.931 * @param functionNode functionNode 3.932 */ 3.933 - private static void finalizeParameters(final FunctionNode functionNode) { 3.934 + private FunctionNode finalizeParameters(final FunctionNode functionNode) { 3.935 + final List<IdentNode> newParams = new ArrayList<>(); 3.936 final boolean isVarArg = functionNode.isVarArg(); 3.937 3.938 - for (final IdentNode ident : functionNode.getParameters()) { 3.939 - final Symbol paramSymbol = ident.getSymbol(); 3.940 + int pos = 0; 3.941 + for (final IdentNode param : functionNode.getParameters()) { 3.942 + final Symbol paramSymbol = functionNode.getBody().getExistingSymbol(param.getName()); 3.943 + assert paramSymbol != null; 3.944 + assert paramSymbol.isParam(); 3.945 + newParams.add((IdentNode)param.setSymbol(getLexicalContext(), paramSymbol)); 3.946 3.947 assert paramSymbol != null; 3.948 - Type type = functionNode.getSpecializedType(ident); 3.949 + Type type = functionNode.getHints().getParameterType(pos); 3.950 if (type == null) { 3.951 type = Type.OBJECT; 3.952 } 3.953 @@ -1436,7 +1417,7 @@ 3.954 // this function, we can tell the runtime system that no matter what the 3.955 // call site is, use this information. TODO 3.956 if (!paramSymbol.getSymbolType().isObject()) { 3.957 - LOG.finest("Parameter ", ident, " could profit from specialization to ", paramSymbol.getSymbolType()); 3.958 + LOG.finest("Parameter ", param, " could profit from specialization to ", paramSymbol.getSymbolType()); 3.959 } 3.960 3.961 newType(paramSymbol, Type.widest(type, paramSymbol.getSymbolType())); 3.962 @@ -1445,7 +1426,11 @@ 3.963 if (isVarArg) { 3.964 paramSymbol.setNeedsSlot(false); 3.965 } 3.966 + 3.967 + pos++; 3.968 } 3.969 + 3.970 + return functionNode.setParameters(getLexicalContext(), newParams); 3.971 } 3.972 3.973 /** 3.974 @@ -1459,7 +1444,7 @@ 3.975 3.976 for (final Property property : map.getProperties()) { 3.977 final String key = property.getKey(); 3.978 - final Symbol symbol = defineSymbol(block, key, IS_GLOBAL, null); 3.979 + final Symbol symbol = defineSymbol(block, key, IS_GLOBAL); 3.980 newType(symbol, Type.OBJECT); 3.981 LOG.info("Added global symbol from property map ", symbol); 3.982 } 3.983 @@ -1498,7 +1483,7 @@ 3.984 * objects as parameters, for example +, but not *, which is known 3.985 * to coerce types into doubles 3.986 */ 3.987 - if (node.getType().isUnknown() || symbol.isParam()) { 3.988 + if (node.getType().isUnknown() || (symbol.isParam() && !symbol.isSpecializedParam())) { 3.989 newType(symbol, Type.OBJECT); 3.990 symbol.setCanBeUndefined(); 3.991 } 3.992 @@ -1614,29 +1599,6 @@ 3.993 } while (!changed.isEmpty()); 3.994 } 3.995 3.996 - /** 3.997 - * This assign helper is called after an assignment, when all children of 3.998 - * the assign has been processed. It fixes the types and recursively makes 3.999 - * sure that everyhing has slots that should have them in the chain. 3.1000 - * 3.1001 - * @param binaryNode assignment node 3.1002 - */ 3.1003 - private Node leaveAssignmentNode(final BinaryNode binaryNode) { 3.1004 - final Node lhs = binaryNode.lhs(); 3.1005 - final Node rhs = binaryNode.rhs(); 3.1006 - 3.1007 - final Type type; 3.1008 - if (rhs.getType().isNumeric()) { 3.1009 - type = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 3.1010 - } else { 3.1011 - type = Type.OBJECT; //force lhs to be an object if not numeric assignment, e.g. strings too. 3.1012 - } 3.1013 - ensureSymbol(type, binaryNode); 3.1014 - newType(lhs.getSymbol(), type); 3.1015 - end(binaryNode); 3.1016 - return binaryNode; 3.1017 - } 3.1018 - 3.1019 private Node leaveSelfModifyingAssignmentNode(final BinaryNode binaryNode) { 3.1020 return leaveSelfModifyingAssignmentNode(binaryNode, binaryNode.getWidestOperationType()); 3.1021 } 3.1022 @@ -1646,25 +1608,20 @@ 3.1023 final Node lhs = binaryNode.lhs(); 3.1024 3.1025 newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType 3.1026 - ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 3.1027 +// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 3.1028 3.1029 ensureAssignmentSlots(getLexicalContext().getCurrentFunction(), binaryNode); 3.1030 3.1031 - end(binaryNode); 3.1032 - return binaryNode; 3.1033 + return end(ensureSymbol(destType, binaryNode)); 3.1034 } 3.1035 3.1036 - private Symbol ensureSymbol(final FunctionNode functionNode, final Type type, final Node node) { 3.1037 - LOG.info("New TEMPORARY added to ", functionNode.getName(), " type=", type); 3.1038 - return functionNode.ensureSymbol(getLexicalContext().getCurrentBlock(), type, node); 3.1039 - } 3.1040 - 3.1041 - private Symbol ensureSymbol(final Type type, final Node node) { 3.1042 - return ensureSymbol(getLexicalContext().getCurrentFunction(), type, node); 3.1043 + private Node ensureSymbol(final Type type, final Node node) { 3.1044 + LOG.info("New TEMPORARY added to ", getLexicalContext().getCurrentFunction().getName(), " type=", type); 3.1045 + return Attr.ensureSymbol(getLexicalContext(), getLexicalContext().getCurrentBlock(), type, node); 3.1046 } 3.1047 3.1048 private Symbol newInternal(final String name, final Type type) { 3.1049 - final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL, null); 3.1050 + final Symbol iter = defineSymbol(getLexicalContext().getCurrentBlock(), name, IS_VAR | IS_INTERNAL); 3.1051 iter.setType(type); // NASHORN-73 3.1052 return iter; 3.1053 } 3.1054 @@ -1721,6 +1678,17 @@ 3.1055 localUses.peek().add(name); 3.1056 } 3.1057 3.1058 + static Node ensureSymbol(final LexicalContext lc, final Block block, final Type type, final Node node) { 3.1059 + Symbol symbol = node.getSymbol(); 3.1060 + if (symbol != null) { 3.1061 + return node; 3.1062 + } 3.1063 + final String uname = lc.getCurrentFunction().uniqueName(TEMP_PREFIX.symbolName()); 3.1064 + symbol = new Symbol(uname, IS_TEMP, type); 3.1065 + block.putSymbol(lc, symbol); 3.1066 + return node.setSymbol(lc, symbol); 3.1067 + } 3.1068 + 3.1069 /** 3.1070 * Pessimistically promote all symbols in current function node to Object types 3.1071 * This is done when the function contains unevaluated black boxes such as 3.1072 @@ -1731,8 +1699,7 @@ 3.1073 private static void objectifySymbols(final Block body) { 3.1074 body.accept(new NodeVisitor() { 3.1075 private void toObject(final Block block) { 3.1076 - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext();) { 3.1077 - final Symbol symbol = iter.next(); 3.1078 + for (final Symbol symbol : block.getSymbols()) { 3.1079 if (!symbol.isTemp()) { 3.1080 newType(symbol, Type.OBJECT); 3.1081 }
4.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Thu May 02 15:01:16 2013 -0300 4.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Fri May 03 15:33:54 2013 +0200 4.3 @@ -568,8 +568,7 @@ 4.4 * @param block block containing symbols. 4.5 */ 4.6 private void symbolInfo(final Block block) { 4.7 - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 4.8 - final Symbol symbol = iter.next(); 4.9 + for (final Symbol symbol : block.getSymbols()) { 4.10 if (symbol.hasSlot()) { 4.11 method.localVariable(symbol, block.getEntryLabel(), block.getBreakLabel()); 4.12 } 4.13 @@ -937,11 +936,10 @@ 4.14 4.15 private static int assignSlots(final Block block, final int firstSlot) { 4.16 int nextSlot = firstSlot; 4.17 - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 4.18 - final Symbol next = iter.next(); 4.19 - if (next.hasSlot()) { 4.20 - next.setSlot(nextSlot); 4.21 - nextSlot += next.slotCount(); 4.22 + for (final Symbol symbol : block.getSymbols()) { 4.23 + if (symbol.hasSlot()) { 4.24 + symbol.setSlot(nextSlot); 4.25 + nextSlot += symbol.slotCount(); 4.26 } 4.27 } 4.28 return nextSlot; 4.29 @@ -1002,10 +1000,7 @@ 4.30 4.31 final boolean hasArguments = function.needsArguments(); 4.32 4.33 - final Iterator<Symbol> symbols = block.symbolIterator(); 4.34 - 4.35 - while (symbols.hasNext()) { 4.36 - final Symbol symbol = symbols.next(); 4.37 + for (final Symbol symbol : block.getSymbols()) { 4.38 4.39 if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { 4.40 continue; 4.41 @@ -1076,12 +1071,7 @@ 4.42 } 4.43 } 4.44 4.45 - final Iterator<Symbol> iter = block.symbolIterator(); 4.46 - final List<Symbol> symbols = new ArrayList<>(); 4.47 - while (iter.hasNext()) { 4.48 - symbols.add(iter.next()); 4.49 - } 4.50 - initSymbols(symbols); 4.51 + initSymbols(block.getSymbols()); 4.52 } 4.53 4.54 // Debugging: print symbols? @see --print-symbols flag 4.55 @@ -2364,7 +2354,6 @@ 4.56 public boolean enterDISCARD(final UnaryNode unaryNode) { 4.57 final Node rhs = unaryNode.rhs(); 4.58 4.59 - // System.err.println("**** Enter discard " + unaryNode); 4.60 discard.push(rhs); 4.61 load(rhs); 4.62 4.63 @@ -2373,7 +2362,7 @@ 4.64 method.pop(); 4.65 discard.pop(); 4.66 } 4.67 - // System.err.println("**** Leave discard " + unaryNode); 4.68 + 4.69 return false; 4.70 } 4.71
5.1 --- a/src/jdk/nashorn/internal/codegen/CompilationPhase.java Thu May 02 15:01:16 2013 -0300 5.2 +++ b/src/jdk/nashorn/internal/codegen/CompilationPhase.java Fri May 03 15:33:54 2013 +0200 5.3 @@ -42,7 +42,7 @@ 5.4 */ 5.5 LAZY_INITIALIZATION_PHASE(EnumSet.of(INITIALIZED, PARSED)) { 5.6 @Override 5.7 - FunctionNode transform(final Compiler compiler, final FunctionNode fn0) { 5.8 + FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 5.9 5.10 /* 5.11 * For lazy compilation, we might be given a node previously marked 5.12 @@ -58,8 +58,7 @@ 5.13 * function from a trampoline 5.14 */ 5.15 5.16 - final FunctionNode outermostFunctionNode = compiler.getFunctionNode(); 5.17 - assert outermostFunctionNode == fn0; 5.18 + final FunctionNode outermostFunctionNode = fn; 5.19 5.20 final Set<FunctionNode> neverLazy = new HashSet<>(); 5.21 final Set<FunctionNode> lazy = new HashSet<>(); 5.22 @@ -172,20 +171,26 @@ 5.23 ATTRIBUTION_PHASE(EnumSet.of(INITIALIZED, PARSED, CONSTANT_FOLDED, LOWERED)) { 5.24 @Override 5.25 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 5.26 - return (FunctionNode)initReturnTypes(fn).accept(new Attr()); 5.27 + return (FunctionNode)enterAttr(fn).accept(new Attr()); 5.28 } 5.29 5.30 /** 5.31 * Pessimistically set all lazy functions' return types to Object 5.32 + * and the function symbols to object 5.33 * @param functionNode node where to start iterating 5.34 */ 5.35 - private FunctionNode initReturnTypes(final FunctionNode functionNode) { 5.36 + private FunctionNode enterAttr(final FunctionNode functionNode) { 5.37 return (FunctionNode)functionNode.accept(new NodeVisitor() { 5.38 @Override 5.39 public Node leaveFunctionNode(final FunctionNode node) { 5.40 - return node.isLazy() ? 5.41 - node.setReturnType(getLexicalContext(), Type.OBJECT) : 5.42 - node.setReturnType(getLexicalContext(), Type.UNKNOWN); 5.43 + final LexicalContext lc = getLexicalContext(); 5.44 + if (node.isLazy()) { 5.45 + FunctionNode newNode = node.setReturnType(getLexicalContext(), Type.OBJECT); 5.46 + return Attr.ensureSymbol(lc, lc.getCurrentBlock(), Type.OBJECT, newNode); 5.47 + } 5.48 + //node may have a reference here that needs to be nulled if it was referred to by 5.49 + //its outer context, if it is lazy and not attributed 5.50 + return node.setReturnType(lc, Type.UNKNOWN).setSymbol(lc, null); 5.51 } 5.52 }); 5.53 } 5.54 @@ -207,6 +212,7 @@ 5.55 FunctionNode transform(final Compiler compiler, final FunctionNode fn) { 5.56 final CompileUnit outermostCompileUnit = compiler.addCompileUnit(compiler.firstCompileUnitName()); 5.57 5.58 +// assert fn.isProgram() ; 5.59 final FunctionNode newFunctionNode = new Splitter(compiler, fn, outermostCompileUnit).split(fn); 5.60 5.61 assert newFunctionNode.getCompileUnit() == outermostCompileUnit : "fn.compileUnit (" + newFunctionNode.getCompileUnit() + ") != " + outermostCompileUnit; 5.62 @@ -216,15 +222,6 @@ 5.63 compiler.setStrictMode(true); 5.64 } 5.65 5.66 - /* 5.67 - newFunctionNode.accept(new NodeVisitor() { 5.68 - @Override 5.69 - public boolean enterFunctionNode(final FunctionNode functionNode) { 5.70 - assert functionNode.getCompileUnit() != null : functionNode.getName() + " " + Debug.id(functionNode) + " has no compile unit"; 5.71 - return true; 5.72 - } 5.73 - });*/ 5.74 - 5.75 return newFunctionNode; 5.76 } 5.77
6.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Thu May 02 15:01:16 2013 -0300 6.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Fri May 03 15:33:54 2013 +0200 6.3 @@ -77,6 +77,8 @@ 6.4 /** Name of the objects package */ 6.5 public static final String OBJECTS_PACKAGE = "jdk/nashorn/internal/objects"; 6.6 6.7 + private Source source; 6.8 + 6.9 private final Map<String, byte[]> bytecode; 6.10 6.11 private final Set<CompileUnit> compileUnits; 6.12 @@ -87,12 +89,10 @@ 6.13 6.14 private final ScriptEnvironment env; 6.15 6.16 - private final String scriptName; 6.17 + private String scriptName; 6.18 6.19 private boolean strict; 6.20 6.21 - private FunctionNode functionNode; 6.22 - 6.23 private CodeInstaller<ScriptEnvironment> installer; 6.24 6.25 /** logger for compiler, trampolines, splits and related code generation events 6.26 @@ -168,6 +168,41 @@ 6.27 } 6.28 6.29 /** 6.30 + * Environment information known to the compile, e.g. params 6.31 + */ 6.32 + public static class Hints { 6.33 + private final Type[] paramTypes; 6.34 + 6.35 + /** singleton empty hints */ 6.36 + public static final Hints EMPTY = new Hints(); 6.37 + 6.38 + private Hints() { 6.39 + this.paramTypes = null; 6.40 + } 6.41 + 6.42 + /** 6.43 + * Constructor 6.44 + * @param paramTypes known parameter types for this callsite 6.45 + */ 6.46 + public Hints(final Type[] paramTypes) { 6.47 + this.paramTypes = paramTypes; 6.48 + } 6.49 + 6.50 + /** 6.51 + * Get the parameter type for this parameter position, or 6.52 + * null if now known 6.53 + * @param pos position 6.54 + * @return parameter type for this callsite if known 6.55 + */ 6.56 + public Type getParameterType(final int pos) { 6.57 + if (paramTypes != null && pos < paramTypes.length) { 6.58 + return paramTypes[pos]; 6.59 + } 6.60 + return null; 6.61 + } 6.62 + } 6.63 + 6.64 + /** 6.65 * Standard (non-lazy) compilation, that basically will take an entire script 6.66 * and JIT it at once. This can lead to long startup time and fewer type 6.67 * specializations 6.68 @@ -207,21 +242,22 @@ 6.69 * @param strict should this compilation use strict mode semantics 6.70 */ 6.71 //TODO support an array of FunctionNodes for batch lazy compilation 6.72 - Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final CompilationSequence sequence, final boolean strict) { 6.73 + Compiler(final ScriptEnvironment env, final CodeInstaller<ScriptEnvironment> installer, final CompilationSequence sequence, final boolean strict) { 6.74 this.env = env; 6.75 - this.functionNode = functionNode; 6.76 this.sequence = sequence; 6.77 this.installer = installer; 6.78 - this.strict = strict || functionNode.isStrict(); 6.79 this.constantData = new ConstantData(); 6.80 this.compileUnits = new HashSet<>(); 6.81 this.bytecode = new HashMap<>(); 6.82 + } 6.83 6.84 + private void initCompiler(final FunctionNode functionNode) { 6.85 + this.strict = strict || functionNode.isStrict(); 6.86 final StringBuilder sb = new StringBuilder(); 6.87 sb.append(functionNode.uniqueName(DEFAULT_SCRIPT_NAME.symbolName() + lazyTag(functionNode))). 6.88 append('$'). 6.89 append(safeSourceName(functionNode.getSource())); 6.90 - 6.91 + this.source = functionNode.getSource(); 6.92 this.scriptName = sb.toString(); 6.93 } 6.94 6.95 @@ -229,52 +265,43 @@ 6.96 * Constructor 6.97 * 6.98 * @param installer code installer 6.99 - * @param functionNode function node (in any available {@link CompilationState}) to compile 6.100 * @param strict should this compilation use strict mode semantics 6.101 */ 6.102 - public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode, final boolean strict) { 6.103 - this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), strict); 6.104 + public Compiler(final CodeInstaller<ScriptEnvironment> installer, final boolean strict) { 6.105 + this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), strict); 6.106 } 6.107 6.108 /** 6.109 * Constructor - compilation will use the same strict semantics as in script environment 6.110 * 6.111 * @param installer code installer 6.112 - * @param functionNode function node (in any available {@link CompilationState}) to compile 6.113 */ 6.114 - public Compiler(final CodeInstaller<ScriptEnvironment> installer, final FunctionNode functionNode) { 6.115 - this(installer.getOwner(), installer, functionNode, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); 6.116 + public Compiler(final CodeInstaller<ScriptEnvironment> installer) { 6.117 + this(installer.getOwner(), installer, sequence(installer.getOwner()._lazy_compilation), installer.getOwner()._strict); 6.118 } 6.119 6.120 /** 6.121 * Constructor - compilation needs no installer, but uses a script environment 6.122 * Used in "compile only" scenarios 6.123 * @param env a script environment 6.124 - * @param functionNode functionNode to compile 6.125 */ 6.126 - public Compiler(final ScriptEnvironment env, final FunctionNode functionNode) { 6.127 - this(env, null, functionNode, sequence(env._lazy_compilation), env._strict); 6.128 + public Compiler(final ScriptEnvironment env) { 6.129 + this(env, null, sequence(env._lazy_compilation), env._strict); 6.130 } 6.131 6.132 /** 6.133 * Execute the compilation this Compiler was created with 6.134 - * @params param types if known, for specialization 6.135 + * @param functionNode function node to compile from its current state 6.136 * @throws CompilationException if something goes wrong 6.137 * @return function node that results from code transforms 6.138 */ 6.139 - public FunctionNode compile() throws CompilationException { 6.140 - return compile(null); 6.141 - } 6.142 + public FunctionNode compile(final FunctionNode functionNode) throws CompilationException { 6.143 + FunctionNode newFunctionNode = functionNode; 6.144 6.145 - /** 6.146 - * Execute the compilation this Compiler was created with 6.147 - * @param paramTypes param types if known, for specialization 6.148 - * @throws CompilationException if something goes wrong 6.149 - * @return function node that results from code transforms 6.150 - */ 6.151 - public FunctionNode compile(final Class<?> paramTypes) throws CompilationException { 6.152 + initCompiler(newFunctionNode); //TODO move this state into functionnode? 6.153 + 6.154 for (final String reservedName : RESERVED_NAMES) { 6.155 - functionNode.uniqueName(reservedName); 6.156 + newFunctionNode.uniqueName(reservedName); 6.157 } 6.158 6.159 final boolean fine = !LOG.levelAbove(Level.FINE); 6.160 @@ -283,7 +310,7 @@ 6.161 long time = 0L; 6.162 6.163 for (final CompilationPhase phase : sequence) { 6.164 - this.functionNode = phase.apply(this, functionNode); 6.165 + newFunctionNode = phase.apply(this, newFunctionNode); 6.166 6.167 final long duration = Timing.isEnabled() ? (phase.getEndTime() - phase.getStartTime()) : 0L; 6.168 time += duration; 6.169 @@ -293,7 +320,7 @@ 6.170 6.171 sb.append(phase.toString()). 6.172 append(" done for function '"). 6.173 - append(functionNode.getName()). 6.174 + append(newFunctionNode.getName()). 6.175 append('\''); 6.176 6.177 if (duration > 0L) { 6.178 @@ -309,7 +336,7 @@ 6.179 if (info) { 6.180 final StringBuilder sb = new StringBuilder(); 6.181 sb.append("Compile job for '"). 6.182 - append(functionNode.getName()). 6.183 + append(newFunctionNode.getName()). 6.184 append("' finished"); 6.185 6.186 if (time > 0L) { 6.187 @@ -321,16 +348,15 @@ 6.188 LOG.info(sb); 6.189 } 6.190 6.191 - return functionNode; 6.192 + return newFunctionNode; 6.193 } 6.194 6.195 - private Class<?> install(final String className, final byte[] code) { 6.196 + private Class<?> install(final FunctionNode functionNode, final String className, final byte[] code) { 6.197 LOG.fine("Installing class ", className); 6.198 6.199 final Class<?> clazz = installer.install(Compiler.binaryName(className), code); 6.200 6.201 try { 6.202 - final Source source = getSource(); 6.203 final Object[] constants = getConstantData().toArray(); 6.204 // Need doPrivileged because these fields are private 6.205 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 6.206 @@ -355,9 +381,10 @@ 6.207 6.208 /** 6.209 * Install compiled classes into a given loader 6.210 + * @param functionNode function node to install - must be in {@link CompilationState#EMITTED} state 6.211 * @return root script class - if there are several compile units they will also be installed 6.212 */ 6.213 - public Class<?> install() { 6.214 + public Class<?> install(final FunctionNode functionNode) { 6.215 final long t0 = Timing.isEnabled() ? System.currentTimeMillis() : 0L; 6.216 6.217 assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " has no bytecode and cannot be installed"; 6.218 @@ -366,7 +393,7 @@ 6.219 6.220 final String rootClassName = firstCompileUnitName(); 6.221 final byte[] rootByteCode = bytecode.get(rootClassName); 6.222 - final Class<?> rootClass = install(rootClassName, rootByteCode); 6.223 + final Class<?> rootClass = install(functionNode, rootClassName, rootByteCode); 6.224 6.225 int length = rootByteCode.length; 6.226 6.227 @@ -380,7 +407,7 @@ 6.228 final byte[] code = entry.getValue(); 6.229 length += code.length; 6.230 6.231 - installedClasses.put(className, install(className, code)); 6.232 + installedClasses.put(className, install(functionNode, className, code)); 6.233 } 6.234 6.235 for (final CompileUnit unit : compileUnits) { 6.236 @@ -430,10 +457,6 @@ 6.237 this.strict = strict; 6.238 } 6.239 6.240 - FunctionNode getFunctionNode() { 6.241 - return functionNode; 6.242 - } 6.243 - 6.244 ConstantData getConstantData() { 6.245 return constantData; 6.246 } 6.247 @@ -442,10 +465,6 @@ 6.248 return installer; 6.249 } 6.250 6.251 - Source getSource() { 6.252 - return functionNode.getSource(); 6.253 - } 6.254 - 6.255 void addClass(final String name, final byte[] code) { 6.256 bytecode.put(name, code); 6.257 } 6.258 @@ -496,7 +515,7 @@ 6.259 } 6.260 6.261 private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) { 6.262 - final ClassEmitter classEmitter = new ClassEmitter(env, functionNode.getSource().getName(), unitClassName, strict); 6.263 + final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict); 6.264 final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight); 6.265 6.266 classEmitter.begin();
7.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Thu May 02 15:01:16 2013 -0300 7.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Fri May 03 15:33:54 2013 +0200 7.3 @@ -30,7 +30,6 @@ 7.4 7.5 import java.util.ArrayList; 7.6 import java.util.HashSet; 7.7 -import java.util.Iterator; 7.8 import java.util.List; 7.9 import jdk.nashorn.internal.codegen.types.Type; 7.10 import jdk.nashorn.internal.ir.AccessNode; 7.11 @@ -354,13 +353,6 @@ 7.12 return true; 7.13 } 7.14 7.15 - /* 7.16 - @Override 7.17 - public Node leaveBlock(final Block block) { 7.18 - final LexicalContext lc = getLexicalContext(); 7.19 - return block;//.setFlag(lc, lc.getFlags(block)); 7.20 - }*/ 7.21 - 7.22 @Override 7.23 public Node leaveCatchNode(final CatchNode catchNode) { 7.24 final Node exceptionCondition = catchNode.getExceptionCondition(); 7.25 @@ -551,8 +543,7 @@ 7.26 final boolean allVarsInScope = functionNode.allVarsInScope(); 7.27 final boolean isVarArg = functionNode.isVarArg(); 7.28 7.29 - for (final Iterator<Symbol> iter = block.symbolIterator(); iter.hasNext(); ) { 7.30 - final Symbol symbol = iter.next(); 7.31 + for (final Symbol symbol : block.getSymbols()) { 7.32 if (symbol.isInternal() || symbol.isThis() || symbol.isTemp()) { 7.33 continue; 7.34 } 7.35 @@ -812,14 +803,12 @@ 7.36 7.37 LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'"); 7.38 7.39 + assert !node.isTerminal(); 7.40 + 7.41 final LexicalContext lc = getLexicalContext(); 7.42 //This is the only place in this file that can create new temporaries 7.43 //FinalizeTypes may not introduce ANY node that is not a conversion. 7.44 - lc.getCurrentFunction().ensureSymbol(lc.getCurrentBlock(), to, resultNode); 7.45 - 7.46 - assert !node.isTerminal(); 7.47 - 7.48 - return resultNode; 7.49 + return Attr.ensureSymbol(lc, lc.getCurrentBlock(), to, resultNode); 7.50 } 7.51 7.52 private static Node discard(final Node node) { 7.53 @@ -905,7 +894,7 @@ 7.54 7.55 if (literalNode != null) { 7.56 //inherit literal symbol for attr. 7.57 - literalNode.setSymbol(parent.getSymbol()); 7.58 + literalNode = (LiteralNode<?>)literalNode.setSymbol(null, parent.getSymbol()); 7.59 } 7.60 7.61 return literalNode;
8.1 --- a/src/jdk/nashorn/internal/codegen/ObjectCreator.java Thu May 02 15:01:16 2013 -0300 8.2 +++ b/src/jdk/nashorn/internal/codegen/ObjectCreator.java Fri May 03 15:33:54 2013 +0200 8.3 @@ -27,7 +27,6 @@ 8.4 8.5 import java.util.List; 8.6 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_PADDING; 8.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.FIELD_ROUNDING; 8.8 import jdk.nashorn.internal.ir.Symbol; 8.9 import jdk.nashorn.internal.runtime.Context; 8.10 import jdk.nashorn.internal.runtime.PropertyMap;
9.1 --- a/src/jdk/nashorn/internal/codegen/Splitter.java Thu May 02 15:01:16 2013 -0300 9.2 +++ b/src/jdk/nashorn/internal/codegen/Splitter.java Fri May 03 15:33:54 2013 +0200 9.3 @@ -75,7 +75,7 @@ 9.4 */ 9.5 public Splitter(final Compiler compiler, final FunctionNode functionNode, final CompileUnit outermostCompileUnit) { 9.6 this.compiler = compiler; 9.7 - this.outermost = functionNode; 9.8 + this.outermost = functionNode; 9.9 this.outermostCompileUnit = outermostCompileUnit; 9.10 } 9.11 9.12 @@ -95,7 +95,7 @@ 9.13 final LexicalContext lc = getLexicalContext(); 9.14 9.15 long weight = WeighNodes.weigh(functionNode); 9.16 - final boolean top = compiler.getFunctionNode() == outermost; 9.17 + final boolean top = fn.isProgram(); //compiler.getFunctionNode() == outermost; 9.18 9.19 if (weight >= SPLIT_THRESHOLD) { 9.20 LOG.finest("Splitting '", functionNode.getName(), "' as its weight ", weight, " exceeds split threshold ", SPLIT_THRESHOLD); 9.21 @@ -273,7 +273,9 @@ 9.22 return literal; 9.23 } 9.24 9.25 - getLexicalContext().setFlag(getLexicalContext().getCurrentFunction(), FunctionNode.IS_SPLIT); 9.26 + final FunctionNode functionNode = getLexicalContext().getCurrentFunction(); 9.27 + 9.28 + getLexicalContext().setFlag(functionNode, FunctionNode.IS_SPLIT); 9.29 9.30 if (literal instanceof ArrayLiteralNode) { 9.31 final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode) literal;
10.1 --- a/src/jdk/nashorn/internal/ir/Block.java Thu May 02 15:01:16 2013 -0300 10.2 +++ b/src/jdk/nashorn/internal/ir/Block.java Fri May 03 15:33:54 2013 +0200 10.3 @@ -30,7 +30,6 @@ 10.4 import java.util.Arrays; 10.5 import java.util.Collections; 10.6 import java.util.Comparator; 10.7 -import java.util.Iterator; 10.8 import java.util.LinkedHashMap; 10.9 import java.util.List; 10.10 import java.util.Map; 10.11 @@ -104,18 +103,26 @@ 10.12 this(source, token, finish, statements.toArray(new Node[statements.size()])); 10.13 } 10.14 10.15 - private Block(final Block block, final int finish, final List<Node> statements, final int flags) { 10.16 + private Block(final Block block, final int finish, final List<Node> statements, final int flags, final Map<String, Symbol> symbols) { 10.17 super(block); 10.18 this.statements = statements; 10.19 this.flags = flags; 10.20 - 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 10.21 + this.symbols = new LinkedHashMap<>(symbols); //todo - symbols have no dependencies on any IR node and can as far as we understand it be shallow copied now 10.22 this.entryLabel = new Label(block.entryLabel); 10.23 - this.finish = finish; 10.24 + this.finish = finish; 10.25 + } 10.26 + 10.27 + /** 10.28 + * Clear the symbols in a block 10.29 + * TODO: make this immutable 10.30 + */ 10.31 + public void clearSymbols() { 10.32 + symbols.clear(); 10.33 } 10.34 10.35 @Override 10.36 public Node ensureUniqueLabels(final LexicalContext lc) { 10.37 - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); 10.38 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols)); 10.39 } 10.40 10.41 /** 10.42 @@ -137,15 +144,15 @@ 10.43 * Get an iterator for all the symbols defined in this block 10.44 * @return symbol iterator 10.45 */ 10.46 - public Iterator<Symbol> symbolIterator() { 10.47 - return symbols.values().iterator(); 10.48 + public List<Symbol> getSymbols() { 10.49 + return Collections.unmodifiableList(new ArrayList<>(symbols.values())); 10.50 } 10.51 10.52 /** 10.53 * Retrieves an existing symbol defined in the current block. 10.54 * @param name the name of the symbol 10.55 * @return an existing symbol with the specified name defined in the current block, or null if this block doesn't 10.56 - * define a symbol with this name. 10.57 + * define a symbol with this name.T 10.58 */ 10.59 public Symbol getExistingSymbol(final String name) { 10.60 return symbols.get(name); 10.61 @@ -241,17 +248,17 @@ 10.62 if (!statements.isEmpty()) { 10.63 lastFinish = statements.get(statements.size() - 1).getFinish(); 10.64 } 10.65 - return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags)); 10.66 + return Node.replaceInLexicalContext(lc, this, new Block(this, Math.max(finish, lastFinish), statements, flags, symbols)); 10.67 } 10.68 10.69 /** 10.70 * Add or overwrite an existing symbol in the block 10.71 * 10.72 - * @param name name of symbol 10.73 + * @param lc get lexical context 10.74 * @param symbol symbol 10.75 */ 10.76 - public void putSymbol(final String name, final Symbol symbol) { 10.77 - symbols.put(name, symbol); 10.78 + public void putSymbol(final LexicalContext lc, final Symbol symbol) { 10.79 + symbols.put(symbol.getName(), symbol); 10.80 } 10.81 10.82 /** 10.83 @@ -268,7 +275,7 @@ 10.84 if (this.flags == flags) { 10.85 return this; 10.86 } 10.87 - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags)); 10.88 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags, symbols)); 10.89 } 10.90 10.91 @Override 10.92 @@ -296,7 +303,7 @@ 10.93 return this; 10.94 } 10.95 10.96 - return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE)); 10.97 + return Node.replaceInLexicalContext(lc, this, new Block(this, finish, statements, flags | NEEDS_SCOPE, symbols)); 10.98 } 10.99 10.100 /** 10.101 @@ -306,13 +313,11 @@ 10.102 * @return next slot 10.103 */ 10.104 public int nextSlot() { 10.105 - final Iterator<Symbol> iter = symbolIterator(); 10.106 int next = 0; 10.107 - while (iter.hasNext()) { 10.108 - final Symbol symbol = iter.next(); 10.109 - if (symbol.hasSlot()) { 10.110 - next += symbol.slotCount(); 10.111 - } 10.112 + for (final Symbol symbol : getSymbols()) { 10.113 + if (symbol.hasSlot()) { 10.114 + next += symbol.slotCount(); 10.115 + } 10.116 } 10.117 return next; 10.118 }
11.1 --- a/src/jdk/nashorn/internal/ir/CatchNode.java Thu May 02 15:01:16 2013 -0300 11.2 +++ b/src/jdk/nashorn/internal/ir/CatchNode.java Fri May 03 15:33:54 2013 +0200 11.3 @@ -138,7 +138,12 @@ 11.4 return body; 11.5 } 11.6 11.7 - private CatchNode setException(final IdentNode exception) { 11.8 + /** 11.9 + * Resets the exception of a catch block 11.10 + * @param exception new exception 11.11 + * @return new catch node if changed, same otherwise 11.12 + */ 11.13 + public CatchNode setException(final IdentNode exception) { 11.14 if (this.exception == exception) { 11.15 return this; 11.16 }
12.1 --- a/src/jdk/nashorn/internal/ir/FunctionNode.java Thu May 02 15:01:16 2013 -0300 12.2 +++ b/src/jdk/nashorn/internal/ir/FunctionNode.java Fri May 03 15:33:54 2013 +0200 12.3 @@ -25,16 +25,12 @@ 12.4 12.5 package jdk.nashorn.internal.ir; 12.6 12.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.LITERAL_PREFIX; 12.8 -import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX; 12.9 -import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT; 12.10 -import static jdk.nashorn.internal.ir.Symbol.IS_TEMP; 12.11 - 12.12 import java.util.Collections; 12.13 import java.util.EnumSet; 12.14 import java.util.HashSet; 12.15 import java.util.List; 12.16 import java.util.Set; 12.17 + 12.18 import jdk.nashorn.internal.codegen.CompileUnit; 12.19 import jdk.nashorn.internal.codegen.Compiler; 12.20 import jdk.nashorn.internal.codegen.CompilerConstants; 12.21 @@ -95,6 +91,10 @@ 12.22 @Ignore 12.23 private final IdentNode ident; 12.24 12.25 + /** Parsed version of functionNode */ 12.26 + @Ignore 12.27 + private final FunctionNode snapshot; 12.28 + 12.29 /** The body of the function node */ 12.30 private final Block body; 12.31 12.32 @@ -127,6 +127,9 @@ 12.33 @Ignore 12.34 private final EnumSet<CompilationState> compilationState; 12.35 12.36 + @Ignore 12.37 + private final Compiler.Hints hints; 12.38 + 12.39 /** Function flags. */ 12.40 private final int flags; 12.41 12.42 @@ -176,6 +179,9 @@ 12.43 /** Does this function have nested declarations? */ 12.44 public static final int HAS_FUNCTION_DECLARATIONS = 1 << 13; 12.45 12.46 + /** Can this function be specialized? */ 12.47 + public static final int CAN_SPECIALIZE = 1 << 14; 12.48 + 12.49 /** Does this function or any nested functions contain an eval? */ 12.50 private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL; 12.51 12.52 @@ -219,37 +225,52 @@ 12.53 final int flags) { 12.54 super(source, token, finish); 12.55 12.56 - this.ident = ident; 12.57 - this.name = name; 12.58 - this.kind = kind; 12.59 - this.parameters = parameters; 12.60 - this.firstToken = firstToken; 12.61 - this.lastToken = token; 12.62 - this.namespace = namespace; 12.63 - this.compilationState = EnumSet.of(CompilationState.INITIALIZED); 12.64 - this.declaredSymbols = new HashSet<>(); 12.65 - this.flags = flags; 12.66 - this.compileUnit = null; 12.67 - this.body = null; 12.68 + this.ident = ident; 12.69 + this.name = name; 12.70 + this.kind = kind; 12.71 + this.parameters = parameters; 12.72 + this.firstToken = firstToken; 12.73 + this.lastToken = token; 12.74 + this.namespace = namespace; 12.75 + this.compilationState = EnumSet.of(CompilationState.INITIALIZED); 12.76 + this.declaredSymbols = new HashSet<>(); 12.77 + this.flags = flags; 12.78 + this.compileUnit = null; 12.79 + this.body = null; 12.80 + this.snapshot = null; 12.81 + this.hints = null; 12.82 } 12.83 12.84 - private FunctionNode(final FunctionNode functionNode, final long lastToken, final int flags, final Type returnType, final CompileUnit compileUnit, final EnumSet<CompilationState> compilationState, final Block body) { 12.85 + private FunctionNode( 12.86 + final FunctionNode functionNode, 12.87 + final long lastToken, 12.88 + final int flags, 12.89 + final Type returnType, 12.90 + final CompileUnit compileUnit, 12.91 + final EnumSet<CompilationState> compilationState, 12.92 + final Block body, 12.93 + final List<IdentNode> parameters, 12.94 + final FunctionNode snapshot, 12.95 + final Compiler.Hints hints) { 12.96 super(functionNode); 12.97 - this.flags = flags; 12.98 - this.returnType = returnType; 12.99 - this.compileUnit = compileUnit; 12.100 - this.lastToken = lastToken; 12.101 + 12.102 + this.flags = flags; 12.103 + this.returnType = returnType; 12.104 + this.compileUnit = compileUnit; 12.105 + this.lastToken = lastToken; 12.106 this.compilationState = compilationState; 12.107 - this.body = body; 12.108 + this.body = body; 12.109 + this.parameters = parameters; 12.110 + this.snapshot = snapshot; 12.111 + this.hints = hints; 12.112 12.113 // the fields below never change - they are final and assigned in constructor 12.114 - this.name = functionNode.name; 12.115 - this.ident = functionNode.ident; 12.116 - this.namespace = functionNode.namespace; 12.117 + this.name = functionNode.name; 12.118 + this.ident = functionNode.ident; 12.119 + this.namespace = functionNode.namespace; 12.120 this.declaredSymbols = functionNode.declaredSymbols; 12.121 - this.kind = functionNode.kind; 12.122 - this.parameters = functionNode.parameters; 12.123 - this.firstToken = functionNode.firstToken; 12.124 + this.kind = functionNode.kind; 12.125 + this.firstToken = functionNode.firstToken; 12.126 } 12.127 12.128 @Override 12.129 @@ -261,6 +282,36 @@ 12.130 } 12.131 12.132 /** 12.133 + * Get the version of this function node's code as it looked upon construction 12.134 + * i.e typically parsed and nothing else 12.135 + * @return initial version of function node 12.136 + */ 12.137 + public FunctionNode getSnapshot() { 12.138 + return snapshot; 12.139 + } 12.140 + 12.141 + /** 12.142 + * Take a snapshot of this function node at a given point in time 12.143 + * and store it in the function node 12.144 + * @param lc lexical context 12.145 + * @return function node 12.146 + */ 12.147 + public FunctionNode snapshot(final LexicalContext lc) { 12.148 + if (this.snapshot == this) { 12.149 + return this; 12.150 + } 12.151 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, this, hints)); 12.152 + } 12.153 + 12.154 + /** 12.155 + * Can this function node be regenerated with more specific type args? 12.156 + * @return true if specialization is possible 12.157 + */ 12.158 + public boolean canSpecialize() { 12.159 + return getFlag(CAN_SPECIALIZE); 12.160 + } 12.161 + 12.162 + /** 12.163 * Get the compilation state of this function 12.164 * @return the compilation state 12.165 */ 12.166 @@ -307,7 +358,28 @@ 12.167 } 12.168 final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState); 12.169 newState.add(state); 12.170 - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body)); 12.171 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, newState, body, parameters, snapshot, hints)); 12.172 + } 12.173 + 12.174 + /** 12.175 + * Get any compiler hints that may associated with the function 12.176 + * @return compiler hints 12.177 + */ 12.178 + public Compiler.Hints getHints() { 12.179 + return this.hints == null ? Compiler.Hints.EMPTY : hints; 12.180 + } 12.181 + 12.182 + /** 12.183 + * Set compiler hints for this function 12.184 + * @param lc lexical context 12.185 + * @param hints compiler hints 12.186 + * @return new function if hints changed 12.187 + */ 12.188 + public FunctionNode setHints(final LexicalContext lc, final Compiler.Hints hints) { 12.189 + if (this.hints == hints) { 12.190 + return this; 12.191 + } 12.192 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.193 } 12.194 12.195 /** 12.196 @@ -319,20 +391,6 @@ 12.197 return namespace.uniqueName(base); 12.198 } 12.199 12.200 - /** 12.201 - * Create a virtual symbol for a literal. 12.202 - * 12.203 - * @param literalNode Primary node to use symbol. 12.204 - * 12.205 - * @return Symbol used. 12.206 - */ 12.207 - public Symbol newLiteral(final LiteralNode<?> literalNode) { 12.208 - final String uname = uniqueName(LITERAL_PREFIX.symbolName()); 12.209 - final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType()); 12.210 - literalNode.setSymbol(symbol); 12.211 - 12.212 - return symbol; 12.213 - } 12.214 12.215 @Override 12.216 public void toString(final StringBuilder sb) { 12.217 @@ -374,7 +432,7 @@ 12.218 if (this.flags == flags) { 12.219 return this; 12.220 } 12.221 - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 12.222 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.223 } 12.224 12.225 @Override 12.226 @@ -483,7 +541,7 @@ 12.227 if(this.body == body) { 12.228 return this; 12.229 } 12.230 - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 12.231 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.232 } 12.233 12.234 /** 12.235 @@ -551,7 +609,7 @@ 12.236 if (this.lastToken == lastToken) { 12.237 return this; 12.238 } 12.239 - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 12.240 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.241 } 12.242 12.243 /** 12.244 @@ -599,13 +657,17 @@ 12.245 } 12.246 12.247 /** 12.248 - * Get a specialized type for an identity, if one exists 12.249 - * @param node node to check specialized type for 12.250 - * @return null if no specialization exists, otherwise type 12.251 + * Reset the compile unit used to compile this function 12.252 + * @see Compiler 12.253 + * @param lc lexical context 12.254 + * @param parameters the compile unit 12.255 + * @return function node or a new one if state was changed 12.256 */ 12.257 - @SuppressWarnings("static-method") 12.258 - public Type getSpecializedType(final IdentNode node) { 12.259 - return null; //TODO implement specialized types later 12.260 + public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) { 12.261 + if (this.parameters == parameters) { 12.262 + return this; 12.263 + } 12.264 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.265 } 12.266 12.267 /** 12.268 @@ -674,7 +736,10 @@ 12.269 returnType), 12.270 compileUnit, 12.271 compilationState, 12.272 - body)); 12.273 + body, 12.274 + parameters, 12.275 + snapshot, 12.276 + hints)); 12.277 } 12.278 12.279 /** 12.280 @@ -705,7 +770,7 @@ 12.281 if (this.compileUnit == compileUnit) { 12.282 return this; 12.283 } 12.284 - return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body)); 12.285 + return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, returnType, compileUnit, compilationState, body, parameters, snapshot, hints)); 12.286 } 12.287 12.288 /** 12.289 @@ -717,19 +782,6 @@ 12.290 * 12.291 * @return Symbol used. 12.292 */ 12.293 - public Symbol ensureSymbol(final Block block, final Type type, final Node node) { 12.294 - Symbol symbol = node.getSymbol(); 12.295 - 12.296 - // If no symbol already present. 12.297 - if (symbol == null) { 12.298 - final String uname = uniqueName(TEMP_PREFIX.symbolName()); 12.299 - symbol = new Symbol(uname, IS_TEMP, type); 12.300 - block.putSymbol(uname, symbol); 12.301 - node.setSymbol(symbol); 12.302 - } 12.303 - 12.304 - return symbol; 12.305 - } 12.306 12.307 /** 12.308 * Get the symbol for a compiler constant, or null if not available (yet)
13.1 --- a/src/jdk/nashorn/internal/ir/LexicalContext.java Thu May 02 15:01:16 2013 -0300 13.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContext.java Fri May 03 15:33:54 2013 +0200 13.3 @@ -64,7 +64,6 @@ 13.4 for (int i = sp - 1; i >= 0; i--) { 13.5 if (stack[i] == node) { 13.6 flags[i] |= flag; 13.7 - //System.err.println("Setting flag " + node + " " + flag); 13.8 return; 13.9 } 13.10 } 13.11 @@ -117,8 +116,6 @@ 13.12 return (FunctionNode)stack[0]; 13.13 } 13.14 13.15 - 13.16 - 13.17 /** 13.18 * Pushes a new block on top of the context, making it the innermost open block. 13.19 * @param node the new node
14.1 --- a/src/jdk/nashorn/internal/ir/LexicalContextNode.java Thu May 02 15:01:16 2013 -0300 14.2 +++ b/src/jdk/nashorn/internal/ir/LexicalContextNode.java Fri May 03 15:33:54 2013 +0200 14.3 @@ -70,4 +70,16 @@ 14.4 final LexicalContextNode newNode = (LexicalContextNode)accept(lc, visitor); 14.5 return lc.pop(newNode); 14.6 } 14.7 + 14.8 + /** 14.9 + * Set the symbol and replace in lexical context if applicable 14.10 + * @param lc lexical context 14.11 + * @param symbol symbol 14.12 + * @return new node if symbol changed 14.13 + */ 14.14 + @Override 14.15 + public Node setSymbol(final LexicalContext lc, final Symbol symbol) { 14.16 + return Node.replaceInLexicalContext(lc, this, (LexicalContextNode)super.setSymbol(null, symbol)); 14.17 + } 14.18 + 14.19 }
15.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Thu May 02 15:01:16 2013 -0300 15.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Fri May 03 15:33:54 2013 +0200 15.3 @@ -659,9 +659,12 @@ 15.4 * Copy constructor 15.5 * @param node source array literal node 15.6 */ 15.7 - protected ArrayLiteralNode(final ArrayLiteralNode node) { 15.8 - super(node); 15.9 + private ArrayLiteralNode(final ArrayLiteralNode node, final Node[] value) { 15.10 + super(node, value); 15.11 this.elementType = node.elementType; 15.12 + this.presets = node.presets; 15.13 + this.postsets = node.postsets; 15.14 + this.units = node.units; 15.15 } 15.16 15.17 /** 15.18 @@ -750,9 +753,8 @@ 15.19 break; 15.20 } 15.21 15.22 - final Symbol symbol = node.getSymbol(); 15.23 - assert symbol != null; //don't run this on unresolved nodes or you are in trouble 15.24 - Type symbolType = symbol.getSymbolType(); 15.25 + assert node.getSymbol() != null; //don't run this on unresolved nodes or you are in trouble 15.26 + Type symbolType = node.getSymbol().getSymbolType(); 15.27 if (symbolType.isUnknown()) { 15.28 symbolType = Type.OBJECT; 15.29 } 15.30 @@ -813,7 +815,8 @@ 15.31 } 15.32 15.33 /** 15.34 - * Get indices of arrays containing computed post sets 15.35 + * Get indices of arrays containing computed post sets. post sets 15.36 + * are things like non literals e.g. "x+y" instead of i or 17 15.37 * @return post set indices 15.38 */ 15.39 public int[] getPostsets() { 15.40 @@ -849,17 +852,17 @@ 15.41 @Override 15.42 public Node accept(final NodeVisitor visitor) { 15.43 if (visitor.enterLiteralNode(this)) { 15.44 - for (int i = 0; i < value.length; i++) { 15.45 - final Node element = value[i]; 15.46 - if (element != null) { 15.47 - value[i] = element.accept(visitor); 15.48 - } 15.49 - } 15.50 - return visitor.leaveLiteralNode(this); 15.51 + final List<Node> oldValue = Arrays.asList(value); 15.52 + final List<Node> newValue = Node.accept(visitor, Node.class, oldValue); 15.53 + return visitor.leaveLiteralNode(oldValue != newValue ? setValue(newValue) : this); 15.54 } 15.55 return this; 15.56 } 15.57 15.58 + private ArrayLiteralNode setValue(final List<Node> value) { 15.59 + return new ArrayLiteralNode(this, value.toArray(new Node[value.size()])); 15.60 + } 15.61 + 15.62 @Override 15.63 public void toString(final StringBuilder sb) { 15.64 sb.append('[');
16.1 --- a/src/jdk/nashorn/internal/ir/Node.java Thu May 02 15:01:16 2013 -0300 16.2 +++ b/src/jdk/nashorn/internal/ir/Node.java Fri May 03 15:33:54 2013 +0200 16.3 @@ -252,10 +252,17 @@ 16.4 * Assign a symbol to this node. See {@link Node#getSymbol()} for explanation 16.5 * of what a symbol is 16.6 * 16.7 + * @param lc lexical context 16.8 * @param symbol the symbol 16.9 + * @return new node 16.10 */ 16.11 - public void setSymbol(final Symbol symbol) { 16.12 - this.symbol = symbol; 16.13 + public Node setSymbol(final LexicalContext lc, final Symbol symbol) { 16.14 + if (this.symbol == symbol) { 16.15 + return this; 16.16 + } 16.17 + final Node newNode = (Node)clone(); 16.18 + newNode.symbol = symbol; 16.19 + return newNode; 16.20 } 16.21 16.22 /** 16.23 @@ -274,7 +281,7 @@ 16.24 final List<T> newList = new ArrayList<>(); 16.25 16.26 for (final Node node : list) { 16.27 - final T newNode = clazz.cast(node.accept(visitor)); 16.28 + final T newNode = node == null ? null : clazz.cast(node.accept(visitor)); 16.29 if (newNode != node) { 16.30 changed = true; 16.31 }
17.1 --- a/src/jdk/nashorn/internal/ir/Symbol.java Thu May 02 15:01:16 2013 -0300 17.2 +++ b/src/jdk/nashorn/internal/ir/Symbol.java Fri May 03 15:33:54 2013 +0200 17.3 @@ -67,6 +67,8 @@ 17.4 public static final int IS_INTERNAL = 1 << 9; 17.5 /** Is this a function self-reference symbol */ 17.6 public static final int IS_FUNCTION_SELF = 1 << 10; 17.7 + /** Is this a specialized param? */ 17.8 + public static final int IS_SPECIALIZED_PARAM = 1 << 11; 17.9 17.10 /** Null or name identifying symbol. */ 17.11 private final String name; 17.12 @@ -384,6 +386,15 @@ 17.13 } 17.14 17.15 /** 17.16 + * Check if this symbol is a function parameter of known 17.17 + * narrowest type 17.18 + * @return true if parameter 17.19 + */ 17.20 + public boolean isSpecializedParam() { 17.21 + return (flags & IS_SPECIALIZED_PARAM) == IS_SPECIALIZED_PARAM; 17.22 + } 17.23 + 17.24 + /** 17.25 * Check whether this symbol ever has primitive assignments. Conservative 17.26 * @return true if primitive assignments exist 17.27 */
18.1 --- a/src/jdk/nashorn/internal/objects/NativeRegExp.java Thu May 02 15:01:16 2013 -0300 18.2 +++ b/src/jdk/nashorn/internal/objects/NativeRegExp.java Fri May 03 15:33:54 2013 +0200 18.3 @@ -794,15 +794,15 @@ 18.4 18.5 RegExpResult match; 18.6 final int inputLength = string.length(); 18.7 - int lastLength = -1; 18.8 - int lastIndex = 0; 18.9 - int lastLastIndex = 0; 18.10 + int splitLastLength = -1; 18.11 + int splitLastIndex = 0; 18.12 + int splitLastLastIndex = 0; 18.13 18.14 - while ((match = execSplit(string, lastIndex)) != null) { 18.15 - lastIndex = match.getIndex() + match.length(); 18.16 + while ((match = execSplit(string, splitLastIndex)) != null) { 18.17 + splitLastIndex = match.getIndex() + match.length(); 18.18 18.19 - if (lastIndex > lastLastIndex) { 18.20 - matches.add(string.substring(lastLastIndex, match.getIndex())); 18.21 + if (splitLastIndex > splitLastLastIndex) { 18.22 + matches.add(string.substring(splitLastLastIndex, match.getIndex())); 18.23 final Object[] groups = match.getGroups(); 18.24 if (groups.length > 1 && match.getIndex() < inputLength) { 18.25 for (int index = 1; index < groups.length && matches.size() < limit; index++) { 18.26 @@ -810,7 +810,7 @@ 18.27 } 18.28 } 18.29 18.30 - lastLength = match.length(); 18.31 + splitLastLength = match.length(); 18.32 18.33 if (matches.size() >= limit) { 18.34 break; 18.35 @@ -818,10 +818,10 @@ 18.36 } 18.37 18.38 // bump the index to avoid infinite loop 18.39 - if (lastIndex == lastLastIndex) { 18.40 - lastIndex++; 18.41 + if (splitLastIndex == splitLastLastIndex) { 18.42 + splitLastIndex++; 18.43 } else { 18.44 - lastLastIndex = lastIndex; 18.45 + splitLastLastIndex = splitLastIndex; 18.46 } 18.47 } 18.48 18.49 @@ -829,12 +829,12 @@ 18.50 // check special case if we need to append an empty string at the 18.51 // end of the match 18.52 // if the lastIndex was the entire string 18.53 - if (lastLastIndex == string.length()) { 18.54 - if (lastLength > 0 || execSplit("", 0) == null) { 18.55 + if (splitLastLastIndex == string.length()) { 18.56 + if (splitLastLength > 0 || execSplit("", 0) == null) { 18.57 matches.add(""); 18.58 } 18.59 } else { 18.60 - matches.add(string.substring(lastLastIndex, inputLength)); 18.61 + matches.add(string.substring(splitLastLastIndex, inputLength)); 18.62 } 18.63 } 18.64 18.65 @@ -899,10 +899,6 @@ 18.66 } 18.67 } 18.68 18.69 - private void setGlobal(final boolean global) { 18.70 - regexp.setGlobal(global); 18.71 - } 18.72 - 18.73 boolean getGlobal() { 18.74 return regexp.isGlobal(); 18.75 }
19.1 --- a/src/jdk/nashorn/internal/parser/AbstractParser.java Thu May 02 15:01:16 2013 -0300 19.2 +++ b/src/jdk/nashorn/internal/parser/AbstractParser.java Fri May 03 15:33:54 2013 +0200 19.3 @@ -249,6 +249,7 @@ 19.4 * 19.5 * @param errorType The error type of the warning 19.6 * @param message Warning message. 19.7 + * @param errorToken error token 19.8 */ 19.9 protected final void warning(final JSErrorType errorType, final String message, final long errorToken) { 19.10 errors.warning(error(errorType, message, errorToken));
20.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Thu May 02 15:01:16 2013 -0300 20.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Fri May 03 15:33:54 2013 +0200 20.3 @@ -305,6 +305,11 @@ 20.4 if (isStrictMode) { 20.5 flags |= FunctionNode.IS_STRICT; 20.6 } 20.7 + if (env._specialize_calls != null) { 20.8 + if (env._specialize_calls.contains(name)) { 20.9 + flags |= FunctionNode.CAN_SPECIALIZE; 20.10 + } 20.11 + } 20.12 20.13 // Start new block. 20.14 FunctionNode functionNode = 20.15 @@ -320,11 +325,11 @@ 20.16 kind, 20.17 flags); 20.18 20.19 - functionNode = functionNode.setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED); 20.20 lc.push(functionNode); 20.21 // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the 20.22 // FunctionNode. 20.23 newBlock(); 20.24 + 20.25 return functionNode; 20.26 } 20.27 20.28 @@ -332,14 +337,19 @@ 20.29 * Restore the current block. 20.30 */ 20.31 private Block restoreBlock(final Block block) { 20.32 - return lc.pop(block);//.setFlag(lc, flags); 20.33 + return lc.pop(block); 20.34 } 20.35 20.36 + 20.37 private FunctionNode restoreFunctionNode(final FunctionNode functionNode, final long lastToken) { 20.38 final Block newBody = restoreBlock(lc.getFunctionBody(functionNode)); 20.39 20.40 - return lc.pop(functionNode).setBody(lc, newBody).setLastToken(lc, lastToken); 20.41 - } 20.42 + return lc.pop(functionNode). 20.43 + setBody(lc, newBody). 20.44 + setLastToken(lc, lastToken). 20.45 + setState(lc, errors.hasErrors() ? CompilationState.PARSE_ERROR : CompilationState.PARSED). 20.46 + snapshot(lc); 20.47 + } 20.48 20.49 /** 20.50 * Get the statements in a block. 20.51 @@ -529,6 +539,7 @@ 20.52 20.53 script = restoreFunctionNode(script, token); //commit code 20.54 script = script.setBody(lc, script.getBody().setNeedsScope(lc)); 20.55 + 20.56 return script; 20.57 } 20.58 20.59 @@ -800,7 +811,6 @@ 20.60 * @param ident Identifier that is verified 20.61 * @param contextString String used in error message to give context to the user 20.62 */ 20.63 - @SuppressWarnings("fallthrough") 20.64 private void verifyStrictIdent(final IdentNode ident, final String contextString) { 20.65 if (isStrictMode) { 20.66 switch (ident.getName()) {
21.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java Thu May 02 15:01:16 2013 -0300 21.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java Fri May 03 15:33:54 2013 +0200 21.3 @@ -88,7 +88,7 @@ 21.4 21.5 int weight = Type.typeFor(type.returnType()).getWeight(); 21.6 for (final Class<?> paramType : type.parameterArray()) { 21.7 - final int pweight = Type.typeFor(paramType).getWeight(); 21.8 + final int pweight = Type.typeFor(paramType).getWeight() * 2; //params are more important than call types as return values are always specialized 21.9 weight += pweight; 21.10 } 21.11 return weight;
22.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Thu May 02 15:01:16 2013 -0300 22.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Fri May 03 15:33:54 2013 +0200 22.3 @@ -69,5 +69,4 @@ 22.4 return best(type).moreGenericThan(type); 22.5 } 22.6 22.7 - 22.8 }
23.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Thu May 02 15:01:16 2013 -0300 23.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Fri May 03 15:33:54 2013 +0200 23.3 @@ -411,7 +411,7 @@ 23.4 return ScriptRuntime.apply(func, evalThis); 23.5 } 23.6 23.7 - private Source loadInternal(final String srcStr, final String prefix, final String resourcePath) { 23.8 + private static Source loadInternal(final String srcStr, final String prefix, final String resourcePath) { 23.9 if (srcStr.startsWith(prefix)) { 23.10 final String resource = resourcePath + srcStr.substring(prefix.length()); 23.11 // NOTE: even sandbox scripts should be able to load scripts in nashorn: scheme 23.12 @@ -759,10 +759,10 @@ 23.13 final CodeSource cs = url == null ? null : new CodeSource(url, (CodeSigner[])null); 23.14 final CodeInstaller<ScriptEnvironment> installer = new ContextCodeInstaller(this, loader, cs); 23.15 23.16 - final Compiler compiler = new Compiler(installer, functionNode, strict); 23.17 + final Compiler compiler = new Compiler(installer, strict); 23.18 23.19 - compiler.compile(); 23.20 - script = compiler.install(); 23.21 + final FunctionNode newFunctionNode = compiler.compile(functionNode); 23.22 + script = compiler.install(newFunctionNode); 23.23 23.24 if (global != null) { 23.25 global.cacheClass(source, script);
24.1 --- a/src/jdk/nashorn/internal/runtime/JSONFunctions.java Thu May 02 15:01:16 2013 -0300 24.2 +++ b/src/jdk/nashorn/internal/runtime/JSONFunctions.java Fri May 03 15:33:54 2013 +0200 24.3 @@ -25,8 +25,6 @@ 24.4 24.5 package jdk.nashorn.internal.runtime; 24.6 24.7 -import static jdk.nashorn.internal.runtime.ScriptObject.isArray; 24.8 - 24.9 import java.lang.invoke.MethodHandle; 24.10 import java.util.Iterator; 24.11 import java.util.List;
25.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu May 02 15:01:16 2013 -0300 25.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Fri May 03 15:33:54 2013 +0200 25.3 @@ -30,9 +30,12 @@ 25.4 import java.lang.invoke.MethodHandle; 25.5 import java.lang.invoke.MethodHandles; 25.6 import java.lang.invoke.MethodType; 25.7 +import java.util.LinkedList; 25.8 + 25.9 import jdk.nashorn.internal.codegen.Compiler; 25.10 import jdk.nashorn.internal.codegen.CompilerConstants; 25.11 import jdk.nashorn.internal.codegen.FunctionSignature; 25.12 +import jdk.nashorn.internal.codegen.types.Type; 25.13 import jdk.nashorn.internal.ir.FunctionNode; 25.14 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 25.15 import jdk.nashorn.internal.parser.Token; 25.16 @@ -148,10 +151,10 @@ 25.17 25.18 if (functionNode.isLazy()) { 25.19 Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); 25.20 - final Compiler compiler = new Compiler(installer, functionNode); 25.21 - functionNode = compiler.compile(); 25.22 + final Compiler compiler = new Compiler(installer); 25.23 + functionNode = compiler.compile(functionNode); 25.24 assert !functionNode.isLazy(); 25.25 - compiler.install(); 25.26 + compiler.install(functionNode); 25.27 25.28 // we don't need to update any flags - varArgs and needsCallee are instrincic 25.29 // in the function world we need to get a destination node from the compile instead 25.30 @@ -164,23 +167,114 @@ 25.31 assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); 25.32 25.33 // code exists - look it up and add it into the automatically sorted invoker list 25.34 - code.add( 25.35 - new CompiledFunction( 25.36 - MH.findStatic( 25.37 + addCode(functionNode, null, null); 25.38 + } 25.39 + 25.40 + private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) { 25.41 + final MethodHandle target = 25.42 + MH.findStatic( 25.43 LOOKUP, 25.44 - functionNode.getCompileUnit().getCode(), 25.45 - functionNode.getName(), 25.46 - new FunctionSignature(functionNode). 25.47 - getMethodType()))); 25.48 + fn.getCompileUnit().getCode(), 25.49 + fn.getName(), 25.50 + new FunctionSignature(fn). 25.51 + getMethodType()); 25.52 + MethodHandle mh = target; 25.53 + if (guard != null) { 25.54 + try { 25.55 + mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); 25.56 + } catch (Throwable e) { 25.57 + e.printStackTrace(); 25.58 + } 25.59 + } 25.60 + 25.61 + final CompiledFunction cf = new CompiledFunction(mh); 25.62 + code.add(cf); 25.63 + 25.64 + return cf.getInvoker(); 25.65 } 25.66 25.67 + private static Type runtimeType(final Object arg) { 25.68 + if (arg == null) { 25.69 + return Type.OBJECT; 25.70 + } 25.71 + 25.72 + final Class<?> clazz = arg.getClass(); 25.73 + assert !clazz.isPrimitive() : "always boxed"; 25.74 + if (clazz == Double.class) { 25.75 + return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER; 25.76 + } else if (clazz == Integer.class) { 25.77 + return Type.INT; 25.78 + } else if (clazz == Long.class) { 25.79 + return Type.LONG; 25.80 + } else if (clazz == String.class) { 25.81 + return Type.STRING; 25.82 + } 25.83 + return Type.OBJECT; 25.84 + } 25.85 + 25.86 + @SuppressWarnings("unused") 25.87 + private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) { 25.88 + //System.err.println("Param type guard " + Arrays.asList(args)); 25.89 + return false; 25.90 + } 25.91 + 25.92 + private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class); 25.93 + 25.94 @Override 25.95 MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { 25.96 final MethodHandle mh = super.getBestInvoker(callSiteType, args); 25.97 - if (code.isLessSpecificThan(callSiteType)) { 25.98 - // opportunity for code specialization - we can regenerate a better version of this method 25.99 + 25.100 + if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) { 25.101 + return mh; 25.102 } 25.103 - return mh; 25.104 + 25.105 + final FunctionNode snapshot = functionNode.getSnapshot(); 25.106 + int i; 25.107 + 25.108 + //classes known at runtime 25.109 + final LinkedList<Type> runtimeArgs = new LinkedList<>(); 25.110 + for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) { 25.111 + runtimeArgs.addLast(runtimeType(args[i])); 25.112 + } 25.113 + 25.114 + //classes known at compile time 25.115 + final LinkedList<Type> compileTimeArgs = new LinkedList<>(); 25.116 + for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) { 25.117 + compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i))); 25.118 + } 25.119 + 25.120 + //the classes known at compile time are a safe to generate as primitives without parameter guards 25.121 + //the classes known at runtime are safe to generate as primitives IFF there are parameter guards 25.122 + MethodHandle guard = null; 25.123 + for (i = 0; i < compileTimeArgs.size(); i++) { 25.124 + final Type runtimeType = runtimeArgs.get(i); 25.125 + final Type compileType = compileTimeArgs.get(i); 25.126 + 25.127 + if (compileType.isObject() && !runtimeType.isObject()) { 25.128 + if (guard == null) { 25.129 + guard = PARAM_TYPE_GUARD; 25.130 + guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()])); 25.131 + } 25.132 + } 25.133 + } 25.134 + 25.135 + //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs); 25.136 + 25.137 + assert snapshot != null; 25.138 + assert snapshot != functionNode; 25.139 + 25.140 + final Compiler compiler = new Compiler(installer); 25.141 + final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()])))); 25.142 + 25.143 + compiler.install(compiledSnapshot); 25.144 + 25.145 + final MethodHandle nmh = addCode(compiledSnapshot, guard, mh); 25.146 + 25.147 + return nmh; 25.148 + } 25.149 + 25.150 + private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { 25.151 + return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types)); 25.152 } 25.153 25.154 }
26.1 --- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu May 02 15:01:16 2013 -0300 26.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java Fri May 03 15:33:54 2013 +0200 26.3 @@ -26,9 +26,13 @@ 26.4 package jdk.nashorn.internal.runtime; 26.5 26.6 import java.io.PrintWriter; 26.7 +import java.util.HashSet; 26.8 import java.util.List; 26.9 import java.util.Locale; 26.10 +import java.util.Set; 26.11 +import java.util.StringTokenizer; 26.12 import java.util.TimeZone; 26.13 + 26.14 import jdk.nashorn.internal.codegen.Namespace; 26.15 import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor; 26.16 import jdk.nashorn.internal.runtime.options.KeyValueOption; 26.17 @@ -151,6 +155,9 @@ 26.18 /** is this environment in scripting mode? */ 26.19 public final boolean _scripting; 26.20 26.21 + /** is the JIT allowed to specializ calls based on callsite types? */ 26.22 + public final Set<String> _specialize_calls; 26.23 + 26.24 /** is this environment in strict mode? */ 26.25 public final boolean _strict; 26.26 26.27 @@ -213,6 +220,17 @@ 26.28 _version = options.getBoolean("version"); 26.29 _verify_code = options.getBoolean("verify.code"); 26.30 26.31 + final String specialize = options.getString("specialize.calls"); 26.32 + if (specialize == null) { 26.33 + _specialize_calls = null; 26.34 + } else { 26.35 + _specialize_calls = new HashSet<>(); 26.36 + final StringTokenizer st = new StringTokenizer(specialize, ","); 26.37 + while (st.hasMoreElements()) { 26.38 + _specialize_calls.add(st.nextToken()); 26.39 + } 26.40 + } 26.41 + 26.42 int callSiteFlags = 0; 26.43 if (options.getBoolean("profile.callsites")) { 26.44 callSiteFlags |= NashornCallSiteDescriptor.CALLSITE_PROFILE; 26.45 @@ -247,6 +265,18 @@ 26.46 } 26.47 26.48 /** 26.49 + * Can we specialize a particular method name? 26.50 + * @param functionName method name 26.51 + * @return true if we are allowed to generate versions of this method 26.52 + */ 26.53 + public boolean canSpecialize(final String functionName) { 26.54 + if (_specialize_calls == null) { 26.55 + return false; 26.56 + } 26.57 + return _specialize_calls.isEmpty() || _specialize_calls.contains(functionName); 26.58 + } 26.59 + 26.60 + /** 26.61 * Get the output stream for this environment 26.62 * @return output print writer 26.63 */
27.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Thu May 02 15:01:16 2013 -0300 27.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Fri May 03 15:33:54 2013 +0200 27.3 @@ -662,9 +662,9 @@ 27.4 } 27.5 27.6 if (deep) { 27.7 - final ScriptObject proto = getProto(); 27.8 - if(proto != null) { 27.9 - return proto.findProperty(key, deep, stopOnNonScope, start); 27.10 + final ScriptObject myProto = getProto(); 27.11 + if (myProto != null) { 27.12 + return myProto.findProperty(key, deep, stopOnNonScope, start); 27.13 } 27.14 } 27.15
28.1 --- a/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Thu May 02 15:01:16 2013 -0300 28.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/DefaultRegExp.java Fri May 03 15:33:54 2013 +0200 28.3 @@ -107,16 +107,16 @@ 28.4 28.5 class DefaultMatcher implements RegExpMatcher { 28.6 final String input; 28.7 - final Matcher matcher; 28.8 + final Matcher defaultMatcher; 28.9 28.10 DefaultMatcher(final String input) { 28.11 this.input = input; 28.12 - this.matcher = pattern.matcher(input); 28.13 + this.defaultMatcher = pattern.matcher(input); 28.14 } 28.15 28.16 @Override 28.17 public boolean search(final int start) { 28.18 - return matcher.find(start); 28.19 + return defaultMatcher.find(start); 28.20 } 28.21 28.22 @Override 28.23 @@ -126,37 +126,37 @@ 28.24 28.25 @Override 28.26 public int start() { 28.27 - return matcher.start(); 28.28 + return defaultMatcher.start(); 28.29 } 28.30 28.31 @Override 28.32 public int start(final int group) { 28.33 - return matcher.start(group); 28.34 + return defaultMatcher.start(group); 28.35 } 28.36 28.37 @Override 28.38 public int end() { 28.39 - return matcher.end(); 28.40 + return defaultMatcher.end(); 28.41 } 28.42 28.43 @Override 28.44 public int end(final int group) { 28.45 - return matcher.end(group); 28.46 + return defaultMatcher.end(group); 28.47 } 28.48 28.49 @Override 28.50 public String group() { 28.51 - return matcher.group(); 28.52 + return defaultMatcher.group(); 28.53 } 28.54 28.55 @Override 28.56 public String group(final int group) { 28.57 - return matcher.group(group); 28.58 + return defaultMatcher.group(group); 28.59 } 28.60 28.61 @Override 28.62 public int groupCount() { 28.63 - return matcher.groupCount(); 28.64 + return defaultMatcher.groupCount(); 28.65 } 28.66 } 28.67
29.1 --- a/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Thu May 02 15:01:16 2013 -0300 29.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/JoniRegExp.java Fri May 03 15:33:54 2013 +0200 29.3 @@ -121,16 +121,16 @@ 29.4 29.5 class JoniMatcher implements RegExpMatcher { 29.6 final String input; 29.7 - final Matcher matcher; 29.8 + final Matcher joniMatcher; 29.9 29.10 JoniMatcher(final String input) { 29.11 this.input = input; 29.12 - this.matcher = regex.matcher(input.toCharArray()); 29.13 + this.joniMatcher = regex.matcher(input.toCharArray()); 29.14 } 29.15 29.16 @Override 29.17 public boolean search(final int start) { 29.18 - return matcher.search(start, input.length(), Option.NONE) > -1; 29.19 + return joniMatcher.search(start, input.length(), Option.NONE) > -1; 29.20 } 29.21 29.22 @Override 29.23 @@ -140,27 +140,27 @@ 29.24 29.25 @Override 29.26 public int start() { 29.27 - return matcher.getBegin(); 29.28 + return joniMatcher.getBegin(); 29.29 } 29.30 29.31 @Override 29.32 public int start(final int group) { 29.33 - return group == 0 ? start() : matcher.getRegion().beg[group]; 29.34 + return group == 0 ? start() : joniMatcher.getRegion().beg[group]; 29.35 } 29.36 29.37 @Override 29.38 public int end() { 29.39 - return matcher.getEnd(); 29.40 + return joniMatcher.getEnd(); 29.41 } 29.42 29.43 @Override 29.44 public int end(final int group) { 29.45 - return group == 0 ? end() : matcher.getRegion().end[group]; 29.46 + return group == 0 ? end() : joniMatcher.getRegion().end[group]; 29.47 } 29.48 29.49 @Override 29.50 public String group() { 29.51 - return input.substring(matcher.getBegin(), matcher.getEnd()); 29.52 + return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd()); 29.53 } 29.54 29.55 @Override 29.56 @@ -168,13 +168,13 @@ 29.57 if (group == 0) { 29.58 return group(); 29.59 } 29.60 - final Region region = matcher.getRegion(); 29.61 + final Region region = joniMatcher.getRegion(); 29.62 return input.substring(region.beg[group], region.end[group]); 29.63 } 29.64 29.65 @Override 29.66 public int groupCount() { 29.67 - final Region region = matcher.getRegion(); 29.68 + final Region region = joniMatcher.getRegion(); 29.69 return region == null ? 0 : region.numRegs - 1; 29.70 } 29.71 }
30.1 --- a/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Thu May 02 15:01:16 2013 -0300 30.2 +++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpScanner.java Fri May 03 15:33:54 2013 +0200 30.3 @@ -934,7 +934,7 @@ 30.4 return true; 30.5 } 30.6 30.7 - private void unicode(final int value, final StringBuilder buffer) { 30.8 + private static void unicode(final int value, final StringBuilder buffer) { 30.9 final String hex = Integer.toHexString(value); 30.10 buffer.append('u'); 30.11 for (int i = 0; i < 4 - hex.length(); i++) { 30.12 @@ -944,7 +944,7 @@ 30.13 } 30.14 30.15 // Convert what would have been a backreference into a unicode escape, or a number literal, or both. 30.16 - private void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) { 30.17 + private static void octalOrLiteral(final String numberLiteral, final StringBuilder buffer) { 30.18 final int length = numberLiteral.length(); 30.19 int octalValue = 0; 30.20 int pos = 0;
31.1 --- a/src/jdk/nashorn/internal/runtime/resources/Options.properties Thu May 02 15:01:16 2013 -0300 31.2 +++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties Fri May 03 15:33:54 2013 +0200 31.3 @@ -288,12 +288,12 @@ 31.4 dependency="--anon-functions=true" \ 31.5 } 31.6 31.7 -nashorn.option.timezone = { \ 31.8 - name="-timezone", \ 31.9 - short_name="-t", \ 31.10 - params="<timezone>", \ 31.11 - desc="Set timezone for script execution.", \ 31.12 - type=TimeZone \ 31.13 +nashorn.option.specialize.calls = { \ 31.14 + name="--specialize-calls", \ 31.15 + is_undocumented=true, \ 31.16 + type=String, \ 31.17 + params="[=function_1,...,function_n]", \ 31.18 + desc="Specialize all or a set of method according to callsite parameter types" \ 31.19 } 31.20 31.21 nashorn.option.stdout = { \ 31.22 @@ -312,6 +312,14 @@ 31.23 desc="Redirect stderr to a filename or to another tty, e.g. stdout" \ 31.24 } 31.25 31.26 +nashorn.option.timezone = { \ 31.27 + name="-timezone", \ 31.28 + short_name="-t", \ 31.29 + params="<timezone>", \ 31.30 + desc="Set timezone for script execution.", \ 31.31 + type=TimeZone \ 31.32 +} 31.33 + 31.34 nashorn.option.trace.callsites = { \ 31.35 name="--trace-callsites", \ 31.36 short_name="-tcs", \
32.1 --- a/src/jdk/nashorn/tools/Shell.java Thu May 02 15:01:16 2013 -0300 32.2 +++ b/src/jdk/nashorn/tools/Shell.java Fri May 03 15:33:54 2013 +0200 32.3 @@ -270,7 +270,7 @@ 32.4 } 32.5 32.6 //null - pass no code installer - this is compile only 32.7 - new Compiler(env, functionNode).compile(); 32.8 + new Compiler(env).compile(functionNode); 32.9 } 32.10 } finally { 32.11 env.getOut().flush();
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/test/script/basic/paramspec.js Fri May 03 15:33:54 2013 +0200 33.3 @@ -0,0 +1,38 @@ 33.4 +/* 33.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 33.7 + * 33.8 + * This code is free software; you can redistribute it and/or modify it 33.9 + * under the terms of the GNU General Public License version 2 only, as 33.10 + * published by the Free Software Foundation. 33.11 + * 33.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 33.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 33.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 33.15 + * version 2 for more details (a copy is included in the LICENSE file that 33.16 + * accompanied this code). 33.17 + * 33.18 + * You should have received a copy of the GNU General Public License version 33.19 + * 2 along with this work; if not, write to the Free Software Foundation, 33.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 33.21 + * 33.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 33.23 + * or visit www.oracle.com if you need additional information or have any 33.24 + * questions. 33.25 + */ 33.26 + 33.27 +/** 33.28 + * paramspec - test that Attr doesn't break parameters when specializing 33.29 + * 33.30 + * @run 33.31 + * @test 33.32 + */ 33.33 + 33.34 +function f(a) { 33.35 + var b = ~a; 33.36 + return b == ~17; 33.37 +} 33.38 + 33.39 +print(f("17")); 33.40 +print(f(17)); 33.41 +
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/test/script/basic/paramspec.js.EXPECTED Fri May 03 15:33:54 2013 +0200 34.3 @@ -0,0 +1,2 @@ 34.4 +true 34.5 +true
35.1 --- a/test/script/basic/runsunspider.js Thu May 02 15:01:16 2013 -0300 35.2 +++ b/test/script/basic/runsunspider.js Fri May 03 15:33:54 2013 +0200 35.3 @@ -86,7 +86,7 @@ 35.4 changed = true; 35.5 } 35.6 } catch (e) { 35.7 - print("error: " + e); 35.8 + print("error: " + e.printStackTrace()); 35.9 if (e.toString().indexOf(tests) == 1) { 35.10 throw e; 35.11 }
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/test/script/currently-failing/logcoverage.js Fri May 03 15:33:54 2013 +0200 36.3 @@ -0,0 +1,109 @@ 36.4 +/* 36.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 36.7 + * 36.8 + * This code is free software; you can redistribute it and/or modify it 36.9 + * under the terms of the GNU General Public License version 2 only, as 36.10 + * published by the Free Software Foundation. 36.11 + * 36.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 36.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 36.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 36.15 + * version 2 for more details (a copy is included in the LICENSE file that 36.16 + * accompanied this code). 36.17 + * 36.18 + * You should have received a copy of the GNU General Public License version 36.19 + * 2 along with this work; if not, write to the Free Software Foundation, 36.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 36.21 + * 36.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 36.23 + * or visit www.oracle.com if you need additional information or have any 36.24 + * questions. 36.25 + */ 36.26 + 36.27 +/** 36.28 + * mh_coverage.js 36.29 + * Screen scrape various logs to ensure that we cover enough functionality, 36.30 + * e.g. method handle instrumentation 36.31 + * 36.32 + * @test 36.33 + * @run 36.34 + */ 36.35 + 36.36 +/* 36.37 + * creates new script engine initialized with given options and 36.38 + * runs given code on it. Returns standard output captured. 36.39 + */ 36.40 + 36.41 +function runScriptEngine(opts, name) { 36.42 + var imports = new JavaImporter( 36.43 + Packages.jdk.nashorn.api.scripting, 36.44 + java.io, java.lang, java.util); 36.45 + 36.46 + with(imports) { 36.47 + var fac = new NashornScriptEngineFactory(); 36.48 + // get current System.err 36.49 + var oldErr = System.err; 36.50 + var oldOut = System.out; 36.51 + var baosErr = new ByteArrayOutputStream(); 36.52 + var newErr = new PrintStream(baosErr); 36.53 + var baosOut = new ByteArrayOutputStream(); 36.54 + var newOut = new PrintStream(baosOut); 36.55 + try { 36.56 + // set new standard err 36.57 + System.setErr(newErr); 36.58 + System.setOut(newOut); 36.59 + var strType = Java.type("java.lang.String"); 36.60 + var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); 36.61 + var reader = new java.io.FileReader(name); 36.62 + engine.eval(reader); 36.63 + newErr.flush(); 36.64 + newOut.flush(); 36.65 + return new java.lang.String(baosErr.toByteArray()); 36.66 + } finally { 36.67 + // restore System.err to old value 36.68 + System.setErr(oldErr); 36.69 + System.setOut(oldOut); 36.70 + } 36.71 + } 36.72 +} 36.73 + 36.74 +var str; 36.75 + 36.76 +var methodsCalled = [ 36.77 + 'asCollector', 36.78 + 'asType', 36.79 + 'bindTo', 36.80 + 'dropArguments', 36.81 + 'explicitCastArguments', 36.82 + 'filterArguments', 36.83 + 'filterReturnValue', 36.84 + 'findStatic', 36.85 + 'findVirtual', 36.86 + 'foldArguments', 36.87 + 'getter', 36.88 + 'guardWithTest', 36.89 + 'insertArguments', 36.90 + 'methodType', 36.91 + 'setter' 36.92 +]; 36.93 + 36.94 +function check(str, strs) { 36.95 + for each (s in strs) { 36.96 + if (str.indexOf(s) !== -1) { 36.97 + continue; 36.98 + } 36.99 + print(s + " not found"); 36.100 + return; 36.101 + } 36.102 + print("check ok!"); 36.103 +} 36.104 + 36.105 +str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js"); 36.106 +str += runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/varargs.js"); 36.107 + 36.108 +check(str, methodsCalled); 36.109 +check(str, ['return', 'get', 'set', '[fields]']); 36.110 +check(str, ['codegen']); 36.111 + 36.112 +print("hello, world!");
37.1 --- a/test/script/trusted/logcoverage.js Thu May 02 15:01:16 2013 -0300 37.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 37.3 @@ -1,108 +0,0 @@ 37.4 -/* 37.5 - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 37.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 37.7 - * 37.8 - * This code is free software; you can redistribute it and/or modify it 37.9 - * under the terms of the GNU General Public License version 2 only, as 37.10 - * published by the Free Software Foundation. 37.11 - * 37.12 - * This code is distributed in the hope that it will be useful, but WITHOUT 37.13 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 37.14 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 37.15 - * version 2 for more details (a copy is included in the LICENSE file that 37.16 - * accompanied this code). 37.17 - * 37.18 - * You should have received a copy of the GNU General Public License version 37.19 - * 2 along with this work; if not, write to the Free Software Foundation, 37.20 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 37.21 - * 37.22 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 37.23 - * or visit www.oracle.com if you need additional information or have any 37.24 - * questions. 37.25 - */ 37.26 - 37.27 -/** 37.28 - * mh_coverage.js 37.29 - * Screen scrape various logs to ensure that we cover enough functionality, 37.30 - * e.g. method handle instrumentation 37.31 - * 37.32 - * @test 37.33 - * @run 37.34 - */ 37.35 - 37.36 -/* 37.37 - * creates new script engine initialized with given options and 37.38 - * runs given code on it. Returns standard output captured. 37.39 - */ 37.40 - 37.41 -function runScriptEngine(opts, name) { 37.42 - var imports = new JavaImporter( 37.43 - Packages.jdk.nashorn.api.scripting, 37.44 - java.io, java.lang, java.util); 37.45 - 37.46 - with(imports) { 37.47 - var fac = new NashornScriptEngineFactory(); 37.48 - // get current System.err 37.49 - var oldErr = System.err; 37.50 - var oldOut = System.out; 37.51 - var baosErr = new ByteArrayOutputStream(); 37.52 - var newErr = new PrintStream(baosErr); 37.53 - var baosOut = new ByteArrayOutputStream(); 37.54 - var newOut = new PrintStream(baosOut); 37.55 - try { 37.56 - // set new standard err 37.57 - System.setErr(newErr); 37.58 - System.setOut(newOut); 37.59 - var strType = Java.type("java.lang.String"); 37.60 - var engine = fac.getScriptEngine(Java.toJavaArray(opts, strType)); 37.61 - var reader = new java.io.FileReader(name); 37.62 - engine.eval(reader); 37.63 - newErr.flush(); 37.64 - newOut.flush(); 37.65 - return new java.lang.String(baosErr.toByteArray()); 37.66 - } finally { 37.67 - // restore System.err to old value 37.68 - System.setErr(oldErr); 37.69 - System.setOut(oldOut); 37.70 - } 37.71 - } 37.72 -} 37.73 - 37.74 -var str; 37.75 - 37.76 -var methodsCalled = [ 37.77 - 'asCollector', 37.78 - 'asType', 37.79 - 'bindTo', 37.80 - 'dropArguments', 37.81 - 'explicitCastArguments', 37.82 - 'filterArguments', 37.83 - 'filterReturnValue', 37.84 - 'findStatic', 37.85 - 'findVirtual', 37.86 - 'foldArguments', 37.87 - 'getter', 37.88 - 'guardWithTest', 37.89 - 'insertArguments', 37.90 - 'methodType', 37.91 - 'setter' 37.92 -]; 37.93 - 37.94 -function check(str, strs) { 37.95 - for each (s in strs) { 37.96 - if (s.indexOf(str) !== -1) { 37.97 - continue; 37.98 - } 37.99 - print(method + "not found"); 37.100 - return; 37.101 - } 37.102 - print("check ok!"); 37.103 -} 37.104 - 37.105 -str = runScriptEngine([ "--log=codegen,compiler=finest,methodhandles=finest,fields=finest" ], __DIR__ + "../basic/NASHORN-19.js"); 37.106 - 37.107 -check(str, methodsCalled); 37.108 -check(str, ['return', 'get', 'set', '[fields]']); 37.109 -check(str, ['codegen']); 37.110 - 37.111 -print("hello, world!");