Merge

Tue, 29 Oct 2013 10:40:00 -0300

author
jlaskey
date
Tue, 29 Oct 2013 10:40:00 -0300
changeset 654
406f2b672937
parent 651
767e85d2a1b3
parent 653
71cfb21c68dc
child 658
5ce78473d6c3

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

mercurial