Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
e097fa7
Assert no SubstrateObjectConstant in simulated graph.
cstancu Nov 3, 2023
e3e8f72
Allow ObjectScanner to process RelocatedPointer arrays.
cstancu Nov 13, 2023
6db561b
RelocatableConstant equality is pointer equality.
cstancu Nov 13, 2023
ee9d912
ImageHeapConstant equality is based on ImageHeapConstant.ConstantData…
cstancu Nov 13, 2023
833f389
Verify and patch relocated pointer value fields.
cstancu Nov 13, 2023
e369d6a
Static fields should be first read from the simulated values registry…
cstancu Nov 14, 2023
da352e7
Add ConstantReflectionProviderExtension for readHostedFieldValue.
cstancu Nov 13, 2023
78cd9a4
Skip simulated constants in hosted object scanner.
cstancu Nov 13, 2023
4e75621
Ensure that HostedSnippetReflectionProvider is used for replacements …
cstancu Nov 15, 2023
d2b77d0
Unwrap ImageHeapConstants in runtime compiled graphs in a custom grap…
cstancu Nov 13, 2023
5ef9495
Read immutable objects through the shadow heap.
cstancu Nov 14, 2023
10af3a6
Read hybrid fields through the shadow heap.
cstancu Nov 14, 2023
9ed07b1
Add missing unknown-field annotations.
cstancu Nov 14, 2023
1f8feef
Run last verification after ImageHeapLayoutInfo is computed.
cstancu Nov 14, 2023
754cebb
Guarantee that we only see ImageHeapConstant in AnalysisConstantRefle…
cstancu Nov 14, 2023
b7d31e0
Replace RelocatableConstant before writing it.
cstancu Nov 14, 2023
668fdc8
Process all primitive fields in the ObjectScanner.
cstancu Nov 15, 2023
8c698b8
Patch values that were set to null after shadowing.
cstancu Nov 15, 2023
06a9e75
Patch ImageHeapPrimitiveArray clone when the hosted object changes va…
cstancu Nov 15, 2023
8136476
Refactor ImageHeapConstant wrap/unwrap.
cstancu Nov 14, 2023
a077d73
Check compressed flag for ImageHeapConstant equaility.
cstancu Nov 18, 2023
c922825
Cache already converted location identity objects to avoid creating m…
cstancu Nov 18, 2023
0f871a2
Refactor HeapSnapshotVerifier.
cstancu Nov 18, 2023
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 @@ -518,7 +518,7 @@ public boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encode
recordInlinedMethods(originalGraph.isRecordingInlinedMethods()).
build();
// @formatter:off
GraphDecoder decoder = new GraphDecoder(architecture, decodedGraph);
GraphDecoder decoder = graphDecoderForVerification(decodedGraph);
decoder.decode(encodedGraph);

decodedGraph.verify();
Expand All @@ -533,6 +533,10 @@ public boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encode
}
return optimizationLogCodec.verify(originalGraph, decodedGraph) && inliningLogCodec.verify(originalGraph, decodedGraph);
}

protected GraphDecoder graphDecoderForVerification(StructuredGraph decodedGraph) {
return new GraphDecoder(architecture, decodedGraph);
}
}

