< prev index next >

src/java.base/share/classes/jdk/internal/misc/Unsafe.java

Print this page

        

@@ -175,19 +175,38 @@
      *         {@link NullPointerException}
      */
     @HotSpotIntrinsicCandidate
     public native void putInt(Object o, long offset, int x);
 
+    private static final int JVM_ACC_FLATTENED = 0x00008000; // HotSpot-specific bit
+
+    /**
+     * Returns true if the given field is flattened.
+     */
+    public boolean isFlattened(Field f) {
+        return (f.getModifiers() & JVM_ACC_FLATTENED) == JVM_ACC_FLATTENED;
+    }
+
+    /**
+     * Returns true if the given class is a flattened array.
+     */
+    public native boolean isFlattenedArray(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)
      */
     @HotSpotIntrinsicCandidate
     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)

@@ -195,10 +214,111 @@
      * @see #putInt(Object, long, int)
      */
     @HotSpotIntrinsicCandidate
     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 vc inline class
+     * @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}
+     */
+    @HotSpotIntrinsicCandidate
+    public native <V> V getValue(Object o, long offset, Class<?> vc);
+
+    /**
+     * 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 vc inline class
+     * @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}
+     */
+    @HotSpotIntrinsicCandidate
+    public native <V> void putValue(Object o, long offset, Class<?> vc, V v);
+
+    /**
+     * Fetches a reference value of type {@code vc} from a given Java variable.
+     * This method can return a reference to a value or a null reference
+     * for a nullable-projection of an inline type.
+     *
+     * @param vc inline class
+     */
+    public Object getReference(Object o, long offset, Class<?> vc) {
+        Object ref = getReference(o, offset);
+        if (ref == null && vc.isInlineClass() && !vc.isIndirectType()) {
+            // If the type of the returned reference is a regular inline type
+            // return an uninitialized default value if null
+            ref = uninitializedDefaultValue(vc);
+        }
+        return ref;
+    }
+
+    public Object getReferenceVolatile(Object o, long offset, Class<?> vc) {
+        Object ref = getReferenceVolatile(o, offset);
+        if (ref == null && vc.isInlineClass() && !vc.isIndirectType()) {
+            // If the type of the returned reference is a regular inline type
+            // return an uninitialized default value if null
+            ref = uninitializedDefaultValue(vc);
+        }
+        return ref;
+    }
+
+    /**
+     * Returns an uninitialized default value of the given inline class.
+     */
+    public native <V> V uninitializedDefaultValue(Class<?> vc);
+
+    /**
+     * 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
+     */
+    @HotSpotIntrinsicCandidate
+    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
+     */
+    @HotSpotIntrinsicCandidate
+    public native <V> V finishPrivateBuffer(V value);
+
+    /**
+     * Returns the header size of the given inline class
+     *
+     * @param vc inline class
+     * @param <V> value clas
+     * @return the header size of the inline class
+     */
+    public native <V> long valueHeaderSize(Class<V> vc);
+
     /** @see #getInt(Object, long) */
     @HotSpotIntrinsicCandidate
     public native boolean getBoolean(Object o, long offset);
 
     /** @see #putInt(Object, long, int) */

@@ -1301,57 +1421,241 @@
     @HotSpotIntrinsicCandidate
     public final native boolean compareAndSetReference(Object o, long offset,
                                                        Object expected,
                                                        Object x);
 
