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