Skip to content

Commit 9ffe380

Browse files
committed
Add special loading for PolymorphicSignature methods
1 parent 3d54364 commit 9ffe380

File tree

7 files changed

+216
-13
lines changed

7 files changed

+216
-13
lines changed

compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/replacements/MethodHandlePlugin.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ protected MacroInvokable createMethodHandleNode(GraphBuilderContext b, ResolvedJ
6565
return new MethodHandleNode(intrinsicMethod, MacroNode.MacroParams.of(invokeKind, b.getMethod(), method, b.bci(), invokeReturnStamp, args));
6666
}
6767

68+
/**
69+
* Hook to add custom code on creation of MethodHandleNodes.
70+
*/
71+
@SuppressWarnings("unused")
72+
protected void onCreateHook(MacroInvokable methodHandleNode, GraphBuilderContext b) {
73+
/* Nothing to do here */
74+
}
75+
6876
@Override
6977
public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
7078
IntrinsicMethod intrinsicMethod = methodHandleAccess.lookupMethodHandleIntrinsic(method);
@@ -87,6 +95,7 @@ public <T extends ValueNode> T add(T node) {
8795
Invoke invoke = MethodHandleNode.tryResolveTargetInvoke(adder, this::createInvoke, methodHandleAccess, intrinsicMethod, method, b.bci(), invokeReturnStamp, args);
8896
if (invoke == null) {
8997
MacroInvokable methodHandleNode = createMethodHandleNode(b, method, args, intrinsicMethod, invokeKind, invokeReturnStamp);
98+
onCreateHook(methodHandleNode, b);
9099
if (invokeReturnStamp.getTrustedStamp().getStackKind() == JavaKind.Void) {
91100
b.add(methodHandleNode.asNode());
92101
} else {

substratevm/src/com.oracle.svm.hosted/resources/SharedLayerSnapshotCapnProtoSchema.capnp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ struct PersistedAnalysisMethod {
113113
declaringClassName @36 :Text;
114114
argumentTypeNames @37 :List(Text);
115115
}
116+
polymorphicSignature :group {
117+
callers @38 :List(MethodId);
118+
}
116119
}
117120
}
118121

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
import com.oracle.svm.hosted.meta.HostedSnippetReflectionProvider;
237237
import com.oracle.svm.hosted.meta.HostedUniverse;
238238
import com.oracle.svm.hosted.meta.UniverseBuilder;
239+
import com.oracle.svm.hosted.methodhandles.SVMMethodHandleWithExceptionPlugin;
239240
import com.oracle.svm.hosted.option.HostedOptionProvider;
240241
import com.oracle.svm.hosted.phases.CInterfaceInvocationPlugin;
241242
import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin;
@@ -304,7 +305,6 @@
304305
import jdk.graal.compiler.phases.tiers.Suites;
305306
import jdk.graal.compiler.phases.util.Providers;
306307
import jdk.graal.compiler.printer.GraalDebugHandlersFactory;
307-
import jdk.graal.compiler.replacements.MethodHandleWithExceptionPlugin;
308308
import jdk.graal.compiler.replacements.NodeIntrinsificationProvider;
309309
import jdk.graal.compiler.replacements.TargetGraphBuilderPlugins;
310310
import jdk.graal.compiler.word.WordOperationPlugin;
@@ -1371,7 +1371,7 @@ public static void registerGraphBuilderPlugins(FeatureHandler featureHandler, Ru
13711371
plugins.appendInlineInvokePlugin(replacements);
13721372

13731373
if (reason.duringAnalysis()) {
1374-
plugins.appendNodePlugin(new MethodHandleWithExceptionPlugin(providers.getConstantReflection().getMethodHandleAccess(), false));
1374+
plugins.appendNodePlugin(new SVMMethodHandleWithExceptionPlugin(providers.getConstantReflection().getMethodHandleAccess(), false));
13751375
}
13761376
plugins.appendNodePlugin(new DeletedFieldsPlugin());
13771377
plugins.appendNodePlugin(new InjectedAccessorsPlugin());

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,14 @@
127127
import jdk.graal.compiler.core.common.NumUtil;
128128
import jdk.graal.compiler.core.common.SuppressFBWarnings;
129129
import jdk.graal.compiler.debug.GraalError;
130+
import jdk.graal.compiler.graph.Node;
130131
import jdk.graal.compiler.graph.iterators.NodeIterable;
131132
import jdk.graal.compiler.java.BytecodeParser;
132133
import jdk.graal.compiler.nodes.ConstantNode;
133134
import jdk.graal.compiler.nodes.EncodedGraph;
134135
import jdk.graal.compiler.nodes.StructuredGraph;
135136
import jdk.graal.compiler.options.OptionValues;
137+
import jdk.graal.compiler.replacements.nodes.MethodHandleNode;
136138
import jdk.graal.compiler.util.ObjectCopier;
137139
import jdk.internal.reflect.ReflectionFactory;
138140
import jdk.vm.ci.meta.JavaConstant;
@@ -171,6 +173,7 @@ public class SVMImageLayerLoader extends ImageLayerLoader {
171173
protected final Map<Integer, Long> objectOffsets = new ConcurrentHashMap<>();
172174
protected final Map<AnalysisField, Integer> fieldLocations = new ConcurrentHashMap<>();
173175
private final Map<Class<?>, Boolean> capturingClasses = new ConcurrentHashMap<>();
176+
private final Map<ResolvedJavaMethod, Boolean> methodHandleCallers = new ConcurrentHashMap<>();
174177

175178
/** Map from {@link SVMImageLayerSnapshotUtil#getTypeDescriptor} to base layer type ids. */
176179
private final Map<String, Integer> typeDescriptorToBaseLayerId = new HashMap<>();
@@ -399,6 +402,7 @@ protected boolean delegateLoadType(PersistedAnalysisType.Reader typeData) {
399402
String capturingClassName = wrappedType.getLambda().getCapturingClass().toString();
400403
Class<?> capturingClass = imageLayerBuildingSupport.lookupClass(false, capturingClassName);
401404
loadLambdaTypes(capturingClass);
405+
return types.containsKey(typeData.getId());
402406
} else if (wrappedType.isProxyType()) {
403407
Class<?>[] interfaces = Stream.of(typeData.getInterfaces()).flatMapToInt(r -> IntStream.range(0, r.size()).map(r::get))
404408
.mapToObj(i -> getAnalysisTypeForBaseLayerId(i).getJavaClass()).toArray(Class<?>[]::new);
@@ -425,23 +429,46 @@ private void loadLambdaTypes(Class<?> capturingClass) {
425429
}
426430

427431
private static void loadLambdaTypes(ResolvedJavaMethod m, BigBang bigBang) {
432+
StructuredGraph graph = getMethodGraph(m, bigBang);
433+
if (graph != null) {
434+
NodeIterable<ConstantNode> constantNodes = ConstantNode.getConstantNodes(graph);
435+
436+
for (ConstantNode cNode : constantNodes) {
437+
Class<?> lambdaClass = getLambdaClassFromConstantNode(cNode);
438+
439+
if (lambdaClass != null) {
440+
bigBang.getMetaAccess().lookupJavaType(lambdaClass);
441+
}
442+
}
443+
}
444+
}
445+
446+
private void loadMethodHandleTargets(ResolvedJavaMethod m, BigBang bigBang) {
447+
methodHandleCallers.computeIfAbsent(m, method -> {
448+
StructuredGraph graph = getMethodGraph(m, bigBang);
449+
if (graph != null) {
450+
for (Node node : graph.getNodes()) {
451+
if (node instanceof MethodHandleNode methodHandleNode) {
452+
bigBang.getUniverse().lookup(methodHandleNode.getTargetMethod());
453+
}
454+
}
455+
}
456+
return true;
457+
});
458+
}
459+
460+
private static StructuredGraph getMethodGraph(ResolvedJavaMethod m, BigBang bigBang) {
461+
if (m instanceof BaseLayerMethod) {
462+
return null;
463+
}
428464
StructuredGraph graph;
429465
try {
430466
graph = createMethodGraph(m, bigBang.getOptions());
431467
} catch (NoClassDefFoundError | BytecodeParser.BytecodeParserError e) {
432468
/* Skip the method if it refers to a missing class */
433-
return;
434-
}
435-
436-
NodeIterable<ConstantNode> constantNodes = ConstantNode.getConstantNodes(graph);
437-
438-
for (ConstantNode cNode : constantNodes) {
439-
Class<?> lambdaClass = getLambdaClassFromConstantNode(cNode);
440-
441-
if (lambdaClass != null) {
442-
bigBang.getMetaAccess().lookupJavaType(lambdaClass);
443-
}
469+
return null;
444470
}
471+
return graph;
445472
}
446473

447474
private ResolvedJavaType getResolvedJavaTypeForBaseLayerId(int tid) {
@@ -735,6 +762,18 @@ protected boolean delegateLoadMethod(PersistedAnalysisMethod.Reader methodData)
735762
JNIAccessFeature.singleton().addMethod(member, (FeatureImpl.DuringAnalysisAccessImpl) universe.getConcurrentAnalysisAccess());
736763
}
737764
return true;
765+
} else if (wrappedMethod.isPolymorphicSignature()) {
766+
int id = methodData.getId();
767+
WrappedMethod.PolymorphicSignature.Reader ps = wrappedMethod.getPolymorphicSignature();
768+
var callers = ps.getCallers();
769+
for (int i = 0; i < callers.size(); ++i) {
770+
loadMethodHandleTargets(getAnalysisMethodForBaseLayerId(callers.get(i)).wrapped, universe.getBigbang());
771+
if (methods.containsKey(id)) {
772+
return true;
773+
}
774+
}
775+
LogUtils.warning("The PolymorphicSignature method %s.%s could not get loaded", methodData.getClassName().toString(), methodData.getName().toString());
776+
return false;
738777
}
739778
return false;
740779
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@
151151
import com.oracle.svm.hosted.reflect.ReflectionExpandSignatureMethod;
152152
import com.oracle.svm.hosted.reflect.proxy.ProxyRenamingSubstitutionProcessor;
153153
import com.oracle.svm.hosted.reflect.proxy.ProxySubstitutionType;
154+
import com.oracle.svm.hosted.substitute.PolymorphicSignatureWrapperMethod;
155+
import com.oracle.svm.hosted.substitute.SubstitutionMethod;
154156
import com.oracle.svm.util.FileDumpingUtil;
155157
import com.oracle.svm.util.LogUtils;
156158
import com.oracle.svm.util.ModuleSupport;
@@ -181,6 +183,7 @@ public class SVMImageLayerWriter extends ImageLayerWriter {
181183
private Map<ImageHeapConstant, ConstantParent> constantsMap;
182184
private final Map<String, MethodGraphsInfo> methodsMap = new ConcurrentHashMap<>();
183185
private final Map<InitialLayerOnlyImageSingleton, Integer> initialLayerOnlySingletonMap = new ConcurrentHashMap<>();
186+
private final Map<AnalysisMethod, Set<AnalysisMethod>> polymorphicSignatureCallers = new ConcurrentHashMap<>();
184187
private FileInfo fileInfo;
185188
private GraphsOutput graphsOutput;
186189
private final boolean useSharedLayerGraphs;
@@ -189,6 +192,8 @@ public class SVMImageLayerWriter extends ImageLayerWriter {
189192
private NativeImageHeap nativeImageHeap;
190193
private HostedUniverse hUniverse;
191194

195+
private boolean polymorphicSignatureSealed = false;
196+
192197
private record ConstantParent(int constantId, int index) {
193198
static ConstantParent NONE = new ConstantParent(UNDEFINED_CONSTANT_ID, UNDEFINED_FIELD_INDEX);
194199
}
@@ -339,6 +344,8 @@ public void persistAnalysisInfo() {
339344
snapshotBuilder.setNextFieldId(aUniverse.getNextFieldId());
340345
snapshotBuilder.setNextConstantId(ImageHeapConstant.getCurrentId());
341346

347+
polymorphicSignatureSealed = true;
348+
342349
List<AnalysisType> typesToPersist = aUniverse.getTypes().stream().filter(AnalysisType::isTrackedAcrossLayers).toList();
343350
List<AnalysisMethod> methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).toList();
344351
List<AnalysisField> fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).toList();
@@ -593,6 +600,15 @@ protected void delegatePersistMethod(AnalysisMethod method, PersistedAnalysisMet
593600
b.setJavaCallVariantWrapper(Void.VOID);
594601
Executable executable = jniJavaCallVariantWrapperMethod.getMember();
595602
persistMethodWrappedMember(b, executable);
603+
} else if (method.wrapped instanceof SubstitutionMethod substitutionMethod && substitutionMethod.getAnnotated() instanceof PolymorphicSignatureWrapperMethod) {
604+
WrappedMethod.PolymorphicSignature.Builder b = builder.getWrappedMethod().initPolymorphicSignature();
605+
Set<AnalysisMethod> callers = polymorphicSignatureCallers.get(method);
606+
var callersBuilder = b.initCallers(callers.size());
607+
int i = 0;
608+
for (AnalysisMethod caller : callers) {
609+
callersBuilder.set(i, caller.getId());
610+
i++;
611+
}
596612
}
597613
}
598614

@@ -974,6 +990,11 @@ private static boolean contains(byte[] data, byte[] seq) {
974990
return false;
975991
}
976992

993+
public void addPolymorphicSignatureCaller(AnalysisMethod polymorphicSignature, AnalysisMethod caller) {
994+
AnalysisError.guarantee(!polymorphicSignatureSealed, "The caller %s for method %s was added after the methods were persisted", caller, polymorphicSignature);
995+
polymorphicSignatureCallers.computeIfAbsent(polymorphicSignature, (m) -> ConcurrentHashMap.newKeySet()).add(caller);
996+
}
997+
977998
record SingletonPersistInfo(LayeredImageSingleton.PersistFlags flags, int id, EconomicMap<String, Object> keyStore) {
978999
}
9791000

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SharedLayerSnapshotCapnProtoSchemaHolder.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,7 @@ public Which which() {
13751375
case 2 : return Which.OUTLINED_S_B;
13761376
case 3 : return Which.C_ENTRY_POINT_CALL_STUB;
13771377
case 4 : return Which.WRAPPED_MEMBER;
1378+
case 5 : return Which.POLYMORPHIC_SIGNATURE;
13781379
default: return Which._NOT_IN_SCHEMA;
13791380
}
13801381
}
@@ -1448,6 +1449,18 @@ public final WrappedMember.Builder initWrappedMember() {
14481449
return new PersistedAnalysisMethod.WrappedMethod.WrappedMember.Builder(segment, data, pointers, dataSize, pointerCount);
14491450
}
14501451

1452+
public final boolean isPolymorphicSignature() {
1453+
return which() == PersistedAnalysisMethod.WrappedMethod.Which.POLYMORPHIC_SIGNATURE;
1454+
}
1455+
public final PolymorphicSignature.Builder getPolymorphicSignature() {
1456+
return new PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.Builder(segment, data, pointers, dataSize, pointerCount);
1457+
}
1458+
public final PolymorphicSignature.Builder initPolymorphicSignature() {
1459+
_setShortField(11, (short)PersistedAnalysisMethod.WrappedMethod.Which.POLYMORPHIC_SIGNATURE.ordinal());
1460+
_clearPointerField(10);
1461+
return new PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.Builder(segment, data, pointers, dataSize, pointerCount);
1462+
}
1463+
14511464
}
14521465

14531466
public static final class Reader extends org.capnproto.StructReader {
@@ -1462,6 +1475,7 @@ public Which which() {
14621475
case 2 : return Which.OUTLINED_S_B;
14631476
case 3 : return Which.C_ENTRY_POINT_CALL_STUB;
14641477
case 4 : return Which.WRAPPED_MEMBER;
1478+
case 5 : return Which.POLYMORPHIC_SIGNATURE;
14651479
default: return Which._NOT_IN_SCHEMA;
14661480
}
14671481
}
@@ -1502,6 +1516,13 @@ public WrappedMember.Reader getWrappedMember() {
15021516
return new PersistedAnalysisMethod.WrappedMethod.WrappedMember.Reader(segment, data, pointers, dataSize, pointerCount, nestingLimit);
15031517
}
15041518

1519+
public final boolean isPolymorphicSignature() {
1520+
return which() == PersistedAnalysisMethod.WrappedMethod.Which.POLYMORPHIC_SIGNATURE;
1521+
}
1522+
public PolymorphicSignature.Reader getPolymorphicSignature() {
1523+
return new PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.Reader(segment, data, pointers, dataSize, pointerCount, nestingLimit);
1524+
}
1525+
15051526
}
15061527