+    private final boolean isInlineType(Object o) {
+        return o != null && o.getClass().isInlineClass();
+    }
+
+    /*
+     * For inline type, CAS should do substitutability test as opposed
+     * to two pointers comparison.
+     *
+     * Perhaps we can keep the xxxObject methods for compatibility and
+     * change the JDK 13 xxxReference method signature freely.
+     */
+    public final <V> boolean compareAndSetReference(Object o, long offset,
+                                                    Class<?> valueType,
+                                                    V expected,
+                                                    V x) {
+        if (valueType.isInlineClass() || isInlineType(expected)) {
+            synchronized (valueLock) {
+                Object witness = getReference(o, offset);
+                if (witness == expected) {
+                    putReference(o, offset, x);
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        } else {
+            return compareAndSetReference(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> boolean compareAndSetValue(Object o, long offset,
+                                                Class<?> valueType,
+                                                V expected,
+                                                V x) {
+        synchronized (valueLock) {
+            Object witness = getValue(o, offset, valueType);
+            if (witness == expected) {
+                putValue(o, offset, valueType, x);
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+    }
+
     @HotSpotIntrinsicCandidate
     public final native Object compareAndExchangeReference(Object o, long offset,
                                                            Object expected,
                                                            Object x);
 
+    public final <V> Object compareAndExchangeReference(Object o, long offset,
+                                                        Class<?> valueType,
+                                                        V expected,
+                                                        V x) {
+        if (valueType.isInlineClass() || isInlineType(expected)) {
+            synchronized (valueLock) {
+                Object witness = getReference(o, offset);
+                if (witness == expected) {
+                    putReference(o, offset, x);
+                }
+                return witness;
+            }
+        } else {
+            return compareAndExchangeReference(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> Object compareAndExchangeValue(Object o, long offset,
+                                                    Class<?> valueType,
+                                                    V expected,
+                                                    V x) {
+        synchronized (valueLock) {
+            Object witness = getValue(o, offset, valueType);
+            if (witness == expected) {
+                putValue(o, offset, valueType, x);
+            }
+            return witness;
+        }
+    }
+
     @HotSpotIntrinsicCandidate
     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 compareAndExchangeValueAcquire(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
+        return compareAndExchangeValue(o, offset, valueType, expected, x);
+    }
+
     @HotSpotIntrinsicCandidate
     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 compareAndExchangeValueRelease(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
+        return compareAndExchangeValue(o, offset, valueType, expected, x);
+    }
+
     @HotSpotIntrinsicCandidate
     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.isInlineClass() || isInlineType(expected)) {
+            return compareAndSetReference(o, offset, valueType, expected, x);
+        } else {
+            return weakCompareAndSetReferencePlain(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> boolean weakCompareAndSetValuePlain(Object o, long offset,
+                                                         Class<?> valueType,
+                                                         V expected,
+                                                         V x) {
+        return compareAndSetValue(o, offset, valueType, expected, x);
+    }
+
     @HotSpotIntrinsicCandidate
     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.isInlineClass() || isInlineType(expected)) {
+            return compareAndSetReference(o, offset, valueType, expected, x);
+        } else {
+            return weakCompareAndSetReferencePlain(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> boolean weakCompareAndSetValueAcquire(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
+        return compareAndSetValue(o, offset, valueType, expected, x);
+    }
+
     @HotSpotIntrinsicCandidate
     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.isInlineClass() || isInlineType(expected)) {
+            return compareAndSetReference(o, offset, valueType, expected, x);
+        } else {
+            return weakCompareAndSetReferencePlain(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> boolean weakCompareAndSetValueRelease(Object o, long offset,
+                                                           Class<?> valueType,
+                                                           V expected,
+                                                           V x) {
+        return compareAndSetValue(o, offset, valueType, expected, x);
+    }
+
     @HotSpotIntrinsicCandidate
     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.isInlineClass() || isInlineType(expected)) {
+            return compareAndSetReference(o, offset, valueType, expected, x);
+        } else {
+            return weakCompareAndSetReferencePlain(o, offset, expected, x);
+        }
+    }
+
+    @ForceInline
+    public final <V> boolean weakCompareAndSetValue(Object o, long offset,
+                                                    Class<?> valueType,
+                                                    V expected,
+                                                    V x) {
+        return compareAndSetValue(o, offset, 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

@@ -1964,16 +2268,35 @@
      */
     @HotSpotIntrinsicCandidate
     public native Object getReferenceVolatile(Object o, long offset);
 
     /**
+     * Global lock for atomic and volatile strength access to any value of
+     * an inline type.  This is a temporary workaround until better localized
+     * atomic access mechanisms are supported for inline types.
+     */
+    private static final Object valueLock = new Object();
+
+    public final <V> Object getValueVolatile(Object base, long offset, Class<?> valueType) {
+        synchronized (valueLock) {
+            return getValue(base, offset, valueType);
+        }
+    }
+
+    /**
      * Stores a reference value into a given Java variable, with
      * volatile store semantics. Otherwise identical to {@link #putReference(Object, long, Object)}
      */
     @HotSpotIntrinsicCandidate
     public native void putReferenceVolatile(Object o, long offset, Object x);
 
+    public final <V> void putValueVolatile(Object o, long offset, Class<?> valueType, V x) {
+        synchronized (valueLock) {
+            putValue(o, offset, valueType, x);
+        }
+    }
+
     /** Volatile version of {@link #getInt(Object, long)}  */
     @HotSpotIntrinsicCandidate
     public native int     getIntVolatile(Object o, long offset);
 
     /** Volatile version of {@link #putInt(Object, long, int)}  */

@@ -2042,10 +2365,14 @@
     @HotSpotIntrinsicCandidate
     public final Object getReferenceAcquire(Object o, long offset) {
         return getReferenceVolatile(o, offset);
     }
 
+    public final <V> Object getValueAcquire(Object base, long offset, Class<?> valueType) {
+        return getValueVolatile(base, offset, valueType);
+    }
+
     /** Acquire version of {@link #getBooleanVolatile(Object, long)} */
     @HotSpotIntrinsicCandidate
     public final boolean getBooleanAcquire(Object o, long offset) {
         return getBooleanVolatile(o, offset);
     }

@@ -2106,10 +2433,14 @@
     @HotSpotIntrinsicCandidate
     public final void putReferenceRelease(Object o, long offset, Object x) {
         putReferenceVolatile(o, offset, x);
     }
 
+    public final <V> void putValueRelease(Object o, long offset, Class<?> valueType, V x) {
+        putValueVolatile(o, offset, valueType, x);
+    }
+
     /** Release version of {@link #putBooleanVolatile(Object, long, boolean)} */
     @HotSpotIntrinsicCandidate
     public final void putBooleanRelease(Object o, long offset, boolean x) {
         putBooleanVolatile(o, offset, x);
     }

@@ -2162,10 +2493,14 @@
     @HotSpotIntrinsicCandidate
     public final Object getReferenceOpaque(Object o, long offset) {
         return getReferenceVolatile(o, offset);
     }
 
+    public final <V> Object getValueOpaque(Object base, long offset, Class<?> valueType) {
+        return getValueVolatile(base, offset, valueType);
+    }
+
     /** Opaque version of {@link #getBooleanVolatile(Object, long)} */
     @HotSpotIntrinsicCandidate
     public final boolean getBooleanOpaque(Object o, long offset) {
         return getBooleanVolatile(o, offset);
     }

@@ -2216,10 +2551,14 @@
     @HotSpotIntrinsicCandidate
     public final void putReferenceOpaque(Object o, long offset, Object x) {
         putReferenceVolatile(o, offset, x);
     }
 
+    public final <V> void putValueOpaque(Object o, long offset, Class<?> valueType, V x) {
+        putValueVolatile(o, offset, valueType, x);
+    }
+
     /** Opaque version of {@link #putBooleanVolatile(Object, long, boolean)} */
     @HotSpotIntrinsicCandidate
     public final void putBooleanOpaque(Object o, long offset, boolean x) {
         putBooleanVolatile(o, offset, x);
     }

@@ -2650,28 +2989,47 @@
             v = getReferenceVolatile(o, offset);
         } while (!weakCompareAndSetReference(o, offset, v, newValue));
         return v;
     }
 
+    @SuppressWarnings("unchecked")
+    public final <V> Object getAndSetValue(Object o, long offset, Class<?> valueType, V newValue) {
+        synchronized (valueLock) {
+            Object oldValue = getValue(o, offset, valueType);
+            putValue(o, offset, valueType, newValue);
+            return oldValue;
+        }
+    }
+
     @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 <V> Object getAndSetValueRelease(Object o, long offset, Class<?> valueType, V newValue) {
+        return getAndSetValue(o, offset, valueType, newValue);
+    }
+
+    @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 <V> Object getAndSetValueAcquire(Object o, long offset, Class<?> valueType, V newValue) {
+        return getAndSetValue(o, offset, valueType, newValue);
+    }
+
     @HotSpotIntrinsicCandidate
     public final byte getAndSetByte(Object o, long offset, byte newValue) {
         byte v;
         do {
             v = getByteVolatile(o, offset);
< prev index next >