class GraphComparison {
Expand Down Expand Up @@ -580,7 +584,7 @@ public static boolean verifyGraphsEqual(StructuredGraph expectedGraph, Structure
for (int i = 0; i < nodeClass.getData().getCount(); i++) {
Object expectedProperty = nodeClass.getData().get(expectedNode, i);
Object actualProperty = nodeClass.getData().get(actualNode, i);
assert Objects.equals(expectedProperty, actualProperty);
assert Objects.equals(expectedProperty, actualProperty): "Expected " + expectedProperty + ", found " + actualProperty;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@

import java.util.Objects;

import jdk.graal.compiler.nodes.util.JavaConstantFormattable;
import jdk.graal.compiler.nodes.util.JavaConstantFormatter;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.util.JavaConstantFormattable;
import jdk.graal.compiler.nodes.util.JavaConstantFormatter;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;

Expand All @@ -50,6 +50,10 @@ private ObjectLocationIdentity(JavaConstant object) {
this.object = object;
}

public JavaConstant getObject() {
return object;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof ObjectLocationIdentity) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2023, 2023, 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;

import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess;

import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaField;

public interface ConstantReflectionProviderExtension<T extends ResolvedJavaField> extends ConstantReflectionProvider {
JavaConstant readHostedFieldValue(UniverseMetaAccess access, T field, JavaConstant receiver);
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ private void execute(Runnable runnable) {
}

protected void scanEmbeddedRoot(JavaConstant root, BytecodePosition position) {
if (root instanceof ImageHeapConstant ihc && ihc.getHostedObject() == null) {
/* Skip embedded simulated constants. */
return;
}
try {
EmbeddedRootScan reason = new EmbeddedRootScan(position, root);
scanningObserver.forEmbeddedRoot(root, reason);
Expand Down Expand Up @@ -160,6 +164,11 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason
assert isUnwrapped(receiver) : receiver;

JavaConstant fieldValue = readFieldValue(field, receiver);
if (fieldValue instanceof ImageHeapConstant ihc && ihc.getHostedObject() == null) {
/* Skip reachable simulated constants. */
return;
}

if (fieldValue == null) {
StringBuilder backtrace = new StringBuilder();
buildObjectBacktrace(bb, reason, backtrace);
Expand All @@ -181,7 +190,7 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason
* referenced elements are being scanned.
*/
scanConstant(fieldValue, reason);
} else if (fieldValue.getJavaKind().isNumericInteger()) {
} else if (fieldValue.getJavaKind().isPrimitive()) {
scanningObserver.forPrimitiveFieldValue(receiver, field, fieldValue, reason);
}

Expand All @@ -190,8 +199,9 @@ protected void scanField(AnalysisField field, JavaConstant receiver, ScanReason
}
}

@SuppressWarnings("unchecked")
protected JavaConstant readFieldValue(AnalysisField field, JavaConstant receiver) {
return bb.getConstantReflectionProvider().readFieldValue(field, receiver);
return ((ConstantReflectionProviderExtension<AnalysisField>) bb.getConstantReflectionProvider()).readHostedFieldValue(bb.getMetaAccess(), field, receiver);
}

/**
Expand Down Expand Up @@ -423,7 +433,7 @@ private void doScan(WorklistEntry entry) {
scanField(field, entry.constant, entry.reason);
}
}
} else if (type.isArray() && bb.getWordTypes().asKind(type.getComponentType()) == JavaKind.Object) {
} else if (type.isArray() && type.getComponentType().getJavaKind() == JavaKind.Object) {
/* Scan the array elements. */
scanArray(entry.constant, entry.reason);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package com.oracle.graal.pointsto.heap;

import static com.oracle.graal.pointsto.ObjectScanner.ScanReason;
import static com.oracle.graal.pointsto.ObjectScanner.constantAsObject;

import java.util.Objects;
import java.util.function.Consumer;
Expand All @@ -46,6 +47,7 @@
import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionType;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;

public class HeapSnapshotVerifier {

Expand Down Expand Up @@ -144,15 +146,7 @@ public ScanningObserver() {

@Override
public boolean forRelocatedPointerFieldValue(JavaConstant receiver, AnalysisField field, JavaConstant fieldValue, ScanReason reason) {
boolean result = false;
ObjectScanningObserver scanningObserver = scanner.getScanningObserver();
if (scanningObserver != null) {
result = scanningObserver.forRelocatedPointerFieldValue(receiver, field, fieldValue, reason);
if (result) {
analysisModified = true;
}
}
return result;
return verifyFieldValue(receiver, field, fieldValue, reason);
}

@Override
Expand All @@ -162,15 +156,7 @@ public boolean forPrimitiveFieldValue(JavaConstant receiver, AnalysisField field

@Override
public boolean forNullFieldValue(JavaConstant receiver, AnalysisField field, ScanReason reason) {
boolean result = false;
ObjectScanningObserver scanningObserver = scanner.getScanningObserver();
if (scanningObserver != null) {
result = scanningObserver.forNullFieldValue(receiver, field, reason);
if (result) {
analysisModified = true;
}
}
return result;
return verifyFieldValue(receiver, field, JavaConstant.NULL_POINTER, reason);
}

@Override
Expand Down Expand Up @@ -204,8 +190,10 @@ private void verifyStaticFieldValue(TypeData typeData, AnalysisField field, Java
Consumer<ScanReason> onAnalysisModified = analysisModified(reason, format, field, unwrappedSnapshot, fieldValue);
result = scanner.patchStaticField(typeData, field, fieldValue, reason, onAnalysisModified).ensureDone();
heapPatched = true;
} else if (patchPrimitiveArrayValue(fieldSnapshot, fieldValue)) {
heapPatched = true;
}
ImageHeapScanner.ensureReaderInstalled(result);
scanner.ensureReaderInstalled(result);
}

private void verifyInstanceFieldValue(AnalysisField field, JavaConstant receiver, ImageHeapInstance receiverObject, JavaConstant fieldSnapshot, JavaConstant fieldValue, ScanReason reason) {
Expand All @@ -216,8 +204,10 @@ private void verifyInstanceFieldValue(AnalysisField field, JavaConstant receiver
Consumer<ScanReason> onAnalysisModified = analysisModified(reason, format, field, asString(receiver), unwrappedSnapshot, fieldValue);
result = scanner.patchInstanceField(receiverObject, field, fieldValue, reason, onAnalysisModified).ensureDone();
heapPatched = true;
} else if (patchPrimitiveArrayValue(fieldSnapshot, fieldValue)) {
heapPatched = true;
}
ImageHeapScanner.ensureReaderInstalled(result);
scanner.ensureReaderInstalled(result);
}

private Consumer<ScanReason> analysisModified(ScanReason reason, String format, Object... args) {
Expand All @@ -235,41 +225,71 @@ private Consumer<ScanReason> analysisModified(ScanReason reason, String format,
}

@Override
public boolean forNullArrayElement(JavaConstant array, AnalysisType arrayType, int elementIndex, ScanReason reason) {
boolean result = false;
ObjectScanningObserver scanningObserver = scanner.getScanningObserver();
if (scanningObserver != null) {
result = scanningObserver.forNullArrayElement(array, arrayType, elementIndex, reason);
if (result) {
analysisModified = true;
}
}
return result;
public boolean forNullArrayElement(JavaConstant array, AnalysisType arrayType, int index, ScanReason reason) {
return verifyArrayElementValue(JavaConstant.NULL_POINTER, index, reason, array);
}

@Override
public boolean forNonNullArrayElement(JavaConstant array, AnalysisType arrayType, JavaConstant elementValue, AnalysisType elementType, int index, ScanReason reason) {
return verifyArrayElementValue(elementValue, index, reason, array);
}

private boolean verifyArrayElementValue(JavaConstant elementValue, int index, ScanReason reason, JavaConstant array) {
ImageHeapObjectArray arrayObject = (ImageHeapObjectArray) getSnapshot(array, reason);
/*
* We don't care if an array element in the shadow heap was not yet read, i.e., the
* future is not yet materialized. This can happen with values originating from lazy
* fields that become available but may have not yet been consumed. We simply execute
* the future, then compare the produced value.
*/
ImageHeapObjectArray arrayObject = (ImageHeapObjectArray) getSnapshot(array, reason);
JavaConstant elementSnapshot = arrayObject.readElementValue(index);
verifyArrayElementValue(elementValue, index, reason, array, arrayObject, elementSnapshot);
return false;
}

private void verifyArrayElementValue(JavaConstant elementValue, int index, ScanReason reason, JavaConstant array, ImageHeapObjectArray arrayObject, JavaConstant elementSnapshot) {
JavaConstant result = elementSnapshot;
if (!Objects.equals(maybeUnwrapSnapshot(elementSnapshot, elementValue instanceof ImageHeapConstant), elementValue)) {
String format = "Value mismatch for array element at index %s of %s %n snapshot: %s %n new value: %s %n";
Consumer<ScanReason> onAnalysisModified = analysisModified(reason, format, index, asString(array), elementSnapshot, elementValue);
result = scanner.patchArrayElement(arrayObject, index, elementValue, reason, onAnalysisModified).ensureDone();
heapPatched = true;
} else if (patchPrimitiveArrayValue(elementSnapshot, elementValue)) {
heapPatched = true;
}
scanner.ensureReaderInstalled(result);
return false;
}

/**
* {@link ImageHeapPrimitiveArray} clones the original primitive array and keeps a reference
* to the original hosted object. The original hosted array can change value, so we use a
* deep equals to check element equality. This method assumes and checks that the originally
* shadowed object did not change since if that happens then the entire constant should have
* been patched instead.
*/
private boolean patchPrimitiveArrayValue(JavaConstant snapshot, JavaConstant newValue) {
if (snapshot.isNull()) {
AnalysisError.guarantee(newValue.isNull());
return false;
}
ImageHeapScanner.ensureReaderInstalled(result);
if (isPrimitiveArrayConstant(snapshot)) {
AnalysisError.guarantee(isPrimitiveArrayConstant(newValue));
Object snapshotArray = ((ImageHeapPrimitiveArray) snapshot).getArray();
Object newValueArray = constantAsObject(bb, newValue);
if (!Objects.deepEquals(snapshotArray, newValueArray)) {
/* Guarantee that the shadowed constant and the hosted constant are the same. */
AnalysisError.guarantee(bb.getConstantReflectionProvider().constantEquals(snapshot, newValue));
Integer length = bb.getConstantReflectionProvider().readArrayLength(newValue);
/* Since the shadowed constant didn't change, the length should match. */
System.arraycopy(newValueArray, 0, snapshotArray, 0, length);
return true;
}
}
return false;
}

private boolean isPrimitiveArrayConstant(JavaConstant snapshot) {
if (snapshot.getJavaKind() == JavaKind.Object) {
AnalysisType type = bb.getMetaAccess().lookupJavaType(snapshot);
return type.isArray() && type.getComponentType().getJavaKind() != JavaKind.Object;
}
return false;
}

@SuppressWarnings({"unchecked", "rawtypes"})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class ImageHeap {
* not-yet-executed {@link AnalysisFuture} of {@link ImageHeapConstant} or its results, an
* {@link ImageHeapConstant}. Not all objects in this cache are reachable.
*/
private final ConcurrentHashMap<JavaConstant, /* ImageHeapObject */ Object> objectsCache;
private final ConcurrentHashMap<JavaConstant, /* ImageHeapConstant */ Object> objectsCache;
/** Store a mapping from types to object snapshots. */
private final Map<AnalysisType, Set<ImageHeapConstant>> reachableObjects;

Expand Down Expand Up @@ -78,7 +78,7 @@ public ImageHeap() {
/** Get the constant snapshot from the cache. */
public Object getSnapshot(JavaConstant constant) {
if (constant instanceof ImageHeapConstant imageHeapConstant) {
assert imageHeapConstant.getHostedObject() == null || objectsCache.get(imageHeapConstant.getHostedObject()) == imageHeapConstant;
assert imageHeapConstant.getHostedObject() == null || objectsCache.get(imageHeapConstant.getHostedObject()).equals(imageHeapConstant);
return imageHeapConstant;
}
return objectsCache.get(constant);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,14 +257,14 @@ public boolean equals(Object o) {
* the previous behavior where the raw object was extracted and used as a key when
* constructing the image heap map.
*/
return this.constantData == other.constantData;
return this.constantData == other.constantData && this.compressed == other.compressed;
}
return false;
}

@Override
public int hashCode() {
return constantData.hashCode();
return constantData.hashCode() + (compressed ? 1 : 0);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void onFieldRead(AnalysisField field) {
AnalysisType declaringClass = field.getDeclaringClass();
if (field.isStatic()) {
if (isValueAvailable(field)) {
JavaConstant fieldValue = declaringClass.getOrComputeData().readFieldValue(field);
JavaConstant fieldValue = readStaticFieldValue(field);
markReachable(fieldValue, reason);
notifyAnalysis(field, null, fieldValue, reason);
} else if (field.canBeNull()) {
Expand Down Expand Up @@ -178,6 +178,13 @@ void markTypeInstantiated(AnalysisType type, ScanReason reason) {
universe.getBigbang().registerTypeAsInHeap(type, reason);
}

public JavaConstant getImageHeapConstant(JavaConstant constant) {
if (isNonNullObjectConstant(constant)) {
return (ImageHeapConstant) imageHeap.getSnapshot(constant);
}
return constant;
}

public JavaConstant createImageHeapConstant(JavaConstant constant, ScanReason reason) {
if (isNonNullObjectConstant(constant)) {
return getOrCreateImageHeapConstant(constant, reason);
Expand Down Expand Up @@ -527,6 +534,14 @@ protected String formatReason(String message, ScanReason reason) {
return message + ' ' + reason;
}

/**
* Redirect static fields reading. The implementors can overwrite this and provide additional
* sources for static fields values.
*/
public JavaConstant readStaticFieldValue(AnalysisField field) {
return field.getDeclaringClass().getOrComputeData().readFieldValue(field);
}

protected ValueSupplier<JavaConstant> readHostedFieldValue(AnalysisField field, JavaConstant receiver) {
// Wrap the hosted constant into a substrate constant
JavaConstant value = universe.fromHosted(constantReflection.readFieldValue(field, receiver));
Expand Down Expand Up @@ -583,8 +598,8 @@ public void rescanField(Object receiver, Field reflectionField) {
* a wrong snapshot, we need to manually ensure that the readers are installed since the
* verification will continue expanding them.
*/
static void ensureReaderInstalled(JavaConstant constant) {
if (constant.getJavaKind() == JavaKind.Object && constant.isNonNull()) {
void ensureReaderInstalled(JavaConstant constant) {
if (isNonNullObjectConstant(constant)) {
((ImageHeapConstant) constant).ensureReaderInstalled();
}
}
Expand Down Expand Up @@ -697,10 +712,6 @@ public void cleanupAfterAnalysis() {
scanningObserver = null;
}

public ObjectScanningObserver getScanningObserver() {
return scanningObserver;
}

protected abstract Class<?> getClass(String className);

protected AnalysisType lookupJavaType(String className) {
Expand Down
Loading