Skip to content

Commit 45ff915

Browse files
committed
Remove usage of NeverInlineTrivial in DynamicAccessDetectionPhase
1 parent e93e8f1 commit 45ff915

16 files changed

+262
-136
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,9 @@
9797
import com.oracle.svm.core.BuildPhaseProvider.AfterHeapLayout;
9898
import com.oracle.svm.core.BuildPhaseProvider.AfterHostedUniverse;
9999
import com.oracle.svm.core.NeverInline;
100-
import com.oracle.svm.core.NeverInlineTrivial;
101100
import com.oracle.svm.core.RuntimeAssertionsSupport;
102101
import com.oracle.svm.core.SubstrateOptions;
103102
import com.oracle.svm.core.SubstrateUtil;
104-
import com.oracle.svm.core.TrackDynamicAccessEnabled;
105103
import com.oracle.svm.core.Uninterruptible;
106104
import com.oracle.svm.core.annotate.Alias;
107105
import com.oracle.svm.core.annotate.Delete;
@@ -1789,7 +1787,6 @@ private static Constructor<?>[] copyConstructors(Constructor<?>[] original) {
17891787
private native Constructor<?> getEnclosingConstructor();
17901788

17911789
@Substitute
1792-
@NeverInlineTrivial(reason = "Used in dynamic access call usage analysis: DynamicAccessDetectionPhase", onlyWith = TrackDynamicAccessEnabled.class)
17931790
@CallerSensitive
17941791
@TargetElement(onlyWith = ClassForNameSupport.IgnoresClassLoader.class)
17951792
private static Class<?> forName(String className) throws Throwable {
@@ -1802,7 +1799,6 @@ private static Class<?> forName(String className) throws Throwable {
18021799
private static native Class<?> forNameOriginal(String className) throws ClassNotFoundException;
18031800

18041801
@Substitute
1805-
@NeverInlineTrivial(reason = "Used in dynamic access call usage analysis: DynamicAccessDetectionPhase", onlyWith = TrackDynamicAccessEnabled.class)
18061802
@CallerSensitiveAdapter
18071803
@TargetElement(onlyWith = ClassForNameSupport.IgnoresClassLoader.class)
18081804
private static Class<?> forName(String className, Class<?> caller) throws Throwable {
@@ -1815,7 +1811,6 @@ private static Class<?> forName(String className, Class<?> caller) throws Throwa
18151811
private static native Class<?> forNameOriginal(String className, Class<?> caller) throws ClassNotFoundException;
18161812

18171813
@Substitute
1818-
@NeverInlineTrivial(reason = "Used in dynamic access call usage analysis: DynamicAccessDetectionPhase", onlyWith = TrackDynamicAccessEnabled.class)
18191814
@CallerSensitive
18201815
@TargetElement(onlyWith = ClassForNameSupport.IgnoresClassLoader.class)
18211816
private static Class<?> forName(Module module, String className) throws Throwable {
@@ -1841,7 +1836,6 @@ private static Class<?> forName(@SuppressWarnings("unused") Module module, Strin
18411836
}
18421837

18431838
@Substitute
1844-
@NeverInlineTrivial(reason = "Used in dynamic access call usage analysis: DynamicAccessDetectionPhase", onlyWith = TrackDynamicAccessEnabled.class)
18451839
@CallerSensitive
18461840
@TargetElement(onlyWith = ClassForNameSupport.IgnoresClassLoader.class)
18471841
private static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws Throwable {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.hosted;
26+
27+
import com.oracle.svm.core.BuildPhaseProvider;
28+
import jdk.graal.compiler.core.common.type.StampFactory;
29+
import jdk.graal.compiler.graph.Node;
30+
import jdk.graal.compiler.graph.NodeClass;
31+
import jdk.graal.compiler.nodeinfo.NodeInfo;
32+
import jdk.graal.compiler.nodes.FixedWithNextNode;
33+
import jdk.graal.compiler.nodes.spi.Canonicalizable;
34+
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
35+
36+
/**
37+
* Base class for nodes that track reachability information during analysis. These nodes do not
38+
* affect optimizations (such as inlining) or image semantics, and are removed from the graph after
39+
* analysis.
40+
*/
41+
@NodeInfo
42+
public abstract class AbstractAnalysisMetadataTrackingNode extends FixedWithNextNode implements Canonicalizable {
43+
public static final NodeClass<AbstractAnalysisMetadataTrackingNode> TYPE = NodeClass.create(AbstractAnalysisMetadataTrackingNode.class);
44+
45+
protected AbstractAnalysisMetadataTrackingNode(NodeClass<? extends AbstractAnalysisMetadataTrackingNode> c) {
46+
super(c, StampFactory.forVoid());
47+
}
48+
49+
@Override
50+
public Node canonical(CanonicalizerTool tool) {
51+
if (BuildPhaseProvider.isAnalysisFinished()) {
52+
return null;
53+
}
54+
return this;
55+
}
56+
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DynamicAccessDetectionFeature.java

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import com.oracle.svm.hosted.phases.DynamicAccessDetectionPhase;
4141
import jdk.graal.compiler.options.OptionKey;
4242
import jdk.graal.compiler.options.OptionValues;
43-
import jdk.vm.ci.meta.ResolvedJavaMethod;
4443
import org.graalvm.collections.EconomicMap;
4544
import org.graalvm.collections.EconomicSet;
4645
import org.graalvm.nativeimage.ImageSingletons;
@@ -52,10 +51,8 @@
5251
import java.nio.file.NoSuchFileException;
5352
import java.nio.file.Path;
5453
import java.util.Arrays;
55-
import java.util.Objects;
5654
import java.util.Set;
5755
import java.util.Map;
58-
import java.util.concurrent.ConcurrentHashMap;
5956
import java.util.concurrent.ConcurrentSkipListMap;
6057
import java.util.concurrent.ConcurrentSkipListSet;
6158
import java.util.stream.Collectors;
@@ -104,15 +101,6 @@ public ConcurrentSkipListSet<String> getMethodCallLocations(String methodName) {
104101
}
105102
}
106103

107-
private static final Set<String> neverInlineTrivialMethods = Set.of(
108-
"java.lang.invoke.MethodHandles$Lookup.unreflectGetter",
109-
"java.lang.invoke.MethodHandles$Lookup.unreflectSetter",
110-
"java.io.ObjectInputStream.readObject",
111-
"java.io.ObjectStreamClass.lookup",
112-
"java.lang.reflect.Array.newInstance",
113-
"java.lang.ClassLoader.loadClass",
114-
"java.lang.foreign.Linker.nativeLinker");
115-
116104
public static final String TRACK_ALL = "all";
117105

118106
private static final String OUTPUT_DIR_NAME = "dynamic-access";
@@ -123,7 +111,6 @@ public ConcurrentSkipListSet<String> getMethodCallLocations(String methodName) {
123111
private EconomicSet<String> sourceEntries; // Class path entries and module or
124112
// package names
125113
private final Map<String, MethodsByAccessKind> callsBySourceEntry;
126-
private final Set<FoldEntry> foldEntries = ConcurrentHashMap.newKeySet();
127114
private final BuildArtifacts buildArtifacts = BuildArtifacts.singleton();
128115
private final OptionValues hostedOptionValues = HostedOptionValues.singleton();
129116

@@ -242,54 +229,6 @@ public void reportDynamicAccess() {
242229
}
243230
}
244231

245-
/**
246-
* Support data structure used to keep track of calls which don't require metadata, but can't be
247-
* folded.
248-
*/
249-
public static class FoldEntry {
250-
private final int bci;
251-
private final ResolvedJavaMethod method;
252-
253-
public FoldEntry(int bci, ResolvedJavaMethod method) {
254-
this.bci = bci;
255-
this.method = method;
256-
}
257-
258-
@Override
259-
public boolean equals(Object obj) {
260-
if (this == obj) {
261-
return true;
262-
}
263-
if (obj == null || getClass() != obj.getClass()) {
264-
return false;
265-
}
266-
FoldEntry other = (FoldEntry) obj;
267-
return bci == other.bci && Objects.equals(method, other.method);
268-
}
269-
270-
@Override
271-
public int hashCode() {
272-
return Objects.hash(bci, method);
273-
}
274-
}
275-
276-
/**
277-
* We only add fold entries for methods registered by
278-
* {@link com.oracle.svm.hosted.snippets.ReflectionPlugins#registerBulkInvocationPlugin}, as
279-
* these represent methods that cannot be folded but also do not require metadata.
280-
*/
281-
public void addFoldEntry(int bci, ResolvedJavaMethod method) {
282-
foldEntries.add(new FoldEntry(bci, method));
283-
}
284-
285-
/**
286-
* If a fold entry exists for the given method, the method should be ignored by the analysis
287-
* phase.
288-
*/
289-
public boolean containsFoldEntry(int bci, ResolvedJavaMethod method) {
290-
return foldEntries.contains(new FoldEntry(bci, method));
291-
}
292-
293232
@Override
294233
public void afterRegistration(AfterRegistrationAccess access) {
295234
ImageClassLoader imageClassLoader = ((FeatureImpl.AfterRegistrationAccessImpl) access).getImageClassLoader();
@@ -333,7 +272,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
333272
public void beforeCompilation(BeforeCompilationAccess access) {
334273
DynamicAccessDetectionFeature.instance().reportDynamicAccess();
335274
DynamicAccessDetectionSupport.instance().clear();
336-
foldEntries.clear();
337275
}
338276

339277
@Override
@@ -374,10 +312,5 @@ public static void parseDynamicAccessOptions(EconomicMap<OptionKey<?>, Object> h
374312
}
375313
}
376314
});
377-
if (!classLoaderSupport.dynamicAccessSelectorsEmpty()) {
378-
for (String method : neverInlineTrivialMethods) {
379-
SubstrateOptions.NeverInlineTrivial.update(hostedValues, method);
380-
}
381-
}
382315
}
383316
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/DynamicAccessDetectionSupport.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ public DynamicAccessDetectionSupport(AnalysisMetaAccess metaAccess) {
214214
new MethodSignature("downcallHandle", MemorySegment.class, FunctionDescriptor.class, Linker.Option[].class),
215215
new MethodSignature("downcallHandle", FunctionDescriptor.class, Linker.Option[].class),
216216
new MethodSignature("upcallStub", MethodHandle.class, FunctionDescriptor.class, Arena.class, Linker.Option[].class)));
217+
Class<?> abstractLinkerClass = ReflectionUtil.lookupClass("jdk.internal.foreign.abi.AbstractLinker");
218+
put(foreignMethods, abstractLinkerClass, Set.of(
219+
new MethodSignature("downcallHandle", MemorySegment.class, FunctionDescriptor.class, Linker.Option[].class),
220+
new MethodSignature("downcallHandle", FunctionDescriptor.class, Linker.Option[].class),
221+
new MethodSignature("upcallStub", MethodHandle.class, FunctionDescriptor.class, Arena.class, Linker.Option[].class)));
217222
}
218223

219224
private void put(EconomicMap<ResolvedJavaType, Set<ResolvedJavaMethod>> map, Class<?> declaringClass, Set<MethodSignature> methodSignatures) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.svm.hosted;
26+
27+
import jdk.graal.compiler.graph.NodeClass;
28+
import jdk.graal.compiler.graph.NodeSourcePosition;
29+
import jdk.graal.compiler.graph.spi.NodeWithIdentity;
30+
import jdk.graal.compiler.nodeinfo.NodeCycles;
31+
import jdk.graal.compiler.nodeinfo.NodeInfo;
32+
import jdk.graal.compiler.nodeinfo.NodeSize;
33+
34+
/**
35+
* Marker node used to track the original method in whose graph it was created. The
36+
* {@link com.oracle.svm.hosted.phases.DynamicAccessMarkingPhase} is responsible for assigning this
37+
* node a {@link NodeSourcePosition}, typically taken from the root position of the first non-start
38+
* node in the graph. This allows the node to be traced back to the original method during analysis,
39+
* even after graph transformations such as inlining.
40+
*/
41+
@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0)
42+
public final class InlinedCalleeTrackingNode extends AbstractAnalysisMetadataTrackingNode implements NodeWithIdentity {
43+
public static final NodeClass<InlinedCalleeTrackingNode> TYPE = NodeClass.create(InlinedCalleeTrackingNode.class);
44+
45+
public InlinedCalleeTrackingNode() {
46+
super(TYPE);
47+
}
48+
}
Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,14 @@
2525
package com.oracle.svm.hosted;
2626

