< prev index next > src/java.base/share/classes/jdk/internal/misc/Unsafe.java
Print this page
*/
package jdk.internal.misc;
import jdk.internal.ref.Cleaner;
+ import jdk.internal.value.ValueClass;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import sun.nio.ch.DirectBuffer;
import java.lang.reflect.Field;
* {@link NullPointerException}
*/
@IntrinsicCandidate
public native void putInt(Object o, long offset, int x);
+
+ /**
+ * Returns true if the given field is flattened.
+ */
+ public boolean isFlatField(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+ return isFlatField0(f);
+ }
+
+ private native boolean isFlatField0(Object o);
+
+ /* Returns true if the given field has a null marker
+ * <p>
+ * Nullable flat fields are stored in a flattened representation
+ * and have an associated null marker to indicate if the the field value is
+ * null or the one stored with the flat representation
+ */
+
+ public boolean hasNullMarker(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+ return hasNullMarker0(f);
+ }
+
+ private native boolean hasNullMarker0(Object o);
+
+ /* Returns the offset of the null marker of the field,
+ * or -1 if the field doesn't have a null marker
+ */
+
+ public int nullMarkerOffset(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+ return nullMarkerOffset0(f);
+ }
+
+ private native int nullMarkerOffset0(Object o);
+
+ public static final int NON_FLAT_LAYOUT = 0;
+
+ /* Reports the kind of layout used for an element in the storage
+ * allocation of the given array. Do not expect to perform any logic
+ * or layout control with this value, it is just an opaque token
+ * used for performance reasons.
+ *
+ * A layout of 0 indicates this array is not flat.
+ */
+ public int arrayLayout(Class<?> arrayClass) {
+ if (arrayClass == null) {
+ throw new NullPointerException();
+ }
+ return arrayLayout0(arrayClass);
+ }
+
+ private native int arrayLayout0(Object o);
+
+
+ /* Reports the kind of layout used for a given field in the storage
+ * allocation of its class. Do not expect to perform any logic
+ * or layout control with this value, it is just an opaque token
+ * used for performance reasons.
+ *
+ * A layout of 0 indicates this field is not flat.
+ */
+ public int fieldLayout(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+ return fieldLayout0(f);
+ }
+
+ private native int fieldLayout0(Object o);
+
+ public native Object[] newSpecialArray(Class<?> componentType,
+ int length, int layoutKind);
+
+ /**
+ * Returns true if the given class is a flattened array.
+ */
+ @IntrinsicCandidate
+ public native boolean isFlatArray(Class<?> arrayClass);
+
/**
* Fetches a reference value from a given Java variable.
+ * This method can return a reference to either an object or value
+ * or a null reference.
+ *
* @see #getInt(Object, long)
*/
@IntrinsicCandidate
public native Object getReference(Object o, long offset);
/**
* Stores a reference value into a given Java variable.
+ * This method can store a reference to either an object or value
+ * or a null reference.
* <p>
* Unless the reference {@code x} being stored is either null
* or matches the field type, the results are undefined.
* If the reference {@code o} is non-null, card marks or
* other store barriers for that object (if the VM requires them)
* @see #putInt(Object, long, int)
*/
@IntrinsicCandidate
public native void putReference(Object o, long offset, Object x);
+ /**
+ * Fetches a value of type {@code <V>} from a given Java variable.
+ * More specifically, fetches a field or array element within the given
+ * {@code o} object at the given offset, or (if {@code o} is null)
+ * from the memory address whose numerical value is the given offset.
+ *
+ * @param o Java heap object in which the variable resides, if any, else
+ * null
+ * @param offset indication of where the variable resides in a Java heap
+ * object, if any, else a memory address locating the variable
+ * statically
+ * @param valueType value type
+ * @param <V> the type of a value
+ * @return the value fetched from the indicated Java variable
+ * @throws RuntimeException No defined exceptions are thrown, not even
+ * {@link NullPointerException}
+ */
+ @IntrinsicCandidate
+ public native <V> V getValue(Object o, long offset, Class<?> valueType);
+
+ /**
+ * Fetches a value of type {@code <V>} from a given Java variable.
+ * More specifically, fetches a field or array element within the given
+ * {@code o} object at the given offset, or (if {@code o} is null)
+ * from the memory address whose numerical value is the given offset.
+ *
+ * @param o Java heap object in which the variable resides, if any, else
+ * null
+ * @param offset indication of where the variable resides in a Java heap
+ * object, if any, else a memory address locating the variable
+ * statically
+ * @param layoutKind opaque value used by the VM to know the layout
+ * the field or array element. This value must be retrieved with
+ * {@link #fieldLayout} or {@link #arrayLayout}.
+ * @param valueType value type
+ * @param <V> the type of a value
+ * @return the value fetched from the indicated Java variable
+ * @throws RuntimeException No defined exceptions are thrown, not even
+ * {@link NullPointerException}
+ */
+ public native <V> V getFlatValue(Object o, long offset, int layoutKind, Class<?> valueType);
+
+
+ /**
+ * Stores the given value into a given Java variable.
+ *
+ * Unless the reference {@code o} being stored is either null
+ * or matches the field type, the results are undefined.
+ *
+ * @param o Java heap object in which the variable resides, if any, else
+ * null
+ * @param offset indication of where the variable resides in a Java heap
+ * object, if any, else a memory address locating the variable
+ * statically
+ * @param valueType value type
+ * @param v the value to store into the indicated Java variable
+ * @param <V> the type of a value
+ * @throws RuntimeException No defined exceptions are thrown, not even
+ * {@link NullPointerException}
+ */
+ @IntrinsicCandidate
+ public native <V> void putValue(Object o, long offset, Class<?> valueType, V v);
+
+ /**
+ * Stores the given value into a given Java variable.
+ *
+ * Unless the reference {@code o} being stored is either null
+ * or matches the field type, the results are undefined.
+ *
+ * @param o Java heap object in which the variable resides, if any, else
+ * null
+ * @param offset indication of where the variable resides in a Java heap
+ * object, if any, else a memory address locating the variable
+ * statically
+ * @param layoutKind opaque value used by the VM to know the layout
+ * the field or array element. This value must be retrieved with
+ * {@link #fieldLayout} or {@link #arrayLayout}.
+ * @param valueType value type
+ * @param v the value to store into the indicated Java variable
+ * @param <V> the type of a value
+ * @throws RuntimeException No defined exceptions are thrown, not even
+ * {@link NullPointerException}
+ */
+ public native <V> void putFlatValue(Object o, long offset, int layoutKind, Class<?> valueType, V v);
+
+ /**
+ * Returns an object instance with a private buffered value whose layout
+ * and contents is exactly the given value instance. The return object
+ * is in the larval state that can be updated using the unsafe put operation.
+ *
+ * @param value a value instance
+ * @param <V> the type of the given value instance
+ */
+ @IntrinsicCandidate
+ public native <V> V makePrivateBuffer(V value);
+
+ /**
+ * Exits the larval state and returns a value instance.
+ *
+ * @param value a value instance
+ * @param <V> the type of the given value instance
+ */
+ @IntrinsicCandidate
+ public native <V> V finishPrivateBuffer(V value);
+
+ /**
+ * Returns the header size of the given value type.
+ *
+ * @param valueType value type
+ * @return the header size of the value type
+ */
+ public native <V> long valueHeaderSize(Class<V> valueType);
+
/** @see #getInt(Object, long) */
@IntrinsicCandidate
public native boolean getBoolean(Object o, long offset);
/** @see #putInt(Object, long, int) */
}
return arrayIndexScale0(arrayClass);
}
+ /**
+ * Return the size of the object in the heap.
+ * @param o an object
+ * @return the objects's size
+ * @since Valhalla
+ */
+ public long getObjectSize(Object o) {
+ if (o == null)
+ throw new NullPointerException();
+ return getObjectSize0(o);
+ }
/** The value of {@code arrayIndexScale(boolean[].class)} */
public static final int ARRAY_BOOLEAN_INDEX_SCALE
= theUnsafe.arrayIndexScale(boolean[].class);
@IntrinsicCandidate
public final native boolean compareAndSetReference(Object o, long offset,
Object expected,
Object x);
+ private final boolean isValueObject(Object o) {
+ return o != null && o.getClass().isValue();
+ }
+
+ /*
+ * For value type, CAS should do substitutability test as opposed
+ * to two pointers comparison.
+ */
+ @ForceInline
+ public final <V> boolean compareAndSetReference(Object o, long offset,
+ Class<?> type,
+ V expected,
+ V x) {
+ if (type.isValue() || isValueObject(expected)) {
+ while (true) {
+ Object witness = getReferenceVolatile(o, offset);
+ if (witness != expected) {
+ return false;
+ }
+ if (compareAndSetReference(o, offset, witness, x)) {
+ return true;
+ }
+ }
+ } else {
+ return compareAndSetReference(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> boolean compareAndSetFlatValue(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ while (true) {
+ Object witness = getFlatValueVolatile(o, offset, layout, valueType);
+ if (witness != expected) {
+ return false;
+ }
+ if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) {
+ return true;
+ }
+ }
+ }
+
@IntrinsicCandidate
public final native Object compareAndExchangeReference(Object o, long offset,
Object expected,
Object x);
+ @ForceInline
+ public final <V> Object compareAndExchangeReference(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ if (valueType.isValue() || isValueObject(expected)) {
+ while (true) {
+ Object witness = getReferenceVolatile(o, offset);
+ if (witness != expected) {
+ return witness;
+ }
+ if (compareAndSetReference(o, offset, witness, x)) {
+ return witness;
+ }
+ }
+ } else {
+ return compareAndExchangeReference(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> Object compareAndExchangeFlatValue(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ while (true) {
+ Object witness = getFlatValueVolatile(o, offset, layout, valueType);
+ if (witness != expected) {
+ return witness;
+ }
+ if (compareAndSetFlatValueAsBytes(o, offset, layout, valueType, witness, x)) {
+ return witness;
+ }
+ }
+ }
+
@IntrinsicCandidate
public final Object compareAndExchangeReferenceAcquire(Object o, long offset,
Object expected,
Object x) {
return compareAndExchangeReference(o, offset, expected, x);
}
+ public final <V> Object compareAndExchangeReferenceAcquire(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndExchangeReference(o, offset, valueType, expected, x);
+ }
+
+ @ForceInline
+ public final <V> Object compareAndExchangeFlatValueAcquire(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndExchangeFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
@IntrinsicCandidate
public final Object compareAndExchangeReferenceRelease(Object o, long offset,
Object expected,
Object x) {
return compareAndExchangeReference(o, offset, expected, x);
}
+ public final <V> Object compareAndExchangeReferenceRelease(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndExchangeReference(o, offset, valueType, expected, x);
+ }
+
+ @ForceInline
+ public final <V> Object compareAndExchangeFlatValueRelease(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndExchangeFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
@IntrinsicCandidate
public final boolean weakCompareAndSetReferencePlain(Object o, long offset,
Object expected,
Object x) {
return compareAndSetReference(o, offset, expected, x);
}
+ public final <V> boolean weakCompareAndSetReferencePlain(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ if (valueType.isValue() || isValueObject(expected)) {
+ return compareAndSetReference(o, offset, valueType, expected, x);
+ } else {
+ return weakCompareAndSetReferencePlain(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> boolean weakCompareAndSetFlatValuePlain(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndSetFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
@IntrinsicCandidate
public final boolean weakCompareAndSetReferenceAcquire(Object o, long offset,
Object expected,
Object x) {
return compareAndSetReference(o, offset, expected, x);
}
+ public final <V> boolean weakCompareAndSetReferenceAcquire(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ if (valueType.isValue() || isValueObject(expected)) {
+ return compareAndSetReference(o, offset, valueType, expected, x);
+ } else {
+ return weakCompareAndSetReferencePlain(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> boolean weakCompareAndSetFlatValueAcquire(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndSetFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
@IntrinsicCandidate
public final boolean weakCompareAndSetReferenceRelease(Object o, long offset,
Object expected,
Object x) {
return compareAndSetReference(o, offset, expected, x);
}
+ public final <V> boolean weakCompareAndSetReferenceRelease(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ if (valueType.isValue() || isValueObject(expected)) {
+ return compareAndSetReference(o, offset, valueType, expected, x);
+ } else {
+ return weakCompareAndSetReferencePlain(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> boolean weakCompareAndSetFlatValueRelease(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndSetFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
@IntrinsicCandidate
public final boolean weakCompareAndSetReference(Object o, long offset,
Object expected,
Object x) {
return compareAndSetReference(o, offset, expected, x);
}
+ public final <V> boolean weakCompareAndSetReference(Object o, long offset,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ if (valueType.isValue() || isValueObject(expected)) {
+ return compareAndSetReference(o, offset, valueType, expected, x);
+ } else {
+ return weakCompareAndSetReferencePlain(o, offset, expected, x);
+ }
+ }
+
+ @ForceInline
+ public final <V> boolean weakCompareAndSetFlatValue(Object o, long offset,
+ int layout,
+ Class<?> valueType,
+ V expected,
+ V x) {
+ return compareAndSetFlatValue(o, offset, layout, valueType, expected, x);
+ }
+
/**
* Atomically updates Java variable to {@code x} if it is currently
* holding {@code expected}.
*
* <p>This operation has memory semantics of a {@code volatile} read
* load semantics. Otherwise identical to {@link #getReference(Object, long)}
*/
@IntrinsicCandidate
public native Object getReferenceVolatile(Object o, long offset);
+ @ForceInline
+ public final <V> Object getFlatValueVolatile(Object o, long offset, int layout, Class<?> valueType) {
+ // we translate using fences (see: https://gee.cs.oswego.edu/dl/html/j9mm.html)
+ Object res = getFlatValue(o, offset, layout, valueType);
+ fullFence();
+ return res;
+ }
+
/**
* Stores a reference value into a given Java variable, with
* volatile store semantics. Otherwise identical to {@link #putReference(Object, long, Object)}
*/
@IntrinsicCandidate
public native void putReferenceVolatile(Object o, long offset, Object x);
+ @ForceInline
+ public final <V> void putFlatValueVolatile(Object o, long offset, int layout, Class<?> valueType, V x) {
+ // we translate using fences (see: https://gee.cs.oswego.edu/dl/html/j9mm.html)
+ putFlatValueRelease(o, offset, layout, valueType, x);
+ fullFence();
+ }
+
/** Volatile version of {@link #getInt(Object, long)} */
@IntrinsicCandidate
public native int getIntVolatile(Object o, long offset);
/** Volatile version of {@link #putInt(Object, long, int)} */
@IntrinsicCandidate
public final Object getReferenceAcquire(Object o, long offset) {
return getReferenceVolatile(o, offset);
}
+ @ForceInline
+ public final <V> Object getFlatValueAcquire(Object o, long offset, int layout, Class<?> valueType) {
+ // we translate using fences (see: https://gee.cs.oswego.edu/dl/html/j9mm.html)
+ Object res = getFlatValue(o, offset, layout, valueType);
+ loadFence();
+ return res;
+ }
+
/** Acquire version of {@link #getBooleanVolatile(Object, long)} */
@IntrinsicCandidate
public final boolean getBooleanAcquire(Object o, long offset) {
return getBooleanVolatile(o, offset);
}
@IntrinsicCandidate
public final void putReferenceRelease(Object o, long offset, Object x) {
putReferenceVolatile(o, offset, x);
}
+ @ForceInline
+ public final <V> void putFlatValueRelease(Object o, long offset, int layout, Class<?> valueType, V x) {
+ // we translate using fences (see: https://gee.cs.oswego.edu/dl/html/j9mm.html)
+ storeFence();
+ putFlatValue(o, offset, layout, valueType, x);
+ }
+
/** Release version of {@link #putBooleanVolatile(Object, long, boolean)} */
@IntrinsicCandidate
public final void putBooleanRelease(Object o, long offset, boolean x) {
putBooleanVolatile(o, offset, x);
}
@IntrinsicCandidate
public final Object getReferenceOpaque(Object o, long offset) {
return getReferenceVolatile(o, offset);
}
+ @ForceInline
+ public final <V> Object getFlatValueOpaque(Object o, long offset, int layout, Class<?> valueType) {
+ // this is stronger than opaque semantics
+ return getFlatValueAcquire(o, offset, layout, valueType);
+ }
+
/** Opaque version of {@link #getBooleanVolatile(Object, long)} */
@IntrinsicCandidate
public final boolean getBooleanOpaque(Object o, long offset) {
return getBooleanVolatile(o, offset);
}
@IntrinsicCandidate
public final void putReferenceOpaque(Object o, long offset, Object x) {
putReferenceVolatile(o, offset, x);
}
+ @ForceInline
+ public final <V> void putFlatValueOpaque(Object o, long offset, int layout, Class<?> valueType, V x) {
+ // this is stronger than opaque semantics
+ putFlatValueRelease(o, offset, layout, valueType, x);
+ }
+
/** Opaque version of {@link #putBooleanVolatile(Object, long, boolean)} */
@IntrinsicCandidate
public final void putBooleanOpaque(Object o, long offset, boolean x) {
putBooleanVolatile(o, offset, x);
}
@IntrinsicCandidate
public final void putDoubleOpaque(Object o, long offset, double x) {
putDoubleVolatile(o, offset, x);
}
+ @ForceInline
+ private boolean compareAndSetFlatValueAsBytes(Object o, long offset, int layout, Class<?> valueType, Object expected, Object x) {
+ // We turn the payload of an atomic value into a numeric value (of suitable type)
+ // by storing the value into an array element (of matching layout) and by reading
+ // back the array element as an integral value. After which we can implement the CAS
+ // as a plain numeric CAS. Note: this only works if the payload contains no oops
+ // (see VarHandles::isAtomicFlat).
+ Object expectedArray = newSpecialArray(valueType, 1, layout);
+ Object xArray = newSpecialArray(valueType, 1, layout);
+ long base = arrayBaseOffset(expectedArray.getClass());
+ int scale = arrayIndexScale(expectedArray.getClass());
+ putFlatValue(expectedArray, base, layout, valueType, expected);
+ putFlatValue(xArray, base, layout, valueType, x);
+ switch (scale) {
+ case 1: {
+ byte expectedByte = getByte(expectedArray, base);
+ byte xByte = getByte(xArray, base);
+ return compareAndSetByte(o, offset, expectedByte, xByte);
+ }
+ case 2: {
+ short expectedShort = getShort(expectedArray, base);
+ short xShort = getShort(xArray, base);
+ return compareAndSetShort(o, offset, expectedShort, xShort);
+ }
+ case 4: {
+ int expectedInt = getInt(expectedArray, base);
+ int xInt = getInt(xArray, base);
+ return compareAndSetInt(o, offset, expectedInt, xInt);
+ }
+ case 8: {
+ long expectedLong = getLong(expectedArray, base);
+ long xLong = getLong(xArray, base);
+ return compareAndSetLong(o, offset, expectedLong, xLong);
+ }
+ default: {
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
/**
* Unblocks the given thread blocked on {@code park}, or, if it is
* not blocked, causes the subsequent call to {@code park} not to
* block. Note: this operation is "unsafe" solely because the
* caller must somehow ensure that the thread has not been
v = getReferenceVolatile(o, offset);
} while (!weakCompareAndSetReference(o, offset, v, newValue));
return v;
}
+ @ForceInline
+ public final Object getAndSetReference(Object o, long offset, Class<?> valueType, Object newValue) {
+ Object v;
+ do {
+ v = getReferenceVolatile(o, offset);
+ } while (!compareAndSetReference(o, offset, valueType, v, newValue));
+ return v;
+ }
+
+ @ForceInline
+ public Object getAndSetFlatValue(Object o, long offset, int layoutKind, Class<?> valueType, Object newValue) {
+ Object v;
+ do {
+ v = getFlatValueVolatile(o, offset, layoutKind, valueType);
+ } while (!compareAndSetFlatValue(o, offset, layoutKind, valueType, v, newValue));
+ return v;
+ }
+
@ForceInline
public final Object getAndSetReferenceRelease(Object o, long offset, Object newValue) {
Object v;
do {
v = getReference(o, offset);
} while (!weakCompareAndSetReferenceRelease(o, offset, v, newValue));
return v;
}
+ @ForceInline
+ public final Object getAndSetReferenceRelease(Object o, long offset, Class<?> valueType, Object newValue) {
+ return getAndSetReference(o, offset, valueType, newValue);
+ }
+
+ @ForceInline
+ public Object getAndSetFlatValueRelease(Object o, long offset, int layoutKind, Class<?> valueType, Object x) {
+ return getAndSetFlatValue(o, offset, layoutKind, valueType, x);
+ }
+
@ForceInline
public final Object getAndSetReferenceAcquire(Object o, long offset, Object newValue) {
Object v;
do {
v = getReferenceAcquire(o, offset);
} while (!weakCompareAndSetReferenceAcquire(o, offset, v, newValue));
return v;
}
+ @ForceInline
+ public final Object getAndSetReferenceAcquire(Object o, long offset, Class<?> valueType, Object newValue) {
+ return getAndSetReference(o, offset, valueType, newValue);
+ }
+
+ @ForceInline
+ public Object getAndSetFlatValueAcquire(Object o, long offset, int layoutKind, Class<?> valueType, Object x) {
+ return getAndSetFlatValue(o, offset, layoutKind, valueType, x);
+ }
+
@IntrinsicCandidate
public final byte getAndSetByte(Object o, long offset, byte newValue) {
byte v;
do {
v = getByteVolatile(o, offset);
private native Object staticFieldBase0(Field f);
private native boolean shouldBeInitialized0(Class<?> c);
private native void ensureClassInitialized0(Class<?> c);
private native int arrayBaseOffset0(Class<?> arrayClass); // public version returns long to promote correct arithmetic
private native int arrayIndexScale0(Class<?> arrayClass);
+ private native long getObjectSize0(Object o);
private native int getLoadAverage0(double[] loadavg, int nelems);
/**
* Invokes the given direct byte buffer's cleaner, if any.
< prev index next >