Skip to content

Commit eeeaeea

Browse files
committed
[GR-47165] Add ParseOnceJIT support for Deopt Testing.
PullRequest: graal/14991
2 parents d1d5e14 + a30c8be commit eeeaeea

File tree

19 files changed

+602
-164
lines changed

19 files changed

+602
-164
lines changed

substratevm/mx.substratevm/suite.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@
16461646
"name" : "org.graalvm.nativeimage.base",
16471647
"exports" : [
16481648
"com.oracle.svm.util to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.llvm,org.graalvm.nativeimage.agent.jvmtibase,org.graalvm.nativeimage.agent.tracing,org.graalvm.nativeimage.agent.diagnostics,org.graalvm.nativeimage.junitsupport,com.oracle.svm.svm_enterprise,com.oracle.svm_enterprise.ml_dataset,org.graalvm.extraimage.builder,com.oracle.svm.extraimage_enterprise,org.graalvm.extraimage.librarysupport",
1649-
"com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder",
1649+
"com.oracle.svm.common.meta to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.llvm,org.graalvm.extraimage.builder",
16501650
"com.oracle.svm.common.option to org.graalvm.nativeimage.pointsto,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.driver",
16511651
],
16521652
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.concurrent.ForkJoinWorkerThread;
4242
import java.util.concurrent.atomic.AtomicLong;
4343
import java.util.concurrent.atomic.AtomicLongArray;
44+
import java.util.function.Consumer;
4445
import java.util.stream.StreamSupport;
4546

4647
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
@@ -79,6 +80,7 @@
7980
import com.oracle.graal.pointsto.util.Timer;
8081
import com.oracle.graal.pointsto.util.Timer.StopTimer;
8182
import com.oracle.graal.pointsto.util.TimerCollection;
83+
import com.oracle.svm.common.meta.MultiMethod;
8284
import com.oracle.svm.util.ClassUtil;
8385
import com.oracle.svm.util.ImageGeneratorThreadMarker;
8486

@@ -288,42 +290,50 @@ public Iterable<AnalysisType> getAllSynchronizedTypes() {
288290
}
289291

290292
@Override
291-
public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial) {
292-
return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial);
293+
public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots) {
294+
return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, otherRoots);
293295
}
294296

