Skip to content

Commit 1fe3acd

Browse files
committed
Use the wrapped qualified name for the method descriptor to distinguish unresolved type and fix check to ensure all method descriptor are unique
1 parent 2385a96 commit 1fe3acd

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,13 @@ public String getMethodDescriptor(AnalysisMethod method) {
299299
if (originalMethod != null) {
300300
return addModuleName(originalMethod.toString(), moduleName);
301301
}
302-
return addModuleName(getQualifiedName(method), moduleName);
302+
/*
303+
* The wrapped qualified method is needed here as the AnalysisMethod replaces unresolved
304+
* parameter or return types with java.lang.Object, potentially causing method descriptor
305+
* duplication. The wrapped method signature preserves the original type information,
306+
* preventing this issue.
307+
*/
308+
return addModuleName(getWrappedQualifiedName(method), moduleName);
303309
}
304310

305311
/*
@@ -326,6 +332,10 @@ private static String getQualifiedName(AnalysisMethod method) {
326332
return method.getSignature().getReturnType().toJavaName(true) + " " + method.getQualifiedName();
327333
}
328334

335+
private static String getWrappedQualifiedName(AnalysisMethod method) {
336+
return method.wrapped.format("%R %H.%n(%P)");
337+
}
338+
329339
public static void forcePersistConstant(ImageHeapConstant imageHeapConstant) {
330340
AnalysisUniverse universe = imageHeapConstant.getType().getUniverse();
331341
universe.getHeapScanner().markReachable(imageHeapConstant, ObjectScanner.OtherReason.PERSISTED);

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

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,13 @@ public class SVMImageLayerWriter extends ImageLayerWriter {
204204
private final MessageBuilder snapshotFileBuilder = new MessageBuilder();
205205
private final SharedLayerSnapshot.Builder snapshotBuilder = this.snapshotFileBuilder.initRoot(SharedLayerSnapshot.factory);
206206
private Map<ImageHeapConstant, ConstantParent> constantsMap;
207-
private final Map<String, MethodGraphsInfo> methodsMap = new ConcurrentHashMap<>();
207+
private final Map<AnalysisMethod, MethodGraphsInfo> methodsMap = new ConcurrentHashMap<>();
208+
/**
209+
* This map is only used for validation, to ensure that all method descriptors are unique. A
210+
* duplicate method descriptor would cause methods to be incorrectly matched across layers,
211+
* which is really hard to debug and can have unexpected consequences.
212+
*/
213+
private final Map<String, AnalysisMethod> methodDescriptors = new HashMap<>();
208214
private final Map<AnalysisMethod, Set<AnalysisMethod>> polymorphicSignatureCallers = new ConcurrentHashMap<>();
209215
private final GraphsOutput graphsOutput;
210216
private final boolean useSharedLayerGraphs;
@@ -231,13 +237,13 @@ private record MethodGraphsInfo(String analysisGraphLocation, boolean analysisGr
231237

232238
static final MethodGraphsInfo NO_GRAPHS = new MethodGraphsInfo(null, false, null);
233239

234-
MethodGraphsInfo withAnalysisGraph(String location, boolean isIntrinsic) {
235-
assert analysisGraphLocation == null && !analysisGraphIsIntrinsic;
240+
MethodGraphsInfo withAnalysisGraph(AnalysisMethod method, String location, boolean isIntrinsic) {
241+
assert analysisGraphLocation == null && !analysisGraphIsIntrinsic : "Only one analysis graph can be persisted for a given method: " + method;
236242
return new MethodGraphsInfo(location, isIntrinsic, strengthenedGraphLocation);
237243
}
238244

239-
MethodGraphsInfo withStrengthenedGraph(String location) {
240-
assert strengthenedGraphLocation == null;
245+
MethodGraphsInfo withStrengthenedGraph(AnalysisMethod method, String location) {
246+
assert strengthenedGraphLocation == null : "Only one strengthened graph can be persisted for a given method: " + method;
241247
return new MethodGraphsInfo(analysisGraphLocation, analysisGraphIsIntrinsic, location);
242248
}
243249
}
@@ -379,6 +385,7 @@ public void persistAnalysisInfo() {
379385
AnalysisMethod[] methodsToPersist = aUniverse.getMethods().stream().filter(AnalysisMethod::isTrackedAcrossLayers).sorted(Comparator.comparingInt(AnalysisMethod::getId))
380386
.toArray(AnalysisMethod[]::new);
381387
initSortedArray(snapshotBuilder::initMethods, methodsToPersist, this::persistMethod);
388+
methodDescriptors.clear();
382389

383390
AnalysisField[] fieldsToPersist = aUniverse.getFields().stream().filter(AnalysisField::isTrackedAcrossLayers).sorted(Comparator.comparingInt(AnalysisField::getId))
384391
.toArray(AnalysisField[]::new);
@@ -582,18 +589,20 @@ private static void handleNameConflict(String message) {
582589

583590
private void persistMethod(AnalysisMethod method, Supplier<PersistedAnalysisMethod.Builder> builderSupplier) {
584591
PersistedAnalysisMethod.Builder builder = builderSupplier.get();
585-
MethodGraphsInfo graphsInfo = methodsMap.putIfAbsent(imageLayerSnapshotUtil.getMethodDescriptor(method), MethodGraphsInfo.NO_GRAPHS);
592+
MethodGraphsInfo graphsInfo = methodsMap.putIfAbsent(method, MethodGraphsInfo.NO_GRAPHS);
586593
Executable executable = method.getJavaMethod();
587594

588-
if (builder.getId() != 0) {
589-
throw GraalError.shouldNotReachHere("The method descriptor should be unique, but " + imageLayerSnapshotUtil.getMethodDescriptor(method) + " got added twice.");
590-
}
591595
if (executable != null) {
592596
initStringList(builder::initArgumentClassNames, Arrays.stream(executable.getParameterTypes()).map(Class::getName));
593597
builder.setClassName(executable.getDeclaringClass().getName());
594598
}
595599

596-
builder.setDescriptor(imageLayerSnapshotUtil.getMethodDescriptor(method));
600+
String methodDescriptor = imageLayerSnapshotUtil.getMethodDescriptor(method);
601+
if (methodDescriptors.put(methodDescriptor, method) != null) {
602+
throw GraalError.shouldNotReachHere("The method descriptor should be unique, but %s got added twice.\nThe first method is %s and the second is %s."
603+
.formatted(methodDescriptor, methodDescriptors.get(methodDescriptor), method));
604+
}
605+
builder.setDescriptor(methodDescriptor);
597606
builder.setDeclaringTypeId(method.getDeclaringClass().getId());
598607
initInts(builder::initArgumentTypeIds, method.getSignature().toParameterList(null).stream().mapToInt(AnalysisType::getId));
599608
builder.setId(method.getId());
@@ -1053,18 +1062,19 @@ private static AnalysisMethod getRelocatableConstantMethod(MethodRef methodRef)
10531062

10541063
@Override
10551064
public void persistAnalysisParsedGraph(AnalysisMethod method, AnalysisParsedGraph analysisParsedGraph) {
1056-
String name = imageLayerSnapshotUtil.getMethodDescriptor(method);
1057-
MethodGraphsInfo graphsInfo = methodsMap.get(name);
1058-
if (graphsInfo == null || graphsInfo.analysisGraphLocation == null) {
1065+
/*
1066+
* A copy of the encoded graph is needed here because the nodeStartOffsets can be
1067+
* concurrently updated otherwise, which causes the ObjectCopier to fail.
1068+
*/
1069+
String location = persistGraph(method, new EncodedGraph(analysisParsedGraph.getEncodedGraph()));
1070+
if (location != null) {
10591071
/*
1060-
* A copy of the encoded graph is needed here because the nodeStartOffsets can be
1061-
* concurrently updated otherwise, which causes the ObjectCopier to fail.
1072+
* This method should only be called once for each method. This check is performed by
1073+
* withAnalysisGraph as it will throw if the MethodGraphsInfo already has an analysis
1074+
* graph.
10621075
*/
1063-
String location = persistGraph(method, new EncodedGraph(analysisParsedGraph.getEncodedGraph()));
1064-
if (location != null) {
1065-
methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS)
1066-
.withAnalysisGraph(location, analysisParsedGraph.isIntrinsic()));
1067-
}
1076+
methodsMap.compute(method, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS)
1077+
.withAnalysisGraph(method, location, analysisParsedGraph.isIntrinsic()));
10681078
}
10691079
}
10701080

@@ -1073,14 +1083,14 @@ public void persistMethodStrengthenedGraph(AnalysisMethod method) {
10731083
return;
10741084
}
10751085

1076-
String name = imageLayerSnapshotUtil.getMethodDescriptor(method);
1077-
MethodGraphsInfo graphsInfo = methodsMap.get(name);
1078-
1079-
if (graphsInfo == null || graphsInfo.strengthenedGraphLocation == null) {
1080-
EncodedGraph analyzedGraph = method.getAnalyzedGraph();
1081-
String location = persistGraph(method, analyzedGraph);
1082-
methodsMap.compute(name, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS).withStrengthenedGraph(location));
1083-
}
1086+
EncodedGraph analyzedGraph = method.getAnalyzedGraph();
1087+
String location = persistGraph(method, analyzedGraph);
1088+
/*
1089+
* This method should only be called once for each method. This check is performed by
1090+
* withStrengthenedGraph as it will throw if the MethodGraphsInfo already has a strengthened
1091+
* graph.
1092+
*/
1093+
methodsMap.compute(method, (n, mgi) -> (mgi != null ? mgi : MethodGraphsInfo.NO_GRAPHS).withStrengthenedGraph(method, location));
10841094
}
10851095

10861096
private String persistGraph(AnalysisMethod method, EncodedGraph analyzedGraph) {

0 commit comments

Comments
 (0)