hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java
changeset 46459 7d4e637d3f21
parent 46393 d497d892ab11
child 46509 b32d3928ad6a
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri May 12 13:14:25 2017 -0700
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri May 12 13:56:13 2017 -0700
@@ -247,6 +247,7 @@
 import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull;
 import static org.graalvm.compiler.debug.GraalError.guarantee;
 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
+import static org.graalvm.compiler.java.BytecodeParserOptions.DumpWithInfopoints;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing;
 import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins;
@@ -262,6 +263,7 @@
 import java.util.Formatter;
 import java.util.List;
 
+import org.graalvm.api.word.LocationIdentity;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
@@ -273,7 +275,6 @@
 import org.graalvm.compiler.bytecode.Bytes;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
-import org.graalvm.compiler.core.common.LocationIdentity;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
@@ -427,6 +428,7 @@
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
 import jdk.vm.ci.meta.TriState;
 
 /**
@@ -1087,7 +1089,7 @@
     }
 
     protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
+        return NormalizeCompareNode.create(x, y, isUnorderedLess, JavaKind.Int, constantReflection);
     }
 
     protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
@@ -1374,7 +1376,7 @@
 
     @Override
     public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
-        createNonInlinedInvoke(callTarget, resultType, null);
+        createNonInlinedInvoke(bci(), callTarget, resultType, null);
     }
 
     private Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
@@ -1440,23 +1442,74 @@
             currentInvokeKind = null;
         }
 
+        int bci = bci();
+        boolean partialIntrinsicExit = false;
+        if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
+            partialIntrinsicExit = true;
+            ResolvedJavaMethod originalMethod = intrinsicContext.getOriginalMethod();
+            if (originalMethod.isStatic()) {
+                invokeKind = InvokeKind.Static;
+            } else {
+                // The original call to the intrinsic must have been devirtualized
+                // otherwise we wouldn't be here.
+                invokeKind = InvokeKind.Special;
+            }
+            Signature sig = originalMethod.getSignature();
+            returnType = sig.getReturnType(method.getDeclaringClass());
+            resultType = sig.getReturnKind();
+            bci = intrinsicContext.bci();
+            assert checkPartialIntrinsicExit(args);
+            targetMethod = originalMethod;
+        }
         JavaTypeProfile profile = null;
         if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
             profile = profilingInfo.getTypeProfile(bci());
         }
-        return createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+        Invoke invoke = createNonInlinedInvoke(args, bci, targetMethod, invokeKind, resultType, returnType, inlineInfo, profile);
+        if (partialIntrinsicExit) {
+            // This invoke must never be later inlined as it might select the intrinsic graph.
+            // Until there is a mechanism to guarantee that any late inlining will not select
+            // the intrinsic graph, prevent this invoke from being inlined.
+            invoke.setUseForInlining(false);
+        }
+        return invoke;
     }
 
-    protected Invoke createNonInlinedInvoke(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind,
-                    JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
+    /**
+     * A partial intrinsic exits by (effectively) calling the intrinsified method. This call must
+     * use exactly the arguments to the call being intrinsified.
+     *
+     * @param args arguments of recursive call to intrinsified method
+     */
+    private boolean checkPartialIntrinsicExit(ValueNode[] args) {
+        if (intrinsicContext.getArgs() != null) {
+            assert intrinsicContext.bci() >= 0;
+            ValueNode[] icArgs = intrinsicContext.getArgs();
+            for (int i = 0; i < icArgs.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(args[i]);
+                ValueNode icArg = GraphUtil.unproxify(icArgs[i]);
+                assert arg == icArg : String.format("argument %d of call denoting partial intrinsic exit should be %s, not %s", i, icArg, arg);
+            }
+        } else {
+            for (int i = 0; i < args.length; i++) {
+                ValueNode arg = GraphUtil.unproxify(args[i]);
+                assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s", i,
+                                ParameterNode.class.getSimpleName(), i, arg);
+            }
+        }
+        return true;
+    }
+
+    protected Invoke createNonInlinedInvoke(ValueNode[] invokeArgs, int invokeBci, ResolvedJavaMethod targetMethod,
+                    InvokeKind invokeKind, JavaKind resultType, JavaType returnType, InlineInfo inlineInfo, JavaTypeProfile profile) {
 
         StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
         if (returnStamp == null) {
             returnStamp = StampFactory.forDeclaredType(graph.getAssumptions(), returnType, false);
         }
 
-        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnStamp, profile));
-        Invoke invoke = createNonInlinedInvoke(callTarget, resultType, inlineInfo);
+        MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
+        Invoke invoke = createNonInlinedInvoke(invokeBci, callTarget, resultType, inlineInfo);
 
         for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
             plugin.notifyNotInlined(this, targetMethod, invoke);
