|
33 | 33 | import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; |
34 | 34 | import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; |
35 | 35 | import org.graalvm.compiler.core.common.type.StampPair; |
| 36 | +import org.graalvm.compiler.core.common.type.TypeReference; |
36 | 37 | import org.graalvm.compiler.debug.DebugHandlersFactory; |
37 | 38 | import org.graalvm.compiler.graph.Node; |
38 | 39 | import org.graalvm.compiler.graph.NodeInputList; |
| 40 | +import org.graalvm.compiler.nodes.BeginNode; |
39 | 41 | import org.graalvm.compiler.nodes.CallTargetNode; |
40 | 42 | import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; |
41 | 43 | import org.graalvm.compiler.nodes.ConstantNode; |
42 | 44 | import org.graalvm.compiler.nodes.DirectCallTargetNode; |
43 | 45 | import org.graalvm.compiler.nodes.FixedGuardNode; |
44 | 46 | import org.graalvm.compiler.nodes.FixedNode; |
| 47 | +import org.graalvm.compiler.nodes.FixedWithNextNode; |
| 48 | +import org.graalvm.compiler.nodes.IfNode; |
45 | 49 | import org.graalvm.compiler.nodes.IndirectCallTargetNode; |
46 | 50 | import org.graalvm.compiler.nodes.Invoke; |
47 | 51 | import org.graalvm.compiler.nodes.InvokeNode; |
|
54 | 58 | import org.graalvm.compiler.nodes.StructuredGraph; |
55 | 59 | import org.graalvm.compiler.nodes.ValueNode; |
56 | 60 | import org.graalvm.compiler.nodes.calc.IsNullNode; |
| 61 | +import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; |
57 | 62 | import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode; |
58 | 63 | import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; |
| 64 | +import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode; |
59 | 65 | import org.graalvm.compiler.nodes.extended.ForeignCallNode; |
60 | 66 | import org.graalvm.compiler.nodes.extended.GetClassNode; |
61 | 67 | import org.graalvm.compiler.nodes.extended.LoadHubNode; |
| 68 | +import org.graalvm.compiler.nodes.extended.OpaqueNode; |
| 69 | +import org.graalvm.compiler.nodes.java.InstanceOfNode; |
62 | 70 | import org.graalvm.compiler.nodes.java.MethodCallTargetNode; |
63 | 71 | import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType; |
64 | 72 | import org.graalvm.compiler.nodes.memory.ReadNode; |
|
73 | 81 | import org.graalvm.word.LocationIdentity; |
74 | 82 |
|
75 | 83 | import com.oracle.svm.core.FrameAccess; |
| 84 | +import com.oracle.svm.core.SubstrateOptions; |
| 85 | +import com.oracle.svm.core.SubstrateUtil; |
76 | 86 | import com.oracle.svm.core.code.CodeInfoTable; |
77 | 87 | import com.oracle.svm.core.graal.code.SubstrateBackend; |
78 | 88 | import com.oracle.svm.core.graal.meta.RuntimeConfiguration; |
|
81 | 91 | import com.oracle.svm.core.meta.SharedMethod; |
82 | 92 | import com.oracle.svm.core.meta.SubstrateObjectConstant; |
83 | 93 | import com.oracle.svm.core.snippets.ImplicitExceptions; |
| 94 | +import com.oracle.svm.core.snippets.SnippetRuntime; |
| 95 | +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; |
84 | 96 | import com.oracle.svm.core.util.VMError; |
85 | 97 |
|
86 | 98 | import jdk.vm.ci.code.CallingConvention; |
|
93 | 105 |
|
94 | 106 | public abstract class NonSnippetLowerings { |
95 | 107 |
|
| 108 | + public static final SnippetRuntime.SubstrateForeignCallDescriptor REPORT_VERIFY_TYPES_ERROR = SnippetRuntime.findForeignCall( |
| 109 | + NonSnippetLowerings.class, "reportVerifyTypesError", false, LocationIdentity.any()); |
| 110 | + |
96 | 111 | private final RuntimeConfiguration runtimeConfig; |
97 | 112 | private final Predicate<ResolvedJavaMethod> mustNotAllocatePredicate; |
98 | 113 |
|
| 114 | + final boolean verifyTypes = SubstrateOptions.VerifyTypes.getValue(); |
| 115 | + |
99 | 116 | @SuppressWarnings("unused") |
100 | 117 | protected NonSnippetLowerings(RuntimeConfiguration runtimeConfig, Predicate<ResolvedJavaMethod> mustNotAllocatePredicate, OptionValues options, Iterable<DebugHandlersFactory> factories, |
101 | 118 | Providers providers, SnippetReflectionProvider snippetReflection, Map<Class<? extends Node>, NodeLoweringProvider<?>> lowerings) { |
@@ -250,12 +267,53 @@ public void lower(FixedNode node, LoweringTool tool) { |
250 | 267 | SharedMethod method = (SharedMethod) callTarget.targetMethod(); |
251 | 268 | JavaType[] signature = method.getSignature().toParameterTypes(callTarget.isStatic() ? null : method.getDeclaringClass()); |
252 | 269 | CallingConvention.Type callType = method.getCallingConventionKind().toType(true); |
253 | | - |
254 | 270 | InvokeKind invokeKind = callTarget.invokeKind(); |
255 | 271 | SharedMethod[] implementations = method.getImplementations(); |
| 272 | + |
| 273 | + if (verifyTypes && !callTarget.isStatic() && receiver.getStackKind() == JavaKind.Object && !((SharedMethod) graph.method()).isUninterruptible()) { |
| 274 | + /* |
| 275 | + * Verify that the receiver is an instance of the class that declares the call |
| 276 | + * target method. To avoid that the new type check floats above a deoptimization |
| 277 | + * entry point, we need to anchor the receiver to the control flow. To avoid |
| 278 | + * that Graal optimizes away the InstanceOfNode immediately, we need an |
| 279 | + * OpaqueNode that removes all type information from the receiver. Then we wire |
| 280 | + * up an IfNode that leads to a ForeignCallNode in case the verification fails. |
| 281 | + */ |
| 282 | + FixedValueAnchorNode anchoredReceiver = graph.add(new FixedValueAnchorNode(receiver)); |
| 283 | + graph.addBeforeFixed(node, anchoredReceiver); |
| 284 | + ValueNode opaqueReceiver = graph.unique(new OpaqueNode(anchoredReceiver)); |
| 285 | + TypeReference declaringClass = TypeReference.createTrustedWithoutAssumptions(method.getDeclaringClass()); |
| 286 | + LogicNode instanceOf = graph.addOrUniqueWithInputs(InstanceOfNode.create(declaringClass, opaqueReceiver)); |
| 287 | + BeginNode passingBegin = graph.add(new BeginNode()); |
| 288 | + BeginNode failingBegin = graph.add(new BeginNode()); |
| 289 | + IfNode ifNode = graph.add(new IfNode(instanceOf, passingBegin, failingBegin, BranchProbabilityNode.EXTREMELY_FAST_PATH_PROFILE)); |
| 290 | + |
| 291 | + ((FixedWithNextNode) node.predecessor()).setNext(ifNode); |
| 292 | + passingBegin.setNext(node); |
| 293 | + |
| 294 | + String errorMessage; |
| 295 | + if (SubstrateUtil.HOSTED) { |
| 296 | + errorMessage = "Invoke " + invokeKind + " of " + method.format("%H.%n(%p)%r"); |
| 297 | + errorMessage += System.lineSeparator() + " declaringClass = " + declaringClass; |
| 298 | + if (implementations.length == 0 || implementations.length > 10) { |
| 299 | + errorMessage += System.lineSeparator() + " implementations.length = " + implementations.length; |
| 300 | + } else { |
| 301 | + for (int i = 0; i < implementations.length; i++) { |
| 302 | + errorMessage += System.lineSeparator() + " implementations[" + i + "] = " + implementations[i].format("%H.%n(%p)%r"); |
| 303 | + } |
| 304 | + } |
| 305 | + } else { |
| 306 | + errorMessage = "Invoke (method name not added because message must be a compile-time constant)"; |
| 307 | + } |
| 308 | + ConstantNode errorConstant = ConstantNode.forConstant(tool.getConstantReflection().forString(errorMessage), tool.getMetaAccess(), graph); |
| 309 | + ForeignCallNode reportError = graph.add(new ForeignCallNode(REPORT_VERIFY_TYPES_ERROR, opaqueReceiver, errorConstant)); |
| 310 | + reportError.setStateAfter(invoke.stateAfter().duplicateModifiedDuringCall(invoke.bci(), node.getStackKind())); |
| 311 | + failingBegin.setNext(reportError); |
| 312 | + reportError.setNext(graph.add(new LoweredDeadEndNode())); |
| 313 | + } |
| 314 | + |
256 | 315 | LoadHubNode hub = null; |
257 | 316 | CallTargetNode loweredCallTarget; |
258 | | - |
259 | 317 | if (invokeKind.isDirect() || implementations.length == 1) { |
260 | 318 | SharedMethod targetMethod = method; |
261 | 319 | if (!invokeKind.isDirect()) { |
@@ -352,4 +410,8 @@ private CallTargetNode createUnreachableCallTarget(LoweringTool tool, FixedNode |
352 | 410 | } |
353 | 411 | } |
354 | 412 |
|
| 413 | + @SubstrateForeignCallTarget(stubCallingConvention = true) |
| 414 | + private static void reportVerifyTypesError(Object object, String message) { |
| 415 | + throw VMError.shouldNotReachHere("VerifyTypes found a type error for object " + (object == null ? "null" : object.getClass().getTypeName()) + ": " + message); |
| 416 | + } |
355 | 417 | } |
0 commit comments