comparison 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
comparison
equal deleted inserted replaced
18466:2d2fcdbae37b 18467:1d2e382d8259
26 import com.oracle.graal.compiler.common.type.*; 26 import com.oracle.graal.compiler.common.type.*;
27 import com.oracle.graal.graph.*; 27 import com.oracle.graal.graph.*;
28 import com.oracle.graal.graph.spi.*; 28 import com.oracle.graal.graph.spi.*;
29 import com.oracle.graal.nodeinfo.*; 29 import com.oracle.graal.nodeinfo.*;
30 import com.oracle.graal.nodes.*; 30 import com.oracle.graal.nodes.*;
31 import com.oracle.graal.nodes.spi.*;
31 import com.oracle.graal.nodes.type.*; 32 import com.oracle.graal.nodes.type.*;
32 33
33 @NodeInfo 34 @NodeInfo
34 public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Simplifiable { 35 public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Simplifiable {
35 protected final JavaType returnType; 36 protected final JavaType returnType;
154 /* 155 /*
155 * We need to check the invoke kind to avoid recursive simplification for virtual 156 * We need to check the invoke kind to avoid recursive simplification for virtual
156 * interface methods calls. 157 * interface methods calls.
157 */ 158 */
158 if (declaredReceiverType.isInterface() && !invokeKind().equals(InvokeKind.Virtual)) { 159 if (declaredReceiverType.isInterface() && !invokeKind().equals(InvokeKind.Virtual)) {
159 ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor(); 160 tryCheckCastSingleImplementor(receiver, declaredReceiverType);
160 if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) { 161 }
161 ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true); 162
162 if (singleImplementorMethod != null) { 163 if (invokeKind().equals(InvokeKind.Interface) && receiver instanceof UncheckedInterfaceProvider) {
163 assert graph().getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal() : "Graph already fixed!"; 164 UncheckedInterfaceProvider uncheckedInterfaceProvider = (UncheckedInterfaceProvider) receiver;
164 /** 165 Stamp uncheckedStamp = uncheckedInterfaceProvider.uncheckedStamp();
165 * We have an invoke on an interface with a single implementor. We can 166 if (uncheckedStamp != null) {
166 * replace this with an invoke virtual. 167 ResolvedJavaType uncheckedReceiverType = StampTool.typeOrNull(uncheckedStamp);
167 * 168 if (uncheckedReceiverType.isInterface()) {
168 * To do so we need to ensure two properties: 1) the receiver must implement 169 tryCheckCastSingleImplementor(receiver, uncheckedReceiverType);
169 * the interface (declaredReceiverType). The verifier does not prove this so
170 * we need a dynamic check. 2) we need to ensure that there is still only
171 * one implementor of this interface, i.e. that we are calling the right
172 * method. We could do this with an assumption but as we need an instanceof
173 * check anyway we can verify both properties by checking of the receiver is
174 * an instance of the single implementor.
175 */
176 LogicNode condition = graph().unique(InstanceOfNode.create(singleImplementor, receiver, getProfile()));
177 GuardNode guard = graph().unique(
178 GuardNode.create(condition, BeginNode.prevBegin(invoke().asNode()), DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile,
179 false, JavaConstant.NULL_OBJECT));
180 PiNode piNode = graph().unique(PiNode.create(receiver, StampFactory.declaredNonNull(singleImplementor), guard));
181 arguments().set(0, piNode);
182 setInvokeKind(InvokeKind.Virtual);
183 setTargetMethod(singleImplementorMethod);
184 } 170 }
185 } 171 }
172 }
173 }
174 }
175
176 private void tryCheckCastSingleImplementor(ValueNode receiver, ResolvedJavaType declaredReceiverType) {
177 ResolvedJavaType singleImplementor = declaredReceiverType.getSingleImplementor();
178 if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) {
179 ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveMethod(targetMethod(), invoke().getContextType(), true);
180 if (singleImplementorMethod != null) {
181 assert graph().getGuardsStage().ordinal() < StructuredGraph.GuardsStage.FIXED_DEOPTS.ordinal() : "Graph already fixed!";
182 /**
183 * We have an invoke on an interface with a single implementor. We can replace this
184 * with an invoke virtual.
185 *
186 * To do so we need to ensure two properties: 1) the receiver must implement the
187 * interface (declaredReceiverType). The verifier does not prove this so we need a
188 * dynamic check. 2) we need to ensure that there is still only one implementor of
189 * this interface, i.e. that we are calling the right method. We could do this with
190 * an assumption but as we need an instanceof check anyway we can verify both
191 * properties by checking of the receiver is an instance of the single implementor.
192 */
193 LogicNode condition = graph().unique(InstanceOfNode.create(singleImplementor, receiver, getProfile()));
194 GuardNode guard = graph().unique(
195 GuardNode.create(condition, BeginNode.prevBegin(invoke().asNode()), DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, false,
196 JavaConstant.NULL_OBJECT));
197 PiNode piNode = graph().unique(PiNode.create(receiver, StampFactory.declaredNonNull(singleImplementor), guard));
198 arguments().set(0, piNode);
199 setInvokeKind(InvokeKind.Virtual);
200 setTargetMethod(singleImplementorMethod);
186 } 201 }
187 } 202 }
188 } 203 }
189 204
190 private JavaTypeProfile getProfile() { 205 private JavaTypeProfile getProfile() {