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 primitiveData = get(baseLayerConstant, DATA_TAG); Object array = getArray(type.getComponentType().getJavaKind(), primitiveData); ImageHeapPrimitiveArray imageHeapPrimitiveArray = new ImageHeapPrimitiveArray(type, null, array, primitiveData.size()); - addBaseLayerObject(type, id, imageHeapPrimitiveArray); + addBaseLayerObject(type, id, imageHeapPrimitiveArray, objectOffset); } default -> throw GraalError.shouldNotReachHere("Unknown constant type: " + constantType); } @@ -844,10 +862,13 @@ private static double getDouble(Object value) { return Double.longBitsToDouble((long) value); } - private void addBaseLayerObject(AnalysisType type, int id, ImageHeapConstant heapObj) { + private void addBaseLayerObject(AnalysisType type, int id, ImageHeapConstant heapObj, String objectOffset) { heapObj.markInBaseLayer(); constants.put(id, heapObj); baseLayerImageHeap.computeIfAbsent(type, t -> ConcurrentHashMap.newKeySet()).add(heapObj); + if (objectOffset != null) { + objectOffsets.put(heapObj.constantData.id, Long.parseLong(objectOffset)); + } } private EconomicMap getElementData(String registry, String elementIdentifier) { @@ -899,4 +920,26 @@ public void setHostedValuesProvider(HostedValuesProvider hostedValuesProvider) { public Set getRelinkedFields(AnalysisType type) { return imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess); } + + public Long getObjectOffset(JavaConstant javaConstant) { + ImageHeapConstant imageHeapConstant = (ImageHeapConstant) javaConstant; + return objectOffsets.get(imageHeapConstant.constantData.id); + } + + public int getFieldLocation(AnalysisField field) { + return fieldLocations.get(field); + } + + public ImageHeapConstant getBaseLayerStaticPrimitiveFields() { + return getTaggedImageHeapConstant(STATIC_PRIMITIVE_FIELDS_TAG); + } + + public ImageHeapConstant getBaseLayerStaticObjectFields() { + return getTaggedImageHeapConstant(STATIC_OBJECT_FIELDS_TAG); + } + + private ImageHeapConstant getTaggedImageHeapConstant(String tag) { + int id = get(jsonMap, tag); + return constants.get(id); + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java index 23859733fa37..2f5ff882dc2a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java @@ -70,6 +70,7 @@ public class ImageLayerSnapshotUtil { public static final String FIELD_READ_TAG = "read"; public static final String FIELD_WRITTEN_TAG = "written"; public static final String FIELD_FOLDED_TAG = "folded"; + public static final String LOCATION_TAG = "location"; public static final String NEXT_TYPE_ID_TAG = "next type id"; public static final String NEXT_METHOD_ID_TAG = "next method id"; public static final String NEXT_FIELD_ID_TAG = "next field id"; @@ -78,6 +79,9 @@ public class ImageLayerSnapshotUtil { public static final String ENUM_NAME_TAG = "enum name"; public static final String CLASS_ID_TAG = "class id"; public static final String SIMULATED_TAG = "simulated"; + public static final String OBJECT_OFFSET_TAG = "object offset"; + public static final String STATIC_PRIMITIVE_FIELDS_TAG = "static primitive fields"; + public static final String STATIC_OBJECT_FIELDS_TAG = "static object fields"; public String getTypeIdentifier(AnalysisType type) { String javaName = type.toJavaName(true); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java index e8d3317352d1..c7b89aefcf78 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java @@ -74,6 +74,7 @@ import org.graalvm.collections.EconomicMap; import com.oracle.graal.pointsto.BigBang; +import com.oracle.graal.pointsto.infrastructure.Universe; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -128,9 +129,11 @@ protected static boolean isTypeSwitch(AnalysisType type) { return type.toJavaName().contains(TYPE_SWITCH_SUBSTRING); } - public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, String fileName, String suffix) { + public void persist(Universe hostedUniverse, AnalysisUniverse analysisUniverse, Path layerSnapshotPath, String fileName, String suffix) { EconomicMap jsonMap = EconomicMap.create(); + persistHook(hostedUniverse, analysisUniverse, jsonMap); + jsonMap.put(NEXT_TYPE_ID_TAG, analysisUniverse.getNextTypeId()); jsonMap.put(NEXT_METHOD_ID_TAG, analysisUniverse.getNextMethodId()); jsonMap.put(NEXT_FIELD_ID_TAG, analysisUniverse.getNextFieldId()); @@ -157,7 +160,7 @@ public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, S EconomicMap> fieldsMap = EconomicMap.create(); for (AnalysisField field : analysisUniverse.getFields().stream().filter(AnalysisField::isReachable).toList()) { - persistField(fieldsMap, field); + persistField(fieldsMap, field, hostedUniverse); } jsonMap.put(FIELDS_TAG, fieldsMap); @@ -172,6 +175,15 @@ public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, S FileDumpingUtil.dumpFile(layerSnapshotPath, fileName, suffix, writer -> JSONFormatter.printJSON(jsonMap, writer)); } + /** + * A hook used to persist more general information about the base layer not accessible in + * pointsto. + */ + @SuppressWarnings("unused") + protected void persistHook(Universe hostedUniverse, AnalysisUniverse analysisUniverse, EconomicMap jsonMap) { + + } + private static void persistType(EconomicMap typesMap, AnalysisType type, String typeIdentifier) { EconomicMap typeMap = EconomicMap.create(); typeMap.put(ID_TAG, type.getId()); @@ -223,7 +235,7 @@ public void persistMethod(EconomicMap methodsMap, AnalysisMethod methodsMap.put(name, methodMap); } - private static void persistField(EconomicMap> fieldsMap, AnalysisField field) { + private void persistField(EconomicMap> fieldsMap, AnalysisField field, Universe hostedUniverse) { EconomicMap fieldMap = EconomicMap.create(); fieldMap.put(ID_TAG, field.getId()); fieldMap.put(FIELD_ACCESSED_TAG, field.getAccessedReason() != null); @@ -231,6 +243,8 @@ private static void persistField(EconomicMap fieldMap.put(FIELD_WRITTEN_TAG, field.getWrittenReason() != null); fieldMap.put(FIELD_FOLDED_TAG, field.getFoldedReason() != null); + persistFieldHook(fieldMap, field, hostedUniverse); + String tid = String.valueOf(field.getDeclaringClass().getId()); if (fieldsMap.containsKey(tid)) { fieldsMap.get(tid).put(field.getName(), fieldMap); @@ -241,31 +255,47 @@ private static void persistField(EconomicMap } } + /** + * A hook used to persist more field information not accessible in pointsto. + */ + @SuppressWarnings("unused") + protected void persistFieldHook(EconomicMap fieldMap, AnalysisField field, Universe hostedUniverse) { + + } + private void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap constantsMap) { - if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(imageHeapConstant.constantData.id))) { + if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(getConstantId(imageHeapConstant)))) { EconomicMap constantMap = EconomicMap.create(); - constantsMap.put(Integer.toString(imageHeapConstant.constantData.id), constantMap); - constantMap.put(TID_TAG, imageHeapConstant.getType().getId()); - if (imageHeapConstant.hasIdentityHashCode()) { - constantMap.put(IDENTITY_HASH_CODE_TAG, imageHeapConstant.getIdentityHashCode()); - } + persistConstant(analysisUniverse, imageHeapConstant, constantMap, constantsMap); + } + } - switch (imageHeapConstant) { - case ImageHeapInstance imageHeapInstance -> { - persistConstant(analysisUniverse, constantsMap, constantMap, INSTANCE_TAG, imageHeapInstance.getFieldValues()); - persistConstantRelinkingInfo(constantMap, imageHeapConstant, analysisUniverse.getBigbang()); - } - case ImageHeapObjectArray imageHeapObjectArray -> - persistConstant(analysisUniverse, constantsMap, constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues()); - case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> { - constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG); - constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray())); - } - default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant); + protected void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap constantMap, EconomicMap constantsMap) { + constantsMap.put(Integer.toString(getConstantId(imageHeapConstant)), constantMap); + constantMap.put(TID_TAG, imageHeapConstant.getType().getId()); + if (imageHeapConstant.hasIdentityHashCode()) { + constantMap.put(IDENTITY_HASH_CODE_TAG, imageHeapConstant.getIdentityHashCode()); + } + + switch (imageHeapConstant) { + case ImageHeapInstance imageHeapInstance -> { + persistConstant(analysisUniverse, constantsMap, constantMap, INSTANCE_TAG, imageHeapInstance.getFieldValues()); + persistConstantRelinkingInfo(constantMap, imageHeapConstant, analysisUniverse.getBigbang()); + } + case ImageHeapObjectArray imageHeapObjectArray -> + persistConstant(analysisUniverse, constantsMap, constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues()); + case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> { + constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG); + constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray())); } + default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant); } } + protected int getConstantId(ImageHeapConstant imageHeapConstant) { + return imageHeapConstant.constantData.id; + } + public void persistConstantRelinkingInfo(EconomicMap constantMap, ImageHeapConstant imageHeapConstant, BigBang bb) { Class clazz = imageHeapConstant.getType().getJavaClass(); JavaConstant hostedObject = imageHeapConstant.getHostedObject(); @@ -318,7 +348,7 @@ protected void persistConstant(AnalysisUniverse analysisUniverse, EconomicMap TYPE = NodeClass.create(StaticFieldBaseNode.class); public final boolean primitive; + public final ResolvedJavaField field; /** * We must not expose that the stamp will eventually be an array, to avoid memory graph @@ -125,9 +131,16 @@ public static final class StaticFieldBaseNode extends FloatingNode implements Lo */ protected StaticFieldBaseNode(boolean primitive) { super(TYPE, StampFactory.objectNonNull()); + this.field = null; this.primitive = primitive; } + protected StaticFieldBaseNode(ResolvedJavaField field) { + super(TYPE, StampFactory.objectNonNull()); + this.field = Objects.requireNonNull(field); + this.primitive = false; // this value doesn't matter if field is not-null + } + /** * At first glance, this method looks like a circular dependency: * {@link StaticFieldsSupport#getStaticPrimitiveFields} is intrinsified to a @@ -156,8 +169,22 @@ public void lower(LoweringTool tool) { */ return; } - - JavaConstant constant = tool.getSnippetReflection().forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); + JavaConstant constant; + if (field != null) { + SharedField sharedField = (SharedField) field; + if (sharedField.isInBaseLayer()) { + constant = sharedField.getStaticFieldBase(); + } else { + /* + * Cannot check primitive flag before we know that the field is SharedField, so + * we can access the storage kind. + */ + boolean isPrimitive = sharedField.getStorageKind().isPrimitive(); + constant = tool.getSnippetReflection().forObject(isPrimitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); + } + } else { + constant = tool.getSnippetReflection().forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); + } assert constant.isNonNull() : constant; replaceAndDelete(ConstantNode.forConstant(constant, tool.getMetaAccess(), graph())); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java index 9f0d18179c10..c58cdd31a712 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateBasicLoweringProvider.java @@ -92,7 +92,6 @@ import jdk.graal.compiler.replacements.nodes.AssertionNode; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.code.TargetDescription; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; @@ -203,7 +202,7 @@ public int arrayLengthOffset() { public ValueNode staticFieldBase(StructuredGraph graph, ResolvedJavaField f) { SharedField field = (SharedField) f; assert field.isStatic(); - return graph.unique(StaticFieldsSupport.createStaticFieldBaseNode(field.getStorageKind() != JavaKind.Object)); + return graph.unique(StaticFieldsSupport.createStaticFieldBaseNode(field)); } private static ValueNode maybeUncompress(ValueNode node) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedField.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedField.java index 484eb721013c..d53d6aa498c2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedField.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedField.java @@ -26,6 +26,7 @@ import com.oracle.svm.core.StaticFieldsSupport; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; @@ -63,4 +64,9 @@ public interface SharedField extends ResolvedJavaField { boolean isValueAvailable(); JavaKind getStorageKind(); + + /** Returns true if this field is defined in a base layer. */ + boolean isInBaseLayer(); + + JavaConstant getStaticFieldBase(); } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java index fcaca720e75d..e2885e2a62ad 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java @@ -170,6 +170,16 @@ public boolean isValueAvailable() { return true; } + @Override + public boolean isInBaseLayer() { + return false; + } + + @Override + public JavaConstant getStaticFieldBase() { + throw intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport + } + @Override public String toString() { return "SubstrateField<" + format("%h.%n") + " location: " + location + ">"; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index ba2f3206f185..9f4669535d46 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -646,6 +646,8 @@ protected void doRun(Map entryPoints, JavaMainSupport j var hConstantReflection = (HostedConstantReflectionProvider) runtimeConfiguration.getProviders().getConstantReflection(); heap = new NativeImageHeap(aUniverse, hUniverse, hMetaAccess, hConstantReflection, ImageSingletons.lookup(ImageHeapLayouter.class)); + ((SVMImageLayerWriter) aUniverse.getImageLayerWriter()).setNativeImageHeap(heap); + BeforeCompilationAccessImpl beforeCompilationConfig = new BeforeCompilationAccessImpl(featureHandler, loader, aUniverse, hUniverse, heap, debug, runtimeConfiguration, nativeLibraries); featureHandler.forEachFeature(feature -> feature.beforeCompilation(beforeCompilationConfig)); @@ -697,10 +699,6 @@ protected void doRun(Map entryPoints, JavaMainSupport j buildNativeImageHeap(heap, codeCache); - if (SubstrateOptions.PersistImageLayer.getValue()) { - persistImageLayer(imageName); - } - AfterHeapLayoutAccessImpl config = new AfterHeapLayoutAccessImpl(featureHandler, loader, heap, hMetaAccess, debug); featureHandler.forEachFeature(feature -> feature.afterHeapLayout(config)); @@ -711,6 +709,11 @@ protected void doRun(Map entryPoints, JavaMainSupport j } image.build(imageName, debug); + + if (SubstrateOptions.PersistImageLayer.getValue()) { + persistImageLayer(imageName); + } + if (NativeImageOptions.PrintUniverse.getValue()) { /* * This debug output must be printed _after_ and not _during_ image @@ -790,7 +793,7 @@ private void persistImageLayer(String imageName) { String fileName = ImageLayerSnapshotUtil.FILE_NAME_PREFIX + imageName.substring(imageNameStart); String filePath = imageName.substring(0, imageNameStart) + fileName; Path layerSnapshotPath = generatedFiles(HostedOptionValues.singleton()).resolve(filePath + ImageLayerSnapshotUtil.FILE_EXTENSION); - bb.getUniverse().getImageLayerWriter().persist(bb.getUniverse(), layerSnapshotPath, fileName, ImageLayerSnapshotUtil.FILE_EXTENSION); + bb.getUniverse().getImageLayerWriter().persist(hUniverse, bb.getUniverse(), layerSnapshotPath, fileName, ImageLayerSnapshotUtil.FILE_EXTENSION); BuildArtifacts.singleton().add(ArtifactType.LAYER_SNAPSHOT, layerSnapshotPath); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java index fbaad53baafe..0a4d2c2e20d4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/CustomTypeFieldHandler.java @@ -85,7 +85,7 @@ private void injectFieldTypes(AnalysisField field, List customType injectFieldTypes(field, customTypes.toArray(new AnalysisType[0])); } - protected abstract void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes); + public abstract void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes); private List transformTypes(AnalysisField field, List> types) { List customTypes = new ArrayList<>(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java index ea9340773929..29d9edbb3146 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImagePointsToAnalysis.java @@ -118,6 +118,11 @@ public void onFieldAccessed(AnalysisField field) { customTypeFieldHandler.handleField(field); } + @Override + public void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) { + customTypeFieldHandler.injectFieldTypes(aField, customTypes); + } + @Override public void onTypeReachable(AnalysisType type) { postTask(d -> { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java index 8b2dc40e7112..03d938308dca 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/NativeImageReachabilityAnalysisEngine.java @@ -58,7 +58,7 @@ public NativeImageReachabilityAnalysisEngine(OptionValues options, AnalysisUnive this.dynamicHubInitializer = new DynamicHubInitializer(this); this.unknownFieldHandler = new CustomTypeFieldHandler(this, metaAccess) { @Override - protected void injectFieldTypes(AnalysisField aField, AnalysisType... declaredTypes) { + public void injectFieldTypes(AnalysisField aField, AnalysisType... declaredTypes) { assert aField.getJavaKind().isObject(); markFieldAccessed(aField, "@UnknownObjectField annotated field."); for (AnalysisType declaredType : declaredTypes) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java index aedf474d532e..25e369316edd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/PointsToCustomTypeFieldHandler.java @@ -41,7 +41,7 @@ public PointsToCustomTypeFieldHandler(BigBang bb, AnalysisMetaAccess metaAccess) * which are not available during analysis. */ @Override - protected void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) { + public void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) { NativeImagePointsToAnalysis analysis = (NativeImagePointsToAnalysis) bb; assert aField.getJavaKind().isObject(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java index 9d7b45593e52..90e97b5d638b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageLayerWriter.java @@ -25,7 +25,11 @@ package com.oracle.svm.hosted.heap; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.CLASS_ID_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG; import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHOD_POINTER_TAG; +import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_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 java.util.List; @@ -34,15 +38,24 @@ import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.heap.ImageHeap; +import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.heap.ImageLayerWriter; +import com.oracle.graal.pointsto.infrastructure.Universe; +import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.image.NativeImageHeap; +import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; import com.oracle.svm.hosted.lambda.StableLambdaProxyNameFeature; +import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.meta.RelocatableConstant; import com.oracle.svm.hosted.methodhandles.MethodHandleFeature; import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerSubstitutionType; @@ -55,10 +68,27 @@ import jdk.vm.ci.meta.ResolvedJavaType; public class SVMImageLayerWriter extends ImageLayerWriter { + private NativeImageHeap nativeImageHeap; + public SVMImageLayerWriter(ImageHeap imageHeap) { super(imageHeap, new SVMImageLayerSnapshotUtil()); } + public void setNativeImageHeap(NativeImageHeap nativeImageHeap) { + this.nativeImageHeap = nativeImageHeap; + } + + @Override + protected void persistHook(Universe universe, AnalysisUniverse analysisUniverse, EconomicMap jsonMap) { + HostedUniverse hostedUniverse = (HostedUniverse) universe; + + ImageHeapConstant staticPrimitiveFields = (ImageHeapConstant) hostedUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticPrimitiveFields()); + ImageHeapConstant staticObjectFields = (ImageHeapConstant) hostedUniverse.getSnippetReflection().forObject(StaticFieldsSupport.getStaticObjectFields()); + + jsonMap.put(STATIC_PRIMITIVE_FIELDS_TAG, getConstantId(staticPrimitiveFields)); + jsonMap.put(STATIC_OBJECT_FIELDS_TAG, getConstantId(staticObjectFields)); + } + @Override public void checkTypeStability(AnalysisType type) { /* @@ -101,6 +131,25 @@ private static void handleNameConflict(String message) { } } + @Override + protected void persistFieldHook(EconomicMap fieldMap, AnalysisField field, Universe universe) { + HostedUniverse hostedUniverse = (HostedUniverse) universe; + HostedField hostedField = hostedUniverse.lookup(field); + int location = hostedField.getLocation(); + if (hostedField.isStatic() && location > 0) { + fieldMap.put(LOCATION_TAG, location); + } + } + + @Override + protected void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap constantMap, EconomicMap constantsMap) { + ObjectInfo objectInfo = nativeImageHeap.getConstantInfo(imageHeapConstant); + if (objectInfo != null) { + constantMap.put(OBJECT_OFFSET_TAG, String.valueOf(objectInfo.getOffset())); + } + super.persistConstant(analysisUniverse, imageHeapConstant, constantMap, constantsMap); + } + @Override public void persistConstantRelinkingInfo(EconomicMap constantMap, BigBang bb, Class clazz, JavaConstant hostedObject) { ResolvedJavaType type = bb.getConstantReflectionProvider().asJavaType(hostedObject); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index c81dde7266ce..4c24089f007f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -37,7 +37,6 @@ import org.graalvm.collections.Pair; import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.objectfile.ObjectFile; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.config.ConfigurationValues; @@ -357,10 +356,6 @@ public void patchMethods(DebugContext debug, RelocatableBuffer relocs, ObjectFil } else if (codeAnnotation instanceof HostedImageHeapConstantPatch) { HostedImageHeapConstantPatch patch = (HostedImageHeapConstantPatch) codeAnnotation; - if (patch.constant instanceof ImageHeapConstant hc && hc.isInBaseLayer()) { - // GR-52911: use object offset in base layer heap - continue; - } ObjectInfo objectInfo = imageHeap.getConstantInfo(patch.constant); long objectAddress = objectInfo.getOffset(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index aefc17284ddc..27bae0c5ee6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -57,7 +57,6 @@ import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.BigBang; -import com.oracle.graal.pointsto.heap.ImageHeapConstant; import com.oracle.graal.pointsto.infrastructure.WrappedElement; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; @@ -682,10 +681,6 @@ protected boolean verifyMethods(DebugContext debug, HostedUniverse hUniverse, Co public void writeConstants(NativeImageHeapWriter writer, RelocatableBuffer buffer) { ByteBuffer bb = buffer.getByteBuffer(); dataSection.buildDataSection(bb, (position, constant) -> { - if (constant instanceof ImageHeapConstant hc && hc.isInBaseLayer()) { - // GR-52911: use object offset in base layer heap - return; - } writer.writeReference(buffer, position, (JavaConstant) constant, "VMConstant: " + constant); }); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index 30ae580f92db..f9c66cf9c365 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -98,6 +98,9 @@ * make any assumptions about the final layout of the image heap. */ public final class NativeImageHeap implements ImageHeap { + /** A pseudo-partition for base layer objects, see {@link BaseLayerPartition}. */ + private static final ImageHeapPartition BASE_LAYER_PARTITION = new BaseLayerPartition(); + public final AnalysisUniverse aUniverse; public final HostedUniverse hUniverse; public final HostedMetaAccess hMetaAccess; @@ -276,6 +279,7 @@ private void addStaticFields() { */ for (HostedField field : hUniverse.getFields()) { if (field.wrapped.isInBaseLayer()) { + /* Base layer static field values are accessed via the base layer arrays. */ continue; } if (Modifier.isStatic(field.getModifiers()) && field.hasLocation() && field.getType().getStorageKind() == JavaKind.Object && field.isRead()) { @@ -344,14 +348,6 @@ public void addObject(final Object original, boolean immutableFromParent, final public void addConstant(final JavaConstant constant, boolean immutableFromParent, final Object reason) { assert addObjectsPhase.isAllowed() : "Objects cannot be added at phase: " + addObjectsPhase.toString() + " with reason: " + reason; - if (constant instanceof ImageHeapConstant hc && hc.isInBaseLayer() && !hMetaAccess.isInstanceOf(constant, Class.class)) { - /* - * Skip base layer constants, but not the hubs. We need the object info in - * NativeImageHeapWriter.writeObjectHeader() - */ - return; - } - if (constant.getJavaKind().isPrimitive() || constant.isNull() || hMetaAccess.isInstanceOf(constant, WordBase.class)) { return; } @@ -540,6 +536,9 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable } info = addToImageHeap(constant, clazz, size, identityHashCode, reason); + if (processBaseLayerConstant(constant, info)) { + return; + } try { recursiveAddObject(hub, false, info); // Recursively add all the fields of the object. @@ -585,6 +584,9 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable int length = hConstantReflection.readArrayLength(constant); final long size = objectLayout.getArraySize(type.getComponentType().getStorageKind(), length, true); info = addToImageHeap(constant, clazz, size, identityHashCode, reason); + if (processBaseLayerConstant(constant, info)) { + return; + } try { recursiveAddObject(hub, false, info); if (hMetaAccess.isInstanceOf(constant, Object[].class)) { @@ -610,6 +612,21 @@ private void addObjectToImageHeap(final JavaConstant constant, boolean immutable heapLayouter.assignObjectToPartition(info, !written || immutable, references, relocatable); } + /** + * For base layer constants reuse the base layer absolute offset and assign the object to a + * pseudo-partition. We do not process this object recursively, i.e., following fields and array + * elements, we only want the JavaConstant -> ObjectInfo mapping for base layer constants that + * are reachable from regular constants in this layer. + */ + private boolean processBaseLayerConstant(JavaConstant constant, ObjectInfo info) { + if (((ImageHeapConstant) constant).isInBaseLayer()) { + info.setOffsetInPartition(aUniverse.getImageLayerLoader().getObjectOffset(constant)); + info.setHeapPartition(BASE_LAYER_PARTITION); + return true; + } + return false; + } + private static HostedType requireType(Optional optionalType, Object object, Object reason) { if (optionalType.isEmpty()) { throw reportIllegalType(object, reason, "Analysis type is missing for hosted object of " + object.getClass().getTypeName() + " class."); @@ -1009,3 +1026,26 @@ static int getByReason(Object reason, Map ad } } } + +/** + * A pseudo-partition necessary for {@link ImageHeapObject}s that refer to base layer constants, + * i.e., they are not actually written in current layer's heap. Their offset is absolute (not + * relative to a partition start offset) and is serialized from the base layer. + */ +final class BaseLayerPartition implements ImageHeapPartition { + /** Zero so that the partition-relative offsets are always absolute. */ + @Override + public long getStartOffset() { + return 0; + } + + @Override + public String getName() { + throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport + } + + @Override + public long getSize() { + throw VMError.shouldNotReachHereAtRuntime(); // ExcludeFromJacocoGeneratedReport + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 6ab683c3bcc5..787c710236d3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -96,6 +96,14 @@ public long writeHeap(DebugContext debug, RelocatableBuffer buffer) { try (Indent perHeapIndent = debug.logAndIndent("NativeImageHeap.writeHeap:")) { for (ObjectInfo info : heap.getObjects()) { assert !heap.isBlacklisted(info.getObject()); + if (info.getConstant().isInBaseLayer()) { + /* + * Base layer constants are only added to the heap model to store the absolute + * offset in the base layer heap. We don't need to actually write them; their + * absolute offset is used by the objects that reference them. + */ + continue; + } writeObject(info, buffer); } @@ -119,6 +127,7 @@ private void writeStaticFields(RelocatableBuffer buffer) { ObjectInfo objectFields = heap.getObjectInfo(StaticFieldsSupport.getStaticObjectFields()); for (HostedField field : heap.hUniverse.getFields()) { if (field.wrapped.isInBaseLayer()) { + /* Base layer static field values are accessed via the base layer arrays. */ continue; } if (Modifier.isStatic(field.getModifiers()) && field.hasLocation() && field.isRead()) { @@ -155,10 +164,6 @@ private void writeField(RelocatableBuffer buffer, ObjectInfo fields, HostedField if (value instanceof RelocatableConstant) { addNonDataRelocation(buffer, index, prepareRelocatable(info, value)); } else { - if (value instanceof ImageHeapConstant hc && hc.isInBaseLayer()) { - // GR-52911: use object offset in base layer heap - return; - } write(buffer, index, value, info != null ? info : field); } } @@ -204,10 +209,6 @@ private void writeConstant(RelocatableBuffer buffer, int index, JavaKind kind, J } else { con = constant; } - if (con instanceof ImageHeapConstant hc && hc.isInBaseLayer()) { - // GR-52911: use object offset in base layer heap - return; - } write(buffer, index, con, info); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index f13a5ef104e3..d7dc1adb5852 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -24,12 +24,16 @@ */ package com.oracle.svm.hosted.meta; +import com.oracle.graal.pointsto.heap.ImageLayerLoader; import com.oracle.graal.pointsto.infrastructure.OriginalFieldProvider; import com.oracle.graal.pointsto.infrastructure.WrappedJavaField; import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisUniverse; +import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaField; @@ -168,4 +172,20 @@ public JavaKind getStorageKind() { public ResolvedJavaField unwrapTowardsOriginalField() { return wrapped; } + + @Override + public boolean isInBaseLayer() { + return wrapped.isInBaseLayer(); + } + + @Override + public JavaConstant getStaticFieldBase() { + AnalysisUniverse universe = type.wrapped.getUniverse(); + boolean primitive = getStorageKind().isPrimitive(); + if (isInBaseLayer()) { + ImageLayerLoader imageLayerLoader = universe.getImageLayerLoader(); + return primitive ? imageLayerLoader.getBaseLayerStaticPrimitiveFields() : imageLayerLoader.getBaseLayerStaticObjectFields(); + } + return universe.getSnippetReflection().forObject(primitive ? StaticFieldsSupport.getStaticPrimitiveFields() : StaticFieldsSupport.getStaticObjectFields()); + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 67b9b8328a5a..f0d64d6ca8f1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -729,6 +729,8 @@ private void layoutStaticFields() { for (HostedField field : fields) { if (skipStaticField(field)) { // does not require memory. + } else if (field.wrapped.isInBaseLayer()) { + field.setLocation(aUniverse.getImageLayerLoader().getFieldLocation(field.wrapped)); } else if (field.getStorageKind() == JavaKind.Object) { field.setLocation(NumUtil.safeToInt(layout.getArrayElementOffset(JavaKind.Object, nextObjectField))); nextObjectField += 1; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java index f5cf838c9041..8b35c2e56b40 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java @@ -860,7 +860,7 @@ private static boolean processStaticFieldBase(GraphBuilderContext b, Receiver re /* Emits a null-check for the otherwise unused receiver. */ receiver.get(true); - b.addPush(JavaKind.Object, StaticFieldsSupport.createStaticFieldBaseNode(targetField.getType().isPrimitive())); + b.addPush(JavaKind.Object, StaticFieldsSupport.createStaticFieldBaseNode(b.getMetaAccess().lookupJavaField(targetField))); return true; }