15071528
public enum Which {
@@ -1510,6 +1531,7 @@ public enum Which {
15101531
OUTLINED_S_B,
15111532
C_ENTRY_POINT_CALL_STUB,
15121533
WRAPPED_MEMBER,
1534+
POLYMORPHIC_SIGNATURE,
15131535
_NOT_IN_SCHEMA,
15141536
}
15151537
public static class FactoryMethod {
@@ -1892,6 +1914,65 @@ public enum Which {
18921914
}
18931915

18941916

1917+
public static class PolymorphicSignature {
1918+
public static final org.capnproto.StructSize STRUCT_SIZE = new org.capnproto.StructSize((short)5,(short)13);
1919+
public static final class Factory extends org.capnproto.StructFactory<Builder, Reader> {
1920+
public Factory() {
1921+
}
1922+
public final Reader constructReader(org.capnproto.SegmentReader segment, int data,int pointers, int dataSize, short pointerCount, int nestingLimit) {
1923+
return new Reader(segment,data,pointers,dataSize,pointerCount,nestingLimit);
1924+
}
1925+
public final Builder constructBuilder(org.capnproto.SegmentBuilder segment, int data,int pointers, int dataSize, short pointerCount) {
1926+
return new Builder(segment, data, pointers, dataSize, pointerCount);
1927+
}
1928+
public final org.capnproto.StructSize structSize() {
1929+
return PersistedAnalysisMethod.WrappedMethod.PolymorphicSignature.STRUCT_SIZE;
1930+
}
1931+
public final Reader asReader(Builder builder) {
1932+
return builder.asReader();
1933+
}
1934+
}
1935+
public static final Factory factory = new Factory();
1936+
public static final org.capnproto.StructList.Factory<Builder,Reader> listFactory =
1937+
new org.capnproto.StructList.Factory<Builder, Reader>(factory);
1938+
public static final class Builder extends org.capnproto.StructBuilder {
1939+
Builder(org.capnproto.SegmentBuilder segment, int data, int pointers,int dataSize, short pointerCount){
1940+
super(segment, data, pointers, dataSize, pointerCount);
1941+
}
1942+
public final Reader asReader() {
1943+
return new Reader(segment, data, pointers, dataSize, pointerCount, 0x7fffffff);
1944+
}
1945+
public final boolean hasCallers() {
1946+
return !_pointerFieldIsNull(10);
1947+
}
1948+
public final org.capnproto.PrimitiveList.Int.Builder getCallers() {
1949+
return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 10, null, 0);
1950+
}
1951+
public final void setCallers(org.capnproto.PrimitiveList.Int.Reader value) {
1952+
_setPointerField(org.capnproto.PrimitiveList.Int.factory, 10, value);
1953+
}
1954+
public final org.capnproto.PrimitiveList.Int.Builder initCallers(int size) {
1955+
return _initPointerField(org.capnproto.PrimitiveList.Int.factory, 10, size);
1956+
}
1957+
}
1958+
1959+
public static final class Reader extends org.capnproto.StructReader {
1960+
Reader(org.capnproto.SegmentReader segment, int data, int pointers,int dataSize, short pointerCount, int nestingLimit){
1961+
super(segment, data, pointers, dataSize, pointerCount, nestingLimit);
1962+
}
1963+
1964+
public final boolean hasCallers() {
1965+
return !_pointerFieldIsNull(10);
1966+
}
1967+
public final org.capnproto.PrimitiveList.Int.Reader getCallers() {
1968+
return _getPointerField(org.capnproto.PrimitiveList.Int.factory, 10, null, 0);
1969+
}
1970+
1971+
}
1972+
1973+
}
1974+
1975+
18951976
}
18961977

18971978

0 commit comments

Comments
 (0)