Skip to content

Commit 24a60fe

Browse files
committed
[GR-41279] Track AnalysisMethod invoke reason.
PullRequest: graal/13279
2 parents fb291f7 + 9b1cf6c commit 24a60fe

File tree

15 files changed

+111
-81
lines changed

15 files changed

+111
-81
lines changed

substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandalonePointsToAnalysis.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public void initializeMetaData(AnalysisType type) {
7070
public void onTypeInitialized(AnalysisType type) {
7171
AnalysisMethod clinitMethod = type.getClassInitializer();
7272
if (clinitMethod != null && !addedClinits.contains(clinitMethod)) {
73-
addRootMethod(clinitMethod, true).registerAsImplementationInvoked();
73+
addRootMethod(clinitMethod, true).registerAsImplementationInvoked(type);
7474
addedClinits.add(clinitMethod);
7575
}
7676
}

substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/features/StandaloneAnalysisFeatureImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,11 @@ public void registerAsUnsafeAccessed(AnalysisField aField, UnsafePartitionKind p
241241
}
242242

243243
public void registerAsInvoked(Executable method, boolean invokeSpecial) {
244-
registerAsInvoked(getMetaAccess().lookupJavaMethod(method), invokeSpecial);
244+
registerAsInvoked(getMetaAccess().lookupJavaMethod(method), invokeSpecial, "registered from standalone feature");
245245
}
246246

247-
public void registerAsInvoked(AnalysisMethod aMethod, boolean invokeSpecial) {
248-
bb.addRootMethod(aMethod, invokeSpecial).registerAsImplementationInvoked();
247+
public void registerAsInvoked(AnalysisMethod aMethod, boolean invokeSpecial, Object reason) {
248+
bb.addRootMethod(aMethod, invokeSpecial).registerAsImplementationInvoked(reason);
249249
}
250250

251251
public void registerUnsafeFieldsRecomputed(Class<?> clazz) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia
313313
*/
314314
postTask(() -> {
315315
pointsToMethod.registerAsDirectRootMethod();
316-
pointsToMethod.registerAsImplementationInvoked(null);
316+
pointsToMethod.registerAsImplementationInvoked("root method");
317317
MethodFlowsGraph methodFlowsGraph = analysisPolicy.staticRootMethodGraph(this, pointsToMethod);
318318
for (int idx = 0; idx < paramCount; idx++) {
319319
AnalysisType declaredParamType = (AnalysisType) signature.getParameterType(idx, declaringClass);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/CallSiteSensitiveMethodTypeFlow.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ public CallSiteSensitiveMethodTypeFlow(OptionValues options, PointsToAnalysisMet
5353
/**
5454
* Add the context, if not already added, and return the method flows clone from that context.
5555
*/
56-
public MethodFlowsGraph addContext(PointsToAnalysis bb, AnalysisContext calleeContext) {
57-
return addContext(bb, calleeContext, null);
58-
}
59-
6056
public MethodFlowsGraph addContext(PointsToAnalysis bb, AnalysisContext calleeContext, InvokeTypeFlow reason) {
6157

6258
/* Ensure that the method is parsed before attempting to clone it. */

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ private synchronized void createFlowsGraph(PointsToAnalysis bb, InvokeTypeFlow r
9494
parsingReason = reason;
9595
try {
9696
MethodTypeFlowBuilder builder = bb.createMethodTypeFlowBuilder(bb, method);
97-
builder.apply();
97+
builder.apply(PointsToAnalysisMethod.unwrapInvokeReason(parsingReason));
9898

9999
returnedParameterIndex = computeReturnedParameterIndex(builder.graph);
100100
bb.numParsedGraphs.incrementAndGet();

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,10 @@ public MethodTypeFlowBuilder(PointsToAnalysis bb, StructuredGraph graph) {
179179
}
180180

181181
@SuppressWarnings("try")
182-
private boolean parse() {
182+
private boolean parse(Object reason) {
183183
AnalysisParsedGraph analysisParsedGraph = method.ensureGraphParsed(bb);
184184
if (analysisParsedGraph.isIntrinsic()) {
185-
method.registerAsIntrinsicMethod();
185+
method.registerAsIntrinsicMethod(reason);
186186
}
187187

188188
if (analysisParsedGraph.getEncodedGraph() == null) {
@@ -394,7 +394,7 @@ private static void registerForeignCall(PointsToAnalysis bb, ForeignCallDescript
394394
targetMethod.ifPresent(analysisMethod -> bb.addRootMethod(analysisMethod, true));
395395
}
396396

397-
protected void apply() {
397+
protected void apply(Object reason) {
398398
// assert method.getAnnotation(Fold.class) == null : method;
399399
if (AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class)) {
400400
graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method);
@@ -417,7 +417,7 @@ protected void apply() {
417417
return;
418418
}
419419

420-
if (!parse()) {
420+
if (!parse(reason)) {
421421
return;
422422
}
423423

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/context/bytecode/BytecodeSensitiveAnalysisPolicy.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ public AbstractStaticInvokeTypeFlow createStaticInvokeTypeFlow(BytecodePosition
338338

339339
@Override
340340
public MethodFlowsGraph staticRootMethodGraph(PointsToAnalysis bb, PointsToAnalysisMethod pointsToMethod) {
341-
return ((CallSiteSensitiveMethodTypeFlow) pointsToMethod.getTypeFlow()).addContext(bb, contextPolicy.emptyContext());
341+
return ((CallSiteSensitiveMethodTypeFlow) pointsToMethod.getTypeFlow()).addContext(bb, contextPolicy.emptyContext(), null);
342342
}
343343

344344
@Override

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

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.Set;
3737
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
3838
import java.util.concurrent.atomic.AtomicReference;
39+
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3940
import java.util.concurrent.locks.ReentrantLock;
4041
import java.util.stream.Collectors;
4142

@@ -80,17 +81,17 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
8081
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isDirectRootMethodUpdater = AtomicIntegerFieldUpdater
8182
.newUpdater(AnalysisMethod.class, "isDirectRootMethod");
8283

83-
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isInvokedUpdater = AtomicIntegerFieldUpdater
84-
.newUpdater(AnalysisMethod.class, "isInvoked");
84+
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isInvokedUpdater = AtomicReferenceFieldUpdater
85+
.newUpdater(AnalysisMethod.class, Object.class, "isInvoked");
8586

86-
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isImplementationInvokedUpdater = AtomicIntegerFieldUpdater
87-
.newUpdater(AnalysisMethod.class, "isImplementationInvoked");
87+
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isImplementationInvokedUpdater = AtomicReferenceFieldUpdater
88+
.newUpdater(AnalysisMethod.class, Object.class, "isImplementationInvoked");
8889

89-
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isIntrinsicMethodUpdater = AtomicIntegerFieldUpdater
90-
.newUpdater(AnalysisMethod.class, "isIntrinsicMethod");
90+
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isIntrinsicMethodUpdater = AtomicReferenceFieldUpdater
91+
.newUpdater(AnalysisMethod.class, Object.class, "isIntrinsicMethod");
9192

92-
private static final AtomicIntegerFieldUpdater<AnalysisMethod> isInlinedUpdater = AtomicIntegerFieldUpdater
93-
.newUpdater(AnalysisMethod.class, "isInlined");
93+
private static final AtomicReferenceFieldUpdater<AnalysisMethod, Object> isInlinedUpdater = AtomicReferenceFieldUpdater
94+
.newUpdater(AnalysisMethod.class, Object.class, "isInlined");
9495

9596
public final ResolvedJavaMethod wrapped;
9697

@@ -108,10 +109,10 @@ public abstract class AnalysisMethod extends AnalysisElement implements WrappedJ
108109
/** Direct (special or static) invoked method registered as root. */
109110
@SuppressWarnings("unused") private volatile int isDirectRootMethod;
110111
private Object entryPointData;
111-
@SuppressWarnings("unused") private volatile int isInvoked;
112-
@SuppressWarnings("unused") private volatile int isImplementationInvoked;
113-
@SuppressWarnings("unused") private volatile int isIntrinsicMethod;
114-
@SuppressWarnings("unused") private volatile int isInlined;
112+
@SuppressWarnings("unused") private volatile Object isInvoked;
113+
@SuppressWarnings("unused") private volatile Object isImplementationInvoked;
114+
@SuppressWarnings("unused") private volatile Object isIntrinsicMethod;
115+
@SuppressWarnings("unused") private volatile Object isInlined;
115116

116117
private final AtomicReference<Object> parsedGraphCacheState = new AtomicReference<>(GRAPH_CACHE_UNPARSED);
117118
private static final Object GRAPH_CACHE_UNPARSED = "unparsed";
@@ -260,8 +261,9 @@ public int getId() {
260261
* builder plugin}. Such a method is treated similar to an invoked method. For example, method
261262
* resolution must be able to find the method (otherwise the intrinsification would not work).
262263
*/
263-
public void registerAsIntrinsicMethod() {
264-
AtomicUtils.atomicMarkAndRun(this, isIntrinsicMethodUpdater, this::onReachable);
264+
public void registerAsIntrinsicMethod(Object reason) {
265+
assert isValidReason(reason) : "Registering a method as intrinsic needs to provide a valid reason, found: " + reason;
266+
AtomicUtils.atomicSetAndRun(this, reason, isIntrinsicMethodUpdater, this::onReachable);
265267
}
266268

267269
public void registerAsEntryPoint(Object newEntryPointData) {
@@ -274,11 +276,13 @@ public void registerAsEntryPoint(Object newEntryPointData) {
274276
startTrackInvocations();
275277
}
276278

277-
public boolean registerAsInvoked() {
278-
return AtomicUtils.atomicMark(this, isInvokedUpdater);
279+
public boolean registerAsInvoked(Object reason) {
280+
assert isValidReason(reason) : "Registering a method as invoked needs to provide a valid reason, found: " + reason;
281+
return AtomicUtils.atomicSet(this, reason, isInvokedUpdater);
279282
}
280283

281-
public boolean registerAsImplementationInvoked() {
284+
public boolean registerAsImplementationInvoked(Object reason) {
285+
assert isValidReason(reason) : "Registering a method as implementation invoked needs to provide a valid reason, found: " + reason;
282286
assert !Modifier.isAbstract(getModifiers());
283287

284288
/*
@@ -290,11 +294,12 @@ public boolean registerAsImplementationInvoked() {
290294
* return before the class gets marked as reachable.
291295
*/
292296
getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as implementation invoked");
293-
return AtomicUtils.atomicMarkAndRun(this, isImplementationInvokedUpdater, this::onReachable);
297+
return AtomicUtils.atomicSetAndRun(this, reason, isImplementationInvokedUpdater, this::onReachable);
294298
}
295299

296-
public void registerAsInlined() {
297-
AtomicUtils.atomicMarkAndRun(this, isInlinedUpdater, this::onReachable);
300+
public void registerAsInlined(Object reason) {
301+
assert isValidReason(reason) : "Registering a method as inlined needs to provide a valid reason, found: " + reason;
302+
AtomicUtils.atomicSetAndRun(this, reason, isInlinedUpdater, this::onReachable);
298303
}
299304

300305
/** Get the set of all callers for this method, as inferred by the static analysis. */
@@ -324,7 +329,7 @@ public boolean isIntrinsicMethod() {
324329
* as invoked also makes the declaring class reachable.
325330
*
326331
* Class is always marked as reachable regardless of the success of the atomic mark, same reason
327-
* as in {@link AnalysisMethod#registerAsImplementationInvoked()}.
332+
* as in {@link AnalysisMethod#registerAsImplementationInvoked(Object)}.
328333
*/
329334
public boolean registerAsVirtualRootMethod() {
330335
getDeclaringClass().registerAsReachable("declared method " + this.format("%H.%n(%p)") + " is registered as virtual root");

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

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
import java.util.ArrayList;
2828
import java.util.List;
29+
import java.util.Set;
2930
import java.util.concurrent.ConcurrentHashMap;
30-
import java.util.concurrent.ConcurrentMap;
3131
import java.util.concurrent.atomic.AtomicReference;
3232

3333
import com.oracle.graal.pointsto.PointsToAnalysis;
@@ -48,8 +48,8 @@
4848
public class PointsToAnalysisMethod extends AnalysisMethod {
4949
private MethodTypeFlow typeFlow;
5050

51-
private ConcurrentMap<InvokeTypeFlow, Object> invokedBy;
52-
private ConcurrentMap<InvokeTypeFlow, Object> implementationInvokedBy;
51+
private Set<InvokeTypeFlow> invokedBy;
52+
private Set<InvokeTypeFlow> implementationInvokedBy;
5353
/**
5454
* Unique, per method, context insensitive invoke. The context insensitive invoke uses the
5555
* receiver type of the method, i.e., its declaring-class. Therefore, this invoke will link with
@@ -66,35 +66,55 @@ public class PointsToAnalysisMethod extends AnalysisMethod {
6666
@Override
6767
public void startTrackInvocations() {
6868
if (invokedBy == null) {
69-
invokedBy = new ConcurrentHashMap<>();
69+
invokedBy = ConcurrentHashMap.newKeySet();
7070
}
7171
if (implementationInvokedBy == null) {
72-
implementationInvokedBy = new ConcurrentHashMap<>();
72+
implementationInvokedBy = ConcurrentHashMap.newKeySet();
7373
}
7474
}
7575

7676
public MethodTypeFlow getTypeFlow() {
7777
return typeFlow;
7878
}
7979

80-
public boolean registerAsInvoked(InvokeTypeFlow invoke) {
81-
if (invokedBy != null && invoke != null) {
82-
invokedBy.put(invoke, Boolean.TRUE);
80+
@Override
81+
public boolean registerAsInvoked(Object reason) {
82+
assert reason instanceof InvokeTypeFlow || reason instanceof String;
83+
if (invokedBy != null && reason instanceof InvokeTypeFlow) {
84+
invokedBy.add((InvokeTypeFlow) reason);
85+
}
86+
return super.registerAsInvoked(unwrapInvokeReason(reason));
87+
}
88+
89+
@Override
90+
public boolean registerAsImplementationInvoked(Object reason) {
91+
assert reason instanceof InvokeTypeFlow || reason instanceof String;
92+
if (implementationInvokedBy != null && reason instanceof InvokeTypeFlow) {
93+
implementationInvokedBy.add((InvokeTypeFlow) reason);
8394
}
84-
return super.registerAsInvoked();
95+
return super.registerAsImplementationInvoked(unwrapInvokeReason(reason));
8596
}
8697

87-
public boolean registerAsImplementationInvoked(InvokeTypeFlow invoke) {
88-
if (implementationInvokedBy != null && invoke != null) {
89-
implementationInvokedBy.put(invoke, Boolean.TRUE);
98+
/**
99+
* In general the reason for a method invocation is an {@link InvokeTypeFlow}. Special and
100+
* virtual root methods have the corresponding context-insensitive invoke reason set. Static
101+
* root method doesn't have any reason set.
102+
*/
103+
public static Object unwrapInvokeReason(Object reason) {
104+
if (reason == null) {
105+
return "static root method";
106+
}
107+
if (reason instanceof InvokeTypeFlow) {
108+
BytecodePosition source = ((InvokeTypeFlow) reason).getSource();
109+
return source != null ? source : "root method";
90110
}
91-
return super.registerAsImplementationInvoked();
111+
return reason;
92112
}
93113

94114
@Override
95115
public List<BytecodePosition> getInvokeLocations() {
96116
List<BytecodePosition> locations = new ArrayList<>();
97-
for (InvokeTypeFlow invoke : implementationInvokedBy.keySet()) {
117+
for (InvokeTypeFlow invoke : implementationInvokedBy) {
98118
if (InvokeTypeFlow.isContextInsensitiveVirtualInvoke(invoke)) {
99119
locations.addAll(((AbstractVirtualInvokeTypeFlow) invoke).getInvokeLocations());
100120
} else if (invoke.getSource() != null) {

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/phases/InlineBeforeAnalysis.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import java.util.Deque;
2929
import java.util.concurrent.ConcurrentHashMap;
3030

31-
import com.oracle.graal.pointsto.BigBang;
3231
import org.graalvm.compiler.bytecode.BytecodeProvider;
3332
import org.graalvm.compiler.debug.DebugContext;
3433
import org.graalvm.compiler.debug.GraalError;
@@ -52,6 +51,7 @@
5251
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
5352
import org.graalvm.compiler.replacements.PEGraphDecoder;
5453

54+
import com.oracle.graal.pointsto.BigBang;
5555
import com.oracle.graal.pointsto.flow.AnalysisParsedGraph;
5656
import com.oracle.graal.pointsto.meta.AnalysisMethod;
5757
import com.oracle.svm.util.ClassUtil;
@@ -278,7 +278,9 @@ protected void finishInlining(MethodScope is) {
278278
if (callerScope.policyScope != null) {
279279
policy.commitCalleeScope(callerScope.policyScope, inlineScope.policyScope);
280280
}
281-
((AnalysisMethod) invokeData.callTarget.targetMethod()).registerAsInlined();
281+
Object reason = graph.currentNodeSourcePosition() != null ? graph.currentNodeSourcePosition() : graph.method();
282+
283+
((AnalysisMethod) invokeData.callTarget.targetMethod()).registerAsInlined(reason);
282284

283285
super.finishInlining(inlineScope);
284286
}

0 commit comments

Comments
 (0)