69
69
import com .oracle .graal .pointsto .heap .ImageHeapPrimitiveArray ;
70
70
import com .oracle .graal .pointsto .heap .ImageHeapRelocatableConstant ;
71
71
import com .oracle .graal .pointsto .heap .value .ValueSupplier ;
72
+ import com .oracle .graal .pointsto .infrastructure .OriginalClassProvider ;
72
73
import com .oracle .graal .pointsto .infrastructure .ResolvedSignature ;
73
74
import com .oracle .graal .pointsto .meta .AnalysisField ;
74
75
import com .oracle .graal .pointsto .meta .AnalysisMetaAccess ;
@@ -166,6 +167,7 @@ public class SVMImageLayerLoader extends ImageLayerLoader {
166
167
167
168
private HostedUniverse hostedUniverse ;
168
169
170
+ /** Maps from the previous layer element id to the linked elements in this layer. */
169
171
protected final Map <Integer , AnalysisType > types = new ConcurrentHashMap <>();
170
172
protected final Map <Integer , AnalysisMethod > methods = new ConcurrentHashMap <>();
171
173
protected final Map <Integer , AnalysisField > fields = new ConcurrentHashMap <>();
@@ -679,6 +681,7 @@ private int getBaseLayerTypeId(AnalysisType type) {
679
681
/* The type was not reachable in the base image */
680
682
return -1 ;
681
683
}
684
+ initializeBaseLayerTypeBeforePublishing (type , typeData );
682
685
int id = typeData .getId ();
683
686
int hubIdentityHashCode = typeData .getHubIdentityHashCode ();
684
687
typeToHubIdentityHashCode .put (id , hubIdentityHashCode );
@@ -696,6 +699,39 @@ protected PersistedAnalysisType.Reader findBaseLayerType(AnalysisType type) {
696
699
return findType (typeId );
697
700
}
698
701
702
+ /**
703
+ * This method is invoked *before* the {@link AnalysisType} is published in the
704
+ * {@link AnalysisUniverse}. The side effects of this method are visible to other threads that
705
+ * are consuming the {@link AnalysisType} object.
706
+ */
707
+ @ SuppressWarnings ("try" )
708
+ private void initializeBaseLayerTypeBeforePublishing (AnalysisType type , PersistedAnalysisType .Reader typeData ) {
709
+ assert !(type .getWrapped () instanceof BaseLayerType );
710
+ /*
711
+ * For types reachable in this layer register the *computed* initialization kind extracted
712
+ * from the previous layer. This will cause base layer types to have a *strict*
713
+ * initialization kind in this layer which will prevent further changes to the
714
+ * initialization kind, even in ways that would otherwise be considered compatible, e.g.,
715
+ * RUN_TIME -> BUILD_TIME. Similarly, if a different initialization kind was already
716
+ * registered in this layer registration will fail.
717
+ *
718
+ * Note that this is done after the app-layer class initialization specification is applied,
719
+ * so we don't have to traverse all types. Moreover, for package-level specification this
720
+ * should also be OK, because package-level specification is only a suggestion and the
721
+ * base-layer will always win as it is going over user classes.
722
+ */
723
+ Class <?> clazz = OriginalClassProvider .getJavaClass (type );
724
+ if (typeData .getIsInitialized ()) {
725
+ classInitializationSupport .withUnsealedConfiguration (() -> classInitializationSupport .initializeAtBuildTime (clazz , "computed in a previous layer" ));
726
+ } else {
727
+ classInitializationSupport .withUnsealedConfiguration (() -> classInitializationSupport .initializeAtRunTime (clazz , "computed in a previous layer" ));
728
+ }
729
+ }
730
+
731
+ /**
732
+ * This method is invoked *after* the {@link AnalysisType} is published in the
733
+ * {@link AnalysisUniverse} and it may execute concurrently with other threads using the type.
734
+ */
699
735
@ Override
700
736
public void initializeBaseLayerType (AnalysisType type ) {
701
737
int id = getBaseLayerTypeId (type );
@@ -1304,6 +1340,19 @@ private ImageHeapConstant getOrCreateConstant(int id, JavaConstant parentReachab
1304
1340
throw GraalError .shouldNotReachHere ("The constant was not reachable in the base image" );
1305
1341
}
1306
1342
1343
+ /*
1344
+ * Important: If this is a constant originating from a static final field ensure that the
1345
+ * field declaring type is initialized before the field type is accessed below. This is to
1346
+ * avoid issue with class initialization execution order in class initialization cycles.
1347
+ */
1348
+ if (baseLayerConstant .isObject () && !baseLayerConstant .getIsSimulated ()) {
1349
+ Relinking .Reader relinking = baseLayerConstant .getObject ().getRelinking ();
1350
+ if (relinking .isFieldConstant ()) {
1351
+ AnalysisField analysisField = getAnalysisFieldForBaseLayerId (relinking .getFieldConstant ().getOriginFieldId ());
1352
+ VMError .guarantee (analysisField .getDeclaringClass ().isInitialized ());
1353
+ }
1354
+ }
1355
+
1307
1356
AnalysisType type = getAnalysisTypeForBaseLayerId (baseLayerConstant .getTypeId ());
1308
1357
1309
1358
long objectOffset = baseLayerConstant .getObjectOffset ();
@@ -1581,31 +1630,18 @@ private JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConsta
1581
1630
} else if (relinking .isFieldConstant ()) {
1582
1631
var fieldConstant = relinking .getFieldConstant ();
1583
1632
AnalysisField analysisField = getAnalysisFieldForBaseLayerId (fieldConstant .getOriginFieldId ());
1584
- if (! (analysisField . getWrapped () instanceof BaseLayerField ) && ! AnnotationAccess . isAnnotationPresent ( analysisField , Delete . class )) {
1585
- VMError .guarantee (!baseLayerConstant .getIsSimulated (), "Should not alter the initialization status for simulated constants." );
1633
+ if (shouldRelinkField (analysisField )) {
1634
+ VMError .guarantee (!baseLayerConstant .getIsSimulated (), "Cannot relink simulated constants." );
1586
1635
/*
1587
1636
* The declaring type of relinked fields was already initialized in the previous
1588
1637
* layer (see SVMImageLayerWriter#shouldRelinkField).
1589
1638
*/
1590
- if (fieldConstant .getRequiresLateLoading ()) {
1591
- /*
1592
- * Fields with a field value transformer are relinked later, after all possible
1593
- * transformers have been registered. *Guarantee* that the declaring type has
1594
- * been initialized by now. Note that reading the field below will prevent a
1595
- * transformer to be installed at a later time.
1596
- */
1597
- VMError .guarantee (analysisField .getDeclaringClass ().isInitialized ());
1598
- } else {
1599
- /*
1600
- * All other fields are relinked earlier, before the constant is needed. *Force*
1601
- * the build time initialization of the declaring type before reading the field
1602
- * value.
1603
- */
1604
- Class <?> fieldDeclaringClass = analysisField .getDeclaringClass ().getJavaClass ();
1605
- classInitializationSupport .initializeAtBuildTime (fieldDeclaringClass , "Already initialized in base layer." );
1606
- }
1639
+ VMError .guarantee (analysisField .getDeclaringClass ().isInitialized ());
1607
1640
/* Read fields through the hostedValueProvider and apply object replacement. */
1608
- return hostedValuesProvider .readFieldValueWithReplacement (analysisField , null );
1641
+ JavaConstant javaConstant = hostedValuesProvider .readFieldValueWithReplacement (analysisField , null );
1642
+ VMError .guarantee (javaConstant .isNonNull (), "Found NULL_CONSTANT when reading the hosted value of relinked field %s. " +
1643
+ "Since relinked fields should have a concrete non-null value there may be a class initialization mismatch." , analysisField );
1644
+ return javaConstant ;
1609
1645
}
1610
1646
} else if (clazz .equals (Class .class )) {
1611
1647
/* DynamicHub corresponding to $$TypeSwitch classes are not relinked */
@@ -1630,6 +1666,11 @@ private JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConsta
1630
1666
return null ;
1631
1667
}
1632
1668
1669
+ private static boolean shouldRelinkField (AnalysisField field ) {
1670
+ VMError .guarantee (field .isInBaseLayer ());
1671
+ return !(field .getWrapped () instanceof BaseLayerField ) && !AnnotationAccess .isAnnotationPresent (field , Delete .class );
1672
+ }
1673
+
1633
1674
@ SuppressWarnings ("unchecked" )
1634
1675
private Enum <?> getEnumValue (Text .Reader className , Text .Reader name ) {
1635
1676
Class <?> enumClass = imageLayerBuildingSupport .lookupClass (false , className .toString ());
0 commit comments