package com.oracle.svm.core.genscavenge;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.replacements.ReplacementsUtil;
import org.graalvm.compiler.word.ObjectAccess;
import org.graalvm.compiler.word.Word;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.word.LocationIdentity;
import org.graalvm.word.Pointer;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordBase;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.SubstrateOptions;
import com.oracle.svm.core.annotate.Uninterruptible;
import com.oracle.svm.core.config.ConfigurationValues;
import com.oracle.svm.core.config.ObjectLayout;
import com.oracle.svm.core.heap.Heap;
import com.oracle.svm.core.heap.ObjectHeader;
import com.oracle.svm.core.heap.ReferenceAccess;
import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.image.ImageHeapObject;
import com.oracle.svm.core.snippets.KnownIntrinsics;
import com.oracle.svm.core.util.VMError;
public final class extends ObjectHeader {
private static final UnsignedWord = WordFactory.unsigned(0b001);
private static final UnsignedWord = WordFactory.unsigned(0b010);
private static final UnsignedWord = WordFactory.unsigned(0b100);
private static final int = 0b111;
private static final UnsignedWord = WordFactory.unsigned(RESERVED_BITS_MASK);
private static final UnsignedWord = MASK_HEADER_BITS.not();
@Platforms(Platform.HOSTED_ONLY.class)
() {
}
@Fold
public static ObjectHeaderImpl () {
ObjectHeaderImpl oh = HeapImpl.getHeapImpl().getObjectHeaderImpl();
assert oh != null;
return oh;
}
@Override
public int () {
assert MASK_HEADER_BITS.rawValue() == RESERVED_BITS_MASK;
assert CLEAR_HEADER_BITS.rawValue() == ~RESERVED_BITS_MASK;
return RESERVED_BITS_MASK;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static UnsignedWord (Pointer objectPointer) {
if (getReferenceSize() == Integer.BYTES) {
return WordFactory.unsigned(objectPointer.readInt(getHubOffset()));
} else {
return objectPointer.readWord(getHubOffset());
}
}
public static UnsignedWord (Pointer p) {
VMError.guarantee(!p.isNull(), "ObjectHeader.readHeaderFromPointerCarefully: p: null");
if (!ReferenceAccess.singleton().haveCompressedReferences()) {
VMError.guarantee(p.notEqual(HeapPolicy.getProducedHeapChunkZapWord()), "ObjectHeader.readHeaderFromPointerCarefully: p: producedZapValue");
VMError.guarantee(p.notEqual(HeapPolicy.getConsumedHeapChunkZapWord()), "ObjectHeader.readHeaderFromPointerCarefully: p: consumedZapValue");
}
UnsignedWord header = readHeaderFromPointer(p);
VMError.guarantee(header.notEqual(WordFactory.zero()), "ObjectHeader.readHeaderFromPointerCarefully: header: 0");
VMError.guarantee(!isProducedHeapChunkZapped(header), "ObjectHeader.readHeaderFromPointerCarefully: header: producedZapValue");
VMError.guarantee(!isConsumedHeapChunkZapped(header), "ObjectHeader.readHeaderFromPointerCarefully: header: consumedZapValue");
return header;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static UnsignedWord (Object o) {
if (getReferenceSize() == Integer.BYTES) {
return WordFactory.unsigned(ObjectAccess.readInt(o, getHubOffset()));
} else {
return ObjectAccess.readWord(o, getHubOffset());
}
}
public static UnsignedWord (Object o) {
VMError.guarantee(o != null, "ObjectHeader.readHeaderFromObjectCarefully: o: null");
UnsignedWord header = readHeaderFromObject(o);
VMError.guarantee(header.notEqual(WordFactory.zero()), "ObjectHeader.readHeaderFromObjectCarefully: header: 0");
VMError.guarantee(!isProducedHeapChunkZapped(header), "ObjectHeader.readHeaderFromObjectCarefully: header: producedZapValue");
VMError.guarantee(!isConsumedHeapChunkZapped(header), "ObjectHeader.readHeaderFromObjectCarefully: header: consumedZapValue");
return header;
}
@Override
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public DynamicHub (Pointer ptr) {
UnsignedWord header = readHeaderFromPointer(ptr);
return dynamicHubFromObjectHeader(header);
}
public static DynamicHub (Object o) {
readHeaderFromObjectCarefully(o);
return KnownIntrinsics.readHub(o);
}
@Override
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public DynamicHub (UnsignedWord header) {
UnsignedWord pointerBits = clearBits(header);
Object objectValue;
ReferenceAccess referenceAccess = ReferenceAccess.singleton();
if (referenceAccess.haveCompressedReferences()) {
UnsignedWord compressedBits = pointerBits.unsignedShiftRight(getCompressionShift());
objectValue = referenceAccess.uncompressReference(compressedBits);
} else {
objectValue = ((Pointer) pointerBits).toObject();
}
return KnownIntrinsics.convertUnknownValue(objectValue, DynamicHub.class);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@Override
public Word (DynamicHub hub) {
return encodeAsObjectHeader(hub, false, false);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
@Override
public void (Pointer objectPointer, Word encodedHub) {
if (getReferenceSize() == Integer.BYTES) {
dynamicAssert(getIdentityHashCodeOffset() == getHubOffset() + 4, "assumed layout to optimize initializing write");
dynamicAssert(encodedHub.and(WordFactory.unsigned(0xFFFFFFFF00000000L)).isNull(), "hub can only use 32 bit");
objectPointer.writeLong(getHubOffset(), encodedHub.rawValue(), LocationIdentity.INIT_LOCATION);
} else {
objectPointer.writeWord(getHubOffset(), encodedHub, LocationIdentity.INIT_LOCATION);
objectPointer.writeInt(getIdentityHashCodeOffset(), 0, LocationIdentity.INIT_LOCATION);
}
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
private static void (boolean condition, String msg) {
if (GraalDirectives.inIntrinsic()) {
ReplacementsUtil.dynamicAssert(condition, msg);
} else {
assert condition : msg;
}
}
private static void (Object o, WordBase header) {
if (getReferenceSize() == Integer.BYTES) {
ObjectAccess.writeInt(o, getHubOffset(), (int) header.rawValue());
} else {
ObjectAccess.writeWord(o, getHubOffset(), header);
}
}
@Override
public Word (DynamicHub hub) {
return encodeAsObjectHeader(hub, false, false);
}
@Uninterruptible(reason = "Called from uninterruptible code.")
public static Word (DynamicHub hub, boolean rememberedSet, boolean unaligned) {
Word result = Word.objectToUntrackedPointer(hub);
if (SubstrateOptions.SpawnIsolates.getValue()) {
if (hasBase()) {
result = result.subtract(KnownIntrinsics.heapBase());
}
}
if (rememberedSet) {
result = result.or(REMEMBERED_SET_BIT);
}
if (unaligned) {
result = result.or(UNALIGNED_BIT);
}
return result;
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static UnsignedWord (UnsignedWord header) {
return header.and(CLEAR_HEADER_BITS);
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static boolean (UnsignedWord header) {
if (getReferenceSize() == Integer.BYTES) {
return header.equal(HeapPolicy.getProducedHeapChunkZapInt());
} else {
return header.equal(HeapPolicy.getProducedHeapChunkZapWord());
}
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
public static boolean (UnsignedWord header) {
if (getReferenceSize() == Integer.BYTES) {
return header.equal(HeapPolicy.getConsumedHeapChunkZapInt());
} else {
return header.equal(HeapPolicy.getConsumedHeapChunkZapWord());
}
}
@Override
public long (ImageHeapObject obj, long hubOffsetFromHeapBase) {
long header = hubOffsetFromHeapBase;
assert (header & MASK_HEADER_BITS.rawValue()) == 0 : "Object header bits must be zero initially";
if (HeapImpl.usesImageHeapCardMarking()) {
if (obj.getPartition() instanceof ChunkedImageHeapPartition) {
ChunkedImageHeapPartition partition = (ChunkedImageHeapPartition) obj.getPartition();
if (partition.isWritable()) {
header |= REMEMBERED_SET_BIT.rawValue();
}
if (partition.usesUnalignedObjects()) {
header |= UNALIGNED_BIT.rawValue();
}
} else {
assert obj.getPartition() instanceof FillerObjectDummyPartition;
}
}
return header;
}
public static boolean (Object o) {
return !isUnalignedObject(o);
}
public static boolean (Object obj, UnsignedWord header) {
return !isUnalignedHeader(obj, header);
}
public static boolean (Pointer ptrToObj, UnsignedWord header) {
return !isUnalignedHeader(ptrToObj, header);
}
public static boolean (UnsignedWord header) {
return !testUnalignedBit(header);
}
public static boolean (Object obj) {
assert !HeapImpl.getHeapImpl().isInImageHeap(obj) : "must not be called for image heap objects";
UnsignedWord header = ObjectHeaderImpl.readHeaderFromObject(obj);
return testUnalignedBit(header);
}
public static boolean (Object obj, UnsignedWord header) {
assert !HeapImpl.getHeapImpl().isInImageHeap(obj) : "must not be called for image heap objects";
return testUnalignedBit(header);
}
public static boolean (Pointer ptrToObj, UnsignedWord header) {
assert !HeapImpl.getHeapImpl().isInImageHeap(ptrToObj) : "must not be called for image heap objects";
return testUnalignedBit(header);
}
private static boolean (UnsignedWord header) {
return header.and(UNALIGNED_BIT).notEqual(0);
}
static void (Object o) {
UnsignedWord oldHeader = readHeaderFromObject(o);
UnsignedWord newHeader = oldHeader.or(REMEMBERED_SET_BIT);
writeHeaderToObject(o, newHeader);
}
public static boolean (UnsignedWord header) {
return header.and(REMEMBERED_SET_BIT).notEqual(0);
}
public static boolean (Pointer p) {
UnsignedWord header = readHeaderFromPointer(p);
return isForwardedHeader(header);
}
public static boolean (Pointer p) {
UnsignedWord header = readHeaderFromPointerCarefully(p);
return isForwardedHeaderCarefully(header);
}
public static boolean (UnsignedWord header) {
return testForwardedHeaderBit(header);
}
public static boolean (UnsignedWord header) {
UnsignedWord headerBits = ObjectHeaderImpl.getHeaderBitsFromHeaderCarefully(header);
return testForwardedHeaderBit(headerBits);
}
private static boolean (UnsignedWord headerBits) {
return headerBits.and(FORWARDED_BIT).notEqual(0);
}
static Object (Pointer ptr) {
UnsignedWord header = readHeaderFromPointer(ptr);
assert isForwardedHeader(header);
if (ReferenceAccess.singleton().haveCompressedReferences()) {
if (ReferenceAccess.singleton().getCompressEncoding().hasShift()) {
ObjectLayout layout = ConfigurationValues.getObjectLayout();
assert layout.isAligned(getHubOffset()) && (2 * getReferenceSize()) <= layout.getAlignment() : "Forwarding reference must fit after hub";
int forwardRefOffset = getHubOffset() + getReferenceSize();
return ReferenceAccess.singleton().readObjectAt(ptr.add(forwardRefOffset), true);
} else {
return ReferenceAccess.singleton().uncompressReference(clearBits(header));
}
} else {
return ((Pointer) clearBits(header)).toObject();
}
}
static void (Object original, Object copy) {
assert !isPointerToForwardedObject(Word.objectToUntrackedPointer(original));
UnsignedWord forwardHeader;
if (ReferenceAccess.singleton().haveCompressedReferences()) {
if (ReferenceAccess.singleton().getCompressEncoding().hasShift()) {
forwardHeader = WordFactory.unsigned(0xf0f0f0f0f0f0f0f0L);
ObjectAccess.writeObject(original, getHubOffset() + getReferenceSize(), copy);
} else {
forwardHeader = ReferenceAccess.singleton().getCompressedRepresentation(copy);
}
} else {
forwardHeader = Word.objectToUntrackedPointer(copy);
}
assert ObjectHeaderImpl.getHeaderBitsFromHeader(forwardHeader).equal(0);
writeHeaderToObject(original, forwardHeader.or(FORWARDED_BIT));
assert isPointerToForwardedObject(Word.objectToUntrackedPointer(original));
}
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
private static UnsignedWord (UnsignedWord header) {
assert !isProducedHeapChunkZapped(header) : "Produced chunk zap value";
assert !isConsumedHeapChunkZapped(header) : "Consumed chunk zap value";
return header.and(MASK_HEADER_BITS);
}
static UnsignedWord (UnsignedWord header) {
VMError.guarantee(!isProducedHeapChunkZapped(header), "Produced chunk zap value");
VMError.guarantee(!isConsumedHeapChunkZapped(header), "Consumed chunk zap value");
return header.and(MASK_HEADER_BITS);
}
@Fold
static int () {
return ConfigurationValues.getObjectLayout().getHubOffset();
}
@Fold
static int () {
return ConfigurationValues.getObjectLayout().getIdentityHashCodeOffset();
}
@Fold
static int () {
return ConfigurationValues.getObjectLayout().getReferenceSize();
}
@Fold
static boolean () {
return ImageSingletons.lookup(CompressEncoding.class).hasBase();
}
@Fold
static int () {
return ReferenceAccess.singleton().getCompressEncoding().getShift();
}
}