diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java
index 7f25485dd6ff..53717f8db7d6 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java
@@ -108,6 +108,10 @@ default boolean isCallAllowed(PointsToAnalysis bb, AnalysisMethod caller, Analys
default void onFieldAccessed(AnalysisField field) {
}
+ @SuppressWarnings("unused")
+ default void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) {
+ }
+
@SuppressWarnings("unused")
default void onTypeInstantiated(AnalysisType type, UsageKind usageKind) {
}
diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java
index 7f847f141352..372ef8e22c70 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java
@@ -156,6 +156,10 @@ protected void scanEmbeddedRoot(JavaConstant root, Object position) {
* @param field the scanned root field
*/
protected final void scanRootField(AnalysisField field) {
+ if (field.isInBaseLayer()) {
+ // skip base layer roots
+ return;
+ }
scanField(field, null, null);
}
diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java
index 52037b766ef8..c4c811fb74b6 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java
@@ -130,6 +130,23 @@ public void onFieldRead(AnalysisField field) {
AnalysisType declaringClass = field.getDeclaringClass();
if (field.isStatic()) {
FieldScan reason = new FieldScan(field);
+ if (field.isInBaseLayer()) {
+ /*
+ * For base layer static fields we don't want to scan the constant value, but
+ * instead inject its type state in the field flow. This will be propagated to any
+ * corresponding field loads.
+ *
+ * GR-52421: the field state needs to be serialized from the base layer analysis
+ */
+ if (field.getJavaKind().isObject()) {
+ AnalysisType fieldType = field.getType();
+ if (fieldType.isArray() || (fieldType.isInstanceClass() && !fieldType.isAbstract())) {
+ fieldType.registerAsInHeap(field);
+ }
+ bb.injectFieldTypes(field, fieldType);
+ }
+ return;
+ }
if (isValueAvailable(field)) {
JavaConstant fieldValue = readStaticFieldValue(field);
markReachable(fieldValue, reason);
diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java
index 5a49670a2adb..43872c79ef6e 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java
@@ -46,6 +46,7 @@
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERFACE_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_LINKED_TAG;
+import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHODS_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.MODIFIERS_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_FIELD_ID_TAG;
@@ -53,11 +54,14 @@
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_TYPE_ID_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NOT_MATERIALIZED_CONSTANT;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NULL_POINTER_CONSTANT;
+import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SIMULATED_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SOURCE_FILE_NAME_TAG;
+import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.STATIC_OBJECT_FIELDS_TAG;
+import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.STATIC_PRIMITIVE_FIELDS_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SUPER_CLASS_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TID_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TYPES_TAG;
@@ -102,6 +106,8 @@
* "next type id": nextTypeId,
* "next method id": nextMethodId,
* "next field id": nextFieldId,
+ * "static primitive fields": staticPrimitiveFields.id,
+ * "static object fields": staticObjectFields.id,
* "types": {
* typeIdentifier: {
* "id": id,
@@ -135,6 +141,7 @@
* "read": read,
* "written": written,
* "folded": folded
+ * (,"location": location)
* },
* ...
* },
@@ -150,6 +157,7 @@
* ...
* ],
* "simulated": simulated
+ * (,"object offset": offset)
* (,"value": string)
* (,"enum class": enumClass)
* (,"enum name": enumValue)
@@ -173,6 +181,8 @@
* the extension image build process and storing it in the constant. This is only done for object
* that can be created or found using a specific recipe. Some fields from those constant can then be
* relinked using the value of the hosted object.
+ *
+ * The "offset object" is the offset of the constant in the heap from the base layer.
*/
public class ImageLayerLoader {
/**
@@ -218,6 +228,8 @@ public class ImageLayerLoader {
private final ImageLayerSnapshotUtil imageLayerSnapshotUtil;
private final Map> baseLayerImageHeap = new ConcurrentHashMap<>();
protected final Map relinkedConstants = new ConcurrentHashMap<>();
+ protected final Map objectOffsets = new ConcurrentHashMap<>();
+ protected final Map fieldLocations = new ConcurrentHashMap<>();
protected final AnalysisUniverse universe;
protected AnalysisMetaAccess metaAccess;
protected HostedValuesProvider hostedValuesProvider;
@@ -559,6 +571,11 @@ public void loadFieldFlags(AnalysisField analysisField) {
return;
}
+ Integer location = get(fieldData, LOCATION_TAG);
+ if (location != null) {
+ fieldLocations.put(analysisField, location);
+ }
+
boolean isAccessed = get(fieldData, FIELD_ACCESSED_TAG);
boolean isRead = get(fieldData, FIELD_READ_TAG);
boolean isWritten = get(fieldData, FIELD_WRITTEN_TAG);
@@ -607,13 +624,14 @@ private void createConstant(EconomicMap constantsMap, String str
if (baseLayerConstant == null) {
throw GraalError.shouldNotReachHere("The constant was not reachable in the base image");
}
+ String objectOffset = get(baseLayerConstant, OBJECT_OFFSET_TAG);
String constantType = get(baseLayerConstant, CONSTANT_TYPE_TAG);
switch (constantType) {
case INSTANCE_TAG -> {
List> instanceData = get(baseLayerConstant, DATA_TAG);
ImageHeapInstance imageHeapInstance = new ImageHeapInstance(type, null);
Object[] fieldValues = getReferencedValues(imageHeapInstance, instanceData, imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess));
- addBaseLayerObject(type, id, imageHeapInstance);
+ addBaseLayerObject(type, id, imageHeapInstance, objectOffset);
imageHeapInstance.setFieldValues(fieldValues);
relinkConstant(imageHeapInstance, baseLayerConstant, type);
/*
@@ -629,14 +647,14 @@ private void createConstant(EconomicMap constantsMap, String str
List> arrayData = get(baseLayerConstant, DATA_TAG);
ImageHeapObjectArray imageHeapObjectArray = new ImageHeapObjectArray(type, null, arrayData.size());
Object[] elementsValues = getReferencedValues(imageHeapObjectArray, arrayData, Set.of());
- addBaseLayerObject(type, id, imageHeapObjectArray);
+ addBaseLayerObject(type, id, imageHeapObjectArray, objectOffset);
imageHeapObjectArray.setElementValues(elementsValues);
}
case PRIMITIVE_ARRAY_TAG -> {
List