Wed, 09 Oct 2013 17:53:22 +0200
8026137: Fix Issues with Binary Evaluation Order
Reviewed-by: hannesw, jlaskey
Contributed-by: marcus.lagergren@oracle.com, attila.szegedi@oracle.com
1.1 --- a/src/jdk/nashorn/internal/codegen/Attr.java Wed Oct 09 14:50:39 2013 +0200 1.2 +++ b/src/jdk/nashorn/internal/codegen/Attr.java Wed Oct 09 17:53:22 2013 +0200 1.3 @@ -480,6 +480,10 @@ 1.4 } 1.5 1.6 //unknown parameters are promoted to object type. 1.7 + if (newFunctionNode.hasLazyChildren()) { 1.8 + //the final body has already been assigned as we have left the function node block body by now 1.9 + objectifySymbols(body); 1.10 + } 1.11 newFunctionNode = finalizeParameters(newFunctionNode); 1.12 newFunctionNode = finalizeTypes(newFunctionNode); 1.13 for (final Symbol symbol : newFunctionNode.getDeclaredSymbols()) { 1.14 @@ -489,11 +493,6 @@ 1.15 } 1.16 } 1.17 1.18 - if (newFunctionNode.hasLazyChildren()) { 1.19 - //the final body has already been assigned as we have left the function node block body by now 1.20 - objectifySymbols(body); 1.21 - } 1.22 - 1.23 List<VarNode> syntheticInitializers = null; 1.24 1.25 if (body.getFlag(Block.NEEDS_SELF_SYMBOL)) { 1.26 @@ -503,8 +502,8 @@ 1.27 syntheticInitializers.add(createSyntheticInitializer(newFunctionNode.getIdent(), CALLEE, newFunctionNode)); 1.28 } 1.29 1.30 - if(newFunctionNode.needsArguments()) { 1.31 - if(syntheticInitializers == null) { 1.32 + if (newFunctionNode.needsArguments()) { 1.33 + if (syntheticInitializers == null) { 1.34 syntheticInitializers = new ArrayList<>(1); 1.35 } 1.36 // "var arguments = :arguments" 1.37 @@ -512,12 +511,12 @@ 1.38 ARGUMENTS, newFunctionNode)); 1.39 } 1.40 1.41 - if(syntheticInitializers != null) { 1.42 - final List<Statement> stmts = body.getStatements(); 1.43 + if (syntheticInitializers != null) { 1.44 + final List<Statement> stmts = newFunctionNode.getBody().getStatements(); 1.45 final List<Statement> newStatements = new ArrayList<>(stmts.size() + syntheticInitializers.size()); 1.46 newStatements.addAll(syntheticInitializers); 1.47 newStatements.addAll(stmts); 1.48 - newFunctionNode = newFunctionNode.setBody(lc, body.setStatements(lc, newStatements)); 1.49 + newFunctionNode = newFunctionNode.setBody(lc, newFunctionNode.getBody().setStatements(lc, newStatements)); 1.50 } 1.51 1.52 if (returnTypes.peek().isUnknown()) { 1.53 @@ -558,12 +557,6 @@ 1.54 } 1.55 1.56 @Override 1.57 - public Node leaveCONVERT(final UnaryNode unaryNode) { 1.58 - assert false : "There should be no convert operators in IR during Attribution"; 1.59 - return end(unaryNode); 1.60 - } 1.61 - 1.62 - @Override 1.63 public Node leaveIdentNode(final IdentNode identNode) { 1.64 final String name = identNode.getName(); 1.65 1.66 @@ -991,7 +984,7 @@ 1.67 1.68 @Override 1.69 public Node leaveNEW(final UnaryNode unaryNode) { 1.70 - return end(ensureSymbol(Type.OBJECT, unaryNode)); 1.71 + return end(ensureSymbol(Type.OBJECT, unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew()))); 1.72 } 1.73 1.74 @Override 1.75 @@ -1287,7 +1280,9 @@ 1.76 private Node leaveCmp(final BinaryNode binaryNode) { 1.77 ensureTypeNotUnknown(binaryNode.lhs()); 1.78 ensureTypeNotUnknown(binaryNode.rhs()); 1.79 - 1.80 + Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 1.81 + ensureSymbol(widest, binaryNode.lhs()); 1.82 + ensureSymbol(widest, binaryNode.rhs()); 1.83 return end(ensureSymbol(Type.BOOLEAN, binaryNode)); 1.84 } 1.85 1.86 @@ -1630,7 +1625,7 @@ 1.87 if (!Type.areEquivalent(from, to) && Type.widest(from, to) == to) { 1.88 LOG.fine("Had to post pass widen '", node, "' ", Debug.id(node), " from ", node.getType(), " to ", to); 1.89 Symbol symbol = node.getSymbol(); 1.90 - if(symbol.isShared() && symbol.wouldChangeType(to)) { 1.91 + if (symbol.isShared() && symbol.wouldChangeType(to)) { 1.92 symbol = temporarySymbols.getTypedTemporarySymbol(to); 1.93 } 1.94 newType(symbol, to); 1.95 @@ -1646,40 +1641,105 @@ 1.96 return !node.isLazy(); 1.97 } 1.98 1.99 - /** 1.100 - * Eg. 1.101 - * 1.102 - * var d = 17; 1.103 - * var e; 1.104 - * e = d; //initially typed as int for node type, should retype as double 1.105 - * e = object; 1.106 - * 1.107 - * var d = 17; 1.108 - * var e; 1.109 - * e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric 1.110 - * e = object; 1.111 - * 1.112 - */ 1.113 + // 1.114 + // Eg. 1.115 + // 1.116 + // var d = 17; 1.117 + // var e; 1.118 + // e = d; //initially typed as int for node type, should retype as double 1.119 + // e = object; 1.120 + // 1.121 + // var d = 17; 1.122 + // var e; 1.123 + // e -= d; //initially type number, should number remain with a final conversion supplied by Store. ugly, but the computation result of the sub is numeric 1.124 + // e = object; 1.125 + // 1.126 @SuppressWarnings("fallthrough") 1.127 @Override 1.128 public Node leaveBinaryNode(final BinaryNode binaryNode) { 1.129 final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 1.130 BinaryNode newBinaryNode = binaryNode; 1.131 - switch (binaryNode.tokenType()) { 1.132 - default: 1.133 - if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) { 1.134 + 1.135 + if (isAdd(binaryNode)) { 1.136 + newBinaryNode = (BinaryNode)widen(newBinaryNode, widest); 1.137 + if (newBinaryNode.getType().isObject() && !isAddString(newBinaryNode)) { 1.138 + return new RuntimeNode(newBinaryNode, Request.ADD); 1.139 + } 1.140 + } else if (binaryNode.isComparison()) { 1.141 + final Expression lhs = newBinaryNode.lhs(); 1.142 + final Expression rhs = newBinaryNode.rhs(); 1.143 + 1.144 + Type cmpWidest = Type.widest(lhs.getType(), rhs.getType()); 1.145 + 1.146 + boolean newRuntimeNode = false, finalized = false; 1.147 + switch (newBinaryNode.tokenType()) { 1.148 + case EQ_STRICT: 1.149 + case NE_STRICT: 1.150 + if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) { 1.151 + newRuntimeNode = true; 1.152 + cmpWidest = Type.OBJECT; 1.153 + finalized = true; 1.154 + } 1.155 + //fallthru 1.156 + default: 1.157 + if (newRuntimeNode || cmpWidest.isObject()) { 1.158 + return new RuntimeNode(newBinaryNode, Request.requestFor(binaryNode)).setIsFinal(finalized); 1.159 + } 1.160 break; 1.161 } 1.162 + 1.163 + return newBinaryNode; 1.164 + } else { 1.165 + if (!binaryNode.isAssignment() || binaryNode.isSelfModifying()) { 1.166 + return newBinaryNode; 1.167 + } 1.168 + checkThisAssignment(binaryNode); 1.169 newBinaryNode = newBinaryNode.setLHS(widen(newBinaryNode.lhs(), widest)); 1.170 - case ADD: 1.171 newBinaryNode = (BinaryNode)widen(newBinaryNode, widest); 1.172 } 1.173 + 1.174 return newBinaryNode; 1.175 + 1.176 + } 1.177 + 1.178 + private boolean isAdd(final Node node) { 1.179 + return node.isTokenType(TokenType.ADD); 1.180 + } 1.181 + 1.182 + /** 1.183 + * Determine if the outcome of + operator is a string. 1.184 + * 1.185 + * @param node Node to test. 1.186 + * @return true if a string result. 1.187 + */ 1.188 + private boolean isAddString(final Node node) { 1.189 + if (node instanceof BinaryNode && isAdd(node)) { 1.190 + final BinaryNode binaryNode = (BinaryNode)node; 1.191 + final Node lhs = binaryNode.lhs(); 1.192 + final Node rhs = binaryNode.rhs(); 1.193 + 1.194 + return isAddString(lhs) || isAddString(rhs); 1.195 + } 1.196 + 1.197 + return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString(); 1.198 + } 1.199 + 1.200 + private void checkThisAssignment(final BinaryNode binaryNode) { 1.201 + if (binaryNode.isAssignment()) { 1.202 + if (binaryNode.lhs() instanceof AccessNode) { 1.203 + final AccessNode accessNode = (AccessNode) binaryNode.lhs(); 1.204 + 1.205 + if (accessNode.getBase().getSymbol().isThis()) { 1.206 + lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName()); 1.207 + } 1.208 + } 1.209 + } 1.210 } 1.211 }); 1.212 lc.replace(currentFunctionNode, newFunctionNode); 1.213 currentFunctionNode = newFunctionNode; 1.214 } while (!changed.isEmpty()); 1.215 + 1.216 return currentFunctionNode; 1.217 } 1.218 1.219 @@ -1692,7 +1752,6 @@ 1.220 final Expression lhs = binaryNode.lhs(); 1.221 1.222 newType(lhs.getSymbol(), destType); //may not narrow if dest is already wider than destType 1.223 -// ensureSymbol(destType, binaryNode); //for OP= nodes, the node can carry a narrower types than its lhs rhs. This is perfectly fine 1.224 1.225 return end(ensureSymbol(destType, binaryNode)); 1.226 }
2.1 --- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Wed Oct 09 14:50:39 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Wed Oct 09 17:53:22 2013 +0200 2.3 @@ -56,10 +56,6 @@ 2.4 branchOptimizer(node, label, state); 2.5 } 2.6 2.7 - private void load(final Expression node) { 2.8 - codegen.load(node); 2.9 - } 2.10 - 2.11 private void branchOptimizer(final UnaryNode unaryNode, final Label label, final boolean state) { 2.12 final Expression rhs = unaryNode.rhs(); 2.13 2.14 @@ -67,18 +63,16 @@ 2.15 case NOT: 2.16 branchOptimizer(rhs, label, !state); 2.17 return; 2.18 - case CONVERT: 2.19 + default: 2.20 if (unaryNode.getType().isBoolean()) { 2.21 branchOptimizer(rhs, label, state); 2.22 return; 2.23 } 2.24 break; 2.25 - default: 2.26 - break; 2.27 } 2.28 2.29 // convert to boolean 2.30 - load(unaryNode); 2.31 + codegen.load(unaryNode); 2.32 method.convert(Type.BOOLEAN); 2.33 if (state) { 2.34 method.ifne(label); 2.35 @@ -90,6 +84,7 @@ 2.36 private void branchOptimizer(final BinaryNode binaryNode, final Label label, final boolean state) { 2.37 final Expression lhs = binaryNode.lhs(); 2.38 final Expression rhs = binaryNode.rhs(); 2.39 + Type widest = Type.widest(lhs.getType(), rhs.getType()); 2.40 2.41 switch (binaryNode.tokenType()) { 2.42 case AND: 2.43 @@ -118,45 +113,33 @@ 2.44 2.45 case EQ: 2.46 case EQ_STRICT: 2.47 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); 2.48 - load(lhs); 2.49 - load(rhs); 2.50 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.51 method.conditionalJump(state ? EQ : NE, true, label); 2.52 return; 2.53 2.54 case NE: 2.55 case NE_STRICT: 2.56 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); 2.57 - load(lhs); 2.58 - load(rhs); 2.59 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.60 method.conditionalJump(state ? NE : EQ, true, label); 2.61 return; 2.62 2.63 case GE: 2.64 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); 2.65 - load(lhs); 2.66 - load(rhs); 2.67 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.68 method.conditionalJump(state ? GE : LT, !state, label); 2.69 return; 2.70 2.71 case GT: 2.72 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); 2.73 - load(lhs); 2.74 - load(rhs); 2.75 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.76 method.conditionalJump(state ? GT : LE, !state, label); 2.77 return; 2.78 2.79 case LE: 2.80 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol(); 2.81 - load(lhs); 2.82 - load(rhs); 2.83 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.84 method.conditionalJump(state ? LE : GT, state, label); 2.85 return; 2.86 2.87 case LT: 2.88 - assert rhs.getType().isEquivalentTo(lhs.getType()) : "type mismatch: " + lhs.getSymbol() + " to " + rhs.getSymbol() + " in " + binaryNode; 2.89 - load(lhs); 2.90 - load(rhs); 2.91 + codegen.loadBinaryOperands(lhs, rhs, widest); 2.92 method.conditionalJump(state ? LT : GE, state, label); 2.93 return; 2.94 2.95 @@ -164,7 +147,7 @@ 2.96 break; 2.97 } 2.98 2.99 - load(binaryNode); 2.100 + codegen.load(binaryNode); 2.101 method.convert(Type.BOOLEAN); 2.102 if (state) { 2.103 method.ifne(label); 2.104 @@ -187,7 +170,7 @@ 2.105 } 2.106 } 2.107 2.108 - load(node); 2.109 + codegen.load(node); 2.110 method.convert(Type.BOOLEAN); 2.111 if (state) { 2.112 method.ifne(label);
3.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 09 14:50:39 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 09 17:53:22 2013 +0200 3.3 @@ -43,7 +43,6 @@ 3.4 import static jdk.nashorn.internal.codegen.CompilerConstants.interfaceCallNoLookup; 3.5 import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor; 3.6 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; 3.7 -import static jdk.nashorn.internal.codegen.CompilerConstants.staticField; 3.8 import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor; 3.9 import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup; 3.10 import static jdk.nashorn.internal.ir.Symbol.IS_INTERNAL; 3.11 @@ -60,7 +59,6 @@ 3.12 import java.util.Iterator; 3.13 import java.util.LinkedList; 3.14 import java.util.List; 3.15 -import java.util.Locale; 3.16 import java.util.Set; 3.17 import java.util.TreeMap; 3.18 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 3.19 @@ -111,7 +109,6 @@ 3.20 import jdk.nashorn.internal.ir.VarNode; 3.21 import jdk.nashorn.internal.ir.WhileNode; 3.22 import jdk.nashorn.internal.ir.WithNode; 3.23 -import jdk.nashorn.internal.ir.debug.ASTWriter; 3.24 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 3.25 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 3.26 import jdk.nashorn.internal.objects.Global; 3.27 @@ -217,12 +214,12 @@ 3.28 * @param identNode an identity node to load 3.29 * @return the method generator used 3.30 */ 3.31 - private MethodEmitter loadIdent(final IdentNode identNode) { 3.32 + private MethodEmitter loadIdent(final IdentNode identNode, final Type type) { 3.33 final Symbol symbol = identNode.getSymbol(); 3.34 3.35 if (!symbol.isScope()) { 3.36 assert symbol.hasSlot() || symbol.isParam(); 3.37 - return method.load(symbol); 3.38 + return method.load(symbol).convert(type); 3.39 } 3.40 3.41 final String name = symbol.getName(); 3.42 @@ -243,11 +240,11 @@ 3.43 if (isFastScope(symbol)) { 3.44 // Only generate shared scope getter for fast-scope symbols so we know we can dial in correct scope. 3.45 if (symbol.getUseCount() > SharedScopeCall.FAST_SCOPE_GET_THRESHOLD) { 3.46 - return loadSharedScopeVar(identNode.getType(), symbol, flags); 3.47 + return loadSharedScopeVar(type, symbol, flags); 3.48 } 3.49 - return loadFastScopeVar(identNode.getType(), symbol, flags, identNode.isFunction()); 3.50 + return loadFastScopeVar(type, symbol, flags, identNode.isFunction()); 3.51 } 3.52 - return method.dynamicGet(identNode.getType(), identNode.getName(), flags, identNode.isFunction()); 3.53 + return method.dynamicGet(type, identNode.getName(), flags, identNode.isFunction()); 3.54 } 3.55 } 3.56 3.57 @@ -313,9 +310,9 @@ 3.58 return method.dynamicGet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE, isMethod); 3.59 } 3.60 3.61 - private MethodEmitter storeFastScopeVar(final Type valueType, final Symbol symbol, final int flags) { 3.62 + private MethodEmitter storeFastScopeVar(final Symbol symbol, final int flags) { 3.63 loadFastScopeProto(symbol, true); 3.64 - method.dynamicSet(valueType, symbol.getName(), flags | CALLSITE_FAST_SCOPE); 3.65 + method.dynamicSet(symbol.getName(), flags | CALLSITE_FAST_SCOPE); 3.66 return method; 3.67 } 3.68 3.69 @@ -359,14 +356,61 @@ 3.70 * @return the method emitter used 3.71 */ 3.72 MethodEmitter load(final Expression node) { 3.73 - return load(node, false); 3.74 + return load(node, node.hasType() ? node.getType() : null, false); 3.75 } 3.76 3.77 - private MethodEmitter load(final Expression node, final boolean baseAlreadyOnStack) { 3.78 + private static boolean safeLiteral(final Expression rhs) { 3.79 + return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode); 3.80 + } 3.81 + 3.82 + MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) { 3.83 + return loadBinaryOperands(lhs, rhs, type, false); 3.84 + } 3.85 + 3.86 + private MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type, final boolean baseAlreadyOnStack) { 3.87 + // ECMAScript 5.1 specification (sections 11.5-11.11 and 11.13) prescribes that when evaluating a binary 3.88 + // expression "LEFT op RIGHT", the order of operations must be: LOAD LEFT, LOAD RIGHT, CONVERT LEFT, CONVERT 3.89 + // RIGHT, EXECUTE OP. Unfortunately, doing it in this order defeats potential optimizations that arise when we 3.90 + // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its 3.91 + // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when 3.92 + // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT. 3.93 + // Basically, if we know that either LEFT is not an object, or RIGHT is a constant literal, then we can do the 3.94 + // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly 3.95 + // separate operations to preserve specification semantics. 3.96 + final Type lhsType = lhs.getType(); 3.97 + if (lhsType.isObject() && !safeLiteral(rhs)) { 3.98 + // Can't reorder. Load and convert separately. 3.99 + load(lhs, lhsType, baseAlreadyOnStack); 3.100 + load(rhs, rhs.getType(), false); 3.101 + // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op 3.102 + if (!lhsType.isEquivalentTo(type)) { 3.103 + method.swap(); 3.104 + method.convert(type); 3.105 + method.swap(); 3.106 + } 3.107 + method.convert(type); 3.108 + } else { 3.109 + // Can reorder. Combine load and convert into single operations. 3.110 + load(lhs, type, baseAlreadyOnStack); 3.111 + load(rhs, type, false); 3.112 + } 3.113 + 3.114 + return method; 3.115 + } 3.116 + 3.117 + MethodEmitter loadBinaryOperands(final BinaryNode node) { 3.118 + return loadBinaryOperands(node.lhs(), node.rhs(), node.getType(), false); 3.119 + } 3.120 + 3.121 + private MethodEmitter load(final Expression node, final Type type) { 3.122 + return load(node, type, false); 3.123 + } 3.124 + 3.125 + private MethodEmitter load(final Expression node, final Type type, final boolean baseAlreadyOnStack) { 3.126 final Symbol symbol = node.getSymbol(); 3.127 3.128 // If we lack symbols, we just generate what we see. 3.129 - if (symbol == null) { 3.130 + if (symbol == null || type == null) { 3.131 node.accept(this); 3.132 return method; 3.133 } 3.134 @@ -378,10 +422,10 @@ 3.135 */ 3.136 final CodeGenerator codegen = this; 3.137 3.138 - node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 3.139 + node.accept(new NodeVisitor<LexicalContext>(lc) { 3.140 @Override 3.141 public boolean enterIdentNode(final IdentNode identNode) { 3.142 - loadIdent(identNode); 3.143 + loadIdent(identNode, type); 3.144 return false; 3.145 } 3.146 3.147 @@ -391,7 +435,7 @@ 3.148 load(accessNode.getBase()).convert(Type.OBJECT); 3.149 } 3.150 assert method.peekType().isObject(); 3.151 - method.dynamicGet(node.getType(), accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); 3.152 + method.dynamicGet(type, accessNode.getProperty().getName(), getCallSiteFlags(), accessNode.isFunction()); 3.153 return false; 3.154 } 3.155 3.156 @@ -401,7 +445,7 @@ 3.157 load(indexNode.getBase()).convert(Type.OBJECT); 3.158 load(indexNode.getIndex()); 3.159 } 3.160 - method.dynamicGetIndex(node.getType(), getCallSiteFlags(), indexNode.isFunction()); 3.161 + method.dynamicGetIndex(type, getCallSiteFlags(), indexNode.isFunction()); 3.162 return false; 3.163 } 3.164 3.165 @@ -410,13 +454,29 @@ 3.166 // function nodes will always leave a constructed function object on stack, no need to load the symbol 3.167 // separately as in enterDefault() 3.168 functionNode.accept(codegen); 3.169 + method.convert(type); 3.170 return false; 3.171 } 3.172 3.173 @Override 3.174 + public boolean enterCallNode(CallNode callNode) { 3.175 + return codegen.enterCallNode(callNode, type); 3.176 + } 3.177 + 3.178 + @Override 3.179 + public boolean enterLiteralNode(LiteralNode<?> literalNode) { 3.180 + return codegen.enterLiteralNode(literalNode, type); 3.181 + } 3.182 + 3.183 + @Override 3.184 public boolean enterDefault(final Node otherNode) { 3.185 + final Node currentDiscard = codegen.lc.getCurrentDiscard(); 3.186 otherNode.accept(codegen); // generate code for whatever we are looking at. 3.187 - method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) 3.188 + if(currentDiscard != otherNode) { 3.189 + method.load(symbol); // load the final symbol to the stack (or nop if no slot, then result is already there) 3.190 + assert method.peekType() != null; 3.191 + method.convert(type); 3.192 + } 3.193 return false; 3.194 } 3.195 }); 3.196 @@ -583,15 +643,19 @@ 3.197 return argCount; 3.198 } 3.199 3.200 + 3.201 @Override 3.202 public boolean enterCallNode(final CallNode callNode) { 3.203 + return enterCallNode(callNode, callNode.getType()); 3.204 + } 3.205 + 3.206 + private boolean enterCallNode(final CallNode callNode, final Type callNodeType) { 3.207 lineNumber(callNode.getLineNumber()); 3.208 3.209 final List<Expression> args = callNode.getArgs(); 3.210 final Expression function = callNode.getFunction(); 3.211 final Block currentBlock = lc.getCurrentBlock(); 3.212 final CodeGeneratorLexicalContext codegenLexicalContext = lc; 3.213 - final Type callNodeType = callNode.getType(); 3.214 3.215 function.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 3.216 3.217 @@ -612,16 +676,14 @@ 3.218 } 3.219 3.220 private void scopeCall(final IdentNode node, final int flags) { 3.221 - load(node); 3.222 - method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 3.223 + load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3 3.224 // ScriptFunction will see CALLSITE_SCOPE and will bind scope accordingly. 3.225 method.loadNull(); //the 'this' 3.226 method.dynamicCall(callNodeType, 2 + loadArgs(args), flags); 3.227 } 3.228 3.229 private void evalCall(final IdentNode node, final int flags) { 3.230 - load(node); 3.231 - method.convert(Type.OBJECT); // foo() makes no sense if foo == 3 3.232 + load(node, Type.OBJECT); // Type.OBJECT as foo() makes no sense if foo == 3 3.233 3.234 final Label not_eval = new Label("not_eval"); 3.235 final Label eval_done = new Label("eval_done"); 3.236 @@ -638,8 +700,7 @@ 3.237 3.238 final CallNode.EvalArgs evalArgs = callNode.getEvalArgs(); 3.239 // load evaluated code 3.240 - load(evalArgs.getCode()); 3.241 - method.convert(Type.OBJECT); 3.242 + load(evalArgs.getCode(), Type.OBJECT); 3.243 // special/extra 'eval' arguments 3.244 load(evalArgs.getThis()); 3.245 method.load(evalArgs.getLocation()); 3.246 @@ -690,13 +751,11 @@ 3.247 3.248 @Override 3.249 public boolean enterAccessNode(final AccessNode node) { 3.250 - load(node.getBase()); 3.251 - method.convert(Type.OBJECT); 3.252 + load(node.getBase(), Type.OBJECT); 3.253 method.dup(); 3.254 method.dynamicGet(node.getType(), node.getProperty().getName(), getCallSiteFlags(), true); 3.255 method.swap(); 3.256 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); 3.257 - assert method.peekType().equals(callNodeType); 3.258 3.259 return false; 3.260 } 3.261 @@ -727,18 +786,17 @@ 3.262 3.263 @Override 3.264 public boolean enterIndexNode(final IndexNode node) { 3.265 - load(node.getBase()); 3.266 - method.convert(Type.OBJECT); 3.267 + load(node.getBase(), Type.OBJECT); 3.268 method.dup(); 3.269 - load(node.getIndex()); 3.270 final Type indexType = node.getIndex().getType(); 3.271 if (indexType.isObject() || indexType.isBoolean()) { 3.272 - method.convert(Type.OBJECT); //TODO 3.273 + load(node.getIndex(), Type.OBJECT); //TODO 3.274 + } else { 3.275 + load(node.getIndex()); 3.276 } 3.277 method.dynamicGetIndex(node.getType(), getCallSiteFlags(), true); 3.278 method.swap(); 3.279 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags()); 3.280 - assert method.peekType().equals(callNode.getType()); 3.281 3.282 return false; 3.283 } 3.284 @@ -746,11 +804,9 @@ 3.285 @Override 3.286 protected boolean enterDefault(final Node node) { 3.287 // Load up function. 3.288 - load(function); 3.289 - method.convert(Type.OBJECT); //TODO, e.g. booleans can be used as functions 3.290 + load(function, Type.OBJECT); //TODO, e.g. booleans can be used as functions 3.291 method.loadNull(); // ScriptFunction will figure out the correct this when it sees CALLSITE_SCOPE 3.292 method.dynamicCall(callNodeType, 2 + loadArgs(args), getCallSiteFlags() | CALLSITE_SCOPE); 3.293 - assert method.peekType().equals(callNode.getType()); 3.294 3.295 return false; 3.296 } 3.297 @@ -853,8 +909,7 @@ 3.298 3.299 final Expression init = forNode.getInit(); 3.300 3.301 - load(modify); 3.302 - assert modify.getType().isObject(); 3.303 + load(modify, Type.OBJECT); 3.304 method.invoke(forNode.isForEach() ? ScriptRuntime.TO_VALUE_ITERATOR : ScriptRuntime.TO_PROPERTY_ITERATOR); 3.305 method.store(iter); 3.306 method._goto(forNode.getContinueLabel()); 3.307 @@ -1203,8 +1258,7 @@ 3.308 if (element == null) { 3.309 method.loadEmpty(elementType); 3.310 } else { 3.311 - assert elementType.isEquivalentTo(element.getType()) : "array element type doesn't match array type"; 3.312 - load(element); 3.313 + load(element, elementType); 3.314 } 3.315 3.316 method.arraystore(); 3.317 @@ -1274,7 +1328,7 @@ 3.318 } 3.319 3.320 // literal values 3.321 - private MethodEmitter load(final LiteralNode<?> node) { 3.322 + private MethodEmitter loadLiteral(final LiteralNode<?> node, final Type type) { 3.323 final Object value = node.getValue(); 3.324 3.325 if (value == null) { 3.326 @@ -1294,15 +1348,26 @@ 3.327 } else if (value instanceof Boolean) { 3.328 method.load((Boolean)value); 3.329 } else if (value instanceof Integer) { 3.330 - method.load((Integer)value); 3.331 + if(type.isEquivalentTo(Type.NUMBER)) { 3.332 + method.load(((Integer)value).doubleValue()); 3.333 + } else if(type.isEquivalentTo(Type.LONG)) { 3.334 + method.load(((Integer)value).longValue()); 3.335 + } else { 3.336 + method.load((Integer)value); 3.337 + } 3.338 } else if (value instanceof Long) { 3.339 - method.load((Long)value); 3.340 + if(type.isEquivalentTo(Type.NUMBER)) { 3.341 + method.load(((Long)value).doubleValue()); 3.342 + } else { 3.343 + method.load((Long)value); 3.344 + } 3.345 } else if (value instanceof Double) { 3.346 method.load((Double)value); 3.347 } else if (node instanceof ArrayLiteralNode) { 3.348 - final ArrayType type = (ArrayType)node.getType(); 3.349 - loadArray((ArrayLiteralNode)node, type); 3.350 - globalAllocateArray(type); 3.351 + final ArrayLiteralNode arrayLiteral = (ArrayLiteralNode)node; 3.352 + final ArrayType atype = arrayLiteral.getArrayType(); 3.353 + loadArray(arrayLiteral, atype); 3.354 + globalAllocateArray(atype); 3.355 } else { 3.356 assert false : "Unknown literal for " + node.getClass() + " " + value.getClass() + " " + value; 3.357 } 3.358 @@ -1346,8 +1411,12 @@ 3.359 3.360 @Override 3.361 public boolean enterLiteralNode(final LiteralNode<?> literalNode) { 3.362 + return enterLiteralNode(literalNode, literalNode.getType()); 3.363 + } 3.364 + 3.365 + private boolean enterLiteralNode(final LiteralNode<?> literalNode, final Type type) { 3.366 assert literalNode.getSymbol() != null : literalNode + " has no symbol"; 3.367 - load(literalNode).store(literalNode.getSymbol()); 3.368 + loadLiteral(literalNode, type).convert(type).store(literalNode.getSymbol()); 3.369 return false; 3.370 } 3.371 3.372 @@ -1622,10 +1691,8 @@ 3.373 return enterCmp(lhs, rhs, Condition.GT, type, symbol); 3.374 case ADD: 3.375 Type widest = Type.widest(lhs.getType(), rhs.getType()); 3.376 - load(lhs); 3.377 - method.convert(widest); 3.378 - load(rhs); 3.379 - method.convert(widest); 3.380 + load(lhs, widest); 3.381 + load(rhs, widest); 3.382 method.add(); 3.383 method.convert(type); 3.384 method.store(symbol); 3.385 @@ -1638,15 +1705,15 @@ 3.386 } 3.387 3.388 if (nullCheck(runtimeNode, args, new FunctionSignature(false, false, runtimeNode.getType(), args).toString())) { 3.389 - return false; 3.390 + return false; 3.391 } 3.392 3.393 if (!runtimeNode.isFinal() && specializationCheck(runtimeNode.getRequest(), runtimeNode, args)) { 3.394 - return false; 3.395 + return false; 3.396 } 3.397 3.398 for (final Expression arg : args) { 3.399 - load(arg).convert(Type.OBJECT); //TODO this should not be necessary below Lower 3.400 + load(arg).convert(Type.OBJECT); 3.401 } 3.402 3.403 method.invokestatic( 3.404 @@ -1903,24 +1970,15 @@ 3.405 method.lookupswitch(defaultLabel, ints, labels); 3.406 } 3.407 } else { 3.408 - load(expression); 3.409 - 3.410 - if (expression.getType().isInteger()) { 3.411 - method.convert(Type.NUMBER).dup(); 3.412 - method.store(tag); 3.413 - method.conditionalJump(Condition.NE, true, defaultLabel); 3.414 - } else { 3.415 - assert tag.getSymbolType().isObject(); 3.416 - method.convert(Type.OBJECT); //e.g. 1 literal pushed and tag is object 3.417 - method.store(tag); 3.418 - } 3.419 + load(expression, Type.OBJECT); 3.420 + method.store(tag); 3.421 3.422 for (final CaseNode caseNode : cases) { 3.423 final Expression test = caseNode.getTest(); 3.424 3.425 if (test != null) { 3.426 method.load(tag); 3.427 - load(test); 3.428 + load(test, Type.OBJECT); 3.429 method.invoke(ScriptRuntime.EQ_STRICT); 3.430 method.ifne(caseNode.getEntry()); 3.431 } 3.432 @@ -1961,8 +2019,7 @@ 3.433 final int line = throwNode.getLineNumber(); 3.434 final int column = source.getColumn(position); 3.435 3.436 - load(expression); 3.437 - assert expression.getType().isObject(); 3.438 + load(expression, Type.OBJECT); 3.439 3.440 method.load(source.getName()); 3.441 method.load(line); 3.442 @@ -2087,29 +2144,28 @@ 3.443 3.444 lineNumber(varNode); 3.445 3.446 - final Symbol varSymbol = varNode.getName().getSymbol(); 3.447 - assert varSymbol != null : "variable node " + varNode + " requires a name with a symbol"; 3.448 + final IdentNode identNode = varNode.getName(); 3.449 + final Symbol identSymbol = identNode.getSymbol(); 3.450 + assert identSymbol != null : "variable node " + varNode + " requires a name with a symbol"; 3.451 3.452 assert method != null; 3.453 3.454 - final boolean needsScope = varSymbol.isScope(); 3.455 + final boolean needsScope = identSymbol.isScope(); 3.456 if (needsScope) { 3.457 method.loadCompilerConstant(SCOPE); 3.458 } 3.459 - load(init); 3.460 3.461 if (needsScope) { 3.462 + load(init); 3.463 int flags = CALLSITE_SCOPE | getCallSiteFlags(); 3.464 - final IdentNode identNode = varNode.getName(); 3.465 - final Type type = identNode.getType(); 3.466 - if (isFastScope(varSymbol)) { 3.467 - storeFastScopeVar(type, varSymbol, flags); 3.468 + if (isFastScope(identSymbol)) { 3.469 + storeFastScopeVar(identSymbol, flags); 3.470 } else { 3.471 - method.dynamicSet(type, identNode.getName(), flags); 3.472 + method.dynamicSet(identNode.getName(), flags); 3.473 } 3.474 } else { 3.475 - method.convert(varNode.getName().getType()); // aw: convert moved here 3.476 - method.store(varSymbol); 3.477 + load(init, identNode.getType()); 3.478 + method.store(identSymbol); 3.479 } 3.480 3.481 return false; 3.482 @@ -2168,8 +2224,7 @@ 3.483 tryLabel = null; 3.484 } 3.485 3.486 - load(expression); 3.487 - assert expression.getType().isObject() : "with expression needs to be object: " + expression; 3.488 + load(expression, Type.OBJECT); 3.489 3.490 if (hasScope) { 3.491 // Construct a WithObject if we have a scope 3.492 @@ -2211,54 +2266,15 @@ 3.493 3.494 @Override 3.495 public boolean enterADD(final UnaryNode unaryNode) { 3.496 - load(unaryNode.rhs()); 3.497 - assert unaryNode.rhs().getType().isNumber() : unaryNode.rhs().getType() + " "+ unaryNode.getSymbol(); 3.498 + load(unaryNode.rhs(), unaryNode.getType()); 3.499 + assert unaryNode.getType().isNumeric(); 3.500 method.store(unaryNode.getSymbol()); 3.501 - 3.502 return false; 3.503 } 3.504 3.505 @Override 3.506 public boolean enterBIT_NOT(final UnaryNode unaryNode) { 3.507 - load(unaryNode.rhs()).convert(Type.INT).load(-1).xor().store(unaryNode.getSymbol()); 3.508 - return false; 3.509 - } 3.510 - 3.511 - // do this better with convert calls to method. TODO 3.512 - @Override 3.513 - public boolean enterCONVERT(final UnaryNode unaryNode) { 3.514 - final Expression rhs = unaryNode.rhs(); 3.515 - final Type to = unaryNode.getType(); 3.516 - 3.517 - if (to.isObject() && rhs instanceof LiteralNode) { 3.518 - final LiteralNode<?> literalNode = (LiteralNode<?>)rhs; 3.519 - final Object value = literalNode.getValue(); 3.520 - 3.521 - if (value instanceof Number) { 3.522 - assert !to.isArray() : "type hygiene - cannot convert number to array: (" + to.getTypeClass().getSimpleName() + ')' + value; 3.523 - if (value instanceof Integer) { 3.524 - method.load((Integer)value); 3.525 - } else if (value instanceof Long) { 3.526 - method.load((Long)value); 3.527 - } else if (value instanceof Double) { 3.528 - method.load((Double)value); 3.529 - } else { 3.530 - assert false; 3.531 - } 3.532 - method.convert(Type.OBJECT); 3.533 - } else if (value instanceof Boolean) { 3.534 - method.getField(staticField(Boolean.class, value.toString().toUpperCase(Locale.ENGLISH), Boolean.class)); 3.535 - } else { 3.536 - load(rhs); 3.537 - method.convert(unaryNode.getType()); 3.538 - } 3.539 - } else { 3.540 - load(rhs); 3.541 - method.convert(unaryNode.getType()); 3.542 - } 3.543 - 3.544 - method.store(unaryNode.getSymbol()); 3.545 - 3.546 + load(unaryNode.rhs(), Type.INT).load(-1).xor().store(unaryNode.getSymbol()); 3.547 return false; 3.548 } 3.549 3.550 @@ -2276,9 +2292,7 @@ 3.551 3.552 @Override 3.553 protected void evaluate() { 3.554 - load(rhs, true); 3.555 - 3.556 - method.convert(type); 3.557 + load(rhs, type, true); 3.558 if (!isPostfix) { 3.559 if (type.isInteger()) { 3.560 method.load(isIncrement ? 1 : -1); 3.561 @@ -2344,12 +2358,11 @@ 3.562 public boolean enterNOT(final UnaryNode unaryNode) { 3.563 final Expression rhs = unaryNode.rhs(); 3.564 3.565 - load(rhs); 3.566 + load(rhs, Type.BOOLEAN); 3.567 3.568 final Label trueLabel = new Label("true"); 3.569 final Label afterLabel = new Label("after"); 3.570 3.571 - method.convert(Type.BOOLEAN); 3.572 method.ifne(trueLabel); 3.573 method.load(true); 3.574 method._goto(afterLabel); 3.575 @@ -2363,8 +2376,8 @@ 3.576 3.577 @Override 3.578 public boolean enterSUB(final UnaryNode unaryNode) { 3.579 - load(unaryNode.rhs()).neg().store(unaryNode.getSymbol()); 3.580 - 3.581 + assert unaryNode.getType().isNumeric(); 3.582 + load(unaryNode.rhs()).convert(unaryNode.getType()).neg().store(unaryNode.getSymbol()); 3.583 return false; 3.584 } 3.585 3.586 @@ -2377,9 +2390,7 @@ 3.587 } 3.588 3.589 private void enterNumericAdd(final Expression lhs, final Expression rhs, final Type type, final Symbol symbol) { 3.590 - assert lhs.getType().equals(rhs.getType()) && lhs.getType().equals(type) : lhs.getType() + " != " + rhs.getType() + " != " + type + " " + new ASTWriter(lhs) + " " + new ASTWriter(rhs); 3.591 - load(lhs); 3.592 - load(rhs); 3.593 + loadBinaryOperands(lhs, rhs, type); 3.594 method.add(); //if the symbol is optimistic, it always needs to be written, not on the stack? 3.595 method.store(symbol); 3.596 } 3.597 @@ -2393,8 +2404,7 @@ 3.598 if (type.isNumeric()) { 3.599 enterNumericAdd(lhs, rhs, type, binaryNode.getSymbol()); 3.600 } else { 3.601 - load(lhs).convert(Type.OBJECT); 3.602 - load(rhs).convert(Type.OBJECT); 3.603 + loadBinaryOperands(binaryNode); 3.604 method.add(); 3.605 method.store(binaryNode.getSymbol()); 3.606 } 3.607 @@ -2439,13 +2449,16 @@ 3.608 3.609 if (!lhsType.isEquivalentTo(rhsType)) { 3.610 //this is OK if scoped, only locals are wrong 3.611 - assert !(lhs instanceof IdentNode) || lhs.getSymbol().isScope() : new ASTWriter(binaryNode); 3.612 } 3.613 3.614 new Store<BinaryNode>(binaryNode, lhs) { 3.615 @Override 3.616 protected void evaluate() { 3.617 - load(rhs); 3.618 + if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) { 3.619 + load(rhs, lhsType); 3.620 + } else { 3.621 + load(rhs); 3.622 + } 3.623 } 3.624 }.store(); 3.625 3.626 @@ -2484,8 +2497,7 @@ 3.627 3.628 @Override 3.629 protected void evaluate() { 3.630 - load(assignNode.lhs(), true).convert(opType); 3.631 - load(assignNode.rhs()).convert(opType); 3.632 + loadBinaryOperands(assignNode.lhs(), assignNode.rhs(), opType, true); 3.633 op(); 3.634 method.convert(assignNode.getType()); 3.635 } 3.636 @@ -2656,8 +2668,7 @@ 3.637 protected abstract void op(); 3.638 3.639 protected void evaluate(final BinaryNode node) { 3.640 - load(node.lhs()); 3.641 - load(node.rhs()); 3.642 + loadBinaryOperands(node); 3.643 op(); 3.644 method.store(node.getSymbol()); 3.645 } 3.646 @@ -2739,11 +2750,7 @@ 3.647 final Type widest = Type.widest(lhsType, rhsType); 3.648 assert widest.isNumeric() || widest.isBoolean() : widest; 3.649 3.650 - load(lhs); 3.651 - method.convert(widest); 3.652 - load(rhs); 3.653 - method.convert(widest); 3.654 - 3.655 + loadBinaryOperands(lhs, rhs, widest); 3.656 final Label trueLabel = new Label("trueLabel"); 3.657 final Label afterLabel = new Label("skip"); 3.658 3.659 @@ -2862,6 +2869,12 @@ 3.660 public boolean enterSHR(final BinaryNode binaryNode) { 3.661 new BinaryArith() { 3.662 @Override 3.663 + protected void evaluate(final BinaryNode node) { 3.664 + loadBinaryOperands(node.lhs(), node.rhs(), Type.INT); 3.665 + op(); 3.666 + method.store(node.getSymbol()); 3.667 + } 3.668 + @Override 3.669 protected void op() { 3.670 method.shr(); 3.671 method.convert(Type.LONG).load(JSType.MAX_UINT).and(); 3.672 @@ -2898,21 +2911,17 @@ 3.673 widest = Type.OBJECT; 3.674 } 3.675 3.676 - load(test); 3.677 - assert test.getType().isBoolean() : "lhs in ternary must be boolean"; 3.678 - 3.679 + load(test, Type.BOOLEAN); 3.680 // we still keep the conversion here as the AccessSpecializer can have separated the types, e.g. var y = x ? x=55 : 17 3.681 // will left as (Object)x=55 : (Object)17 by Lower. Then the first term can be {I}x=55 of type int, which breaks the 3.682 // symmetry for the temporary slot for this TernaryNode. This is evidence that we assign types and explicit conversions 3.683 // too early, or Apply the AccessSpecializer too late. We are mostly probably looking for a separate type pass to 3.684 // do this property. Then we never need any conversions in CodeGenerator 3.685 method.ifeq(falseLabel); 3.686 - load(trueExpr); 3.687 - method.convert(widest); 3.688 + load(trueExpr, widest); 3.689 method._goto(exitLabel); 3.690 method.label(falseLabel); 3.691 - load(falseExpr); 3.692 - method.convert(widest); 3.693 + load(falseExpr, widest); 3.694 method.label(exitLabel); 3.695 method.store(symbol); 3.696 3.697 @@ -3044,8 +3053,7 @@ 3.698 final BaseNode baseNode = (BaseNode)target; 3.699 final Expression base = baseNode.getBase(); 3.700 3.701 - load(base); 3.702 - method.convert(Type.OBJECT); 3.703 + load(base, Type.OBJECT); 3.704 depth += Type.OBJECT.getSlots(); 3.705 3.706 if (isSelfModifying()) { 3.707 @@ -3064,10 +3072,11 @@ 3.708 enterBaseNode(); 3.709 3.710 final Expression index = node.getIndex(); 3.711 - // could be boolean here as well 3.712 - load(index); 3.713 if (!index.getType().isNumeric()) { 3.714 - method.convert(Type.OBJECT); 3.715 + // could be boolean here as well 3.716 + load(index, Type.OBJECT); 3.717 + } else { 3.718 + load(index); 3.719 } 3.720 depth += index.getType().getSlots(); 3.721 3.722 @@ -3136,8 +3145,6 @@ 3.723 * need to do a conversion on non-equivalent types exists, but is 3.724 * very rare. See for example test/script/basic/access-specializer.js 3.725 */ 3.726 - method.convert(target.getType()); 3.727 - 3.728 target.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 3.729 @Override 3.730 protected boolean enterDefault(Node node) { 3.731 @@ -3145,24 +3152,17 @@ 3.732 } 3.733 3.734 @Override 3.735 - public boolean enterUnaryNode(final UnaryNode node) { 3.736 - if (node.tokenType() == TokenType.CONVERT && node.getSymbol() != null) { 3.737 - method.convert(node.rhs().getType()); 3.738 - } 3.739 - return true; 3.740 - } 3.741 - 3.742 - @Override 3.743 public boolean enterIdentNode(final IdentNode node) { 3.744 final Symbol symbol = node.getSymbol(); 3.745 assert symbol != null; 3.746 if (symbol.isScope()) { 3.747 if (isFastScope(symbol)) { 3.748 - storeFastScopeVar(node.getType(), symbol, CALLSITE_SCOPE | getCallSiteFlags()); 3.749 + storeFastScopeVar(symbol, CALLSITE_SCOPE | getCallSiteFlags()); 3.750 } else { 3.751 - method.dynamicSet(node.getType(), node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); 3.752 + method.dynamicSet(node.getName(), CALLSITE_SCOPE | getCallSiteFlags()); 3.753 } 3.754 } else { 3.755 + method.convert(node.getType()); 3.756 method.store(symbol); 3.757 } 3.758 return false; 3.759 @@ -3171,7 +3171,7 @@ 3.760 3.761 @Override 3.762 public boolean enterAccessNode(final AccessNode node) { 3.763 - method.dynamicSet(node.getProperty().getType(), node.getProperty().getName(), getCallSiteFlags()); 3.764 + method.dynamicSet(node.getProperty().getName(), getCallSiteFlags()); 3.765 return false; 3.766 } 3.767
4.1 --- a/src/jdk/nashorn/internal/codegen/CompileUnit.java Wed Oct 09 14:50:39 2013 +0200 4.2 +++ b/src/jdk/nashorn/internal/codegen/CompileUnit.java Wed Oct 09 17:53:22 2013 +0200 4.3 @@ -28,7 +28,7 @@ 4.4 /** 4.5 * Used to track split class compilation. 4.6 */ 4.7 -public class CompileUnit { 4.8 +public class CompileUnit implements Comparable<CompileUnit> { 4.9 /** Current class name */ 4.10 private final String className; 4.11 4.12 @@ -116,4 +116,9 @@ 4.13 public String toString() { 4.14 return "[classname=" + className + " weight=" + weight + '/' + Splitter.SPLIT_THRESHOLD + ']'; 4.15 } 4.16 + 4.17 + @Override 4.18 + public int compareTo(CompileUnit o) { 4.19 + return className.compareTo(o.className); 4.20 + } 4.21 }
5.1 --- a/src/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 09 14:50:39 2013 +0200 5.2 +++ b/src/jdk/nashorn/internal/codegen/Compiler.java Wed Oct 09 17:53:22 2013 +0200 5.3 @@ -36,8 +36,6 @@ 5.4 import static jdk.nashorn.internal.codegen.CompilerConstants.THIS; 5.5 import static jdk.nashorn.internal.codegen.CompilerConstants.VARARGS; 5.6 5.7 -import jdk.nashorn.internal.ir.TemporarySymbols; 5.8 - 5.9 import java.io.File; 5.10 import java.lang.reflect.Field; 5.11 import java.security.AccessController; 5.12 @@ -48,18 +46,20 @@ 5.13 import java.util.Comparator; 5.14 import java.util.EnumSet; 5.15 import java.util.HashMap; 5.16 -import java.util.HashSet; 5.17 +import java.util.LinkedHashMap; 5.18 import java.util.LinkedList; 5.19 import java.util.List; 5.20 import java.util.Map; 5.21 import java.util.Map.Entry; 5.22 import java.util.Set; 5.23 +import java.util.TreeSet; 5.24 import java.util.logging.Level; 5.25 import jdk.internal.dynalink.support.NameCodec; 5.26 import jdk.nashorn.internal.codegen.ClassEmitter.Flag; 5.27 import jdk.nashorn.internal.codegen.types.Type; 5.28 import jdk.nashorn.internal.ir.FunctionNode; 5.29 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 5.30 +import jdk.nashorn.internal.ir.TemporarySymbols; 5.31 import jdk.nashorn.internal.ir.debug.ClassHistogramElement; 5.32 import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; 5.33 import jdk.nashorn.internal.runtime.CodeInstaller; 5.34 @@ -256,8 +256,8 @@ 5.35 this.sequence = sequence; 5.36 this.installer = installer; 5.37 this.constantData = new ConstantData(); 5.38 - this.compileUnits = new HashSet<>(); 5.39 - this.bytecode = new HashMap<>(); 5.40 + this.compileUnits = new TreeSet<>(); 5.41 + this.bytecode = new LinkedHashMap<>(); 5.42 } 5.43 5.44 private void initCompiler(final FunctionNode functionNode) {
6.1 --- a/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed Oct 09 14:50:39 2013 +0200 6.2 +++ b/src/jdk/nashorn/internal/codegen/FinalizeTypes.java Wed Oct 09 17:53:22 2013 +0200 6.3 @@ -28,49 +28,22 @@ 6.4 import static jdk.nashorn.internal.codegen.CompilerConstants.CALLEE; 6.5 import static jdk.nashorn.internal.codegen.CompilerConstants.SCOPE; 6.6 6.7 -import java.util.ArrayList; 6.8 -import java.util.HashSet; 6.9 -import java.util.List; 6.10 -import jdk.nashorn.internal.codegen.types.Type; 6.11 -import jdk.nashorn.internal.ir.AccessNode; 6.12 -import jdk.nashorn.internal.ir.Assignment; 6.13 import jdk.nashorn.internal.ir.BinaryNode; 6.14 import jdk.nashorn.internal.ir.Block; 6.15 -import jdk.nashorn.internal.ir.CallNode; 6.16 -import jdk.nashorn.internal.ir.CaseNode; 6.17 -import jdk.nashorn.internal.ir.CatchNode; 6.18 import jdk.nashorn.internal.ir.Expression; 6.19 import jdk.nashorn.internal.ir.ExpressionStatement; 6.20 import jdk.nashorn.internal.ir.ForNode; 6.21 import jdk.nashorn.internal.ir.FunctionNode; 6.22 import jdk.nashorn.internal.ir.FunctionNode.CompilationState; 6.23 -import jdk.nashorn.internal.ir.IdentNode; 6.24 -import jdk.nashorn.internal.ir.IfNode; 6.25 -import jdk.nashorn.internal.ir.IndexNode; 6.26 import jdk.nashorn.internal.ir.LexicalContext; 6.27 -import jdk.nashorn.internal.ir.LiteralNode; 6.28 -import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode; 6.29 import jdk.nashorn.internal.ir.Node; 6.30 -import jdk.nashorn.internal.ir.ReturnNode; 6.31 -import jdk.nashorn.internal.ir.RuntimeNode; 6.32 -import jdk.nashorn.internal.ir.RuntimeNode.Request; 6.33 -import jdk.nashorn.internal.ir.SwitchNode; 6.34 import jdk.nashorn.internal.ir.Symbol; 6.35 import jdk.nashorn.internal.ir.TemporarySymbols; 6.36 -import jdk.nashorn.internal.ir.TernaryNode; 6.37 -import jdk.nashorn.internal.ir.ThrowNode; 6.38 -import jdk.nashorn.internal.ir.TypeOverride; 6.39 import jdk.nashorn.internal.ir.UnaryNode; 6.40 -import jdk.nashorn.internal.ir.VarNode; 6.41 -import jdk.nashorn.internal.ir.WhileNode; 6.42 -import jdk.nashorn.internal.ir.WithNode; 6.43 import jdk.nashorn.internal.ir.visitor.NodeOperatorVisitor; 6.44 -import jdk.nashorn.internal.ir.visitor.NodeVisitor; 6.45 import jdk.nashorn.internal.parser.Token; 6.46 import jdk.nashorn.internal.parser.TokenType; 6.47 -import jdk.nashorn.internal.runtime.Debug; 6.48 import jdk.nashorn.internal.runtime.DebugLogger; 6.49 -import jdk.nashorn.internal.runtime.JSType; 6.50 6.51 /** 6.52 * Lower to more primitive operations. After lowering, an AST has symbols and 6.53 @@ -97,272 +70,32 @@ 6.54 } 6.55 6.56 @Override 6.57 - public Node leaveCallNode(final CallNode callNode) { 6.58 - // AccessSpecializer - call return type may change the access for this location 6.59 - final Node function = callNode.getFunction(); 6.60 - if (function instanceof FunctionNode) { 6.61 - return setTypeOverride(callNode, ((FunctionNode)function).getReturnType()); 6.62 - } 6.63 - return callNode; 6.64 - } 6.65 - 6.66 - private Node leaveUnary(final UnaryNode unaryNode) { 6.67 - return unaryNode.setRHS(convert(unaryNode.rhs(), unaryNode.getType())); 6.68 - } 6.69 - 6.70 - @Override 6.71 - public Node leaveADD(final UnaryNode unaryNode) { 6.72 - return leaveUnary(unaryNode); 6.73 - } 6.74 - 6.75 - @Override 6.76 - public Node leaveBIT_NOT(final UnaryNode unaryNode) { 6.77 - return leaveUnary(unaryNode); 6.78 - } 6.79 - 6.80 - @Override 6.81 - public Node leaveCONVERT(final UnaryNode unaryNode) { 6.82 - assert unaryNode.rhs().tokenType() != TokenType.CONVERT : "convert(convert encountered. check its origin and remove it"; 6.83 - return unaryNode; 6.84 - } 6.85 - 6.86 - @Override 6.87 - public Node leaveDECINC(final UnaryNode unaryNode) { 6.88 - return specialize(unaryNode).node; 6.89 - } 6.90 - 6.91 - @Override 6.92 - public Node leaveNEW(final UnaryNode unaryNode) { 6.93 - assert unaryNode.getSymbol() != null && unaryNode.getSymbol().getSymbolType().isObject(); 6.94 - return unaryNode.setRHS(((CallNode)unaryNode.rhs()).setIsNew()); 6.95 - } 6.96 - 6.97 - @Override 6.98 - public Node leaveSUB(final UnaryNode unaryNode) { 6.99 - return leaveUnary(unaryNode); 6.100 - } 6.101 - 6.102 - /** 6.103 - * Add is a special binary, as it works not only on arithmetic, but for 6.104 - * strings etc as well. 6.105 - */ 6.106 - @Override 6.107 - public Expression leaveADD(final BinaryNode binaryNode) { 6.108 - final Expression lhs = binaryNode.lhs(); 6.109 - final Expression rhs = binaryNode.rhs(); 6.110 - 6.111 - final Type type = binaryNode.getType(); 6.112 - 6.113 - if (type.isObject()) { 6.114 - if (!isAddString(binaryNode)) { 6.115 - return new RuntimeNode(binaryNode, Request.ADD); 6.116 - } 6.117 + public Node leaveForNode(final ForNode forNode) { 6.118 + if (forNode.isForIn()) { 6.119 + return forNode; 6.120 } 6.121 6.122 - return binaryNode.setLHS(convert(lhs, type)).setRHS(convert(rhs, type)); 6.123 - } 6.124 + final Expression init = forNode.getInit(); 6.125 + final Expression test = forNode.getTest(); 6.126 + final Expression modify = forNode.getModify(); 6.127 6.128 - @Override 6.129 - public Node leaveAND(final BinaryNode binaryNode) { 6.130 - return binaryNode; 6.131 - } 6.132 + assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction(); 6.133 6.134 - @Override 6.135 - public Node leaveASSIGN(final BinaryNode binaryNode) { 6.136 - final SpecializedNode specialized = specialize(binaryNode); 6.137 - final BinaryNode specBinaryNode = (BinaryNode)specialized.node; 6.138 - Type destType = specialized.type; 6.139 - if (destType == null) { 6.140 - destType = specBinaryNode.getType(); 6.141 - } 6.142 - // Register assignments to this object in case this is used as constructor 6.143 - if (binaryNode.lhs() instanceof AccessNode) { 6.144 - AccessNode accessNode = (AccessNode) binaryNode.lhs(); 6.145 - 6.146 - if (accessNode.getBase().getSymbol().isThis()) { 6.147 - lc.getCurrentFunction().addThisProperty(accessNode.getProperty().getName()); 6.148 - } 6.149 - } 6.150 - return specBinaryNode.setRHS(convert(specBinaryNode.rhs(), destType)); 6.151 - } 6.152 - 6.153 - @Override 6.154 - public Node leaveASSIGN_ADD(final BinaryNode binaryNode) { 6.155 - return leaveASSIGN(binaryNode); 6.156 - } 6.157 - 6.158 - @Override 6.159 - public Node leaveASSIGN_BIT_AND(final BinaryNode binaryNode) { 6.160 - return leaveASSIGN(binaryNode); 6.161 - } 6.162 - 6.163 - @Override 6.164 - public Node leaveASSIGN_BIT_OR(final BinaryNode binaryNode) { 6.165 - return leaveASSIGN(binaryNode); 6.166 - } 6.167 - 6.168 - @Override 6.169 - public Node leaveASSIGN_BIT_XOR(final BinaryNode binaryNode) { 6.170 - return leaveASSIGN(binaryNode); 6.171 - } 6.172 - 6.173 - @Override 6.174 - public Node leaveASSIGN_DIV(final BinaryNode binaryNode) { 6.175 - return leaveASSIGN(binaryNode); 6.176 - } 6.177 - 6.178 - @Override 6.179 - public Node leaveASSIGN_MOD(final BinaryNode binaryNode) { 6.180 - return leaveASSIGN(binaryNode); 6.181 - } 6.182 - 6.183 - @Override 6.184 - public Node leaveASSIGN_MUL(final BinaryNode binaryNode) { 6.185 - return leaveASSIGN(binaryNode); 6.186 - } 6.187 - 6.188 - @Override 6.189 - public Node leaveASSIGN_SAR(final BinaryNode binaryNode) { 6.190 - return leaveASSIGN(binaryNode); 6.191 - } 6.192 - 6.193 - @Override 6.194 - public Node leaveASSIGN_SHL(final BinaryNode binaryNode) { 6.195 - return leaveASSIGN(binaryNode); 6.196 - } 6.197 - 6.198 - @Override 6.199 - public Node leaveASSIGN_SHR(final BinaryNode binaryNode) { 6.200 - return leaveASSIGN(binaryNode); 6.201 - } 6.202 - 6.203 - @Override 6.204 - public Node leaveASSIGN_SUB(final BinaryNode binaryNode) { 6.205 - return leaveASSIGN(binaryNode); 6.206 - } 6.207 - 6.208 - private boolean symbolIsInteger(final Expression node) { 6.209 - final Symbol symbol = node.getSymbol(); 6.210 - assert symbol != null && symbol.getSymbolType().isInteger() : "int coercion expected: " + Debug.id(symbol) + " " + symbol + " " + lc.getCurrentFunction().getSource(); 6.211 - return true; 6.212 - } 6.213 - 6.214 - @Override 6.215 - public Node leaveBIT_AND(final BinaryNode binaryNode) { 6.216 - assert symbolIsInteger(binaryNode); 6.217 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.218 - } 6.219 - 6.220 - @Override 6.221 - public Node leaveBIT_OR(final BinaryNode binaryNode) { 6.222 - assert symbolIsInteger(binaryNode); 6.223 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.224 - } 6.225 - 6.226 - @Override 6.227 - public Node leaveBIT_XOR(final BinaryNode binaryNode) { 6.228 - assert symbolIsInteger(binaryNode); 6.229 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.230 + return forNode. 6.231 + setInit(lc, init == null ? null : discard(init)). 6.232 + setModify(lc, modify == null ? null : discard(modify)); 6.233 } 6.234 6.235 @Override 6.236 public Node leaveCOMMALEFT(final BinaryNode binaryNode) { 6.237 assert binaryNode.getSymbol() != null; 6.238 - final BinaryNode newBinaryNode = binaryNode.setRHS(discard(binaryNode.rhs())); 6.239 - // AccessSpecializer - the type of lhs, which is the remaining value of this node may have changed 6.240 - // in that case, update the node type as well 6.241 - return propagateType(newBinaryNode, newBinaryNode.lhs().getType()); 6.242 + return binaryNode.setRHS(discard(binaryNode.rhs())); 6.243 } 6.244 6.245 @Override 6.246 public Node leaveCOMMARIGHT(final BinaryNode binaryNode) { 6.247 assert binaryNode.getSymbol() != null; 6.248 - final BinaryNode newBinaryNode = binaryNode.setLHS(discard(binaryNode.lhs())); 6.249 - // AccessSpecializer - the type of rhs, which is the remaining value of this node may have changed 6.250 - // in that case, update the node type as well 6.251 - return propagateType(newBinaryNode, newBinaryNode.rhs().getType()); 6.252 - } 6.253 - 6.254 - @Override 6.255 - public Node leaveDIV(final BinaryNode binaryNode) { 6.256 - return leaveBinaryArith(binaryNode); 6.257 - } 6.258 - 6.259 - 6.260 - @Override 6.261 - public Node leaveEQ(final BinaryNode binaryNode) { 6.262 - return leaveCmp(binaryNode, Request.EQ); 6.263 - } 6.264 - 6.265 - @Override 6.266 - public Node leaveEQ_STRICT(final BinaryNode binaryNode) { 6.267 - return leaveCmp(binaryNode, Request.EQ_STRICT); 6.268 - } 6.269 - 6.270 - @Override 6.271 - public Node leaveGE(final BinaryNode binaryNode) { 6.272 - return leaveCmp(binaryNode, Request.GE); 6.273 - } 6.274 - 6.275 - @Override 6.276 - public Node leaveGT(final BinaryNode binaryNode) { 6.277 - return leaveCmp(binaryNode, Request.GT); 6.278 - } 6.279 - 6.280 - @Override 6.281 - public Node leaveLE(final BinaryNode binaryNode) { 6.282 - return leaveCmp(binaryNode, Request.LE); 6.283 - } 6.284 - 6.285 - @Override 6.286 - public Node leaveLT(final BinaryNode binaryNode) { 6.287 - return leaveCmp(binaryNode, Request.LT); 6.288 - } 6.289 - 6.290 - @Override 6.291 - public Node leaveMOD(final BinaryNode binaryNode) { 6.292 - return leaveBinaryArith(binaryNode); 6.293 - } 6.294 - 6.295 - @Override 6.296 - public Node leaveMUL(final BinaryNode binaryNode) { 6.297 - return leaveBinaryArith(binaryNode); 6.298 - } 6.299 - 6.300 - @Override 6.301 - public Node leaveNE(final BinaryNode binaryNode) { 6.302 - return leaveCmp(binaryNode, Request.NE); 6.303 - } 6.304 - 6.305 - @Override 6.306 - public Node leaveNE_STRICT(final BinaryNode binaryNode) { 6.307 - return leaveCmp(binaryNode, Request.NE_STRICT); 6.308 - } 6.309 - 6.310 - @Override 6.311 - public Node leaveOR(final BinaryNode binaryNode) { 6.312 - return binaryNode; 6.313 - } 6.314 - 6.315 - @Override 6.316 - public Node leaveSAR(final BinaryNode binaryNode) { 6.317 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.318 - } 6.319 - 6.320 - @Override 6.321 - public Node leaveSHL(final BinaryNode binaryNode) { 6.322 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.323 - } 6.324 - 6.325 - @Override 6.326 - public Node leaveSHR(final BinaryNode binaryNode) { 6.327 - assert binaryNode.getSymbol() != null && binaryNode.getSymbol().getSymbolType().isLong() : "long coercion expected: " + binaryNode.getSymbol(); 6.328 - return leaveBinary(binaryNode, Type.INT, Type.INT); 6.329 - } 6.330 - 6.331 - @Override 6.332 - public Node leaveSUB(final BinaryNode binaryNode) { 6.333 - return leaveBinaryArith(binaryNode); 6.334 + return binaryNode.setLHS(discard(binaryNode.lhs())); 6.335 } 6.336 6.337 @Override 6.338 @@ -372,38 +105,12 @@ 6.339 } 6.340 6.341 @Override 6.342 - public Node leaveCatchNode(final CatchNode catchNode) { 6.343 - final Expression exceptionCondition = catchNode.getExceptionCondition(); 6.344 - if (exceptionCondition != null) { 6.345 - return catchNode.setExceptionCondition(convert(exceptionCondition, Type.BOOLEAN)); 6.346 - } 6.347 - return catchNode; 6.348 - } 6.349 - 6.350 - @Override 6.351 public Node leaveExpressionStatement(final ExpressionStatement expressionStatement) { 6.352 temporarySymbols.reuse(); 6.353 return expressionStatement.setExpression(discard(expressionStatement.getExpression())); 6.354 } 6.355 6.356 @Override 6.357 - public Node leaveForNode(final ForNode forNode) { 6.358 - final Expression init = forNode.getInit(); 6.359 - final Expression test = forNode.getTest(); 6.360 - final Expression modify = forNode.getModify(); 6.361 - 6.362 - if (forNode.isForIn()) { 6.363 - return forNode.setModify(lc, convert(forNode.getModify(), Type.OBJECT)); // NASHORN-400 6.364 - } 6.365 - assert test != null || forNode.hasGoto() : "forNode " + forNode + " needs goto and is missing it in " + lc.getCurrentFunction(); 6.366 - 6.367 - return forNode. 6.368 - setInit(lc, init == null ? null : discard(init)). 6.369 - setTest(lc, test == null ? null : convert(test, Type.BOOLEAN)). 6.370 - setModify(lc, modify == null ? null : discard(modify)); 6.371 - } 6.372 - 6.373 - @Override 6.374 public boolean enterFunctionNode(final FunctionNode functionNode) { 6.375 if (functionNode.isLazy()) { 6.376 return false; 6.377 @@ -430,113 +137,6 @@ 6.378 return functionNode.setState(lc, CompilationState.FINALIZED); 6.379 } 6.380 6.381 - @Override 6.382 - public Node leaveIfNode(final IfNode ifNode) { 6.383 - return ifNode.setTest(convert(ifNode.getTest(), Type.BOOLEAN)); 6.384 - } 6.385 - 6.386 - @SuppressWarnings("rawtypes") 6.387 - @Override 6.388 - public boolean enterLiteralNode(final LiteralNode literalNode) { 6.389 - if (literalNode instanceof ArrayLiteralNode) { 6.390 - final ArrayLiteralNode arrayLiteralNode = (ArrayLiteralNode)literalNode; 6.391 - final Expression[] array = arrayLiteralNode.getValue(); 6.392 - final Type elementType = arrayLiteralNode.getElementType(); 6.393 - 6.394 - for (int i = 0; i < array.length; i++) { 6.395 - final Node element = array[i]; 6.396 - if (element != null) { 6.397 - array[i] = convert((Expression)element.accept(this), elementType); 6.398 - } 6.399 - } 6.400 - } 6.401 - 6.402 - return false; 6.403 - } 6.404 - 6.405 - @Override 6.406 - public Node leaveReturnNode(final ReturnNode returnNode) { 6.407 - final Expression expr = returnNode.getExpression(); 6.408 - if (expr != null) { 6.409 - return returnNode.setExpression(convert(expr, lc.getCurrentFunction().getReturnType())); 6.410 - } 6.411 - return returnNode; 6.412 - } 6.413 - 6.414 - @Override 6.415 - public Node leaveRuntimeNode(final RuntimeNode runtimeNode) { 6.416 - final List<Expression> args = runtimeNode.getArgs(); 6.417 - for (final Expression arg : args) { 6.418 - assert !arg.getType().isUnknown(); 6.419 - } 6.420 - return runtimeNode; 6.421 - } 6.422 - 6.423 - @Override 6.424 - public Node leaveSwitchNode(final SwitchNode switchNode) { 6.425 - final boolean allInteger = switchNode.getTag().getSymbolType().isInteger(); 6.426 - 6.427 - if (allInteger) { 6.428 - return switchNode; 6.429 - } 6.430 - 6.431 - final Expression expression = switchNode.getExpression(); 6.432 - final List<CaseNode> cases = switchNode.getCases(); 6.433 - final List<CaseNode> newCases = new ArrayList<>(); 6.434 - 6.435 - for (final CaseNode caseNode : cases) { 6.436 - final Expression test = caseNode.getTest(); 6.437 - newCases.add(test != null ? caseNode.setTest(convert(test, Type.OBJECT)) : caseNode); 6.438 - } 6.439 - 6.440 - return switchNode. 6.441 - setExpression(lc, convert(expression, Type.OBJECT)). 6.442 - setCases(lc, newCases); 6.443 - } 6.444 - 6.445 - @Override 6.446 - public Node leaveTernaryNode(final TernaryNode ternaryNode) { 6.447 - return ternaryNode.setTest(convert(ternaryNode.getTest(), Type.BOOLEAN)); 6.448 - } 6.449 - 6.450 - @Override 6.451 - public Node leaveThrowNode(final ThrowNode throwNode) { 6.452 - return throwNode.setExpression(convert(throwNode.getExpression(), Type.OBJECT)); 6.453 - } 6.454 - 6.455 - @Override 6.456 - public Node leaveVarNode(final VarNode varNode) { 6.457 - final Expression init = varNode.getInit(); 6.458 - if (init != null) { 6.459 - final SpecializedNode specialized = specialize(varNode); 6.460 - final VarNode specVarNode = (VarNode)specialized.node; 6.461 - Type destType = specialized.type; 6.462 - if (destType == null) { 6.463 - destType = specVarNode.getName().getType(); 6.464 - } 6.465 - assert specVarNode.getName().hasType() : specVarNode + " doesn't have a type"; 6.466 - final Expression convertedInit = convert(init, destType); 6.467 - temporarySymbols.reuse(); 6.468 - return specVarNode.setInit(convertedInit); 6.469 - } 6.470 - temporarySymbols.reuse(); 6.471 - return varNode; 6.472 - } 6.473 - 6.474 - @Override 6.475 - public Node leaveWhileNode(final WhileNode whileNode) { 6.476 - final Expression test = whileNode.getTest(); 6.477 - if (test != null) { 6.478 - return whileNode.setTest(lc, convert(test, Type.BOOLEAN)); 6.479 - } 6.480 - return whileNode; 6.481 - } 6.482 - 6.483 - @Override 6.484 - public Node leaveWithNode(final WithNode withNode) { 6.485 - return withNode.setExpression(lc, convert(withNode.getExpression(), Type.OBJECT)); 6.486 - } 6.487 - 6.488 private static void updateSymbolsLog(final FunctionNode functionNode, final Symbol symbol, final boolean loseSlot) { 6.489 if (LOG.isEnabled()) { 6.490 if (!symbol.isScope()) { 6.491 @@ -583,260 +183,6 @@ 6.492 } 6.493 } 6.494 6.495 - /** 6.496 - * Exit a comparison node and do the appropriate replacements. We need to introduce runtime 6.497 - * nodes late for comparisons as types aren't known until the last minute 6.498 - * 6.499 - * Both compares and adds may turn into runtimes node at this level as when we first bump 6.500 - * into the op in Attr, we may type it according to what we know there, which may be wrong later 6.501 - * 6.502 - * e.g. i (int) < 5 -> normal compare 6.503 - * i = object 6.504 - * then the post pass that would add the conversion to the 5 needs to 6.505 - * 6.506 - * @param binaryNode binary node to leave 6.507 - * @param request runtime request 6.508 - * @return lowered cmp node 6.509 - */ 6.510 - @SuppressWarnings("fallthrough") 6.511 - private Node leaveCmp(final BinaryNode binaryNode, final RuntimeNode.Request request) { 6.512 - final Expression lhs = binaryNode.lhs(); 6.513 - final Expression rhs = binaryNode.rhs(); 6.514 - 6.515 - Type widest = Type.widest(lhs.getType(), rhs.getType()); 6.516 - 6.517 - boolean newRuntimeNode = false, finalized = false; 6.518 - switch (request) { 6.519 - case EQ_STRICT: 6.520 - case NE_STRICT: 6.521 - if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) { 6.522 - newRuntimeNode = true; 6.523 - widest = Type.OBJECT; 6.524 - finalized = true; 6.525 - } 6.526 - //fallthru 6.527 - default: 6.528 - if (newRuntimeNode || widest.isObject()) { 6.529 - return new RuntimeNode(binaryNode, request).setIsFinal(finalized); 6.530 - } 6.531 - break; 6.532 - } 6.533 - 6.534 - return binaryNode.setLHS(convert(lhs, widest)).setRHS(convert(rhs, widest)); 6.535 - } 6.536 - 6.537 - /** 6.538 - * Compute the binary arithmetic type given the lhs and an rhs of a binary expression 6.539 - * @param lhsType the lhs type 6.540 - * @param rhsType the rhs type 6.541 - * @return the correct binary type 6.542 - */ 6.543 - private static Type binaryArithType(final Type lhsType, final Type rhsType) { 6.544 - if (!Compiler.shouldUseIntegerArithmetic()) { 6.545 - return Type.NUMBER; 6.546 - } 6.547 - return Type.widest(lhsType, rhsType, Type.NUMBER); 6.548 - } 6.549 - 6.550 - private Node leaveBinaryArith(final BinaryNode binaryNode) { 6.551 - final Type type = binaryArithType(binaryNode.lhs().getType(), binaryNode.rhs().getType()); 6.552 - return leaveBinary(binaryNode, type, type); 6.553 - } 6.554 - 6.555 - private Node leaveBinary(final BinaryNode binaryNode, final Type lhsType, final Type rhsType) { 6.556 - Node b = binaryNode.setLHS(convert(binaryNode.lhs(), lhsType)).setRHS(convert(binaryNode.rhs(), rhsType)); 6.557 - return b; 6.558 - } 6.559 - 6.560 - /** 6.561 - * A symbol (and {@link jdk.nashorn.internal.runtime.Property}) can be tagged as "may be primitive". 6.562 - * This is used a hint for dual fields that it is even worth it to try representing this 6.563 - * field as something other than java.lang.Object. 6.564 - * 6.565 - * @param node node in which to tag symbols as primitive 6.566 - * @param to which primitive type to use for tagging 6.567 - */ 6.568 - private static void setCanBePrimitive(final Node node, final Type to) { 6.569 - final HashSet<Node> exclude = new HashSet<>(); 6.570 - 6.571 - node.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) { 6.572 - private void setCanBePrimitive(final Symbol symbol) { 6.573 - LOG.info("*** can be primitive symbol ", symbol, " ", Debug.id(symbol)); 6.574 - symbol.setCanBePrimitive(to); 6.575 - } 6.576 - 6.577 - @Override 6.578 - public boolean enterIdentNode(final IdentNode identNode) { 6.579 - if (!exclude.contains(identNode)) { 6.580 - setCanBePrimitive(identNode.getSymbol()); 6.581 - } 6.582 - return false; 6.583 - } 6.584 - 6.585 - @Override 6.586 - public boolean enterAccessNode(final AccessNode accessNode) { 6.587 - setCanBePrimitive(accessNode.getProperty().getSymbol()); 6.588 - return false; 6.589 - } 6.590 - 6.591 - @Override 6.592 - public boolean enterIndexNode(final IndexNode indexNode) { 6.593 - exclude.add(indexNode.getBase()); //prevent array base node to be flagged as primitive, but k in a[k++] is fine 6.594 - return true; 6.595 - } 6.596 - }); 6.597 - } 6.598 - 6.599 - private static class SpecializedNode { 6.600 - final Node node; 6.601 - final Type type; 6.602 - 6.603 - SpecializedNode(Node node, Type type) { 6.604 - this.node = node; 6.605 - this.type = type; 6.606 - } 6.607 - } 6.608 - 6.609 - <T extends Expression> SpecializedNode specialize(final Assignment<T> assignment) { 6.610 - final Node node = ((Node)assignment); 6.611 - final T lhs = assignment.getAssignmentDest(); 6.612 - final Expression rhs = assignment.getAssignmentSource(); 6.613 - 6.614 - if (!canHaveCallSiteType(lhs)) { 6.615 - return new SpecializedNode(node, null); 6.616 - } 6.617 - 6.618 - final Type to; 6.619 - if (node.isSelfModifying()) { 6.620 - to = node.getWidestOperationType(); 6.621 - } else { 6.622 - to = rhs.getType(); 6.623 - } 6.624 - 6.625 - if (!isSupportedCallSiteType(to)) { 6.626 - //meaningless to specialize to boolean or object 6.627 - return new SpecializedNode(node, null); 6.628 - } 6.629 - 6.630 - final Node newNode = assignment.setAssignmentDest(setTypeOverride(lhs, to)); 6.631 - final Node typePropagatedNode; 6.632 - if(newNode instanceof Expression) { 6.633 - typePropagatedNode = propagateType((Expression)newNode, to); 6.634 - } else if(newNode instanceof VarNode) { 6.635 - // VarNode, being a statement, doesn't have its own symbol; it uses the symbol of its name instead. 6.636 - final VarNode varNode = (VarNode)newNode; 6.637 - typePropagatedNode = varNode.setName((IdentNode)propagateType(varNode.getName(), to)); 6.638 - } else { 6.639 - throw new AssertionError(); 6.640 - } 6.641 - return new SpecializedNode(typePropagatedNode, to); 6.642 - } 6.643 - 6.644 - 6.645 - /** 6.646 - * Is this a node that can have its type overridden. This is true for 6.647 - * AccessNodes, IndexNodes and IdentNodes 6.648 - * 6.649 - * @param node the node to check 6.650 - * @return true if node can have a callsite type 6.651 - */ 6.652 - private static boolean canHaveCallSiteType(final Node node) { 6.653 - return node instanceof TypeOverride && ((TypeOverride<?>)node).canHaveCallSiteType(); 6.654 - } 6.655 - 6.656 - /** 6.657 - * Is the specialization type supported. Currently we treat booleans as objects 6.658 - * and have no special boolean type accessor, thus booleans are ignored. 6.659 - * TODO - support booleans? NASHORN-590 6.660 - * 6.661 - * @param castTo the type to check 6.662 - * @return true if call site type is supported 6.663 - */ 6.664 - private static boolean isSupportedCallSiteType(final Type castTo) { 6.665 - return castTo.isNumeric(); // don't specializable for boolean 6.666 - } 6.667 - 6.668 - /** 6.669 - * Override the type of a node for e.g. access specialization of scope 6.670 - * objects. Normally a variable can only get a wider type and narrower type 6.671 - * sets are ignored. Not that a variable can still be on object type as 6.672 - * per the type analysis, but a specific access may be narrower, e.g. if it 6.673 - * is used in an arithmetic op. This overrides a type, regardless of 6.674 - * type environment and is used primarily by the access specializer 6.675 - * 6.676 - * @param node node for which to change type 6.677 - * @param to new type 6.678 - */ 6.679 - @SuppressWarnings("unchecked") 6.680 - <T extends Expression> T setTypeOverride(final T node, final Type to) { 6.681 - final Type from = node.getType(); 6.682 - if (!node.getType().equals(to)) { 6.683 - LOG.info("Changing call override type for '", node, "' from ", node.getType(), " to ", to); 6.684 - if (!to.isObject() && from.isObject()) { 6.685 - setCanBePrimitive(node, to); 6.686 - } 6.687 - } 6.688 - LOG.info("Type override for lhs in '", node, "' => ", to); 6.689 - return ((TypeOverride<T>)node).setType(temporarySymbols, lc, to); 6.690 - } 6.691 - 6.692 - /** 6.693 - * Add an explicit conversion. This is needed when attribution has created types 6.694 - * that do not mesh into an op type, e.g. a = b, where b is object and a is double 6.695 - * at the end of Attr, needs explicit conversion logic. 6.696 - * 6.697 - * An explicit conversion can be one of the following: 6.698 - * + Convert a literal - just replace it with another literal 6.699 - * + Convert a scope object - just replace the type of the access, e.g. get()D->get()I 6.700 - * + Explicit convert placement, e.g. a = (double)b - all other cases 6.701 - * 6.702 - * No other part of the world after {@link Attr} may introduce new symbols. This 6.703 - * is the only place. 6.704 - * 6.705 - * @param node node to convert 6.706 - * @param to destination type 6.707 - * @return conversion node 6.708 - */ 6.709 - private Expression convert(final Expression node, final Type to) { 6.710 - assert !to.isUnknown() : "unknown type for " + node + " class=" + node.getClass(); 6.711 - assert node != null : "node is null"; 6.712 - assert node.getSymbol() != null : "node " + node + " " + node.getClass() + " has no symbol! " + lc.getCurrentFunction(); 6.713 - assert node.tokenType() != TokenType.CONVERT : "assert convert in convert " + node + " in " + lc.getCurrentFunction(); 6.714 - 6.715 - final Type from = node.getType(); 6.716 - 6.717 - if (Type.areEquivalent(from, to)) { 6.718 - return node; 6.719 - } 6.720 - 6.721 - if (from.isObject() && to.isObject()) { 6.722 - return node; 6.723 - } 6.724 - 6.725 - Expression resultNode = node; 6.726 - 6.727 - if (node instanceof LiteralNode && !(node instanceof ArrayLiteralNode) && !to.isObject()) { 6.728 - final LiteralNode<?> newNode = new LiteralNodeConstantEvaluator((LiteralNode<?>)node, to).eval(); 6.729 - if (newNode != null) { 6.730 - resultNode = newNode; 6.731 - } 6.732 - } else { 6.733 - if (canHaveCallSiteType(node) && isSupportedCallSiteType(to)) { 6.734 - assert node instanceof TypeOverride; 6.735 - return setTypeOverride(node, to); 6.736 - } 6.737 - resultNode = new UnaryNode(Token.recast(node.getToken(), TokenType.CONVERT), node); 6.738 - } 6.739 - 6.740 - LOG.info("CONVERT('", node, "', ", to, ") => '", resultNode, "'"); 6.741 - 6.742 - assert !node.isTerminal(); 6.743 - 6.744 - //This is the only place in this file that can create new temporaries 6.745 - //FinalizeTypes may not introduce ANY node that is not a conversion. 6.746 - return temporarySymbols.ensureSymbol(lc, to, resultNode); 6.747 - } 6.748 - 6.749 private static Expression discard(final Expression node) { 6.750 if (node.getSymbol() != null) { 6.751 final UnaryNode discard = new UnaryNode(Token.recast(node.getToken(), TokenType.DISCARD), node); 6.752 @@ -849,82 +195,5 @@ 6.753 return node; 6.754 } 6.755 6.756 - /** 6.757 - * Whenever an expression like an addition or an assignment changes type, it 6.758 - * may be that case that {@link Attr} created a symbol for an intermediate 6.759 - * result of the expression, say for an addition. This also has to be updated 6.760 - * if the expression type changes. 6.761 - * 6.762 - * Assignments use their lhs as node symbol, and in this case we can't modify 6.763 - * it. Then {@link CodeGenerator.Store} needs to do an explicit conversion. 6.764 - * This is happens very rarely. 6.765 - * 6.766 - * @param node 6.767 - * @param to 6.768 - */ 6.769 - private Expression propagateType(final Expression node, final Type to) { 6.770 - Symbol symbol = node.getSymbol(); 6.771 - if (symbol.isTemp() && symbol.getSymbolType() != to) { 6.772 - symbol = symbol.setTypeOverrideShared(to, temporarySymbols); 6.773 - LOG.info("Type override for temporary in '", node, "' => ", to); 6.774 - } 6.775 - return node.setSymbol(lc, symbol); 6.776 - } 6.777 6.778 - /** 6.779 - * Determine if the outcome of + operator is a string. 6.780 - * 6.781 - * @param node Node to test. 6.782 - * @return true if a string result. 6.783 - */ 6.784 - private boolean isAddString(final Node node) { 6.785 - if (node instanceof BinaryNode && node.isTokenType(TokenType.ADD)) { 6.786 - final BinaryNode binaryNode = (BinaryNode)node; 6.787 - final Node lhs = binaryNode.lhs(); 6.788 - final Node rhs = binaryNode.rhs(); 6.789 - 6.790 - return isAddString(lhs) || isAddString(rhs); 6.791 - } 6.792 - 6.793 - return node instanceof LiteralNode<?> && ((LiteralNode<?>)node).isString(); 6.794 - } 6.795 - 6.796 - /** 6.797 - * Whenever an explicit conversion is needed and the convertee is a literal, we can 6.798 - * just change the literal 6.799 - */ 6.800 - class LiteralNodeConstantEvaluator extends FoldConstants.ConstantEvaluator<LiteralNode<?>> { 6.801 - private final Type type; 6.802 - 6.803 - LiteralNodeConstantEvaluator(final LiteralNode<?> parent, final Type type) { 6.804 - super(parent); 6.805 - this.type = type; 6.806 - } 6.807 - 6.808 - @Override 6.809 - protected LiteralNode<?> eval() { 6.810 - final Object value = ((LiteralNode<?>)parent).getValue(); 6.811 - 6.812 - LiteralNode<?> literalNode = null; 6.813 - 6.814 - if (type.isString()) { 6.815 - literalNode = LiteralNode.newInstance(token, finish, JSType.toString(value)); 6.816 - } else if (type.isBoolean()) { 6.817 - literalNode = LiteralNode.newInstance(token, finish, JSType.toBoolean(value)); 6.818 - } else if (type.isInteger()) { 6.819 - literalNode = LiteralNode.newInstance(token, finish, JSType.toInt32(value)); 6.820 - } else if (type.isLong()) { 6.821 - literalNode = LiteralNode.newInstance(token, finish, JSType.toLong(value)); 6.822 - } else if (type.isNumber() || parent.getType().isNumeric() && !parent.getType().isNumber()) { 6.823 - literalNode = LiteralNode.newInstance(token, finish, JSType.toNumber(value)); 6.824 - } 6.825 - 6.826 - if (literalNode != null) { 6.827 - //inherit literal symbol for attr. 6.828 - literalNode = (LiteralNode<?>)literalNode.setSymbol(lc, parent.getSymbol()); 6.829 - } 6.830 - 6.831 - return literalNode; 6.832 - } 6.833 - } 6.834 }
7.1 --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Oct 09 14:50:39 2013 +0200 7.2 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Oct 09 17:53:22 2013 +0200 7.3 @@ -69,7 +69,6 @@ 7.4 import java.lang.reflect.Array; 7.5 import java.util.EnumSet; 7.6 import java.util.List; 7.7 - 7.8 import jdk.internal.dynalink.support.NameCodec; 7.9 import jdk.internal.org.objectweb.asm.Handle; 7.10 import jdk.internal.org.objectweb.asm.MethodVisitor; 7.11 @@ -1560,7 +1559,7 @@ 7.12 MethodEmitter convert(final Type to) { 7.13 final Type type = peekType().convert(method, to); 7.14 if (type != null) { 7.15 - if (peekType() != to) { 7.16 + if (!peekType().isEquivalentTo(to)) { 7.17 debug("convert", peekType(), "->", to); 7.18 } 7.19 popType(); 7.20 @@ -1790,15 +1789,14 @@ 7.21 * @param name name of property 7.22 * @param flags call site flags 7.23 */ 7.24 - void dynamicSet(final Type valueType, final String name, final int flags) { 7.25 + void dynamicSet(final String name, final int flags) { 7.26 debug("dynamic_set", name, peekType()); 7.27 7.28 - Type type = valueType; 7.29 - if (type.isObject() || type.isBoolean()) { //promote strings to objects etc 7.30 + Type type = peekType(); 7.31 + if (type.isObject()) { //promote strings to objects etc 7.32 type = Type.OBJECT; 7.33 convert(Type.OBJECT); //TODO bad- until we specialize boolean setters, 7.34 } 7.35 - 7.36 popType(type); 7.37 popType(Type.SCOPE); 7.38
8.1 --- a/src/jdk/nashorn/internal/codegen/WeighNodes.java Wed Oct 09 14:50:39 2013 +0200 8.2 +++ b/src/jdk/nashorn/internal/codegen/WeighNodes.java Wed Oct 09 17:53:22 2013 +0200 8.3 @@ -297,11 +297,6 @@ 8.4 } 8.5 8.6 @Override 8.7 - public Node leaveCONVERT(final UnaryNode unaryNode) { 8.8 - return unaryNodeWeight(unaryNode); 8.9 - } 8.10 - 8.11 - @Override 8.12 public Node leaveDECINC(final UnaryNode unaryNode) { 8.13 return unaryNodeWeight(unaryNode); 8.14 }
9.1 --- a/src/jdk/nashorn/internal/codegen/types/BooleanType.java Wed Oct 09 14:50:39 2013 +0200 9.2 +++ b/src/jdk/nashorn/internal/codegen/types/BooleanType.java Wed Oct 09 17:53:22 2013 +0200 9.3 @@ -136,8 +136,7 @@ 9.4 invokeStatic(method, JSType.TO_LONG); 9.5 } else if (to.isString()) { 9.6 invokeStatic(method, VALUE_OF); 9.7 - invokeStatic(method, JSType.TO_PRIMITIVE); 9.8 - invokeStatic(method, JSType.TO_STRING); 9.9 + invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING); 9.10 } else if (to.isObject()) { 9.11 invokeStatic(method, VALUE_OF); 9.12 } else {
10.1 --- a/src/jdk/nashorn/internal/codegen/types/ObjectType.java Wed Oct 09 14:50:39 2013 +0200 10.2 +++ b/src/jdk/nashorn/internal/codegen/types/ObjectType.java Wed Oct 09 17:53:22 2013 +0200 10.3 @@ -153,8 +153,7 @@ 10.4 } else if (to.isBoolean()) { 10.5 invokeStatic(method, JSType.TO_BOOLEAN); 10.6 } else if (to.isString()) { 10.7 - invokeStatic(method, JSType.TO_PRIMITIVE); 10.8 - invokeStatic(method, JSType.TO_STRING); 10.9 + invokeStatic(method, JSType.TO_PRIMITIVE_TO_STRING); 10.10 } else { 10.11 assert false : "Illegal conversion " + this + " -> " + to + " " + isString() + " " + toString; 10.12 }
11.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java Wed Oct 09 14:50:39 2013 +0200 11.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Wed Oct 09 17:53:22 2013 +0200 11.3 @@ -441,7 +441,12 @@ 11.4 if (type0.isArray() && type1.isArray()) { 11.5 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT; 11.6 } else if (type0.isArray() != type1.isArray()) { 11.7 - return Type.OBJECT; //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 11.8 + //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 11.9 + return Type.OBJECT; 11.10 + } else if (type0.isObject() && type1.isObject() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) { 11.11 + // Object<type=String> and Object<type=ScriptFunction> will produce Object 11.12 + // TODO: maybe find most specific common superclass? 11.13 + return Type.OBJECT; 11.14 } 11.15 return type0.weight() > type1.weight() ? type0 : type1; 11.16 }
12.1 --- a/src/jdk/nashorn/internal/ir/AccessNode.java Wed Oct 09 14:50:39 2013 +0200 12.2 +++ b/src/jdk/nashorn/internal/ir/AccessNode.java Wed Oct 09 17:53:22 2013 +0200 12.3 @@ -25,7 +25,6 @@ 12.4 12.5 package jdk.nashorn.internal.ir; 12.6 12.7 -import jdk.nashorn.internal.codegen.types.Type; 12.8 import jdk.nashorn.internal.ir.annotations.Immutable; 12.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 12.10 12.11 @@ -46,12 +45,12 @@ 12.12 * @param property property 12.13 */ 12.14 public AccessNode(final long token, final int finish, final Expression base, final IdentNode property) { 12.15 - super(token, finish, base, false, false); 12.16 + super(token, finish, base, false); 12.17 this.property = property.setIsPropertyName(); 12.18 } 12.19 12.20 - private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction, final boolean hasCallSiteType) { 12.21 - super(accessNode, base, isFunction, hasCallSiteType); 12.22 + private AccessNode(final AccessNode accessNode, final Expression base, final IdentNode property, final boolean isFunction) { 12.23 + super(accessNode, base, isFunction); 12.24 this.property = property; 12.25 } 12.26 12.27 @@ -73,13 +72,6 @@ 12.28 public void toString(final StringBuilder sb) { 12.29 final boolean needsParen = tokenType().needsParens(getBase().tokenType(), true); 12.30 12.31 - if (hasCallSiteType()) { 12.32 - sb.append('{'); 12.33 - final String desc = getType().getDescriptor(); 12.34 - sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 12.35 - sb.append('}'); 12.36 - } 12.37 - 12.38 if (needsParen) { 12.39 sb.append('('); 12.40 } 12.41 @@ -107,21 +99,14 @@ 12.42 if (this.base == base) { 12.43 return this; 12.44 } 12.45 - return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); 12.46 + return new AccessNode(this, base, property, isFunction()); 12.47 } 12.48 12.49 private AccessNode setProperty(final IdentNode property) { 12.50 if (this.property == property) { 12.51 return this; 12.52 } 12.53 - return new AccessNode(this, base, property, isFunction(), hasCallSiteType()); 12.54 - } 12.55 - 12.56 - @Override 12.57 - public AccessNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 12.58 - logTypeChange(type); 12.59 - final AccessNode newAccessNode = (AccessNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts)); 12.60 - return new AccessNode(newAccessNode, base, property.setType(ts, lc, type), isFunction(), hasCallSiteType()); 12.61 + return new AccessNode(this, base, property, isFunction()); 12.62 } 12.63 12.64 @Override 12.65 @@ -129,7 +114,7 @@ 12.66 if (isFunction()) { 12.67 return this; 12.68 } 12.69 - return new AccessNode(this, base, property, true, hasCallSiteType()); 12.70 + return new AccessNode(this, base, property, true); 12.71 } 12.72 12.73 }
13.1 --- a/src/jdk/nashorn/internal/ir/BaseNode.java Wed Oct 09 14:50:39 2013 +0200 13.2 +++ b/src/jdk/nashorn/internal/ir/BaseNode.java Wed Oct 09 17:53:22 2013 +0200 13.3 @@ -25,10 +25,6 @@ 13.4 13.5 package jdk.nashorn.internal.ir; 13.6 13.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; 13.8 - 13.9 -import jdk.nashorn.internal.codegen.ObjectClassGenerator; 13.10 -import jdk.nashorn.internal.codegen.types.Type; 13.11 import jdk.nashorn.internal.ir.annotations.Immutable; 13.12 13.13 /** 13.14 @@ -38,15 +34,13 @@ 13.15 * @see IndexNode 13.16 */ 13.17 @Immutable 13.18 -public abstract class BaseNode extends Expression implements FunctionCall, TypeOverride<BaseNode> { 13.19 +public abstract class BaseNode extends Expression implements FunctionCall { 13.20 13.21 /** Base Node. */ 13.22 protected final Expression base; 13.23 13.24 private final boolean isFunction; 13.25 13.26 - private final boolean hasCallSiteType; 13.27 - 13.28 /** 13.29 * Constructor 13.30 * 13.31 @@ -54,13 +48,11 @@ 13.32 * @param finish finish 13.33 * @param base base node 13.34 * @param isFunction is this a function 13.35 - * @param hasCallSiteType does this access have a callsite type 13.36 */ 13.37 - public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean hasCallSiteType) { 13.38 + public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) { 13.39 super(token, base.getStart(), finish); 13.40 this.base = base; 13.41 this.isFunction = isFunction; 13.42 - this.hasCallSiteType = hasCallSiteType; 13.43 } 13.44 13.45 /** 13.46 @@ -68,13 +60,11 @@ 13.47 * @param baseNode node to inherit from 13.48 * @param base base 13.49 * @param isFunction is this a function 13.50 - * @param hasCallSiteType does this access have a callsite type 13.51 */ 13.52 - protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final boolean hasCallSiteType) { 13.53 + protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction) { 13.54 super(baseNode); 13.55 this.base = base; 13.56 this.isFunction = isFunction; 13.57 - this.hasCallSiteType = hasCallSiteType; 13.58 } 13.59 13.60 /** 13.61 @@ -96,26 +86,4 @@ 13.62 */ 13.63 public abstract BaseNode setIsFunction(); 13.64 13.65 - @Override 13.66 - public boolean canHaveCallSiteType() { 13.67 - return true; //carried by the symbol and always the same nodetype==symboltype 13.68 - } 13.69 - 13.70 - /** 13.71 - * Does the access have a call site type override? 13.72 - * @return true if overridden 13.73 - */ 13.74 - protected boolean hasCallSiteType() { 13.75 - return hasCallSiteType; 13.76 - } 13.77 - 13.78 - /** 13.79 - * Debug type change 13.80 - * @param type new type 13.81 - */ 13.82 - protected final void logTypeChange(final Type type) { 13.83 - if (DEBUG_FIELDS && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 13.84 - ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType()); 13.85 - } 13.86 - } 13.87 }
14.1 --- a/src/jdk/nashorn/internal/ir/CallNode.java Wed Oct 09 14:50:39 2013 +0200 14.2 +++ b/src/jdk/nashorn/internal/ir/CallNode.java Wed Oct 09 17:53:22 2013 +0200 14.3 @@ -36,9 +36,7 @@ 14.4 * IR representation for a function call. 14.5 */ 14.6 @Immutable 14.7 -public final class CallNode extends LexicalContextExpression implements TypeOverride<CallNode> { 14.8 - 14.9 - private final Type type; 14.10 +public final class CallNode extends LexicalContextExpression { 14.11 14.12 /** Function identifier or function body. */ 14.13 private final Expression function; 14.14 @@ -150,18 +148,16 @@ 14.15 this.function = function; 14.16 this.args = args; 14.17 this.flags = 0; 14.18 - this.type = null; 14.19 this.evalArgs = null; 14.20 this.lineNumber = lineNumber; 14.21 } 14.22 14.23 - private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final Type type, final EvalArgs evalArgs) { 14.24 + private CallNode(final CallNode callNode, final Expression function, final List<Expression> args, final int flags, final EvalArgs evalArgs) { 14.25 super(callNode); 14.26 this.lineNumber = callNode.lineNumber; 14.27 this.function = function; 14.28 this.args = args; 14.29 this.flags = flags; 14.30 - this.type = type; 14.31 this.evalArgs = evalArgs; 14.32 } 14.33 14.34 @@ -175,29 +171,9 @@ 14.35 14.36 @Override 14.37 public Type getType() { 14.38 - if (hasCallSiteType()) { 14.39 - return type; 14.40 - } 14.41 return function instanceof FunctionNode ? ((FunctionNode)function).getReturnType() : Type.OBJECT; 14.42 } 14.43 14.44 - @Override 14.45 - public CallNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 14.46 - if (this.type == type) { 14.47 - return this; 14.48 - } 14.49 - return new CallNode(this, function, args, flags, type, evalArgs); 14.50 - } 14.51 - 14.52 - private boolean hasCallSiteType() { 14.53 - return this.type != null; 14.54 - } 14.55 - 14.56 - @Override 14.57 - public boolean canHaveCallSiteType() { 14.58 - return true; 14.59 - } 14.60 - 14.61 /** 14.62 * Assist in IR navigation. 14.63 * 14.64 @@ -212,7 +188,6 @@ 14.65 setFunction((Expression)function.accept(visitor)). 14.66 setArgs(Node.accept(visitor, Expression.class, args)). 14.67 setFlags(flags). 14.68 - setType(null, lc, type). 14.69 setEvalArgs(evalArgs == null ? 14.70 null : 14.71 evalArgs.setCode((Expression)evalArgs.getCode().accept(visitor)). 14.72 @@ -229,13 +204,6 @@ 14.73 14.74 @Override 14.75 public void toString(final StringBuilder sb) { 14.76 - if (hasCallSiteType()) { 14.77 - sb.append('{'); 14.78 - final String desc = getType().getDescriptor(); 14.79 - sb.append(desc.charAt(desc.length() - 1) == ';' ? 'O' : getType().getDescriptor()); 14.80 - sb.append('}'); 14.81 - } 14.82 - 14.83 function.toString(sb); 14.84 14.85 sb.append('('); 14.86 @@ -271,7 +239,7 @@ 14.87 if (this.args == args) { 14.88 return this; 14.89 } 14.90 - return new CallNode(this, function, args, flags, type, evalArgs); 14.91 + return new CallNode(this, function, args, flags, evalArgs); 14.92 } 14.93 14.94 /** 14.95 @@ -293,7 +261,7 @@ 14.96 if (this.evalArgs == evalArgs) { 14.97 return this; 14.98 } 14.99 - return new CallNode(this, function, args, flags, type, evalArgs); 14.100 + return new CallNode(this, function, args, flags, evalArgs); 14.101 } 14.102 14.103 /** 14.104 @@ -321,7 +289,7 @@ 14.105 if (this.function == function) { 14.106 return this; 14.107 } 14.108 - return new CallNode(this, function, args, flags, type, evalArgs); 14.109 + return new CallNode(this, function, args, flags, evalArgs); 14.110 } 14.111 14.112 /** 14.113 @@ -344,6 +312,6 @@ 14.114 if (this.flags == flags) { 14.115 return this; 14.116 } 14.117 - return new CallNode(this, function, args, flags, type, evalArgs); 14.118 + return new CallNode(this, function, args, flags, evalArgs); 14.119 } 14.120 }
15.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java Wed Oct 09 14:50:39 2013 +0200 15.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Wed Oct 09 17:53:22 2013 +0200 15.3 @@ -28,9 +28,7 @@ 15.4 import static jdk.nashorn.internal.codegen.CompilerConstants.__DIR__; 15.5 import static jdk.nashorn.internal.codegen.CompilerConstants.__FILE__; 15.6 import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__; 15.7 -import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS; 15.8 15.9 -import jdk.nashorn.internal.codegen.ObjectClassGenerator; 15.10 import jdk.nashorn.internal.codegen.types.Type; 15.11 import jdk.nashorn.internal.ir.annotations.Immutable; 15.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 15.13 @@ -39,7 +37,7 @@ 15.14 * IR representation for an identifier. 15.15 */ 15.16 @Immutable 15.17 -public final class IdentNode extends Expression implements PropertyKey, TypeOverride<IdentNode>, FunctionCall { 15.18 +public final class IdentNode extends Expression implements PropertyKey, FunctionCall { 15.19 private static final int PROPERTY_NAME = 1 << 0; 15.20 private static final int INITIALIZED_HERE = 1 << 1; 15.21 private static final int FUNCTION = 1 << 2; 15.22 @@ -101,19 +99,6 @@ 15.23 return callSiteType != null; 15.24 } 15.25 15.26 - @Override 15.27 - public IdentNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 15.28 - // do NOT, repeat NOT touch the symbol here. it might be a local variable or whatever. This is the override if it isn't 15.29 - if (this.callSiteType == type) { 15.30 - return this; 15.31 - } 15.32 - if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), type)) { 15.33 - ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", type, " instead of ", getType()); 15.34 - } 15.35 - 15.36 - return new IdentNode(this, name, type, flags); 15.37 - } 15.38 - 15.39 /** 15.40 * Assist in IR navigation. 15.41 * 15.42 @@ -154,31 +139,6 @@ 15.43 } 15.44 15.45 /** 15.46 - * We can only override type if the symbol lives in the scope, as otherwise 15.47 - * it is strongly determined by the local variable already allocated. 15.48 - * 15.49 - * <p>We also return true if the symbol represents the return value of a function with a 15.50 - * non-generic return type as in this case we need to propagate the type instead of 15.51 - * converting to object, for example if the symbol is used as the left hand side of an 15.52 - * assignment such as in the code below.</p> 15.53 - * 15.54 - * <pre> 15.55 - * try { 15.56 - * return 2; 15.57 - * } finally { 15.58 - * return 3; 15.59 - * } 15.60 - * } 15.61 - * </pre> 15.62 - * 15.63 - * @return true if can have callsite type 15.64 - */ 15.65 - @Override 15.66 - public boolean canHaveCallSiteType() { 15.67 - return getSymbol() != null && (getSymbol().isScope() || getSymbol().isNonGenericReturn()); 15.68 - } 15.69 - 15.70 - /** 15.71 * Check if this IdentNode is a property name 15.72 * @return true if this is a property name 15.73 */
16.1 --- a/src/jdk/nashorn/internal/ir/IndexNode.java Wed Oct 09 14:50:39 2013 +0200 16.2 +++ b/src/jdk/nashorn/internal/ir/IndexNode.java Wed Oct 09 17:53:22 2013 +0200 16.3 @@ -25,7 +25,6 @@ 16.4 16.5 package jdk.nashorn.internal.ir; 16.6 16.7 -import jdk.nashorn.internal.codegen.types.Type; 16.8 import jdk.nashorn.internal.ir.annotations.Immutable; 16.9 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 16.10 16.11 @@ -46,12 +45,12 @@ 16.12 * @param index index for access 16.13 */ 16.14 public IndexNode(final long token, final int finish, final Expression base, final Expression index) { 16.15 - super(token, finish, base, false, false); 16.16 + super(token, finish, base, false); 16.17 this.index = index; 16.18 } 16.19 16.20 - private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final boolean hasCallSiteType) { 16.21 - super(indexNode, base, isFunction, hasCallSiteType); 16.22 + private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction) { 16.23 + super(indexNode, base, isFunction); 16.24 this.index = index; 16.25 } 16.26 16.27 @@ -69,13 +68,6 @@ 16.28 public void toString(final StringBuilder sb) { 16.29 final boolean needsParen = tokenType().needsParens(base.tokenType(), true); 16.30 16.31 - if (hasCallSiteType()) { 16.32 - sb.append('{'); 16.33 - final String desc = getType().getDescriptor(); 16.34 - sb.append(desc.charAt(desc.length() - 1) == ';' ? "O" : getType().getDescriptor()); 16.35 - sb.append('}'); 16.36 - } 16.37 - 16.38 if (needsParen) { 16.39 sb.append('('); 16.40 } 16.41 @@ -103,7 +95,7 @@ 16.42 if (this.base == base) { 16.43 return this; 16.44 } 16.45 - return new IndexNode(this, base, index, isFunction(), hasCallSiteType()); 16.46 + return new IndexNode(this, base, index, isFunction()); 16.47 } 16.48 16.49 /** 16.50 @@ -115,7 +107,7 @@ 16.51 if(this.index == index) { 16.52 return this; 16.53 } 16.54 - return new IndexNode(this, base, index, isFunction(), hasCallSiteType()); 16.55 + return new IndexNode(this, base, index, isFunction()); 16.56 } 16.57 16.58 @Override 16.59 @@ -123,14 +115,7 @@ 16.60 if (isFunction()) { 16.61 return this; 16.62 } 16.63 - return new IndexNode(this, base, index, true, hasCallSiteType()); 16.64 - } 16.65 - 16.66 - @Override 16.67 - public IndexNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 16.68 - logTypeChange(type); 16.69 - final IndexNode newIndexNode = (IndexNode)setSymbol(lc, getSymbol().setTypeOverrideShared(type, ts)); 16.70 - return new IndexNode(newIndexNode, base, index, isFunction(), true); 16.71 + return new IndexNode(this, base, index, true); 16.72 } 16.73 16.74 }
17.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Wed Oct 09 14:50:39 2013 +0200 17.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Wed Oct 09 17:53:22 2013 +0200 17.3 @@ -28,10 +28,13 @@ 17.4 import java.util.Arrays; 17.5 import java.util.Collections; 17.6 import java.util.List; 17.7 + 17.8 import jdk.nashorn.internal.codegen.CompileUnit; 17.9 +import jdk.nashorn.internal.codegen.types.ArrayType; 17.10 import jdk.nashorn.internal.codegen.types.Type; 17.11 import jdk.nashorn.internal.ir.annotations.Immutable; 17.12 import jdk.nashorn.internal.ir.visitor.NodeVisitor; 17.13 +import jdk.nashorn.internal.objects.NativeArray; 17.14 import jdk.nashorn.internal.parser.Lexer.LexerToken; 17.15 import jdk.nashorn.internal.parser.Token; 17.16 import jdk.nashorn.internal.parser.TokenType; 17.17 @@ -526,12 +529,6 @@ 17.18 return object; 17.19 } else if (object instanceof LiteralNode) { 17.20 return objectAsConstant(((LiteralNode<?>)object).getValue()); 17.21 - } else if (object instanceof UnaryNode) { 17.22 - final UnaryNode unaryNode = (UnaryNode)object; 17.23 - 17.24 - if (unaryNode.isTokenType(TokenType.CONVERT) && unaryNode.getType().isObject()) { 17.25 - return objectAsConstant(unaryNode.rhs()); 17.26 - } 17.27 } 17.28 17.29 return POSTSET_MARKER; 17.30 @@ -782,8 +779,7 @@ 17.31 return value; 17.32 } 17.33 17.34 - @Override 17.35 - public Type getType() { 17.36 + public ArrayType getArrayType() { 17.37 if (elementType.isInteger()) { 17.38 return Type.INT_ARRAY; 17.39 } else if (elementType.isLong()) { 17.40 @@ -795,6 +791,11 @@ 17.41 } 17.42 } 17.43 17.44 + @Override 17.45 + public Type getType() { 17.46 + return Type.typeFor(NativeArray.class); 17.47 + } 17.48 + 17.49 /** 17.50 * Get the element type of this array literal 17.51 * @return element type
18.1 --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Oct 09 14:50:39 2013 +0200 18.2 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Oct 09 17:53:22 2013 +0200 18.3 @@ -38,7 +38,7 @@ 18.4 * IR representation for a runtime call. 18.5 */ 18.6 @Immutable 18.7 -public class RuntimeNode extends Expression implements TypeOverride<RuntimeNode> { 18.8 +public class RuntimeNode extends Expression { 18.9 18.10 /** 18.11 * Request enum used for meta-information about the runtime request 18.12 @@ -159,6 +159,36 @@ 18.13 } 18.14 18.15 /** 18.16 + * Derive a runtime node request type for a node 18.17 + * @param node the node 18.18 + * @return request type 18.19 + */ 18.20 + public static Request requestFor(final Node node) { 18.21 + assert node.isComparison(); 18.22 + switch (node.tokenType()) { 18.23 + case EQ_STRICT: 18.24 + return Request.EQ_STRICT; 18.25 + case NE_STRICT: 18.26 + return Request.NE_STRICT; 18.27 + case EQ: 18.28 + return Request.EQ; 18.29 + case NE: 18.30 + return Request.NE; 18.31 + case LT: 18.32 + return Request.LT; 18.33 + case LE: 18.34 + return Request.LE; 18.35 + case GT: 18.36 + return Request.GT; 18.37 + case GE: 18.38 + return Request.GE; 18.39 + default: 18.40 + assert false; 18.41 + return null; 18.42 + } 18.43 + } 18.44 + 18.45 + /** 18.46 * Is this an EQ or EQ_STRICT? 18.47 * 18.48 * @param request a request 18.49 @@ -268,9 +298,6 @@ 18.50 /** Call arguments. */ 18.51 private final List<Expression> args; 18.52 18.53 - /** Call site override - e.g. we know that a ScriptRuntime.ADD will return an int */ 18.54 - private final Type callSiteType; 18.55 - 18.56 /** is final - i.e. may not be removed again, lower in the code pipeline */ 18.57 private final boolean isFinal; 18.58 18.59 @@ -287,16 +314,14 @@ 18.60 18.61 this.request = request; 18.62 this.args = args; 18.63 - this.callSiteType = null; 18.64 this.isFinal = false; 18.65 } 18.66 18.67 - private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final Type callSiteType, final boolean isFinal, final List<Expression> args) { 18.68 + private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final boolean isFinal, final List<Expression> args) { 18.69 super(runtimeNode); 18.70 18.71 this.request = request; 18.72 this.args = args; 18.73 - this.callSiteType = callSiteType; 18.74 this.isFinal = isFinal; 18.75 } 18.76 18.77 @@ -335,7 +360,6 @@ 18.78 18.79 this.request = request; 18.80 this.args = args; 18.81 - this.callSiteType = null; 18.82 this.isFinal = false; 18.83 } 18.84 18.85 @@ -376,7 +400,7 @@ 18.86 if (this.isFinal == isFinal) { 18.87 return this; 18.88 } 18.89 - return new RuntimeNode(this, request, callSiteType, isFinal, args); 18.90 + return new RuntimeNode(this, request, isFinal, args); 18.91 } 18.92 18.93 /** 18.94 @@ -384,24 +408,7 @@ 18.95 */ 18.96 @Override 18.97 public Type getType() { 18.98 - return hasCallSiteType() ? callSiteType : request.getReturnType(); 18.99 - } 18.100 - 18.101 - @Override 18.102 - public RuntimeNode setType(final TemporarySymbols ts, final LexicalContext lc, final Type type) { 18.103 - if (this.callSiteType == type) { 18.104 - return this; 18.105 - } 18.106 - return new RuntimeNode(this, request, type, isFinal, args); 18.107 - } 18.108 - 18.109 - @Override 18.110 - public boolean canHaveCallSiteType() { 18.111 - return request == Request.ADD; 18.112 - } 18.113 - 18.114 - private boolean hasCallSiteType() { 18.115 - return callSiteType != null; 18.116 + return request.getReturnType(); 18.117 } 18.118 18.119 @Override 18.120 @@ -450,7 +457,7 @@ 18.121 if (this.args == args) { 18.122 return this; 18.123 } 18.124 - return new RuntimeNode(this, request, callSiteType, isFinal, args); 18.125 + return new RuntimeNode(this, request, isFinal, args); 18.126 } 18.127 18.128 /**
19.1 --- a/src/jdk/nashorn/internal/ir/TypeOverride.java Wed Oct 09 14:50:39 2013 +0200 19.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 19.3 @@ -1,62 +0,0 @@ 19.4 -/* 19.5 - * Copyright (c) 2010, 2013, 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. Oracle designates this 19.11 - * particular file as subject to the "Classpath" exception as provided 19.12 - * by Oracle in the LICENSE file that accompanied this code. 19.13 - * 19.14 - * This code is distributed in the hope that it will be useful, but WITHOUT 19.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 19.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 19.17 - * version 2 for more details (a copy is included in the LICENSE file that 19.18 - * accompanied this code). 19.19 - * 19.20 - * You should have received a copy of the GNU General Public License version 19.21 - * 2 along with this work; if not, write to the Free Software Foundation, 19.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19.23 - * 19.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19.25 - * or visit www.oracle.com if you need additional information or have any 19.26 - * questions. 19.27 - */ 19.28 - 19.29 -package jdk.nashorn.internal.ir; 19.30 - 19.31 -import jdk.nashorn.internal.codegen.types.Type; 19.32 - 19.33 -/** 19.34 - * A type override makes it possible to change the return type of a node, if we know 19.35 - * that the linker can provide it directly. For example, an identity node that is 19.36 - * in the scope, can very well look like an object to the compiler of the method it 19.37 - * is in, but if someone does (int)x, it make senses to ask for it directly 19.38 - * with an int getter instead of loading it as an object and explicitly converting it 19.39 - * by using JSType.toInt32. Especially in scenarios where the field is already stored 19.40 - * as a primitive, this will be much faster than the "object is all I see" scope 19.41 - * available in the method 19.42 - * @param <T> the type of the node implementing the interface 19.43 - */ 19.44 - 19.45 -public interface TypeOverride<T extends Node> { 19.46 - /** 19.47 - * Set the override type 19.48 - * 19.49 - * @param ts temporary symbols 19.50 - * @param lc the current lexical context 19.51 - * @param type the type 19.52 - * @return a node equivalent to this one except for the requested change. 19.53 - */ 19.54 - public T setType(final TemporarySymbols ts, final LexicalContext lc, final Type type); 19.55 - 19.56 - /** 19.57 - * Returns true if this node can have a callsite override, e.g. all scope ident nodes 19.58 - * which lead to dynamic getters can have it, local variable nodes (slots) can't. 19.59 - * Call nodes can have it unconditionally and so on 19.60 - * 19.61 - * @return true if it is possible to assign a type override to this node 19.62 - */ 19.63 - public boolean canHaveCallSiteType(); 19.64 - 19.65 -}
20.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Wed Oct 09 14:50:39 2013 +0200 20.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Wed Oct 09 17:53:22 2013 +0200 20.3 @@ -26,7 +26,6 @@ 20.4 package jdk.nashorn.internal.ir; 20.5 20.6 import static jdk.nashorn.internal.parser.TokenType.BIT_NOT; 20.7 -import static jdk.nashorn.internal.parser.TokenType.CONVERT; 20.8 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX; 20.9 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX; 20.10 20.11 @@ -150,19 +149,10 @@ 20.12 final TokenType type = tokenType(); 20.13 final String name = type.getName(); 20.14 final boolean isPostfix = type == DECPOSTFIX || type == INCPOSTFIX; 20.15 - final boolean isConvert = type == CONVERT && getSymbol() != null; 20.16 20.17 boolean rhsParen = type.needsParens(rhs().tokenType(), false); 20.18 - int convertPos = 0; 20.19 20.20 - if (isConvert) { 20.21 - convertPos = sb.length(); 20.22 - sb.append("("); 20.23 - sb.append(getType()); 20.24 - sb.append(")("); 20.25 - } 20.26 - 20.27 - if (!isPostfix && !isConvert) { 20.28 + if (!isPostfix) { 20.29 if (name == null) { 20.30 sb.append(type.name()); 20.31 rhsParen = true; 20.32 @@ -186,16 +176,6 @@ 20.33 if (isPostfix) { 20.34 sb.append(type == DECPOSTFIX ? "--" : "++"); 20.35 } 20.36 - 20.37 - if (isConvert) { 20.38 - // strip extra cast parenthesis which makes the printout harder to read 20.39 - final boolean endsWithParenthesis = sb.charAt(sb.length() - 1) == ')'; 20.40 - if (!endsWithParenthesis) { 20.41 - sb.append(')'); 20.42 - } else { 20.43 - sb.setCharAt(convertPos, ' '); 20.44 - } 20.45 - } 20.46 } 20.47 20.48 /**
21.1 --- a/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed Oct 09 14:50:39 2013 +0200 21.2 +++ b/src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java Wed Oct 09 17:53:22 2013 +0200 21.3 @@ -51,8 +51,6 @@ 21.4 return enterADD(unaryNode); 21.5 case BIT_NOT: 21.6 return enterBIT_NOT(unaryNode); 21.7 - case CONVERT: 21.8 - return enterCONVERT(unaryNode); 21.9 case DELETE: 21.10 return enterDELETE(unaryNode); 21.11 case DISCARD: 21.12 @@ -84,8 +82,6 @@ 21.13 return leaveADD(unaryNode); 21.14 case BIT_NOT: 21.15 return leaveBIT_NOT(unaryNode); 21.16 - case CONVERT: 21.17 - return leaveCONVERT(unaryNode); 21.18 case DELETE: 21.19 return leaveDELETE(unaryNode); 21.20 case DISCARD: 21.21 @@ -323,26 +319,6 @@ 21.22 } 21.23 21.24 /** 21.25 - * Unary enter - callback for entering a conversion 21.26 - * 21.27 - * @param unaryNode the node 21.28 - * @return true if traversal should continue and node children be traversed, false otherwise 21.29 - */ 21.30 - public boolean enterCONVERT(final UnaryNode unaryNode) { 21.31 - return enterDefault(unaryNode); 21.32 - } 21.33 - 21.34 - /** 21.35 - * Unary leave - callback for leaving a conversion 21.36 - * 21.37 - * @param unaryNode the node 21.38 - * @return processed node, which will replace the original one, or the original node 21.39 - */ 21.40 - public Node leaveCONVERT(final UnaryNode unaryNode) { 21.41 - return leaveDefault(unaryNode); 21.42 - } 21.43 - 21.44 - /** 21.45 * Unary enter - callback for entering a ++ or -- operator 21.46 * 21.47 * @param unaryNode the node
22.1 --- a/src/jdk/nashorn/internal/parser/TokenType.java Wed Oct 09 14:50:39 2013 +0200 22.2 +++ b/src/jdk/nashorn/internal/parser/TokenType.java Wed Oct 09 17:53:22 2013 +0200 22.3 @@ -178,7 +178,6 @@ 22.4 ARRAY (LITERAL, null), 22.5 22.6 COMMALEFT (IR, null), 22.7 - CONVERT (IR, null), 22.8 DISCARD (IR, null), 22.9 DECPOSTFIX (IR, null), 22.10 INCPOSTFIX (IR, null);
23.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Wed Oct 09 14:50:39 2013 +0200 23.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Wed Oct 09 17:53:22 2013 +0200 23.3 @@ -625,11 +625,11 @@ 23.4 * @param clazz Class object 23.5 * @throw SecurityException if not accessible 23.6 */ 23.7 - public static void checkPackageAccess(final Class clazz) { 23.8 + public static void checkPackageAccess(final Class<?> clazz) { 23.9 final SecurityManager sm = System.getSecurityManager(); 23.10 if (sm != null) { 23.11 - Class bottomClazz = clazz; 23.12 - while(bottomClazz.isArray()) { 23.13 + Class<?> bottomClazz = clazz; 23.14 + while (bottomClazz.isArray()) { 23.15 bottomClazz = bottomClazz.getComponentType(); 23.16 } 23.17 checkPackageAccess(sm, bottomClazz.getName()); 23.18 @@ -664,7 +664,7 @@ 23.19 * @param clazz Class object 23.20 * @return true if package is accessible, false otherwise 23.21 */ 23.22 - private static boolean isAccessiblePackage(final Class clazz) { 23.23 + private static boolean isAccessiblePackage(final Class<?> clazz) { 23.24 try { 23.25 checkPackageAccess(clazz); 23.26 return true; 23.27 @@ -838,7 +838,7 @@ 23.28 return Context.getContextTrusted(); 23.29 } 23.30 23.31 - private URL getResourceURL(final String resName) throws IOException { 23.32 + private URL getResourceURL(final String resName) { 23.33 // try the classPathLoader if we have and then 23.34 // try the appLoader if non-null. 23.35 if (classPathLoader != null) {
24.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java Wed Oct 09 14:50:39 2013 +0200 24.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Wed Oct 09 17:53:22 2013 +0200 24.3 @@ -104,14 +104,11 @@ 24.4 /** JavaScript compliant conversion function from number to int64 */ 24.5 public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class); 24.6 24.7 - /** JavaScript compliant conversion function from Object to String */ 24.8 - public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class); 24.9 - 24.10 /** JavaScript compliant conversion function from number to String */ 24.11 public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class); 24.12 24.13 - /** JavaScript compliant conversion function from Object to primitive */ 24.14 - public static final Call TO_PRIMITIVE = staticCall(myLookup, JSType.class, "toPrimitive", Object.class, Object.class); 24.15 + /** Combined call to toPrimitive followed by toString. */ 24.16 + public static final Call TO_PRIMITIVE_TO_STRING = staticCall(myLookup, JSType.class, "toPrimitiveToString", String.class, Object.class); 24.17 24.18 private static final double INT32_LIMIT = 4294967296.0; 24.19 24.20 @@ -273,6 +270,17 @@ 24.21 } 24.22 24.23 /** 24.24 + * Combines a hintless toPrimitive and a toString call. 24.25 + * 24.26 + * @param obj an object 24.27 + * 24.28 + * @return the string form of the primitive form of the object 24.29 + */ 24.30 + public static String toPrimitiveToString(Object obj) { 24.31 + return toString(toPrimitive(obj)); 24.32 + } 24.33 + 24.34 + /** 24.35 * JavaScript compliant conversion of number to boolean 24.36 * 24.37 * @param num a number 24.38 @@ -874,7 +882,7 @@ 24.39 if (obj instanceof ScriptObject) { 24.40 return convertArray(((ScriptObject)obj).getArray().asObjectArray(), componentType); 24.41 } else if (obj instanceof JSObject) { 24.42 - final ArrayLikeIterator itr = ArrayLikeIterator.arrayLikeIterator(obj); 24.43 + final ArrayLikeIterator<?> itr = ArrayLikeIterator.arrayLikeIterator(obj); 24.44 final int len = (int) itr.getLength(); 24.45 final Object[] res = new Object[len]; 24.46 int idx = 0;
25.1 --- a/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java Wed Oct 09 14:50:39 2013 +0200 25.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java Wed Oct 09 17:53:22 2013 +0200 25.3 @@ -77,4 +77,4 @@ 25.4 public void remove() { 25.5 throw new UnsupportedOperationException("remove"); 25.6 } 25.7 -} 25.8 \ No newline at end of file 25.9 +}
26.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java Wed Oct 09 14:50:39 2013 +0200 26.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java Wed Oct 09 17:53:22 2013 +0200 26.3 @@ -55,4 +55,4 @@ 26.4 protected long bumpIndex() { 26.5 return index--; 26.6 } 26.7 -} 26.8 \ No newline at end of file 26.9 +}
27.1 --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Oct 09 14:50:39 2013 +0200 27.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Oct 09 17:53:22 2013 +0200 27.3 @@ -140,7 +140,7 @@ 27.4 @SuppressWarnings("unused") 27.5 private static Object get(final Object jsobj, final Object key) { 27.6 if (key instanceof Integer) { 27.7 - return ((JSObject)jsobj).getSlot((int)(Integer)key); 27.8 + return ((JSObject)jsobj).getSlot((Integer)key); 27.9 } else if (key instanceof Number) { 27.10 final int index = getIndex((Number)key); 27.11 if (index > -1) { 27.12 @@ -155,7 +155,7 @@ 27.13 @SuppressWarnings("unused") 27.14 private static void put(final Object jsobj, final Object key, final Object value) { 27.15 if (key instanceof Integer) { 27.16 - ((JSObject)jsobj).setSlot((int)(Integer)key, value); 27.17 + ((JSObject)jsobj).setSlot((Integer)key, value); 27.18 } else if (key instanceof Number) { 27.19 ((JSObject)jsobj).setSlot(getIndex((Number)key), value); 27.20 } else if (key instanceof String) {
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 28.2 +++ b/test/script/basic/JDK-8026137.js Wed Oct 09 17:53:22 2013 +0200 28.3 @@ -0,0 +1,44 @@ 28.4 +/* 28.5 + * Copyright (c) 2010, 2013, 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-8026137: Binary evaluation order in JavaScript is load load 28.29 + * convert convert, not load convert load convert. 28.30 + * 28.31 + * @test 28.32 + * @run 28.33 + */ 28.34 + 28.35 +try { 28.36 + (function f() { Object.defineProperty({},"x",{get: function(){return {valueOf:function(){throw 0}}}}).x - Object.defineProperty({},"x",{get: function(){throw 1}}).x })() 28.37 +} 28.38 +catch (e) { 28.39 + print(e); 28.40 +} 28.41 + 28.42 +try { 28.43 + ({valueOf: function(){throw 0}}) - ({valueOf: function(){throw 1}} - 1) 28.44 +} catch (e) { 28.45 + print(e); 28.46 +} 28.47 +
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 29.2 +++ b/test/script/basic/JDK-8026137.js.EXPECTED Wed Oct 09 17:53:22 2013 +0200 29.3 @@ -0,0 +1,2 @@ 29.4 +1 29.5 +1