Tue, 29 Oct 2013 10:40:00 -0300
Merge
1.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Oct 28 12:29:40 2013 -0700 1.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java Tue Oct 29 10:40:00 2013 -0300 1.3 @@ -359,8 +359,11 @@ 1.4 return load(node, node.hasType() ? node.getType() : null, false); 1.5 } 1.6 1.7 - private static boolean safeLiteral(final Expression rhs) { 1.8 - return rhs instanceof LiteralNode && !(rhs instanceof ArrayLiteralNode); 1.9 + // Test whether conversion from source to target involves a call of ES 9.1 ToPrimitive 1.10 + // with possible side effects from calling an object's toString or valueOf methods. 1.11 + private boolean noToPrimitiveConversion(final Type source, final Type target) { 1.12 + // Object to boolean conversion does not cause ToPrimitive call 1.13 + return source.isJSPrimitive() || !target.isJSPrimitive() || target.isBoolean(); 1.14 } 1.15 1.16 MethodEmitter loadBinaryOperands(final Expression lhs, final Expression rhs, final Type type) { 1.17 @@ -374,25 +377,19 @@ 1.18 // can combine a LOAD with a CONVERT operation (e.g. use a dynamic getter with the conversion target type as its 1.19 // return value). What we do here is reorder LOAD RIGHT and CONVERT LEFT when possible; it is possible only when 1.20 // we can prove that executing CONVERT LEFT can't have a side effect that changes the value of LOAD RIGHT. 1.21 - // Basically, if we know that either LEFT is not an object, or RIGHT is a constant literal, then we can do the 1.22 + // Basically, if we know that either LEFT already is a primitive value, or does not have to be converted to 1.23 + // a primitive value, or RIGHT is an expression that loads without side effects, then we can do the 1.24 // reordering and collapse LOAD/CONVERT into a single operation; otherwise we need to do the more costly 1.25 // separate operations to preserve specification semantics. 1.26 - final Type lhsType = lhs.getType(); 1.27 - if (lhsType.isObject() && !safeLiteral(rhs)) { 1.28 - // Can't reorder. Load and convert separately. 1.29 - load(lhs, lhsType, baseAlreadyOnStack); 1.30 - load(rhs, rhs.getType(), false); 1.31 - // Avoid empty SWAP, SWAP bytecode sequence if CONVERT LEFT is a no-op 1.32 - if (!lhsType.isEquivalentTo(type)) { 1.33 - method.swap(); 1.34 - method.convert(type); 1.35 - method.swap(); 1.36 - } 1.37 - method.convert(type); 1.38 - } else { 1.39 + if (noToPrimitiveConversion(lhs.getType(), type) || rhs.isLocal()) { 1.40 // Can reorder. Combine load and convert into single operations. 1.41 load(lhs, type, baseAlreadyOnStack); 1.42 load(rhs, type, false); 1.43 + } else { 1.44 + // Can't reorder. Load and convert separately. 1.45 + load(lhs, lhs.getType(), baseAlreadyOnStack); 1.46 + load(rhs, rhs.getType(), false); 1.47 + method.swap().convert(type).swap().convert(type); 1.48 } 1.49 1.50 return method;
2.1 --- a/src/jdk/nashorn/internal/codegen/types/Type.java Mon Oct 28 12:29:40 2013 -0700 2.2 +++ b/src/jdk/nashorn/internal/codegen/types/Type.java Tue Oct 29 10:40:00 2013 -0300 2.3 @@ -292,6 +292,16 @@ 2.4 } 2.5 2.6 /** 2.7 + * Determines whether this type represents an primitive type according to the ECMAScript specification, 2.8 + * which includes Boolean, Number, and String. 2.9 + * 2.10 + * @return true if a JavaScript primitive type, false otherwise. 2.11 + */ 2.12 + public boolean isJSPrimitive() { 2.13 + return !isObject() || isString(); 2.14 + } 2.15 + 2.16 + /** 2.17 * Determines whether a type is the BOOLEAN type 2.18 * @return true if BOOLEAN, false otherwise 2.19 */ 2.20 @@ -443,7 +453,7 @@ 2.21 } else if (type0.isArray() != type1.isArray()) { 2.22 //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 2.23 return Type.OBJECT; 2.24 - } else if (type0.isObject() && type1.isObject() && ((ObjectType)type0).getTypeClass() != ((ObjectType)type1).getTypeClass()) { 2.25 + } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { 2.26 // Object<type=String> and Object<type=ScriptFunction> will produce Object 2.27 // TODO: maybe find most specific common superclass? 2.28 return Type.OBJECT;
3.1 --- a/src/jdk/nashorn/internal/ir/BinaryNode.java Mon Oct 28 12:29:40 2013 -0700 3.2 +++ b/src/jdk/nashorn/internal/ir/BinaryNode.java Tue Oct 29 10:40:00 2013 -0300 3.3 @@ -90,6 +90,9 @@ 3.4 return Type.LONG; 3.5 case ASSIGN_SAR: 3.6 case ASSIGN_SHL: 3.7 + case BIT_AND: 3.8 + case BIT_OR: 3.9 + case BIT_XOR: 3.10 case ASSIGN_BIT_AND: 3.11 case ASSIGN_BIT_OR: 3.12 case ASSIGN_BIT_XOR: 3.13 @@ -170,6 +173,42 @@ 3.14 } 3.15 3.16 @Override 3.17 + public boolean isLocal() { 3.18 + switch (tokenType()) { 3.19 + case SAR: 3.20 + case SHL: 3.21 + case SHR: 3.22 + case BIT_AND: 3.23 + case BIT_OR: 3.24 + case BIT_XOR: 3.25 + case ADD: 3.26 + case DIV: 3.27 + case MOD: 3.28 + case MUL: 3.29 + case SUB: 3.30 + return lhs.isLocal() && lhs.getType().isJSPrimitive() 3.31 + && rhs.isLocal() && rhs.getType().isJSPrimitive(); 3.32 + case ASSIGN_ADD: 3.33 + case ASSIGN_BIT_AND: 3.34 + case ASSIGN_BIT_OR: 3.35 + case ASSIGN_BIT_XOR: 3.36 + case ASSIGN_DIV: 3.37 + case ASSIGN_MOD: 3.38 + case ASSIGN_MUL: 3.39 + case ASSIGN_SAR: 3.40 + case ASSIGN_SHL: 3.41 + case ASSIGN_SHR: 3.42 + case ASSIGN_SUB: 3.43 + return lhs instanceof IdentNode && lhs.isLocal() && lhs.getType().isJSPrimitive() 3.44 + && rhs.isLocal() && rhs.getType().isJSPrimitive(); 3.45 + case ASSIGN: 3.46 + return lhs instanceof IdentNode && lhs.isLocal() && rhs.isLocal(); 3.47 + default: 3.48 + return false; 3.49 + } 3.50 + } 3.51 + 3.52 + @Override 3.53 public void toString(final StringBuilder sb) { 3.54 final TokenType type = tokenType(); 3.55
4.1 --- a/src/jdk/nashorn/internal/ir/Expression.java Mon Oct 28 12:29:40 2013 -0700 4.2 +++ b/src/jdk/nashorn/internal/ir/Expression.java Tue Oct 29 10:40:00 2013 -0300 4.3 @@ -96,4 +96,16 @@ 4.4 assert hasType() : this + " has no type"; 4.5 return symbol.getSymbolType(); 4.6 } 4.7 + 4.8 + /** 4.9 + * Returns {@code true} if this expression depends exclusively on state that is constant 4.10 + * or local to the currently running function and thus inaccessible to other functions. 4.11 + * This implies that a local expression must not call any other functions (neither directly 4.12 + * nor implicitly through a getter, setter, or object-to-primitive type conversion). 4.13 + * 4.14 + * @return true if this expression does not depend on state shared with other functions. 4.15 + */ 4.16 + public boolean isLocal() { 4.17 + return false; 4.18 + } 4.19 }
5.1 --- a/src/jdk/nashorn/internal/ir/IdentNode.java Mon Oct 28 12:29:40 2013 -0700 5.2 +++ b/src/jdk/nashorn/internal/ir/IdentNode.java Tue Oct 29 10:40:00 2013 -0300 5.3 @@ -138,6 +138,11 @@ 5.4 return getName(); 5.5 } 5.6 5.7 + @Override 5.8 + public boolean isLocal() { 5.9 + return !getSymbol().isScope(); 5.10 + } 5.11 + 5.12 /** 5.13 * Check if this IdentNode is a property name 5.14 * @return true if this is a property name
6.1 --- a/src/jdk/nashorn/internal/ir/LiteralNode.java Mon Oct 28 12:29:40 2013 -0700 6.2 +++ b/src/jdk/nashorn/internal/ir/LiteralNode.java Tue Oct 29 10:40:00 2013 -0300 6.3 @@ -275,6 +275,11 @@ 6.4 public boolean isTrue() { 6.5 return JSType.toBoolean(value); 6.6 } 6.7 + 6.8 + @Override 6.9 + public boolean isLocal() { 6.10 + return true; 6.11 + } 6.12 } 6.13 6.14 @Immutable
7.1 --- a/src/jdk/nashorn/internal/ir/TernaryNode.java Mon Oct 28 12:29:40 2013 -0700 7.2 +++ b/src/jdk/nashorn/internal/ir/TernaryNode.java Tue Oct 29 10:40:00 2013 -0300 7.3 @@ -109,6 +109,13 @@ 7.4 } 7.5 } 7.6 7.7 + @Override 7.8 + public boolean isLocal() { 7.9 + return getTest().isLocal() 7.10 + && getTrueExpression().isLocal() 7.11 + && getFalseExpression().isLocal(); 7.12 + } 7.13 + 7.14 /** 7.15 * Get the test expression for this ternary expression, i.e. "x" in x ? y : z 7.16 * @return the test expression
8.1 --- a/src/jdk/nashorn/internal/ir/UnaryNode.java Mon Oct 28 12:29:40 2013 -0700 8.2 +++ b/src/jdk/nashorn/internal/ir/UnaryNode.java Tue Oct 29 10:40:00 2013 -0300 8.3 @@ -129,6 +129,26 @@ 8.4 } 8.5 8.6 @Override 8.7 + public boolean isLocal() { 8.8 + switch (tokenType()) { 8.9 + case NEW: 8.10 + return false; 8.11 + case ADD: 8.12 + case SUB: 8.13 + case NOT: 8.14 + case BIT_NOT: 8.15 + return rhs.isLocal() && rhs.getType().isJSPrimitive(); 8.16 + case DECPOSTFIX: 8.17 + case DECPREFIX: 8.18 + case INCPOSTFIX: 8.19 + case INCPREFIX: 8.20 + return rhs instanceof IdentNode && rhs.isLocal() && rhs.getType().isJSPrimitive(); 8.21 + default: 8.22 + return rhs.isLocal(); 8.23 + } 8.24 + } 8.25 + 8.26 + @Override 8.27 public void toString(final StringBuilder sb) { 8.28 toString(sb, new Runnable() { 8.29 @Override
9.1 --- a/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Mon Oct 28 12:29:40 2013 -0700 9.2 +++ b/src/jdk/nashorn/internal/runtime/CompiledFunctions.java Tue Oct 29 10:40:00 2013 -0300 9.3 @@ -24,6 +24,7 @@ 9.4 */ 9.5 package jdk.nashorn.internal.runtime; 9.6 9.7 +import java.lang.invoke.MethodHandle; 9.8 import java.lang.invoke.MethodType; 9.9 import java.util.Iterator; 9.10 import java.util.TreeSet; 9.11 @@ -35,6 +36,8 @@ 9.12 @SuppressWarnings("serial") 9.13 final class CompiledFunctions extends TreeSet<CompiledFunction> { 9.14 9.15 + private CompiledFunction generic; 9.16 + 9.17 CompiledFunction best(final MethodType type) { 9.18 final Iterator<CompiledFunction> iter = iterator(); 9.19 while (iter.hasNext()) { 9.20 @@ -43,13 +46,10 @@ 9.21 return next; 9.22 } 9.23 } 9.24 - return mostGeneric(); 9.25 + return generic(); 9.26 } 9.27 9.28 boolean needsCallee() { 9.29 - for (final CompiledFunction inv : this) { 9.30 - assert ScriptFunctionData.needsCallee(inv.getInvoker()) == ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); 9.31 - } 9.32 return ScriptFunctionData.needsCallee(mostGeneric().getInvoker()); 9.33 } 9.34 9.35 @@ -57,6 +57,48 @@ 9.36 return last(); 9.37 } 9.38 9.39 + CompiledFunction generic() { 9.40 + CompiledFunction gen = this.generic; 9.41 + if (gen == null) { 9.42 + gen = this.generic = makeGeneric(mostGeneric()); 9.43 + } 9.44 + return gen; 9.45 + } 9.46 + 9.47 + private static CompiledFunction makeGeneric(final CompiledFunction func) { 9.48 + final MethodHandle invoker = composeGenericMethod(func.getInvoker()); 9.49 + final MethodHandle constructor = func.hasConstructor() ? composeGenericMethod(func.getConstructor()) : null; 9.50 + return new CompiledFunction(invoker.type(), invoker, constructor); 9.51 + } 9.52 + 9.53 + /** 9.54 + * Takes a method handle, and returns a potentially different method handle that can be used in 9.55 + * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. 9.56 + * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into 9.57 + * {@code Object} as well, except for the following ones: 9.58 + * <ul> 9.59 + * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li> 9.60 + * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself 9.61 + * (callee) as an argument.</li> 9.62 + * </ul> 9.63 + * 9.64 + * @param mh the original method handle 9.65 + * 9.66 + * @return the new handle, conforming to the rules above. 9.67 + */ 9.68 + private static MethodHandle composeGenericMethod(final MethodHandle mh) { 9.69 + final MethodType type = mh.type(); 9.70 + final boolean isVarArg = ScriptFunctionData.isVarArg(mh); 9.71 + final int paramCount = isVarArg ? type.parameterCount() - 1 : type.parameterCount(); 9.72 + 9.73 + MethodType newType = MethodType.genericMethodType(paramCount, isVarArg); 9.74 + 9.75 + if (ScriptFunctionData.needsCallee(mh)) { 9.76 + newType = newType.changeParameterType(0, ScriptFunction.class); 9.77 + } 9.78 + return type.equals(newType) ? mh : mh.asType(newType); 9.79 + } 9.80 + 9.81 /** 9.82 * Is the given type even more specific than this entire list? That means 9.83 * we have an opportunity for more specific versions of the method
10.1 --- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Mon Oct 28 12:29:40 2013 -0700 10.2 +++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Tue Oct 29 10:40:00 2013 -0300 10.3 @@ -40,7 +40,7 @@ 10.4 * 10.5 * @param name name 10.6 * @param arity arity 10.7 - * @param list precompiled code 10.8 + * @param functions precompiled code 10.9 * @param isStrict strict 10.10 * @param isBuiltin builtin 10.11 * @param isConstructor constructor 10.12 @@ -73,12 +73,13 @@ 10.13 } 10.14 10.15 private void addInvoker(final MethodHandle mh) { 10.16 - boolean needsCallee = needsCallee(mh); 10.17 if (isConstructor(mh)) { 10.18 - //only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor 10.19 - //is too conservative a check. However, isConstructor(mh) always implies isConstructor param 10.20 + // only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor 10.21 + // is too conservative a check. However, isConstructor(mh) always implies isConstructor param 10.22 assert isConstructor(); 10.23 - code.add(new CompiledFunction(mh.type(), MH.insertArguments(mh, 0, false), composeConstructor(MH.insertArguments(mh, 0, true), needsCallee))); //make sure callee state can be determined when we reach constructor 10.24 + final MethodHandle invoker = MH.insertArguments(mh, 0, false); 10.25 + final MethodHandle constructor = composeConstructor(MH.insertArguments(mh, 0, true)); 10.26 + code.add(new CompiledFunction(mh.type(), invoker, constructor)); 10.27 } else { 10.28 code.add(new CompiledFunction(mh.type(), mh)); 10.29 }
11.1 --- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Mon Oct 28 12:29:40 2013 -0700 11.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Oct 29 10:40:00 2013 -0300 11.3 @@ -213,13 +213,13 @@ 11.4 */ 11.5 public final MethodHandle getGenericInvoker() { 11.6 ensureCodeGenerated(); 11.7 - return composeGenericMethod(code.mostGeneric().getInvoker()); 11.8 + return code.generic().getInvoker(); 11.9 } 11.10 11.11 final MethodHandle getGenericConstructor() { 11.12 ensureCodeGenerated(); 11.13 - ensureConstructor(code.mostGeneric()); 11.14 - return composeGenericMethod(code.mostGeneric().getConstructor()); 11.15 + ensureConstructor(code.generic()); 11.16 + return code.generic().getConstructor(); 11.17 } 11.18 11.19 private CompiledFunction getBest(final MethodType callSiteType) { 11.20 @@ -267,18 +267,17 @@ 11.21 } 11.22 11.23 /** 11.24 - * Compose a constructor given a primordial constructor handle 11.25 + * Compose a constructor given a primordial constructor handle. 11.26 * 11.27 - * @param ctor primordial constructor handle 11.28 - * @param needsCallee do we need to pass a callee 11.29 - * 11.30 + * @param ctor primordial constructor handle 11.31 * @return the composed constructor 11.32 */ 11.33 - protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) { 11.34 + protected MethodHandle composeConstructor(final MethodHandle ctor) { 11.35 // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having 11.36 // "this" in the first argument position is what allows the elegant folded composition of 11.37 // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor 11.38 // always returns Object. 11.39 + final boolean needsCallee = needsCallee(ctor); 11.40 MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; 11.41 11.42 composedCtor = changeReturnTypeToObject(composedCtor); 11.43 @@ -472,33 +471,6 @@ 11.44 } 11.45 11.46 /** 11.47 - * Takes a method handle, and returns a potentially different method handle that can be used in 11.48 - * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}. 11.49 - * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into 11.50 - * {@code Object} as well, except for the following ones: 11.51 - * <ul> 11.52 - * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li> 11.53 - * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself 11.54 - * (callee) as an argument.</li> 11.55 - * </ul> 11.56 - * 11.57 - * @param mh the original method handle 11.58 - * 11.59 - * @return the new handle, conforming to the rules above. 11.60 - */ 11.61 - protected MethodHandle composeGenericMethod(final MethodHandle mh) { 11.62 - final MethodType type = mh.type(); 11.63 - MethodType newType = type.generic(); 11.64 - if (isVarArg(mh)) { 11.65 - newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class); 11.66 - } 11.67 - if (needsCallee(mh)) { 11.68 - newType = newType.changeParameterType(0, ScriptFunction.class); 11.69 - } 11.70 - return type.equals(newType) ? mh : mh.asType(newType); 11.71 - } 11.72 - 11.73 - /** 11.74 * Execute this script function. 11.75 * 11.76 * @param self Target object. 11.77 @@ -508,10 +480,9 @@ 11.78 * @throws Throwable if there is an exception/error with the invocation or thrown from it 11.79 */ 11.80 Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable { 11.81 - final MethodHandle mh = getGenericInvoker(); 11.82 - 11.83 - final Object selfObj = convertThisObject(self); 11.84 - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 11.85 + final MethodHandle mh = getGenericInvoker(); 11.86 + final Object selfObj = convertThisObject(self); 11.87 + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 11.88 11.89 if (isVarArg(mh)) { 11.90 if (needsCallee(mh)) { 11.91 @@ -531,6 +502,12 @@ 11.92 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1)); 11.93 case 5: 11.94 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 11.95 + case 6: 11.96 + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); 11.97 + case 7: 11.98 + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); 11.99 + case 8: 11.100 + return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); 11.101 default: 11.102 return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args)); 11.103 } 11.104 @@ -545,15 +522,20 @@ 11.105 return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1)); 11.106 case 4: 11.107 return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 11.108 + case 5: 11.109 + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); 11.110 + case 6: 11.111 + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); 11.112 + case 7: 11.113 + return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); 11.114 default: 11.115 return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args)); 11.116 } 11.117 } 11.118 11.119 Object construct(final ScriptFunction fn, final Object... arguments) throws Throwable { 11.120 - final MethodHandle mh = getGenericConstructor(); 11.121 - 11.122 - final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 11.123 + final MethodHandle mh = getGenericConstructor(); 11.124 + final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments; 11.125 11.126 if (isVarArg(mh)) { 11.127 if (needsCallee(mh)) { 11.128 @@ -573,6 +555,12 @@ 11.129 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1)); 11.130 case 4: 11.131 return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2)); 11.132 + case 5: 11.133 + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); 11.134 + case 6: 11.135 + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); 11.136 + case 7: 11.137 + return mh.invokeExact(fn, getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); 11.138 default: 11.139 return mh.invokeWithArguments(withArguments(fn, paramCount, args)); 11.140 } 11.141 @@ -587,6 +575,12 @@ 11.142 return mh.invokeExact(getArg(args, 0), getArg(args, 1)); 11.143 case 3: 11.144 return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2)); 11.145 + case 4: 11.146 + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3)); 11.147 + case 5: 11.148 + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4)); 11.149 + case 6: 11.150 + return mh.invokeExact(getArg(args, 0), getArg(args, 1), getArg(args, 2), getArg(args, 3), getArg(args, 4), getArg(args, 5)); 11.151 default: 11.152 return mh.invokeWithArguments(withArguments(null, paramCount, args)); 11.153 } 11.154 @@ -664,20 +658,21 @@ 11.155 * @return the adapted handle 11.156 */ 11.157 private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) { 11.158 - return MH.asType(mh, mh.type().changeReturnType(Object.class)); 11.159 + final MethodType type = mh.type(); 11.160 + return (type.returnType() == Object.class) ? mh : MH.asType(mh, type.changeReturnType(Object.class)); 11.161 } 11.162 11.163 private void ensureConstructor(final CompiledFunction inv) { 11.164 if (!inv.hasConstructor()) { 11.165 - inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker()))); 11.166 + inv.setConstructor(composeConstructor(inv.getInvoker())); 11.167 } 11.168 } 11.169 11.170 /** 11.171 - * Heuristic to figure out if the method handle has a callee argument. If it's type is either 11.172 - * {@code (boolean, ScriptFunction, ...)} or {@code (ScriptFunction, ...)}, then we'll assume it has 11.173 - * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly 11.174 - * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore 11.175 + * Heuristic to figure out if the method handle has a callee argument. If it's type is 11.176 + * {@code (ScriptFunction, ...)}, then we'll assume it has a callee argument. We need this as 11.177 + * the constructor above is not passed this information, and can't just blindly assume it's false 11.178 + * (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore 11.179 * they also always receive a callee). 11.180 * 11.181 * @param mh the examined method handle 11.182 @@ -685,18 +680,8 @@ 11.183 * @return true if the method handle expects a callee, false otherwise 11.184 */ 11.185 protected static boolean needsCallee(final MethodHandle mh) { 11.186 - final MethodType type = mh.type(); 11.187 - final int length = type.parameterCount(); 11.188 - 11.189 - if (length == 0) { 11.190 - return false; 11.191 - } 11.192 - 11.193 - if (type.parameterType(0) == ScriptFunction.class) { 11.194 - return true; 11.195 - } 11.196 - 11.197 - return length > 1 && type.parameterType(0) == boolean.class && type.parameterType(1) == ScriptFunction.class; 11.198 + final MethodType type = mh.type(); 11.199 + return (type.parameterCount() > 0 && type.parameterType(0) == ScriptFunction.class); 11.200 } 11.201 11.202 /**
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 12.2 +++ b/test/script/basic/JDK-8027042.js Tue Oct 29 10:40:00 2013 -0300 12.3 @@ -0,0 +1,58 @@ 12.4 +/* 12.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 12.7 + * 12.8 + * This code is free software; you can redistribute it and/or modify it 12.9 + * under the terms of the GNU General Public License version 2 only, as 12.10 + * published by the Free Software Foundation. 12.11 + * 12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12.15 + * version 2 for more details (a copy is included in the LICENSE file that 12.16 + * accompanied this code). 12.17 + * 12.18 + * You should have received a copy of the GNU General Public License version 12.19 + * 2 along with this work; if not, write to the Free Software Foundation, 12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 12.21 + * 12.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 12.23 + * or visit www.oracle.com if you need additional information or have any 12.24 + * questions. 12.25 + */ 12.26 + 12.27 +/** 12.28 + * JDK-8027042: Evaluation order for binary operators can be improved 12.29 + * 12.30 + * @test 12.31 + * @run 12.32 + */ 12.33 + 12.34 +// var with getter side effect 12.35 +Object.defineProperty(this, "a", { get: function() {print("get a"); return 1; }}); 12.36 + 12.37 +// var with both getter and conversion side effect 12.38 +Object.defineProperty(this, "b", { get: function() {print("get b"); return {valueOf: function() { print("conv b"); return 10; }}; }}); 12.39 + 12.40 +(function() { 12.41 + // var with toPrimitive conversion side effect 12.42 + var c = {valueOf: function() { print("conv c"); return 100; }}; 12.43 + 12.44 + print(b + (c + a)); 12.45 + print(b + (c + b)); 12.46 + print(b + (a + b)); 12.47 + print(b + (b + c)); 12.48 + print(b + (b + c)); 12.49 + print(b + (c + (a - b))); 12.50 + print(b + (c + (c - b))); 12.51 + print(b + (c + (b - c))); 12.52 + print(b + (b + (a ? 2 : 3))); 12.53 + print(b + (b + (b ? 2 : 3))); 12.54 + print(b + (b + (c ? 2 : 3))); 12.55 + print(b + ((-c) + (-a))); 12.56 + print(b + ((-c) + (-b))); 12.57 + print(b + ((-c) + (-c))); 12.58 + try { print(b + new a); } catch (e) {} 12.59 + try { print(b + new b); } catch (e) {} 12.60 + try { print(b + new c); } catch (e) {} 12.61 +})();
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 13.2 +++ b/test/script/basic/JDK-8027042.js.EXPECTED Tue Oct 29 10:40:00 2013 -0300 13.3 @@ -0,0 +1,88 @@ 13.4 +get b 13.5 +get a 13.6 +conv c 13.7 +conv b 13.8 +111 13.9 +get b 13.10 +get b 13.11 +conv c 13.12 +conv b 13.13 +conv b 13.14 +120 13.15 +get b 13.16 +get a 13.17 +get b 13.18 +conv b 13.19 +conv b 13.20 +21 13.21 +get b 13.22 +get b 13.23 +conv b 13.24 +conv c 13.25 +conv b 13.26 +120 13.27 +get b 13.28 +get b 13.29 +conv b 13.30 +conv c 13.31 +conv b 13.32 +120 13.33 +get b 13.34 +get a 13.35 +get b 13.36 +conv b 13.37 +conv c 13.38 +conv b 13.39 +101 13.40 +get b 13.41 +get b 13.42 +conv c 13.43 +conv b 13.44 +conv c 13.45 +conv b 13.46 +200 13.47 +get b 13.48 +get b 13.49 +conv b 13.50 +conv c 13.51 +conv c 13.52 +conv b 13.53 +20 13.54 +get b 13.55 +get b 13.56 +get a 13.57 +conv b 13.58 +conv b 13.59 +22 13.60 +get b 13.61 +get b 13.62 +get b 13.63 +conv b 13.64 +conv b 13.65 +22 13.66 +get b 13.67 +get b 13.68 +conv b 13.69 +conv b 13.70 +22 13.71 +get b 13.72 +conv c 13.73 +get a 13.74 +conv b 13.75 +-91 13.76 +get b 13.77 +conv c 13.78 +get b 13.79 +conv b 13.80 +conv b 13.81 +-100 13.82 +get b 13.83 +conv c 13.84 +conv c 13.85 +conv b 13.86 +-190 13.87 +get b 13.88 +get a 13.89 +get b 13.90 +get b 13.91 +get b