54
54
import java .util .stream .Stream ;
55
55
import java .util .stream .StreamSupport ;
56
56
57
+ import org .graalvm .collections .EconomicMap ;
57
58
import org .graalvm .nativeimage .AnnotationAccess ;
58
59
import org .graalvm .nativeimage .ImageSingletons ;
59
60
import org .graalvm .nativeimage .c .function .CEntryPoint ;
@@ -187,9 +188,9 @@ public class SVMImageLayerLoader extends ImageLayerLoader {
187
188
private final Map <ResolvedJavaMethod , Boolean > methodHandleCallers = new ConcurrentHashMap <>();
188
189
189
190
/** Map from {@link SVMImageLayerSnapshotUtil#getTypeDescriptor} to base layer type ids. */
190
- private final Map <String , Integer > typeDescriptorToBaseLayerId = new HashMap <>() ;
191
+ private EconomicMap <String , Integer > typeDescriptorToBaseLayerId ;
191
192
/** Map from {@link SVMImageLayerSnapshotUtil#getMethodDescriptor} to base layer method ids. */
192
- private final Map <String , Integer > methodDescriptorToBaseLayerId = new HashMap <>() ;
193
+ private EconomicMap <String , Integer > methodDescriptorToBaseLayerId ;
193
194
194
195
protected AnalysisUniverse universe ;
195
196
protected AnalysisMetaAccess metaAccess ;
@@ -261,12 +262,16 @@ public void loadLayerAnalysis() {
261
262
universe .setStartFieldId (snapshot .getNextFieldId ());
262
263
ImageHeapConstant .setCurrentId (snapshot .getNextConstantId ());
263
264
264
- for (PersistedAnalysisType .Reader typeData : snapshot .getTypes ()) {
265
+ StructList .Reader <PersistedAnalysisType .Reader > typesReader = snapshot .getTypes ();
266
+ typeDescriptorToBaseLayerId = EconomicMap .create (typesReader .size ());
267
+ for (PersistedAnalysisType .Reader typeData : typesReader ) {
265
268
String descriptor = typeData .getDescriptor ().toString ();
266
269
typeDescriptorToBaseLayerId .put (descriptor , typeData .getId ());
267
270
}
268
271
269
- for (PersistedAnalysisMethod .Reader methodData : snapshot .getMethods ()) {
272
+ StructList .Reader <PersistedAnalysisMethod .Reader > methodsReader = snapshot .getMethods ();
273
+ methodDescriptorToBaseLayerId = EconomicMap .create (methodsReader .size ());
274
+ for (PersistedAnalysisMethod .Reader methodData : methodsReader ) {
270
275
String descriptor = methodData .getDescriptor ().toString ();
271
276
methodDescriptorToBaseLayerId .put (descriptor , methodData .getId ());
272
277
}
@@ -397,7 +402,7 @@ public AnalysisType getAnalysisTypeForBaseLayerId(int tid) {
397
402
guarantee (types .containsKey (tid ), "Type with id %d was not correctly loaded." , tid );
398
403
/*
399
404
* The type needs to be looked up because it ensures the type is completely created, as the
400
- * types Map is populated before the type is created.
405
+ * types map is populated before the type is created.
401
406
*/
402
407
return universe .lookup (types .get (tid ).getWrapped ());
403
408
}
@@ -406,29 +411,35 @@ private PersistedAnalysisType.Reader findType(int tid) {
406
411
return binarySearchUnique (tid , snapshot .getTypes (), PersistedAnalysisType .Reader ::getId );
407
412
}
408
413
414
+ /**
415
+ * Load the host VM type corresponding to the serialized type data.
416
+ * <p>
417
+ * First, find the corresponding host VM {@link Class} object by name using
418
+ * {@link #lookupBaseLayerTypeInHostVM(String)}.
419
+ * <p>
420
+ * Then, lookup the hosted {@link Class} in the {@link AnalysisMetaAccess} which will trigger
421
+ * creation of the corresponding {@link AnalysisType} object.
422
+ * <p>
423
+ * The {@link AnalysisType} constructor calls {@link #lookupHostedTypeInBaseLayer(AnalysisType)}
424
+ * to check if the newly created type already exists in the base layer. If that's the case, the
425
+ * {@link AnalysisType} object takes the same {@code id} as the corresponding base layer type
426
+ * and this mapping is also registered in the {@link #types} map.
427
+ */
409
428
private void loadType (PersistedAnalysisType .Reader typeData ) {
410
429
int tid = typeData .getId ();
411
430
412
431
if (delegateLoadType (typeData )) {
413
432
return ;
414
433
}
415
434
416
- String name = typeData .getClassJavaName ().toString ();
417
- Class <?> clazz = lookupBaseLayerTypeInHostVM (name );
435
+ Class <?> clazz = lookupBaseLayerTypeInHostVM (typeData .getClassJavaName ().toString ());
418
436
419
437
ResolvedJavaType superClass = getResolvedJavaTypeForBaseLayerId (typeData .getSuperClassTypeId ());
420
-
421
438
ResolvedJavaType [] interfaces = streamInts (typeData .getInterfaces ())
422
439
.mapToObj (this ::getResolvedJavaTypeForBaseLayerId ).toArray (ResolvedJavaType []::new );
423
440
424
441
if (clazz != null ) {
425
- /*
426
- * When looking up the class by name, the host VM will create the corresponding
427
- * AnalysisType. During this process, the method lookupHostedTypeInBaseLayer will be
428
- * called to see if the type already exists in the base layer. If it is the case, the id
429
- * from the base layer will be reused and the ImageLayerLoader#types map will be
430
- * populated.
431
- */
442
+ /* Lookup the host VM type and create the analysis type. */
432
443
metaAccess .lookupJavaType (clazz );
433
444
}
434
445
@@ -567,7 +578,6 @@ protected Class<?> lookupBaseLayerTypeInHostVM(String type) {
567
578
return null ;
568
579
}
569
580
while (arrayType > 0 ) {
570
- assert clazz != null ;
571
581
clazz = clazz .arrayType ();
572
582
arrayType --;
573
583
}
@@ -664,39 +674,31 @@ yield switch (JavaKind.fromPrimitiveOrVoidTypeChar(typeChar)) {
664
674
665
675
@ Override
666
676
public int lookupHostedTypeInBaseLayer (AnalysisType type ) {
667
- int id = getBaseLayerTypeId (type );
677
+ /* Assume that the type was not reachable in the base image. */
678
+ int id = -1 ;
679
+ if (type .getWrapped () instanceof BaseLayerType baseLayerType ) {
680
+ id = baseLayerType .getBaseLayerId ();
681
+ } else {
682
+ String typeDescriptor = imageLayerSnapshotUtil .getTypeDescriptor (type );
683
+ Integer typeId = typeDescriptorToBaseLayerId .get (typeDescriptor );
684
+ if (typeId != null ) {
685
+ id = typeId ;
686
+ initializeBaseLayerTypeBeforePublishing (type , findType (typeId ));
687
+ }
688
+ }
668
689
if (id == -1 || types .putIfAbsent (id , type ) != null ) {
669
690
/* A complete type is treated as a different type than its incomplete version */
670
691
return -1 ;
671
692
}
672
693
return id ;
673
694
}
674
695
675
- private int getBaseLayerTypeId (AnalysisType type ) {
696
+ private static int getBaseLayerTypeId (AnalysisType type ) {
697
+ VMError .guarantee (type .isInBaseLayer ());
676
698
if (type .getWrapped () instanceof BaseLayerType baseLayerType ) {
677
699
return baseLayerType .getBaseLayerId ();
678
700
}
679
- PersistedAnalysisType .Reader typeData = findBaseLayerType (type );
680
- if (typeData == null ) {
681
- /* The type was not reachable in the base image */
682
- return -1 ;
683
- }
684
- initializeBaseLayerTypeBeforePublishing (type , typeData );
685
- int id = typeData .getId ();
686
- int hubIdentityHashCode = typeData .getHubIdentityHashCode ();
687
- typeToHubIdentityHashCode .put (id , hubIdentityHashCode );
688
- return id ;
689
- }
690
-
691
- protected PersistedAnalysisType .Reader findBaseLayerType (AnalysisType type ) {
692
- assert !(type .getWrapped () instanceof BaseLayerType );
693
- String typeDescriptor = imageLayerSnapshotUtil .getTypeDescriptor (type );
694
- Integer typeId = typeDescriptorToBaseLayerId .get (typeDescriptor );
695
- if (typeId == null ) {
696
- /* The type was not reachable in the base image */
697
- return null ;
698
- }
699
- return findType (typeId );
701
+ return type .getId ();
700
702
}
701
703
702
704
/**
@@ -726,6 +728,10 @@ private void initializeBaseLayerTypeBeforePublishing(AnalysisType type, Persiste
726
728
} else {
727
729
classInitializationSupport .withUnsealedConfiguration (() -> classInitializationSupport .initializeAtRunTime (clazz , "computed in a previous layer" ));
728
730
}
731
+
732
+ /* Extract and record the base layer identity hashcode for this type. */
733
+ int hubIdentityHashCode = typeData .getHubIdentityHashCode ();
734
+ typeToHubIdentityHashCode .put (typeData .getId (), hubIdentityHashCode );
729
735
}
730
736
731
737
/**
@@ -734,11 +740,8 @@ private void initializeBaseLayerTypeBeforePublishing(AnalysisType type, Persiste
734
740
*/
735
741
@ Override
736
742
public void initializeBaseLayerType (AnalysisType type ) {
737
- int id = getBaseLayerTypeId (type );
738
- if (id == -1 ) {
739
- return ;
740
- }
741
- PersistedAnalysisType .Reader td = findType (id );
743
+ VMError .guarantee (type .isInBaseLayer ());
744
+ PersistedAnalysisType .Reader td = findType (getBaseLayerTypeId (type ));
742
745
registerFlag (td .getIsInstantiated (), debug -> type .registerAsInstantiated (PERSISTED ));
743
746
registerFlag (td .getIsUnsafeAllocated (), debug -> type .registerAsUnsafeAllocated (PERSISTED ));
744
747
registerFlag (td .getIsReachable (), debug -> type .registerAsReachable (PERSISTED ));
@@ -1782,9 +1785,8 @@ private void scanCompanionField(DynamicHub hub) {
1782
1785
}
1783
1786
1784
1787
public ClassInitializationInfo getClassInitializationInfo (AnalysisType type ) {
1785
- PersistedAnalysisType .Reader typeMap = findType (type .getId ());
1786
-
1787
- var initInfo = typeMap .getClassInitializationInfo ();
1788
+ PersistedAnalysisType .Reader typeData = findType (type .getId ());
1789
+ var initInfo = typeData .getClassInitializationInfo ();
1788
1790
if (initInfo .getIsNoInitializerNoTracking ()) {
1789
1791
return ClassInitializationInfo .forNoInitializerInfo (false );
1790
1792
} else if (initInfo .getIsInitializedNoTracking ()) {
0 commit comments