Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GR-55192] Add support for patching prior layer heaps. #10007

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.List;

import com.oracle.graal.pointsto.PointsToAnalysis;
import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant;
import com.oracle.graal.pointsto.meta.AnalysisType;

import jdk.vm.ci.meta.JavaConstant;
Expand Down Expand Up @@ -75,6 +76,7 @@ public ConstantContextSensitiveObject(PointsToAnalysis bb, AnalysisType type) {
public ConstantContextSensitiveObject(PointsToAnalysis bb, AnalysisType type, JavaConstant constant) {
super(bb.getUniverse(), type, AnalysisObjectKind.ConstantContextSensitive);
assert bb.trackConcreteAnalysisObjects(type) : type;
assert !(constant instanceof ImageHeapRelocatableConstant) : "relocatable constants have an unknown state and should not be represented by a constant type state: " + constant;
this.constant = constant;
bb.profileConstantObject(type);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.graal.pointsto.heap;

import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.util.AnalysisError;

import jdk.vm.ci.meta.JavaConstant;

/**
* Used for layered images only. Represents a reference to an object which will be defined in a
* later layer. References to these constants will be patched at execution startup time to point to
* the corresponding object created in a subsequent layer.
*/
public final class ImageHeapRelocatableConstant extends ImageHeapConstant {

public static final class RelocatableConstantData extends ConstantData {
public final String key;

RelocatableConstantData(AnalysisType type, String key) {
super(type, null, -1);
this.key = key;
}
}

private ImageHeapRelocatableConstant(ConstantData constantData, boolean compressed) {
super(constantData, compressed);
}

@Override
public RelocatableConstantData getConstantData() {
return (RelocatableConstantData) constantData;
}

public static ImageHeapRelocatableConstant create(AnalysisType type, String key) {
var data = new RelocatableConstantData(type, key);
return new ImageHeapRelocatableConstant(data, false);
}

@Override
public JavaConstant compress() {
throw AnalysisError.shouldNotReachHere("Unsupported in ImageHeapRelocatableConstant");
}

@Override
public JavaConstant uncompress() {
throw AnalysisError.shouldNotReachHere("Unsupported in ImageHeapRelocatableConstant");
}

@Override
public ImageHeapConstant forObjectClone() {
throw AnalysisError.shouldNotReachHere("Unsupported in ImageHeapRelocatableConstant");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ private void onInstanceFieldRead(AnalysisField field, AnalysisType type) {
for (AnalysisType subtype : type.getSubTypes()) {
for (ImageHeapConstant imageHeapConstant : imageHeap.getReachableObjects(subtype)) {
FieldScan reason = new FieldScan(field, imageHeapConstant);
if (imageHeapConstant instanceof ImageHeapRelocatableConstant) {
// This constant has no contents to be scanned.
continue;
}
ImageHeapInstance imageHeapInstance = (ImageHeapInstance) imageHeapConstant;
updateInstanceField(field, imageHeapInstance, reason, null);
}
Expand Down Expand Up @@ -603,6 +607,11 @@ protected void onObjectReachable(ImageHeapConstant imageHeapConstant, ScanReason
updateInstanceField(field, imageHeapInstance, new FieldScan(field, imageHeapInstance, reason), onAnalysisModified);
}
}
} else if (imageHeapConstant instanceof ImageHeapRelocatableConstant) {
/*
* Currently we expect any type registration needed for ImageHeapRelocatableConstants to
* be manually implemented by the user.
*/
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.POSITION_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RETURN_TYPE_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RELOCATED_CONSTANT_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;
Expand Down Expand Up @@ -1098,6 +1099,10 @@ protected ImageHeapConstant getOrCreateConstant(EconomicMap<String, Object> cons
Object array = getArray(type.getComponentType().getJavaKind(), primitiveData);
addBaseLayerObject(id, objectOffset, () -> new ImageHeapPrimitiveArray(type, null, array, primitiveData.size(), identityHashCode));
}
case RELOCATED_CONSTANT_TAG -> {
String key = get(baseLayerConstant, DATA_TAG);
addBaseLayerObject(id, objectOffset, () -> ImageHeapRelocatableConstant.create(type, key));
}
default -> throw GraalError.shouldNotReachHere("Unknown constant type: " + constantType);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ public class ImageLayerSnapshotUtil {
public static final String INSTANCE_TAG = "instance";
public static final String ARRAY_TAG = "array";
public static final String PRIMITIVE_ARRAY_TAG = "primitive array";
public static final String RELOCATED_CONSTANT_TAG = "relocation constant";
public static final String FIELD_ACCESSED_TAG = "accessed";
public static final String FIELD_READ_TAG = "read";
public static final String FIELD_WRITTEN_TAG = "written";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.POSITION_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.PRIMITIVE_ARRAY_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RETURN_TYPE_TAG;
import static com.oracle.graal.pointsto.heap.ImageLayerSnapshotUtil.RELOCATED_CONSTANT_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.STRENGTHENED_GRAPH_TAG;
Expand Down Expand Up @@ -551,6 +552,10 @@ protected void persistConstant(int parentId, int index, ImageHeapConstant imageH
constantMap.put(CONSTANT_TYPE_TAG, PRIMITIVE_ARRAY_TAG);
constantMap.put(DATA_TAG, getString(imageHeapPrimitiveArray.getType().getComponentType().getJavaKind(), imageHeapPrimitiveArray.getArray()));
}
case ImageHeapRelocatableConstant relocatableConstant -> {
constantMap.put(CONSTANT_TYPE_TAG, RELOCATED_CONSTANT_TAG);
constantMap.put(DATA_TAG, relocatableConstant.getConstantData().key);
}
default -> throw AnalysisError.shouldNotReachHere("Unexpected constant type " + imageHeapConstant);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.oracle.graal.pointsto.BigBang;
import com.oracle.graal.pointsto.PointsToAnalysis;
import com.oracle.graal.pointsto.flow.context.object.AnalysisObject;
import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant;
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.util.AnalysisError;

Expand All @@ -49,6 +50,7 @@ public class ConstantTypeState extends SingleTypeState {
public ConstantTypeState(PointsToAnalysis bb, AnalysisType type, JavaConstant constant) {
super(bb, false, type);
assert !bb.analysisPolicy().isContextSensitiveAnalysis() : "The ConstantTypeState is indented to be used with a context insensitive analysis.";
assert !(constant instanceof ImageHeapRelocatableConstant) : "relocatable constants have an unknown state and should not be represented by a constant type state: " + constant;
this.constant = constant;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import com.oracle.graal.pointsto.flow.TypeFlow;
import com.oracle.graal.pointsto.flow.context.AnalysisContext;
import com.oracle.graal.pointsto.flow.context.object.AnalysisObject;
import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant;
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 @@ -129,7 +130,14 @@ public AnalysisObject createConstantObject(PointsToAnalysis bb, JavaConstant con
}

@Override
public ConstantTypeState constantTypeState(PointsToAnalysis bb, JavaConstant constant, AnalysisType exactType) {
public TypeState constantTypeState(PointsToAnalysis bb, JavaConstant constant, AnalysisType exactType) {
if (constant instanceof ImageHeapRelocatableConstant relocatableConstant) {
/*
* ImageHeapRelocatableConstants are placeholder values which will be later replaced
* with an unknown non-null object.
*/
return TypeState.forType(bb, relocatableConstant.getType(), false);
}
return new ConstantTypeState(bb, exactType, constant);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,13 @@ public class ChunkedImageHeapLayouter implements ImageHeapLayouter {
* A relocated reference is read-only once relocated, e.g., at runtime.
*/
private static final int READ_ONLY_RELOCATABLE = READ_ONLY_REGULAR + 1;
/**
* A partition holding objects which must be patched at execution startup by our initialization
* code. This is currently only used within layered images.
*/
private static final int WRITABLE_PATCHED = READ_ONLY_RELOCATABLE + 1;
/** A partition holding writable objects. */
private static final int WRITABLE_REGULAR = READ_ONLY_RELOCATABLE + 1;
private static final int WRITABLE_REGULAR = WRITABLE_PATCHED + 1;
/** A partition holding very large writable objects with or without references. */
private static final int WRITABLE_HUGE = WRITABLE_REGULAR + 1;
/**
Expand All @@ -83,6 +88,7 @@ public ChunkedImageHeapLayouter(ImageHeapInfo heapInfo, long startOffset) {
this.partitions = new ChunkedImageHeapPartition[PARTITION_COUNT];
this.partitions[READ_ONLY_REGULAR] = new ChunkedImageHeapPartition("readOnly", false, false, alignment, alignment);
this.partitions[READ_ONLY_RELOCATABLE] = new ChunkedImageHeapPartition("readOnlyRelocatable", false, false, alignment, alignment);
this.partitions[WRITABLE_PATCHED] = new ChunkedImageHeapPartition("writablePatched", true, false, alignment, alignment);
this.partitions[WRITABLE_REGULAR] = new ChunkedImageHeapPartition("writable", true, false, alignment, alignment);
this.partitions[WRITABLE_HUGE] = new ChunkedImageHeapPartition("writableHuge", true, true, alignment, alignment);
this.partitions[READ_ONLY_HUGE] = new ChunkedImageHeapPartition("readOnlyHuge", false, true, alignment, SubstrateOptions.getPageSize());
Expand All @@ -104,14 +110,16 @@ public ChunkedImageHeapPartition[] getPartitions() {
}

@Override
public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable) {
ChunkedImageHeapPartition partition = choosePartition(info, immutable, relocatable);
public void assignObjectToPartition(ImageHeapObject info, boolean immutable, boolean references, boolean relocatable, boolean patched) {
ChunkedImageHeapPartition partition = choosePartition(info, immutable, relocatable, patched);
info.setHeapPartition(partition);
partition.assign(info);
}

private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean immutable, boolean hasRelocatables) {
if (immutable) {
private ChunkedImageHeapPartition choosePartition(ImageHeapObject info, boolean immutable, boolean hasRelocatables, boolean patched) {
if (patched) {
return getWritablePatched();
} else if (immutable) {
if (hasRelocatables) {
VMError.guarantee(info.getSize() < hugeObjectThreshold, "Objects with relocatable pointers cannot be huge objects");
return getReadOnlyRelocatable();
Expand Down Expand Up @@ -177,14 +185,16 @@ private ImageHeapLayoutInfo populateInfoObjects(int dynamicHubCount, int pageSiz
}

heapInfo.initialize(getReadOnlyRegular().firstObject, getReadOnlyRegular().lastObject, getReadOnlyRelocatable().firstObject, getReadOnlyRelocatable().lastObject,
getWritablePatched().firstObject, getWritablePatched().lastObject,
getWritableRegular().firstObject, getWritableRegular().lastObject, getWritableHuge().firstObject, getWritableHuge().lastObject,
getReadOnlyHuge().firstObject, getReadOnlyHuge().lastObject, offsetOfFirstWritableAlignedChunk, offsetOfFirstWritableUnalignedChunk, offsetOfLastWritableUnalignedChunk,
dynamicHubCount);

long writableEnd = getWritableHuge().getStartOffset() + getWritableHuge().getSize();
long writableSize = writableEnd - offsetOfFirstWritableAlignedChunk;
long imageHeapSize = getReadOnlyHuge().getStartOffset() + getReadOnlyHuge().getSize() - startOffset;
return new ImageHeapLayoutInfo(startOffset, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(), imageHeapSize);
return new ImageHeapLayoutInfo(startOffset, imageHeapSize, offsetOfFirstWritableAlignedChunk, writableSize, getReadOnlyRelocatable().getStartOffset(), getReadOnlyRelocatable().getSize(),
getWritablePatched().getStartOffset(), getWritablePatched().getSize());
}

@Override
Expand Down Expand Up @@ -231,6 +241,10 @@ private ChunkedImageHeapPartition getReadOnlyRelocatable() {
return partitions[READ_ONLY_RELOCATABLE];
}

private ChunkedImageHeapPartition getWritablePatched() {
return partitions[WRITABLE_PATCHED];
}

private ChunkedImageHeapPartition getWritableRegular() {
return partitions[WRITABLE_REGULAR];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,9 @@ private boolean printLocationInfo(Log log, Pointer ptr, boolean allowJavaHeapAcc
} else if (info.isInReadOnlyRelocatablePartition(ptr)) {
log.string("points into the image heap (read-only relocatables)");
return true;
} else if (info.isInWritablePatchedPartition(ptr)) {
log.string("points into the image heap (writable patched)");
return true;
} else if (info.isInWritableRegularPartition(ptr)) {
log.string("points into the image heap (writable)");
return true;
Expand Down
Loading