2727
import com.oracle.graal.pointsto.util.AnalysisFuture;
28-
import com.oracle.svm.core.BuildPhaseProvider;
2928
import com.oracle.svm.core.ParsingReason;
3029
import com.oracle.svm.core.util.VMError;
3130

32-
import jdk.graal.compiler.core.common.type.StampFactory;
33-
import jdk.graal.compiler.graph.Node;
3431
import jdk.graal.compiler.graph.NodeClass;
3532
import jdk.graal.compiler.nodeinfo.NodeCycles;
3633
import jdk.graal.compiler.nodeinfo.NodeInfo;
3734
import jdk.graal.compiler.nodeinfo.NodeSize;
38-
import jdk.graal.compiler.nodes.FixedWithNextNode;
3935
import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin.RequiredInvocationPlugin;
40-
import jdk.graal.compiler.nodes.spi.Canonicalizable;
41-
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
4236

4337
/**
4438
* Allows a custom callback to be executed when this node is reachable.
@@ -66,30 +60,22 @@
6660
* </ol>
6761
*/
6862
@NodeInfo(cycles = NodeCycles.CYCLES_0, size = NodeSize.SIZE_0)
69-
public final class ReachabilityRegistrationNode extends FixedWithNextNode implements Canonicalizable {
70-
public static final NodeClass<ReachabilityRegistrationNode> TYPE = NodeClass.create(ReachabilityRegistrationNode.class);
63+
public final class ReachabilityCallbackNode extends AbstractAnalysisMetadataTrackingNode {
64+
public static final NodeClass<ReachabilityCallbackNode> TYPE = NodeClass.create(ReachabilityCallbackNode.class);
7165

7266
private final AnalysisFuture<Void> registrationTask;
7367

74-
protected ReachabilityRegistrationNode(Runnable registrationHandler) {
75-
super(TYPE, StampFactory.forVoid());
68+
protected ReachabilityCallbackNode(Runnable registrationHandler) {
69+
super(TYPE);
7670
this.registrationTask = new AnalysisFuture<>(registrationHandler, null);
7771
}
7872

79-
public static ReachabilityRegistrationNode create(Runnable registrationHandler, ParsingReason reason) {
73+
public static ReachabilityCallbackNode create(Runnable registrationHandler, ParsingReason reason) {
8074
VMError.guarantee(reason.duringAnalysis() && reason != ParsingReason.JITCompilation);
81-
return new ReachabilityRegistrationNode(registrationHandler);
75+
return new ReachabilityCallbackNode(registrationHandler);
8276
}
8377

8478
public AnalysisFuture<Void> getRegistrationTask() {
8579
return registrationTask;
8680
}
87-
88-
@Override
89-
public Node canonical(CanonicalizerTool tool) {
90-
if (BuildPhaseProvider.isAnalysisFinished()) {
91-
return null;
92-
}
93-
return this;
94-
}
9581
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ResourcesFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
737737
} catch (ReflectiveOperationException e) {
738738
throw VMError.shouldNotReachHere(e);
739739
}
740-
b.add(ReachabilityRegistrationNode.create(() -> RuntimeResourceAccess.addResource(clazz.getModule(), resourceName), reason));
740+
b.add(ReachabilityCallbackNode.create(() -> RuntimeResourceAccess.addResource(clazz.getModule(), resourceName), reason));
741741
if (inferenceLog != null) {
742742
inferenceLog.logRegistration(b, reason, targetMethod, clazz, new String[]{resource});
743743
}

0 commit comments

Comments
 (0)