8060241: Immediately invoked function expressions cause lot of deoptimization

Wed, 15 Oct 2014 16:00:21 +0200

author
attila
date
Wed, 15 Oct 2014 16:00:21 +0200
changeset 1057
ef1e5e03e03e
parent 1056
db675278b4d3
child 1058
2bf4c14345aa

8060241: Immediately invoked function expressions cause lot of deoptimization
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/codegen/TypeEvaluator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java	Wed Oct 15 15:57:46 2014 +0200
     1.2 +++ b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java	Wed Oct 15 16:00:21 2014 +0200
     1.3 @@ -29,9 +29,12 @@
     1.4  import static jdk.nashorn.internal.runtime.Property.NOT_ENUMERABLE;
     1.5  import static jdk.nashorn.internal.runtime.Property.NOT_WRITABLE;
     1.6  
     1.7 +import java.lang.invoke.MethodType;
     1.8  import jdk.nashorn.internal.codegen.types.Type;
     1.9  import jdk.nashorn.internal.ir.AccessNode;
    1.10 +import jdk.nashorn.internal.ir.CallNode;
    1.11  import jdk.nashorn.internal.ir.Expression;
    1.12 +import jdk.nashorn.internal.ir.FunctionNode;
    1.13  import jdk.nashorn.internal.ir.IdentNode;
    1.14  import jdk.nashorn.internal.ir.IndexNode;
    1.15  import jdk.nashorn.internal.ir.Optimistic;
    1.16 @@ -40,6 +43,8 @@
    1.17  import jdk.nashorn.internal.runtime.FindProperty;
    1.18  import jdk.nashorn.internal.runtime.JSType;
    1.19  import jdk.nashorn.internal.runtime.Property;
    1.20 +import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
    1.21 +import jdk.nashorn.internal.runtime.ScriptFunction;
    1.22  import jdk.nashorn.internal.runtime.ScriptObject;
    1.23  import jdk.nashorn.internal.runtime.ScriptRuntime;
    1.24  
    1.25 @@ -48,6 +53,13 @@
    1.26   * Used during recompilation.
    1.27   */
    1.28  final class TypeEvaluator {
    1.29 +    /**
    1.30 +     * Type signature for invocation of functions without parameters: we must pass (callee, this) of type
    1.31 +     * (ScriptFunction, Object) respectively. We also use Object as the return type (we must pass something,
    1.32 +     * but it'll be ignored; it can't be void, though).
    1.33 +     */
    1.34 +    private static final MethodType EMPTY_INVOCATION_TYPE = MethodType.methodType(Object.class, ScriptFunction.class, Object.class);
    1.35 +
    1.36      private final Compiler compiler;
    1.37      private final ScriptObject runtimeScope;
    1.38  
    1.39 @@ -191,28 +203,39 @@
    1.40                  return null;
    1.41              }
    1.42              return getPropertyType(runtimeScope, ((IdentNode)expr).getName());
    1.43 -        }
    1.44 -
    1.45 -        if (expr instanceof AccessNode) {
    1.46 +        } else if (expr instanceof AccessNode) {
    1.47              final AccessNode accessNode = (AccessNode)expr;
    1.48              final Object base = evaluateSafely(accessNode.getBase());
    1.49              if (!(base instanceof ScriptObject)) {
    1.50                  return null;
    1.51              }
    1.52              return getPropertyType((ScriptObject)base, accessNode.getProperty());
    1.53 -        }
    1.54 -
    1.55 -        if (expr instanceof IndexNode) {
    1.56 +        } else if (expr instanceof IndexNode) {
    1.57              final IndexNode indexNode = (IndexNode)expr;
    1.58              final Object    base = evaluateSafely(indexNode.getBase());
    1.59              if(base instanceof NativeArray || base instanceof ArrayBufferView) {
    1.60 -                // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their underlying
    1.61 -                // array storage, not based on values of individual elements. Thus, a LongArrayData will throw UOE for every
    1.62 -                // optimistic int linkage attempt, even if the long value being returned in the first invocation would be
    1.63 -                // representable as int. That way, we can presume that the array's optimistic type is the most optimistic
    1.64 -                // type for which an element getter has a chance of executing successfully.
    1.65 +                // NOTE: optimistic array getters throw UnwarrantedOptimismException based on the type of their
    1.66 +                // underlying array storage, not based on values of individual elements. Thus, a LongArrayData will
    1.67 +                // throw UOE for every optimistic int linkage attempt, even if the long value being returned in the
    1.68 +                // first invocation would be representable as int. That way, we can presume that the array's optimistic
    1.69 +                // type is the most optimistic type for which an element getter has a chance of executing successfully.
    1.70                  return ((ScriptObject)base).getArray().getOptimisticType();
    1.71              }
    1.72 +        } else if (expr instanceof CallNode) {
    1.73 +            // Currently, we'll only try to guess the return type of immediately invoked function expressions with no
    1.74 +            // parameters, that is (function() { ... })(). We could do better, but these are all heuristics and we can
    1.75 +            // gradually introduce them as needed. An easy one would be to do the same for .call(this) idiom.
    1.76 +            final CallNode callExpr = (CallNode)expr;
    1.77 +            final Expression fnExpr = callExpr.getFunction();
    1.78 +            if (fnExpr instanceof FunctionNode) {
    1.79 +                final FunctionNode fn = (FunctionNode)fnExpr;
    1.80 +                if (callExpr.getArgs().isEmpty()) {
    1.81 +                    final RecompilableScriptFunctionData data = compiler.getScriptFunctionData(fn.getId());
    1.82 +                    if (data != null) {
    1.83 +                        return Type.typeFor(data.getReturnType(EMPTY_INVOCATION_TYPE, runtimeScope));
    1.84 +                    }
    1.85 +                }
    1.86 +            }
    1.87          }
    1.88  
    1.89          return null;
     2.1 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Oct 15 15:57:46 2014 +0200
     2.2 +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java	Wed Oct 15 16:00:21 2014 +0200
     2.3 @@ -676,6 +676,22 @@
     2.4          return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
     2.5      }
     2.6  
     2.7 +    /**
     2.8 +     * Returns the return type of a function specialization for particular parameter types.<br>
     2.9 +     * <b>Be aware that the way this is implemented, it forces full materialization (compilation and installation) of
    2.10 +     * code for that specialization.</b>
    2.11 +     * @param callSiteType the parameter types at the call site. It must include the mandatory {@code callee} and
    2.12 +     * {@code this} parameters, so it needs to start with at least {@code ScriptFunction.class} and
    2.13 +     * {@code Object.class} class. Since the return type of the function is calculated from the code itself, it is
    2.14 +     * irrelevant and should be set to {@code Object.class}.
    2.15 +     * @param runtimeScope a current runtime scope. Can be null but when it's present it will be used as a source of
    2.16 +     * current runtime values that can improve the compiler's type speculations (and thus reduce the need for later
    2.17 +     * recompilations) if the specialization is not already present and thus needs to be freshly compiled.
    2.18 +     * @return the return type of the function specialization.
    2.19 +     */
    2.20 +    public Class<?> getReturnType(final MethodType callSiteType, final ScriptObject runtimeScope) {
    2.21 +        return getBest(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS).type().returnType();
    2.22 +    }
    2.23  
    2.24      @Override
    2.25      synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {

mercurial