diff options
Diffstat (limited to 'src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java')
-rw-r--r-- | src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java | 124 |
1 files changed, 111 insertions, 13 deletions
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index c2259896..03a25dab 100644 --- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -30,9 +30,12 @@ import static jdk.nashorn.internal.lookup.Lookup.MH; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.LinkedList; + import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.codegen.FunctionSignature; +import jdk.nashorn.internal.codegen.types.Type; import jdk.nashorn.internal.ir.FunctionNode; import jdk.nashorn.internal.ir.FunctionNode.CompilationState; import jdk.nashorn.internal.parser.Token; @@ -148,10 +151,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { if (functionNode.isLazy()) { Compiler.LOG.info("Trampoline hit: need to do lazy compilation of '", functionNode.getName(), "'"); - final Compiler compiler = new Compiler(installer, functionNode); - functionNode = compiler.compile(); + final Compiler compiler = new Compiler(installer); + functionNode = compiler.compile(functionNode); assert !functionNode.isLazy(); - compiler.install(); + compiler.install(functionNode); // we don't need to update any flags - varArgs and needsCallee are instrincic // in the function world we need to get a destination node from the compile instead @@ -164,23 +167,118 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { assert functionNode.hasState(CompilationState.EMITTED) : functionNode.getName() + " " + functionNode.getState() + " " + Debug.id(functionNode); // code exists - look it up and add it into the automatically sorted invoker list - code.add( - new CompiledFunction( - MH.findStatic( + addCode(functionNode, null, null); + } + + private MethodHandle addCode(final FunctionNode fn, final MethodHandle guard, final MethodHandle fallback) { + final MethodHandle target = + MH.findStatic( LOOKUP, - functionNode.getCompileUnit().getCode(), - functionNode.getName(), - new FunctionSignature(functionNode). - getMethodType()))); + fn.getCompileUnit().getCode(), + fn.getName(), + new FunctionSignature(fn). + getMethodType()); + MethodHandle mh = target; + if (guard != null) { + try { + mh = MH.guardWithTest(MH.asCollector(guard, Object[].class, target.type().parameterCount()), MH.asType(target, fallback.type()), fallback); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + final CompiledFunction cf = new CompiledFunction(mh); + code.add(cf); + + return cf.getInvoker(); } + private static Type runtimeType(final Object arg) { + if (arg == null) { + return Type.OBJECT; + } + + final Class<?> clazz = arg.getClass(); + assert !clazz.isPrimitive() : "always boxed"; + if (clazz == Double.class) { + return JSType.isRepresentableAsInt((double)arg) ? Type.INT : Type.NUMBER; + } else if (clazz == Integer.class) { + return Type.INT; + } else if (clazz == Long.class) { + return Type.LONG; + } else if (clazz == String.class) { + return Type.STRING; + } + return Type.OBJECT; + } + + @SuppressWarnings("unused") + private static boolean paramTypeGuard(final Type[] compileTimeTypes, final Type[] runtimeTypes, Object... args) { + //System.err.println("Param type guard " + Arrays.asList(args)); + return false; + } + + private static final MethodHandle PARAM_TYPE_GUARD = findOwnMH("paramTypeGuard", boolean.class, Type[].class, Type[].class, Object[].class); + @Override MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) { final MethodHandle mh = super.getBestInvoker(callSiteType, args); - if (code.isLessSpecificThan(callSiteType)) { - // opportunity for code specialization - we can regenerate a better version of this method + + if (!functionNode.canSpecialize() || !code.isLessSpecificThan(callSiteType)) { + return mh; + } + + final FunctionNode snapshot = functionNode.getSnapshot(); + if (snapshot == null) { + return mh; } - return mh; + + int i; + + //classes known at runtime + final LinkedList<Type> runtimeArgs = new LinkedList<>(); + for (i = args.length - 1; i >= args.length - snapshot.getParameters().size(); i--) { + runtimeArgs.addLast(runtimeType(args[i])); + } + + //classes known at compile time + final LinkedList<Type> compileTimeArgs = new LinkedList<>(); + for (i = callSiteType.parameterCount() - 1; i >= 0 && compileTimeArgs.size() < snapshot.getParameters().size(); i--) { + compileTimeArgs.addLast(Type.typeFor(callSiteType.parameterType(i))); + } + + //the classes known at compile time are a safe to generate as primitives without parameter guards + //the classes known at runtime are safe to generate as primitives IFF there are parameter guards + MethodHandle guard = null; + for (i = 0; i < compileTimeArgs.size(); i++) { + final Type runtimeType = runtimeArgs.get(i); + final Type compileType = compileTimeArgs.get(i); + + if (compileType.isObject() && !runtimeType.isObject()) { + if (guard == null) { + guard = PARAM_TYPE_GUARD; + guard = MH.insertArguments(guard, 0, compileTimeArgs.toArray(new Type[compileTimeArgs.size()]), runtimeArgs.toArray(new Type[runtimeArgs.size()])); + } + } + } + + //System.err.println("Specialized " + name + " " + runtimeArgs + " known=" + compileTimeArgs); + + assert snapshot != null; + assert snapshot != functionNode; + + final Compiler compiler = new Compiler(installer); + final FunctionNode compiledSnapshot = compiler.compile(snapshot.setHints(null, new Compiler.Hints(compileTimeArgs.toArray(new Type[compileTimeArgs.size()])))); + + compiler.install(compiledSnapshot); + + final MethodHandle nmh = addCode(compiledSnapshot, guard, mh); + + return nmh; + } + + private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) { + return MH.findStatic(MethodHandles.lookup(), RecompilableScriptFunctionData.class, name, MH.type(rtype, types)); } } |