@@ -1465,11 +1518,11 @@
         return invoke;
     }
 
-    protected Invoke createNonInlinedInvoke(CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) {
+    protected Invoke createNonInlinedInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType, InlineInfo inlineInfo) {
         if (omitInvokeExceptionEdge(callTarget, inlineInfo)) {
-            return createInvoke(callTarget, resultType);
+            return createInvoke(invokeBci, callTarget, resultType);
         } else {
-            Invoke invoke = createInvokeWithException(callTarget, resultType);
+            Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType);
             AbstractBeginNode beginNode = graph.add(KillingBeginNode.create(LocationIdentity.any()));
             invoke.setNext(beginNode);
             lastInstr = beginNode;
@@ -1678,15 +1731,15 @@
 
     /**
      * Performs any action required after execution of an invocation plugin. This includes
-     * {@linkplain InvocationPluginAssertions#check(boolean) checking} invocation plugin invariants
-     * as well as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
+     * {@linkplain InvocationPluginAssertions#check checking} invocation plugin invariants as well
+     * as weaving the {@code else} branch of the code woven by {@link #guardIntrinsic} if
      * {@code guard != null}.
      */
-    protected void afterInvocationPluginExecution(boolean pluginResult, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
+    protected void afterInvocationPluginExecution(boolean pluginHandledInvoke, InvocationPluginAssertions assertions, IntrinsicGuard intrinsicGuard,
                     InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
-        assert assertions.check(pluginResult);
+        assert assertions.check(pluginHandledInvoke);
         if (intrinsicGuard != null) {
-            if (pluginResult) {
+            if (pluginHandledInvoke) {
                 if (intrinsicGuard.nonIntrinsicBranch != null) {
                     // Intrinsic emitted: emit a virtual call to the target method and
                     // merge it with the intrinsic branch
@@ -1701,7 +1754,7 @@
                     }
 
                     lastInstr = intrinsicGuard.nonIntrinsicBranch;
-                    createNonInlinedInvoke(args, targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
+                    createNonInlinedInvoke(args, bci(), targetMethod, invokeKind, resultType, returnType, null, intrinsicGuard.profile);
 
                     EndNode nonIntrinsicEnd = append(new EndNode());
                     AbstractMergeNode mergeNode = graph.add(new MergeNode());
@@ -1825,7 +1878,9 @@
                     ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get();
                     ResolvedJavaField resolvedField = (ResolvedJavaField) field;
                     genGetField(resolvedField, receiver);
+                    notifyBeforeInline(targetMethod);
                     printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
+                    notifyAfterInline(targetMethod);
                     return true;
                 }
             }
@@ -1844,7 +1899,6 @@
     }
 
     private boolean inline(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, BytecodeProvider intrinsicBytecodeProvider, ValueNode[] args) {
-        traceInlining(targetMethod, inlinedMethod);
         IntrinsicContext intrinsic = this.intrinsicContext;
 
         if (intrinsic == null && !graphBuilderConfig.insertFullInfopoints() &&
@@ -1864,32 +1918,35 @@
                 printInlining(targetMethod, inlinedMethod, true, "compilation root (bytecode parsing)");
                 return true;
             } else {
-                // Otherwise inline the original method. Any frame state created
-                // during the inlining will exclude frame(s) in the
-                // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
                 if (intrinsic.getOriginalMethod().isNative()) {
                     printInlining(targetMethod, inlinedMethod, false, "native method (bytecode parsing)");
                     return false;
                 }
-                printInlining(targetMethod, inlinedMethod, true, "inline intrinsic (bytecode parsing)");
-                parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
-                return true;
+                if (inlinePartialIntrinsicExit()) {
+                    // Otherwise inline the original method. Any frame state created
+                    // during the inlining will exclude frame(s) in the
+                    // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                    notifyBeforeInline(inlinedMethod);
+                    printInlining(targetMethod, inlinedMethod, true, "partial intrinsic exit (bytecode parsing)");
+                    parseAndInlineCallee(intrinsic.getOriginalMethod(), args, null);
+                    notifyAfterInline(inlinedMethod);
+                    return true;
+                } else {
+                    printInlining(targetMethod, inlinedMethod, false, "partial intrinsic exit (bytecode parsing)");
+                    return false;
+                }
             }
         } else {
             boolean isIntrinsic = intrinsicBytecodeProvider != null;
             if (intrinsic == null && isIntrinsic) {
                 assert !inlinedMethod.equals(targetMethod);
-                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING);
+                intrinsic = new IntrinsicContext(targetMethod, inlinedMethod, intrinsicBytecodeProvider, INLINE_DURING_PARSING, args, bci());
             }
             if (inlinedMethod.hasBytecodes()) {
-                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
-                    plugin.notifyBeforeInline(inlinedMethod);
-                }
+                notifyBeforeInline(inlinedMethod);
                 printInlining(targetMethod, inlinedMethod, true, "inline method (bytecode parsing)");
                 parseAndInlineCallee(inlinedMethod, args, intrinsic);
-                for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
-                    plugin.notifyAfterInline(inlinedMethod);
-                }
+                notifyAfterInline(inlinedMethod);
             } else {
                 printInlining(targetMethod, inlinedMethod, false, "no bytecodes (abstract or native) (bytecode parsing)");
                 return false;
@@ -1898,17 +1955,36 @@
         return true;
     }
 
-    private void traceInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod) {
-        if (TraceInlineDuringParsing.getValue(options) || TraceParserPlugins.getValue(options)) {
-            if (targetMethod.equals(inlinedMethod)) {
-                traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
-            } else {
-                traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
-            }
+    protected void notifyBeforeInline(ResolvedJavaMethod inlinedMethod) {
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            plugin.notifyBeforeInline(inlinedMethod);
         }
     }
 
+    protected void notifyAfterInline(ResolvedJavaMethod inlinedMethod) {
+        for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
+            plugin.notifyAfterInline(inlinedMethod);
+        }
+    }
+
+    /**
+     * Determines if a partial intrinsic exit (i.e., a call to the original method within an
+     * intrinsic) should be inlined.
+     */
+    protected boolean inlinePartialIntrinsicExit() {
+        return true;
+    }
+
     private void printInlining(ResolvedJavaMethod targetMethod, ResolvedJavaMethod inlinedMethod, boolean success, String msg) {
+        if (success) {
+            if (TraceInlineDuringParsing.getValue(options) || TraceParserPlugins.getValue(options)) {
+                if (targetMethod.equals(inlinedMethod)) {
+                    traceWithContext("inlining call to %s", inlinedMethod.format("%h.%n(%p)"));
+                } else {
+                    traceWithContext("inlining call to %s as intrinsic for %s", inlinedMethod.format("%h.%n(%p)"), targetMethod.format("%h.%n(%p)"));
+                }
+            }
+        }
         if (HotSpotPrintInlining.getValue(options)) {
             if (targetMethod.equals(inlinedMethod)) {
                 Util.printInlining(inlinedMethod, bci(), getDepth(), success, "%s", msg);
@@ -1934,8 +2010,12 @@
 
     protected void traceWithContext(String format, Object... args) {
         StackTraceElement where = code.asStackTraceElement(bci());
-        TTY.println(format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
-                        format(format, args)));
+        String s = format("%s%s (%s:%d) %s", nSpaces(getDepth()), method.isConstructor() ? method.format("%h.%n") : method.getName(), where.getFileName(), where.getLineNumber(),
+                        format(format, args));
+        if (s.equals("decrypt (CipherBlockChainingSubstitutions.java:117) inlining call to CipherBlockChainingSubstitutions.decrypt(Object, byte[], int, int, byte[], int)")) {
+            System.console();
+        }
+        TTY.println(s);
     }
 
     protected BytecodeParserError asParserError(Throwable e) {
@@ -2003,14 +2083,15 @@
         return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, profile);
     }
 
-    protected InvokeNode createInvoke(CallTargetNode callTarget, JavaKind resultType) {
-        InvokeNode invoke = append(new InvokeNode(callTarget, bci()));
+    protected InvokeNode createInvoke(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+        InvokeNode invoke = append(new InvokeNode(callTarget, invokeBci));
         frameState.pushReturn(resultType, invoke);
         invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
         return invoke;
     }
 
-    protected InvokeWithExceptionNode createInvokeWithException(CallTargetNode callTarget, JavaKind resultType) {
+    protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+        assert bci() == invokeBci;
         if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
             /*
              * Clear non-live locals early so that the exception handler entry gets the cleared
@@ -2642,7 +2723,7 @@
     }
 
     private DebugCloseable openNodeContext() {
-        if ((graphBuilderConfig.trackNodeSourcePosition() || Debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) {
+        if ((graphBuilderConfig.trackNodeSourcePosition() || (Debug.isDumpEnabledForMethod() && DumpWithInfopoints.getValue(options))) && !parsingIntrinsic()) {
             return graph.withNodeSourcePosition(createBytecodePosition());
         }
         return null;