Skip to content

Commit d719a13

Browse files
committed
[GR-52911] Patch base layer objects offsets.
PullRequest: graal/17531
2 parents 0292853 + 86871c8 commit d719a13

23 files changed

+319
-65
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/BigBang.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ default boolean isCallAllowed(PointsToAnalysis bb, AnalysisMethod caller, Analys
108108
default void onFieldAccessed(AnalysisField field) {
109109
}
110110

111+
@SuppressWarnings("unused")
112+
default void injectFieldTypes(AnalysisField aField, AnalysisType... customTypes) {
113+
}
114+
111115
@SuppressWarnings("unused")
112116
default void onTypeInstantiated(AnalysisType type, UsageKind usageKind) {
113117
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ protected void scanEmbeddedRoot(JavaConstant root, Object position) {
156156
* @param field the scanned root field
157157
*/
158158
protected final void scanRootField(AnalysisField field) {
159+
if (field.isInBaseLayer()) {
160+
// skip base layer roots
161+
return;
162+
}
159163
scanField(field, null, null);
160164
}
161165

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageHeapScanner.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ public void onFieldRead(AnalysisField field) {
130130
AnalysisType declaringClass = field.getDeclaringClass();
131131
if (field.isStatic()) {
132132
FieldScan reason = new FieldScan(field);
133+
if (field.isInBaseLayer()) {
134+
/*
135+
* For base layer static fields we don't want to scan the constant value, but
136+
* instead inject its type state in the field flow. This will be propagated to any
137+
* corresponding field loads.
138+
*
139+
* GR-52421: the field state needs to be serialized from the base layer analysis
140+
*/
141+
if (field.getJavaKind().isObject()) {
142+
AnalysisType fieldType = field.getType();
143+
if (fieldType.isArray() || (fieldType.isInstanceClass() && !fieldType.isAbstract())) {
144+
fieldType.registerAsInHeap(field);
145+
}
146+
bb.injectFieldTypes(field, fieldType);
147+
}
148+
return;
149+
}
133150
if (isValueAvailable(field)) {
134151
JavaConstant fieldValue = readStaticFieldValue(field);
135152
markReachable(fieldValue, reason);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerLoader.java

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,22 @@
4646
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INITIALIZED_TAG;
4747
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_INTERFACE_TAG;
4848
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.IS_LINKED_TAG;
49+
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.LOCATION_TAG;
4950
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.METHODS_TAG;
5051
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.MODIFIERS_TAG;
5152
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_FIELD_ID_TAG;
5253
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_METHOD_ID_TAG;
5354
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_TYPE_ID_TAG;
5455
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NOT_MATERIALIZED_CONSTANT;
5556
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NULL_POINTER_CONSTANT;
57+
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_OFFSET_TAG;
5658
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.OBJECT_TAG;
5759
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PERSISTED;
5860
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG;
5961
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SIMULATED_TAG;
6062
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SOURCE_FILE_NAME_TAG;
63+
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.STATIC_OBJECT_FIELDS_TAG;
64+
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.STATIC_PRIMITIVE_FIELDS_TAG;
6165
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.SUPER_CLASS_TAG;
6266
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TID_TAG;
6367
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.TYPES_TAG;
@@ -102,6 +106,8 @@
102106
* "next type id": nextTypeId,
103107
* "next method id": nextMethodId,
104108
* "next field id": nextFieldId,
109+
* "static primitive fields": staticPrimitiveFields.id,
110+
* "static object fields": staticObjectFields.id,
105111
* "types": {
106112
* typeIdentifier: {
107113
* "id": id,
@@ -135,6 +141,7 @@
135141
* "read": read,
136142
* "written": written,
137143
* "folded": folded
144+
* (,"location": location)
138145
* },
139146
* ...
140147
* },
@@ -150,6 +157,7 @@
150157
* ...
151158
* ],
152159
* "simulated": simulated
160+
* (,"object offset": offset)
153161
* (,"value": string)
154162
* (,"enum class": enumClass)
155163
* (,"enum name": enumValue)
@@ -173,6 +181,8 @@
173181
* the extension image build process and storing it in the constant. This is only done for object
174182
* that can be created or found using a specific recipe. Some fields from those constant can then be
175183
* relinked using the value of the hosted object.
184+
* <p>
185+
* The "offset object" is the offset of the constant in the heap from the base layer.
176186
*/
177187
public class ImageLayerLoader {
178188
/**
@@ -218,6 +228,8 @@ public class ImageLayerLoader {
218228
private final ImageLayerSnapshotUtil imageLayerSnapshotUtil;
219229
private final Map<AnalysisType, Set<ImageHeapConstant>> baseLayerImageHeap = new ConcurrentHashMap<>();
220230
protected final Map<JavaConstant, ImageHeapConstant> relinkedConstants = new ConcurrentHashMap<>();
231+
protected final Map<Integer, Long> objectOffsets = new ConcurrentHashMap<>();
232+
protected final Map<AnalysisField, Integer> fieldLocations = new ConcurrentHashMap<>();
221233
protected final AnalysisUniverse universe;
222234
protected AnalysisMetaAccess metaAccess;
223235
protected HostedValuesProvider hostedValuesProvider;
@@ -559,6 +571,11 @@ public void loadFieldFlags(AnalysisField analysisField) {
559571
return;
560572
}
561573

574+
Integer location = get(fieldData, LOCATION_TAG);
575+
if (location != null) {
576+
fieldLocations.put(analysisField, location);
577+
}
578+
562579
boolean isAccessed = get(fieldData, FIELD_ACCESSED_TAG);
563580
boolean isRead = get(fieldData, FIELD_READ_TAG);
564581
boolean isWritten = get(fieldData, FIELD_WRITTEN_TAG);
@@ -607,13 +624,14 @@ private void createConstant(EconomicMap<String, Object> constantsMap, String str
607624
if (baseLayerConstant == null) {
608625
throw GraalError.shouldNotReachHere("The constant was not reachable in the base image");
609626
}
627+
String objectOffset = get(baseLayerConstant, OBJECT_OFFSET_TAG);
610628
String constantType = get(baseLayerConstant, CONSTANT_TYPE_TAG);
611629
switch (constantType) {
612630
case INSTANCE_TAG -> {
613631
List<List<Object>> instanceData = get(baseLayerConstant, DATA_TAG);
614632
ImageHeapInstance imageHeapInstance = new ImageHeapInstance(type, null);
615633
Object[] fieldValues = getReferencedValues(imageHeapInstance, instanceData, imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess));
616-
addBaseLayerObject(type, id, imageHeapInstance);
634+
addBaseLayerObject(type, id, imageHeapInstance, objectOffset);
617635
imageHeapInstance.setFieldValues(fieldValues);
618636
relinkConstant(imageHeapInstance, baseLayerConstant, type);
619637
/*
@@ -629,14 +647,14 @@ private void createConstant(EconomicMap<String, Object> constantsMap, String str
629647
List<List<Object>> arrayData = get(baseLayerConstant, DATA_TAG);
630648
ImageHeapObjectArray imageHeapObjectArray = new ImageHeapObjectArray(type, null, arrayData.size());
631649
Object[] elementsValues = getReferencedValues(imageHeapObjectArray, arrayData, Set.of());
632-
addBaseLayerObject(type, id, imageHeapObjectArray);
650+
addBaseLayerObject(type, id, imageHeapObjectArray, objectOffset);
633651
imageHeapObjectArray.setElementValues(elementsValues);
634652
}
635653
case PRIMITIVE_ARRAY_TAG -> {
636654
List<Object> primitiveData = get(baseLayerConstant, DATA_TAG);
637655
Object array = getArray(type.getComponentType().getJavaKind(), primitiveData);
638656
ImageHeapPrimitiveArray imageHeapPrimitiveArray = new ImageHeapPrimitiveArray(type, null, array, primitiveData.size());
639-
addBaseLayerObject(type, id, imageHeapPrimitiveArray);
657+
addBaseLayerObject(type, id, imageHeapPrimitiveArray, objectOffset);
640658
}
641659
default -> throw GraalError.shouldNotReachHere("Unknown constant type: " + constantType);
642660
}
@@ -844,10 +862,13 @@ private static double getDouble(Object value) {
844862
return Double.longBitsToDouble((long) value);
845863
}
846864

847-
private void addBaseLayerObject(AnalysisType type, int id, ImageHeapConstant heapObj) {
865+
private void addBaseLayerObject(AnalysisType type, int id, ImageHeapConstant heapObj, String objectOffset) {
848866
heapObj.markInBaseLayer();
849867
constants.put(id, heapObj);
850868
baseLayerImageHeap.computeIfAbsent(type, t -> ConcurrentHashMap.newKeySet()).add(heapObj);
869+
if (objectOffset != null) {
870+
objectOffsets.put(heapObj.constantData.id, Long.parseLong(objectOffset));
871+
}
851872
}
852873

853874
private EconomicMap<String, Object> getElementData(String registry, String elementIdentifier) {
@@ -899,4 +920,26 @@ public void setHostedValuesProvider(HostedValuesProvider hostedValuesProvider) {
899920
public Set<Integer> getRelinkedFields(AnalysisType type) {
900921
return imageLayerSnapshotUtil.getRelinkedFields(type, metaAccess);
901922
}
923+
924+
public Long getObjectOffset(JavaConstant javaConstant) {
925+
ImageHeapConstant imageHeapConstant = (ImageHeapConstant) javaConstant;
926+
return objectOffsets.get(imageHeapConstant.constantData.id);
927+
}
928+
929+
public int getFieldLocation(AnalysisField field) {
930+
return fieldLocations.get(field);
931+
}
932+
933+
public ImageHeapConstant getBaseLayerStaticPrimitiveFields() {
934+
return getTaggedImageHeapConstant(STATIC_PRIMITIVE_FIELDS_TAG);
935+
}
936+
937+
public ImageHeapConstant getBaseLayerStaticObjectFields() {
938+
return getTaggedImageHeapConstant(STATIC_OBJECT_FIELDS_TAG);
939+
}
940+
941+
private ImageHeapConstant getTaggedImageHeapConstant(String tag) {
942+
int id = get(jsonMap, tag);
943+
return constants.get(id);
944+
}
902945
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerSnapshotUtil.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public class ImageLayerSnapshotUtil {
7070
public static final String FIELD_READ_TAG = "read";
7171
public static final String FIELD_WRITTEN_TAG = "written";
7272
public static final String FIELD_FOLDED_TAG = "folded";
73+
public static final String LOCATION_TAG = "location";
7374
public static final String NEXT_TYPE_ID_TAG = "next type id";
7475
public static final String NEXT_METHOD_ID_TAG = "next method id";
7576
public static final String NEXT_FIELD_ID_TAG = "next field id";
@@ -78,6 +79,9 @@ public class ImageLayerSnapshotUtil {
7879
public static final String ENUM_NAME_TAG = "enum name";
7980
public static final String CLASS_ID_TAG = "class id";
8081
public static final String SIMULATED_TAG = "simulated";
82+
public static final String OBJECT_OFFSET_TAG = "object offset";
83+
public static final String STATIC_PRIMITIVE_FIELDS_TAG = "static primitive fields";
84+
public static final String STATIC_OBJECT_FIELDS_TAG = "static object fields";
8185

8286
public String getTypeIdentifier(AnalysisType type) {
8387
String javaName = type.toJavaName(true);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/ImageLayerWriter.java

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import org.graalvm.collections.EconomicMap;
7575

7676
import com.oracle.graal.pointsto.BigBang;
77+
import com.oracle.graal.pointsto.infrastructure.Universe;
7778
import com.oracle.graal.pointsto.meta.AnalysisField;
7879
import com.oracle.graal.pointsto.meta.AnalysisMethod;
7980
import com.oracle.graal.pointsto.meta.AnalysisType;
@@ -128,9 +129,11 @@ protected static boolean isTypeSwitch(AnalysisType type) {
128129
return type.toJavaName().contains(TYPE_SWITCH_SUBSTRING);
129130
}
130131

131-
public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, String fileName, String suffix) {
132+
public void persist(Universe hostedUniverse, AnalysisUniverse analysisUniverse, Path layerSnapshotPath, String fileName, String suffix) {
132133
EconomicMap<String, Object> jsonMap = EconomicMap.create();
133134

135+
persistHook(hostedUniverse, analysisUniverse, jsonMap);
136+
134137
jsonMap.put(NEXT_TYPE_ID_TAG, analysisUniverse.getNextTypeId());
135138
jsonMap.put(NEXT_METHOD_ID_TAG, analysisUniverse.getNextMethodId());
136139
jsonMap.put(NEXT_FIELD_ID_TAG, analysisUniverse.getNextFieldId());
@@ -157,7 +160,7 @@ public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, S
157160

158161
EconomicMap<String, EconomicMap<String, Object>> fieldsMap = EconomicMap.create();
159162
for (AnalysisField field : analysisUniverse.getFields().stream().filter(AnalysisField::isReachable).toList()) {
160-
persistField(fieldsMap, field);
163+
persistField(fieldsMap, field, hostedUniverse);
161164
}
162165
jsonMap.put(FIELDS_TAG, fieldsMap);
163166

@@ -172,6 +175,15 @@ public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, S
172175
FileDumpingUtil.dumpFile(layerSnapshotPath, fileName, suffix, writer -> JSONFormatter.printJSON(jsonMap, writer));
173176
}
174177

178+
/**
179+
* A hook used to persist more general information about the base layer not accessible in
180+
* pointsto.
181+
*/
182+
@SuppressWarnings("unused")
183+
protected void persistHook(Universe hostedUniverse, AnalysisUniverse analysisUniverse, EconomicMap<String, Object> jsonMap) {
184+
185+
}
186+
175187
private static void persistType(EconomicMap<String, Object> typesMap, AnalysisType type, String typeIdentifier) {
176188
EconomicMap<String, Object> typeMap = EconomicMap.create();
177189
typeMap.put(ID_TAG, type.getId());
@@ -223,14 +235,16 @@ public void persistMethod(EconomicMap<String, Object> methodsMap, AnalysisMethod
223235
methodsMap.put(name, methodMap);
224236
}
225237

226-
private static void persistField(EconomicMap<String, EconomicMap<String, Object>> fieldsMap, AnalysisField field) {
238+
private void persistField(EconomicMap<String, EconomicMap<String, Object>> fieldsMap, AnalysisField field, Universe hostedUniverse) {
227239
EconomicMap<String, Object> fieldMap = EconomicMap.create();
228240
fieldMap.put(ID_TAG, field.getId());
229241
fieldMap.put(FIELD_ACCESSED_TAG, field.getAccessedReason() != null);
230242
fieldMap.put(FIELD_READ_TAG, field.getReadReason() != null);
231243
fieldMap.put(FIELD_WRITTEN_TAG, field.getWrittenReason() != null);
232244
fieldMap.put(FIELD_FOLDED_TAG, field.getFoldedReason() != null);
233245

246+
persistFieldHook(fieldMap, field, hostedUniverse);
247+
234248
String tid = String.valueOf(field.getDeclaringClass().getId());
235249
if (fieldsMap.containsKey(tid)) {
236250
fieldsMap.get(tid).put(field.getName(), fieldMap);
@@ -241,31 +255,47 @@ private static void persistField(EconomicMap<String, EconomicMap<String, Object>
241255
}
242256
}
243257

258+
/**
259+
* A hook used to persist more field information not accessible in pointsto.
260+
*/
261+
@SuppressWarnings("unused")
262+
protected void persistFieldHook(EconomicMap<String, Object> fieldMap, AnalysisField field, Universe hostedUniverse) {
263+
264+
}
265+
244266
private void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap<String, Object> constantsMap) {
245-
if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(imageHeapConstant.constantData.id))) {
267+
if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(getConstantId(imageHeapConstant)))) {
246268
EconomicMap<String, Object> constantMap = EconomicMap.create();
247-
constantsMap.put(Integer.toString(imageHeapConstant.constantData.id), constantMap);
248-
constantMap.put(TID_TAG, imageHeapConstant.getType().getId());
249-
if (imageHeapConstant.hasIdentityHashCode()) {
250-
constantMap.put(IDENTITY_HASH_CODE_TAG, imageHeapConstant.getIdentityHashCode());
251-
}
269+
persistConstant(analysisUniverse, imageHeapConstant, constantMap, constantsMap);
270+
}
271+
}
252272

253-
switch (imageHeapConstant) {
254-
case ImageHeapInstance imageHeapInstance -> {
255-
persistConstant(analysisUniverse, constantsMap, constantMap, INSTANCE_TAG, imageHeapInstance.getFieldValues());
256-
persistConstantRelinkingInfo(constantMap, imageHeapConstant, analysisUniverse.getBigbang());
257-
}
258-
case ImageHeapObjectArray imageHeapObjectArray ->
259-
persistConstant(analysisUniverse, constantsMap, constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues());
260-
case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> {
261-
constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG);
262-
constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray()));
263-
}
264-
default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant);
273+
protected void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap<String, Object> constantMap, EconomicMap<String, Object> constantsMap) {
274+
constantsMap.put(Integer.toString(getConstantId(imageHeapConstant)), constantMap);
275+
constantMap.put(TID_TAG, imageHeapConstant.getType().getId());
276+
if (imageHeapConstant.hasIdentityHashCode()) {
277+
constantMap.put(IDENTITY_HASH_CODE_TAG, imageHeapConstant.getIdentityHashCode());
278+
}
279+
280+
switch (imageHeapConstant) {
281+
case ImageHeapInstance imageHeapInstance -> {
282+
persistConstant(analysisUniverse, constantsMap, constantMap, INSTANCE_TAG, imageHeapInstance.getFieldValues());
283+
persistConstantRelinkingInfo(constantMap, imageHeapConstant, analysisUniverse.getBigbang());
284+
}
285+
case ImageHeapObjectArray imageHeapObjectArray ->
286+
persistConstant(analysisUniverse, constantsMap, constantMap, ARRAY_TAG, imageHeapObjectArray.getElementValues());
287+
case ImageHeapPrimitiveArray imageHeapPrimitiveArray -> {
288+
constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG);
289+
constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray()));
265290
}
291+
default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant);
266292
}
267293
}
268294

295+
protected int getConstantId(ImageHeapConstant imageHeapConstant) {
296+
return imageHeapConstant.constantData.id;
297+
}
298+
269299
public void persistConstantRelinkingInfo(EconomicMap<String, Object> constantMap, ImageHeapConstant imageHeapConstant, BigBang bb) {
270300
Class<?> clazz = imageHeapConstant.getType().getJavaClass();
271301
JavaConstant hostedObject = imageHeapConstant.getHostedObject();
@@ -318,7 +348,7 @@ protected void persistConstant(AnalysisUniverse analysisUniverse, EconomicMap<St
318348
if (delegateProcessing(data, object)) {
319349
/* The object was already persisted */
320350
} else if (object instanceof ImageHeapConstant imageHeapConstant) {
321-
data.add(List.of(OBJECT_TAG, imageHeapConstant.constantData.id));
351+
data.add(List.of(OBJECT_TAG, getConstantId(imageHeapConstant)));
322352
/*
323353
* Some constants are not in imageHeap#reachableObjects, but are still created in
324354
* reachable constants. They can be created in the extension image, but should not

0 commit comments

Comments
 (0)