@@ -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.\n The 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