Wed, 17 Dec 2014 12:51:46 -0800
Merge
.hgtags | file | annotate | diff | comparison | revisions |
1.1 --- a/.hgtags Tue Dec 16 14:46:13 2014 -0800 1.2 +++ b/.hgtags Wed Dec 17 12:51:46 2014 -0800 1.3 @@ -354,3 +354,4 @@ 1.4 e079f3f6d536510b1ab3589b1038d893d78302ac jdk8u40-b16 1.5 88e22262fdb26e3154a1034c2413415e97b9a86a jdk8u40-b17 1.6 653739706172ae94e999731a3a9f10f8ce11ffca jdk8u40-b18 1.7 +6ec61d2494283fbaca6df227f1a5b45487dc1ca7 jdk8u40-b19
2.1 --- a/THIRD_PARTY_README Tue Dec 16 14:46:13 2014 -0800 2.2 +++ b/THIRD_PARTY_README Wed Dec 17 12:51:46 2014 -0800 2.3 @@ -3385,7 +3385,7 @@ 2.4 included with JRE 8, JDK 8, and OpenJDK 8. 2.5 2.6 Apache Commons Math 3.2 2.7 - Apache Derby 10.10.1.3 2.8 + Apache Derby 10.11.1.2 2.9 Apache Jakarta BCEL 5.1 2.10 Apache Jakarta Regexp 1.4 2.11 Apache Santuario XML Security for Java 1.5.4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/samples/browser_dom.js Wed Dec 17 12:51:46 2014 -0800 3.3 @@ -0,0 +1,91 @@ 3.4 +#// Usage: jjs -fx browser.js 3.5 + 3.6 +/* 3.7 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3.8 + * 3.9 + * Redistribution and use in source and binary forms, with or without 3.10 + * modification, are permitted provided that the following conditions 3.11 + * are met: 3.12 + * 3.13 + * - Redistributions of source code must retain the above copyright 3.14 + * notice, this list of conditions and the following disclaimer. 3.15 + * 3.16 + * - Redistributions in binary form must reproduce the above copyright 3.17 + * notice, this list of conditions and the following disclaimer in the 3.18 + * documentation and/or other materials provided with the distribution. 3.19 + * 3.20 + * - Neither the name of Oracle nor the names of its 3.21 + * contributors may be used to endorse or promote products derived 3.22 + * from this software without specific prior written permission. 3.23 + * 3.24 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 3.25 + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 3.26 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 3.27 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 3.28 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 3.29 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 3.30 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3.31 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3.32 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3.33 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3.34 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3.35 + */ 3.36 + 3.37 +if (!$OPTIONS._fx) { 3.38 + print("Usage: jjs -fx browser.js"); 3.39 + exit(1); 3.40 +} 3.41 + 3.42 +// JavaFX classes used 3.43 +var ChangeListener = Java.type("javafx.beans.value.ChangeListener"); 3.44 +var Scene = Java.type("javafx.scene.Scene"); 3.45 +var WebView = Java.type("javafx.scene.web.WebView"); 3.46 +var EventListener = Java.type("org.w3c.dom.events.EventListener"); 3.47 + 3.48 +// JavaFX start method 3.49 +function start(stage) { 3.50 + start.title = "Web View"; 3.51 + var wv = new WebView(); 3.52 + wv.engine.loadContent(<<EOF 3.53 +<html> 3.54 +<head> 3.55 +<title> 3.56 +This is the title 3.57 +</title> 3.58 +<script> 3.59 +// click count for OK button 3.60 +var okCount = 0; 3.61 +</script> 3.62 +</head> 3.63 +<body> 3.64 +Button from the input html<br> 3.65 +<button type="button" onclick="okCount++">OK</button><br> 3.66 +</body> 3.67 +</html> 3.68 +EOF, "text/html"); 3.69 + 3.70 + // attach onload handler 3.71 + wv.engine.loadWorker.stateProperty().addListener( 3.72 + new ChangeListener() { 3.73 + changed: function() { 3.74 + // DOM document element 3.75 + var document = wv.engine.document; 3.76 + // DOM manipulation 3.77 + var btn = document.createElement("button"); 3.78 + var n = 0; 3.79 + // attach a button handler - nashorn function! 3.80 + btn.onclick = new EventListener(function() { 3.81 + n++; print("You clicked " + n + " time(s)"); 3.82 + print("you clicked OK " + wv.engine.executeScript("okCount")); 3.83 + }); 3.84 + // attach text to button 3.85 + var t = document.createTextNode("Click Me!"); 3.86 + btn.appendChild(t); 3.87 + // attach button to the document 3.88 + document.body.appendChild(btn); 3.89 + } 3.90 + } 3.91 + ); 3.92 + stage.scene = new Scene(wv, 750, 500); 3.93 + stage.show(); 3.94 +}
4.1 --- a/src/jdk/nashorn/internal/codegen/AssignSymbols.java Tue Dec 16 14:46:13 2014 -0800 4.2 +++ b/src/jdk/nashorn/internal/codegen/AssignSymbols.java Wed Dec 17 12:51:46 2014 -0800 4.3 @@ -910,7 +910,7 @@ 4.4 @Override 4.5 public Node leaveSwitchNode(final SwitchNode switchNode) { 4.6 // We only need a symbol for the tag if it's not an integer switch node 4.7 - if(!switchNode.isInteger()) { 4.8 + if(!switchNode.isUniqueInteger()) { 4.9 switchNode.setTag(newObjectInternal(SWITCH_TAG_PREFIX)); 4.10 } 4.11 return switchNode;
5.1 --- a/src/jdk/nashorn/internal/codegen/AstSerializer.java Tue Dec 16 14:46:13 2014 -0800 5.2 +++ b/src/jdk/nashorn/internal/codegen/AstSerializer.java Wed Dec 17 12:51:46 2014 -0800 5.3 @@ -48,11 +48,13 @@ 5.4 private static final int COMPRESSION_LEVEL = Options.getIntProperty("nashorn.serialize.compression", 4); 5.5 static byte[] serialize(final FunctionNode fn) { 5.6 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 5.7 - try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, 5.8 - new Deflater(COMPRESSION_LEVEL)))) { 5.9 + final Deflater deflater = new Deflater(COMPRESSION_LEVEL); 5.10 + try (final ObjectOutputStream oout = new ObjectOutputStream(new DeflaterOutputStream(out, deflater))) { 5.11 oout.writeObject(removeInnerFunctionBodies(fn)); 5.12 } catch (final IOException e) { 5.13 throw new AssertionError("Unexpected exception serializing function", e); 5.14 + } finally { 5.15 + deflater.end(); 5.16 } 5.17 return out.toByteArray(); 5.18 }
6.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Dec 16 14:46:13 2014 -0800 6.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Dec 17 12:51:46 2014 -0800 6.3 @@ -465,10 +465,10 @@ 6.4 // If this is either __FILE__, __DIR__, or __LINE__ then load the property initially as Object as we'd convert 6.5 // it anyway for replaceLocationPropertyPlaceholder. 6.6 if(identNode.isCompileTimePropertyName()) { 6.7 - method.dynamicGet(Type.OBJECT, identNode.getSymbol().getName(), flags, identNode.isFunction()); 6.8 + method.dynamicGet(Type.OBJECT, identNode.getSymbol().getName(), flags, identNode.isFunction(), false); 6.9 replaceCompileTimeProperty(); 6.10 } else { 6.11 - dynamicGet(identNode.getSymbol().getName(), flags, identNode.isFunction()); 6.12 + dynamicGet(identNode.getSymbol().getName(), flags, identNode.isFunction(), false); 6.13 } 6.14 } 6.15 } 6.16 @@ -486,7 +486,7 @@ 6.17 6.18 private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) { 6.19 loadFastScopeProto(symbol, true); 6.20 - method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE); 6.21 + method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE, false); 6.22 return method; 6.23 } 6.24 6.25 @@ -571,9 +571,11 @@ 6.26 6.27 // Operands' load type should not be narrower than the narrowest of the individual operand types, nor narrower 6.28 // than the lower explicit bound, but it should also not be wider than 6.29 - final Type narrowestOperandType = Type.narrowest(Type.widest(lhs.getType(), rhs.getType()), explicitOperandBounds.widest); 6.30 + final Type lhsType = undefinedToNumber(lhs.getType()); 6.31 + final Type rhsType = undefinedToNumber(rhs.getType()); 6.32 + final Type narrowestOperandType = Type.narrowest(Type.widest(lhsType, rhsType), explicitOperandBounds.widest); 6.33 final TypeBounds operandBounds = explicitOperandBounds.notNarrowerThan(narrowestOperandType); 6.34 - if (noToPrimitiveConversion(lhs.getType(), explicitOperandBounds.widest) || rhs.isLocal()) { 6.35 + if (noToPrimitiveConversion(lhsType, explicitOperandBounds.widest) || rhs.isLocal()) { 6.36 // Can reorder. We might still need to separate conversion, but at least we can do it with reordering 6.37 if (forceConversionSeparation) { 6.38 // Can reorder, but can't move conversion into the operand as the operation depends on operands 6.39 @@ -594,10 +596,10 @@ 6.40 // Can't reorder. Load and convert separately. 6.41 final TypeBounds safeConvertBounds = TypeBounds.UNBOUNDED.notNarrowerThan(narrowestOperandType); 6.42 loadExpression(lhs, safeConvertBounds, baseAlreadyOnStack); 6.43 - final Type lhsType = method.peekType(); 6.44 + final Type lhsLoadedType = method.peekType(); 6.45 loadExpression(rhs, safeConvertBounds, false); 6.46 final Type convertedLhsType = operandBounds.within(method.peekType()); 6.47 - if (convertedLhsType != lhsType) { 6.48 + if (convertedLhsType != lhsLoadedType) { 6.49 // Do it conditionally, so that if conversion is a no-op we don't introduce a SWAP, SWAP. 6.50 method.swap().convert(convertedLhsType).swap(); 6.51 } 6.52 @@ -609,6 +611,10 @@ 6.53 return method; 6.54 } 6.55 6.56 + private static final Type undefinedToNumber(final Type type) { 6.57 + return type == Type.UNDEFINED ? Type.NUMBER : type; 6.58 + } 6.59 + 6.60 private static final class TypeBounds { 6.61 final Type narrowest; 6.62 final Type widest; 6.63 @@ -739,7 +745,7 @@ 6.64 @Override 6.65 void consumeStack() { 6.66 final int flags = getCallSiteFlags(); 6.67 - dynamicGet(accessNode.getProperty(), flags, accessNode.isFunction()); 6.68 + dynamicGet(accessNode.getProperty(), flags, accessNode.isFunction(), accessNode.isIndex()); 6.69 } 6.70 }.emit(baseAlreadyOnStack ? 1 : 0); 6.71 return false; 6.72 @@ -1443,7 +1449,7 @@ 6.73 // NOTE: not using a nested OptimisticOperation on this dynamicGet, as we expect to get back 6.74 // a callable object. Nobody in their right mind would optimistically type this call site. 6.75 assert !node.isOptimistic(); 6.76 - method.dynamicGet(node.getType(), node.getProperty(), flags, true); 6.77 + method.dynamicGet(node.getType(), node.getProperty(), flags, true, node.isIndex()); 6.78 method.swap(); 6.79 argCount = loadArgs(args); 6.80 } 6.81 @@ -2015,6 +2021,19 @@ 6.82 final Expression test = ifNode.getTest(); 6.83 final Block pass = ifNode.getPass(); 6.84 final Block fail = ifNode.getFail(); 6.85 + 6.86 + if (Expression.isAlwaysTrue(test)) { 6.87 + loadAndDiscard(test); 6.88 + pass.accept(this); 6.89 + return false; 6.90 + } else if (Expression.isAlwaysFalse(test)) { 6.91 + loadAndDiscard(test); 6.92 + if (fail != null) { 6.93 + fail.accept(this); 6.94 + } 6.95 + return false; 6.96 + } 6.97 + 6.98 final boolean hasFailConversion = LocalVariableConversion.hasLiveConversion(ifNode); 6.99 6.100 final Label failLabel = new Label("if_fail"); 6.101 @@ -2034,7 +2053,7 @@ 6.102 method.beforeJoinPoint(ifNode); 6.103 } 6.104 6.105 - if(afterLabel != null) { 6.106 + if(afterLabel != null && afterLabel.isReachable()) { 6.107 method.label(afterLabel); 6.108 } 6.109 6.110 @@ -2811,7 +2830,7 @@ 6.111 Label defaultLabel = defaultCase != null ? defaultCase.getEntry() : breakLabel; 6.112 final boolean hasSkipConversion = LocalVariableConversion.hasLiveConversion(switchNode); 6.113 6.114 - if (switchNode.isInteger()) { 6.115 + if (switchNode.isUniqueInteger()) { 6.116 // Tree for sorting values. 6.117 final TreeMap<Integer, Label> tree = new TreeMap<>(); 6.118 6.119 @@ -3145,14 +3164,13 @@ 6.120 if (isFastScope(identSymbol)) { 6.121 storeFastScopeVar(identSymbol, flags); 6.122 } else { 6.123 - method.dynamicSet(identNode.getName(), flags); 6.124 + method.dynamicSet(identNode.getName(), flags, false); 6.125 } 6.126 } else { 6.127 final Type identType = identNode.getType(); 6.128 if(identType == Type.UNDEFINED) { 6.129 - // The symbol must not be slotted; the initializer is either itself undefined (explicit assignment of 6.130 - // undefined to undefined), or the left hand side is a dead variable. 6.131 - assert !identNode.getSymbol().isScope(); 6.132 + // The initializer is either itself undefined (explicit assignment of undefined to undefined), 6.133 + // or the left hand side is a dead variable. 6.134 assert init.getType() == Type.UNDEFINED || identNode.getSymbol().slotCount() == 0; 6.135 loadAndDiscard(init); 6.136 return false; 6.137 @@ -3264,7 +3282,7 @@ 6.138 emitContinueLabel(continueLabel, liveLocalsOnContinue); 6.139 } 6.140 6.141 - if (loopNode.hasPerIterationScope() && lc.getParentBlock().needsScope()) { 6.142 + if (loopNode.hasPerIterationScope() && lc.getCurrentBlock().needsScope()) { 6.143 // ES6 for loops with LET init need a new scope for each iteration. We just create a shallow copy here. 6.144 method.loadCompilerConstant(SCOPE); 6.145 method.invoke(virtualCallNoLookup(ScriptObject.class, "copy", ScriptObject.class)); 6.146 @@ -3575,9 +3593,9 @@ 6.147 operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT); 6.148 } else { 6.149 // Non-optimistic, non-FP +. Allow it to overflow. 6.150 - operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest), 6.151 - Type.OBJECT); 6.152 - forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest); 6.153 + final Type widestOperationType = binaryNode.getWidestOperationType(); 6.154 + operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest), widestOperationType); 6.155 + forceConversionSeparation = widestOperationType.narrowerThan(resultBounds.widest); 6.156 } 6.157 loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation); 6.158 } 6.159 @@ -3692,8 +3710,7 @@ 6.160 final Expression lhs = assignNode.lhs(); 6.161 final Expression rhs = assignNode.rhs(); 6.162 final Type widestOperationType = assignNode.getWidestOperationType(); 6.163 - final Type widest = assignNode.isTokenType(TokenType.ASSIGN_ADD) ? Type.OBJECT : widestOperationType; 6.164 - final TypeBounds bounds = new TypeBounds(assignNode.getType(), widest); 6.165 + final TypeBounds bounds = new TypeBounds(assignNode.getType(), widestOperationType); 6.166 new OptimisticOperation(assignNode, bounds) { 6.167 @Override 6.168 void loadStack() { 6.169 @@ -4251,7 +4268,7 @@ 6.170 if (isFastScope(symbol)) { 6.171 storeFastScopeVar(symbol, flags); 6.172 } else { 6.173 - method.dynamicSet(node.getName(), flags); 6.174 + method.dynamicSet(node.getName(), flags, false); 6.175 } 6.176 } else { 6.177 final Type storeType = assignNode.getType(); 6.178 @@ -4268,7 +4285,7 @@ 6.179 6.180 @Override 6.181 public boolean enterAccessNode(final AccessNode node) { 6.182 - method.dynamicSet(node.getProperty(), getCallSiteFlags()); 6.183 + method.dynamicSet(node.getProperty(), getCallSiteFlags(), node.isIndex()); 6.184 return false; 6.185 } 6.186 6.187 @@ -4606,11 +4623,11 @@ 6.188 * @param isMethod whether we're preferrably retrieving a function 6.189 * @return the current method emitter 6.190 */ 6.191 - MethodEmitter dynamicGet(final String name, final int flags, final boolean isMethod) { 6.192 + MethodEmitter dynamicGet(final String name, final int flags, final boolean isMethod, final boolean isIndex) { 6.193 if(isOptimistic) { 6.194 - return method.dynamicGet(getOptimisticCoercedType(), name, getOptimisticFlags(flags), isMethod); 6.195 - } 6.196 - return method.dynamicGet(resultBounds.within(expression.getType()), name, nonOptimisticFlags(flags), isMethod); 6.197 + return method.dynamicGet(getOptimisticCoercedType(), name, getOptimisticFlags(flags), isMethod, isIndex); 6.198 + } 6.199 + return method.dynamicGet(resultBounds.within(expression.getType()), name, nonOptimisticFlags(flags), isMethod, isIndex); 6.200 } 6.201 6.202 MethodEmitter dynamicGetIndex(final int flags, final boolean isMethod) {
7.1 --- a/src/jdk/nashorn/internal/codegen/FoldConstants.java Tue Dec 16 14:46:13 2014 -0800 7.2 +++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java Wed Dec 17 12:51:46 2014 -0800 7.3 @@ -26,12 +26,16 @@ 7.4 package jdk.nashorn.internal.codegen; 7.5 7.6 import java.util.ArrayList; 7.7 +import java.util.HashSet; 7.8 import java.util.List; 7.9 +import java.util.Set; 7.10 import jdk.nashorn.internal.codegen.types.Type; 7.11 import jdk.nashorn.internal.ir.BinaryNode; 7.12 import jdk.nashorn.internal.ir.Block; 7.13 import jdk.nashorn.internal.ir.BlockStatement; 7.14 +import jdk.nashorn.internal.ir.CaseNode; 7.15 import jdk.nashorn.internal.ir.EmptyNode; 7.16 +import jdk.nashorn.internal.ir.Expression; 7.17 import jdk.nashorn.internal.ir.FunctionNode; 7.18 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 7.19 import jdk.nashorn.internal.ir.IfNode; 7.20 @@ -40,6 +44,7 @@ 7.21 import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 7.22 import jdk.nashorn.internal.ir.Node; 7.23 import jdk.nashorn.internal.ir.Statement; 7.24 +import jdk.nashorn.internal.ir.SwitchNode; 7.25 import jdk.nashorn.internal.ir.TernaryNode; 7.26 import jdk.nashorn.internal.ir.UnaryNode; 7.27 import jdk.nashorn.internal.ir.VarNode; 7.28 @@ -126,11 +131,37 @@ 7.29 public Node leaveTernaryNode(final TernaryNode ternaryNode) { 7.30 final Node test = ternaryNode.getTest(); 7.31 if (test instanceof LiteralNode.PrimitiveLiteralNode) { 7.32 - return ((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression(); 7.33 + return (((LiteralNode.PrimitiveLiteralNode<?>)test).isTrue() ? ternaryNode.getTrueExpression() : ternaryNode.getFalseExpression()).getExpression(); 7.34 } 7.35 return ternaryNode; 7.36 } 7.37 7.38 + @Override 7.39 + public Node leaveSwitchNode(final SwitchNode switchNode) { 7.40 + return switchNode.setUniqueInteger(lc, isUniqueIntegerSwitchNode(switchNode)); 7.41 + } 7.42 + 7.43 + private static boolean isUniqueIntegerSwitchNode(final SwitchNode switchNode) { 7.44 + final Set<Integer> alreadySeen = new HashSet<>(); 7.45 + for (final CaseNode caseNode : switchNode.getCases()) { 7.46 + final Expression test = caseNode.getTest(); 7.47 + if (test != null && !isUniqueIntegerLiteral(test, alreadySeen)) { 7.48 + return false; 7.49 + } 7.50 + } 7.51 + return true; 7.52 + } 7.53 + 7.54 + private static boolean isUniqueIntegerLiteral(final Expression expr, final Set<Integer> alreadySeen) { 7.55 + if (expr instanceof LiteralNode) { 7.56 + final Object value = ((LiteralNode<?>)expr).getValue(); 7.57 + if (value instanceof Integer) { 7.58 + return alreadySeen.add((Integer)value); 7.59 + } 7.60 + } 7.61 + return false; 7.62 + } 7.63 + 7.64 /** 7.65 * Helper class to evaluate constant expressions at compile time This is 7.66 * also a simplifier used by BinaryNode visits, UnaryNode visits and
8.1 --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Tue Dec 16 14:46:13 2014 -0800 8.2 +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Dec 17 12:51:46 2014 -0800 8.3 @@ -28,6 +28,7 @@ 8.4 import static jdk.nashorn.internal.codegen.CompilerConstants.RETURN; 8.5 import static jdk.nashorn.internal.ir.Expression.isAlwaysFalse; 8.6 import static jdk.nashorn.internal.ir.Expression.isAlwaysTrue; 8.7 + 8.8 import java.util.ArrayDeque; 8.9 import java.util.ArrayList; 8.10 import java.util.Collections; 8.11 @@ -82,7 +83,6 @@ 8.12 import jdk.nashorn.internal.ir.VarNode; 8.13 import jdk.nashorn.internal.ir.WhileNode; 8.14 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 8.15 -import jdk.nashorn.internal.parser.Token; 8.16 import jdk.nashorn.internal.parser.TokenType; 8.17 8.18 /** 8.19 @@ -93,6 +93,13 @@ 8.20 * variable to its widest used type after the join point. That would eliminate some widenings of undefined variables to 8.21 * object, most notably those used only in loops. We need a full liveness analysis for that. Currently, we can establish 8.22 * per-type liveness, which eliminates most of unwanted dead widenings. 8.23 + * NOTE: the way this class is implemented, it actually processes the AST in two passes. The first pass is top-down and 8.24 + * implemented in {@code enterXxx} methods. This pass does not mutate the AST (except for one occurrence, noted below), 8.25 + * as being able to find relevant labels for control flow joins is sensitive to their reference identity, and mutated 8.26 + * label-carrying nodes will create copies of their labels. A second bottom-up pass applying the changes is implemented 8.27 + * in the separate visitor sitting in {@link #leaveFunctionNode(FunctionNode)}. This visitor will also instantiate new 8.28 + * instances of the calculator to be run on nested functions (when not lazy compiling). 8.29 + * 8.30 */ 8.31 final class LocalVariableTypesCalculator extends NodeVisitor<LexicalContext>{ 8.32 8.33 @@ -398,48 +405,53 @@ 8.34 8.35 @Override 8.36 public boolean enterBinaryNode(final BinaryNode binaryNode) { 8.37 + // NOTE: regardless of operator's lexical associativity, lhs is always evaluated first. 8.38 final Expression lhs = binaryNode.lhs(); 8.39 - final Expression rhs = binaryNode.rhs(); 8.40 final boolean isAssignment = binaryNode.isAssignment(); 8.41 - 8.42 - final TokenType tokenType = Token.descType(binaryNode.getToken()); 8.43 - if(tokenType.isLeftAssociative()) { 8.44 - assert !isAssignment; 8.45 - final boolean isLogical = binaryNode.isLogical(); 8.46 - final Label joinLabel = isLogical ? new Label("") : null; 8.47 - lhs.accept(this); 8.48 - if(isLogical) { 8.49 - jumpToLabel((JoinPredecessor)lhs, joinLabel); 8.50 - } 8.51 - rhs.accept(this); 8.52 - if(isLogical) { 8.53 - jumpToLabel((JoinPredecessor)rhs, joinLabel); 8.54 - } 8.55 - joinOnLabel(joinLabel); 8.56 - } else { 8.57 - rhs.accept(this); 8.58 - if(isAssignment) { 8.59 - if(lhs instanceof BaseNode) { 8.60 - ((BaseNode)lhs).getBase().accept(this); 8.61 - if(lhs instanceof IndexNode) { 8.62 - ((IndexNode)lhs).getIndex().accept(this); 8.63 - } else { 8.64 - assert lhs instanceof AccessNode; 8.65 - } 8.66 + LvarType lhsTypeOnLoad = null; 8.67 + if(isAssignment) { 8.68 + if(lhs instanceof BaseNode) { 8.69 + ((BaseNode)lhs).getBase().accept(this); 8.70 + if(lhs instanceof IndexNode) { 8.71 + ((IndexNode)lhs).getIndex().accept(this); 8.72 } else { 8.73 - assert lhs instanceof IdentNode; 8.74 - if(binaryNode.isSelfModifying()) { 8.75 - ((IdentNode)lhs).accept(this); 8.76 - } 8.77 + assert lhs instanceof AccessNode; 8.78 } 8.79 } else { 8.80 - lhs.accept(this); 8.81 + assert lhs instanceof IdentNode; 8.82 + if(binaryNode.isSelfModifying()) { 8.83 + final IdentNode ident = ((IdentNode)lhs); 8.84 + ident.accept(this); 8.85 + // Self-assignment can cause a change in the type of the variable. For purposes of evaluating 8.86 + // the type of the operation, we must use its type as it was when it was loaded. If we didn't 8.87 + // do this, some awkward expressions would end up being calculated incorrectly, e.g. 8.88 + // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN). 8.89 + // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the 8.90 + // result type would be either optimistic int or pessimistic long, which would be wrong. 8.91 + lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol()); 8.92 + } 8.93 } 8.94 + } else { 8.95 + lhs.accept(this); 8.96 } 8.97 8.98 + final boolean isLogical = binaryNode.isLogical(); 8.99 + assert !(isAssignment && isLogical); // there are no logical assignment operators in JS 8.100 + final Label joinLabel = isLogical ? new Label("") : null; 8.101 + if(isLogical) { 8.102 + jumpToLabel((JoinPredecessor)lhs, joinLabel); 8.103 + } 8.104 + 8.105 + final Expression rhs = binaryNode.rhs(); 8.106 + rhs.accept(this); 8.107 + if(isLogical) { 8.108 + jumpToLabel((JoinPredecessor)rhs, joinLabel); 8.109 + } 8.110 + joinOnLabel(joinLabel); 8.111 + 8.112 if(isAssignment && lhs instanceof IdentNode) { 8.113 if(binaryNode.isSelfModifying()) { 8.114 - onSelfAssignment((IdentNode)lhs, binaryNode); 8.115 + onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad); 8.116 } else { 8.117 onAssignment((IdentNode)lhs, rhs); 8.118 } 8.119 @@ -704,7 +716,7 @@ 8.120 8.121 // Control flow is different for all-integer cases where we dispatch by switch table, and for all other cases 8.122 // where we do sequential comparison. Note that CaseNode objects act as join points. 8.123 - final boolean isInteger = switchNode.isInteger(); 8.124 + final boolean isInteger = switchNode.isUniqueInteger(); 8.125 final Label breakLabel = switchNode.getBreakLabel(); 8.126 final boolean hasDefault = switchNode.getDefaultCase() != null; 8.127 8.128 @@ -919,7 +931,8 @@ 8.129 8.130 if(unaryNode.isSelfModifying()) { 8.131 if(expr instanceof IdentNode) { 8.132 - onSelfAssignment((IdentNode)expr, unaryNode); 8.133 + final IdentNode ident = (IdentNode)expr; 8.134 + onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol())); 8.135 } 8.136 } 8.137 return false; 8.138 @@ -973,12 +986,41 @@ 8.139 return types; 8.140 } 8.141 8.142 + /** 8.143 + * Returns the current type of the local variable represented by the symbol. This is the most strict of all 8.144 + * {@code getLocalVariableType*} methods, as it will throw an assertion if the type is null. Therefore, it is only 8.145 + * safe to be invoked on symbols known to be bytecode locals, and only after they have been initialized. 8.146 + * Regardless, it is recommended to use this method in majority of cases, as because of its strictness it is the 8.147 + * best suited for catching missing type calculation bugs early. 8.148 + * @param symbol a symbol representing a bytecode local variable. 8.149 + * @return the current type of the local variable represented by the symbol 8.150 + */ 8.151 private LvarType getLocalVariableType(final Symbol symbol) { 8.152 final LvarType type = getLocalVariableTypeOrNull(symbol); 8.153 assert type != null; 8.154 return type; 8.155 } 8.156 8.157 + /** 8.158 + * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where 8.159 + * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to 8.160 + * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already 8.161 + * defined (that is, not null). 8.162 + * @param symbol the symbol representing the variable. 8.163 + * @return the current variable type, if it is a bytecode local, otherwise null. 8.164 + */ 8.165 + private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) { 8.166 + return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null; 8.167 + } 8.168 + 8.169 + /** 8.170 + * Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict 8.171 + * of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where 8.172 + * a just-defined symbol might still be null). 8.173 + * @param symbol the symbol 8.174 + * @return the current type for the symbol, or null if the type is not known either because the symbol has not been 8.175 + * initialized, or because the symbol does not represent a bytecode local variable. 8.176 + */ 8.177 private LvarType getLocalVariableTypeOrNull(final Symbol symbol) { 8.178 return localVariableTypes.get(symbol); 8.179 } 8.180 @@ -1358,13 +1400,13 @@ 8.181 jumpToCatchBlock(identNode); 8.182 } 8.183 8.184 - private void onSelfAssignment(final IdentNode identNode, final Expression assignment) { 8.185 + private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) { 8.186 final Symbol symbol = identNode.getSymbol(); 8.187 assert symbol != null : identNode.getName(); 8.188 if(!symbol.isBytecodeLocal()) { 8.189 return; 8.190 } 8.191 - final LvarType type = toLvarType(getType(assignment)); 8.192 + final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type)); 8.193 // Self-assignment never produce either a boolean or undefined 8.194 assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN; 8.195 setType(symbol, type); 8.196 @@ -1445,13 +1487,24 @@ 8.197 symbolIsUsed(symbol, getLocalVariableType(symbol)); 8.198 } 8.199 8.200 + /** 8.201 + * Gets the type of the expression, dependent on the current types of the local variables. 8.202 + * 8.203 + * @param expr the expression 8.204 + * @return the current type of the expression dependent on the current types of the local variables. 8.205 + */ 8.206 private Type getType(final Expression expr) { 8.207 return expr.getType(getSymbolToType()); 8.208 } 8.209 8.210 + /** 8.211 + * Returns a function object from symbols to their types, used by the expressions to evaluate their type. 8.212 + * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes 8.213 + * sure to return the same function object while the local variable types don't change, and create a new function 8.214 + * object if the local variable types have been changed. 8.215 + * @return a function object representing a mapping from symbols to their types. 8.216 + */ 8.217 private Function<Symbol, Type> getSymbolToType() { 8.218 - // BinaryNode uses identity of the function to cache type calculations. Therefore, we must use different 8.219 - // function instances for different localVariableTypes instances. 8.220 if(symbolToType.isStale()) { 8.221 symbolToType = new SymbolToType(); 8.222 } 8.223 @@ -1469,4 +1522,41 @@ 8.224 return boundTypes != localVariableTypes; 8.225 } 8.226 } 8.227 + 8.228 + /** 8.229 + * Gets the type of the expression, dependent on the current types of the local variables and a single overridden 8.230 + * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was 8.231 + * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for 8.232 + * the calculation. 8.233 + * 8.234 + * @param expr the expression 8.235 + * @param overriddenSymbol the overridden symbol 8.236 + * @param overriddenType the overridden type 8.237 + * @return the current type of the expression dependent on the current types of the local variables and the single 8.238 + * potentially overridden type. 8.239 + */ 8.240 + private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) { 8.241 + return expr.getType(getSymbolToType(overriddenSymbol, overriddenType)); 8.242 + } 8.243 + 8.244 + private Function<Symbol, Type> getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) { 8.245 + return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() : 8.246 + new SymbolToTypeOverride(overriddenSymbol, overriddenType); 8.247 + } 8.248 + 8.249 + private class SymbolToTypeOverride implements Function<Symbol, Type> { 8.250 + private final Function<Symbol, Type> originalSymbolToType = getSymbolToType(); 8.251 + private final Symbol overriddenSymbol; 8.252 + private final Type overriddenType; 8.253 + 8.254 + SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) { 8.255 + this.overriddenSymbol = overriddenSymbol; 8.256 + this.overriddenType = overriddenType; 8.257 + } 8.258 + 8.259 + @Override 8.260 + public Type apply(final Symbol symbol) { 8.261 + return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol); 8.262 + } 8.263 + } 8.264 }
9.1 --- a/src/jdk/nashorn/internal/codegen/Lower.java Tue Dec 16 14:46:13 2014 -0800 9.2 +++ b/src/jdk/nashorn/internal/codegen/Lower.java Wed Dec 17 12:51:46 2014 -0800 9.3 @@ -34,6 +34,8 @@ 9.4 import java.util.Collections; 9.5 import java.util.List; 9.6 import java.util.ListIterator; 9.7 +import java.util.regex.Pattern; 9.8 +import jdk.nashorn.internal.ir.AccessNode; 9.9 import jdk.nashorn.internal.ir.BaseNode; 9.10 import jdk.nashorn.internal.ir.BinaryNode; 9.11 import jdk.nashorn.internal.ir.Block; 9.12 @@ -52,6 +54,7 @@ 9.13 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 9.14 import jdk.nashorn.internal.ir.IdentNode; 9.15 import jdk.nashorn.internal.ir.IfNode; 9.16 +import jdk.nashorn.internal.ir.IndexNode; 9.17 import jdk.nashorn.internal.ir.JumpStatement; 9.18 import jdk.nashorn.internal.ir.LabelNode; 9.19 import jdk.nashorn.internal.ir.LexicalContext; 9.20 @@ -93,6 +96,10 @@ 9.21 9.22 private final DebugLogger log; 9.23 9.24 + // Conservative pattern to test if element names consist of characters valid for identifiers. 9.25 + // This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit. 9.26 + private static Pattern SAFE_PROPERTY_NAME = Pattern.compile("[a-zA-Z_$][\\w$]*"); 9.27 + 9.28 /** 9.29 * Constructor. 9.30 */ 9.31 @@ -140,7 +147,7 @@ 9.32 } 9.33 }); 9.34 9.35 - this.log = initLogger(compiler.getContext()); 9.36 + this.log = initLogger(compiler.getContext()); 9.37 } 9.38 9.39 @Override 9.40 @@ -181,6 +188,28 @@ 9.41 } 9.42 9.43 @Override 9.44 + public Node leaveIndexNode(final IndexNode indexNode) { 9.45 + final String name = getConstantPropertyName(indexNode.getIndex()); 9.46 + if (name != null) { 9.47 + // If index node is a constant property name convert index node to access node. 9.48 + assert Token.descType(indexNode.getToken()) == TokenType.LBRACKET; 9.49 + return new AccessNode(indexNode.getToken(), indexNode.getFinish(), indexNode.getBase(), name); 9.50 + } 9.51 + return super.leaveIndexNode(indexNode); 9.52 + } 9.53 + 9.54 + // If expression is a primitive literal that is not an array index and does return its string value. Else return null. 9.55 + private static String getConstantPropertyName(final Expression expression) { 9.56 + if (expression instanceof LiteralNode.PrimitiveLiteralNode) { 9.57 + final Object value = ((LiteralNode) expression).getValue(); 9.58 + if (value instanceof String && SAFE_PROPERTY_NAME.matcher((String) value).matches()) { 9.59 + return (String) value; 9.60 + } 9.61 + } 9.62 + return null; 9.63 + } 9.64 + 9.65 + @Override 9.66 public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { 9.67 final Expression expr = expressionStatement.getExpression(); 9.68 ExpressionStatement node = expressionStatement; 9.69 @@ -275,7 +304,7 @@ 9.70 9.71 @Override 9.72 public Node leaveSwitchNode(final SwitchNode switchNode) { 9.73 - if(!switchNode.isInteger()) { 9.74 + if(!switchNode.isUniqueInteger()) { 9.75 // Wrap it in a block so its internally created tag is restricted in scope 9.76 addStatementEnclosedInBlock(switchNode); 9.77 } else {
10.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Dec 16 14:46:13 2014 -0800 10.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Dec 17 12:51:46 2014 -0800 10.3 @@ -2214,10 +2214,10 @@ 10.4 * @param name name of property 10.5 * @param flags call site flags 10.6 * @param isMethod should it prefer retrieving methods 10.7 - * 10.8 + * @param isIndex is this an index operation? 10.9 * @return the method emitter 10.10 */ 10.11 - MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) { 10.12 + MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) { 10.13 debug("dynamic_get", name, valueType, getProgramPoint(flags)); 10.14 10.15 Type type = valueType; 10.16 @@ -2226,8 +2226,8 @@ 10.17 } 10.18 10.19 popType(Type.SCOPE); 10.20 - method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") + 10.21 - NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags); 10.22 + method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name), 10.23 + Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags); 10.24 10.25 pushType(type); 10.26 convert(valueType); //most probably a nop 10.27 @@ -2240,8 +2240,9 @@ 10.28 * 10.29 * @param name name of property 10.30 * @param flags call site flags 10.31 + * @param isIndex is this an index operation? 10.32 */ 10.33 - void dynamicSet(final String name, final int flags) { 10.34 + void dynamicSet(final String name, final int flags, final boolean isIndex) { 10.35 assert !isOptimistic(flags); 10.36 debug("dynamic_set", name, peekType()); 10.37 10.38 @@ -2253,7 +2254,8 @@ 10.39 popType(type); 10.40 popType(Type.SCOPE); 10.41 10.42 - method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags); 10.43 + method.visitInvokeDynamicInsn(dynSetOperation(isIndex) + ':' + NameCodec.encode(name), 10.44 + methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags); 10.45 } 10.46 10.47 /** 10.48 @@ -2286,7 +2288,7 @@ 10.49 10.50 final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index); 10.51 10.52 - method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod", signature, LINKERBOOTSTRAP, flags); 10.53 + method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags); 10.54 pushType(resultType); 10.55 10.56 if (result.isBoolean()) { 10.57 @@ -2500,6 +2502,18 @@ 10.58 } 10.59 } 10.60 10.61 + private static String dynGetOperation(final boolean isMethod, final boolean isIndex) { 10.62 + if (isMethod) { 10.63 + return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem"; 10.64 + } else { 10.65 + return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod"; 10.66 + } 10.67 + } 10.68 + 10.69 + private static String dynSetOperation(final boolean isIndex) { 10.70 + return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem"; 10.71 + } 10.72 + 10.73 private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) { 10.74 final Type from = conversion.getFrom(); 10.75 final Type to = conversion.getTo();
11.1 --- a/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Tue Dec 16 14:46:13 2014 -0800 11.2 +++ b/src/jdk/nashorn/internal/codegen/SharedScopeCall.java Wed Dec 17 12:51:46 2014 -0800 11.3 @@ -156,7 +156,7 @@ 11.4 assert !isCall || valueType.isObject(); // Callables are always objects 11.5 // If flags are optimistic, but we're doing a call, remove optimistic flags from the getter, as they obviously 11.6 // only apply to the call. 11.7 - method.dynamicGet(valueType, symbol.getName(), isCall ? CodeGenerator.nonOptimisticFlags(flags) : flags, isCall); 11.8 + method.dynamicGet(valueType, symbol.getName(), isCall ? CodeGenerator.nonOptimisticFlags(flags) : flags, isCall, false); 11.9 11.10 // If this is a get we're done, otherwise call the value as function. 11.11 if (isCall) {
12.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java Tue Dec 16 14:46:13 2014 -0800 12.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Wed Dec 17 12:51:46 2014 -0800 12.3 @@ -28,6 +28,8 @@ 12.4 import jdk.nashorn.internal.codegen.types.Type; 12.5 import jdk.nashorn.internal.ir.annotations.Immutable; 12.6 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 12.7 +import jdk.nashorn.internal.parser.Token; 12.8 +import jdk.nashorn.internal.parser.TokenType; 12.9 12.10 /** 12.11 * IR representation of a property access (period operator.) 12.12 @@ -101,6 +103,14 @@ 12.13 return property; 12.14 } 12.15 12.16 + /** 12.17 + * Return true if this node represents an index operation normally represented as {@link IndexNode}. 12.18 + * @return true if an index access. 12.19 + */ 12.20 + public boolean isIndex() { 12.21 + return Token.descType(getToken()) == TokenType.LBRACKET; 12.22 + } 12.23 + 12.24 private AccessNode setBase(final Expression base) { 12.25 if (this.base == base) { 12.26 return this;
13.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Dec 16 14:46:13 2014 -0800 13.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Dec 17 12:51:46 2014 -0800 13.3 @@ -341,10 +341,7 @@ 13.4 @Override 13.5 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 13.6 if (visitor.enterBinaryNode(this)) { 13.7 - if(tokenType().isLeftAssociative()) { 13.8 - return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor))); 13.9 - } 13.10 - return visitor.leaveBinaryNode(setRHS((Expression)rhs.accept(visitor)).setLHS((Expression)lhs.accept(visitor))); 13.11 + return visitor.leaveBinaryNode(setLHS((Expression)lhs.accept(visitor)).setRHS((Expression)rhs.accept(visitor))); 13.12 } 13.13 13.14 return this;
14.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Tue Dec 16 14:46:13 2014 -0800 14.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Dec 17 12:51:46 2014 -0800 14.3 @@ -27,7 +27,6 @@ 14.4 14.5 import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT; 14.6 14.7 -import java.util.ArrayList; 14.8 import java.util.Arrays; 14.9 import java.util.Collections; 14.10 import java.util.List; 14.11 @@ -468,11 +467,7 @@ 14.12 @Override 14.13 public Node accept(final NodeVisitor<? extends LexicalContext> visitor) { 14.14 if (visitor.enterRuntimeNode(this)) { 14.15 - final List<Expression> newArgs = new ArrayList<>(); 14.16 - for (final Node arg : args) { 14.17 - newArgs.add((Expression)arg.accept(visitor)); 14.18 - } 14.19 - return visitor.leaveRuntimeNode(setArgs(newArgs)); 14.20 + return visitor.leaveRuntimeNode(setArgs(Node.accept(visitor, args))); 14.21 } 14.22 14.23 return this;
15.1 --- a/src/jdk/nashorn/internal/ir/SwitchNode.java Tue Dec 16 14:46:13 2014 -0800 15.2 +++ b/src/jdk/nashorn/internal/ir/SwitchNode.java Wed Dec 17 12:51:46 2014 -0800 15.3 @@ -48,6 +48,10 @@ 15.4 /** Switch default index. */ 15.5 private final int defaultCaseIndex; 15.6 15.7 + /** True if all cases are 32-bit signed integer constants, without repetitions. It's a prerequisite for 15.8 + * using a tableswitch/lookupswitch when generating code. */ 15.9 + private final boolean uniqueInteger; 15.10 + 15.11 /** Tag symbol. */ 15.12 private Symbol tag; 15.13 15.14 @@ -66,15 +70,17 @@ 15.15 this.expression = expression; 15.16 this.cases = cases; 15.17 this.defaultCaseIndex = defaultCase == null ? -1 : cases.indexOf(defaultCase); 15.18 + this.uniqueInteger = false; 15.19 } 15.20 15.21 private SwitchNode(final SwitchNode switchNode, final Expression expression, final List<CaseNode> cases, 15.22 - final int defaultCaseIndex, final LocalVariableConversion conversion) { 15.23 + final int defaultCaseIndex, final LocalVariableConversion conversion, final boolean uniqueInteger) { 15.24 super(switchNode, conversion); 15.25 this.expression = expression; 15.26 this.cases = cases; 15.27 this.defaultCaseIndex = defaultCaseIndex; 15.28 - this.tag = switchNode.getTag(); //TODO are symbols inhereted as references? 15.29 + this.tag = switchNode.getTag(); //TODO are symbols inherited as references? 15.30 + this.uniqueInteger = uniqueInteger; 15.31 } 15.32 15.33 @Override 15.34 @@ -83,7 +89,7 @@ 15.35 for (final CaseNode caseNode : cases) { 15.36 newCases.add(new CaseNode(caseNode, caseNode.getTest(), caseNode.getBody(), caseNode.getLocalVariableConversion())); 15.37 } 15.38 - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion)); 15.39 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, newCases, defaultCaseIndex, conversion, uniqueInteger)); 15.40 } 15.41 15.42 @Override 15.43 @@ -151,7 +157,7 @@ 15.44 if (this.cases == cases) { 15.45 return this; 15.46 } 15.47 - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); 15.48 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); 15.49 } 15.50 15.51 /** 15.52 @@ -183,7 +189,7 @@ 15.53 if (this.expression == expression) { 15.54 return this; 15.55 } 15.56 - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); 15.57 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); 15.58 } 15.59 15.60 /** 15.61 @@ -205,25 +211,30 @@ 15.62 } 15.63 15.64 /** 15.65 - * Returns true if all cases of this switch statement are 32-bit signed integer constants. 15.66 - * @return true if all cases of this switch statement are 32-bit signed integer constants. 15.67 + * Returns true if all cases of this switch statement are 32-bit signed integer constants, without repetitions. 15.68 + * @return true if all cases of this switch statement are 32-bit signed integer constants, without repetitions. 15.69 */ 15.70 - public boolean isInteger() { 15.71 - for (final CaseNode caseNode : cases) { 15.72 - final Expression test = caseNode.getTest(); 15.73 - if (test != null && !isIntegerLiteral(test)) { 15.74 - return false; 15.75 - } 15.76 + public boolean isUniqueInteger() { 15.77 + return uniqueInteger; 15.78 + } 15.79 + 15.80 + /** 15.81 + * Sets whether all cases of this switch statement are 32-bit signed integer constants, without repetitions. 15.82 + * @param lc lexical context 15.83 + * @param uniqueInteger if true, all cases of this switch statement have been determined to be 32-bit signed 15.84 + * integer constants, without repetitions. 15.85 + * @return this switch node, if the value didn't change, or a new switch node with the changed value 15.86 + */ 15.87 + public SwitchNode setUniqueInteger(final LexicalContext lc, final boolean uniqueInteger) { 15.88 + if(this.uniqueInteger == uniqueInteger) { 15.89 + return this; 15.90 } 15.91 - return true; 15.92 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); 15.93 } 15.94 15.95 @Override 15.96 JoinPredecessor setLocalVariableConversionChanged(final LexicalContext lc, final LocalVariableConversion conversion) { 15.97 - return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion)); 15.98 + return Node.replaceInLexicalContext(lc, this, new SwitchNode(this, expression, cases, defaultCaseIndex, conversion, uniqueInteger)); 15.99 } 15.100 15.101 - private static boolean isIntegerLiteral(final Expression expr) { 15.102 - return expr instanceof LiteralNode && ((LiteralNode<?>)expr).getValue() instanceof Integer; 15.103 - } 15.104 }
16.1 --- a/src/jdk/nashorn/internal/parser/Parser.java Tue Dec 16 14:46:13 2014 -0800 16.2 +++ b/src/jdk/nashorn/internal/parser/Parser.java Wed Dec 17 12:51:46 2014 -0800 16.3 @@ -2644,7 +2644,7 @@ 16.4 // name is null, generate anonymous name 16.5 boolean isAnonymous = false; 16.6 if (name == null) { 16.7 - final String tmpName = getDefaultValidFunctionName(functionLine); 16.8 + final String tmpName = getDefaultValidFunctionName(functionLine, isStatement); 16.9 name = new IdentNode(functionToken, Token.descPosition(functionToken), tmpName); 16.10 isAnonymous = true; 16.11 } 16.12 @@ -2653,7 +2653,15 @@ 16.13 final List<IdentNode> parameters = formalParameterList(); 16.14 expect(RPAREN); 16.15 16.16 - FunctionNode functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine); 16.17 + FunctionNode functionNode; 16.18 + // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}" 16.19 + // If we didn't hide the current default name, then the innermost anonymous function would receive "x3". 16.20 + hideDefaultName(); 16.21 + try { 16.22 + functionNode = functionBody(functionToken, name, parameters, FunctionNode.Kind.NORMAL, functionLine); 16.23 + } finally { 16.24 + defaultNames.pop(); 16.25 + } 16.26 16.27 if (isStatement) { 16.28 if (topLevel || useBlockScope()) { 16.29 @@ -2722,9 +2730,17 @@ 16.30 return functionNode; 16.31 } 16.32 16.33 - private String getDefaultValidFunctionName(final int functionLine) { 16.34 + private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) { 16.35 final String defaultFunctionName = getDefaultFunctionName(); 16.36 - return isValidIdentifier(defaultFunctionName) ? defaultFunctionName : ANON_FUNCTION_PREFIX.symbolName() + functionLine; 16.37 + if (isValidIdentifier(defaultFunctionName)) { 16.38 + if (isStatement) { 16.39 + // The name will be used as the LHS of a symbol assignment. We add the anonymous function 16.40 + // prefix to ensure that it can't clash with another variable. 16.41 + return ANON_FUNCTION_PREFIX.symbolName() + defaultFunctionName; 16.42 + } 16.43 + return defaultFunctionName; 16.44 + } 16.45 + return ANON_FUNCTION_PREFIX.symbolName() + functionLine; 16.46 } 16.47 16.48 private static boolean isValidIdentifier(final String name) { 16.49 @@ -2758,6 +2774,10 @@ 16.50 16.51 private void markDefaultNameUsed() { 16.52 defaultNames.pop(); 16.53 + hideDefaultName(); 16.54 + } 16.55 + 16.56 + private void hideDefaultName() { 16.57 // Can be any value as long as getDefaultFunctionName doesn't recognize it as something it can extract a value 16.58 // from. Can't be null 16.59 defaultNames.push("");
17.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java Tue Dec 16 14:46:13 2014 -0800 17.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Dec 17 12:51:46 2014 -0800 17.3 @@ -2001,12 +2001,11 @@ 17.4 17.5 if (find == null) { 17.6 switch (operator) { 17.7 + case "getElem": // getElem only gets here if element name is constant, so treat it like a property access 17.8 case "getProp": 17.9 return noSuchProperty(desc, request); 17.10 case "getMethod": 17.11 return noSuchMethod(desc, request); 17.12 - case "getElem": 17.13 - return createEmptyGetter(desc, explicitInstanceOfCheck, name); 17.14 default: 17.15 throw new AssertionError(operator); // never invoked with any other operation 17.16 } 17.17 @@ -2333,8 +2332,9 @@ 17.18 } 17.19 17.20 final ScriptFunction func = (ScriptFunction)value; 17.21 - final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this; 17.22 + final Object thiz = scopeCall && func.isStrict() ? UNDEFINED : this; 17.23 // TODO: It'd be awesome if we could bind "name" without binding "this". 17.24 + // Since we're binding this we must use an identity guard here. 17.25 return new GuardedInvocation( 17.26 MH.dropArguments( 17.27 MH.constant( 17.28 @@ -2342,9 +2342,9 @@ 17.29 func.makeBoundFunction(thiz, new Object[] { name })), 17.30 0, 17.31 Object.class), 17.32 - NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), 17.33 - (SwitchPoint)null, 17.34 - explicitInstanceOfCheck ? null : ClassCastException.class); 17.35 + NashornGuards.combineGuards( 17.36 + NashornGuards.getIdentityGuard(this), 17.37 + NashornGuards.getMapGuard(getMap(), true))); 17.38 } 17.39 17.40 /** 17.41 @@ -3710,7 +3710,9 @@ 17.42 final ScriptObject clone = (ScriptObject) super.clone(); 17.43 if (objectSpill != null) { 17.44 clone.objectSpill = objectSpill.clone(); 17.45 - clone.primitiveSpill = primitiveSpill.clone(); 17.46 + if (primitiveSpill != null) { 17.47 + clone.primitiveSpill = primitiveSpill.clone(); 17.48 + } 17.49 } 17.50 clone.arrayData = arrayData.copy(); 17.51 return clone;
18.1 --- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Tue Dec 16 14:46:13 2014 -0800 18.2 +++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Wed Dec 17 12:51:46 2014 -0800 18.3 @@ -29,6 +29,7 @@ 18.4 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT; 18.5 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER; 18.6 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT; 18.7 +import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_CALL; 18.8 import java.lang.invoke.MethodHandle; 18.9 import java.lang.invoke.MethodHandles; 18.10 import jdk.internal.dynalink.CallSiteDescriptor; 18.11 @@ -123,6 +124,8 @@ 18.12 case "setProp": 18.13 case "setElem": 18.14 return c > 2 ? findSetMethod(desc) : findSetIndexMethod(); 18.15 + case "call": 18.16 + return findCallMethod(desc); 18.17 default: 18.18 return null; 18.19 } 18.20 @@ -148,6 +151,11 @@ 18.21 return new GuardedInvocation(JSOBJECTLINKER_PUT, IS_JSOBJECT_GUARD); 18.22 } 18.23 18.24 + private static GuardedInvocation findCallMethod(final CallSiteDescriptor desc) { 18.25 + final MethodHandle call = MH.insertArguments(JSOBJECT_CALL, 1, "call"); 18.26 + return new GuardedInvocation(MH.asCollector(call, Object[].class, desc.getMethodType().parameterCount() - 1), IS_JSOBJECT_GUARD); 18.27 + } 18.28 + 18.29 @SuppressWarnings("unused") 18.30 private static boolean isJSObject(final Object self) { 18.31 return jsObjectClass.isInstance(self); 18.32 @@ -207,6 +215,7 @@ 18.33 static final MethodHandle JSOBJECT_GETSLOT = findJSObjectMH_V("getSlot", Object.class, int.class).asType(MH.type(Object.class, Object.class, int.class)); 18.34 static final MethodHandle JSOBJECT_SETMEMBER = findJSObjectMH_V("setMember", Void.TYPE, String.class, Object.class).asType(MH.type(Void.TYPE, Object.class, String.class, Object.class)); 18.35 static final MethodHandle JSOBJECT_SETSLOT = findJSObjectMH_V("setSlot", Void.TYPE, int.class, Object.class).asType(MH.type(Void.TYPE, Object.class, int.class, Object.class)); 18.36 + static final MethodHandle JSOBJECT_CALL = findJSObjectMH_V("call", Object.class, String.class, Object[].class).asType(MH.type(Object.class, Object.class, String.class, Object[].class)); 18.37 18.38 private static MethodHandle findJSObjectMH_V(final String name, final Class<?> rtype, final Class<?>... types) { 18.39 checkJSObjectClass();
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 19.2 +++ b/test/script/basic/JDK-8066221.js Wed Dec 17 12:51:46 2014 -0800 19.3 @@ -0,0 +1,31 @@ 19.4 +/* 19.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 19.7 + * 19.8 + * This code is free software; you can redistribute it and/or modify it 19.9 + * under the terms of the GNU General Public License version 2 only, as 19.10 + * published by the Free Software Foundation. 19.11 + * 19.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 19.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19.15 + * version 2 for more details (a copy is included in the LICENSE file that 19.16 + * accompanied this code). 19.17 + * 19.18 + * You should have received a copy of the GNU General Public License version 19.19 + * 2 along with this work; if not, write to the Free Software Foundation, 19.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19.21 + * 19.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19.23 + * or visit www.oracle.com if you need additional information or have any 19.24 + * questions. 19.25 + */ 19.26 + 19.27 +/** 19.28 + * JDK-8066221: anonymous function statement name clashes with another symbol 19.29 + * (compile-only test) 19.30 + * 19.31 + * @test 19.32 + */ 19.33 + 19.34 +x3 = function x1(x3) { function (){} };
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 20.2 +++ b/test/script/basic/JDK-8066224.js Wed Dec 17 12:51:46 2014 -0800 20.3 @@ -0,0 +1,38 @@ 20.4 +/* 20.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 20.7 + * 20.8 + * This code is free software; you can redistribute it and/or modify it 20.9 + * under the terms of the GNU General Public License version 2 only, as 20.10 + * published by the Free Software Foundation. 20.11 + * 20.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 20.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 20.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20.15 + * version 2 for more details (a copy is included in the LICENSE file that 20.16 + * accompanied this code). 20.17 + * 20.18 + * You should have received a copy of the GNU General Public License version 20.19 + * 2 along with this work; if not, write to the Free Software Foundation, 20.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20.21 + * 20.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20.23 + * or visit www.oracle.com if you need additional information or have any 20.24 + * questions. 20.25 + */ 20.26 + 20.27 +/** 20.28 + * JDK-8066224: fixes for folding a constant-test ternary operator 20.29 + * 20.30 + * @test 20.31 + * @run 20.32 + */ 20.33 + 20.34 +print((function(){ 20.35 + if(false ? 0 : '') { 20.36 + throw false; 20.37 + } else if (x = this) { 20.38 + var x = x; 20.39 + } 20.40 + return x === this; 20.41 +})())
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 21.2 +++ b/test/script/basic/JDK-8066224.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 21.3 @@ -0,0 +1,1 @@ 21.4 +true
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 22.2 +++ b/test/script/basic/JDK-8066225.js Wed Dec 17 12:51:46 2014 -0800 22.3 @@ -0,0 +1,36 @@ 22.4 +/* 22.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 22.7 + * 22.8 + * This code is free software; you can redistribute it and/or modify it 22.9 + * under the terms of the GNU General Public License version 2 only, as 22.10 + * published by the Free Software Foundation. 22.11 + * 22.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 22.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 22.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 22.15 + * version 2 for more details (a copy is included in the LICENSE file that 22.16 + * accompanied this code). 22.17 + * 22.18 + * You should have received a copy of the GNU General Public License version 22.19 + * 2 along with this work; if not, write to the Free Software Foundation, 22.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22.21 + * 22.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22.23 + * or visit www.oracle.com if you need additional information or have any 22.24 + * questions. 22.25 + */ 22.26 + 22.27 +/** 22.28 + * JDK-8066225: NPE in MethodEmitter with duplicate integer switch cases 22.29 + * 22.30 + * @test 22.31 + * @run 22.32 + */ 22.33 + 22.34 +(function (x){ 22.35 + switch(x) { 22.36 + case 44: for (var x in {}) {x}; print("1"); 22.37 + case 44: print("2"); 22.38 + } 22.39 +})(44);
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 23.2 +++ b/test/script/basic/JDK-8066225.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 23.3 @@ -0,0 +1,2 @@ 23.4 +1 23.5 +2
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 24.2 +++ b/test/script/basic/JDK-8066227.js Wed Dec 17 12:51:46 2014 -0800 24.3 @@ -0,0 +1,40 @@ 24.4 +/* 24.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 24.7 + * 24.8 + * This code is free software; you can redistribute it and/or modify it 24.9 + * under the terms of the GNU General Public License version 2 only, as 24.10 + * published by the Free Software Foundation. 24.11 + * 24.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 24.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 24.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 24.15 + * version 2 for more details (a copy is included in the LICENSE file that 24.16 + * accompanied this code). 24.17 + * 24.18 + * You should have received a copy of the GNU General Public License version 24.19 + * 2 along with this work; if not, write to the Free Software Foundation, 24.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 24.21 + * 24.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24.23 + * or visit www.oracle.com if you need additional information or have any 24.24 + * questions. 24.25 + */ 24.26 + 24.27 +/** 24.28 + * JDK-8066227: CodeGenerator load unitialized slot 24.29 + * 24.30 + * @test 24.31 + * @run 24.32 + */ 24.33 + 24.34 +print((function () { var x; (x += x = 0); return x; })()); 24.35 +print((function () { var x; (x -= x = 0); return x; })()); 24.36 +print((function () { var x; (x *= x = 0); return x; })()); 24.37 +print((function () { var x; (x /= x = 0); return x; })()); 24.38 +print((function () { var x; (x %= x = 0); return x; })()); 24.39 +print((function () { var x; (x <<= x = 0); return x; })()); 24.40 +print((function () { var x; (x >>= x = 0); return x; })()); 24.41 +print((function () { var x; (x >>>= x = 0); return x; })()); 24.42 +print((function () { var x; (x |= x = 0); return x; })()); 24.43 +print((function () { var x; (x &= x = 0); return x; })());
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 25.2 +++ b/test/script/basic/JDK-8066227.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 25.3 @@ -0,0 +1,10 @@ 25.4 +NaN 25.5 +NaN 25.6 +NaN 25.7 +NaN 25.8 +NaN 25.9 +0 25.10 +0 25.11 +0 25.12 +0 25.13 +0
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 26.2 +++ b/test/script/basic/JDK-8066230.js Wed Dec 17 12:51:46 2014 -0800 26.3 @@ -0,0 +1,34 @@ 26.4 +/* 26.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 26.7 + * 26.8 + * This code is free software; you can redistribute it and/or modify it 26.9 + * under the terms of the GNU General Public License version 2 only, as 26.10 + * published by the Free Software Foundation. 26.11 + * 26.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 26.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 26.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 26.15 + * version 2 for more details (a copy is included in the LICENSE file that 26.16 + * accompanied this code). 26.17 + * 26.18 + * You should have received a copy of the GNU General Public License version 26.19 + * 2 along with this work; if not, write to the Free Software Foundation, 26.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 26.21 + * 26.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 26.23 + * or visit www.oracle.com if you need additional information or have any 26.24 + * questions. 26.25 + */ 26.26 + 26.27 +/** 26.28 + * JDK-8066230: Undefined object type assertion when computing TypeBounds 26.29 + * 26.30 + * @test 26.31 + * @run 26.32 + */ 26.33 + 26.34 +(function() { void null + 0; })(); 26.35 +(function() { var x; x += void x; })(); 26.36 +(function() { var a = true + x, x; })(); 26.37 +print("SUCCESS");
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 27.2 +++ b/test/script/basic/JDK-8066230.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 27.3 @@ -0,0 +1,1 @@ 27.4 +SUCCESS
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/test/script/basic/JDK-8066236.js Wed Dec 17 12:51:46 2014 -0800 28.3 @@ -0,0 +1,46 @@ 28.4 +/* 28.5 + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. 28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 28.7 + * 28.8 + * This code is free software; you can redistribute it and/or modify it 28.9 + * under the terms of the GNU General Public License version 2 only, as 28.10 + * published by the Free Software Foundation. 28.11 + * 28.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 28.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 28.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 28.15 + * version 2 for more details (a copy is included in the LICENSE file that 28.16 + * accompanied this code). 28.17 + * 28.18 + * You should have received a copy of the GNU General Public License version 28.19 + * 2 along with this work; if not, write to the Free Software Foundation, 28.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 28.21 + * 28.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 28.23 + * or visit www.oracle.com if you need additional information or have any 28.24 + * questions. 28.25 + */ 28.26 + 28.27 +/** 28.28 + * JDK-8066236: RuntimeNode forces copy creation on visitation 28.29 + * 28.30 + * @test 28.31 + * @run 28.32 + */ 28.33 + 28.34 +// Note: we're using Function("code") instead of (function(){ code }) so that 28.35 +// we don't trigger parser API validation in JDK-8008448 tests. The test code 28.36 +// encapsulated in functions below can't be correctly handled by the parser API 28.37 +// currently, as it contains parser-generated REFERENCE_ERROR runtime nodes. 28.38 +try { 28.39 + Function("L: {this = x;break L}")(); 28.40 +} catch (e) { 28.41 + print("threw ReferenceError: " + (e instanceof ReferenceError)); 28.42 +} 28.43 +try { 28.44 + Function("L:with(this--)break L;")(); 28.45 +} catch (e) { 28.46 + print("threw ReferenceError: " + (e instanceof ReferenceError)); 28.47 +} 28.48 +Function("L:with(Object in Object)break L;")(); 28.49 +print("SUCCESS");
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/test/script/basic/JDK-8066236.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 29.3 @@ -0,0 +1,3 @@ 29.4 +threw ReferenceError: true 29.5 +threw ReferenceError: true 29.6 +SUCCESS
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 30.2 +++ b/test/script/basic/JDK-8066669.js Wed Dec 17 12:51:46 2014 -0800 30.3 @@ -0,0 +1,58 @@ 30.4 +/* 30.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 30.7 + * 30.8 + * This code is free software; you can redistribute it and/or modify it 30.9 + * under the terms of the GNU General Public License version 2 only, as 30.10 + * published by the Free Software Foundation. 30.11 + * 30.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 30.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 30.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 30.15 + * version 2 for more details (a copy is included in the LICENSE file that 30.16 + * accompanied this code). 30.17 + * 30.18 + * You should have received a copy of the GNU General Public License version 30.19 + * 2 along with this work; if not, write to the Free Software Foundation, 30.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 30.21 + * 30.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 30.23 + * or visit www.oracle.com if you need additional information or have any 30.24 + * questions. 30.25 + */ 30.26 + 30.27 +/** 30.28 + * JDK-8066669: dust.js performance regression caused by primitive field conversion 30.29 + * 30.30 + * @test 30.31 + * @run 30.32 + */ 30.33 + 30.34 +// Make sure index access on Java objects is working as expected. 30.35 +var map = new java.util.HashMap(); 30.36 + 30.37 +map["foo"] = "bar"; 30.38 +map[1] = 2; 30.39 +map[false] = true; 30.40 +map[null] = 0; 30.41 + 30.42 +print(map); 30.43 + 30.44 +var keys = map.keySet().iterator(); 30.45 + 30.46 +while(keys.hasNext()) { 30.47 + var key = keys.next(); 30.48 + print(typeof key, key); 30.49 +} 30.50 + 30.51 +print(typeof map["foo"], map["foo"]); 30.52 +print(typeof map[1], map[1]); 30.53 +print(typeof map[false], map[false]); 30.54 +print(typeof map[null], map[null]); 30.55 + 30.56 +print(map.foo); 30.57 +print(map.false); 30.58 +print(map.null); 30.59 + 30.60 +map.foo = "baz"; 30.61 +print(map);
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 31.2 +++ b/test/script/basic/JDK-8066669.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 31.3 @@ -0,0 +1,13 @@ 31.4 +{null=0, 1=2, false=true, foo=bar} 31.5 +object null 31.6 +number 1 31.7 +boolean false 31.8 +string foo 31.9 +string bar 31.10 +number 2 31.11 +boolean true 31.12 +number 0 31.13 +bar 31.14 +null 31.15 +null 31.16 +{null=0, 1=2, false=true, foo=baz}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 32.2 +++ b/test/script/basic/JDK-8066932.js Wed Dec 17 12:51:46 2014 -0800 32.3 @@ -0,0 +1,48 @@ 32.4 +/* 32.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 32.7 + * 32.8 + * This code is free software; you can redistribute it and/or modify it 32.9 + * under the terms of the GNU General Public License version 2 only, as 32.10 + * published by the Free Software Foundation. 32.11 + * 32.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 32.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 32.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 32.15 + * version 2 for more details (a copy is included in the LICENSE file that 32.16 + * accompanied this code). 32.17 + * 32.18 + * You should have received a copy of the GNU General Public License version 32.19 + * 2 along with this work; if not, write to the Free Software Foundation, 32.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 32.21 + * 32.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 32.23 + * or visit www.oracle.com if you need additional information or have any 32.24 + * questions. 32.25 + */ 32.26 + 32.27 +/** 32.28 + * JDK-8066932: __noSuchMethod__ binds to this-object without proper guard 32.29 + * 32.30 + * @test 32.31 + * @run 32.32 + */ 32.33 + 32.34 +function C(id) { 32.35 + this.id = id; 32.36 +} 32.37 + 32.38 +C.prototype.__noSuchMethod__ = function(name, args) { 32.39 + return this.id; 32.40 +}; 32.41 + 32.42 +function test(id) { 32.43 + var c = new C(id); 32.44 + return c.nonExistingMethod(); 32.45 +} 32.46 + 32.47 +for (var i = 0; i < 30; i++) { 32.48 + if (test(i) !== i) { 32.49 + throw new Error("Wrong result from noSuchMethod in iteration " + i); 32.50 + } 32.51 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 33.2 +++ b/test/script/basic/JDK-8067136.js Wed Dec 17 12:51:46 2014 -0800 33.3 @@ -0,0 +1,69 @@ 33.4 +/* 33.5 + * Copyright (c) 2014, 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 + * JDK-8067136: BrowserJSObjectLinker does not handle call on JSObjects 33.29 + * 33.30 + * @test 33.31 + * @option -scripting 33.32 + * @run 33.33 + */ 33.34 + 33.35 +// call on netscape.javascript.JSObject 33.36 + 33.37 +function main() { 33.38 + var JSObject; 33.39 + try { 33.40 + JSObject = Java.type("netscape.javascript.JSObject"); 33.41 + } catch (e) { 33.42 + if (e instanceof java.lang.ClassNotFoundException) { 33.43 + // pass vacuously by emitting the .EXPECTED file content 33.44 + var str = readFully(__DIR__ + "JDK-8067136.js.EXPECTED"); 33.45 + print(str.substring(0, str.length - 1)); 33.46 + return; 33.47 + } else{ 33.48 + fail("unexpected exception for JSObject", e); 33.49 + } 33.50 + } 33.51 + test(JSObject); 33.52 +} 33.53 + 33.54 +function test(JSObject) { 33.55 + var obj = new (Java.extend(JSObject))() { 33.56 + getMember: function(name) { 33.57 + if (name == "func") { 33.58 + return new (Java.extend(JSObject)) { 33.59 + call: function(n) { 33.60 + print("func called"); 33.61 + } 33.62 + } 33.63 + } 33.64 + return name.toUpperCase(); 33.65 + }, 33.66 + 33.67 + }; 33.68 + 33.69 + obj.func(); 33.70 +} 33.71 + 33.72 +main();
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 34.2 +++ b/test/script/basic/JDK-8067136.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 34.3 @@ -0,0 +1,1 @@ 34.4 +func called
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 35.2 +++ b/test/script/basic/es6/for-let-object-fields.js Wed Dec 17 12:51:46 2014 -0800 35.3 @@ -0,0 +1,81 @@ 35.4 +/* 35.5 + * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 35.7 + * 35.8 + * This code is free software; you can redistribute it and/or modify it 35.9 + * under the terms of the GNU General Public License version 2 only, as 35.10 + * published by the Free Software Foundation. 35.11 + * 35.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 35.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 35.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 35.15 + * version 2 for more details (a copy is included in the LICENSE file that 35.16 + * accompanied this code). 35.17 + * 35.18 + * You should have received a copy of the GNU General Public License version 35.19 + * 2 along with this work; if not, write to the Free Software Foundation, 35.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 35.21 + * 35.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 35.23 + * or visit www.oracle.com if you need additional information or have any 35.24 + * questions. 35.25 + */ 35.26 + 35.27 +/** 35.28 + * JDK-8067219: NPE in ScriptObject.clone() when running with object fields 35.29 + * 35.30 + * @test 35.31 + * @run 35.32 + * @fork 35.33 + * @option -Dnashorn.fields.objects=true 35.34 + * @option --language=es6 35.35 + */ 35.36 + 35.37 +"use strict"; 35.38 + 35.39 +for (let i = 0; i < 10; i++) { 35.40 + print(i); 35.41 +} 35.42 + 35.43 +try { 35.44 + print(i); 35.45 +} catch (e) { 35.46 + print(e); 35.47 +} 35.48 + 35.49 +let a = []; 35.50 + 35.51 +for (let i = 0; i < 10; i++) { 35.52 + a.push(function() { print(i); }); 35.53 +} 35.54 + 35.55 +a.forEach(function(f) { f(); }); 35.56 + 35.57 +a = []; 35.58 + 35.59 +for (let i = 0; i < 10; i++) { 35.60 + if (i == 5) { 35.61 + i = "foo"; 35.62 + } 35.63 + a.push(function() { print(i); }); 35.64 +} 35.65 + 35.66 +a.forEach(function(f) { f(); }); 35.67 + 35.68 +try { 35.69 + print(i); 35.70 +} catch (e) { 35.71 + print(e); 35.72 +} 35.73 + 35.74 +a = []; 35.75 + 35.76 +for (let i = 0; i < 20; i++) { 35.77 + if (i % 2 == 1) { 35.78 + i += 2; 35.79 + continue; 35.80 + } 35.81 + a.push(function() { print(i); }); 35.82 +} 35.83 + 35.84 +a.forEach(function(f) { f(); });
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 36.2 +++ b/test/script/basic/es6/for-let-object-fields.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 36.3 @@ -0,0 +1,33 @@ 36.4 +0 36.5 +1 36.6 +2 36.7 +3 36.8 +4 36.9 +5 36.10 +6 36.11 +7 36.12 +8 36.13 +9 36.14 +ReferenceError: "i" is not defined 36.15 +0 36.16 +1 36.17 +2 36.18 +3 36.19 +4 36.20 +5 36.21 +6 36.22 +7 36.23 +8 36.24 +9 36.25 +0 36.26 +1 36.27 +2 36.28 +3 36.29 +4 36.30 +foo 36.31 +ReferenceError: "i" is not defined 36.32 +0 36.33 +4 36.34 +8 36.35 +12 36.36 +16
37.1 --- a/test/script/basic/es6/for-let.js Tue Dec 16 14:46:13 2014 -0800 37.2 +++ b/test/script/basic/es6/for-let.js Wed Dec 17 12:51:46 2014 -0800 37.3 @@ -26,7 +26,8 @@ 37.4 * 37.5 * @test 37.6 * @run 37.7 - * @option --language=es6 */ 37.8 + * @option --language=es6 37.9 + */ 37.10 37.11 "use strict"; 37.12
38.1 --- a/test/script/basic/list.js.EXPECTED Tue Dec 16 14:46:13 2014 -0800 38.2 +++ b/test/script/basic/list.js.EXPECTED Wed Dec 17 12:51:46 2014 -0800 38.3 @@ -10,7 +10,7 @@ 38.4 l[0]=foo 38.5 l[1]=a 38.6 l[0.9]=null 38.7 -l['blah']=null 38.8 +l['blah']=undefined 38.9 l[size_name]()=2 38.10 java.lang.IndexOutOfBoundsException: Index: 2, Size: 2 38.11 java.lang.IndexOutOfBoundsException: Index: Infinity, Size: 2