changeset 1238:a9229fb1634b

Merge
author lana
date Thu, 12 Mar 2015 13:45:00 -0700
parents 80966e5cc384 965aae6772f1
children 4ba23f4c0ed6
files src/jdk/nashorn/internal/codegen/RuntimeCallSite.java
diffstat 48 files changed, 2381 insertions(+), 1198 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk/nashorn/api/scripting/AbstractJSObject.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/api/scripting/AbstractJSObject.java	Thu Mar 12 13:45:00 2015 -0700
@@ -28,6 +28,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
+import jdk.nashorn.internal.runtime.JSType;
 
 /**
  * This is the base class for nashorn ScriptObjectMirror class.
@@ -161,9 +162,8 @@
      * @return set of property names
      */
     @Override
-    @SuppressWarnings("unchecked")
     public Set<String> keySet() {
-        return Collections.EMPTY_SET;
+        return Collections.emptySet();
     }
 
     /**
@@ -172,9 +172,8 @@
      * @return set of property values.
      */
     @Override
-    @SuppressWarnings("unchecked")
     public Collection<Object> values() {
-        return Collections.EMPTY_SET;
+        return Collections.emptySet();
     }
 
     // JavaScript instanceof check
@@ -249,9 +248,41 @@
      * Returns this object's numeric value.
      *
      * @return this object's numeric value.
+     * @deprecated use {@link #getDefaultValue(Class)} with {@link Number} hint instead.
      */
-    @Override
+    @Override @Deprecated
     public double toNumber() {
-        return Double.NaN;
+        return JSType.toNumber(JSType.toPrimitive(this, Number.class));
+    }
+
+    /**
+     * Implements this object's {@code [[DefaultValue]]} method. The default implementation follows ECMAScript 5.1
+     * section 8.6.2 but subclasses are free to provide their own implementations.
+     *
+     * @param hint the type hint. Should be either {@code null}, {@code Number.class} or {@code String.class}.
+     * @return this object's default value.
+     * @throws UnsupportedOperationException if the conversion can't be performed. The engine will convert this
+     * exception into a JavaScript {@code TypeError}.
+     */
+    public Object getDefaultValue(final Class<?> hint) {
+        return DefaultValueImpl.getDefaultValue(this, hint);
+    }
+
+    /**
+     * When passed an {@link AbstractJSObject}, invokes its {@link #getDefaultValue(Class)} method. When passed any
+     * other {@link JSObject}, it will obtain its {@code [[DefaultValue]]} method as per ECMAScript 5.1 section
+     * 8.6.2.
+     *
+     * @param jsobj the {@link JSObject} whose {@code [[DefaultValue]]} is obtained.
+     * @param hint the type hint. Should be either {@code null}, {@code Number.class} or {@code String.class}.
+     * @return this object's default value.
+     * @throws UnsupportedOperationException if the conversion can't be performed. The engine will convert this
+     * exception into a JavaScript {@code TypeError}.
+     */
+    public static Object getDefaultValue(final JSObject jsobj, final Class<?> hint) {
+        if (jsobj instanceof AbstractJSObject) {
+            return ((AbstractJSObject)jsobj).getDefaultValue(hint);
+        }
+        return DefaultValueImpl.getDefaultValue(jsobj, hint);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk/nashorn/api/scripting/DefaultValueImpl.java	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api.scripting;
+
+import jdk.nashorn.internal.runtime.JSType;
+
+/**
+ * Default implementation of {@link JSObject#getDefaultValue(Class)}. Isolated into a separate class mostly so
+ * that we can have private static instances of function name arrays, something we couldn't declare without it
+ * being visible in {@link JSObject} interface.
+ */
+class DefaultValueImpl {
+    private static final String[] DEFAULT_VALUE_FNS_NUMBER = new String[] { "valueOf", "toString" };
+    private static final String[] DEFAULT_VALUE_FNS_STRING = new String[] { "toString", "valueOf" };
+
+    static Object getDefaultValue(final JSObject jsobj, final Class<?> hint) throws UnsupportedOperationException {
+        final boolean isNumber = hint == null || hint == Number.class;
+        for(final String methodName: isNumber ? DEFAULT_VALUE_FNS_NUMBER : DEFAULT_VALUE_FNS_STRING) {
+            final Object objMember = jsobj.getMember(methodName);
+            if (objMember instanceof JSObject) {
+                final JSObject member = (JSObject)objMember;
+                if (member.isFunction()) {
+                    final Object value = member.call(jsobj);
+                    if (JSType.isPrimitive(value)) {
+                        return value;
+                    }
+                }
+            }
+        }
+        throw new UnsupportedOperationException(isNumber ? "cannot.get.default.number" : "cannot.get.default.string");
+    }
+}
--- a/src/jdk/nashorn/api/scripting/JSObject.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/api/scripting/JSObject.java	Thu Mar 12 13:45:00 2015 -0700
@@ -186,6 +186,8 @@
      * Returns this object's numeric value.
      *
      * @return this object's numeric value.
+     * @deprecated use {@link AbstractJSObject#getDefaultValue(JSObject, Class)} with {@link Number} hint instead.
      */
+    @Deprecated
     public double toNumber();
 }
--- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Mar 12 13:45:00 2015 -0700
@@ -46,6 +46,7 @@
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ECMAException;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -812,7 +813,7 @@
         }
     }
 
-    @Override
+    @Override @Deprecated
     public double toNumber() {
         return inGlobal(new Callable<Double>() {
             @Override public Double call() {
@@ -820,4 +821,21 @@
             }
         });
     }
+
+    @Override
+    public Object getDefaultValue(final Class<?> hint) {
+        return inGlobal(new Callable<Object>() {
+            @Override public Object call() {
+                try {
+                    return sobj.getDefaultValue(hint);
+                } catch (final ECMAException e) {
+                    // We're catching ECMAException (likely TypeError), and translating it to
+                    // UnsupportedOperationException. This in turn will be translated into TypeError of the
+                    // caller's Global by JSType#toPrimitive(JSObject,Class) therefore ensuring that it's
+                    // recognized as "instanceof TypeError" in the caller.
+                    throw new UnsupportedOperationException(e.getMessage(), e);
+                }
+            }
+        });
+    }
 }
--- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java	Thu Mar 12 13:45:00 2015 -0700
@@ -105,33 +105,33 @@
 
         case EQ:
         case EQ_STRICT:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? EQ : NE, true, label);
             return;
 
         case NE:
         case NE_STRICT:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? NE : EQ, true, label);
             return;
 
         case GE:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? GE : LT, false, label);
             return;
 
         case GT:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? GT : LE, false, label);
             return;
 
         case LE:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? LE : GT, true, label);
             return;
 
         case LT:
-            codegen.loadBinaryOperands(binaryNode);
+            codegen.loadComparisonOperands(binaryNode);
             method.conditionalJump(state ? LT : GE, true, label);
             return;
 
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Thu Mar 12 13:45:00 2015 -0700
@@ -202,6 +202,12 @@
     private static final Call CREATE_FUNCTION_OBJECT_NO_SCOPE = CompilerConstants.staticCallNoLookup(ScriptFunctionImpl.class,
             "create", ScriptFunction.class, Object[].class, int.class);
 
+    private static final Call TO_NUMBER_FOR_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
+            "toNumberForEq", double.class, Object.class);
+    private static final Call TO_NUMBER_FOR_STRICT_EQ = CompilerConstants.staticCallNoLookup(JSType.class,
+            "toNumberForStrictEq", double.class, Object.class);
+
+
     private static final Class<?> ITERATOR_CLASS = Iterator.class;
     static {
         assert ITERATOR_CLASS == CompilerConstants.ITERATOR_PREFIX.type();
@@ -618,6 +624,104 @@
         return method;
     }
 
+    /**
+     * Similar to {@link #loadBinaryOperands(BinaryNode)} but used specifically for loading operands of
+     * relational and equality comparison operators where at least one argument is non-object. (When both
+     * arguments are objects, we use {@link ScriptRuntime#EQ(Object, Object)}, {@link ScriptRuntime#LT(Object, Object)}
+     * etc. methods instead. Additionally, {@code ScriptRuntime} methods are used for strict (in)equality comparison
+     * of a boolean to anything that isn't a boolean.) This method handles the special case where one argument
+     * is an object and another is a primitive. Naively, these could also be delegated to {@code ScriptRuntime} methods
+     * by boxing the primitive. However, in all such cases the comparison is performed on numeric values, so it is
+     * possible to strength-reduce the operation by taking the number value of the object argument instead and
+     * comparing that to the primitive value ("primitive" will always be int, long, double, or boolean, and booleans
+     * compare as ints in these cases, so they're essentially numbers too). This method will emit code for loading
+     * arguments for such strength-reduced comparison. When both arguments are primitives, it just delegates to
+     * {@link #loadBinaryOperands(BinaryNode)}.
+     *
+     * @param cmp the comparison operation for which the operands need to be loaded on stack.
+     * @return the current method emitter.
+     */
+    MethodEmitter loadComparisonOperands(final BinaryNode cmp) {
+        final Expression lhs = cmp.lhs();
+        final Expression rhs = cmp.rhs();
+        final Type lhsType = lhs.getType();
+        final Type rhsType = rhs.getType();
+
+        // Only used when not both are object, for that we have ScriptRuntime.LT etc.
+        assert !(lhsType.isObject() && rhsType.isObject());
+
+        if (lhsType.isObject() || rhsType.isObject()) {
+            // We can reorder CONVERT LEFT and LOAD RIGHT only if either the left is a primitive, or the right
+            // is a local. This is more strict than loadBinaryNode reorder criteria, as it can allow JS primitive
+            // types too (notably: String is a JS primitive, but not a JVM primitive). We disallow String otherwise
+            // we would prematurely convert it to number when comparing to an optimistic expression, e.g. in
+            // "Hello" === String("Hello") the RHS starts out as an optimistic-int function call. If we allowed
+            // reordering, we'd end up with ToNumber("Hello") === {I%}String("Hello") that is obviously incorrect.
+            final boolean canReorder = lhsType.isPrimitive() || rhs.isLocal();
+            // If reordering is allowed, and we're using a relational operator (that is, <, <=, >, >=) and not an
+            // (in)equality operator, then we encourage combining of LOAD and CONVERT into a single operation.
+            // This is because relational operators' semantics prescribes vanilla ToNumber() conversion, while
+            // (in)equality operators need the specialized JSType.toNumberFor[Strict]Equals. E.g. in the code snippet
+            // "i < obj.size" (where i is primitive and obj.size is statically an object), ".size" will thus be allowed
+            // to compile as:
+            //   invokedynamic dyn:getProp|getElem|getMethod:size(Object;)D
+            // instead of the more costly:
+            //   invokedynamic dyn:getProp|getElem|getMethod:size(Object;)Object
+            //   invokestatic JSType.toNumber(Object)D
+            // Note also that even if this is allowed, we're only using it on operands that are non-optimistic, as
+            // otherwise the logic for determining effective optimistic-ness would turn an optimistic double return
+            // into a freely coercible one, which would be wrong.
+            final boolean canCombineLoadAndConvert = canReorder && cmp.isRelational();
+
+            // LOAD LEFT
+            loadExpression(lhs, canCombineLoadAndConvert && !lhs.isOptimistic() ? TypeBounds.NUMBER : TypeBounds.UNBOUNDED);
+
+            final Type lhsLoadedType = method.peekType();
+            final TokenType tt = cmp.tokenType();
+            if (canReorder) {
+                // Can reorder CONVERT LEFT and LOAD RIGHT
+                emitObjectToNumberComparisonConversion(method, tt);
+                loadExpression(rhs, canCombineLoadAndConvert && !rhs.isOptimistic() ? TypeBounds.NUMBER : TypeBounds.UNBOUNDED);
+            } else {
+                // Can't reorder CONVERT LEFT and LOAD RIGHT
+                loadExpression(rhs, TypeBounds.UNBOUNDED);
+                if (lhsLoadedType != Type.NUMBER) {
+                    method.swap();
+                    emitObjectToNumberComparisonConversion(method, tt);
+                    method.swap();
+                }
+            }
+
+            // CONVERT RIGHT
+            emitObjectToNumberComparisonConversion(method, tt);
+            return method;
+        }
+        // For primitive operands, just don't do anything special.
+        return loadBinaryOperands(cmp);
+    }
+
+    private static void emitObjectToNumberComparisonConversion(final MethodEmitter method, final TokenType tt) {
+        switch(tt) {
+        case EQ:
+        case NE:
+            if (method.peekType().isObject()) {
+                TO_NUMBER_FOR_EQ.invoke(method);
+                return;
+            }
+            break;
+        case EQ_STRICT:
+        case NE_STRICT:
+            if (method.peekType().isObject()) {
+                TO_NUMBER_FOR_STRICT_EQ.invoke(method);
+                return;
+            }
+            break;
+        default:
+            break;
+        }
+        method.convert(Type.NUMBER);
+    }
+
     private static final Type undefinedToNumber(final Type type) {
         return type == Type.UNDEFINED ? Type.NUMBER : type;
     }
@@ -628,6 +732,7 @@
 
         static final TypeBounds UNBOUNDED = new TypeBounds(Type.UNKNOWN, Type.OBJECT);
         static final TypeBounds INT = exact(Type.INT);
+        static final TypeBounds NUMBER = exact(Type.NUMBER);
         static final TypeBounds OBJECT = exact(Type.OBJECT);
         static final TypeBounds BOOLEAN = exact(Type.BOOLEAN);
 
@@ -731,7 +836,7 @@
          */
         final CodeGenerator codegen = this;
 
-        final Node currentDiscard = codegen.lc.getCurrentDiscard();
+        final boolean isCurrentDiscard = codegen.lc.isCurrentDiscard(expr);
         expr.accept(new NodeOperatorVisitor<LexicalContext>(new LexicalContext()) {
             @Override
             public boolean enterIdentNode(final IdentNode identNode) {
@@ -1087,7 +1192,7 @@
 
             @Override
             public boolean enterJoinPredecessorExpression(final JoinPredecessorExpression joinExpr) {
-                loadExpression(joinExpr.getExpression(), resultBounds);
+                loadMaybeDiscard(joinExpr, joinExpr.getExpression(), resultBounds);
                 return false;
             }
 
@@ -1104,7 +1209,7 @@
                 throw new AssertionError(otherNode.getClass().getName());
             }
         });
-        if(currentDiscard != expr) {
+        if(!isCurrentDiscard) {
             coerceStackTop(resultBounds);
         }
         return method;
@@ -2756,25 +2861,18 @@
             newRuntimeNode = runtimeNode;
         }
 
-        new OptimisticOperation(newRuntimeNode, TypeBounds.UNBOUNDED) {
-            @Override
-            void loadStack() {
-                for (final Expression arg : args) {
-                    loadExpression(arg, TypeBounds.OBJECT);
-                }
-            }
-            @Override
-            void consumeStack() {
-                method.invokestatic(
-                        CompilerConstants.className(ScriptRuntime.class),
-                        newRuntimeNode.getRequest().toString(),
-                        new FunctionSignature(
-                            false,
-                            false,
-                            newRuntimeNode.getType(),
-                            args.size()).toString());
-            }
-        }.emit();
+        for (final Expression arg : args) {
+            loadExpression(arg, TypeBounds.OBJECT);
+        }
+
+        method.invokestatic(
+                CompilerConstants.className(ScriptRuntime.class),
+                newRuntimeNode.getRequest().toString(),
+                new FunctionSignature(
+                    false,
+                    false,
+                    newRuntimeNode.getType(),
+                    args.size()).toString());
 
         method.convert(newRuntimeNode.getType());
     }
