# HG changeset patch # User lana # Date 1426728115 25200 # Node ID e024db176497a3655f7c9d1d86571df74707ba62 # Parent da9741520576496d55099e232b5301214fe6fd82# Parent 4ba23f4c0ed666ac8175ec5841fcf62dea9262e9 Merge diff -r da9741520576 -r e024db176497 src/jdk/nashorn/api/scripting/AbstractJSObject.java --- a/src/jdk/nashorn/api/scripting/AbstractJSObject.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/api/scripting/AbstractJSObject.java Wed Mar 18 18:21:55 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 keySet() { - return Collections.EMPTY_SET; + return Collections.emptySet(); } /** @@ -172,9 +172,8 @@ * @return set of property values. */ @Override - @SuppressWarnings("unchecked") public Collection 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); } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/api/scripting/DefaultValueImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/jdk/nashorn/api/scripting/DefaultValueImpl.java Wed Mar 18 18:21:55 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"); + } +} diff -r da9741520576 -r e024db176497 src/jdk/nashorn/api/scripting/JSObject.java --- a/src/jdk/nashorn/api/scripting/JSObject.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/api/scripting/JSObject.java Wed Mar 18 18:21:55 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(); } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/api/scripting/ScriptObjectMirror.java --- a/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java Wed Mar 18 18:21:55 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() { @Override public Double call() { @@ -820,4 +821,21 @@ } }); } + + @Override + public Object getDefaultValue(final Class hint) { + return inGlobal(new Callable() { + @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); + } + } + }); + } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/BranchOptimizer.java --- a/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/BranchOptimizer.java Wed Mar 18 18:21:55 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; diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Mar 18 18:21:55 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(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; } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java --- a/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/CodeGeneratorLexicalContext.java Wed Mar 18 18:21:55 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 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 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 discard = new ArrayDeque<>(); + private final Deque>> unwarrantedOptimismHandlers = new ArrayDeque<>(); private final Deque 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) { diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/FindScopeDepths.java --- a/src/jdk/nashorn/internal/codegen/FindScopeDepths.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/FindScopeDepths.java Wed Mar 18 18:21:55 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), diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java --- a/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Wed Mar 18 18:21:55 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 afterTestLvarTypes = localVariableTypes; - if(!isAlwaysFalse(test)) { + final Map passLvarTypes; + final boolean reachableFromPass; + final boolean isTestAlwaysTrue = isAlwaysTrue(test); + if(isAlwaysFalse(test)) { + passLvarTypes = null; + reachableFromPass = false; + } else { + final Map afterTestLvarTypes = localVariableTypes; pass.accept(this); assertTypeStackIsEmpty(); + if (isTestAlwaysTrue) { + return; + } + passLvarTypes = localVariableTypes; + reachableFromPass = reachable; + localVariableTypes = afterTestLvarTypes; + reachable = true; } - final Map 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 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 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()) { diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/MapCreator.java --- a/src/jdk/nashorn/internal/codegen/MapCreator.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/MapCreator.java Wed Mar 18 18:21:55 2015 -0700 @@ -100,15 +100,16 @@ for (final MapTuple 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)); } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/MethodEmitter.java --- a/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Mar 18 18:21:55 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 diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java --- a/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Mar 18 18:21:55 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); } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/codegen/RuntimeCallSite.java --- a/src/jdk/nashorn/internal/codegen/RuntimeCallSite.java Wed Mar 18 13:57:04 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 METHODS; - - /** Generic method cache */ - private static final Map GENERIC_METHODS; - - /** Unbox cache */ - private static final Map, 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)); - } -} diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/ir/BinaryNode.java --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Wed Mar 18 18:21:55 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. */ diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/ir/RuntimeNode.java --- a/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/ir/RuntimeNode.java Wed Mar 18 18:21:55 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 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 args, final int programPoint) { + private RuntimeNode(final RuntimeNode runtimeNode, final Request request, final List 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; - } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/lookup/MethodHandleFactory.java --- a/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Wed Mar 18 18:21:55 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(" "); - } else if (d instanceof String || d instanceof ConsString) { + } else if (isString(d)) { sb.append(d.toString()); sb.append(' '); } else if (d.getClass().isArray()) { diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/Global.java --- a/src/jdk/nashorn/internal/objects/Global.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/Global.java Wed Mar 18 18:21:55 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); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/NativeArrayBuffer.java --- a/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java Wed Mar 18 18:21:55 2015 -0700 @@ -101,7 +101,7 @@ } if (args.length == 0) { - throw new RuntimeException("missing length argument"); + return new NativeArrayBuffer(0); } return new NativeArrayBuffer(JSType.toInt32(args[0])); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/NativeDate.java --- a/src/jdk/nashorn/internal/objects/NativeDate.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeDate.java Wed Mar 18 18:21:55 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])); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/NativeJSON.java --- a/src/jdk/nashorn/internal/objects/NativeJSON.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeJSON.java Wed Mar 18 18:21:55 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 { diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/NativeString.java --- a/src/jdk/nashorn/internal/objects/NativeString.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/NativeString.java Wed Mar 18 18:21:55 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(); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java --- a/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Wed Mar 18 18:21:55 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); } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/parser/JSONParser.java --- a/src/jdk/nashorn/internal/parser/JSONParser.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/parser/JSONParser.java Wed Mar 18 18:21:55 2015 -0700 @@ -244,20 +244,15 @@ private static PropertyMap addObjectProperty(final PropertyMap propertyMap, final List 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; diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/AllocationStrategy.java --- a/src/jdk/nashorn/internal/runtime/AllocationStrategy.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/AllocationStrategy.java Wed Mar 18 18:21:55 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 + "]"; } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/ConsString.java --- a/src/jdk/nashorn/internal/runtime/ConsString.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/ConsString.java Wed Mar 18 18:21:55 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(); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/JSType.java --- a/src/jdk/nashorn/internal/runtime/JSType.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/JSType.java Wed Mar 18 18:21:55 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) { diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Mar 18 18:21:55 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 installer, - final AllocatorDescriptor allocationDescriptor, + final AllocationStrategy allocationStrategy, final Map nestedFunctions, final Map externalScopeDepths, final Set 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)); diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/ScriptFunction.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Mar 18 18:21:55 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 diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/ScriptFunctionData.java --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Mar 18 18:21:55 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; } /** diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/ScriptRuntime.java --- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java Wed Mar 18 18:21:55 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 }); } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/ScriptingFunctions.java --- a/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/ScriptingFunctions.java Wed Mar 18 18:21:55 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()); } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/SpillProperty.java --- a/src/jdk/nashorn/internal/runtime/SpillProperty.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java Wed Mar 18 18:21:55 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); } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Mar 18 18:21:55 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 diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Wed Mar 18 18:21:55 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); } } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Wed Mar 18 18:21:55 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, 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)); } diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java --- a/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaArgumentConverters.java Wed Mar 18 18:21:55 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; diff -r da9741520576 -r e024db176497 src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java --- a/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java Wed Mar 18 13:57:04 2015 -0700 +++ b/src/jdk/nashorn/internal/runtime/linker/NashornPrimitiveLinker.java Wed Mar 18 18:21:55 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); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8023026.js.EXPECTED --- a/test/script/basic/JDK-8023026.js.EXPECTED Wed Mar 18 13:57:04 2015 -0700 +++ b/test/script/basic/JDK-8023026.js.EXPECTED Wed Mar 18 18:21:55 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 diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8024847.js --- a/test/script/basic/JDK-8024847.js Wed Mar 18 13:57:04 2015 -0700 +++ b/test/script/basic/JDK-8024847.js Wed Mar 18 18:21:55 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); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8035712.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8035712.js Wed Mar 18 18:21:55 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]); + } +})(); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8055762.js --- a/test/script/basic/JDK-8055762.js Wed Mar 18 13:57:04 2015 -0700 +++ b/test/script/basic/JDK-8055762.js Wed Mar 18 18:21:55 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"); } diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8055762.js.EXPECTED --- a/test/script/basic/JDK-8055762.js.EXPECTED Wed Mar 18 13:57:04 2015 -0700 +++ b/test/script/basic/JDK-8055762.js.EXPECTED Wed Mar 18 18:21:55 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 diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8072426.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8072426.js Wed Mar 18 18:21:55 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({})); +})(); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8074545.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8074545.js Wed Mar 18 18:21:55 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); +} diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8074556.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8074556.js Wed Mar 18 18:21:55 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()); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8074687.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8074687.js Wed Mar 18 18:21:55 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}'); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8074693.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8074693.js Wed Mar 18 18:21:55 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(); diff -r da9741520576 -r e024db176497 test/script/basic/JDK-8074693.js.EXPECTED --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/basic/JDK-8074693.js.EXPECTED Wed Mar 18 18:21:55 2015 -0700 @@ -0,0 +1,2 @@ +init A called +init B called diff -r da9741520576 -r e024db176497 test/script/basic/typedarrays.js --- a/test/script/basic/typedarrays.js Wed Mar 18 13:57:04 2015 -0700 +++ b/test/script/basic/typedarrays.js Wed Mar 18 18:21:55 2015 -0700 @@ -28,6 +28,17 @@ * @run */ +//JDK-8066217, constructor for arraybuffer not behaving as per spec +function checkLength(ab, l) { + if (ab.byteLength != l) { + throw "length error: " + ab.byteLength + " != " + l; + } +} +checkLength(new ArrayBuffer(), 0); +checkLength(new ArrayBuffer(0), 0); +checkLength(new ArrayBuffer(1024), 1024); +checkLength(new ArrayBuffer(1,2,3), 1); +checkLength(new ArrayBuffer([17]), 17); var typeDefinitions = [ Int8Array, diff -r da9741520576 -r e024db176497 test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java --- a/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Wed Mar 18 13:57:04 2015 -0700 +++ b/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Wed Mar 18 18:21:55 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;