--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java Thu Mar 10 11:52:54 2016 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java Thu Mar 10 16:08:20 2016 -0800
@@ -40,6 +40,15 @@
* Although the class and all methods are public, use of this class is
* limited because only trusted code can obtain instances of it.
*
+ * <em>Note:</em> It is the resposibility of the caller to make sure
+ * arguments are checked before methods of this class are
+ * called. While some rudimentary checks are performed on the input,
+ * the checks are best effort and when performance is an overriding
+ * priority, as when methods of this class are optimized by the
+ * runtime compiler, some or all checks (if any) may be elided. Hence,
+ * the caller must not rely on the checks and corresponding
+ * exceptions!
+ *
* @author John R. Rose
* @see #getUnsafe
*/
@@ -358,6 +367,169 @@
@HotSpotIntrinsicCandidate
public native void putAddress(long address, long x);
+
+
+ /// helper methods for validating various types of objects/values
+
+ /**
+ * Create an exception reflecting that some of the input was invalid
+ *
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @return an exception object
+ */
+ private RuntimeException invalidInput() {
+ return new IllegalArgumentException();
+ }
+
+ /**
+ * Check if a value is 32-bit clean (32 MSB are all zero)
+ *
+ * @param value the 64-bit value to check
+ *
+ * @return true if the value is 32-bit clean
+ */
+ private boolean is32BitClean(long value) {
+ return value >>> 32 == 0;
+ }
+
+ /**
+ * Check the validity of a size (the equivalent of a size_t)
+ *
+ * @throws RuntimeException if the size is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void checkSize(long size) {
+ if (ADDRESS_SIZE == 4) {
+ // Note: this will also check for negative sizes
+ if (!is32BitClean(size)) {
+ throw invalidInput();
+ }
+ } else if (size < 0) {
+ throw invalidInput();
+ }
+ }
+
+ /**
+ * Check the validity of a native address (the equivalent of void*)
+ *
+ * @throws RuntimeException if the address is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void checkNativeAddress(long address) {
+ if (ADDRESS_SIZE == 4) {
+ // Accept both zero and sign extended pointers. A valid
+ // pointer will, after the +1 below, either have produced
+ // the value 0x0 or 0x1. Masking off the low bit allows
+ // for testing against 0.
+ if ((((address >> 32) + 1) & ~1) != 0) {
+ throw invalidInput();
+ }
+ }
+ }
+
+ /**
+ * Check the validity of an offset, relative to a base object
+ *
+ * @param o the base object
+ * @param offset the offset to check
+ *
+ * @throws RuntimeException if the size is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void checkOffset(Object o, long offset) {
+ if (ADDRESS_SIZE == 4) {
+ // Note: this will also check for negative offsets
+ if (!is32BitClean(offset)) {
+ throw invalidInput();
+ }
+ } else if (offset < 0) {
+ throw invalidInput();
+ }
+ }
+
+ /**
+ * Check the validity of a double-register pointer
+ *
+ * Note: This code deliberately does *not* check for NPE for (at
+ * least) three reasons:
+ *
+ * 1) NPE is not just NULL/0 - there is a range of values all
+ * resulting in an NPE, which is not trivial to check for
+ *
+ * 2) It is the responsibility of the callers of Unsafe methods
+ * to verify the input, so throwing an exception here is not really
+ * useful - passing in a NULL pointer is a critical error and the
+ * must not expect an exception to be thrown anyway.
+ *
+ * 3) the actual operations will detect NULL pointers anyway by
+ * means of traps and signals (like SIGSEGV).
+ *
+ * @param o Java heap object, or null
+ * @param offset indication of where the variable resides in a Java heap
+ * object, if any, else a memory address locating the variable
+ * statically
+ *
+ * @throws RuntimeException if the pointer is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void checkPointer(Object o, long offset) {
+ if (o == null) {
+ checkNativeAddress(offset);
+ } else {
+ checkOffset(o, offset);
+ }
+ }
+
+ /**
+ * Check if a type is a primitive array type
+ *
+ * @param c the type to check
+ *
+ * @return true if the type is a primitive array type
+ */
+ private void checkPrimitiveArray(Class<?> c) {
+ Class<?> componentType = c.getComponentType();
+ if (componentType == null || !componentType.isPrimitive()) {
+ throw invalidInput();
+ }
+ }
+
+ /**
+ * Check that a pointer is a valid primitive array type pointer
+ *
+ * Note: pointers off-heap are considered to be primitive arrays
+ *
+ * @throws RuntimeException if the pointer is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void checkPrimitivePointer(Object o, long offset) {
+ checkPointer(o, offset);
+
+ if (o != null) {
+ // If on heap, it it must be a primitive array
+ checkPrimitiveArray(o.getClass());
+ }
+ }
+
+
/// wrappers for malloc, realloc, free:
/**
@@ -367,7 +539,16 @@
* aligned for all value types. Dispose of this memory by calling {@link
* #freeMemory}, or resize it with {@link #reallocateMemory}.
*
- * @throws IllegalArgumentException if the size is negative or too large
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if the size is negative or too large
* for the native size_t type
*
* @throws OutOfMemoryError if the allocation is refused by the system
@@ -375,7 +556,32 @@
* @see #getByte(long)
* @see #putByte(long, byte)
*/
- public native long allocateMemory(long bytes);
+ public long allocateMemory(long bytes) {
+ allocateMemoryChecks(bytes);
+
+ if (bytes == 0) {
+ return 0;
+ }
+
+ long p = allocateMemory0(bytes);
+ if (p == 0) {
+ throw new OutOfMemoryError();
+ }
+
+ return p;
+ }
+
+ /**
+ * Validate the arguments to allocateMemory
+ *
+ * @throws RuntimeException if the arguments are invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void allocateMemoryChecks(long bytes) {
+ checkSize(bytes);
+ }
/**
* Resizes a new block of native memory, to the given size in bytes. The
@@ -387,14 +593,50 @@
* #reallocateMemory}. The address passed to this method may be null, in
* which case an allocation will be performed.
*
- * @throws IllegalArgumentException if the size is negative or too large
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if the size is negative or too large
* for the native size_t type
*
* @throws OutOfMemoryError if the allocation is refused by the system
*
* @see #allocateMemory
*/
- public native long reallocateMemory(long address, long bytes);
+ public long reallocateMemory(long address, long bytes) {
+ reallocateMemoryChecks(address, bytes);
+
+ if (bytes == 0) {
+ freeMemory(address);
+ return 0;
+ }
+
+ long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes);
+ if (p == 0) {
+ throw new OutOfMemoryError();
+ }
+
+ return p;
+ }
+
+ /**
+ * Validate the arguments to reallocateMemory
+ *
+ * @throws RuntimeException if the arguments are invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void reallocateMemoryChecks(long address, long bytes) {
+ checkPointer(null, address);
+ checkSize(bytes);
+ }
/**
* Sets all bytes in a given block of memory to a fixed value
@@ -411,9 +653,28 @@
* If the effective address and length are (resp.) even modulo 4 or 2,
* the stores take place in units of 'int' or 'short'.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @since 1.7
*/
- public native void setMemory(Object o, long offset, long bytes, byte value);
+ public void setMemory(Object o, long offset, long bytes, byte value) {
+ setMemoryChecks(o, offset, bytes, value);
+
+ if (bytes == 0) {
+ return;
+ }
+
+ setMemory0(o, offset, bytes, value);
+ }
/**
* Sets all bytes in a given block of memory to a fixed value
@@ -427,6 +688,19 @@
}
/**
+ * Validate the arguments to setMemory
+ *
+ * @throws RuntimeException if the arguments are invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void setMemoryChecks(Object o, long offset, long bytes, byte value) {
+ checkPrimitivePointer(o, offset);
+ checkSize(bytes);
+ }
+
+ /**
* Sets all bytes in a given block of memory to a copy of another
* block.
*
@@ -441,12 +715,31 @@
* If the effective addresses and length are (resp.) even modulo 4 or 2,
* the transfer takes place in units of 'int' or 'short'.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @since 1.7
*/
- @HotSpotIntrinsicCandidate
- public native void copyMemory(Object srcBase, long srcOffset,
- Object destBase, long destOffset,
- long bytes);
+ public void copyMemory(Object srcBase, long srcOffset,
+ Object destBase, long destOffset,
+ long bytes) {
+ copyMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes);
+
+ if (bytes == 0) {
+ return;
+ }
+
+ copyMemory0(srcBase, srcOffset, destBase, destOffset, bytes);
+ }
+
/**
* Sets all bytes in a given block of memory to a copy of another
* block. This provides a <em>single-register</em> addressing mode,
@@ -458,15 +751,22 @@
copyMemory(null, srcAddress, null, destAddress, bytes);
}
- private boolean isPrimitiveArray(Class<?> c) {
- Class<?> componentType = c.getComponentType();
- return componentType != null && componentType.isPrimitive();
+ /**
+ * Validate the arguments to copyMemory
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void copyMemoryChecks(Object srcBase, long srcOffset,
+ Object destBase, long destOffset,
+ long bytes) {
+ checkSize(bytes);
+ checkPrimitivePointer(srcBase, srcOffset);
+ checkPrimitivePointer(destBase, destOffset);
}
- private native void copySwapMemory0(Object srcBase, long srcOffset,
- Object destBase, long destOffset,
- long bytes, long elemSize);
-
/**
* Copies all elements from one block of memory to another block,
* *unconditionally* byte swapping the elements on the fly.
@@ -476,39 +776,23 @@
* as discussed in {@link #getInt(Object,long)}. When the object reference is null,
* the offset supplies an absolute base address.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @since 9
*/
public void copySwapMemory(Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes, long elemSize) {
- if (bytes < 0) {
- throw new IllegalArgumentException();
- }
- if (elemSize != 2 && elemSize != 4 && elemSize != 8) {
- throw new IllegalArgumentException();
- }
- if (bytes % elemSize != 0) {
- throw new IllegalArgumentException();
- }
- if ((srcBase == null && srcOffset == 0) ||
- (destBase == null && destOffset == 0)) {
- throw new NullPointerException();
- }
-
- // Must be off-heap, or primitive heap arrays
- if (srcBase != null && (srcOffset < 0 || !isPrimitiveArray(srcBase.getClass()))) {
- throw new IllegalArgumentException();
- }
- if (destBase != null && (destOffset < 0 || !isPrimitiveArray(destBase.getClass()))) {
- throw new IllegalArgumentException();
- }
-
- // Sanity check size and offsets on 32-bit platforms. Most
- // significant 32 bits must be zero.
- if (ADDRESS_SIZE == 4 &&
- (bytes >>> 32 != 0 || srcOffset >>> 32 != 0 || destOffset >>> 32 != 0)) {
- throw new IllegalArgumentException();
- }
+ copySwapMemoryChecks(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
if (bytes == 0) {
return;
@@ -517,6 +801,22 @@
copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
}
+ private void copySwapMemoryChecks(Object srcBase, long srcOffset,
+ Object destBase, long destOffset,
+ long bytes, long elemSize) {
+ checkSize(bytes);
+
+ if (elemSize != 2 && elemSize != 4 && elemSize != 8) {
+ throw invalidInput();
+ }
+ if (bytes % elemSize != 0) {
+ throw invalidInput();
+ }
+
+ checkPrimitivePointer(srcBase, srcOffset);
+ checkPrimitivePointer(destBase, destOffset);
+ }
+
/**
* Copies all elements from one block of memory to another block, byte swapping the
* elements on the fly.
@@ -535,9 +835,40 @@
* #allocateMemory} or {@link #reallocateMemory}. The address passed to
* this method may be null, in which case no action is taken.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @see #allocateMemory
*/
- public native void freeMemory(long address);
+ public void freeMemory(long address) {
+ freeMemoryChecks(address);
+
+ if (address == 0) {
+ return;
+ }
+
+ freeMemory0(address);
+ }
+
+ /**
+ * Validate the arguments to freeMemory
+ *
+ * @throws RuntimeException if the arguments are invalid
+ * (<em>Note:</em> after optimization, invalid inputs may
+ * go undetected, which will lead to unpredictable
+ * behavior)
+ */
+ private void freeMemoryChecks(long address) {
+ checkPointer(null, address);
+ }
/// random queries
@@ -546,7 +877,7 @@
* {@link #staticFieldOffset}, {@link #objectFieldOffset},
* or {@link #arrayBaseOffset}.
*/
- public static final int INVALID_FIELD_OFFSET = -1;
+ public static final int INVALID_FIELD_OFFSET = -1;
/**
* Reports the location of a given field in the storage allocation of its
@@ -566,7 +897,13 @@
* must preserve all bits of static field offsets.
* @see #getInt(Object, long)
*/
- public native long objectFieldOffset(Field f);
+ public long objectFieldOffset(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+
+ return objectFieldOffset0(f);
+ }
/**
* Reports the location of a given static field, in conjunction with {@link
@@ -585,7 +922,13 @@
* this method reports its result as a long value.
* @see #getInt(Object, long)
*/
- public native long staticFieldOffset(Field f);
+ public long staticFieldOffset(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+
+ return staticFieldOffset0(f);
+ }
/**
* Reports the location of a given static field, in conjunction with {@link
@@ -597,7 +940,13 @@
* not be used in any way except as argument to the get and put routines in
* this class.
*/
- public native Object staticFieldBase(Field f);
+ public Object staticFieldBase(Field f) {
+ if (f == null) {
+ throw new NullPointerException();
+ }
+
+ return staticFieldBase0(f);
+ }
/**
* Detects if the given class may need to be initialized. This is often
@@ -605,14 +954,26 @@
* class.
* @return false only if a call to {@code ensureClassInitialized} would have no effect
*/
- public native boolean shouldBeInitialized(Class<?> c);
+ public boolean shouldBeInitialized(Class<?> c) {
+ if (c == null) {
+ throw new NullPointerException();
+ }
+
+ return shouldBeInitialized0(c);
+ }
/**
* Ensures the given class has been initialized. This is often
* needed in conjunction with obtaining the static field base of a
* class.
*/
- public native void ensureClassInitialized(Class<?> c);
+ public void ensureClassInitialized(Class<?> c) {
+ if (c == null) {
+ throw new NullPointerException();
+ }
+
+ ensureClassInitialized0(c);
+ }
/**
* Reports the offset of the first element in the storage allocation of a
@@ -624,7 +985,14 @@
* @see #getInt(Object, long)
* @see #putInt(Object, long, int)
*/
- public native int arrayBaseOffset(Class<?> arrayClass);
+ public int arrayBaseOffset(Class<?> arrayClass) {
+ if (arrayClass == null) {
+ throw new NullPointerException();
+ }
+
+ return arrayBaseOffset0(arrayClass);
+ }
+
/** The value of {@code arrayBaseOffset(boolean[].class)} */
public static final int ARRAY_BOOLEAN_BASE_OFFSET
@@ -673,7 +1041,14 @@
* @see #getInt(Object, long)
* @see #putInt(Object, long, int)
*/
- public native int arrayIndexScale(Class<?> arrayClass);
+ public int arrayIndexScale(Class<?> arrayClass) {
+ if (arrayClass == null) {
+ throw new NullPointerException();
+ }
+
+ return arrayIndexScale0(arrayClass);
+ }
+
/** The value of {@code arrayIndexScale(boolean[].class)} */
public static final int ARRAY_BOOLEAN_INDEX_SCALE
@@ -717,10 +1092,12 @@
* other primitive types (as stored in native memory blocks) is determined
* fully by their information content.
*/
- public native int addressSize();
+ public int addressSize() {
+ return ADDRESS_SIZE;
+ }
/** The value of {@code addressSize()} */
- public static final int ADDRESS_SIZE = theUnsafe.addressSize();
+ public static final int ADDRESS_SIZE = theUnsafe.addressSize0();
/**
* Reports the size in bytes of a native memory page (whatever that is).
@@ -735,9 +1112,22 @@
* Tells the VM to define a class, without security checks. By default, the
* class loader and protection domain come from the caller's class.
*/
- public native Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader,
- ProtectionDomain protectionDomain);
+ public Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader,
+ ProtectionDomain protectionDomain) {
+ if (b == null) {
+ throw new NullPointerException();
+ }
+ if (len < 0) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ return defineClass0(name, b, off, len, loader, protectionDomain);
+ }
+
+ public native Class<?> defineClass0(String name, byte[] b, int off, int len,
+ ClassLoader loader,
+ ProtectionDomain protectionDomain);
/**
* Defines a class but does not make it known to the class loader or system dictionary.
@@ -755,7 +1145,13 @@
* @param data bytes of a class file
* @param cpPatches where non-null entries exist, they replace corresponding CP entries in data
*/
- public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);
+ public Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
+ if (hostClass == null || data == null) {
+ throw new NullPointerException();
+ }
+
+ return defineAnonymousClass0(hostClass, data, cpPatches);
+ }
/**
* Allocates an instance but does not run any constructor.
@@ -765,6 +1161,59 @@
public native Object allocateInstance(Class<?> cls)
throws InstantiationException;
+ /**
+ * Allocates an array of a given type, but does not do zeroing.
+ * <p>
+ * This method should only be used in the very rare cases where a high-performance code
+ * overwrites the destination array completely, and compilers cannot assist in zeroing elimination.
+ * In an overwhelming majority of cases, a normal Java allocation should be used instead.
+ * <p>
+ * Users of this method are <b>required</b> to overwrite the initial (garbage) array contents
+ * before allowing untrusted code, or code in other threads, to observe the reference
+ * to the newly allocated array. In addition, the publication of the array reference must be
+ * safe according to the Java Memory Model requirements.
+ * <p>
+ * The safest approach to deal with an uninitialized array is to keep the reference to it in local
+ * variable at least until the initialization is complete, and then publish it <b>once</b>, either
+ * by writing it to a <em>volatile</em> field, or storing it into a <em>final</em> field in constructor,
+ * or issuing a {@link #storeFence} before publishing the reference.
+ * <p>
+ * @implnote This method can only allocate primitive arrays, to avoid garbage reference
+ * elements that could break heap integrity.
+ *
+ * @param componentType array component type to allocate
+ * @param length array size to allocate
+ * @throws IllegalArgumentException if component type is null, or not a primitive class;
+ * or the length is negative
+ */
+ public Object allocateUninitializedArray(Class<?> componentType, int length) {
+ if (componentType == null) {
+ throw new IllegalArgumentException("Component type is null");
+ }
+ if (!componentType.isPrimitive()) {
+ throw new IllegalArgumentException("Component type is not primitive");
+ }
+ if (length < 0) {
+ throw new IllegalArgumentException("Negative length");
+ }
+ return allocateUninitializedArray0(componentType, length);
+ }
+
+ @HotSpotIntrinsicCandidate
+ private Object allocateUninitializedArray0(Class<?> componentType, int length) {
+ // These fallbacks provide zeroed arrays, but intrinsic is not required to
+ // return the zeroed arrays.
+ if (componentType == byte.class) return new byte[length];
+ if (componentType == boolean.class) return new boolean[length];
+ if (componentType == short.class) return new short[length];
+ if (componentType == char.class) return new char[length];
+ if (componentType == int.class) return new int[length];
+ if (componentType == float.class) return new float[length];
+ if (componentType == long.class) return new long[length];
+ if (componentType == double.class) return new double[length];
+ return null;
+ }
+
/** Throws the exception without telling the verifier. */
public native void throwException(Throwable ee);
@@ -1290,7 +1739,13 @@
* @return the number of samples actually retrieved; or -1
* if the load average is unobtainable.
*/
- public native int getLoadAverage(double[] loadavg, int nelems);
+ public int getLoadAverage(double[] loadavg, int nelems) {
+ if (nelems < 0 || nelems > 3 || nelems > loadavg.length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ return getLoadAverage0(loadavg, nelems);
+ }
// The following contain CAS-based Java implementations used on
// platforms not supporting native instructions
@@ -1718,9 +2173,6 @@
}
// JVM interface methods
- private native boolean unalignedAccess0();
- private native boolean isBigEndian0();
-
// BE is true iff the native endianness of this platform is big.
private static final boolean BE = theUnsafe.isBigEndian0();
@@ -1820,4 +2272,26 @@
private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; }
private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; }
private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; }
+
+
+
+ private native long allocateMemory0(long bytes);
+ private native long reallocateMemory0(long address, long bytes);
+ private native void freeMemory0(long address);
+ private native void setMemory0(Object o, long offset, long bytes, byte value);
+ @HotSpotIntrinsicCandidate
+ private native void copyMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
+ private native void copySwapMemory0(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes, long elemSize);
+ private native long objectFieldOffset0(Field f);
+ private native long staticFieldOffset0(Field f);
+ private native Object staticFieldBase0(Field f);
+ private native boolean shouldBeInitialized0(Class<?> c);
+ private native void ensureClassInitialized0(Class<?> c);
+ private native int arrayBaseOffset0(Class<?> arrayClass);
+ private native int arrayIndexScale0(Class<?> arrayClass);
+ private native int addressSize0();
+ private native Class<?> defineAnonymousClass0(Class<?> hostClass, byte[] data, Object[] cpPatches);
+ private native int getLoadAverage0(double[] loadavg, int nelems);
+ private native boolean unalignedAccess0();
+ private native boolean isBigEndian0();
}
--- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Thu Mar 10 11:52:54 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Thu Mar 10 16:08:20 2016 -0800
@@ -25,7 +25,7 @@
package sun.misc;
-import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -39,21 +39,29 @@
* Although the class and all methods are public, use of this class is
* limited because only trusted code can obtain instances of it.
*
+ * <em>Note:</em> It is the resposibility of the caller to make sure
+ * arguments are checked before methods of this class are
+ * called. While some rudimentary checks are performed on the input,
+ * the checks are best effort and when performance is an overriding
+ * priority, as when methods of this class are optimized by the
+ * runtime compiler, some or all checks (if any) may be elided. Hence,
+ * the caller must not rely on the checks and corresponding
+ * exceptions!
+ *
* @author John R. Rose
* @see #getUnsafe
*/
public final class Unsafe {
- private static native void registerNatives();
static {
- registerNatives();
sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe");
}
private Unsafe() {}
private static final Unsafe theUnsafe = new Unsafe();
+ private static final jdk.internal.misc.Unsafe theInternalUnsafe = jdk.internal.misc.Unsafe.getUnsafe();
/**
* Provides the caller with the capability of performing unsafe
@@ -150,8 +158,10 @@
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
- @HotSpotIntrinsicCandidate
- public native int getInt(Object o, long offset);
+ @ForceInline
+ public int getInt(Object o, long offset) {
+ return theInternalUnsafe.getInt(o, offset);
+ }
/**
* Stores a value into a given Java variable.
@@ -173,15 +183,19 @@
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
*/
- @HotSpotIntrinsicCandidate
- public native void putInt(Object o, long offset, int x);
+ @ForceInline
+ public void putInt(Object o, long offset, int x) {
+ theInternalUnsafe.putInt(o, offset, x);
+ }
/**
* Fetches a reference value from a given Java variable.
* @see #getInt(Object, long)
*/
- @HotSpotIntrinsicCandidate
- public native Object getObject(Object o, long offset);
+ @ForceInline
+ public Object getObject(Object o, long offset) {
+ return theInternalUnsafe.getObject(o, offset);
+ }
/**
* Stores a reference value into a given Java variable.
@@ -193,51 +207,95 @@
* are updated.
* @see #putInt(Object, long, int)
*/
- @HotSpotIntrinsicCandidate
- public native void putObject(Object o, long offset, Object x);
+ @ForceInline
+ public void putObject(Object o, long offset, Object x) {
+ theInternalUnsafe.putObject(o, offset, x);
+ }
+
+ /** @see #getInt(Object, long) */
+ @ForceInline
+ public boolean getBoolean(Object o, long offset) {
+ return theInternalUnsafe.getBoolean(o, offset);
+ }
+
+ /** @see #putInt(Object, long, int) */
+ @ForceInline
+ public void putBoolean(Object o, long offset, boolean x) {
+ theInternalUnsafe.putBoolean(o, offset, x);
+ }
+
+ /** @see #getInt(Object, long) */
+ @ForceInline
+ public byte getByte(Object o, long offset) {
+ return theInternalUnsafe.getByte(o, offset);
+ }
+
+ /** @see #putInt(Object, long, int) */
+ @ForceInline
+ public void putByte(Object o, long offset, byte x) {
+ theInternalUnsafe.putByte(o, offset, x);
+ }
+
+ /** @see #getInt(Object, long) */
+ @ForceInline
+ public short getShort(Object o, long offset) {
+ return theInternalUnsafe.getShort(o, offset);
+ }
+
+ /** @see #putInt(Object, long, int) */
+ @ForceInline
+ public void putShort(Object o, long offset, short x) {
+ theInternalUnsafe.putShort(o, offset, x);
+ }
/** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native boolean getBoolean(Object o, long offset);
- /** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putBoolean(Object o, long offset, boolean x);
- /** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native byte getByte(Object o, long offset);
+ @ForceInline
+ public char getChar(Object o, long offset) {
+ return theInternalUnsafe.getChar(o, offset);
+ }
+
/** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putByte(Object o, long offset, byte x);
+ @ForceInline
+ public void putChar(Object o, long offset, char x) {
+ theInternalUnsafe.putChar(o, offset, x);
+ }
+
/** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native short getShort(Object o, long offset);
- /** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putShort(Object o, long offset, short x);
- /** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native char getChar(Object o, long offset);
+ @ForceInline
+ public long getLong(Object o, long offset) {
+ return theInternalUnsafe.getLong(o, offset);
+ }
+
/** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putChar(Object o, long offset, char x);
- /** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native long getLong(Object o, long offset);
- /** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putLong(Object o, long offset, long x);
+ @ForceInline
+ public void putLong(Object o, long offset, long x) {
+ theInternalUnsafe.putLong(o, offset, x);
+ }
+
/** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native float getFloat(Object o, long offset);
+ @ForceInline
+ public float getFloat(Object o, long offset) {
+ return theInternalUnsafe.getFloat(o, offset);
+ }
+
/** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putFloat(Object o, long offset, float x);
+ @ForceInline
+ public void putFloat(Object o, long offset, float x) {
+ theInternalUnsafe.putFloat(o, offset, x);
+ }
+
/** @see #getInt(Object, long) */
- @HotSpotIntrinsicCandidate
- public native double getDouble(Object o, long offset);
+ @ForceInline
+ public double getDouble(Object o, long offset) {
+ return theInternalUnsafe.getDouble(o, offset);
+ }
+
/** @see #putInt(Object, long, int) */
- @HotSpotIntrinsicCandidate
- public native void putDouble(Object o, long offset, double x);
+ @ForceInline
+ public void putDouble(Object o, long offset, double x) {
+ theInternalUnsafe.putDouble(o, offset, x);
+ }
+
// These read VM internal data.
@@ -248,7 +306,10 @@
* @param address a memory address locating the variable
* @return the value fetched from the indicated native variable
*/
- public native Object getUncompressedObject(long address);
+ @ForceInline
+ public Object getUncompressedObject(long address) {
+ return theInternalUnsafe.getUncompressedObject(address);
+ }
/**
* Fetches the {@link java.lang.Class} Java mirror for the given native
@@ -257,7 +318,10 @@
* @param metaspaceKlass a native metaspace {@code Klass} pointer
* @return the {@link java.lang.Class} Java mirror
*/
- public native Class<?> getJavaMirror(long metaspaceKlass);
+ @ForceInline
+ public Class<?> getJavaMirror(long metaspaceKlass) {
+ return theInternalUnsafe.getJavaMirror(metaspaceKlass);
+ }
/**
* Fetches a native metaspace {@code Klass} pointer for the given Java
@@ -266,7 +330,10 @@
* @param o Java heap object for which to fetch the class pointer
* @return a native metaspace {@code Klass} pointer
*/
- public native long getKlassPointer(Object o);
+ @ForceInline
+ public long getKlassPointer(Object o) {
+ return theInternalUnsafe.getKlassPointer(o);
+ }
// These work on values in the C heap.
@@ -277,8 +344,10 @@
*
* @see #allocateMemory
*/
- @HotSpotIntrinsicCandidate
- public native byte getByte(long address);
+ @ForceInline
+ public byte getByte(long address) {
+ return theInternalUnsafe.getByte(address);
+ }
/**
* Stores a value into a given memory address. If the address is zero, or
@@ -287,45 +356,83 @@
*
* @see #getByte(long)
*/
- @HotSpotIntrinsicCandidate
- public native void putByte(long address, byte x);
+ @ForceInline
+ public void putByte(long address, byte x) {
+ theInternalUnsafe.putByte(address, x);
+ }
+
+ /** @see #getByte(long) */
+ @ForceInline
+ public short getShort(long address) {
+ return theInternalUnsafe.getShort(address);
+ }
+
+ /** @see #putByte(long, byte) */
+ @ForceInline
+ public void putShort(long address, short x) {
+ theInternalUnsafe.putShort(address, x);
+ }
+
+ /** @see #getByte(long) */
+ @ForceInline
+ public char getChar(long address) {
+ return theInternalUnsafe.getChar(address);
+ }
+
+ /** @see #putByte(long, byte) */
+ @ForceInline
+ public void putChar(long address, char x) {
+ theInternalUnsafe.putChar(address, x);
+ }
/** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native short getShort(long address);
- /** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putShort(long address, short x);
- /** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native char getChar(long address);
+ @ForceInline
+ public int getInt(long address) {
+ return theInternalUnsafe.getInt(address);
+ }
+
/** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putChar(long address, char x);
+ @ForceInline
+ public void putInt(long address, int x) {
+ theInternalUnsafe.putInt(address, x);
+ }
+
/** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native int getInt(long address);
+ @ForceInline
+ public long getLong(long address) {
+ return theInternalUnsafe.getLong(address);
+ }
+
/** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putInt(long address, int x);
+ @ForceInline
+ public void putLong(long address, long x) {
+ theInternalUnsafe.putLong(address, x);
+ }
+
/** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native long getLong(long address);
- /** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putLong(long address, long x);
- /** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native float getFloat(long address);
+ @ForceInline
+ public float getFloat(long address) {
+ return theInternalUnsafe.getFloat(address);
+ }
+
/** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putFloat(long address, float x);
+ @ForceInline
+ public void putFloat(long address, float x) {
+ theInternalUnsafe.putFloat(address, x);
+ }
+
/** @see #getByte(long) */
- @HotSpotIntrinsicCandidate
- public native double getDouble(long address);
+ @ForceInline
+ public double getDouble(long address) {
+ return theInternalUnsafe.getDouble(address);
+ }
+
/** @see #putByte(long, byte) */
- @HotSpotIntrinsicCandidate
- public native void putDouble(long address, double x);
+ @ForceInline
+ public void putDouble(long address, double x) {
+ theInternalUnsafe.putDouble(address, x);
+ }
+
/**
* Fetches a native pointer from a given memory address. If the address is
@@ -341,8 +448,10 @@
*
* @see #allocateMemory
*/
- @HotSpotIntrinsicCandidate
- public native long getAddress(long address);
+ @ForceInline
+ public long getAddress(long address) {
+ return theInternalUnsafe.getAddress(address);
+ }
/**
* Stores a native pointer into a given memory address. If the address is
@@ -354,8 +463,11 @@
*
* @see #getAddress(long)
*/
- @HotSpotIntrinsicCandidate
- public native void putAddress(long address, long x);
+ @ForceInline
+ public void putAddress(long address, long x) {
+ theInternalUnsafe.putAddress(address, x);
+ }
+
/// wrappers for malloc, realloc, free:
@@ -366,7 +478,16 @@
* aligned for all value types. Dispose of this memory by calling {@link
* #freeMemory}, or resize it with {@link #reallocateMemory}.
*
- * @throws IllegalArgumentException if the size is negative or too large
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if the size is negative or too large
* for the native size_t type
*
* @throws OutOfMemoryError if the allocation is refused by the system
@@ -374,7 +495,10 @@
* @see #getByte(long)
* @see #putByte(long, byte)
*/
- public native long allocateMemory(long bytes);
+ @ForceInline
+ public long allocateMemory(long bytes) {
+ return theInternalUnsafe.allocateMemory(bytes);
+ }
/**
* Resizes a new block of native memory, to the given size in bytes. The
@@ -386,14 +510,26 @@
* #reallocateMemory}. The address passed to this method may be null, in
* which case an allocation will be performed.
*
- * @throws IllegalArgumentException if the size is negative or too large
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if the size is negative or too large
* for the native size_t type
*
* @throws OutOfMemoryError if the allocation is refused by the system
*
* @see #allocateMemory
*/
- public native long reallocateMemory(long address, long bytes);
+ @ForceInline
+ public long reallocateMemory(long address, long bytes) {
+ return theInternalUnsafe.reallocateMemory(address, bytes);
+ }
/**
* Sets all bytes in a given block of memory to a fixed value
@@ -410,9 +546,23 @@
* If the effective address and length are (resp.) even modulo 4 or 2,
* the stores take place in units of 'int' or 'short'.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @since 1.7
*/
- public native void setMemory(Object o, long offset, long bytes, byte value);
+ @ForceInline
+ public void setMemory(Object o, long offset, long bytes, byte value) {
+ theInternalUnsafe.setMemory(o, offset, bytes, value);
+ }
/**
* Sets all bytes in a given block of memory to a fixed value
@@ -421,8 +571,9 @@
*
* <p>Equivalent to {@code setMemory(null, address, bytes, value)}.
*/
+ @ForceInline
public void setMemory(long address, long bytes, byte value) {
- setMemory(null, address, bytes, value);
+ theInternalUnsafe.setMemory(address, bytes, value);
}
/**
@@ -440,12 +591,26 @@
* If the effective addresses and length are (resp.) even modulo 4 or 2,
* the transfer takes place in units of 'int' or 'short'.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @since 1.7
*/
- @HotSpotIntrinsicCandidate
- public native void copyMemory(Object srcBase, long srcOffset,
- Object destBase, long destOffset,
- long bytes);
+ @ForceInline
+ public void copyMemory(Object srcBase, long srcOffset,
+ Object destBase, long destOffset,
+ long bytes) {
+ theInternalUnsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes);
+ }
+
/**
* Sets all bytes in a given block of memory to a copy of another
* block. This provides a <em>single-register</em> addressing mode,
@@ -453,8 +618,9 @@
*
* Equivalent to {@code copyMemory(null, srcAddress, null, destAddress, bytes)}.
*/
+ @ForceInline
public void copyMemory(long srcAddress, long destAddress, long bytes) {
- copyMemory(null, srcAddress, null, destAddress, bytes);
+ theInternalUnsafe.copyMemory(srcAddress, destAddress, bytes);
}
/**
@@ -462,9 +628,23 @@
* #allocateMemory} or {@link #reallocateMemory}. The address passed to
* this method may be null, in which case no action is taken.
*
+ * <em>Note:</em> It is the resposibility of the caller to make
+ * sure arguments are checked before the methods are called. While
+ * some rudimentary checks are performed on the input, the checks
+ * are best effort and when performance is an overriding priority,
+ * as when methods of this class are optimized by the runtime
+ * compiler, some or all checks (if any) may be elided. Hence, the
+ * caller must not rely on the checks and corresponding
+ * exceptions!
+ *
+ * @throws RuntimeException if any of the arguments is invalid
+ *
* @see #allocateMemory
*/
- public native void freeMemory(long address);
+ @ForceInline
+ public void freeMemory(long address) {
+ theInternalUnsafe.freeMemory(address);
+ }
/// random queries
@@ -473,7 +653,7 @@
* {@link #staticFieldOffset}, {@link #objectFieldOffset},
* or {@link #arrayBaseOffset}.
*/
- public static final int INVALID_FIELD_OFFSET = -1;
+ public static final int INVALID_FIELD_OFFSET = jdk.internal.misc.Unsafe.INVALID_FIELD_OFFSET;
/**
* Reports the location of a given field in the storage allocation of its
@@ -493,7 +673,10 @@
* must preserve all bits of static field offsets.
* @see #getInt(Object, long)
*/
- public native long objectFieldOffset(Field f);
+ @ForceInline
+ public long objectFieldOffset(Field f) {
+ return theInternalUnsafe.objectFieldOffset(f);
+ }
/**
* Reports the location of a given static field, in conjunction with {@link
@@ -512,7 +695,10 @@
* this method reports its result as a long value.
* @see #getInt(Object, long)
*/
- public native long staticFieldOffset(Field f);
+ @ForceInline
+ public long staticFieldOffset(Field f) {
+ return theInternalUnsafe.staticFieldOffset(f);
+ }
/**
* Reports the location of a given static field, in conjunction with {@link
@@ -524,7 +710,10 @@
* not be used in any way except as argument to the get and put routines in
* this class.
*/
- public native Object staticFieldBase(Field f);
+ @ForceInline
+ public Object staticFieldBase(Field f) {
+ return theInternalUnsafe.staticFieldBase(f);
+ }
/**
* Detects if the given class may need to be initialized. This is often
@@ -532,14 +721,20 @@
* class.
* @return false only if a call to {@code ensureClassInitialized} would have no effect
*/
- public native boolean shouldBeInitialized(Class<?> c);
+ @ForceInline
+ public boolean shouldBeInitialized(Class<?> c) {
+ return theInternalUnsafe.shouldBeInitialized(c);
+ }
/**
* Ensures the given class has been initialized. This is often
* needed in conjunction with obtaining the static field base of a
* class.
*/
- public native void ensureClassInitialized(Class<?> c);
+ @ForceInline
+ public void ensureClassInitialized(Class<?> c) {
+ theInternalUnsafe.ensureClassInitialized(c);
+ }
/**
* Reports the offset of the first element in the storage allocation of a
@@ -551,43 +746,37 @@
* @see #getInt(Object, long)
* @see #putInt(Object, long, int)
*/
- public native int arrayBaseOffset(Class<?> arrayClass);
+ @ForceInline
+ public int arrayBaseOffset(Class<?> arrayClass) {
+ return theInternalUnsafe.arrayBaseOffset(arrayClass);
+ }
/** The value of {@code arrayBaseOffset(boolean[].class)} */
- public static final int ARRAY_BOOLEAN_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(boolean[].class);
+ public static final int ARRAY_BOOLEAN_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(byte[].class)} */
- public static final int ARRAY_BYTE_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(byte[].class);
+ public static final int ARRAY_BYTE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(short[].class)} */
- public static final int ARRAY_SHORT_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(short[].class);
+ public static final int ARRAY_SHORT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(char[].class)} */
- public static final int ARRAY_CHAR_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(char[].class);
+ public static final int ARRAY_CHAR_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(int[].class)} */
- public static final int ARRAY_INT_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(int[].class);
+ public static final int ARRAY_INT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_INT_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(long[].class)} */
- public static final int ARRAY_LONG_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(long[].class);
+ public static final int ARRAY_LONG_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_LONG_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(float[].class)} */
- public static final int ARRAY_FLOAT_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(float[].class);
+ public static final int ARRAY_FLOAT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(double[].class)} */
- public static final int ARRAY_DOUBLE_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(double[].class);
+ public static final int ARRAY_DOUBLE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
/** The value of {@code arrayBaseOffset(Object[].class)} */
- public static final int ARRAY_OBJECT_BASE_OFFSET
- = theUnsafe.arrayBaseOffset(Object[].class);
+ public static final int ARRAY_OBJECT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET;
/**
* Reports the scale factor for addressing elements in the storage
@@ -600,43 +789,37 @@
* @see #getInt(Object, long)
* @see #putInt(Object, long, int)
*/
- public native int arrayIndexScale(Class<?> arrayClass);
+ @ForceInline
+ public int arrayIndexScale(Class<?> arrayClass) {
+ return theInternalUnsafe.arrayIndexScale(arrayClass);
+ }
/** The value of {@code arrayIndexScale(boolean[].class)} */
- public static final int ARRAY_BOOLEAN_INDEX_SCALE
- = theUnsafe.arrayIndexScale(boolean[].class);
+ public static final int ARRAY_BOOLEAN_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
/** The value of {@code arrayIndexScale(byte[].class)} */
- public static final int ARRAY_BYTE_INDEX_SCALE
- = theUnsafe.arrayIndexScale(byte[].class);
+ public static final int ARRAY_BYTE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE;
/** The value of {@code arrayIndexScale(short[].class)} */
- public static final int ARRAY_SHORT_INDEX_SCALE
- = theUnsafe.arrayIndexScale(short[].class);
+ public static final int ARRAY_SHORT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE;
/** The value of {@code arrayIndexScale(char[].class)} */
- public static final int ARRAY_CHAR_INDEX_SCALE
- = theUnsafe.arrayIndexScale(char[].class);
+ public static final int ARRAY_CHAR_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE;
/** The value of {@code arrayIndexScale(int[].class)} */
- public static final int ARRAY_INT_INDEX_SCALE
- = theUnsafe.arrayIndexScale(int[].class);
+ public static final int ARRAY_INT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_INT_INDEX_SCALE;
/** The value of {@code arrayIndexScale(long[].class)} */
- public static final int ARRAY_LONG_INDEX_SCALE
- = theUnsafe.arrayIndexScale(long[].class);
+ public static final int ARRAY_LONG_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_LONG_INDEX_SCALE;
/** The value of {@code arrayIndexScale(float[].class)} */
- public static final int ARRAY_FLOAT_INDEX_SCALE
- = theUnsafe.arrayIndexScale(float[].class);
+ public static final int ARRAY_FLOAT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE;
/** The value of {@code arrayIndexScale(double[].class)} */
- public static final int ARRAY_DOUBLE_INDEX_SCALE
- = theUnsafe.arrayIndexScale(double[].class);
+ public static final int ARRAY_DOUBLE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
/** The value of {@code arrayIndexScale(Object[].class)} */
- public static final int ARRAY_OBJECT_INDEX_SCALE
- = theUnsafe.arrayIndexScale(Object[].class);
+ public static final int ARRAY_OBJECT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE;
/**
* Reports the size in bytes of a native pointer, as stored via {@link
@@ -644,16 +827,22 @@
* other primitive types (as stored in native memory blocks) is determined
* fully by their information content.
*/
- public native int addressSize();
+ @ForceInline
+ public int addressSize() {
+ return theInternalUnsafe.addressSize();
+ }
/** The value of {@code addressSize()} */
- public static final int ADDRESS_SIZE = theUnsafe.addressSize();
+ public static final int ADDRESS_SIZE = theInternalUnsafe.addressSize();
/**
* Reports the size in bytes of a native memory page (whatever that is).
* This value will always be a power of two.
*/
- public native int pageSize();
+ @ForceInline
+ public int pageSize() {
+ return theInternalUnsafe.pageSize();
+ }
/// random trusted operations from JNI:
@@ -662,9 +851,12 @@
* Tells the VM to define a class, without security checks. By default, the
* class loader and protection domain come from the caller's class.
*/
- public native Class<?> defineClass(String name, byte[] b, int off, int len,
- ClassLoader loader,
- ProtectionDomain protectionDomain);
+ @ForceInline
+ public Class<?> defineClass(String name, byte[] b, int off, int len,
+ ClassLoader loader,
+ ProtectionDomain protectionDomain) {
+ return theInternalUnsafe.defineClass(name, b, off, len, loader, protectionDomain);
+ }
/**
* Defines a class but does not make it known to the class loader or system dictionary.
@@ -682,18 +874,26 @@
* @param data bytes of a class file
* @param cpPatches where non-null entries exist, they replace corresponding CP entries in data
*/
- public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);
+ @ForceInline
+ public Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
+ return theInternalUnsafe.defineAnonymousClass(hostClass, data, cpPatches);
+ }
/**
* Allocates an instance but does not run any constructor.
* Initializes the class if it has not yet been.
*/
- @HotSpotIntrinsicCandidate
- public native Object allocateInstance(Class<?> cls)
- throws InstantiationException;
+ @ForceInline
+ public Object allocateInstance(Class<?> cls)
+ throws InstantiationException {
+ return theInternalUnsafe.allocateInstance(cls);
+ }
/** Throws the exception without telling the verifier. */
- public native void throwException(Throwable ee);
+ @ForceInline
+ public void throwException(Throwable ee) {
+ theInternalUnsafe.throwException(ee);
+ }
/**
* Atomically updates Java variable to {@code x} if it is currently
@@ -704,10 +904,12 @@
*
* @return {@code true} if successful
*/
- @HotSpotIntrinsicCandidate
- public final native boolean compareAndSwapObject(Object o, long offset,
- Object expected,
- Object x);
+ @ForceInline
+ public final boolean compareAndSwapObject(Object o, long offset,
+ Object expected,
+ Object x) {
+ return theInternalUnsafe.compareAndSwapObject(o, offset, expected, x);
+ }
/**
* Atomically updates Java variable to {@code x} if it is currently
@@ -718,10 +920,12 @@
*
* @return {@code true} if successful
*/
- @HotSpotIntrinsicCandidate
- public final native boolean compareAndSwapInt(Object o, long offset,
- int expected,
- int x);
+ @ForceInline
+ public final boolean compareAndSwapInt(Object o, long offset,
+ int expected,
+ int x) {
+ return theInternalUnsafe.compareAndSwapInt(o, offset, expected, x);
+ }
/**
* Atomically updates Java variable to {@code x} if it is currently
@@ -732,88 +936,126 @@
*
* @return {@code true} if successful
*/
- @HotSpotIntrinsicCandidate
- public final native boolean compareAndSwapLong(Object o, long offset,
- long expected,
- long x);
+ @ForceInline
+ public final boolean compareAndSwapLong(Object o, long offset,
+ long expected,
+ long x) {
+ return theInternalUnsafe.compareAndSwapLong(o, offset, expected, x);
+ }
/**
* Fetches a reference value from a given Java variable, with volatile
* load semantics. Otherwise identical to {@link #getObject(Object, long)}
*/
- @HotSpotIntrinsicCandidate
- public native Object getObjectVolatile(Object o, long offset);
+ @ForceInline
+ public Object getObjectVolatile(Object o, long offset) {
+ return theInternalUnsafe.getObjectVolatile(o, offset);
+ }
/**
* Stores a reference value into a given Java variable, with
* volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)}
*/
- @HotSpotIntrinsicCandidate
- public native void putObjectVolatile(Object o, long offset, Object x);
+ @ForceInline
+ public void putObjectVolatile(Object o, long offset, Object x) {
+ theInternalUnsafe.putObjectVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getInt(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native int getIntVolatile(Object o, long offset);
+ @ForceInline
+ public int getIntVolatile(Object o, long offset) {
+ return theInternalUnsafe.getIntVolatile(o, offset);
+ }
/** Volatile version of {@link #putInt(Object, long, int)} */
- @HotSpotIntrinsicCandidate
- public native void putIntVolatile(Object o, long offset, int x);
+ @ForceInline
+ public void putIntVolatile(Object o, long offset, int x) {
+ theInternalUnsafe.putIntVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getBoolean(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native boolean getBooleanVolatile(Object o, long offset);
+ @ForceInline
+ public boolean getBooleanVolatile(Object o, long offset) {
+ return theInternalUnsafe.getBooleanVolatile(o, offset);
+ }
/** Volatile version of {@link #putBoolean(Object, long, boolean)} */
- @HotSpotIntrinsicCandidate
- public native void putBooleanVolatile(Object o, long offset, boolean x);
+ @ForceInline
+ public void putBooleanVolatile(Object o, long offset, boolean x) {
+ theInternalUnsafe.putBooleanVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getByte(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native byte getByteVolatile(Object o, long offset);
+ @ForceInline
+ public byte getByteVolatile(Object o, long offset) {
+ return theInternalUnsafe.getByteVolatile(o, offset);
+ }
/** Volatile version of {@link #putByte(Object, long, byte)} */
- @HotSpotIntrinsicCandidate
- public native void putByteVolatile(Object o, long offset, byte x);
+ @ForceInline
+ public void putByteVolatile(Object o, long offset, byte x) {
+ theInternalUnsafe.putByteVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getShort(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native short getShortVolatile(Object o, long offset);
+ @ForceInline
+ public short getShortVolatile(Object o, long offset) {
+ return theInternalUnsafe.getShortVolatile(o, offset);
+ }
/** Volatile version of {@link #putShort(Object, long, short)} */
- @HotSpotIntrinsicCandidate
- public native void putShortVolatile(Object o, long offset, short x);
+ @ForceInline
+ public void putShortVolatile(Object o, long offset, short x) {
+ theInternalUnsafe.putShortVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getChar(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native char getCharVolatile(Object o, long offset);
+ @ForceInline
+ public char getCharVolatile(Object o, long offset) {
+ return theInternalUnsafe.getCharVolatile(o, offset);
+ }
/** Volatile version of {@link #putChar(Object, long, char)} */
- @HotSpotIntrinsicCandidate
- public native void putCharVolatile(Object o, long offset, char x);
+ @ForceInline
+ public void putCharVolatile(Object o, long offset, char x) {
+ theInternalUnsafe.putCharVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getLong(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native long getLongVolatile(Object o, long offset);
+ @ForceInline
+ public long getLongVolatile(Object o, long offset) {
+ return theInternalUnsafe.getLongVolatile(o, offset);
+ }
/** Volatile version of {@link #putLong(Object, long, long)} */
- @HotSpotIntrinsicCandidate
- public native void putLongVolatile(Object o, long offset, long x);
+ @ForceInline
+ public void putLongVolatile(Object o, long offset, long x) {
+ theInternalUnsafe.putLongVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getFloat(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native float getFloatVolatile(Object o, long offset);
+ @ForceInline
+ public float getFloatVolatile(Object o, long offset) {
+ return theInternalUnsafe.getFloatVolatile(o, offset);
+ }
/** Volatile version of {@link #putFloat(Object, long, float)} */
- @HotSpotIntrinsicCandidate
- public native void putFloatVolatile(Object o, long offset, float x);
+ @ForceInline
+ public void putFloatVolatile(Object o, long offset, float x) {
+ theInternalUnsafe.putFloatVolatile(o, offset, x);
+ }
/** Volatile version of {@link #getDouble(Object, long)} */
- @HotSpotIntrinsicCandidate
- public native double getDoubleVolatile(Object o, long offset);
+ @ForceInline
+ public double getDoubleVolatile(Object o, long offset) {
+ return theInternalUnsafe.getDoubleVolatile(o, offset);
+ }
/** Volatile version of {@link #putDouble(Object, long, double)} */
- @HotSpotIntrinsicCandidate
- public native void putDoubleVolatile(Object o, long offset, double x);
+ @ForceInline
+ public void putDoubleVolatile(Object o, long offset, double x) {
+ theInternalUnsafe.putDoubleVolatile(o, offset, x);
+ }
/**
* Version of {@link #putObjectVolatile(Object, long, Object)}
@@ -824,16 +1066,22 @@
*
* Corresponds to C11 atomic_store_explicit(..., memory_order_release).
*/
- @HotSpotIntrinsicCandidate
- public native void putOrderedObject(Object o, long offset, Object x);
+ @ForceInline
+ public void putOrderedObject(Object o, long offset, Object x) {
+ theInternalUnsafe.putOrderedObject(o, offset, x);
+ }
/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */
- @HotSpotIntrinsicCandidate
- public native void putOrderedInt(Object o, long offset, int x);
+ @ForceInline
+ public void putOrderedInt(Object o, long offset, int x) {
+ theInternalUnsafe.putOrderedInt(o, offset, x);
+ }
/** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */
- @HotSpotIntrinsicCandidate
- public native void putOrderedLong(Object o, long offset, long x);
+ @ForceInline
+ public void putOrderedLong(Object o, long offset, long x) {
+ theInternalUnsafe.putOrderedLong(o, offset, x);
+ }
/**
* Unblocks the given thread blocked on {@code park}, or, if it is
@@ -847,8 +1095,10 @@
*
* @param thread the thread to unpark.
*/
- @HotSpotIntrinsicCandidate
- public native void unpark(Object thread);
+ @ForceInline
+ public void unpark(Object thread) {
+ theInternalUnsafe.unpark(thread);
+ }
/**
* Blocks current thread, returning when a balancing
@@ -861,8 +1111,10 @@
* because {@code unpark} is, so it would be strange to place it
* elsewhere.
*/
- @HotSpotIntrinsicCandidate
- public native void park(boolean isAbsolute, long time);
+ @ForceInline
+ public void park(boolean isAbsolute, long time) {
+ theInternalUnsafe.park(isAbsolute, time);
+ }
/**
* Gets the load average in the system run queue assigned
@@ -879,7 +1131,10 @@
* @return the number of samples actually retrieved; or -1
* if the load average is unobtainable.
*/
- public native int getLoadAverage(double[] loadavg, int nelems);
+ @ForceInline
+ public int getLoadAverage(double[] loadavg, int nelems) {
+ return theInternalUnsafe.getLoadAverage(loadavg, nelems);
+ }
// The following contain CAS-based Java implementations used on
// platforms not supporting native instructions
@@ -895,13 +1150,9 @@
* @return the previous value
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
+ @ForceInline
public final int getAndAddInt(Object o, long offset, int delta) {
- int v;
- do {
- v = getIntVolatile(o, offset);
- } while (!compareAndSwapInt(o, offset, v, v + delta));
- return v;
+ return theInternalUnsafe.getAndAddInt(o, offset, delta);
}
/**
@@ -915,13 +1166,9 @@
* @return the previous value
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
+ @ForceInline
public final long getAndAddLong(Object o, long offset, long delta) {
- long v;
- do {
- v = getLongVolatile(o, offset);
- } while (!compareAndSwapLong(o, offset, v, v + delta));
- return v;
+ return theInternalUnsafe.getAndAddLong(o, offset, delta);
}
/**
@@ -935,13 +1182,9 @@
* @return the previous value
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
+ @ForceInline
public final int getAndSetInt(Object o, long offset, int newValue) {
- int v;
- do {
- v = getIntVolatile(o, offset);
- } while (!compareAndSwapInt(o, offset, v, newValue));
- return v;
+ return theInternalUnsafe.getAndSetInt(o, offset, newValue);
}
/**
@@ -955,13 +1198,9 @@
* @return the previous value
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
+ @ForceInline
public final long getAndSetLong(Object o, long offset, long newValue) {
- long v;
- do {
- v = getLongVolatile(o, offset);
- } while (!compareAndSwapLong(o, offset, v, newValue));
- return v;
+ return theInternalUnsafe.getAndSetLong(o, offset, newValue);
}
/**
@@ -975,13 +1214,9 @@
* @return the previous value
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
+ @ForceInline
public final Object getAndSetObject(Object o, long offset, Object newValue) {
- Object v;
- do {
- v = getObjectVolatile(o, offset);
- } while (!compareAndSwapObject(o, offset, v, newValue));
- return v;
+ return theInternalUnsafe.getAndSetObject(o, offset, newValue);
}
@@ -997,8 +1232,10 @@
* provide a LoadLoad barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
- public native void loadFence();
+ @ForceInline
+ public void loadFence() {
+ theInternalUnsafe.loadFence();
+ }
/**
* Ensures that loads and stores before the fence will not be reordered with
@@ -1012,8 +1249,10 @@
* provide a StoreStore barrier also provide a LoadStore barrier for free.
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
- public native void storeFence();
+ @ForceInline
+ public void storeFence() {
+ theInternalUnsafe.storeFence();
+ }
/**
* Ensures that loads and stores before the fence will not be reordered
@@ -1024,15 +1263,8 @@
* Corresponds to C11 atomic_thread_fence(memory_order_seq_cst).
* @since 1.8
*/
- @HotSpotIntrinsicCandidate
- public native void fullFence();
-
- /**
- * Throws IllegalAccessError; for use by the VM for access control
- * error support.
- * @since 1.8
- */
- private static void throwIllegalAccessError() {
- throw new IllegalAccessError();
+ @ForceInline
+ public void fullFence() {
+ theInternalUnsafe.fullFence();
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java Thu Mar 10 16:08:20 2016 -0800
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+import jdk.internal.misc.Unsafe;
+import java.lang.reflect.Field;
+
+/*
+ * @test
+ * @summary Test Unsafe.copyMemory
+ * @modules java.base/jdk.internal.misc
+ */
+public class CopyMemory {
+ private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG");
+
+ public static final long KB = 1024;
+ public static final long MB = KB * 1024;
+ public static final long GB = MB * 1024;
+
+ private static final Unsafe UNSAFE;
+ private static final int SMALL_COPY_SIZE = 32;
+ private static final int BASE_ALIGNMENT = 16;
+
+ static {
+ try {
+ Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ UNSAFE = (jdk.internal.misc.Unsafe) f.get(null);
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to get Unsafe instance.", e);
+ }
+ }
+
+ private static long alignDown(long value, long alignment) {
+ return value & ~(alignment - 1);
+ }
+
+ private static long alignUp(long value, long alignment) {
+ return (value + alignment - 1) & ~(alignment - 1);
+ }
+
+ private static boolean isAligned(long value, long alignment) {
+ return value == alignDown(value, alignment);
+ }
+
+ private CopyMemory() {
+ }
+
+ /**
+ * Generate verification data for a given offset
+ *
+ * The verification data is used to verify that the correct bytes
+ * have indeed been copied and byte swapped.
+ *
+ * The data is generated based on the offset (in bytes) into the
+ * source buffer. For a native buffer the offset is relative to
+ * the base pointer. For a heap array it is relative to the
+ * address of the first array element.
+ *
+ * This method will return the result of doing an elementSize byte
+ * read starting at offset (in bytes).
+ *
+ * @param offset offset into buffer
+ * @param elemSize size (in bytes) of the element
+ *
+ * @return the verification data, only the least significant
+ * elemSize*8 bits are set, zero extended
+ */
+ private long getVerificationDataForOffset(long offset, long elemSize) {
+ byte[] bytes = new byte[(int)elemSize];
+
+ for (long i = 0; i < elemSize; i++) {
+ bytes[(int)i] = (byte)(offset + i);
+ }
+
+ long o = UNSAFE.arrayBaseOffset(byte[].class);
+
+ switch ((int)elemSize) {
+ case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o));
+ case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o));
+ case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o));
+ case 8: return UNSAFE.getLongUnaligned(bytes, o);
+ default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+ }
+ }
+
+ /**
+ * Verify byte swapped data
+ *
+ * @param ptr the data to verify
+ * @param srcOffset the srcOffset (in bytes) from which the copy started,
+ * used as key to regenerate the verification data
+ * @param dstOffset the offset (in bytes) in the array at which to start
+ * the verification, relative to the first element in the array
+ * @param size size (in bytes) of data to to verify
+ * @param elemSize size (in bytes) of the individual array elements
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) {
+ for (long offset = 0; offset < size; offset += elemSize) {
+ long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize);
+ long expected = byteSwap(expectedUnswapped, elemSize);
+
+ long actual = getArrayElem(ptr, dstOffset + offset, elemSize);
+
+ if (expected != actual) {
+ throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) +
+ " dstOffset: 0x" + Long.toHexString(dstOffset) +
+ " size: 0x" + Long.toHexString(size) +
+ " offset: 0x" + Long.toHexString(offset) +
+ " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) +
+ " expected: 0x" + Long.toHexString(expected) +
+ " != actual: 0x" + Long.toHexString(actual));
+ }
+ }
+ }
+
+ /**
+ * Initialize an array with verification friendly data
+ *
+ * @param ptr pointer to the data to initialize
+ * @param size size (in bytes) of the data
+ * @param elemSize size (in bytes) of the individual elements
+ */
+ private void initVerificationData(GenericPointer ptr, long size, long elemSize) {
+ for (long offset = 0; offset < size; offset++) {
+ byte data = (byte)getVerificationDataForOffset(offset, 1);
+
+ if (ptr.isOnHeap()) {
+ UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data);
+ } else {
+ UNSAFE.putByte(ptr.getOffset() + offset, data);
+ }
+ }
+ }
+
+ /**
+ * Allocate a primitive array
+ *
+ * @param size size (in bytes) of all the array elements (elemSize * length)
+ * @param elemSize the size of the array elements
+ *
+ * @return a newly allocated primitive array
+ */
+ Object allocArray(long size, long elemSize) {
+ int length = (int)(size / elemSize);
+
+ switch ((int)elemSize) {
+ case 1: return new byte[length];
+ case 2: return new short[length];
+ case 4: return new int[length];
+ case 8: return new long[length];
+ default:
+ throw new IllegalArgumentException("Invalid element size: " + elemSize);
+ }
+ }
+
+ /**
+ * Get the value of a primitive array entry
+ *
+ * @param ptr pointer to the data
+ * @param offset offset (in bytes) of the array element, relative to the first element in the array
+ *
+ * @return the array element, as an unsigned long
+ */
+ private long getArrayElem(GenericPointer ptr, long offset, long elemSize) {
+ if (ptr.isOnHeap()) {
+ Object o = ptr.getObject();
+ int index = (int)(offset / elemSize);
+
+ if (o instanceof short[]) {
+ short[] arr = (short[])o;
+ return Short.toUnsignedLong(arr[index]);
+ } else if (o instanceof int[]) {
+ int[] arr = (int[])o;
+ return Integer.toUnsignedLong(arr[index]);
+ } else if (o instanceof long[]) {
+ long[] arr = (long[])o;
+ return arr[index];
+ } else {
+ throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+ }
+ } else {
+ long addr = ptr.getOffset() + offset;
+
+ switch ((int)elemSize) {
+ case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr));
+ case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr));
+ case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr));
+ case 8: return UNSAFE.getLongUnaligned(null, addr);
+ default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+ }
+ }
+ }
+
+ private void putValue(long addr, long elemSize, long value) {
+ switch ((int)elemSize) {
+ case 1: UNSAFE.putByte(addr, (byte)value); break;
+ case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break;
+ case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break;
+ case 8: UNSAFE.putLongUnaligned(null, addr, value); break;
+ default: throw new IllegalArgumentException("Invalid element size: " + elemSize);
+ }
+ }
+
+ /**
+ * Get the size of the elements for an array
+ *
+ * @param o a primitive heap array
+ *
+ * @return the size (in bytes) of the individual array elements
+ */
+ private long getArrayElemSize(Object o) {
+ if (o instanceof short[]) {
+ return 2;
+ } else if (o instanceof int[]) {
+ return 4;
+ } else if (o instanceof long[]) {
+ return 8;
+ } else {
+ throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName());
+ }
+ }
+
+ /**
+ * Byte swap a value
+ *
+ * @param value the value to swap, only the bytes*8 least significant bits are used
+ * @param size size (in bytes) of the value
+ *
+ * @return the byte swapped value in the bytes*8 least significant bits
+ */
+ private long byteSwap(long value, long size) {
+ switch ((int)size) {
+ case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value));
+ case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value));
+ case 8: return Long.reverseBytes(value);
+ default: throw new IllegalArgumentException("Invalid element size: " + size);
+ }
+ }
+
+ /**
+ * Verify data which has *not* been byte swapped
+ *
+ * @param ptr the data to verify
+ * @param startOffset the offset (in bytes) at which to start the verification
+ * @param size size (in bytes) of the data to verify
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) {
+ for (long i = 0; i < size; i++) {
+ byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1);
+
+ byte actual;
+ if (ptr.isOnHeap()) {
+ actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i);
+ } else {
+ actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i);
+ }
+
+ if (expected != actual) {
+ throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) +
+ " srcOffset: 0x" + Long.toHexString(srcOffset) +
+ " size: 0x" + Long.toHexString(size) +
+ " i: 0x" + Long.toHexString(i) +
+ " expected: 0x" + Long.toHexString(expected) +
+ " != actual: 0x" + Long.toHexString(actual));
+ }
+ }
+ }
+
+
+ /**
+ * Copy and byte swap data from the source to the destination
+ *
+ * This method will pre-populate the whole source and destination
+ * buffers with verification friendly data. It will then use
+ * copypMemory to fill part of the destination buffer with
+ * data from the source. Some space (padding) will be
+ * left before and after the data in the destination buffer, which
+ * should not be touched/overwritten by the copy call.
+ *
+ * Note: Both source and destination buffers will be overwritten!
+ *
+ * @param src source buffer to copy from
+ * @param srcOffset the offset (in bytes) in the source buffer, relative to
+ * the first array element, at which to start reading data
+ * @param dst destination buffer to copy to
+ * @param dstOffset the offset (in bytes) in the destination
+ * buffer, relative to the first array element, at which to
+ * start writing data
+ * @param bufSize the size (in bytes) of the src and dst arrays
+ * @param copyBytes the size (in bytes) of the copy to perform,
+ * must be a multiple of elemSize
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void testCopy(GenericPointer src, long srcOffset,
+ GenericPointer dst, long dstOffset,
+ long bufSize, long copyBytes) {
+ if (srcOffset + copyBytes > bufSize) {
+ throw new IllegalArgumentException(
+ "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+ }
+ if (dstOffset + copyBytes > bufSize) {
+ throw new IllegalArgumentException(
+ "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")");
+ }
+
+ // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes)
+ initVerificationData(src, bufSize, 1);
+ if (!src.equals(dst)) {
+ initVerificationData(dst, bufSize, 1);
+ }
+
+ if (DEBUG) {
+ System.out.println("===before===");
+ for (int offset = 0; offset < bufSize; offset++) {
+ long srcValue = getArrayElem(src, offset, 1);
+ long dstValue = getArrayElem(dst, offset, 1);
+
+ System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+ " src=0x" + Long.toHexString(srcValue) +
+ " dst=0x" + Long.toHexString(dstValue));
+ }
+ }
+
+ // Copy & swap data into the middle of the destination buffer
+ UNSAFE.copyMemory(src.getObject(),
+ src.getOffset() + srcOffset,
+ dst.getObject(),
+ dst.getOffset() + dstOffset,
+ copyBytes);
+
+ if (DEBUG) {
+ System.out.println("===after===");
+ for (int offset = 0; offset < bufSize; offset++) {
+ long srcValue = getArrayElem(src, offset, 1);
+ long dstValue = getArrayElem(dst, offset, 1);
+
+ System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) +
+ " src=0x" + Long.toHexString(srcValue) +
+ " dst=0x" + Long.toHexString(dstValue));
+ }
+ }
+
+ // Verify the the front padding is unchanged
+ verifyUnswappedData(dst, 0, 0, dstOffset);
+
+ // Verify copied data
+ verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes);
+
+ // Verify that the back back padding is unchanged
+ long frontAndDataBytes = dstOffset + copyBytes;
+ long trailingBytes = bufSize - frontAndDataBytes;
+ verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes);
+ }
+
+ /**
+ * Test various configurations copying from one buffer to the other
+ *
+ * @param src the source buffer to copy from
+ * @param dst the destination buffer to copy to
+ * @param size size (in bytes) of the buffers
+ * @param elemSize size (in bytes) of the individual elements
+ *
+ * @throws RuntimeException if an error is found
+ */
+ public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) {
+ // offset in source from which to start reading data
+ for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) {
+
+ // offset in destination at which to start writing data
+ for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) {
+
+ // number of bytes to copy
+ long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset);
+ for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) {
+ try {
+ testCopy(src, srcOffset, dst, dstOffset, size, copyBytes);
+ } catch (RuntimeException e) {
+ // Wrap the exception in another exception to catch the relevant configuration data
+ throw new RuntimeException("testBufferPair: " +
+ "src=" + src +
+ " dst=" + dst +
+ " elemSize=0x" + Long.toHexString(elemSize) +
+ " copyBytes=0x" + Long.toHexString(copyBytes) +
+ " srcOffset=0x" + Long.toHexString(srcOffset) +
+ " dstOffset=0x" + Long.toHexString(dstOffset),
+ e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Test copying between various permutations of buffers
+ *
+ * @param buffers buffers to permute (src x dst)
+ * @param size size (in bytes) of buffers
+ * @param elemSize size (in bytes) of individual elements
+ *
+ * @throws RuntimeException if an error is found
+ */
+ public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) {
+ for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) {
+ for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) {
+ testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize);
+ }
+ }
+ }
+
+ /**
+ * Test copying of a specific element size
+ *
+ * @param size size (in bytes) of buffers to allocate
+ * @param elemSize size (in bytes) of individual elements
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void testElemSize(long size, long elemSize) {
+ long buf1Raw = 0;
+ long buf2Raw = 0;
+
+ try {
+ buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+ long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT);
+
+ buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+ long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT);
+
+ GenericPointer[] buffers = {
+ new GenericPointer(buf1),
+ new GenericPointer(buf2),
+ new GenericPointer(allocArray(size, elemSize)),
+ new GenericPointer(allocArray(size, elemSize))
+ };
+
+ testPermuteBuffers(buffers, size, elemSize);
+ } finally {
+ if (buf1Raw != 0) {
+ UNSAFE.freeMemory(buf1Raw);
+ }
+ if (buf2Raw != 0) {
+ UNSAFE.freeMemory(buf2Raw);
+ }
+ }
+ }
+
+ /**
+ * Verify that small copies work
+ */
+ private void testSmallCopy() {
+ int smallBufSize = SMALL_COPY_SIZE;
+
+ testElemSize(smallBufSize, 1);
+ }
+
+
+ /**
+ * Verify that large copies work
+ */
+ private void testLargeCopy() {
+ long size = 2 * GB + 8;
+ long bufRaw = 0;
+
+ // Check that a large native copy succeeds
+ try {
+ try {
+ bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT);
+ } catch (OutOfMemoryError e) {
+ // Accept failure, skip test
+ return;
+ }
+
+ long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+
+ UNSAFE.copyMemory(null, buf, null, buf, size);
+ } catch (Exception e) {
+ throw new RuntimeException("copyMemory of large buffer failed");
+ } finally {
+ if (bufRaw != 0) {
+ UNSAFE.freeMemory(bufRaw);
+ }
+ }
+ }
+
+ /**
+ * Run positive tests
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void testPositive() {
+ testSmallCopy();
+ testLargeCopy();
+ }
+
+ /**
+ * Run negative tests, testing corner cases and the various exceptions
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void testNegative() {
+ long bufRaw = 0;
+
+ try {
+ bufRaw = UNSAFE.allocateMemory(1024);
+ long buf = alignUp(bufRaw, BASE_ALIGNMENT);
+ short[] arr = new short[16];
+
+ // Check illegal sizes
+ System.out.println("Testing negative size");
+ try {
+ UNSAFE.copyMemory(null, buf, null, buf, -1);
+ throw new RuntimeException("copyMemory failed to throw IAE for size=-1");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+
+ System.out.println("Testing negative srcOffset");
+ try {
+ // Check that negative srcOffset throws an IAE
+ UNSAFE.copyMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16);
+ throw new RuntimeException("copyMemory failed to throw IAE for srcOffset=-1");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+
+ System.out.println("Testing negative destOffset");
+ try {
+ // Check that negative dstOffset throws an IAE
+ UNSAFE.copyMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16);
+ throw new RuntimeException("copyMemory failed to throw IAE for destOffset=-1");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+
+ System.out.println("Testing reference array");
+ try {
+ // Check that a reference array destination throws IAE
+ UNSAFE.copyMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16);
+ throw new RuntimeException("copyMemory failed to throw IAE");
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+
+ // Check that invalid source & dest pointers throw IAEs (only relevant on 32-bit platforms)
+ if (UNSAFE.addressSize() == 4) {
+ long invalidPtr = (long)1 << 35; // Pick a random bit in upper 32 bits
+
+ try {
+ // Check that an invalid (not 32-bit clean) source pointer throws IAE
+ UNSAFE.copyMemory(null, invalidPtr, null, buf, 16);
+ throw new RuntimeException("copyMemory failed to throw IAE for srcOffset 0x" +
+ Long.toHexString(invalidPtr));
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+
+ try {
+ // Check that an invalid (not 32-bit clean) source pointer throws IAE
+ UNSAFE.copyMemory(null, buf, null, invalidPtr, 16);
+ throw new RuntimeException("copyMemory failed to throw IAE for destOffset 0x" +
+ Long.toHexString(invalidPtr));
+ } catch (IllegalArgumentException e) {
+ // good
+ }
+ }
+ } finally {
+ if (bufRaw != 0) {
+ UNSAFE.freeMemory(bufRaw);
+ }
+ }
+ }
+
+ /**
+ * Run all tests
+ *
+ * @throws RuntimeException if an error is found
+ */
+ private void test() {
+ testPositive();
+ testNegative();
+ }
+
+ public static void main(String[] args) {
+ CopyMemory cs = new CopyMemory();
+ cs.test();
+ }
+
+ /**
+ * Helper class to represent a "pointer" - either a heap array or
+ * a pointer to a native buffer.
+ *
+ * In the case of a native pointer, the Object is null and the offset is
+ * the absolute address of the native buffer.
+ *
+ * In the case of a heap object, the Object is a primitive array, and
+ * the offset will be set to the base offset to the first element, meaning
+ * the object and the offset together form a double-register pointer.
+ */
+ static class GenericPointer {
+ private final Object o;
+ private final long offset;
+
+ private GenericPointer(Object o, long offset) {
+ this.o = o;
+ this.offset = offset;
+ }
+
+ public String toString() {
+ return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")";
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof GenericPointer)) {
+ return false;
+ }
+
+ GenericPointer otherp = (GenericPointer)other;
+
+ return o == otherp.o && offset == otherp.offset;
+ }
+
+ GenericPointer(Object o) {
+ this(o, UNSAFE.arrayBaseOffset(o.getClass()));
+ }
+
+ GenericPointer(long offset) {
+ this(null, offset);
+ }
+
+ public boolean isOnHeap() {
+ return o != null;
+ }
+
+ public Object getObject() {
+ return o;
+ }
+
+ public long getOffset() {
+ return offset;
+ }
+ }
+}