@@ -204,7 +204,13 @@ public class SVMImageLayerWriter extends ImageLayerWriter {
204
204
private final MessageBuilder snapshotFileBuilder = new MessageBuilder ();
205
205
private final SharedLayerSnapshot .Builder snapshotBuilder = this .snapshotFileBuilder .initRoot (SharedLayerSnapshot .factory );
206
206
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 <>();
208
214
private final Map <AnalysisMethod , Set <AnalysisMethod >> polymorphicSignatureCallers = new ConcurrentHashMap <>();
209
215
private final GraphsOutput graphsOutput ;
210
216
private final boolean useSharedLayerGraphs ;
@@ -231,13 +237,13 @@ private record MethodGraphsInfo(String analysisGraphLocation, boolean analysisGr
231
237
232
238
static final MethodGraphsInfo NO_GRAPHS = new MethodGraphsInfo (null , false , null );
233
239
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 ;
236
242
return new MethodGraphsInfo (location , isIntrinsic , strengthenedGraphLocation );
237
243
}
238
244
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 ;
241
247
return new MethodGraphsInfo (analysisGraphLocation , analysisGraphIsIntrinsic , location );
242
248
}
243
249
}
@@ -379,6 +385,7 @@ public void persistAnalysisInfo() {
379
385
AnalysisMethod [] methodsToPersist = aUniverse .getMethods ().stream ().filter (AnalysisMethod ::isTrackedAcrossLayers ).sorted (Comparator .comparingInt (AnalysisMethod ::getId ))
380
386
.toArray (AnalysisMethod []::new );
381
387
initSortedArray (snapshotBuilder ::initMethods , methodsToPersist , this ::persistMethod );
388
+ methodDescriptors .clear ();
382
389
383
390
AnalysisField [] fieldsToPersist = aUniverse .getFields ().stream ().filter (AnalysisField ::isTrackedAcrossLayers ).sorted (Comparator .comparingInt (AnalysisField ::getId ))
384
391
.toArray (AnalysisField []::new );
@@ -582,18 +589,20 @@ private static void handleNameConflict(String message) {
582
589
583
590
private void persistMethod (AnalysisMethod method , Supplier <PersistedAnalysisMethod .Builder > builderSupplier ) {
584
591
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 );
586
593
Executable executable = method .getJavaMethod ();
587
594
588
- if (builder .getId () != 0 ) {
589
- throw GraalError .shouldNotReachHere ("The method descriptor should be unique, but " + imageLayerSnapshotUtil .getMethodDescriptor (method ) + " got added twice." );
590
- }
591
595
if (executable != null ) {
592
596
initStringList (builder ::initArgumentClassNames , Arrays .stream (executable .getParameterTypes ()).map (Class ::getName ));
593
597
builder .setClassName (executable .getDeclaringClass ().getName ());
594
598
}
595
599
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.\n The first method is %s and the second is %s."
603
+ .formatted (methodDescriptor , methodDescriptors .get (methodDescriptor ), method ));
604
+ }
605
+ builder .setDescriptor (methodDescriptor );
597
606
builder .setDeclaringTypeId (method .getDeclaringClass ().getId ());
598
607
initInts (builder ::initArgumentTypeIds , method .getSignature ().toParameterList (null ).stream ().mapToInt (AnalysisType ::getId ));
599
608
builder .setId (method .getId ());
@@ -1053,18 +1062,19 @@ private static AnalysisMethod getRelocatableConstantMethod(MethodRef methodRef)
1053
1062
1054
1063
@ Override
1055
1064
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 ) {
1059
1071
/*
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.
1062
1075
*/
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 ()));
1068
1078
}
1069
1079
}
1070
1080
@@ -1073,14 +1083,14 @@ public void persistMethodStrengthenedGraph(AnalysisMethod method) {
1073
1083
return ;
1074
1084
}
1075
1085
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 ));
1084
1094
}
1085
1095
1086
1096
private String persistGraph (AnalysisMethod method , EncodedGraph analyzedGraph ) {
0 commit comments