Mercurial > hg > graal-compiler
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) {