8026137: Fix Issues with Binary Evaluation Order

Wed, 09 Oct 2013 17:53:22 +0200

author
lagergren
date
Wed, 09 Oct 2013 17:53:22 +0200
changeset 605
03a68e7ca1d5
parent 604
ec3094d9d5d5
child 606
7cc5ff16380f

8026137: Fix Issues with Binary Evaluation Order
Reviewed-by: hannesw, jlaskey
Contributed-by: marcus.lagergren@oracle.com, attila.szegedi@oracle.com

src/jdk/nashorn/internal/codegen/Attr.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/BranchOptimizer.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/CompileUnit.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/Compiler.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/FinalizeTypes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/MethodEmitter.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/WeighNodes.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/BooleanType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/ObjectType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/Type.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/AccessNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/BaseNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/CallNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/IdentNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/IndexNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/LiteralNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/RuntimeNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/TypeOverride.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/UnaryNode.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/parser/TokenType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/JSType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java file | annotate | diff | comparison | revisions
test/script/basic/JDK-8026137.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8026137.js.EXPECTED file | annotate | diff | comparison | revisions
     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

mercurial