295297
@Override
296298
@SuppressWarnings("try")
297-
public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial) {
298-
assert aMethod.isOriginalMethod();
299+
public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots) {
299300
assert !universe.sealed() : "Cannot register root methods after analysis universe is sealed.";
301+
AnalysisError.guarantee(aMethod.isOriginalMethod());
300302
AnalysisType declaringClass = aMethod.getDeclaringClass();
301303
boolean isStatic = aMethod.isStatic();
302304
WrappedSignature signature = aMethod.getSignature();
303305
int paramCount = signature.getParameterCount(!isStatic);
304-
PointsToAnalysisMethod pointsToMethod = assertPointsToAnalysisMethod(aMethod);
306+
PointsToAnalysisMethod originalPTAMethod = assertPointsToAnalysisMethod(aMethod);
305307

306308
if (isStatic) {
307309
/*
308310
* For static methods trigger analysis in the empty context. This will trigger parsing
309311
* and return the method flows graph. Then the method parameter type flows are
310312
* initialized with the corresponding parameter declared type.
311313
*/
312-
postTask(() -> {
313-
pointsToMethod.registerAsDirectRootMethod();
314-
pointsToMethod.registerAsImplementationInvoked("root method");
315-
MethodFlowsGraphInfo flowInfo = analysisPolicy.staticRootMethodGraph(this, pointsToMethod);
316-
for (int idx = 0; idx < paramCount; idx++) {
317-
AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx, declaringClass);
318-
FormalParamTypeFlow parameter = flowInfo.getParameter(idx);
319-
if (declaredParamType.getJavaKind() == JavaKind.Object && parameter != null) {
320-
TypeFlow<?> initialParameterFlow = declaredParamType.getTypeFlow(this, true);
321-
initialParameterFlow.addUse(this, parameter);
314+
Consumer<PointsToAnalysisMethod> triggerStaticMethodFlow = (pointsToMethod) -> {
315+
postTask(() -> {
316+
pointsToMethod.registerAsDirectRootMethod();
317+
pointsToMethod.registerAsImplementationInvoked("root method");
318+
MethodFlowsGraphInfo flowInfo = analysisPolicy.staticRootMethodGraph(this, pointsToMethod);
319+
for (int idx = 0; idx < paramCount; idx++) {
320+
AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx, declaringClass);
321+
FormalParamTypeFlow parameter = flowInfo.getParameter(idx);
322+
if (declaredParamType.getJavaKind() == JavaKind.Object && parameter != null) {
323+
TypeFlow<?> initialParameterFlow = declaredParamType.getTypeFlow(this, true);
324+
initialParameterFlow.addUse(this, parameter);
325+
}
322326
}
323-
}
324-
});
327+
});
328+
};
329+
triggerStaticMethodFlow.accept(originalPTAMethod);
330+
for (MultiMethod.MultiMethodKey key : otherRoots) {
331+
assert key != MultiMethod.ORIGINAL_METHOD;
332+
PointsToAnalysisMethod ptaMethod = assertPointsToAnalysisMethod(originalPTAMethod.getMultiMethod(key));
333+
triggerStaticMethodFlow.accept(ptaMethod);
334+
}
325335
} else {
326-
if (invokeSpecial && pointsToMethod.isAbstract()) {
336+
if (invokeSpecial && originalPTAMethod.isAbstract()) {
327337
throw AnalysisError.userError("Abstract methods cannot be registered as special invoke entry point.");
328338
}
329339
/*
@@ -340,14 +350,20 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia
340350
* corresponding declared type state. When a callee is resolved the method is parsed and
341351
* the actual parameter type state is propagated to the formal parameters. Then the
342352
* callee is linked and registered as implementation-invoked.
353+
*
354+
* Note for virtual and special methods no action is needed when there are otherRoots.
355+
* This is due to two factors: First, the callee methods are only resolved once types
356+
* flow into the context insensitive invoke typeflow. Second, otherRoots is only
357+
* (currently) used for runtime compilation; in this use case, all necessary linking
358+
* will be done during callee resolution.
343359
*/
344360
postTask(() -> {
345361
if (invokeSpecial) {
346-
pointsToMethod.registerAsDirectRootMethod();
362+
originalPTAMethod.registerAsDirectRootMethod();
347363
} else {
348-
pointsToMethod.registerAsVirtualRootMethod();
364+
originalPTAMethod.registerAsVirtualRootMethod();
349365
}
350-
InvokeTypeFlow invoke = pointsToMethod.initAndGetContextInsensitiveInvoke(PointsToAnalysis.this, null, invokeSpecial, pointsToMethod.getMultiMethodKey());
366+
InvokeTypeFlow invoke = originalPTAMethod.initAndGetContextInsensitiveInvoke(PointsToAnalysis.this, null, invokeSpecial, MultiMethod.ORIGINAL_METHOD);
351367
/*
352368
* Initialize the type flow of the invoke's actual parameters with the corresponding
353369
* parameter declared type. Thus, when the invoke links callees it will propagate

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ReachabilityAnalysis.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.oracle.graal.pointsto.meta.AnalysisMethod;
3232
import com.oracle.graal.pointsto.meta.AnalysisType;
3333
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
34+
import com.oracle.svm.common.meta.MultiMethod;
3435
import com.oracle.svm.util.UnsafePartitionKind;
3536

3637
/**
@@ -58,7 +59,7 @@ public interface ReachabilityAnalysis {
5859
AnalysisType addRootField(Class<?> clazz, String fieldName);
5960

6061
/**
61-
* Registers the method as root.
62+
* Registers the method as root. Must be an {@link MultiMethod#ORIGINAL_METHOD}.
6263
*
6364
* Static methods are immediately analyzed and marked as implementation-invoked which will also
6465
* trigger their compilation.
@@ -70,16 +71,21 @@ public interface ReachabilityAnalysis {
7071
* is instantiated will actually be linked. Trying to register an abstract method as a special
7172
* invoked root will result in an error.
7273
*
74+
* If {@code otherRoots} are specified, these versions of the method will also be registered as
75+
* root methods.
76+
*
7377
* @param aMethod the method to register as root
7478
* @param invokeSpecial if true only the target method is analyzed, even if it has overrides, or
7579
* it is itself an override. If the method is static this flag is ignored.
80+
* @param otherRoots other versions of this method to also register as roots.
7681
*/
77-
AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial);
82+
AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots);
7883

7984
/**
80-
* @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean)
85+
* @see ReachabilityAnalysis#addRootMethod(AnalysisMethod, boolean,
86+
* MultiMethod.MultiMethodKey...)
8187
*/
82-
AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial);
88+
AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots);
8389

