Skip to content

Commit

Permalink
[GR-52911] Patch base layer objects offsets.
Browse files Browse the repository at this point in the history
PullRequest: graal/17531
  • Loading branch information
cstancu committed Apr 20, 2024
2 parents 0292853 + 86871c8 commit d719a13
Show file tree
Hide file tree
Showing 23 changed files with 319 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,22 @@
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;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.NEXT_METHOD_ID_TAG;
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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -135,6 +141,7 @@
* "read": read,
* "written": written,
* "folded": folded
* (,"location": location)
* },
* ...
* },
Expand All @@ -150,6 +157,7 @@
* ...
* ],
* "simulated": simulated
* (,"object offset": offset)
* (,"value": string)
* (,"enum class": enumClass)
* (,"enum name": enumValue)
Expand All @@ -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.
* <p>
* The "offset object" is the offset of the constant in the heap from the base layer.
*/
public class ImageLayerLoader {
/**
Expand Down Expand Up @@ -218,6 +228,8 @@ public class ImageLayerLoader {
private final ImageLayerSnapshotUtil imageLayerSnapshotUtil;
private final Map<AnalysisType, Set<ImageHeapConstant>> baseLayerImageHeap = new ConcurrentHashMap<>();
protected final Map<JavaConstant, ImageHeapConstant> relinkedConstants = new ConcurrentHashMap<>();
protected final Map<Integer, Long> objectOffsets = new ConcurrentHashMap<>();
protected final Map<AnalysisField, Integer> fieldLocations = new ConcurrentHashMap<>();
protected final AnalysisUniverse universe;
protected AnalysisMetaAccess metaAccess;
protected HostedValuesProvider hostedValuesProvider;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -607,13 +624,14 @@ private void createConstant(EconomicMap<String, Object> 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<List<Object>> 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);
/*
Expand All @@ -629,14 +647,14 @@ private void createConstant(EconomicMap<String, Object> constantsMap, String str
List<List<Object>> 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<Object> 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);
}
Expand Down Expand Up @@ -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<String, Object> getElementData(String registry, String elementIdentifier) {
Expand Down Expand Up @@ -899,4 +920,26 @@ public void setHostedValuesProvider(HostedValuesProvider hostedValuesProvider) {
public Set<Integer> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, Object> 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());
Expand All @@ -157,7 +160,7 @@ public void persist(AnalysisUniverse analysisUniverse, Path layerSnapshotPath, S

EconomicMap<String, EconomicMap<String, Object>> 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);

Expand All @@ -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<String, Object> jsonMap) {

}

private static void persistType(EconomicMap<String, Object> typesMap, AnalysisType type, String typeIdentifier) {
EconomicMap<String, Object> typeMap = EconomicMap.create();
typeMap.put(ID_TAG, type.getId());
Expand Down Expand Up @@ -223,14 +235,16 @@ public void persistMethod(EconomicMap<String, Object> methodsMap, AnalysisMethod
methodsMap.put(name, methodMap);
}

private static void persistField(EconomicMap<String, EconomicMap<String, Object>> fieldsMap, AnalysisField field) {
private void persistField(EconomicMap<String, EconomicMap<String, Object>> fieldsMap, AnalysisField field, Universe hostedUniverse) {
EconomicMap<String, Object> fieldMap = EconomicMap.create();
fieldMap.put(ID_TAG, field.getId());
fieldMap.put(FIELD_ACCESSED_TAG, field.getAccessedReason() != null);
fieldMap.put(FIELD_READ_TAG, field.getReadReason() != null);
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);
Expand All @@ -241,31 +255,47 @@ private static void persistField(EconomicMap<String, EconomicMap<String, Object>
}
}

/**
* A hook used to persist more field information not accessible in pointsto.
*/
@SuppressWarnings("unused")
protected void persistFieldHook(EconomicMap<String, Object> fieldMap, AnalysisField field, Universe hostedUniverse) {

}

private void persistConstant(AnalysisUniverse analysisUniverse, ImageHeapConstant imageHeapConstant, EconomicMap<String, Object> constantsMap) {
if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(imageHeapConstant.constantData.id))) {
if (imageHeapConstant.isReaderInstalled() && !constantsMap.containsKey(Integer.toString(getConstantId(imageHeapConstant)))) {
EconomicMap<String, Object> 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<String, Object> constantMap, EconomicMap<String, Object> 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<String, Object> constantMap, ImageHeapConstant imageHeapConstant, BigBang bb) {
Class<?> clazz = imageHeapConstant.getType().getJavaClass();
JavaConstant hostedObject = imageHeapConstant.getHostedObject();
Expand Down Expand Up @@ -318,7 +348,7 @@ protected void persistConstant(AnalysisUniverse analysisUniverse, EconomicMap<St
if (delegateProcessing(data, object)) {
/* The object was already persisted */
} else if (object instanceof ImageHeapConstant imageHeapConstant) {
data.add(List.of(OBJECT_TAG, imageHeapConstant.constantData.id));
data.add(List.of(OBJECT_TAG, getConstantId(imageHeapConstant)));
/*
* Some constants are not in imageHeap#reachableObjects, but are still created in
* reachable constants. They can be created in the extension image, but should not
Expand Down
Loading

0 comments on commit d719a13

Please sign in to comment.