diff graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java @ 18467:1d2e382d8259

Add UncheckedInterfaceProvider interface for nodes that can give an unchecked hint about the interface type they are likely to return. Use it in MethodCallTargetNode to attempt single-implementor checkcast based devirtualization.
author Gilles Duboscq <duboscq@ssw.jku.at>
date Wed, 19 Nov 2014 14:36:01 +0100
parents c7cd54360119
children ca81508f2a19
line wrap: on
line diff
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Nov 19 17:11:19 2014 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed Nov 19 14:36:01 2014 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 @NodeInfo
@@ -156,37 +157,51 @@
              * interface methods calls.
              */
             if (declaredReceiverType.isInterface() && !invokeKind().equals(InvokeKind.Virtual)) {
-                ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
-                if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
-                    ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true);
-                    if (singleImplementorMethod != null) {
-                        assert graph().getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal() : "Graph already fixed!";
-                        /**
-                         * We have an invoke on an interface with a single implementor. We can
-                         * replace this with an invoke virtual.
-                         *
-                         * To do so we need to ensure two properties: 1) the receiver must implement
-                         * the interface (declaredReceiverType). The verifier does not prove this so
-                         * we need a dynamic check. 2) we need to ensure that there is still only
-                         * one implementor of this interface, i.e. that we are calling the right
-                         * method. We could do this with an assumption but as we need an instanceof
-                         * check anyway we can verify both properties by checking of the receiver is
-                         * an instance of the single implementor.
-                         */
-                        LogicNode condition = graph().unique(InstanceOfNode.create(singleImplementor, receiver, getProfile()));
-                        GuardNode guard = graph().unique(
-                                        GuardNode.create(condition, BeginNode.prevBegin(invoke().asNode()), DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile,
-                                                        false, JavaConstant.NULL_OBJECT));
-                        PiNode piNode = graph().unique(PiNode.create(receiver, StampFactory.declaredNonNull(singleImplementor), guard));
-                        arguments().set(0, piNode);
-                        setInvokeKind(InvokeKind.Virtual);
-                        setTargetMethod(singleImplementorMethod);
+                tryCheckCastSingleImplementor(receiver, declaredReceiverType);
+            }
+
+            if (invokeKind().equals(InvokeKind.Interface) && receiver instanceof UncheckedInterfaceProvider) {
+                UncheckedInterfaceProvider uncheckedInterfaceProvider = (UncheckedInterfaceProvider) receiver;
+                Stamp uncheckedStamp = uncheckedInterfaceProvider.uncheckedStamp();
+                if (uncheckedStamp != null) {
+                    ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp);
+                    if (uncheckedReceiverType.isInterface()) {
+                        tryCheckCastSingleImplementor(receiver, uncheckedReceiverType);
                     }
                 }
             }
         }
     }
 
+    private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) {
+        ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
+        if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
+            ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true);
+            if (singleImplementorMethod != null) {
+                assert graph().getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal() : "Graph already fixed!";
+                /**
+                 * We have an invoke on an interface with a single implementor. We can replace this
+                 * with an invoke virtual.
+                 *
+                 * To do so we need to ensure two properties: 1) the receiver must implement the
+                 * interface (declaredReceiverType). The verifier does not prove this so we need a
+                 * dynamic check. 2) we need to ensure that there is still only one implementor of
+                 * this interface, i.e. that we are calling the right method. We could do this with
+                 * an assumption but as we need an instanceof check anyway we can verify both
+                 * properties by checking of the receiver is an instance of the single implementor.
+                 */
+                LogicNode condition = graph().unique(InstanceOfNode.create(singleImplementor, receiver, getProfile()));
+                GuardNode guard = graph().unique(
+                                GuardNode.create(condition, BeginNode.prevBegin(invoke().asNode()), DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, false,
+                                                JavaConstant.NULL_OBJECT));
+                PiNode piNode = graph().unique(PiNode.create(receiver, StampFactory.declaredNonNull(singleImplementor), guard));
+                arguments().set(0, piNode);
+                setInvokeKind(InvokeKind.Virtual);
+                setTargetMethod(singleImplementorMethod);
+            }
+        }
+    }
+
     private JavaTypeProfile getProfile() {
         assert !isStatic();
         if (receiver() instanceof TypeProfileProxyNode) {