8490
default void registerAsFrozenUnsafeAccessed(AnalysisField field) {
8591
field.setUnsafeFrozenTypeState(true);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,14 @@ public Function<AnalysisType, ResolvedJavaType> getStrengthenGraphsToTargetFunct
388388
return (t) -> t;
389389
}
390390

391+
public boolean allowConstantFolding(AnalysisMethod method) {
392+
/*
393+
* Currently constant folding is only enabled for original methods. More work is needed to
394+
* support it within deoptimization targets and runtime-compiled methods.
395+
*/
396+
return method.isOriginalMethod();
397+
}
398+
391399
public FieldValueComputer createFieldValueComputer(@SuppressWarnings("unused") AnalysisField field) {
392400
return null;
393401
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/PointsToAnalysisMethod.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,11 @@ public boolean isImplementationInvokable() {
242242
} else {
243243
/*
244244
* If only a stub is ever created for this method, then it will not be invoked.
245+
*
246+
* However, for deopt targets it is possible for a root to temporarily be a stub before
247+
* a full flow graph is created.
245248
*/
246-
return !getTypeFlow().getMethodFlowsGraphInfo().isStub();
249+
return !getTypeFlow().getMethodFlowsGraphInfo().isStub() || (isDirectRootMethod() && isDeoptTarget());
247250
}
248251
}
249252

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/StrengthenGraphs.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,7 @@ class StrengthenSimplifier implements CustomSimplification {
296296
nodeFlows.put(node, cursor.getValue());
297297
}
298298

299-
/*
300-
* Currently constant folding is only enabled for original methods. More work is needed
301-
* to support it within deoptimization targets and runtime-compiled methods.
302-
*/
303-
this.allowConstantFolding = method.isOriginalMethod() && strengthenGraphWithConstants;
299+
this.allowConstantFolding = strengthenGraphWithConstants && bb.getHostVM().allowConstantFolding(method);
304300

305301
/*
306302
* In deoptimization target methods optimizing the return parameter can make new values

substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/ReachabilityAnalysisEngine.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.oracle.graal.pointsto.util.CompletionExecutor;
5252
import com.oracle.graal.pointsto.util.Timer;
5353
import com.oracle.graal.pointsto.util.TimerCollection;
54+
import com.oracle.svm.common.meta.MultiMethod;
5455

5556
import jdk.vm.ci.code.BytecodePosition;
5657
import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -106,8 +107,8 @@ public AnalysisType addRootClass(Class<?> clazz, boolean addFields, boolean addA
106107
}
107108

108109
@Override
109-
public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial) {
110-
return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial);
110+
public AnalysisMethod addRootMethod(Executable method, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots) {
111+
return addRootMethod(metaAccess.lookupJavaMethod(method), invokeSpecial, otherRoots);
111112
}
112113

113114
@SuppressWarnings("try")
@@ -145,7 +146,8 @@ public AnalysisType addRootField(Class<?> clazz, String fieldName) {
145146
}
146147

147148
@Override
148-
public AnalysisMethod addRootMethod(AnalysisMethod m, boolean invokeSpecial) {
149+
public AnalysisMethod addRootMethod(AnalysisMethod m, boolean invokeSpecial, MultiMethod.MultiMethodKey... otherRoots) {
150+
assert otherRoots.length == 0;
149151
ReachabilityAnalysisMethod method = (ReachabilityAnalysisMethod) m;
150152
if (m.isStatic()) {
151153
postTask(() -> {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/nodes/TestDeoptimizeNode.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import com.oracle.svm.common.meta.MultiMethod;
3939
import com.oracle.svm.core.SubstrateOptions;
4040
import com.oracle.svm.core.meta.SharedMethod;
41-
import com.oracle.svm.core.util.VMError;
4241

4342
import jdk.vm.ci.meta.DeoptimizationAction;
4443
import jdk.vm.ci.meta.DeoptimizationReason;
@@ -61,7 +60,13 @@ public Node canonical(CanonicalizerTool tool) {
6160
ResolvedJavaMethod method = graph().method();
6261

6362
if (SubstrateOptions.parseOnce()) {
64-
throw VMError.unimplemented("Deopt Testing does not yet work.");
63+
if (MultiMethod.isDeoptTarget(method)) {
64+
/* no-op for deoptimization target methods. */
65+
return null;
66+
} else {
67+
/* deoptimization for all other methods. */
68+
return new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter);
69+
}
6570
} else {
6671
if (method instanceof SharedMethod) {
6772
if (MultiMethod.isDeoptTarget(method)) {

0 commit comments

Comments
 (0)