@@ -3550,7 +3648,7 @@
         // TODO: move checks for discarding to actual expression load code (e.g. as we do with void). That way we might
         // be able to eliminate even more checks.
         if(expr instanceof PrimitiveLiteralNode | isLocalVariable(expr)) {
-            assert lc.getCurrentDiscard() != expr;
+            assert !lc.isCurrentDiscard(expr);
             // Don't bother evaluating expressions without side effects. Typical usage is "void 0" for reliably generating
             // undefined.
             return;
@@ -3558,11 +3656,37 @@
 
         lc.pushDiscard(expr);
         loadExpression(expr, TypeBounds.UNBOUNDED);
-        if (lc.getCurrentDiscard() == expr) {
+        if (lc.popDiscardIfCurrent(expr)) {
             assert !expr.isAssignment();
             // NOTE: if we had a way to load with type void, we could avoid popping
             method.pop();
-            lc.popDiscard();
+        }
+    }
+
+    /**
+     * Loads the expression with the specified type bounds, but if the parent expression is the current discard,
+     * then instead loads and discards the expression.
+     * @param parent the parent expression that's tested for being the current discard
+     * @param expr the expression that's either normally loaded or discard-loaded
+     * @param resultBounds result bounds for when loading the expression normally
+     */
+    private void loadMaybeDiscard(final Expression parent, final Expression expr, final TypeBounds resultBounds) {
+        loadMaybeDiscard(lc.popDiscardIfCurrent(parent), expr, resultBounds);
+    }
+
+    /**
+     * Loads the expression with the specified type bounds, or loads and discards the expression, depending on the
+     * value of the discard flag. Useful as a helper for expressions with control flow where you often can't combine
+     * testing for being the current discard and loading the subexpressions.
+     * @param discard if true, the expression is loaded and discarded
+     * @param expr the expression that's either normally loaded or discard-loaded
+     * @param resultBounds result bounds for when loading the expression normally
+     */
+    private void loadMaybeDiscard(final boolean discard, final Expression expr, final TypeBounds resultBounds) {
+        if (discard) {
+            loadAndDiscard(expr);
+        } else {
+            loadExpression(expr, resultBounds);
         }
     }
 
@@ -3619,9 +3743,7 @@
 
     public void loadVOID(final UnaryNode unaryNode, final TypeBounds resultBounds) {
         loadAndDiscard(unaryNode.getExpression());
-        if(lc.getCurrentDiscard() == unaryNode) {
-            lc.popDiscard();
-        } else {
+        if (!lc.popDiscardIfCurrent(unaryNode)) {
             method.loadUndefined(resultBounds.widest);
         }
     }
@@ -3654,16 +3776,23 @@
     private void loadAND_OR(final BinaryNode binaryNode, final TypeBounds resultBounds, final boolean isAnd) {
         final Type narrowestOperandType = Type.widestReturnType(binaryNode.lhs().getType(), binaryNode.rhs().getType());
 
+        final boolean isCurrentDiscard = lc.popDiscardIfCurrent(binaryNode);
+
         final Label skip = new Label("skip");
         if(narrowestOperandType == Type.BOOLEAN) {
             // optimize all-boolean logical expressions
             final Label onTrue = new Label("andor_true");
             emitBranch(binaryNode, onTrue, true);
-            method.load(false);
-            method._goto(skip);
-            method.label(onTrue);
-            method.load(true);
-            method.label(skip);
+            if (isCurrentDiscard) {
+                method.label(onTrue);
+                method.pop();
+            } else {
+                method.load(false);
+                method._goto(skip);
+                method.label(onTrue);
+                method.load(true);
+                method.label(skip);
+            }
             return;
         }
 
@@ -3672,7 +3801,11 @@
         final boolean lhsConvert = LocalVariableConversion.hasLiveConversion(lhs);
         final Label evalRhs = lhsConvert ? new Label("eval_rhs") : null;
 
-        loadExpression(lhs, outBounds).dup().convert(Type.BOOLEAN);
+        loadExpression(lhs, outBounds);
+        if (!isCurrentDiscard) {
+            method.dup();
+        }
+        method.convert(Type.BOOLEAN);
         if (isAnd) {
             if(lhsConvert) {
                 method.ifne(evalRhs);
@@ -3691,9 +3824,11 @@
             method.label(evalRhs);
         }
 
-        method.pop();
+        if (!isCurrentDiscard) {
+            method.pop();
+        }
         final JoinPredecessorExpression rhs = (JoinPredecessorExpression)binaryNode.rhs();
-        loadExpression(rhs, outBounds);
+        loadMaybeDiscard(isCurrentDiscard, rhs, outBounds);
         method.beforeJoinPoint(rhs);
         method.label(skip);
     }
@@ -3715,9 +3850,8 @@
         // Detect dead assignments
         if(lhs instanceof IdentNode) {
             final Symbol symbol = ((IdentNode)lhs).getSymbol();
-            if(!symbol.isScope() && !symbol.hasSlotFor(rhsType) && lc.getCurrentDiscard() == binaryNode) {
+            if(!symbol.isScope() && !symbol.hasSlotFor(rhsType) && lc.popDiscardIfCurrent(binaryNode)) {
                 loadAndDiscard(rhs);
-                lc.popDiscard();
                 method.markDeadLocalVariable(symbol);
                 return;
             }
@@ -3971,11 +4105,11 @@
 
     private void loadCOMMARIGHT(final BinaryNode binaryNode, final TypeBounds resultBounds) {
         loadAndDiscard(binaryNode.lhs());
-        loadExpression(binaryNode.rhs(), resultBounds);
+        loadMaybeDiscard(binaryNode, binaryNode.rhs(), resultBounds);
     }
 
     private void loadCOMMALEFT(final BinaryNode binaryNode, final TypeBounds resultBounds) {
-        loadExpression(binaryNode.lhs(), resultBounds);
+        loadMaybeDiscard(binaryNode, binaryNode.lhs(), resultBounds);
         loadAndDiscard(binaryNode.rhs());
     }
 
@@ -3989,8 +4123,7 @@
     }
 
     private void loadCmp(final BinaryNode binaryNode, final Condition cond) {
-        assert comparisonOperandsArePrimitive(binaryNode) : binaryNode;
-        loadBinaryOperands(binaryNode);
+        loadComparisonOperands(binaryNode);
 
         final Label trueLabel  = new Label("trueLabel");
         final Label afterLabel = new Label("skip");
@@ -4004,11 +4137,6 @@
         method.label(afterLabel);
     }
 
-    private static boolean comparisonOperandsArePrimitive(final BinaryNode binaryNode) {
-        final Type widest = Type.widest(binaryNode.lhs().getType(), binaryNode.rhs().getType());
-        return widest.isNumeric() || widest.isBoolean();
-    }
-
     private void loadMOD(final BinaryNode binaryNode, final TypeBounds resultBounds) {
         new BinaryArith() {
             @Override
@@ -4081,13 +4209,14 @@
 
         emitBranch(test, falseLabel, false);
 
-        loadExpression(trueExpr.getExpression(), outBounds);
-        assert Type.generic(method.peekType()) == outBounds.narrowest;
+        final boolean isCurrentDiscard = lc.popDiscardIfCurrent(ternaryNode);
+        loadMaybeDiscard(isCurrentDiscard, trueExpr.getExpression(), outBounds);
+        assert isCurrentDiscard || Type.generic(method.peekType()) == outBounds.narrowest;
         method.beforeJoinPoint(trueExpr);
         method._goto(exitLabel);
         method.label(falseLabel);
-        loadExpression(falseExpr.getExpression(), outBounds);
-        assert Type.generic(method.peekType()) == outBounds.narrowest;
+        loadMaybeDiscard(isCurrentDiscard, falseExpr.getExpression(), outBounds);
+        assert isCurrentDiscard || Type.generic(method.peekType()) == outBounds.narrowest;
         method.beforeJoinPoint(falseExpr);
         method.label(exitLabel);
     }
@@ -4273,9 +4402,8 @@
 
         // store the result that "lives on" after the op, e.g. "i" in i++ postfix.
         protected void storeNonDiscard() {
-            if (lc.getCurrentDiscard() == assignNode) {
+            if (lc.popDiscardIfCurrent(assignNode)) {
                 assert assignNode.isAssignment();
-                lc.popDiscard();
                 return;
             }
 
--- a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java	Thu Mar 12 13:45:00 2015 -0700
@@ -34,6 +34,7 @@
 import jdk.nashorn.internal.IntDeque;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.ir.Block;
+import jdk.nashorn.internal.ir.Expression;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LexicalContextNode;
@@ -59,9 +60,11 @@
     /** Method emitter stack - every time we start a sub method (e.g. a split) we push one */
     private final Deque<MethodEmitter> methodEmitters = new ArrayDeque<>();
 
-    /** The discard stack - whenever we enter a discard node we keep track of its return value status -
-     *  i.e. should we keep it or throw it away */
-    private final Deque<Node> discard = new ArrayDeque<>();
+    /** The discard stack - whenever we evaluate an expression that will be discarded, we push it on this stack. Various
+     * implementations of expression code emitter can choose to emit code that'll discard the expression themselves, or
+     * ignore it in which case CodeGenerator.loadAndDiscard() will explicitly emit a pop instruction. */
+    private final Deque<Expression> discard = new ArrayDeque<>();
+
 
     private final Deque<Map<String, Collection<Label>>> unwarrantedOptimismHandlers = new ArrayDeque<>();
     private final Deque<StringBuilder> slotTypesDescriptors = new ArrayDeque<>();
@@ -270,16 +273,20 @@
         }
     }
 
-    void pushDiscard(final Node node) {
-        discard.push(node);
+    void pushDiscard(final Expression expr) {
+        discard.push(expr);
     }
 
-    Node popDiscard() {
-        return discard.pop();
+    boolean popDiscardIfCurrent(final Expression expr) {
+        if (isCurrentDiscard(expr)) {
+            discard.pop();
+            return true;
+        }
+        return false;
     }
 
-    Node getCurrentDiscard() {
-        return discard.peek();
+    boolean isCurrentDiscard(final Expression expr) {
+        return discard.peek() == expr;
     }
 
     int quickSlot(final Type type) {
--- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java	Thu Mar 12 13:45:00 2015 -0700
@@ -32,7 +32,6 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
 import jdk.nashorn.internal.ir.Block;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
@@ -208,7 +207,7 @@
         final RecompilableScriptFunctionData data = new RecompilableScriptFunctionData(
                 newFunctionNode,
                 compiler.getCodeInstaller(),
-                new AllocatorDescriptor(newFunctionNode.getThisProperties()),
+                ObjectClassGenerator.createAllocationStrategy(newFunctionNode.getThisProperties()),
                 nestedFunctions,
                 externalSymbolDepths.get(fnId),
                 internalSymbols.get(fnId),
--- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Thu Mar 12 13:45:00 2015 -0700
@@ -206,7 +206,6 @@
         // continuations (since RewriteException's byteCodeSlots carries an array and not a name-value map).
 
         symbolIsConverted(symbol, branchLvarType, targetType);
-        //symbolIsUsed(symbol, branchLvarType);
         return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
     }
 
@@ -229,7 +228,7 @@
             for(final Symbol symbol: commonSymbols) {
                 final LvarType type1 = types1.get(symbol);
                 final LvarType type2 = types2.get(symbol);
-                final LvarType widest = widestLvarType(type1,  type2);
+                final LvarType widest = widestLvarType(type1, type2);
                 if(widest != type1 && matches1) {
                     matches1 = false;
                     if(!matches2) {
@@ -242,7 +241,7 @@
                         union = cloneMap(types2);
                     }
                 }
-                if(!(matches1 || matches2) && union != null) { //remove overly enthusiastic "union can be null" warning
+                if(!(matches1 || matches2)) {
                     assert union != null;
                     union.put(symbol, widest);
                 }
@@ -711,8 +710,13 @@
 
     @Override
     public boolean enterIfNode(final IfNode ifNode) {
+        processIfNode(ifNode);
+        return false;
+    }
+
+    private void processIfNode(final IfNode ifNode) {
         if(!reachable) {
-            return false;
+            return;
         }
 
         final Expression test = ifNode.getTest();
@@ -721,48 +725,48 @@
 
         visitExpressionOnEmptyStack(test);
 
-        final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
-        if(!isAlwaysFalse(test)) {
+        final Map<Symbol, LvarType> passLvarTypes;
+        final boolean reachableFromPass;
+        final boolean isTestAlwaysTrue = isAlwaysTrue(test);
+        if(isAlwaysFalse(test)) {
+            passLvarTypes = null;
+            reachableFromPass = false;
+        } else {
+            final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
             pass.accept(this);
             assertTypeStackIsEmpty();
+            if (isTestAlwaysTrue) {
+                return;
+            }
+            passLvarTypes = localVariableTypes;
+            reachableFromPass = reachable;
+            localVariableTypes = afterTestLvarTypes;
+            reachable = true;
         }
-        final Map<Symbol, LvarType> passLvarTypes = localVariableTypes;
-        final boolean reachableFromPass = reachable;
 
-        reachable = true;
-        localVariableTypes = afterTestLvarTypes;
-        if(!isAlwaysTrue(test) && fail != null) {
+        // If we get here, then we need to consider the case where pass block is not executed
+        assert !isTestAlwaysTrue;
+
+        if (fail != null) {
             fail.accept(this);
             assertTypeStackIsEmpty();
-            final boolean reachableFromFail = reachable;
-            reachable |= reachableFromPass;
-            if(!reachable) {
-                return false;
-            }
-
-            if(reachableFromFail) {
-                if(reachableFromPass) {
-                    final Map<Symbol, LvarType> failLvarTypes = localVariableTypes;
-                    localVariableTypes = getUnionTypes(passLvarTypes, failLvarTypes);
-                    setConversion(pass, passLvarTypes, localVariableTypes);
-                    setConversion(fail, failLvarTypes, localVariableTypes);
-                }
-                return false;
-            }
         }
 
-        if(reachableFromPass) {
-            localVariableTypes = getUnionTypes(afterTestLvarTypes, passLvarTypes);
-            // IfNode itself is associated with conversions that might need to be performed after the test if there's no
-            // else branch. E.g.
-            // if(x = 1, cond) { x = 1.0 } must widen "x = 1" to a double.
-            setConversion(pass, passLvarTypes, localVariableTypes);
-            setConversion(ifNode, afterTestLvarTypes, localVariableTypes);
-        } else {
-            localVariableTypes = afterTestLvarTypes;
+        if(reachable) {
+            if(reachableFromPass) {
+                final Map<Symbol, LvarType> failLvarTypes = localVariableTypes;
+                localVariableTypes = getUnionTypes(passLvarTypes, failLvarTypes);
+                setConversion(pass, passLvarTypes, localVariableTypes);
+                // IfNode itself is associated with conversions that might need to be performed after the test if
+                // there's no else branch. E.g.
+                // if(x = 1, cond) { x = 1.0 } must widen "x = 1" to a double.
+                setConversion(fail != null ? fail : ifNode, failLvarTypes, localVariableTypes);
+            }
+        } else if (reachableFromPass) {
+            assert passLvarTypes != null;
+            localVariableTypes = passLvarTypes;
+            reachable = true;
         }
-
-        return false;
     }
 
     @Override
@@ -1359,8 +1363,6 @@
                     final Expression lhs = binaryNode.lhs();
                     final Expression rhs = binaryNode.rhs();
 
-                    Type cmpWidest = Type.widest(lhs.getType(), rhs.getType());
-                    boolean newRuntimeNode = false, finalized = false;
                     final TokenType tt = binaryNode.tokenType();
                     switch (tt) {
                     case EQ_STRICT:
@@ -1373,14 +1375,12 @@
                         }
                         // Specialize comparison of boolean with non-boolean
                         if (lhs.getType().isBoolean() != rhs.getType().isBoolean()) {
-                            newRuntimeNode = true;
-                            cmpWidest = Type.OBJECT;
-                            finalized = true;
+                            return new RuntimeNode(binaryNode);
                         }
                         // fallthrough
                     default:
-                        if (newRuntimeNode || cmpWidest.isObject()) {
-                            return new RuntimeNode(binaryNode).setIsFinal(finalized);
+                        if (lhs.getType().isObject() && rhs.getType().isObject()) {
+                            return new RuntimeNode(binaryNode);
                         }
                     }
                 } else if(binaryNode.isOptimisticUndecidedType()) {
--- a/src/jdk/nashorn/internal/codegen/MapCreator.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/MapCreator.java	Thu Mar 12 13:45:00 2015 -0700
@@ -100,15 +100,16 @@
         for (final MapTuple<T> tuple : tuples) {
             final String key    = tuple.key;
             final Symbol symbol = tuple.symbol;
+            final Class<?> initialType = tuple.getValueType();
 
-            //TODO initial type is object here no matter what. Is that right?
             if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
                 final int flags = getPropertyFlags(symbol, hasArguments, false);
                 properties.add(
                         new SpillProperty(
                                 key,
                                 flags,
-                                spillIndex++));
+                                spillIndex++,
+                                initialType));
             }
         }
 
--- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java	Thu Mar 12 13:45:00 2015 -0700
@@ -94,7 +94,6 @@
 import jdk.nashorn.internal.ir.JoinPredecessor;
 import jdk.nashorn.internal.ir.LiteralNode;
 import jdk.nashorn.internal.ir.LocalVariableConversion;
-import jdk.nashorn.internal.ir.RuntimeNode;
 import jdk.nashorn.internal.ir.Symbol;
 import jdk.nashorn.internal.ir.TryNode;
 import jdk.nashorn.internal.objects.Global;
@@ -175,9 +174,6 @@
     /** Bootstrap for normal indy:s */
     private static final Handle LINKERBOOTSTRAP  = new Handle(H_INVOKESTATIC, Bootstrap.BOOTSTRAP.className(), Bootstrap.BOOTSTRAP.name(), Bootstrap.BOOTSTRAP.descriptor());
 
-    /** Bootstrap for runtime node indy:s */
-    private static final Handle RUNTIMEBOOTSTRAP = new Handle(H_INVOKESTATIC, RuntimeCallSite.BOOTSTRAP.className(), RuntimeCallSite.BOOTSTRAP.name(), RuntimeCallSite.BOOTSTRAP.descriptor());
-
     /** Bootstrap for array populators */
     private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor());
 
@@ -2189,25 +2185,6 @@
     }
 
     /**
-     * Generate a dynamic call for a runtime node
-     *
-     * @param name       tag for the invoke dynamic for this runtime node
-     * @param returnType return type
-     * @param request    RuntimeNode request
-     *
-     * @return the method emitter
-     */
-    MethodEmitter dynamicRuntimeCall(final String name, final Type returnType, final RuntimeNode.Request request) {
-        debug("dynamic_runtime_call", name, "args=", request.getArity(), "returnType=", returnType);
-        final String signature = getDynamicSignature(returnType, request.getArity());
-        debug("   signature", signature);
-        method.visitInvokeDynamicInsn(name, signature, RUNTIMEBOOTSTRAP);
-        pushType(returnType);
-
-        return this;
-    }
-
-    /**
      * Generate dynamic getter. Pop scope from stack. Push result
      *
      * @param valueType type of the value to set
--- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java	Thu Mar 12 13:45:00 2015 -0700
@@ -56,6 +56,7 @@
 import jdk.nashorn.internal.codegen.ClassEmitter.Flag;
 import jdk.nashorn.internal.codegen.types.Type;
 import jdk.nashorn.internal.runtime.AccessorProperty;
+import jdk.nashorn.internal.runtime.AllocationStrategy;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.FunctionScope;
 import jdk.nashorn.internal.runtime.JSType;
@@ -826,44 +827,13 @@
     }
 
     /**
-     * Describes the allocator class name and property map for a constructor function with the specified
+     * Creates the allocator class name and property map for a constructor function with the specified
      * number of "this" properties that it initializes.
-     *
+     * @param thisProperties number of properties assigned to "this"
+     * @return the allocation strategy
      */
-    public static class AllocatorDescriptor {
-        private final String allocatorClassName;
-        private final PropertyMap allocatorMap;
-
-        /**
-         * Creates a new allocator descriptor
-         * @param thisProperties the number of "this" properties that the function initializes
-         */
-        public AllocatorDescriptor(final int thisProperties) {
-            final int paddedFieldCount = getPaddedFieldCount(thisProperties);
-            this.allocatorClassName = Compiler.binaryName(getClassName(paddedFieldCount));
-            this.allocatorMap = PropertyMap.newMap(null, allocatorClassName, 0, paddedFieldCount, 0);
-        }
-
-        /**
-         * Returns the name of the class that the function allocates
-         * @return the name of the class that the function allocates
-         */
-        public String getAllocatorClassName() {
-            return allocatorClassName;
-        }
-
-        /**
-         * Returns the allocator map for the function.
-         * @return the allocator map for the function.
-         */
-        public PropertyMap getAllocatorMap() {
-            return allocatorMap;
-        }
-
-        @Override
-        public String toString() {
-            return "AllocatorDescriptor[allocatorClassName=" + allocatorClassName + ", allocatorMap.size=" +
-                    allocatorMap.size() + "]";
-        }
+    static AllocationStrategy createAllocationStrategy(final int thisProperties) {
+        final int paddedFieldCount = getPaddedFieldCount(thisProperties);
+        return new AllocationStrategy(paddedFieldCount);
     }
 }
--- a/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java	Wed Mar 11 14:11:06 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,683 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.codegen;
-
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
-import static jdk.nashorn.internal.codegen.types.Type.BOOLEAN;
-import static jdk.nashorn.internal.codegen.types.Type.INT;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-
-import java.lang.invoke.CallSite;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.invoke.MutableCallSite;
-import java.util.HashMap;
-import java.util.Map;
-import jdk.nashorn.internal.codegen.CompilerConstants.Call;
-import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.ir.RuntimeNode;
-import jdk.nashorn.internal.ir.RuntimeNode.Request;
-import jdk.nashorn.internal.lookup.Lookup;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.linker.Bootstrap;
-
-/**
- * Optimistic call site that assumes its Object arguments to be of a boxed type.
- * Gradually reverts to wider boxed types if the assumption for the RuntimeNode
- * is proven wrong. Finally reverts to the generic ScriptRuntime method.
- *
- * This is used from the CodeGenerator when we have a runtime node, but 1 or more
- * primitive arguments. This class generated appropriate specializations, for example
- * {@code Object a === int b} is a good idea to specialize to {@code ((Integer)a).intValue() == b}
- * surrounded by catch blocks that will try less narrow specializations
- */
-public final class RuntimeCallSite extends MutableCallSite {
-    static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "runtimeBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
-
-    private static final MethodHandle NEXT = findOwnMH_V("next",  MethodHandle.class, String.class);
-
-    private final RuntimeNode.Request request;
-
-    /**
-     * A specialized runtime node, i.e. on where we know at least one more specific type than object
-     */
-    static final class SpecializedRuntimeNode {
-        private static final char REQUEST_SEPARATOR = ':';
-
-        private final RuntimeNode.Request request;
-
-        private final Type[] parameterTypes;
-
-        private final Type   returnType;
-
-        /**
-         * Constructor.
-         *
-         * @param request        runtime node request to specialize
-         * @param parameterTypes parameter types of the call site
-         * @param returnType     return type of the call site
-         */
-        SpecializedRuntimeNode(final RuntimeNode.Request request, final Type[] parameterTypes, final Type returnType) {
-            this.request        = request;
-            this.parameterTypes = parameterTypes;
-            this.returnType     = returnType;
-        }
-
-        /**
-         * The first type to try to use for this generated runtime node
-         *
-         * @return a type
-         */
-        public Type firstTypeGuess() {
-            Type widest = Type.UNKNOWN;
-            for (final Type type : parameterTypes) {
-                if (type.isObject()) {
-                    continue;
-                }
-                widest = Type.widest(type, widest);
-            }
-            widest = Type.widest(widest, firstTypeGuessForObject(request));
-
-            return widest;
-        }
-
-        private static Type firstTypeGuessForObject(final Request request) {
-            switch (request) {
-            case ADD:
-                return INT;
-            default:
-                return BOOLEAN;
-            }
-        }
-
-        Request getRequest() {
-            return request;
-        }
-
-        Type[] getParameterTypes() {
-            return parameterTypes;
-        }
-
-        Type getReturnType() {
-            return returnType;
-        }
-
-        private static char descFor(final Type type) {
-            if (type.isObject()) {
-                return 'O';
-            }
-            return type.getDescriptor().charAt(0);
-        }
-
-        @Override
-        public boolean equals(final Object other) {
-            if (other instanceof SpecializedRuntimeNode) {
-                final SpecializedRuntimeNode otherNode = (SpecializedRuntimeNode)other;
-
-                if (!otherNode.getReturnType().equals(getReturnType())) {
-                    return false;
-                }
-
-                if (getParameterTypes().length != otherNode.getParameterTypes().length) {
-                    return false;
-                }
-
-                for (int i = 0; i < getParameterTypes().length; i++) {
-                    if (!Type.areEquivalent(getParameterTypes()[i], otherNode.getParameterTypes()[i])) {
-                        return false;
-                    }
-                }
-
-                return otherNode.getRequest().equals(getRequest());
-            }
-
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            int hashCode = getRequest().toString().hashCode();
-            hashCode ^= getReturnType().hashCode();
-            for (final Type type : getParameterTypes()) {
-                hashCode ^= type.hashCode();
-            }
-            return hashCode;
-        }
-
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            sb.append(getRequest().toString());
-            sb.append(REQUEST_SEPARATOR);
-            sb.append(descFor(getReturnType()));
-
-            for (final Type type : getParameterTypes()) {
-                sb.append(descFor(type));
-            }
-
-            return sb.toString();
-        }
-
-        String getName(final Type extraType) {
-            return toString() + "_" + descFor(extraType);
-        }
-
-        String getInitialName() {
-            return getName(firstTypeGuess());
-        }
-    }
-
-
-    /**
-     * Constructor
-     *
-     * @param type method type for call site
-     * @param name name of runtime call
-     */
-    public RuntimeCallSite(final MethodType type, final String name) {
-        super(type);
-        this.request = Request.valueOf(name.substring(0, name.indexOf(SpecializedRuntimeNode.REQUEST_SEPARATOR)));
-        setTarget(makeMethod(name));
-    }
-
-    private String nextName(final String requestName) {
-        if (requestName.equals(request.toString())) {
-            return null;
-        }
-
-        final char[] c = requestName.toCharArray();
-        final int last = c.length - 1;
-
-        if (c[last - 1] != '_') {
-            return null;
-        }
-
-        switch (c[last]) {
-        case 'Z':
-            c[last] = 'I';
-            break;
-        case 'I':
-            c[last] = 'J';
-            break;
-        case 'J':
-            c[last] = 'D';
-            break;
-        case 'D':
-        default:
-            return request.toString();
-        }
-
-        return new String(c);
-    }
-
-    private boolean isSpecialized(final String requestName) {
-        return nextName(requestName) != null;
-    }
-
-    private MethodHandle makeMethod(final String requestName) {
-        MethodHandle mh;
-
-        if (isSpecialized(requestName)) {
-            final Class<?> boxedType;
-            final Class<?> primitiveType;
-
-            switch (requestName.charAt(requestName.length() - 1)) {
-            case 'Z':
-                boxedType = Boolean.class;
-                primitiveType = int.class;
-                break;
-            case 'I':
-                boxedType = Integer.class;
-                primitiveType = int.class;
-                break;
-            case 'J':
-                boxedType = Long.class;
-                primitiveType = long.class;
-                break;
-            case 'D':
-                boxedType = Number.class;
-                primitiveType = double.class;
-                break;
-            default:
-                throw new RuntimeException("should not reach here");
-            }
-
-            final boolean isStrictCmp = (request == Request.EQ_STRICT || request == Request.NE_STRICT);
-
-            if (isStrictCmp &&
-                    (boxedType != Boolean.class &&
-                        (type().parameterType(0) == boolean.class ||
-                         type().parameterType(1) == boolean.class))) {
-                // number and boolean are never strictly equal, e.g. 0 !== false
-                mh = MH.dropArguments(MH.constant(boolean.class, request == Request.NE_STRICT), 0, type().parameterArray());
-            } else {
-                mh = METHODS.get(request.nonStrictName() + primitiveType.getSimpleName());
-                // unbox objects
-
-                for (int i = 0; i < type().parameterCount(); i++) {
-                    if (!type().parameterType(i).isPrimitive()) {
-                        mh = MH.filterArguments(mh, i, UNBOX.get(boxedType));
-                    }
-                }
-
-                mh = Lookup.filterReturnType(mh, type().returnType());
-                mh = MH.explicitCastArguments(mh, type());
-            }
-
-            final MethodHandle fallback = MH.foldArguments(MethodHandles.exactInvoker(type()), MH.insertArguments(NEXT, 0, this, requestName));
-
-            MethodHandle guard;
-            if (type().parameterType(0).isPrimitive()) {
-                guard = MH.insertArguments(
-                            MH.dropArguments(CHECKCAST, 1, type().parameterType(0)), 0, boxedType);
-            } else if (type().parameterType(1).isPrimitive()) {
-                guard = MH.insertArguments(
-                            MH.dropArguments(CHECKCAST, 2, type().parameterType(1)), 0, boxedType);
-            } else {
-                assert !type().parameterType(0).isPrimitive() && !type().parameterType(1).isPrimitive();
-                guard = MH.insertArguments(CHECKCAST2, 0, boxedType);
-            }
-
-            if (request == Request.ADD && boxedType == Integer.class) {
-                // int add needs additional overflow check
-                MethodHandle addcheck = ADDCHECK;
-                for (int i = 0; i < type().parameterCount(); i++) {
-                    if (!type().parameterType(i).isPrimitive()) {
-                        addcheck = MH.filterArguments(addcheck, i, UNBOX.get(boxedType));
-                    }
-                }
-                addcheck = MH.explicitCastArguments(addcheck, type().changeReturnType(boolean.class));
-                guard    = MH.guardWithTest(upcastGuard(guard), addcheck,
-                                MH.dropArguments(MH.constant(boolean.class, false), 0, type().parameterArray()));
-            }
-
-            return MH.guardWithTest(upcastGuard(guard), mh, fallback);
-        }
-
-        // generic fallback
-        return MH.explicitCastArguments(Lookup.filterReturnType(GENERIC_METHODS.get(request.name()), type().returnType()), type());
-    }
-
-    private MethodHandle upcastGuard(final MethodHandle guard) {
-        return MH.asType(guard, type().changeReturnType(boolean.class));
-    }
-
-    /**
-     * This is public just so that the generated specialization code can
-     * use it to get the next wider typed method
-     *
-     * Do not call directly
-     *
-     * @param name current name (with type) of runtime call at the call site
-     * @return next wider specialization method for this RuntimeCallSite
-     */
-   public MethodHandle next(final String name) {
-        final MethodHandle next = makeMethod(nextName(name));
-        setTarget(next);
-        return next;
-    }
-
-    /** Method cache */
-    private static final Map<String, MethodHandle> METHODS;
-
-    /** Generic method cache */
-    private static final Map<String, MethodHandle> GENERIC_METHODS;
-
-    /** Unbox cache */
-    private static final Map<Class<?>, MethodHandle> UNBOX;
-
-    private static final MethodHandle CHECKCAST  = findOwnMH_S("checkcast", boolean.class, Class.class, Object.class);
-    private static final MethodHandle CHECKCAST2 = findOwnMH_S("checkcast", boolean.class, Class.class, Object.class, Object.class);
-    private static final MethodHandle ADDCHECK   = findOwnMH_S("ADDcheck",  boolean.class, int.class, int.class);
-
-    /**
-     * Build maps of correct boxing operations
-     */
-    static {
-        UNBOX = new HashMap<>();
-        UNBOX.put(Boolean.class, findOwnMH_S("unboxZ", int.class, Object.class));
-        UNBOX.put(Integer.class, findOwnMH_S("unboxI", int.class, Object.class));
-        UNBOX.put(Long.class,    findOwnMH_S("unboxJ", long.class, Object.class));
-        UNBOX.put(Number.class,  findOwnMH_S("unboxD", double.class, Object.class));
-
-        METHODS = new HashMap<>();
-
-        for (final Request req : Request.values()) {
-            if (req.canSpecialize()) {
-                if (req.name().endsWith("_STRICT")) {
-                    continue;
-                }
-
-                final boolean isCmp = Request.isComparison(req);
-
-                METHODS.put(req.name() + "int",    findOwnMH_S(req.name(), (isCmp ? boolean.class : int.class),  int.class, int.class));
-                METHODS.put(req.name() + "long",   findOwnMH_S(req.name(), (isCmp ? boolean.class : long.class), long.class, long.class));
-                METHODS.put(req.name() + "double", findOwnMH_S(req.name(), (isCmp ? boolean.class : double.class), double.class, double.class));
-            }
-        }
-
-        GENERIC_METHODS = new HashMap<>();
-        for (final Request req : Request.values()) {
-            if (req.canSpecialize()) {
-                GENERIC_METHODS.put(req.name(), MH.findStatic(MethodHandles.lookup(), ScriptRuntime.class, req.name(),
-                        MH.type(req.getReturnType().getTypeClass(), Object.class, Object.class)));
-            }
-        }
-    }
-
-    /**
-     * Specialized version of != operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a != b
-     */
-    public static boolean NE(final int a, final int b) {
-        return a != b;
-    }
-
-    /**
-     * Specialized version of != operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a != b
-     */
-    public static boolean NE(final double a, final double b) {
-        return a != b;
-    }
-
-    /**
-     * Specialized version of != operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a != b
-     */
-    public static boolean NE(final long a, final long b) {
-        return a != b;
-    }
-
-    /**
-     * Specialized version of == operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a == b
-     */
-    public static boolean EQ(final int a, final int b) {
-        return a == b;
-    }
-
-    /**
-     * Specialized version of == operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a == b
-     */
-    public static boolean EQ(final double a, final double b) {
-        return a == b;
-    }
-
-    /**
-     * Specialized version of == operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a == b
-     */
-    public static boolean EQ(final long a, final long b) {
-        return a == b;
-    }
-
-    /**
-     * Specialized version of {@literal <} operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a {@code <} b
-     */
-    public static boolean LT(final int a, final int b) {
-        return a < b;
-    }
-
-    /**
-     * Specialized version of {@literal <} operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a {@literal <} b
-     */
-    public static boolean LT(final double a, final double b) {
-        return a < b;
-    }
-
-    /**
-     * Specialized version of {@literal <} operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a {@literal <} b
-     */
-    public static boolean LT(final long a, final long b) {
-        return a < b;
-    }
-
-    /**
-     * Specialized version of {@literal <=} operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a {@literal <=} b
-     */
-    public static boolean LE(final int a, final int b) {
-        return a <= b;
-    }
-
-    /**
-     * Specialized version of {@literal <=} operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a {@literal <=} b
-     */
-    public static boolean LE(final double a, final double b) {
-        return a <= b;
-    }
-
-    /**
-     * Specialized version of {@literal <=} operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a {@literal <=} b
-     */
-    public static boolean LE(final long a, final long b) {
-        return a <= b;
-    }
-
-    /**
-     * Specialized version of {@literal >} operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a {@literal >} b
-     */
-    public static boolean GT(final int a, final int b) {
-        return a > b;
-    }
-
-    /**
-     * Specialized version of {@literal >} operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a {@literal >} b
-     */
-    public static boolean GT(final double a, final double b) {
-        return a > b;
-    }
-
-    /**
-     * Specialized version of {@literal >} operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a {@literal >} b
-     */
-    public static boolean GT(final long a, final long b) {
-        return a > b;
-    }
-
-    /**
-     * Specialized version of {@literal >=} operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a {@literal >=} b
-     */
-    public static boolean GE(final int a, final int b) {
-        return a >= b;
-    }
-
-    /**
-     * Specialized version of {@literal >=} operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a {@literal >=} b
-     */
-    public static boolean GE(final double a, final double b) {
-        return a >= b;
-    }
-
-    /**
-     * Specialized version of {@literal >=} operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a {@code >=} b
-     */
-    public static boolean GE(final long a, final long b) {
-        return a >= b;
-    }
-
-    /**
-     * Specialized version of + operator for two int arguments. Do not call directly.
-     * @param a int
-     * @param b int
-     * @return a + b
-     */
-    public static int ADD(final int a, final int b) {
-        return a + b;
-    }
-
-    /**
-     * Specialized version of + operator for two long arguments. Do not call directly.
-     * @param a long
-     * @param b long
-     * @return a + b
-     */
-    public static long ADD(final long a, final long b) {
-        return a + b;
-    }
-
-    /**
-     * Specialized version of + operator for two double arguments. Do not call directly.
-     * @param a double
-     * @param b double
-     * @return a + b
-     */
-    public static double ADD(final double a, final double b) {
-        return a + b;
-    }
-
-    /**
-     * Check that ints are addition compatible, i.e. their sum is equal to the sum
-     * of them cast to long. Otherwise the addition will overflow. Do not call directly.
-     *
-     * @param a int
-     * @param b int
-     *
-     * @return true if addition does not overflow
-     */
-    public static boolean ADDcheck(final int a, final int b) {
-        return (a + b == (long)a + (long)b);
-    }
-
-    /**
-     * Checkcast used for specialized ops. Do not call directly
-     *
-     * @param type to to check against
-     * @param obj  object to check for type
-     *
-     * @return true if type check holds
-     */
-    public static boolean checkcast(final Class<?> type, final Object obj) {
-        return type.isInstance(obj);
-    }
-
-    /**
-     * Checkcast used for specialized ops. Do not call directly
-     *
-     * @param type type to check against
-     * @param objA first object to check against type
-     * @param objB second object to check against type
-     *
-     * @return true if type check holds for both objects
-     */
-    public static boolean checkcast(final Class<?> type, final Object objA, final Object objB) {
-        return type.isInstance(objA) && type.isInstance(objB);
-    }
-
-    /**
-     * Unbox a java.lang.Boolean. Do not call directly
-     * @param obj object to cast to int and unbox
-     * @return an int value for the boolean, 1 is true, 0 is false
-     */
-    public static int unboxZ(final Object obj) {
-        return (boolean)obj ? 1 : 0;
-    }
-
-    /**
-     * Unbox a java.lang.Integer. Do not call directly
-     * @param obj object to cast to int and unbox
-     * @return an int
-     */
-    public static int unboxI(final Object obj) {
-        return (int)obj;
-    }
-
-    /**
-     * Unbox a java.lang.Long. Do not call directly
-     * @param obj object to cast to long and unbox
-     * @return a long
-     */
-    public static long unboxJ(final Object obj) {
-        return (long)obj;
-    }
-
-    /**
-     * Unbox a java.lang.Number. Do not call directly
-     * @param obj object to cast to Number and unbox
-     * @return a double
-     */
-    public static double unboxD(final Object obj) {
-        return ((Number)obj).doubleValue();
-    }
-
-    private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
-        return MH.findStatic(MethodHandles.lookup(), RuntimeCallSite.class, name, MH.type(rtype, types));
-    }
-
-    private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
-        return MH.findVirtual(MethodHandles.lookup(), RuntimeCallSite.class, name, MH.type(rtype, types));
-    }
-}
--- a/src/jdk/nashorn/internal/ir/BinaryNode.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/BinaryNode.java	Thu Mar 12 13:45:00 2015 -0700
@@ -98,7 +98,7 @@
     }
 
     /**
-     * Returns true if the node is a comparison operation.
+     * Returns true if the node is a comparison operation (either equality, inequality, or relational).
      * @return true if the node is a comparison operation.
      */
     public boolean isComparison() {
@@ -118,6 +118,22 @@
     }
 
     /**
+     * Returns true if the node is a relational operation (less than (or equals), greater than (or equals)).
+     * @return true if the node is a relational operation.
+     */
+    public boolean isRelational() {
+        switch (tokenType()) {
+        case LT:
+        case GT:
+        case LE:
+        case GE:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    /**
      * Returns true if the node is a logical operation.
      * @return true if the node is a logical operation.
      */
--- a/src/jdk/nashorn/internal/ir/RuntimeNode.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java	Thu Mar 12 13:45:00 2015 -0700
@@ -25,8 +25,6 @@
 
 package jdk.nashorn.internal.ir;
 
-import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -39,7 +37,7 @@
  * IR representation for a runtime call.
  */
 @Immutable
-public class RuntimeNode extends Expression implements Optimistic {
+public class RuntimeNode extends Expression {
     private static final long serialVersionUID = 1L;
 
     /**
@@ -333,11 +331,6 @@
     /** Call arguments. */
     private final List<Expression> args;
 
-    /** is final - i.e. may not be removed again, lower in the code pipeline */
-    private final boolean isFinal;
-
-    private final int programPoint;
-
     /**
      * Constructor
      *
@@ -351,17 +344,13 @@
 
         this.request      = request;
         this.args         = args;
-        this.isFinal      = false;
-        this.programPoint = INVALID_PROGRAM_POINT;
     }
 
-    private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final boolean isFinal, final List<Expression> args, final int programPoint) {
+    private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final List<Expression> args) {
         super(runtimeNode);
 
         this.request      = request;
         this.args         = args;
-        this.isFinal      = isFinal;
-        this.programPoint = programPoint;
     }
 
     /**
@@ -399,8 +388,6 @@
 
         this.request      = request;
         this.args         = args;
-        this.isFinal      = false;
-        this.programPoint = parent instanceof Optimistic ? ((Optimistic)parent).getProgramPoint() : INVALID_PROGRAM_POINT;
     }
 
     /**
@@ -428,32 +415,11 @@
      * @return new runtime node or same if same request
      */
     public RuntimeNode setRequest(final Request request) {
-       if (this.request == request) {
-           return this;
-       }
-       return new RuntimeNode(this, request, isFinal, args, programPoint);
-   }
-
-
-    /**
-     * Is this node final - i.e. it can never be replaced with other nodes again
-     * @return true if final
-     */
-    public boolean isFinal() {
-        return isFinal;
-    }
-
-    /**
-     * Flag this node as final - i.e it may never be replaced with other nodes again
-     * @param isFinal is the node final, i.e. can not be removed and replaced by a less generic one later in codegen
-     * @return same runtime node if already final, otherwise a new one
-     */
-    public RuntimeNode setIsFinal(final boolean isFinal) {
-        if (this.isFinal == isFinal) {
+        if (this.request == request) {
             return this;
         }
-        return new RuntimeNode(this, request, isFinal, args, programPoint);
-    }
+        return new RuntimeNode(this, request, args);
+   }
 
     /**
      * Return type for the ReferenceNode
@@ -510,7 +476,7 @@
         if (this.args == args) {
             return this;
         }
-        return new RuntimeNode(this, request, isFinal, args, programPoint);
+        return new RuntimeNode(this, request, args);
     }
 
     /**
@@ -536,39 +502,4 @@
         }
         return true;
     }
-
-//TODO these are blank for now:
-
-    @Override
-    public int getProgramPoint() {
-        return programPoint;
-    }
-
-    @Override
-    public RuntimeNode setProgramPoint(final int programPoint) {
-        if(this.programPoint == programPoint) {
-            return this;
-        }
-        return new RuntimeNode(this, request, isFinal, args, programPoint);
-    }
-
-    @Override
-    public boolean canBeOptimistic() {
-        return false;
-    }
-
-    @Override
-    public Type getMostOptimisticType() {
-        return getType();
-    }
-
-    @Override
-    public Type getMostPessimisticType() {
-        return getType();
-    }
-
-    @Override
-    public RuntimeNode setType(final Type type) {
-        return this;
-    }
 }
--- a/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java	Thu Mar 12 13:45:00 2015 -0700
@@ -25,6 +25,8 @@
 
 package jdk.nashorn.internal.lookup;
 
+import static jdk.nashorn.internal.runtime.JSType.isString;
+
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
 import java.lang.invoke.MethodHandle;
@@ -36,7 +38,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.logging.Level;
-import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.Debug;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -343,7 +344,7 @@
                 final Object d = data[i];
                 if (d == null) {
                     sb.append("<null> ");
-                } else if (d instanceof String || d instanceof ConsString) {
+                } else if (isString(d)) {
                     sb.append(d.toString());
                     sb.append(' ');
                 } else if (d.getClass().isArray()) {
--- a/src/jdk/nashorn/internal/objects/Global.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/Global.java	Thu Mar 12 13:45:00 2015 -0700
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.JSType.isString;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 import java.io.IOException;
@@ -55,7 +56,6 @@
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Property;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ECMAErrors;
 import jdk.nashorn.internal.runtime.GlobalConstants;
@@ -578,7 +578,7 @@
             return new NativeBoolean((Boolean)obj, this);
         } else if (obj instanceof Number) {
             return new NativeNumber(((Number)obj).doubleValue(), this);
-        } else if (obj instanceof String || obj instanceof ConsString) {
+        } else if (isString(obj)) {
             return new NativeString((CharSequence)obj, this);
         } else if (obj instanceof Object[]) { // extension
             return new NativeArray(ArrayData.allocate((Object[])obj), this);
@@ -605,7 +605,7 @@
      * @return guarded invocation
      */
     public static GuardedInvocation primitiveLookup(final LinkRequest request, final Object self) {
-        if (self instanceof String || self instanceof ConsString) {
+        if (isString(self)) {
             return NativeString.lookupPrimitive(request, self);
         } else if (self instanceof Number) {
             return NativeNumber.lookupPrimitive(request, self);
@@ -622,7 +622,7 @@
      * @return method handle to create wrapper objects for primitive receiver
      */
     public static MethodHandle getPrimitiveWrapFilter(final Object self) {
-        if (self instanceof String || self instanceof ConsString) {
+        if (isString(self)) {
             return NativeString.WRAPFILTER;
         } else if (self instanceof Number) {
             return NativeNumber.WRAPFILTER;
@@ -948,7 +948,7 @@
      * This is directly invoked from generated when eval(code) is called in user code
      */
     public static Object directEval(final Object self, final Object str, final Object callThis, final Object location, final boolean strict) {
-        if (!(str instanceof String || str instanceof ConsString)) {
+        if (!isString(str)) {
             return str;
         }
         final Global global = Global.instanceFrom(self);
--- a/src/jdk/nashorn/internal/objects/NativeDate.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java	Thu Mar 12 13:45:00 2015 -0700
@@ -30,6 +30,7 @@
 import static java.lang.Double.isNaN;
 import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
 import java.util.Locale;
 import java.util.TimeZone;
 import java.util.concurrent.Callable;
@@ -40,7 +41,6 @@
 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
 import jdk.nashorn.internal.objects.annotations.Where;
 import jdk.nashorn.internal.parser.DateParser;
-import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.PropertyMap;
 import jdk.nashorn.internal.runtime.ScriptEnvironment;
@@ -183,7 +183,7 @@
         case 1:
             double num;
             final Object arg = JSType.toPrimitive(args[0]);
-            if (arg instanceof String || arg instanceof ConsString) {
+            if (JSType.isString(arg)) {
                 num = parseDateString(arg.toString());
             } else {
                 num = timeClip(JSType.toNumber(args[0]));
--- a/src/jdk/nashorn/internal/objects/NativeJSON.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeJSON.java	Thu Mar 12 13:45:00 2015 -0700
@@ -181,7 +181,7 @@
                 }
                 gap = sb.toString();
             }
-        } else if (modSpace instanceof String || modSpace instanceof ConsString) {
+        } else if (JSType.isString(modSpace)) {
             final String str = modSpace.toString();
             gap = str.substring(0, Math.min(10, str.length()));
         } else {
--- a/src/jdk/nashorn/internal/objects/NativeString.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/NativeString.java	Thu Mar 12 13:45:00 2015 -0700
@@ -90,7 +90,7 @@
 
     private NativeString(final CharSequence value, final ScriptObject proto, final PropertyMap map) {
         super(proto, map);
-        assert value instanceof String || value instanceof ConsString;
+        assert JSType.isString(value);
         this.value = value;
     }
 
@@ -155,7 +155,7 @@
         final Object self = request.getReceiver();
         final Class<?> returnType = desc.getMethodType().returnType();
 
-        if (returnType == Object.class && (self instanceof String || self instanceof ConsString)) {
+        if (returnType == Object.class && JSType.isString(self)) {
             try {
                 return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getInstanceOf2Guard(String.class, ConsString.class));
             } catch (final LookupException e) {
@@ -1312,7 +1312,7 @@
     }
 
     private static CharSequence getCharSequence(final Object self) {
-        if (self instanceof String || self instanceof ConsString) {
+        if (JSType.isString(self)) {
             return (CharSequence)self;
         } else if (self instanceof NativeString) {
             return ((NativeString)self).getValue();
--- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java	Thu Mar 12 13:45:00 2015 -0700
@@ -305,7 +305,7 @@
         final ScriptFunction typeErrorThrower = global.getTypeErrorThrower();
         if (findProperty("arguments", true) != null) {
             initUserAccessors("arguments", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
-       }
+        }
         if (findProperty("caller", true) != null) {
             initUserAccessors("caller", Property.NOT_CONFIGURABLE | Property.NOT_ENUMERABLE, typeErrorThrower, typeErrorThrower);
        }
--- a/src/jdk/nashorn/internal/parser/JSONParser.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java	Thu Mar 12 13:45:00 2015 -0700
@@ -244,20 +244,15 @@
     private static PropertyMap addObjectProperty(final PropertyMap propertyMap, final List<Object> values,
                                                  final String id, final Object value) {
         final Property oldProperty = propertyMap.findProperty(id);
-        final Property newProperty;
         final PropertyMap newMap;
         final Class<?> type = ObjectClassGenerator.OBJECT_FIELDS_ONLY ? Object.class : getType(value);
 
         if (oldProperty != null) {
             values.set(oldProperty.getSlot(), value);
-            newProperty = new SpillProperty(id, 0, oldProperty.getSlot());
-            newProperty.setType(type);
-            newMap = propertyMap.replaceProperty(oldProperty, newProperty);;
+            newMap = propertyMap.replaceProperty(oldProperty, new SpillProperty(id, 0, oldProperty.getSlot(), type));;
         } else {
             values.add(value);
-            newProperty = new SpillProperty(id, 0, propertyMap.size());
-            newProperty.setType(type);
-            newMap = propertyMap.addProperty(newProperty);
+            newMap = propertyMap.addProperty(new SpillProperty(id, 0, propertyMap.size(), type));
         }
 
         return newMap;
--- a/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/AllocationStrategy.java	Thu Mar 12 13:45:00 2015 -0700
@@ -29,55 +29,52 @@
 import java.io.Serializable;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
+import jdk.nashorn.internal.codegen.Compiler;
 import jdk.nashorn.internal.codegen.CompilerConstants;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
+import jdk.nashorn.internal.codegen.ObjectClassGenerator;
 
 /**
- * Encapsulates the allocation strategy for a function when used as a constructor. Basically the same as
- * {@link AllocatorDescriptor}, but with an additionally cached resolved method handle. There is also a
- * canonical default allocation strategy for functions that don't assign any "this" properties (vast majority
- * of all functions), therefore saving some storage space in {@link RecompilableScriptFunctionData} that would
- * otherwise be lost to identical tuples of (map, className, handle) fields.
+ * Encapsulates the allocation strategy for a function when used as a constructor.
  */
-final class AllocationStrategy implements Serializable {
+final public class AllocationStrategy implements Serializable {
     private static final long serialVersionUID = 1L;
 
     private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 
-    private static final AllocationStrategy DEFAULT_STRATEGY = new AllocationStrategy(new AllocatorDescriptor(0));
-
-    /** Allocator map from allocator descriptor */
-    private final PropertyMap allocatorMap;
+    /** Number of fields in the allocated object */
+    private final int fieldCount;
 
     /** Name of class where allocator function resides */
-    private final String allocatorClassName;
+    private transient String allocatorClassName;
 
     /** lazily generated allocator */
     private transient MethodHandle allocator;
 
-    private AllocationStrategy(final AllocatorDescriptor desc) {
-        this.allocatorMap = desc.getAllocatorMap();
-        // These classes get loaded, so an interned variant of their name is most likely around anyway.
-        this.allocatorClassName = desc.getAllocatorClassName().intern();
+    /**
+     * Construct an allocation strategy with the given map and class name.
+     * @param fieldCount number of fields in the allocated object
+     */
+    public AllocationStrategy(final int fieldCount) {
+        this.fieldCount = fieldCount;
     }
 
-    private boolean matches(final AllocatorDescriptor desc) {
-        return desc.getAllocatorMap().size() == allocatorMap.size() &&
-                desc.getAllocatorClassName().equals(allocatorClassName);
-    }
-
-    static AllocationStrategy get(final AllocatorDescriptor desc) {
-        return DEFAULT_STRATEGY.matches(desc) ? DEFAULT_STRATEGY : new AllocationStrategy(desc);
+    private String getAllocatorClassName() {
+        if (allocatorClassName == null) {
+            // These classes get loaded, so an interned variant of their name is most likely around anyway.
+            allocatorClassName = Compiler.binaryName(ObjectClassGenerator.getClassName(fieldCount)).intern();
+        }
+        return allocatorClassName;
     }
 
     PropertyMap getAllocatorMap() {
-        return allocatorMap;
+        // Create a new map for each function instance
+        return PropertyMap.newMap(null, getAllocatorClassName(), 0, fieldCount, 0);
     }
 
     ScriptObject allocate(final PropertyMap map) {
         try {
             if (allocator == null) {
-                allocator = MH.findStatic(LOOKUP, Context.forStructureClass(allocatorClassName),
+                allocator = MH.findStatic(LOOKUP, Context.forStructureClass(getAllocatorClassName()),
                         CompilerConstants.ALLOCATE.symbolName(), MH.type(ScriptObject.class, PropertyMap.class));
             }
             return (ScriptObject)allocator.invokeExact(map);
@@ -88,17 +85,8 @@
         }
     }
 
-    private Object readResolve() {
-        if(allocatorMap.size() == DEFAULT_STRATEGY.allocatorMap.size() &&
-                allocatorClassName.equals(DEFAULT_STRATEGY.allocatorClassName)) {
-            return DEFAULT_STRATEGY;
-        }
-        return this;
-    }
-
     @Override
     public String toString() {
-        return "AllocationStrategy[allocatorClassName=" + allocatorClassName + ", allocatorMap.size=" +
-                allocatorMap.size() + "]";
+        return "AllocationStrategy[fieldCount=" + fieldCount + "]";
     }
 }
--- a/src/jdk/nashorn/internal/runtime/ConsString.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ConsString.java	Thu Mar 12 13:45:00 2015 -0700
@@ -25,6 +25,8 @@
 
 package jdk.nashorn.internal.runtime;
 
+import static jdk.nashorn.internal.runtime.JSType.isString;
+
 import java.util.ArrayDeque;
 import java.util.Deque;
 
@@ -52,8 +54,8 @@
      * @param right right char sequence
      */
     public ConsString(final CharSequence left, final CharSequence right) {
-        assert left instanceof String || left instanceof ConsString;
-        assert right instanceof String || right instanceof ConsString;
+        assert isString(left);
+        assert isString(right);
         this.left = left;
         this.right = right;
         length = left.length() + right.length();
--- a/src/jdk/nashorn/internal/runtime/JSType.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/JSType.java	Thu Mar 12 13:45:00 2015 -0700
@@ -29,6 +29,7 @@
 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.reflect.Array;
@@ -37,6 +38,7 @@
 import java.util.Deque;
 import java.util.List;
 import jdk.internal.dynalink.beans.StaticClass;
+import jdk.nashorn.api.scripting.AbstractJSObject;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.types.Type;
@@ -210,7 +212,6 @@
     /** Method handle for void returns. */
     public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class);
 
-
     /**
      * The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide
      *  in the dual--fields world
@@ -311,7 +312,7 @@
             return JSType.BOOLEAN;
         }
 
-        if (obj instanceof String || obj instanceof ConsString) {
+        if (isString(obj)) {
             return JSType.STRING;
         }
 
@@ -349,7 +350,7 @@
             return JSType.BOOLEAN;
         }
 
-        if (obj instanceof String || obj instanceof ConsString) {
+        if (isString(obj)) {
             return JSType.STRING;
         }
 
@@ -455,8 +456,7 @@
                obj == ScriptRuntime.UNDEFINED ||
                obj instanceof Boolean ||
                obj instanceof Number ||
-               obj instanceof String ||
-               obj instanceof ConsString;
+               isString(obj);
     }
 
    /**
@@ -480,17 +480,47 @@
      * @return the primitive form of the object
      */
     public static Object toPrimitive(final Object obj, final Class<?> hint) {
-        return obj instanceof ScriptObject ? toPrimitive((ScriptObject)obj, hint) : obj;
+        if (obj instanceof ScriptObject) {
+            return toPrimitive((ScriptObject)obj, hint);
+        } else if (isPrimitive(obj)) {
+            return obj;
+        } else if (obj instanceof JSObject) {
+            return toPrimitive((JSObject)obj, hint);
+        } else if (obj instanceof StaticClass) {
+            final String name = ((StaticClass)obj).getRepresentedClass().getName();
+            return new StringBuilder(12 + name.length()).append("[JavaClass ").append(name).append(']').toString();
+        }
+        return obj.toString();
     }
 
     private static Object toPrimitive(final ScriptObject sobj, final Class<?> hint) {
-        final Object result = sobj.getDefaultValue(hint);
+        return requirePrimitive(sobj.getDefaultValue(hint));
+    }
 
+    private static Object requirePrimitive(final Object result) {
         if (!isPrimitive(result)) {
             throw typeError("bad.default.value", result.toString());
         }
+        return result;
+    }
 
-        return result;
+    /**
+     * Primitive converter for a {@link JSObject} including type hint. Invokes
+     * {@link AbstractJSObject#getDefaultValue(JSObject, Class)} and translates any thrown
+     * {@link UnsupportedOperationException} to an ECMAScript {@code TypeError}.
+     * See ECMA 9.1 ToPrimitive
+     *
+     * @param jsobj  a JSObject
+     * @param hint a type hint
+     *
+     * @return the primitive form of the JSObject
+     */
+    public static Object toPrimitive(final JSObject jsobj, final Class<?> hint) {
+        try {
+            return requirePrimitive(AbstractJSObject.getDefaultValue(jsobj, hint));
+        } catch (final UnsupportedOperationException e) {
+            throw new ECMAException(Context.getGlobal().newTypeError(e.getMessage()), e);
+        }
     }
 
     /**
@@ -547,7 +577,7 @@
             return num != 0 && !Double.isNaN(num);
         }
 
-        if (obj instanceof String || obj instanceof ConsString) {
+        if (isString(obj)) {
             return ((CharSequence)obj).length() > 0;
         }
 
@@ -598,6 +628,15 @@
     }
 
     /**
+     * Returns true if object represents a primitive JavaScript string value.
+     * @param obj the object
+     * @return true if the object represents a primitive JavaScript string value.
+     */
+    public static boolean isString(final Object obj) {
+        return obj instanceof String || obj instanceof ConsString;
+    }
+
+    /**
      * JavaScript compliant conversion of integer to String
      *
      * @param num an integer
@@ -723,6 +762,48 @@
         return toNumberGeneric(obj);
     }
 
+    /**
+     * Converts an object for a comparison with a number. Almost identical to {@link #toNumber(Object)} but
+     * converts {@code null} to {@code NaN} instead of zero, so it won't compare equal to zero.
+     *
+     * @param obj  an object
+     *
+     * @return a number
+     */
+    public static double toNumberForEq(final Object obj) {
+        return obj == null ? Double.NaN : toNumber(obj);
+    }
+
+    /**
+     * Converts an object for strict comparison with a number. Returns {@code NaN} for any object that is not
+     * a {@link Number}, so only boxed numerics can compare strictly equal to numbers.
+     *
+     * @param obj  an object
+     *
+     * @return a number
+     */
+    public static double toNumberForStrictEq(final Object obj) {
+        if (obj instanceof Double) {
+            return (Double)obj;
+        }
+        if (obj instanceof Number) {
+            return ((Number)obj).doubleValue();
+        }
+        return Double.NaN;
+    }
+
+
+    /**
+     * JavaScript compliant conversion of Boolean to number
+     * See ECMA 9.3 ToNumber
+     *
+     * @param b a boolean
+     *
+     * @return JS numeric value of the boolean: 1.0 or 0.0
+     */
+    public static double toNumber(final Boolean b) {
+        return b ? 1d : +0d;
+    }
 
     /**
      * JavaScript compliant conversion of Object to number
@@ -1301,6 +1382,10 @@
             return (String)obj;
         }
 
+        if (obj instanceof ConsString) {
+            return obj.toString();
+        }
+
         if (obj instanceof Number) {
             return toString(((Number)obj).doubleValue());
         }
@@ -1313,23 +1398,19 @@
             return "null";
         }
 
-        if (obj instanceof ScriptObject) {
-            if (safe) {
-                final ScriptObject sobj = (ScriptObject)obj;
-                final Global gobj = Context.getGlobal();
-                return gobj.isError(sobj) ?
-                    ECMAException.safeToString(sobj) :
-                    sobj.safeToString();
-            }
-
-            return toString(toPrimitive(obj, String.class));
+        if (obj instanceof Boolean) {
+            return obj.toString();
         }
 
-        if (obj instanceof StaticClass) {
-            return "[JavaClass " + ((StaticClass)obj).getRepresentedClass().getName() + "]";
+        if (safe && obj instanceof ScriptObject) {
+            final ScriptObject sobj = (ScriptObject)obj;
+            final Global gobj = Context.getGlobal();
+            return gobj.isError(sobj) ?
+                ECMAException.safeToString(sobj) :
+                sobj.safeToString();
         }
 
-        return obj.toString();
+        return toString(toPrimitive(obj, String.class));
     }
 
     // trim from left for JS whitespaces.
@@ -1822,18 +1903,18 @@
         }
 
         if (obj instanceof Boolean) {
-            return (Boolean)obj ? 1 : +0.0;
+            return toNumber((Boolean)obj);
         }
 
         if (obj instanceof ScriptObject) {
             return toNumber((ScriptObject)obj);
         }
 
-        if (obj instanceof JSObject) {
-            return ((JSObject)obj).toNumber();
+        if (obj instanceof Undefined) {
+            return Double.NaN;
         }
 
-        return Double.NaN;
+        return toNumber(toPrimitive(obj, Number.class));
     }
 
     private static Object invoke(final MethodHandle mh, final Object arg) {
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Thu Mar 12 13:45:00 2015 -0700
@@ -43,7 +43,6 @@
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.FunctionSignature;
 import jdk.nashorn.internal.codegen.Namespace;
-import jdk.nashorn.internal.codegen.ObjectClassGenerator.AllocatorDescriptor;
 import jdk.nashorn.internal.codegen.OptimisticTypesPersistence;
 import jdk.nashorn.internal.codegen.TypeMap;
 import jdk.nashorn.internal.codegen.types.Type;
@@ -126,7 +125,7 @@
      *
      * @param functionNode        functionNode that represents this function code
      * @param installer           installer for code regeneration versions of this function
-     * @param allocationDescriptor descriptor for the allocation behavior when this function is used as a constructor
+     * @param allocationStrategy  strategy for the allocation behavior when this function is used as a constructor
      * @param nestedFunctions     nested function map
      * @param externalScopeDepths external scope depths
      * @param internalSymbols     internal symbols to method, defined in its scope
@@ -135,7 +134,7 @@
     public RecompilableScriptFunctionData(
         final FunctionNode functionNode,
         final CodeInstaller<ScriptEnvironment> installer,
-        final AllocatorDescriptor allocationDescriptor,
+        final AllocationStrategy allocationStrategy,
         final Map<Integer, RecompilableScriptFunctionData> nestedFunctions,
         final Map<String, Integer> externalScopeDepths,
         final Set<String> internalSymbols,
@@ -153,7 +152,7 @@
         this.endParserState      = functionNode.getEndParserState();
         this.token               = tokenFor(functionNode);
         this.installer           = installer;
-        this.allocationStrategy  = AllocationStrategy.get(allocationDescriptor);
+        this.allocationStrategy  = allocationStrategy;
         this.nestedFunctions     = smallMap(nestedFunctions);
         this.externalScopeDepths = smallMap(externalScopeDepths);
         this.internalSymbols     = smallSet(new HashSet<>(internalSymbols));
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java	Thu Mar 12 13:45:00 2015 -0700
@@ -143,7 +143,6 @@
 
         this.data  = data;
         this.scope = scope;
-        this.allocatorMap = data.getAllocatorMap();
     }
 
     @Override
@@ -253,7 +252,7 @@
 
         assert !isBoundFunction(); // allocate never invoked on bound functions
 
-        final ScriptObject object = data.allocate(allocatorMap);
+        final ScriptObject object = data.allocate(getAllocatorMap());
 
         if (object != null) {
             final Object prototype = getPrototype();
@@ -269,6 +268,13 @@
         return object;
     }
 
+    private PropertyMap getAllocatorMap() {
+        if (allocatorMap == null) {
+            allocatorMap = data.getAllocatorMap();
+        }
+        return allocatorMap;
+    }
+
     /**
      * Return Object.prototype - used by "allocate"
      * @return Object.prototype
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java	Thu Mar 12 13:45:00 2015 -0700
@@ -28,6 +28,7 @@
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
@@ -456,8 +457,7 @@
     }
 
     static boolean isPrimitiveThis(final Object obj) {
-        return obj instanceof String || obj instanceof ConsString ||
-               obj instanceof Number || obj instanceof Boolean;
+        return JSType.isString(obj) || obj instanceof Number || obj instanceof Boolean;
     }
 
     /**
--- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java	Thu Mar 12 13:45:00 2015 -0700
@@ -32,6 +32,8 @@
 import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
+import static jdk.nashorn.internal.runtime.JSType.isString;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.SwitchPoint;
@@ -55,7 +57,6 @@
 import jdk.nashorn.internal.parser.Lexer;
 import jdk.nashorn.internal.runtime.linker.Bootstrap;
 
-
 /**
  * Utilities to be called by JavaScript runtime API and generated classes.
  */
@@ -535,8 +536,6 @@
 
     /**
      * ECMA 11.6.1 - The addition operator (+) - generic implementation
-     * Compiler specializes using {@link jdk.nashorn.internal.codegen.RuntimeCallSite}
-     * if any type information is available for any of the operands
      *
      * @param x  first term
      * @param y  second term
@@ -563,8 +562,7 @@
         final Object xPrim = JSType.toPrimitive(x);
         final Object yPrim = JSType.toPrimitive(y);
 
-        if (xPrim instanceof String || yPrim instanceof String
-                || xPrim instanceof ConsString || yPrim instanceof ConsString) {
+        if (isString(xPrim) || isString(yPrim)) {
             try {
                 return new ConsString(JSType.toCharSequence(xPrim), JSType.toCharSequence(yPrim));
             } catch (final IllegalArgumentException iae) {
@@ -734,7 +732,7 @@
             return true;
         }
         if (x instanceof ScriptObject && y instanceof ScriptObject) {
-            return x == y;
+            return false; // x != y
         }
         if (x instanceof ScriptObjectMirror || y instanceof ScriptObjectMirror) {
             return ScriptObjectMirror.identical(x, y);
@@ -798,37 +796,55 @@
      * @return true if they're equal
      */
     private static boolean equalDifferentTypeValues(final Object x, final Object y, final JSType xType, final JSType yType) {
-        if (xType == JSType.UNDEFINED && yType == JSType.NULL || xType == JSType.NULL && yType == JSType.UNDEFINED) {
+        if (isUndefinedAndNull(xType, yType) || isUndefinedAndNull(yType, xType)) {
             return true;
-        }
-
-        if (xType == JSType.NUMBER && yType == JSType.STRING) {
-            return equals(x, JSType.toNumber(y));
-        }
-
-        if (xType == JSType.STRING && yType == JSType.NUMBER) {
-            return equals(JSType.toNumber(x), y);
-        }
-
-        if (xType == JSType.BOOLEAN) {
-            return equals(JSType.toNumber(x), y);
-        }
-
-        if (yType == JSType.BOOLEAN) {
-            return equals(x, JSType.toNumber(y));
-        }
-
-        if ((xType == JSType.STRING || xType == JSType.NUMBER) && y instanceof ScriptObject)  {
-            return equals(x, JSType.toPrimitive(y));
-        }
-
-        if (x instanceof ScriptObject && (yType == JSType.STRING || yType == JSType.NUMBER)) {
-            return equals(JSType.toPrimitive(x), y);
+        } else if (isNumberAndString(xType, yType)) {
+            return equalNumberToString(x, y);
+        } else if (isNumberAndString(yType, xType)) {
+            // Can reverse order as both are primitives
+            return equalNumberToString(y, x);
+        } else if (xType == JSType.BOOLEAN) {
+            return equalBooleanToAny(x, y);
+        } else if (yType == JSType.BOOLEAN) {
+            // Can reverse order as y is primitive
+            return equalBooleanToAny(y, x);
+        } else if (isNumberOrStringAndObject(xType, yType)) {
+            return equalNumberOrStringToObject(x, y);
+        } else if (isNumberOrStringAndObject(yType, xType)) {
+            // Can reverse order as y is primitive
+            return equalNumberOrStringToObject(y, x);
         }
 
         return false;
     }
 
+    private static boolean isUndefinedAndNull(final JSType xType, final JSType yType) {
+        return xType == JSType.UNDEFINED && yType == JSType.NULL;
+    }
+
+    private static boolean isNumberAndString(final JSType xType, final JSType yType) {
+        return xType == JSType.NUMBER && yType == JSType.STRING;
+    }
+
+    private static boolean isNumberOrStringAndObject(final JSType xType, final JSType yType) {
+        return (xType == JSType.NUMBER || xType == JSType.STRING) && yType == JSType.OBJECT;
+    }
+
+    private static boolean equalNumberToString(final Object num, final Object str) {
+        // Specification says comparing a number to string should be done as "equals(num, JSType.toNumber(str))". We
+        // can short circuit it to this as we know that "num" is a number, so it'll end up being a number-number
+        // comparison.
+        return ((Number)num).doubleValue() == JSType.toNumber(str.toString());
+    }
+
+    private static boolean equalBooleanToAny(final Object bool, final Object any) {
+        return equals(JSType.toNumber((Boolean)bool), any);
+    }
+
+    private static boolean equalNumberOrStringToObject(final Object numOrStr, final Object any) {
+        return equals(numOrStr, JSType.toPrimitive(any));
+    }
+
     /**
      * ECMA 11.9.4 - The strict equal operator (===) - generic implementation
      *
@@ -935,8 +951,15 @@
      * @return true if x is less than y
      */
     public static boolean LT(final Object x, final Object y) {
-        final Object value = lessThan(x, y, true);
-        return value == UNDEFINED ? false : (Boolean)value;
+        final Object px = JSType.toPrimitive(x, Number.class);
+        final Object py = JSType.toPrimitive(y, Number.class);
+
+        return areBothString(px, py) ? px.toString().compareTo(py.toString()) < 0 :
+            JSType.toNumber(px) < JSType.toNumber(py);
+    }
+
+    private static boolean areBothString(final Object x, final Object y) {
+        return isString(x) && isString(y);
     }
 
     /**
@@ -948,8 +971,11 @@
      * @return true if x is greater than y
      */
     public static boolean GT(final Object x, final Object y) {
-        final Object value = lessThan(y, x, false);
-        return value == UNDEFINED ? false : (Boolean)value;
+        final Object px = JSType.toPrimitive(x, Number.class);
+        final Object py = JSType.toPrimitive(y, Number.class);
+
+        return areBothString(px, py) ? px.toString().compareTo(py.toString()) > 0 :
+            JSType.toNumber(px) > JSType.toNumber(py);
     }
 
     /**
@@ -961,8 +987,11 @@
      * @return true if x is less than or equal to y
      */
     public static boolean LE(final Object x, final Object y) {
-        final Object value = lessThan(y, x, false);
-        return !(Boolean.TRUE.equals(value) || value == UNDEFINED);
+        final Object px = JSType.toPrimitive(x, Number.class);
+        final Object py = JSType.toPrimitive(y, Number.class);
+
+        return areBothString(px, py) ? px.toString().compareTo(py.toString()) <= 0 :
+            JSType.toNumber(px) <= JSType.toNumber(py);
     }
 
     /**
@@ -974,48 +1003,11 @@
      * @return true if x is greater than or equal to y
      */
     public static boolean GE(final Object x, final Object y) {
-        final Object value = lessThan(x, y, true);
-        return !(Boolean.TRUE.equals(value) || value == UNDEFINED);
-    }
+        final Object px = JSType.toPrimitive(x, Number.class);
+        final Object py = JSType.toPrimitive(y, Number.class);
 
-    /** ECMA 11.8.5 The Abstract Relational Comparison Algorithm */
-    private static Object lessThan(final Object x, final Object y, final boolean leftFirst) {
-        Object px, py;
-
-        //support e.g. x < y should throw exception correctly if x or y are not numeric
-        if (leftFirst) {
-            px = JSType.toPrimitive(x, Number.class);
-            py = JSType.toPrimitive(y, Number.class);
-        } else {
-            py = JSType.toPrimitive(y, Number.class);
-            px = JSType.toPrimitive(x, Number.class);
-        }
-
-        if (JSType.ofNoFunction(px) == JSType.STRING && JSType.ofNoFunction(py) == JSType.STRING) {
-            // May be String or ConsString
-            return px.toString().compareTo(py.toString()) < 0;
-        }
-
-        final double nx = JSType.toNumber(px);
-        final double ny = JSType.toNumber(py);
-
-        if (Double.isNaN(nx) || Double.isNaN(ny)) {
-            return UNDEFINED;
-        }
-
-        if (nx == ny) {
-            return false;
-        }
-
-        if (nx > 0 && ny > 0 && Double.isInfinite(nx) && Double.isInfinite(ny)) {
-            return false;
-        }
-
-        if (nx < 0 && ny < 0 && Double.isInfinite(nx) && Double.isInfinite(ny)) {
-            return false;
-        }
-
-        return nx < ny;
+        return areBothString(px, py) ? px.toString().compareTo(py.toString()) >= 0 :
+            JSType.toNumber(px) >= JSType.toNumber(py);
     }
 
     /**
@@ -1028,9 +1020,7 @@
         final Context context = Context.getContextTrusted();
         final SwitchPoint sp = context.getBuiltinSwitchPoint(name);
         assert sp != null;
-        if (sp != null) {
-            context.getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
-            SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
-        }
+        context.getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
+        SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
     }
 }
--- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Thu Mar 12 13:45:00 2015 -0700
@@ -107,7 +107,7 @@
 
         if (file instanceof File) {
             f = (File)file;
-        } else if (file instanceof String || file instanceof ConsString) {
+        } else if (JSType.isString(file)) {
             f = new java.io.File(((CharSequence)file).toString());
         }
 
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java	Thu Mar 12 13:45:00 2015 -0700
@@ -164,7 +164,14 @@
         assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class;
     }
 
-    SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
+    /**
+     * Constructor for spill properties with an initial type.
+     * @param key         the property key
+     * @param flags       the property flags
+     * @param slot        spill slot
+     * @param initialType initial type
+     */
+    public SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
         this(key, flags, slot);
         setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
     }
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java	Thu Mar 12 13:45:00 2015 -0700
@@ -48,7 +48,6 @@
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
 import jdk.nashorn.internal.codegen.ObjectClassGenerator;
-import jdk.nashorn.internal.codegen.RuntimeCallSite;
 import jdk.nashorn.internal.lookup.MethodHandleFactory;
 import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
 import jdk.nashorn.internal.objects.ScriptFunctionImpl;
@@ -210,19 +209,6 @@
     }
 
     /**
-     * Bootstrapper for a specialized Runtime call
-     *
-     * @param lookup       lookup
-     * @param initialName  initial name for callsite
-     * @param type         method type for call site
-     *
-     * @return callsite for a runtime node
-     */
-    public static CallSite runtimeBootstrap(final MethodHandles.Lookup lookup, final String initialName, final MethodType type) {
-        return new RuntimeCallSite(type, initialName);
-    }
-
-    /**
      * Boostrapper for math calls that may overflow
      * @param lookup         lookup
      * @param name           name of operation
--- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java	Thu Mar 12 13:45:00 2015 -0700
@@ -25,11 +25,13 @@
 
 package jdk.nashorn.internal.runtime.linker;
 
+import static jdk.nashorn.internal.runtime.JSType.isString;
+import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_CALL;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETMEMBER;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_GETSLOT;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETMEMBER;
 import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_SETSLOT;
-import static jdk.nashorn.internal.runtime.linker.BrowserJSObjectLinker.JSObjectHandles.JSOBJECT_CALL;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import jdk.internal.dynalink.CallSiteDescriptor;
@@ -170,12 +172,12 @@
             if (index > -1) {
                 return JSOBJECT_GETSLOT.invokeExact(jsobj, index);
             }
-        } else if (key instanceof String) {
-            final String name = (String)key;
+        } else if (isString(key)) {
+            final String name = key.toString();
             if (name.indexOf('(') != -1) {
-                return fallback.invokeExact(jsobj, key);
+                return fallback.invokeExact(jsobj, (Object) name);
             }
-            return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
+            return JSOBJECT_GETMEMBER.invokeExact(jsobj, name);
         }
         return null;
     }
@@ -186,8 +188,8 @@
             JSOBJECT_SETSLOT.invokeExact(jsobj, (int)key, value);
         } else if (key instanceof Number) {
             JSOBJECT_SETSLOT.invokeExact(jsobj, getIndex((Number)key), value);
-        } else if (key instanceof String) {
-            JSOBJECT_SETMEMBER.invokeExact(jsobj, (String)key, value);
+        } else if (isString(key)) {
+            JSOBJECT_SETMEMBER.invokeExact(jsobj, key.toString(), value);
         }
     }
 
--- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java	Thu Mar 12 13:45:00 2015 -0700
@@ -25,16 +25,14 @@
 
 package jdk.nashorn.internal.runtime.linker;
 
+import static jdk.nashorn.internal.runtime.JSType.isString;
+
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.util.HashMap;
 import java.util.Map;
 import javax.script.Bindings;
 import jdk.internal.dynalink.CallSiteDescriptor;
 import jdk.internal.dynalink.linker.GuardedInvocation;
-import jdk.internal.dynalink.linker.GuardedTypeConversion;
-import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
 import jdk.internal.dynalink.linker.LinkRequest;
 import jdk.internal.dynalink.linker.LinkerServices;
 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
@@ -48,7 +46,7 @@
  * A Dynalink linker to handle web browser built-in JS (DOM etc.) objects as well
  * as ScriptObjects from other Nashorn contexts.
  */
-final class JSObjectLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory {
+final class JSObjectLinker implements TypeBasedGuardingDynamicLinker {
     private final NashornBeansLinker nashornBeansLinker;
 
     JSObjectLinker(final NashornBeansLinker nashornBeansLinker) {
@@ -94,22 +92,6 @@
         return Bootstrap.asTypeSafeReturn(inv, linkerServices, desc);
     }
 
-    @Override
-    public GuardedTypeConversion convertToType(final Class<?> sourceType, final Class<?> targetType) throws Exception {
-        final boolean sourceIsAlwaysJSObject = JSObject.class.isAssignableFrom(sourceType);
-        if(!sourceIsAlwaysJSObject && !sourceType.isAssignableFrom(JSObject.class)) {
-            return null;
-        }
-
-        final MethodHandle converter = CONVERTERS.get(targetType);
-        if(converter == null) {
-            return null;
-        }
-
-        return new GuardedTypeConversion(new GuardedInvocation(converter, sourceIsAlwaysJSObject ? null : IS_JSOBJECT_GUARD).asType(MethodType.methodType(targetType, sourceType)), true);
-    }
-
-
     private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception {
         final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
         final int c = desc.getNameTokenCount();
@@ -185,11 +167,11 @@
             if (index > -1) {
                 return ((JSObject)jsobj).getSlot(index);
             }
-        } else if (key instanceof String) {
-            final String name = (String)key;
+        } else if (isString(key)) {
+            final String name = key.toString();
             // get with method name and signature. delegate it to beans linker!
             if (name.indexOf('(') != -1) {
-                return fallback.invokeExact(jsobj, key);
+                return fallback.invokeExact(jsobj, (Object) name);
             }
             return ((JSObject)jsobj).getMember(name);
         }
@@ -202,30 +184,11 @@
             ((JSObject)jsobj).setSlot((Integer)key, value);
         } else if (key instanceof Number) {
             ((JSObject)jsobj).setSlot(getIndex((Number)key), value);
-        } else if (key instanceof String) {
-            ((JSObject)jsobj).setMember((String)key, value);
+        } else if (isString(key)) {
+            ((JSObject)jsobj).setMember(key.toString(), value);
         }
     }
 
-    @SuppressWarnings("unused")
-    private static int toInt32(final JSObject obj) {
-        return JSType.toInt32(toNumber(obj));
-    }
-
-    @SuppressWarnings("unused")
-    private static long toLong(final JSObject obj) {
-        return JSType.toLong(toNumber(obj));
-    }
-
-    private static double toNumber(final JSObject obj) {
-        return obj == null ? 0 : obj.toNumber();
-    }
-
-    @SuppressWarnings("unused")
-    private static boolean toBoolean(final JSObject obj) {
-        return obj != null;
-    }
-
     private static int getIndex(final Number n) {
         final double value = n.doubleValue();
         return JSType.isRepresentableAsInt(value) ? (int)value : -1;
@@ -260,14 +223,6 @@
     private static final MethodHandle JSOBJECT_CALL_TO_APPLY = findOwnMH_S("callToApply", Object.class, MethodHandle.class, JSObject.class, Object.class, Object[].class);
     private static final MethodHandle JSOBJECT_NEW           = findJSObjectMH_V("newObject", Object.class, Object[].class);
 
-    private static final Map<Class<?>, MethodHandle> CONVERTERS = new HashMap<>();
-    static {
-        CONVERTERS.put(boolean.class, findOwnMH_S("toBoolean", boolean.class, JSObject.class));
-        CONVERTERS.put(int.class,     findOwnMH_S("toInt32", int.class, JSObject.class));
-        CONVERTERS.put(long.class,    findOwnMH_S("toLong", long.class, JSObject.class));
-        CONVERTERS.put(double.class,  findOwnMH_S("toNumber", double.class, JSObject.class));
-    }
-
     private static MethodHandle findJSObjectMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
         return MH.findVirtual(MethodHandles.lookup(), JSObject.class, name, MH.type(rtype, types));
     }
--- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java	Thu Mar 12 13:45:00 2015 -0700
@@ -27,6 +27,7 @@
 
 import static jdk.nashorn.internal.lookup.Lookup.MH;
 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+import static jdk.nashorn.internal.runtime.JSType.isString;
 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
 
 import java.lang.invoke.MethodHandle;
@@ -78,7 +79,7 @@
         }
 
         if (obj == UNDEFINED) {
-            // NOTE: same reasoning for FindBugs NP_BOOLEAN_RETURN_NUL warning as in the preceding comment.
+            // NOTE: same reasoning for FindBugs NP_BOOLEAN_RETURN_NULL warning as in the preceding comment.
             return null;
         }
 
@@ -87,7 +88,7 @@
             return num != 0 && !Double.isNaN(num);
         }
 
-        if (obj instanceof String || obj instanceof ConsString) {
+        if (isString(obj)) {
             return ((CharSequence) obj).length() > 0;
         }
 
@@ -207,7 +208,7 @@
                 return f.longValue();
             } else if (obj instanceof Number) {
                 return ((Number)obj).longValue();
-            } else if (obj instanceof String || obj instanceof ConsString) {
+            } else if (isString(obj)) {
                 return JSType.toLong(obj);
             } else if (obj instanceof Boolean) {
                 return (Boolean)obj ? 1L : 0L;
--- a/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java	Thu Mar 12 13:45:00 2015 -0700
@@ -39,6 +39,7 @@
 import jdk.internal.dynalink.support.TypeUtilities;
 import jdk.nashorn.internal.objects.Global;
 import jdk.nashorn.internal.runtime.ConsString;
+import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptRuntime;
 
 /**
@@ -170,7 +171,7 @@
 
     @SuppressWarnings("unused")
     private static boolean isJavaScriptPrimitive(final Object o) {
-        return o instanceof String || o instanceof Boolean || o instanceof Number || o instanceof ConsString || o == null;
+        return JSType.isString(o) || o instanceof Boolean || o instanceof Number || o == null;
     }
 
     private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class);
--- a/test/script/basic/JDK-8023026.js.EXPECTED	Wed Mar 11 14:11:06 2015 -0700
+++ b/test/script/basic/JDK-8023026.js.EXPECTED	Thu Mar 12 13:45:00 2015 -0700
@@ -26,7 +26,7 @@
 reduceRight 15 1
 right sum 16
 squared 1,9,25,49
-iterating on [object Array]
+iterating on 2,4,6,8
 forEach 2
 forEach 4
 forEach 6
--- a/test/script/basic/JDK-8024847.js	Wed Mar 11 14:11:06 2015 -0700
+++ b/test/script/basic/JDK-8024847.js	Thu Mar 12 13:45:00 2015 -0700
@@ -102,7 +102,18 @@
 print(jlist);
 
 var obj = new JSObject() {
-    toNumber: function() { return 42; }
+    getMember: function(name) {
+        if (name == "valueOf") {
+            return new JSObject() {
+                isFunction: function() {
+                    return true;
+                },
+                call: function(thiz) {
+                    return 42;
+                }
+            };
+        }
+    }
 };
 
 print(32 + obj);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8035712.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8035712: Restore some of the RuntimeCallSite specializations
+ *
+ * @test
+ * @run
+ */
+
+if ((typeof Assert) == "undefined") {
+    Assert = { 
+        assertTrue: function(x) { if(!x) { throw "expected true" } },
+        assertFalse: function(x) { if(x) { throw "expected false" } },
+    };
+}
+
+function nop() {}
+
+function EQ(x, y) {
+    // Exercise normal evaluation
+    Assert.assertTrue (x == y);
+    Assert.assertTrue (y == x);
+    Assert.assertFalse(x != y);
+    Assert.assertFalse(y != x);
+    // Exercise the branch optimizer
+    if (x == y) { nop(); } else { Assert.fail(); }
+    if (y == x) { nop(); } else { Assert.fail(); }
+    if (x != y) { Assert.fail(); } else { nop(); }
+    if (y != x) { Assert.fail(); } else { nop(); }
+}
+
+function NE(x, y) {
+    // Exercise normal evaluation
+    Assert.assertTrue (x != y);
+    Assert.assertTrue (y != x);
+    Assert.assertFalse(x == y);
+    Assert.assertFalse(y == x);
+    // Exercise the branch optimizer
+    if (x != y) { nop(); } else { Assert.fail(); }
+    if (y != x) { nop(); } else { Assert.fail(); }
+    if (x == y) { Assert.fail(); } else { nop(); }
+    if (y == x) { Assert.fail(); } else { nop(); }
+}
+
+function STRICT_EQ(x, y) {
+    // Exercise normal evaluation
+    Assert.assertTrue (x === y);
+    Assert.assertTrue (y === x);
+    Assert.assertFalse(x !== y);
+    Assert.assertFalse(y !== x);
+    // Exercise the branch optimizer
+    if (x === y) { nop(); } else { Assert.fail(); }
+    if (y === x) { nop(); } else { Assert.fail(); }
+    if (x !== y) { Assert.fail(); } else { nop(); }
+    if (y !== x) { Assert.fail(); } else { nop(); }
+}
+
+function STRICT_NE(x, y) {
+    // Exercise normal evaluation
+    Assert.assertTrue (x !== y);
+    Assert.assertTrue (y !== x);
+    Assert.assertFalse(x === y);
+    Assert.assertFalse(y === x);
+    // Exercise the branch optimizer
+    if (x !== y) { nop(); } else { Assert.fail(); }
+    if (y !== x) { nop(); } else { Assert.fail(); }
+    if (x === y) { Assert.fail(); } else { nop(); }
+    if (y === x) { Assert.fail(); } else { nop(); }
+}
+
+function cmpToAnyNumber(cmp, value) {
+    cmp(1, value);
+    cmp(4294967296, value);
+    cmp(1.2, value);
+    cmp(Infinity, value);
+    cmp(-Infinity, value);
+    cmp(1/Infinity, value);
+    cmp(0, value);
+    cmp(-0, value);
+    cmp(true, value);
+    cmp(false, value);
+}
+
+function notEqualToAnyNumber(value) {
+    cmpToAnyNumber(NE, value);
+    cmpToAnyNumber(STRICT_NE, value);
+}
+
+notEqualToAnyNumber(null);
+notEqualToAnyNumber(void 0);
+notEqualToAnyNumber("abc");
+notEqualToAnyNumber({});
+notEqualToAnyNumber(["xyz"]);
+
+function objectWithPrimitiveFunctionNotEqualToAnyNumber(fnName) {
+    var obj = {
+        count: 0
+    };
+    obj[fnName] = function() { this.count++; return "foo"; };
+    notEqualToAnyNumber(obj);
+    // Every NE will invoke it 8 times; cmpToAnyNumber has 10 comparisons
+    // STRICT_NE doesn't invoke toString.
+    Assert.assertTrue(80 === obj.count);
+}
+objectWithPrimitiveFunctionNotEqualToAnyNumber("valueOf");
+objectWithPrimitiveFunctionNotEqualToAnyNumber("toString");
+
+function objectEqualButNotStrictlyEqual(val, obj) {
+    EQ(val, obj);
+    STRICT_NE(val, obj);
+}
+
+function numberEqualButNotStrictlyEqualToObject(num, obj) {
+    objectEqualButNotStrictlyEqual(num, obj);
+    objectEqualButNotStrictlyEqual(num, [obj]);
+    objectEqualButNotStrictlyEqual(num, [[obj]]);
+}
+
+function numberEqualButNotStrictlyEqualToZeroObjects(num) {
+    numberEqualButNotStrictlyEqualToObject(num, [0]);
+    numberEqualButNotStrictlyEqualToObject(num, "");
+    numberEqualButNotStrictlyEqualToObject(num, []);
+    numberEqualButNotStrictlyEqualToObject(num, "0");
+}
+
+numberEqualButNotStrictlyEqualToZeroObjects(0);
+numberEqualButNotStrictlyEqualToZeroObjects(1/Infinity);
+numberEqualButNotStrictlyEqualToZeroObjects(false);
+
+function numberEqualButNotStrictlyEqualToObjectEquivalent(num) {
+    var str = String(num);
+    objectEqualButNotStrictlyEqual(num, str);
+    objectEqualButNotStrictlyEqual(num, { valueOf:  function() { return str }});
+    objectEqualButNotStrictlyEqual(num, { toString: function() { return str }});
+    objectEqualButNotStrictlyEqual(num, { valueOf:  function() { return num }});
+    objectEqualButNotStrictlyEqual(num, { toString: function() { return num }});
+}
+
+numberEqualButNotStrictlyEqualToObjectEquivalent(1);
+numberEqualButNotStrictlyEqualToObjectEquivalent(4294967296);
+numberEqualButNotStrictlyEqualToObjectEquivalent(1.2);
+numberEqualButNotStrictlyEqualToObjectEquivalent(Infinity);
+numberEqualButNotStrictlyEqualToObjectEquivalent(-Infinity);
+numberEqualButNotStrictlyEqualToObjectEquivalent(1/Infinity);
+numberEqualButNotStrictlyEqualToObjectEquivalent(0);
+numberEqualButNotStrictlyEqualToObjectEquivalent(-0);
+
+STRICT_EQ(1, new java.lang.Integer(1));
+STRICT_EQ(1, new java.lang.Double(1));
+STRICT_EQ(1.2, new java.lang.Double(1.2));
+
+function LE(x, y) {
+    // Exercise normal evaluation
+    Assert.assertTrue(x <= y);
+    Assert.assertTrue(y >= x);
+    Assert.assertFalse(x > y);
+    Assert.assertFalse(x < y);
+    // Exercise the branch optimizer
+    if (x <= y) { nop(); } else { Assert.fail(); }
+    if (y >= x) { nop(); } else { Assert.fail(); }
+    if (x > y) { Assert.fail(); } else { nop(); }
+    if (y < x) { Assert.fail(); } else { nop(); }
+}
+
+function mutuallyLessThanOrEqual(x, y) {
+    LE(x, y);
+    LE(y, x);
+}
+
+mutuallyLessThanOrEqual(0, null);
+mutuallyLessThanOrEqual(false, null);
+mutuallyLessThanOrEqual(1/Infinity, null);
+
+function mutuallyLessThanEqualToObjectWithValue(num, val) {
+    mutuallyLessThanOrEqual(num, { valueOf: function() { return val } });
+    mutuallyLessThanOrEqual(num, { toString: function() { return val } });
+}
+
+mutuallyLessThanEqualToObjectWithValue(false, 0);
+mutuallyLessThanEqualToObjectWithValue(false, "");
+
+mutuallyLessThanEqualToObjectWithValue(true, 1);
+mutuallyLessThanEqualToObjectWithValue(true, "1");
+
+function lessThanEqualToObjectEquivalent(num) {
+    var str = String(num);
+    mutuallyLessThanOrEqual(num, str);
+    mutuallyLessThanEqualToObjectWithValue(num, num);
+    mutuallyLessThanEqualToObjectWithValue(num, str);
+}
+
+lessThanEqualToObjectEquivalent(1);
+lessThanEqualToObjectEquivalent(4294967296);
+lessThanEqualToObjectEquivalent(1.2);
+lessThanEqualToObjectEquivalent(Infinity);
+lessThanEqualToObjectEquivalent(-Infinity);
+lessThanEqualToObjectEquivalent(1/Infinity);
+lessThanEqualToObjectEquivalent(0);
+lessThanEqualToObjectEquivalent(-0);
+
+function INCOMPARABLE(x, y) {
+    // Exercise normal evaluation
+    Assert.assertFalse(x < y);
+    Assert.assertFalse(x > y);
+    Assert.assertFalse(x <= y);
+    Assert.assertFalse(x >= y);
+    Assert.assertFalse(y < x);
+    Assert.assertFalse(y > x);
+    Assert.assertFalse(y <= x);
+    Assert.assertFalse(y >= x);
+    // Exercise the branch optimizer
+    if (x < y) { Assert.fail(); } else { nop(); }
+    if (x > y) { Assert.fail(); } else { nop(); }
+    if (x <= y) { Assert.fail(); } else { nop(); }
+    if (x >= y) { Assert.fail(); } else { nop(); }
+    if (y < x) { Assert.fail(); } else { nop(); }
+    if (y > x) { Assert.fail(); } else { nop(); }
+    if (y <= x) { Assert.fail(); } else { nop(); }
+    if (y >= x) { Assert.fail(); } else { nop(); }
+}
+
+function isIncomparable(value) {
+    cmpToAnyNumber(INCOMPARABLE, value);
+}
+
+isIncomparable(void 0);
+isIncomparable({ valueOf: function() { return NaN }});
+isIncomparable({ toString: function() { return NaN }});
+
+// Force ScriptRuntime.LT(Object, Object) etc. comparisons
+function cmpObj(fn, x, y) {
+    fn({valueOf: function() { return x }}, {valueOf: function() { return y }});
+}
+
+function LT(x, y) {
+    Assert.assertTrue(x < y);
+    Assert.assertTrue(y > x);
+    Assert.assertFalse(x >= y);
+    Assert.assertFalse(y <= x);
+}
+
+cmpObj(LT, 1, 2);
+cmpObj(LT, 1, "2");
+cmpObj(LT, "1", 2);
+cmpObj(LT, "a", "b");
+cmpObj(LT, -Infinity, 0);
+cmpObj(LT, 0, Infinity);
+cmpObj(LT, -Infinity, Infinity);
+cmpObj(INCOMPARABLE, 1, NaN);
+cmpObj(INCOMPARABLE, NaN, NaN);
+cmpObj(INCOMPARABLE, "boo", NaN);
+cmpObj(INCOMPARABLE, 1, "boo"); // boo number value will be NaN
+
+// Test that a comparison call site can deoptimize from (int, int) to (object, object)
+(function(){
+    var x = [1,  2,  "a"];
+    var y = [2, "3", "b"];
+    for(var i = 0; i < 3; ++i) {
+        Assert.assertTrue(x[i] < y[i]);
+    }
+})();
--- a/test/script/basic/JDK-8055762.js	Wed Mar 11 14:11:06 2015 -0700
+++ b/test/script/basic/JDK-8055762.js	Thu Mar 12 13:45:00 2015 -0700
@@ -74,9 +74,12 @@
         }
     };
 
+    var a = "a";
     print(obj["foo"]);
+    print(obj[a + "bc"]);
     print(obj[2]);
     obj.bar = 23;
+    obj[a + "bc"] = 23;
     obj[3] = 23;
     obj.func("hello");
 }
--- a/test/script/basic/JDK-8055762.js.EXPECTED	Wed Mar 11 14:11:06 2015 -0700
+++ b/test/script/basic/JDK-8055762.js.EXPECTED	Thu Mar 12 13:45:00 2015 -0700
@@ -1,5 +1,7 @@
 FOO
+ABC
 0
 bar set to 23
+abc set to 23
 [3] set to 23
 func called with hello
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8072426.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8072426: Can't compare Java objects to strings or numbers
+ *
+ * @test
+ * @run
+ */
+
+Assert.assertTrue(java.math.RoundingMode.UP == "UP");
+
+var JSObject = Java.type("jdk.nashorn.api.scripting.JSObject");
+
+// Adds an "isFunction" member to the JSObject that returns the specified value
+function addIsFunction(isFunction, obj) {
+    obj.isFunction = function() {
+        return isFunction;
+    };
+    return obj;
+}
+
+function makeJSObjectConstantFunction(value) {
+    return new JSObject(addIsFunction(true, {
+        call: function() {
+            return value;
+        }
+    }));
+}
+
+function makeJSObjectWithMembers(mapping) {
+    return new JSObject({
+        getMember: function(name) {
+            Assert.assertTrue(mapping.hasOwnProperty(name));
+            return mapping[name];
+        },
+        toNumber: function() {
+            // toNumber no longer invoked
+            Assert.fail();
+        }
+    });
+}
+
+// Test JSObjectLinker toInt32/toLong/toNumber
+function testNumericJSObject(kind, value) {
+    var obj = makeJSObjectWithMembers({
+            valueOf: makeJSObjectConstantFunction(value)
+        });
+
+    if (kind === "double") {
+        // There's no assertEquals(double actual, double expected). There's only
+        // assertEquals(double actual, double expected, double delta).
+        Assert["assertEquals(double,double,double)"](value, obj, 0);
+    } else {
+        Assert["assertEquals(" + kind + ", " + kind + ")"](value, obj);
+    }
+    Assert.assertTrue(value == Number(obj));
+}
+testNumericJSObject("int", 42);
+testNumericJSObject("long", 4294967296);
+testNumericJSObject("double", 1.2);
+
+// Test fallback from toNumber to toString for numeric conversion when toNumber doesn't exist
+(function() {
+    var obj = makeJSObjectWithMembers({
+        valueOf:  null, // Explicitly no valueOf
+        toString: makeJSObjectConstantFunction("123")
+    });
+    Assert["assertEquals(int,int)"](123, obj);
+})();
+
+// Test fallback from toNumber to toString for numeric conversion when toNumber isn't a callable
+(function() {
+    var obj = makeJSObjectWithMembers({
+        valueOf:  new JSObject(addIsFunction(false, {})),
+        toString: makeJSObjectConstantFunction("124")
+    });
+    Assert["assertEquals(int,int)"](124, obj);
+})();
+
+// Test fallback from toNumber to toString for numeric conversion when toNumber returns a non-primitive
+(function() {
+    var obj = makeJSObjectWithMembers({
+        valueOf:  makeJSObjectConstantFunction({}),
+        toString: makeJSObjectConstantFunction("125")
+    });
+    Assert["assertEquals(int,int)"](125, obj);
+})();
+
+// Test TypeError from toNumber to toString when both return a non-primitive
+(function() {
+    var obj = makeJSObjectWithMembers({
+        valueOf:  makeJSObjectConstantFunction({}),
+        toString: makeJSObjectConstantFunction({})
+    });
+    try {
+        Number(obj);
+        Assert.fail(); // must throw
+    } catch(e) {
+        Assert.assertTrue(e instanceof TypeError); 
+    }
+})();
+
+// Test toString for string conversion
+(function() {
+    var obj = makeJSObjectWithMembers({
+        toString: makeJSObjectConstantFunction("Hello")
+    });
+    Assert.assertTrue("Hello" === String(obj));
+    Assert["assertEquals(String,String)"]("Hello", obj);
+})();
+
+// Test fallback from toString to valueOf for string conversion when toString doesn't exist
+(function() {
+    var obj = makeJSObjectWithMembers({
+        toString: null,
+        valueOf:  makeJSObjectConstantFunction("Hello1")
+    });
+    Assert.assertTrue("Hello1" === String(obj));
+    Assert["assertEquals(String,String)"]("Hello1", obj);
+})();
+
+// Test fallback from toString to valueOf for string conversion when toString is not callable
+(function() {
+    var obj = makeJSObjectWithMembers({
+        toString: new JSObject(addIsFunction(false, {})),
+        valueOf:  makeJSObjectConstantFunction("Hello2")
+    });
+    Assert["assertEquals(String,String)"]("Hello2", obj);
+})();
+
+// Test fallback from toString to valueOf for string conversion when toString returns non-primitive
+(function() {
+    var obj = makeJSObjectWithMembers({
+        toString: makeJSObjectConstantFunction({}),
+        valueOf:  makeJSObjectConstantFunction("Hello3")
+    });
+    Assert["assertEquals(String,String)"]("Hello3", obj);
+})();
+
+// Test toBoolean for JSObject
+(function() {
+    Assert["assertEquals(boolean,boolean)"](true, new JSObject({}));
+})();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8074545.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,1038 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8074545: Undefined object values in object literals with spill properties
+ *
+ * @test
+ * @run
+ */
+
+var obj = {
+    "p0": { "x" : 0 },
+    "p1": { "x" : 1 },
+    "p2": { "x" : 2 },
+    "p3": { "x" : 3 },
+    "p4": { "x" : 4 },
+    "p5": { "x" : 5 },
+    "p6": { "x" : 6 },
+    "p7": { "x" : 7 },
+    "p8": { "x" : 8 },
+    "p9": { "x" : 9 },
+    "p10": { "x" : 10 },
+    "p11": { "x" : 11 },
+    "p12": { "x" : 12 },
+    "p13": { "x" : 13 },
+    "p14": { "x" : 14 },
+    "p15": { "x" : 15 },
+    "p16": { "x" : 16 },
+    "p17": { "x" : 17 },
+    "p18": { "x" : 18 },
+    "p19": { "x" : 19 },
+    "p20": { "x" : 20 },
+    "p21": { "x" : 21 },
+    "p22": { "x" : 22 },
+    "p23": { "x" : 23 },
+    "p24": { "x" : 24 },
+    "p25": { "x" : 25 },
+    "p26": { "x" : 26 },
+    "p27": { "x" : 27 },
+    "p28": { "x" : 28 },
+    "p29": { "x" : 29 },
+    "p30": { "x" : 30 },
+    "p31": { "x" : 31 },
+    "p32": { "x" : 32 },
+    "p33": { "x" : 33 },
+    "p34": { "x" : 34 },
+    "p35": { "x" : 35 },
+    "p36": { "x" : 36 },
+    "p37": { "x" : 37 },
+    "p38": { "x" : 38 },
+    "p39": { "x" : 39 },
+    "p40": { "x" : 40 },
+    "p41": { "x" : 41 },
+    "p42": { "x" : 42 },
+    "p43": { "x" : 43 },
+    "p44": { "x" : 44 },
+    "p45": { "x" : 45 },
+    "p46": { "x" : 46 },
+    "p47": { "x" : 47 },
+    "p48": { "x" : 48 },
+    "p49": { "x" : 49 },
+    "p50": { "x" : 50 },
+    "p51": { "x" : 51 },
+    "p52": { "x" : 52 },
+    "p53": { "x" : 53 },
+    "p54": { "x" : 54 },
+    "p55": { "x" : 55 },
+    "p56": { "x" : 56 },
+    "p57": { "x" : 57 },
+    "p58": { "x" : 58 },
+    "p59": { "x" : 59 },
+    "p60": { "x" : 60 },
+    "p61": { "x" : 61 },
+    "p62": { "x" : 62 },
+    "p63": { "x" : 63 },
+    "p64": { "x" : 64 },
+    "p65": { "x" : 65 },
+    "p66": { "x" : 66 },
+    "p67": { "x" : 67 },
+    "p68": { "x" : 68 },
+    "p69": { "x" : 69 },
+    "p70": { "x" : 70 },
+    "p71": { "x" : 71 },
+    "p72": { "x" : 72 },
+    "p73": { "x" : 73 },
+    "p74": { "x" : 74 },
+    "p75": { "x" : 75 },
+    "p76": { "x" : 76 },
+    "p77": { "x" : 77 },
+    "p78": { "x" : 78 },
+    "p79": { "x" : 79 },
+    "p80": { "x" : 80 },
+    "p81": { "x" : 81 },
+    "p82": { "x" : 82 },
+    "p83": { "x" : 83 },
+    "p84": { "x" : 84 },
+    "p85": { "x" : 85 },
+    "p86": { "x" : 86 },
+    "p87": { "x" : 87 },
+    "p88": { "x" : 88 },
+    "p89": { "x" : 89 },
+    "p90": { "x" : 90 },
+    "p91": { "x" : 91 },
+    "p92": { "x" : 92 },
+    "p93": { "x" : 93 },
+    "p94": { "x" : 94 },
+    "p95": { "x" : 95 },
+    "p96": { "x" : 96 },
+    "p97": { "x" : 97 },
+    "p98": { "x" : 98 },
+    "p99": { "x" : 99 },
+    "p100": { "x" : 100 },
+    "p101": { "x" : 101 },
+    "p102": { "x" : 102 },
+    "p103": { "x" : 103 },
+    "p104": { "x" : 104 },
+    "p105": { "x" : 105 },
+    "p106": { "x" : 106 },
+    "p107": { "x" : 107 },
+    "p108": { "x" : 108 },
+    "p109": { "x" : 109 },
+    "p110": { "x" : 110 },
+    "p111": { "x" : 111 },
+    "p112": { "x" : 112 },
+    "p113": { "x" : 113 },
+    "p114": { "x" : 114 },
+    "p115": { "x" : 115 },
+    "p116": { "x" : 116 },
+    "p117": { "x" : 117 },
+    "p118": { "x" : 118 },
+    "p119": { "x" : 119 },
+    "p120": { "x" : 120 },
+    "p121": { "x" : 121 },
+    "p122": { "x" : 122 },
+    "p123": { "x" : 123 },
+    "p124": { "x" : 124 },
+    "p125": { "x" : 125 },
+    "p126": { "x" : 126 },
+    "p127": { "x" : 127 },
+    "p128": { "x" : 128 },
+    "p129": { "x" : 129 },
+    "p130": { "x" : 130 },
+    "p131": { "x" : 131 },
+    "p132": { "x" : 132 },
+    "p133": { "x" : 133 },
+    "p134": { "x" : 134 },
+    "p135": { "x" : 135 },
+    "p136": { "x" : 136 },
+    "p137": { "x" : 137 },
+    "p138": { "x" : 138 },
+    "p139": { "x" : 139 },
+    "p140": { "x" : 140 },
+    "p141": { "x" : 141 },
+    "p142": { "x" : 142 },
+    "p143": { "x" : 143 },
+    "p144": { "x" : 144 },
+    "p145": { "x" : 145 },
+    "p146": { "x" : 146 },
+    "p147": { "x" : 147 },
+    "p148": { "x" : 148 },
+    "p149": { "x" : 149 },
+    "p150": { "x" : 150 },
+    "p151": { "x" : 151 },
+    "p152": { "x" : 152 },
+    "p153": { "x" : 153 },
+    "p154": { "x" : 154 },
+    "p155": { "x" : 155 },
+    "p156": { "x" : 156 },
+    "p157": { "x" : 157 },
+    "p158": { "x" : 158 },
+    "p159": { "x" : 159 },
+    "p160": { "x" : 160 },
+    "p161": { "x" : 161 },
+    "p162": { "x" : 162 },
+    "p163": { "x" : 163 },
+    "p164": { "x" : 164 },
+    "p165": { "x" : 165 },
+    "p166": { "x" : 166 },
+    "p167": { "x" : 167 },
+    "p168": { "x" : 168 },
+    "p169": { "x" : 169 },
+    "p170": { "x" : 170 },
+    "p171": { "x" : 171 },
+    "p172": { "x" : 172 },
+    "p173": { "x" : 173 },
+    "p174": { "x" : 174 },
+    "p175": { "x" : 175 },
+    "p176": { "x" : 176 },
+    "p177": { "x" : 177 },
+    "p178": { "x" : 178 },
+    "p179": { "x" : 179 },
+    "p180": { "x" : 180 },
+    "p181": { "x" : 181 },
+    "p182": { "x" : 182 },
+    "p183": { "x" : 183 },
+    "p184": { "x" : 184 },
+    "p185": { "x" : 185 },
+    "p186": { "x" : 186 },
+    "p187": { "x" : 187 },
+    "p188": { "x" : 188 },
+    "p189": { "x" : 189 },
+    "p190": { "x" : 190 },
+    "p191": { "x" : 191 },
+    "p192": { "x" : 192 },
+    "p193": { "x" : 193 },
+    "p194": { "x" : 194 },
+    "p195": { "x" : 195 },
+    "p196": { "x" : 196 },
+    "p197": { "x" : 197 },
+    "p198": { "x" : 198 },
+    "p199": { "x" : 199 },
+    "p200": { "x" : 200 },
+    "p201": { "x" : 201 },
+    "p202": { "x" : 202 },
+    "p203": { "x" : 203 },
+    "p204": { "x" : 204 },
+    "p205": { "x" : 205 },
+    "p206": { "x" : 206 },
+    "p207": { "x" : 207 },
+    "p208": { "x" : 208 },
+    "p209": { "x" : 209 },
+    "p210": { "x" : 210 },
+    "p211": { "x" : 211 },
+    "p212": { "x" : 212 },
+    "p213": { "x" : 213 },
+    "p214": { "x" : 214 },
+    "p215": { "x" : 215 },
+    "p216": { "x" : 216 },
+    "p217": { "x" : 217 },
+    "p218": { "x" : 218 },
+    "p219": { "x" : 219 },
+    "p220": { "x" : 220 },
+    "p221": { "x" : 221 },
+    "p222": { "x" : 222 },
+    "p223": { "x" : 223 },
+    "p224": { "x" : 224 },
+    "p225": { "x" : 225 },
+    "p226": { "x" : 226 },
+    "p227": { "x" : 227 },
+    "p228": { "x" : 228 },
+    "p229": { "x" : 229 },
+    "p230": { "x" : 230 },
+    "p231": { "x" : 231 },
+    "p232": { "x" : 232 },
+    "p233": { "x" : 233 },
+    "p234": { "x" : 234 },
+    "p235": { "x" : 235 },
+    "p236": { "x" : 236 },
+    "p237": { "x" : 237 },
+    "p238": { "x" : 238 },
+    "p239": { "x" : 239 },
+    "p240": { "x" : 240 },
+    "p241": { "x" : 241 },
+    "p242": { "x" : 242 },
+    "p243": { "x" : 243 },
+    "p244": { "x" : 244 },
+    "p245": { "x" : 245 },
+    "p246": { "x" : 246 },
+    "p247": { "x" : 247 },
+    "p248": { "x" : 248 },
+    "p249": { "x" : 249 },
+    "p250": { "x" : 250 },
+    "p251": { "x" : 251 },
+    "p252": { "x" : 252 },
+    "p253": { "x" : 253 },
+    "p254": { "x" : 254 },
+    "p255": { "x" : 255 },
+    "p256": { "x" : 256 },
+    "p257": { "x" : 257 },
+    "p258": { "x" : 258 },
+    "p259": { "x" : 259 },
+    "p260": { "x" : 260 },
+    "p261": { "x" : 261 },
+    "p262": { "x" : 262 },
+    "p263": { "x" : 263 },
+    "p264": { "x" : 264 },
+    "p265": { "x" : 265 },
+    "p266": { "x" : 266 },
+    "p267": { "x" : 267 },
+    "p268": { "x" : 268 },
+    "p269": { "x" : 269 },
+    "p270": { "x" : 270 },
+    "p271": { "x" : 271 },
+    "p272": { "x" : 272 },
+    "p273": { "x" : 273 },
+    "p274": { "x" : 274 },
+    "p275": { "x" : 275 },
+    "p276": { "x" : 276 },
+    "p277": { "x" : 277 },
+    "p278": { "x" : 278 },
+    "p279": { "x" : 279 },
+    "p280": { "x" : 280 },
+    "p281": { "x" : 281 },
+    "p282": { "x" : 282 },
+    "p283": { "x" : 283 },
+    "p284": { "x" : 284 },
+    "p285": { "x" : 285 },
+    "p286": { "x" : 286 },
+    "p287": { "x" : 287 },
+    "p288": { "x" : 288 },
+    "p289": { "x" : 289 },
+    "p290": { "x" : 290 },
+    "p291": { "x" : 291 },
+    "p292": { "x" : 292 },
+    "p293": { "x" : 293 },
+    "p294": { "x" : 294 },
+    "p295": { "x" : 295 },
+    "p296": { "x" : 296 },
+    "p297": { "x" : 297 },
+    "p298": { "x" : 298 },
+    "p299": { "x" : 299 },
+    "p300": { "x" : 300 },
+    "p301": { "x" : 301 },
+    "p302": { "x" : 302 },
+    "p303": { "x" : 303 },
+    "p304": { "x" : 304 },
+    "p305": { "x" : 305 },
+    "p306": { "x" : 306 },
+    "p307": { "x" : 307 },
+    "p308": { "x" : 308 },
+    "p309": { "x" : 309 },
+    "p310": { "x" : 310 },
+    "p311": { "x" : 311 },
+    "p312": { "x" : 312 },
+    "p313": { "x" : 313 },
+    "p314": { "x" : 314 },
+    "p315": { "x" : 315 },
+    "p316": { "x" : 316 },
+    "p317": { "x" : 317 },
+    "p318": { "x" : 318 },
+    "p319": { "x" : 319 },
+    "p320": { "x" : 320 },
+    "p321": { "x" : 321 },
+    "p322": { "x" : 322 },
+    "p323": { "x" : 323 },
+    "p324": { "x" : 324 },
+    "p325": { "x" : 325 },
+    "p326": { "x" : 326 },
+    "p327": { "x" : 327 },
+    "p328": { "x" : 328 },
+    "p329": { "x" : 329 },
+    "p330": { "x" : 330 },
+    "p331": { "x" : 331 },
+    "p332": { "x" : 332 },
+    "p333": { "x" : 333 },
+    "p334": { "x" : 334 },
+    "p335": { "x" : 335 },
+    "p336": { "x" : 336 },
+    "p337": { "x" : 337 },
+    "p338": { "x" : 338 },
+    "p339": { "x" : 339 },
+    "p340": { "x" : 340 },
+    "p341": { "x" : 341 },
+    "p342": { "x" : 342 },
+    "p343": { "x" : 343 },
+    "p344": { "x" : 344 },
+    "p345": { "x" : 345 },
+    "p346": { "x" : 346 },
+    "p347": { "x" : 347 },
+    "p348": { "x" : 348 },
+    "p349": { "x" : 349 },
+    "p350": { "x" : 350 },
+    "p351": { "x" : 351 },
+    "p352": { "x" : 352 },
+    "p353": { "x" : 353 },
+    "p354": { "x" : 354 },
+    "p355": { "x" : 355 },
+    "p356": { "x" : 356 },
+    "p357": { "x" : 357 },
+    "p358": { "x" : 358 },
+    "p359": { "x" : 359 },
+    "p360": { "x" : 360 },
+    "p361": { "x" : 361 },
+    "p362": { "x" : 362 },
+    "p363": { "x" : 363 },
+    "p364": { "x" : 364 },
+    "p365": { "x" : 365 },
+    "p366": { "x" : 366 },
+    "p367": { "x" : 367 },
+    "p368": { "x" : 368 },
+    "p369": { "x" : 369 },
+    "p370": { "x" : 370 },
+    "p371": { "x" : 371 },
+    "p372": { "x" : 372 },
+    "p373": { "x" : 373 },
+    "p374": { "x" : 374 },
+    "p375": { "x" : 375 },
+    "p376": { "x" : 376 },
+    "p377": { "x" : 377 },
+    "p378": { "x" : 378 },
+    "p379": { "x" : 379 },
+    "p380": { "x" : 380 },
+    "p381": { "x" : 381 },
+    "p382": { "x" : 382 },
+    "p383": { "x" : 383 },
+    "p384": { "x" : 384 },
+    "p385": { "x" : 385 },
+    "p386": { "x" : 386 },
+    "p387": { "x" : 387 },
+    "p388": { "x" : 388 },
+    "p389": { "x" : 389 },
+    "p390": { "x" : 390 },
+    "p391": { "x" : 391 },
+    "p392": { "x" : 392 },
+    "p393": { "x" : 393 },
+    "p394": { "x" : 394 },
+    "p395": { "x" : 395 },
+    "p396": { "x" : 396 },
+    "p397": { "x" : 397 },
+    "p398": { "x" : 398 },
+    "p399": { "x" : 399 },
+    "p400": { "x" : 400 },
+    "p401": { "x" : 401 },
+    "p402": { "x" : 402 },
+    "p403": { "x" : 403 },
+    "p404": { "x" : 404 },
+    "p405": { "x" : 405 },
+    "p406": { "x" : 406 },
+    "p407": { "x" : 407 },
+    "p408": { "x" : 408 },
+    "p409": { "x" : 409 },
+    "p410": { "x" : 410 },
+    "p411": { "x" : 411 },
+    "p412": { "x" : 412 },
+    "p413": { "x" : 413 },
+    "p414": { "x" : 414 },
+    "p415": { "x" : 415 },
+    "p416": { "x" : 416 },
+    "p417": { "x" : 417 },
+    "p418": { "x" : 418 },
+    "p419": { "x" : 419 },
+    "p420": { "x" : 420 },
+    "p421": { "x" : 421 },
+    "p422": { "x" : 422 },
+    "p423": { "x" : 423 },
+    "p424": { "x" : 424 },
+    "p425": { "x" : 425 },
+    "p426": { "x" : 426 },
+    "p427": { "x" : 427 },
+    "p428": { "x" : 428 },
+    "p429": { "x" : 429 },
+    "p430": { "x" : 430 },
+    "p431": { "x" : 431 },
+    "p432": { "x" : 432 },
+    "p433": { "x" : 433 },
+    "p434": { "x" : 434 },
+    "p435": { "x" : 435 },
+    "p436": { "x" : 436 },
+    "p437": { "x" : 437 },
+    "p438": { "x" : 438 },
+    "p439": { "x" : 439 },
+    "p440": { "x" : 440 },
+    "p441": { "x" : 441 },
+    "p442": { "x" : 442 },
+    "p443": { "x" : 443 },
+    "p444": { "x" : 444 },
+    "p445": { "x" : 445 },
+    "p446": { "x" : 446 },
+    "p447": { "x" : 447 },
+    "p448": { "x" : 448 },
+    "p449": { "x" : 449 },
+    "p450": { "x" : 450 },
+    "p451": { "x" : 451 },
+    "p452": { "x" : 452 },
+    "p453": { "x" : 453 },
+    "p454": { "x" : 454 },
+    "p455": { "x" : 455 },
+    "p456": { "x" : 456 },
+    "p457": { "x" : 457 },
+    "p458": { "x" : 458 },
+    "p459": { "x" : 459 },
+    "p460": { "x" : 460 },
+    "p461": { "x" : 461 },
+    "p462": { "x" : 462 },
+    "p463": { "x" : 463 },
+    "p464": { "x" : 464 },
+    "p465": { "x" : 465 },
+    "p466": { "x" : 466 },
+    "p467": { "x" : 467 },
+    "p468": { "x" : 468 },
+    "p469": { "x" : 469 },
+    "p470": { "x" : 470 },
+    "p471": { "x" : 471 },
+    "p472": { "x" : 472 },
+    "p473": { "x" : 473 },
+    "p474": { "x" : 474 },
+    "p475": { "x" : 475 },
+    "p476": { "x" : 476 },
+    "p477": { "x" : 477 },
+    "p478": { "x" : 478 },
+    "p479": { "x" : 479 },
+    "p480": { "x" : 480 },
+    "p481": { "x" : 481 },
+    "p482": { "x" : 482 },
+    "p483": { "x" : 483 },
+    "p484": { "x" : 484 },
+    "p485": { "x" : 485 },
+    "p486": { "x" : 486 },
+    "p487": { "x" : 487 },
+    "p488": { "x" : 488 },
+    "p489": { "x" : 489 },
+    "p490": { "x" : 490 },
+    "p491": { "x" : 491 },
+    "p492": { "x" : 492 },
+    "p493": { "x" : 493 },
+    "p494": { "x" : 494 },
+    "p495": { "x" : 495 },
+    "p496": { "x" : 496 },
+    "p497": { "x" : 497 },
+    "p498": { "x" : 498 },
+    "p499": { "x" : 499 },
+    "p500": { "x" : 500 },
+    "p501": { "x" : 501 },
+    "p502": { "x" : 502 },
+    "p503": { "x" : 503 },
+    "p504": { "x" : 504 },
+    "p505": { "x" : 505 },
+    "p506": { "x" : 506 },
+    "p507": { "x" : 507 },
+    "p508": { "x" : 508 },
+    "p509": { "x" : 509 },
+    "p510": { "x" : 510 },
+    "p511": { "x" : 511 },
+    "p512": { "x" : 512 },
+    "p513": { "x" : 513 },
+    "p514": { "x" : 514 },
+    "p515": { "x" : 515 },
+    "p516": { "x" : 516 },
+    "p517": { "x" : 517 },
+    "p518": { "x" : 518 },
+    "p519": { "x" : 519 },
+    "p520": { "x" : 520 },
+    "p521": { "x" : 521 },
+    "p522": { "x" : 522 },
+    "p523": { "x" : 523 },
+    "p524": { "x" : 524 },
+    "p525": { "x" : 525 },
+    "p526": { "x" : 526 },
+    "p527": { "x" : 527 },
+    "p528": { "x" : 528 },
+    "p529": { "x" : 529 },
+    "p530": { "x" : 530 },
+    "p531": { "x" : 531 },
+    "p532": { "x" : 532 },
+    "p533": { "x" : 533 },
+    "p534": { "x" : 534 },
+    "p535": { "x" : 535 },
+    "p536": { "x" : 536 },
+    "p537": { "x" : 537 },
+    "p538": { "x" : 538 },
+    "p539": { "x" : 539 },
+    "p540": { "x" : 540 },
+    "p541": { "x" : 541 },
+    "p542": { "x" : 542 },
+    "p543": { "x" : 543 },
+    "p544": { "x" : 544 },
+    "p545": { "x" : 545 },
+    "p546": { "x" : 546 },
+    "p547": { "x" : 547 },
+    "p548": { "x" : 548 },
+    "p549": { "x" : 549 },
+    "p550": { "x" : 550 },
+    "p551": { "x" : 551 },
+    "p552": { "x" : 552 },
+    "p553": { "x" : 553 },
+    "p554": { "x" : 554 },
+    "p555": { "x" : 555 },
+    "p556": { "x" : 556 },
+    "p557": { "x" : 557 },
+    "p558": { "x" : 558 },
+    "p559": { "x" : 559 },
+    "p560": { "x" : 560 },
+    "p561": { "x" : 561 },
+    "p562": { "x" : 562 },
+    "p563": { "x" : 563 },
+    "p564": { "x" : 564 },
+    "p565": { "x" : 565 },
+    "p566": { "x" : 566 },
+    "p567": { "x" : 567 },
+    "p568": { "x" : 568 },
+    "p569": { "x" : 569 },
+    "p570": { "x" : 570 },
+    "p571": { "x" : 571 },
+    "p572": { "x" : 572 },
+    "p573": { "x" : 573 },
+    "p574": { "x" : 574 },
+    "p575": { "x" : 575 },
+    "p576": { "x" : 576 },
+    "p577": { "x" : 577 },
+    "p578": { "x" : 578 },
+    "p579": { "x" : 579 },
+    "p580": { "x" : 580 },
+    "p581": { "x" : 581 },
+    "p582": { "x" : 582 },
+    "p583": { "x" : 583 },
+    "p584": { "x" : 584 },
+    "p585": { "x" : 585 },
+    "p586": { "x" : 586 },
+    "p587": { "x" : 587 },
+    "p588": { "x" : 588 },
+    "p589": { "x" : 589 },
+    "p590": { "x" : 590 },
+    "p591": { "x" : 591 },
+    "p592": { "x" : 592 },
+    "p593": { "x" : 593 },
+    "p594": { "x" : 594 },
+    "p595": { "x" : 595 },
+    "p596": { "x" : 596 },
+    "p597": { "x" : 597 },
+    "p598": { "x" : 598 },
+    "p599": { "x" : 599 },
+    "p600": { "x" : 600 },
+    "p601": { "x" : 601 },
+    "p602": { "x" : 602 },
+    "p603": { "x" : 603 },
+    "p604": { "x" : 604 },
+    "p605": { "x" : 605 },
+    "p606": { "x" : 606 },
+    "p607": { "x" : 607 },
+    "p608": { "x" : 608 },
+    "p609": { "x" : 609 },
+    "p610": { "x" : 610 },
+    "p611": { "x" : 611 },
+    "p612": { "x" : 612 },
+    "p613": { "x" : 613 },
+    "p614": { "x" : 614 },
+    "p615": { "x" : 615 },
+    "p616": { "x" : 616 },
+    "p617": { "x" : 617 },
+    "p618": { "x" : 618 },
+    "p619": { "x" : 619 },
+    "p620": { "x" : 620 },
+    "p621": { "x" : 621 },
+    "p622": { "x" : 622 },
+    "p623": { "x" : 623 },
+    "p624": { "x" : 624 },
+    "p625": { "x" : 625 },
+    "p626": { "x" : 626 },
+    "p627": { "x" : 627 },
+    "p628": { "x" : 628 },
+    "p629": { "x" : 629 },
+    "p630": { "x" : 630 },
+    "p631": { "x" : 631 },
+    "p632": { "x" : 632 },
+    "p633": { "x" : 633 },
+    "p634": { "x" : 634 },
+    "p635": { "x" : 635 },
+    "p636": { "x" : 636 },
+    "p637": { "x" : 637 },
+    "p638": { "x" : 638 },
+    "p639": { "x" : 639 },
+    "p640": { "x" : 640 },
+    "p641": { "x" : 641 },
+    "p642": { "x" : 642 },
+    "p643": { "x" : 643 },
+    "p644": { "x" : 644 },
+    "p645": { "x" : 645 },
+    "p646": { "x" : 646 },
+    "p647": { "x" : 647 },
+    "p648": { "x" : 648 },
+    "p649": { "x" : 649 },
+    "p650": { "x" : 650 },
+    "p651": { "x" : 651 },
+    "p652": { "x" : 652 },
+    "p653": { "x" : 653 },
+    "p654": { "x" : 654 },
+    "p655": { "x" : 655 },
+    "p656": { "x" : 656 },
+    "p657": { "x" : 657 },
+    "p658": { "x" : 658 },
+    "p659": { "x" : 659 },
+    "p660": { "x" : 660 },
+    "p661": { "x" : 661 },
+    "p662": { "x" : 662 },
+    "p663": { "x" : 663 },
+    "p664": { "x" : 664 },
+    "p665": { "x" : 665 },
+    "p666": { "x" : 666 },
+    "p667": { "x" : 667 },
+    "p668": { "x" : 668 },
+    "p669": { "x" : 669 },
+    "p670": { "x" : 670 },
+    "p671": { "x" : 671 },
+    "p672": { "x" : 672 },
+    "p673": { "x" : 673 },
+    "p674": { "x" : 674 },
+    "p675": { "x" : 675 },
+    "p676": { "x" : 676 },
+    "p677": { "x" : 677 },
+    "p678": { "x" : 678 },
+    "p679": { "x" : 679 },
+    "p680": { "x" : 680 },
+    "p681": { "x" : 681 },
+    "p682": { "x" : 682 },
+    "p683": { "x" : 683 },
+    "p684": { "x" : 684 },
+    "p685": { "x" : 685 },
+    "p686": { "x" : 686 },
+    "p687": { "x" : 687 },
+    "p688": { "x" : 688 },
+    "p689": { "x" : 689 },
+    "p690": { "x" : 690 },
+    "p691": { "x" : 691 },
+    "p692": { "x" : 692 },
+    "p693": { "x" : 693 },
+    "p694": { "x" : 694 },
+    "p695": { "x" : 695 },
+    "p696": { "x" : 696 },
+    "p697": { "x" : 697 },
+    "p698": { "x" : 698 },
+    "p699": { "x" : 699 },
+    "p700": { "x" : 700 },
+    "p701": { "x" : 701 },
+    "p702": { "x" : 702 },
+    "p703": { "x" : 703 },
+    "p704": { "x" : 704 },
+    "p705": { "x" : 705 },
+    "p706": { "x" : 706 },
+    "p707": { "x" : 707 },
+    "p708": { "x" : 708 },
+    "p709": { "x" : 709 },
+    "p710": { "x" : 710 },
+    "p711": { "x" : 711 },
+    "p712": { "x" : 712 },
+    "p713": { "x" : 713 },
+    "p714": { "x" : 714 },
+    "p715": { "x" : 715 },
+    "p716": { "x" : 716 },
+    "p717": { "x" : 717 },
+    "p718": { "x" : 718 },
+    "p719": { "x" : 719 },
+    "p720": { "x" : 720 },
+    "p721": { "x" : 721 },
+    "p722": { "x" : 722 },
+    "p723": { "x" : 723 },
+    "p724": { "x" : 724 },
+    "p725": { "x" : 725 },
+    "p726": { "x" : 726 },
+    "p727": { "x" : 727 },
+    "p728": { "x" : 728 },
+    "p729": { "x" : 729 },
+    "p730": { "x" : 730 },
+    "p731": { "x" : 731 },
+    "p732": { "x" : 732 },
+    "p733": { "x" : 733 },
+    "p734": { "x" : 734 },
+    "p735": { "x" : 735 },
+    "p736": { "x" : 736 },
+    "p737": { "x" : 737 },
+    "p738": { "x" : 738 },
+    "p739": { "x" : 739 },
+    "p740": { "x" : 740 },
+    "p741": { "x" : 741 },
+    "p742": { "x" : 742 },
+    "p743": { "x" : 743 },
+    "p744": { "x" : 744 },
+    "p745": { "x" : 745 },
+    "p746": { "x" : 746 },
+    "p747": { "x" : 747 },
+    "p748": { "x" : 748 },
+    "p749": { "x" : 749 },
+    "p750": { "x" : 750 },
+    "p751": { "x" : 751 },
+    "p752": { "x" : 752 },
+    "p753": { "x" : 753 },
+    "p754": { "x" : 754 },
+    "p755": { "x" : 755 },
+    "p756": { "x" : 756 },
+    "p757": { "x" : 757 },
+    "p758": { "x" : 758 },
+    "p759": { "x" : 759 },
+    "p760": { "x" : 760 },
+    "p761": { "x" : 761 },
+    "p762": { "x" : 762 },
+    "p763": { "x" : 763 },
+    "p764": { "x" : 764 },
+    "p765": { "x" : 765 },
+    "p766": { "x" : 766 },
+    "p767": { "x" : 767 },
+    "p768": { "x" : 768 },
+    "p769": { "x" : 769 },
+    "p770": { "x" : 770 },
+    "p771": { "x" : 771 },
+    "p772": { "x" : 772 },
+    "p773": { "x" : 773 },
+    "p774": { "x" : 774 },
+    "p775": { "x" : 775 },
+    "p776": { "x" : 776 },
+    "p777": { "x" : 777 },
+    "p778": { "x" : 778 },
+    "p779": { "x" : 779 },
+    "p780": { "x" : 780 },
+    "p781": { "x" : 781 },
+    "p782": { "x" : 782 },
+    "p783": { "x" : 783 },
+    "p784": { "x" : 784 },
+    "p785": { "x" : 785 },
+    "p786": { "x" : 786 },
+    "p787": { "x" : 787 },
+    "p788": { "x" : 788 },
+    "p789": { "x" : 789 },
+    "p790": { "x" : 790 },
+    "p791": { "x" : 791 },
+    "p792": { "x" : 792 },
+    "p793": { "x" : 793 },
+    "p794": { "x" : 794 },
+    "p795": { "x" : 795 },
+    "p796": { "x" : 796 },
+    "p797": { "x" : 797 },
+    "p798": { "x" : 798 },
+    "p799": { "x" : 799 },
+    "p800": { "x" : 800 },
+    "p801": { "x" : 801 },
+    "p802": { "x" : 802 },
+    "p803": { "x" : 803 },
+    "p804": { "x" : 804 },
+    "p805": { "x" : 805 },
+    "p806": { "x" : 806 },
+    "p807": { "x" : 807 },
+    "p808": { "x" : 808 },
+    "p809": { "x" : 809 },
+    "p810": { "x" : 810 },
+    "p811": { "x" : 811 },
+    "p812": { "x" : 812 },
+    "p813": { "x" : 813 },
+    "p814": { "x" : 814 },
+    "p815": { "x" : 815 },
+    "p816": { "x" : 816 },
+    "p817": { "x" : 817 },
+    "p818": { "x" : 818 },
+    "p819": { "x" : 819 },
+    "p820": { "x" : 820 },
+    "p821": { "x" : 821 },
+    "p822": { "x" : 822 },
+    "p823": { "x" : 823 },
+    "p824": { "x" : 824 },
+    "p825": { "x" : 825 },
+    "p826": { "x" : 826 },
+    "p827": { "x" : 827 },
+    "p828": { "x" : 828 },
+    "p829": { "x" : 829 },
+    "p830": { "x" : 830 },
+    "p831": { "x" : 831 },
+    "p832": { "x" : 832 },
+    "p833": { "x" : 833 },
+    "p834": { "x" : 834 },
+    "p835": { "x" : 835 },
+    "p836": { "x" : 836 },
+    "p837": { "x" : 837 },
+    "p838": { "x" : 838 },
+    "p839": { "x" : 839 },
+    "p840": { "x" : 840 },
+    "p841": { "x" : 841 },
+    "p842": { "x" : 842 },
+    "p843": { "x" : 843 },
+    "p844": { "x" : 844 },
+    "p845": { "x" : 845 },
+    "p846": { "x" : 846 },
+    "p847": { "x" : 847 },
+    "p848": { "x" : 848 },
+    "p849": { "x" : 849 },
+    "p850": { "x" : 850 },
+    "p851": { "x" : 851 },
+    "p852": { "x" : 852 },
+    "p853": { "x" : 853 },
+    "p854": { "x" : 854 },
+    "p855": { "x" : 855 },
+    "p856": { "x" : 856 },
+    "p857": { "x" : 857 },
+    "p858": { "x" : 858 },
+    "p859": { "x" : 859 },
+    "p860": { "x" : 860 },
+    "p861": { "x" : 861 },
+    "p862": { "x" : 862 },
+    "p863": { "x" : 863 },
+    "p864": { "x" : 864 },
+    "p865": { "x" : 865 },
+    "p866": { "x" : 866 },
+    "p867": { "x" : 867 },
+    "p868": { "x" : 868 },
+    "p869": { "x" : 869 },
+    "p870": { "x" : 870 },
+    "p871": { "x" : 871 },
+    "p872": { "x" : 872 },
+    "p873": { "x" : 873 },
+    "p874": { "x" : 874 },
+    "p875": { "x" : 875 },
+    "p876": { "x" : 876 },
+    "p877": { "x" : 877 },
+    "p878": { "x" : 878 },
+    "p879": { "x" : 879 },
+    "p880": { "x" : 880 },
+    "p881": { "x" : 881 },
+    "p882": { "x" : 882 },
+    "p883": { "x" : 883 },
+    "p884": { "x" : 884 },
+    "p885": { "x" : 885 },
+    "p886": { "x" : 886 },
+    "p887": { "x" : 887 },
+    "p888": { "x" : 888 },
+    "p889": { "x" : 889 },
+    "p890": { "x" : 890 },
+    "p891": { "x" : 891 },
+    "p892": { "x" : 892 },
+    "p893": { "x" : 893 },
+    "p894": { "x" : 894 },
+    "p895": { "x" : 895 },
+    "p896": { "x" : 896 },
+    "p897": { "x" : 897 },
+    "p898": { "x" : 898 },
+    "p899": { "x" : 899 },
+    "p900": { "x" : 900 },
+    "p901": { "x" : 901 },
+    "p902": { "x" : 902 },
+    "p903": { "x" : 903 },
+    "p904": { "x" : 904 },
+    "p905": { "x" : 905 },
+    "p906": { "x" : 906 },
+    "p907": { "x" : 907 },
+    "p908": { "x" : 908 },
+    "p909": { "x" : 909 },
+    "p910": { "x" : 910 },
+    "p911": { "x" : 911 },
+    "p912": { "x" : 912 },
+    "p913": { "x" : 913 },
+    "p914": { "x" : 914 },
+    "p915": { "x" : 915 },
+    "p916": { "x" : 916 },
+    "p917": { "x" : 917 },
+    "p918": { "x" : 918 },
+    "p919": { "x" : 919 },
+    "p920": { "x" : 920 },
+    "p921": { "x" : 921 },
+    "p922": { "x" : 922 },
+    "p923": { "x" : 923 },
+    "p924": { "x" : 924 },
+    "p925": { "x" : 925 },
+    "p926": { "x" : 926 },
+    "p927": { "x" : 927 },
+    "p928": { "x" : 928 },
+    "p929": { "x" : 929 },
+    "p930": { "x" : 930 },
+    "p931": { "x" : 931 },
+    "p932": { "x" : 932 },
+    "p933": { "x" : 933 },
+    "p934": { "x" : 934 },
+    "p935": { "x" : 935 },
+    "p936": { "x" : 936 },
+    "p937": { "x" : 937 },
+    "p938": { "x" : 938 },
+    "p939": { "x" : 939 },
+    "p940": { "x" : 940 },
+    "p941": { "x" : 941 },
+    "p942": { "x" : 942 },
+    "p943": { "x" : 943 },
+    "p944": { "x" : 944 },
+    "p945": { "x" : 945 },
+    "p946": { "x" : 946 },
+    "p947": { "x" : 947 },
+    "p948": { "x" : 948 },
+    "p949": { "x" : 949 },
+    "p950": { "x" : 950 },
+    "p951": { "x" : 951 },
+    "p952": { "x" : 952 },
+    "p953": { "x" : 953 },
+    "p954": { "x" : 954 },
+    "p955": { "x" : 955 },
+    "p956": { "x" : 956 },
+    "p957": { "x" : 957 },
+    "p958": { "x" : 958 },
+    "p959": { "x" : 959 },
+    "p960": { "x" : 960 },
+    "p961": { "x" : 961 },
+    "p962": { "x" : 962 },
+    "p963": { "x" : 963 },
+    "p964": { "x" : 964 },
+    "p965": { "x" : 965 },
+    "p966": { "x" : 966 },
+    "p967": { "x" : 967 },
+    "p968": { "x" : 968 },
+    "p969": { "x" : 969 },
+    "p970": { "x" : 970 },
+    "p971": { "x" : 971 },
+    "p972": { "x" : 972 },
+    "p973": { "x" : 973 },
+    "p974": { "x" : 974 },
+    "p975": { "x" : 975 },
+    "p976": { "x" : 976 },
+    "p977": { "x" : 977 },
+    "p978": { "x" : 978 },
+    "p979": { "x" : 979 },
+    "p980": { "x" : 980 },
+    "p981": { "x" : 981 },
+    "p982": { "x" : 982 },
+    "p983": { "x" : 983 },
+    "p984": { "x" : 984 },
+    "p985": { "x" : 985 },
+    "p986": { "x" : 986 },
+    "p987": { "x" : 987 },
+    "p988": { "x" : 988 },
+    "p989": { "x" : 989 },
+    "p990": { "x" : 990 },
+    "p991": { "x" : 991 },
+    "p992": { "x" : 992 },
+    "p993": { "x" : 993 },
+    "p994": { "x" : 994 },
+    "p995": { "x" : 995 },
+    "p996": { "x" : 996 },
+    "p997": { "x" : 997 },
+    "p998": { "x" : 998 },
+    "p999": { "x" : 999 }
+};
+
+for (var i = 0; i < 1000; i++) {
+    var value = obj["p" + i];
+    Assert.assertTrue(typeof value === "object");
+    Assert.assertTrue(value.x === i);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8074556.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8074556: Functions should not share allocator maps
+ *
+ * @test
+ * @run
+ */
+
+function A () {
+    return this;
+}
+
+function B() {
+    return this;
+}
+
+A.prototype.x = "x";
+A.prototype.y = "y";
+B.prototype.y = "y";  // same properties but different order
+B.prototype.x = "x";
+
+function test(o) {
+    Assert.assertEquals(o.x, "x");
+    Assert.assertEquals(o.y, "y");
+}
+
+test(new A());
+test(new B());
+test(new A());
+test(new B());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8074687.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8074687:  Add tests for JSON parsing of numeric keys
+ *
+ * @test
+ * @run
+ */
+
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": {} }')),                   '{"0":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": 1 }')),                    '{"0":1}');
+
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "65503": {} }')),               '{"65503":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "65503": 1 }')),                '{"65503":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": {}, "65503": {} }')),      '{"0":{},"65503":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": 1, "65503": 1 }')),        '{"0":1,"65503":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "65503": {}, "0": {} }')),      '{"0":{},"65503":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "65503": 1, "0": 1 }')),        '{"0":1,"65503":1}');
+
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "4294967295": {} }')),          '{"4294967295":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "4294967295": 1 }')),           '{"4294967295":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": {}, "4294967295": {} }')), '{"0":{},"4294967295":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": 1, "4294967295": 1 }')),   '{"0":1,"4294967295":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "4294967295": {}, "0": {} }')), '{"0":{},"4294967295":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "4294967295": 1, "0": 1 }')),   '{"0":1,"4294967295":1}');
+
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "100": {} }')),                 '{"100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "100": 1 }')),                  '{"100":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": {}, "100": {} }')),        '{"0":{},"100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": 1, "100": 1 }')),          '{"0":1,"100":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "100": {}, "0": {} }')),        '{"0":{},"100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "100": 1, "0": 1 }')),          '{"0":1,"100":1}');
+
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "-100": {} }')),                '{"-100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "-100": 1 }')),                 '{"-100":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": {}, "-100": {} }')),       '{"0":{},"-100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "0": 1, "-100": 1 }')),         '{"0":1,"-100":1}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "-100": {}, "0": {} }')),       '{"0":{},"-100":{}}');
+Assert.assertEquals(JSON.stringify(JSON.parse('{ "-100": 1, "0": 1 }')),         '{"0":1,"-100":1}');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8074693.js	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8074693: Different instances of same function use same allocator map
+ *
+ * @test
+ * @run
+ */
+
+var lib = {};
+
+lib.mixin = function(target, source) {
+    for (var p in source) {
+        if (source.hasOwnProperty(p) && !target.hasOwnProperty(p)) {
+            target.prototype[p] = source[p];
+        }
+    }
+};
+
+lib.declare = function(def) {
+    var className = def.name;
+
+    lib[className] = function() {
+        this.init.apply(this, arguments);
+    };
+
+    lib.mixin(lib[className], def.members);
+};
+
+
+lib.declare({
+    name: "ClassA",
+    members: {
+        init : function () {
+            print("init A called");
+        }
+    }
+});
+
+lib.declare({
+    name: "ClassB",
+    members: {
+        util : function () {
+            print("util called")
+        },
+        init : function() {
+            print("init B called");
+        }
+    }
+});
+
+var objA = new lib.ClassA();
+var objB = new lib.ClassB();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/script/basic/JDK-8074693.js.EXPECTED	Thu Mar 12 13:45:00 2015 -0700
@@ -0,0 +1,2 @@
+init A called
+init B called
--- a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java	Wed Mar 11 14:11:06 2015 -0700
+++ b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java	Thu Mar 12 13:45:00 2015 -0700
@@ -109,6 +109,35 @@
         }
     }
 
+    // @bug 8062030: Nashorn bug retrieving array property after key string concatenation
+    @Test
+    // ConsString attribute access on a JSObject
+    public void consStringTest() {
+        final ScriptEngineManager m = new ScriptEngineManager();
+        final ScriptEngine e = m.getEngineByName("nashorn");
+        try {
+            final MapWrapperObject obj = new MapWrapperObject();
+            e.put("obj", obj);
+            e.put("f", "f");
+            e.eval("obj[f + 'oo'] = 'bar';");
+
+            assertEquals(obj.getMap().get("foo"), "bar");
+            assertEquals(e.eval("obj[f + 'oo']"), "bar");
+            assertEquals(e.eval("obj['foo']"), "bar");
+            assertEquals(e.eval("f + 'oo' in obj"), Boolean.TRUE);
+            assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
+            e.eval("delete obj[f + 'oo']");
+            assertFalse(obj.getMap().containsKey("foo"));
+            assertEquals(e.eval("obj[f + 'oo']"), null);
+            assertEquals(e.eval("obj['foo']"), null);
+            assertEquals(e.eval("f + 'oo' in obj"), Boolean.FALSE);
+            assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
+        } catch (final Exception exp) {
+            exp.printStackTrace();
+            fail(exp.getMessage());
+        }
+    }
+
     public static class BufferObject extends AbstractJSObject {
         private final IntBuffer buf;