Merge
This commit is contained in:
commit
d147a661d8
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -137,12 +137,6 @@ ifeq ($(OPENJDK_TARGET_OS), solaris)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(OPENJDK_TARGET_OS), linux)
|
|
||||||
ifeq ($(OPENJDK_TARGET_CPU), x86_64)
|
|
||||||
BUILD_LIBJAVA_Bits.c_CFLAGS := $(C_O_FLAG_NORM)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
$(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \
|
$(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \
|
||||||
LIBRARY := java, \
|
LIBRARY := java, \
|
||||||
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
|
||||||
|
@ -229,12 +229,6 @@ SUNWprivate_1.1 {
|
|||||||
Java_java_lang_Throwable_fillInStackTrace;
|
Java_java_lang_Throwable_fillInStackTrace;
|
||||||
Java_java_lang_Throwable_getStackTraceDepth;
|
Java_java_lang_Throwable_getStackTraceDepth;
|
||||||
Java_java_lang_Throwable_getStackTraceElement;
|
Java_java_lang_Throwable_getStackTraceElement;
|
||||||
Java_java_nio_Bits_copyFromShortArray;
|
|
||||||
Java_java_nio_Bits_copyToShortArray;
|
|
||||||
Java_java_nio_Bits_copyFromIntArray;
|
|
||||||
Java_java_nio_Bits_copyToIntArray;
|
|
||||||
Java_java_nio_Bits_copyFromLongArray;
|
|
||||||
Java_java_nio_Bits_copyToLongArray;
|
|
||||||
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2;
|
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2;
|
||||||
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedAction_2Ljava_security_AccessControlContext_2;
|
||||||
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2;
|
Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2;
|
||||||
|
@ -778,8 +778,21 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
|||||||
return (asTypeCache = wrapper);
|
return (asTypeCache = wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Customize target if counting happens for too long.
|
||||||
|
private int invocations = CUSTOMIZE_THRESHOLD;
|
||||||
|
private void maybeCustomizeTarget() {
|
||||||
|
int c = invocations;
|
||||||
|
if (c >= 0) {
|
||||||
|
if (c == 1) {
|
||||||
|
target.customize();
|
||||||
|
}
|
||||||
|
invocations = c - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boolean countDown() {
|
boolean countDown() {
|
||||||
int c = count;
|
int c = count;
|
||||||
|
maybeCustomizeTarget();
|
||||||
if (c <= 1) {
|
if (c <= 1) {
|
||||||
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
|
// Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility.
|
||||||
if (isCounting) {
|
if (isCounting) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -807,31 +807,131 @@ class Bits { // package-private
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyFromCharArray(Object src, long srcPos, long dstAddr,
|
/**
|
||||||
long length)
|
* Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
|
||||||
{
|
*
|
||||||
copyFromShortArray(src, srcPos, dstAddr, length);
|
* @param src
|
||||||
|
* the source array, must be a 16-bit primitive array type
|
||||||
|
* @param srcPos
|
||||||
|
* byte offset within source array of the first element to read
|
||||||
|
* @param dstAddr
|
||||||
|
* destination address
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyFromCharArray(Object src, long srcPos, long dstAddr, long length) {
|
||||||
|
unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyToCharArray(long srcAddr, Object dst, long dstPos,
|
/**
|
||||||
long length)
|
* Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
|
||||||
{
|
*
|
||||||
copyToShortArray(srcAddr, dst, dstPos, length);
|
* @param srcAddr
|
||||||
|
* source address
|
||||||
|
* @param dst
|
||||||
|
* destination array, must be a 16-bit primitive array type
|
||||||
|
* @param dstPos
|
||||||
|
* byte offset within the destination array of the first element to write
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyToCharArray(long srcAddr, Object dst, long dstPos, long length) {
|
||||||
|
unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static native void copyFromShortArray(Object src, long srcPos, long dstAddr,
|
/**
|
||||||
long length);
|
* Copy and unconditionally byte swap 16 bit elements from a heap array to off-heap memory
|
||||||
static native void copyToShortArray(long srcAddr, Object dst, long dstPos,
|
*
|
||||||
long length);
|
* @param src
|
||||||
|
* the source array, must be a 16-bit primitive array type
|
||||||
|
* @param srcPos
|
||||||
|
* byte offset within source array of the first element to read
|
||||||
|
* @param dstAddr
|
||||||
|
* destination address
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyFromShortArray(Object src, long srcPos, long dstAddr, long length) {
|
||||||
|
unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 2);
|
||||||
|
}
|
||||||
|
|
||||||
static native void copyFromIntArray(Object src, long srcPos, long dstAddr,
|
/**
|
||||||
long length);
|
* Copy and unconditionally byte swap 16 bit elements from off-heap memory to a heap array
|
||||||
static native void copyToIntArray(long srcAddr, Object dst, long dstPos,
|
*
|
||||||
long length);
|
* @param srcAddr
|
||||||
|
* source address
|
||||||
|
* @param dst
|
||||||
|
* destination array, must be a 16-bit primitive array type
|
||||||
|
* @param dstPos
|
||||||
|
* byte offset within the destination array of the first element to write
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyToShortArray(long srcAddr, Object dst, long dstPos, long length) {
|
||||||
|
unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 2);
|
||||||
|
}
|
||||||
|
|
||||||
static native void copyFromLongArray(Object src, long srcPos, long dstAddr,
|
/**
|
||||||
long length);
|
* Copy and unconditionally byte swap 32 bit elements from a heap array to off-heap memory
|
||||||
static native void copyToLongArray(long srcAddr, Object dst, long dstPos,
|
*
|
||||||
long length);
|
* @param src
|
||||||
|
* the source array, must be a 32-bit primitive array type
|
||||||
|
* @param srcPos
|
||||||
|
* byte offset within source array of the first element to read
|
||||||
|
* @param dstAddr
|
||||||
|
* destination address
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyFromIntArray(Object src, long srcPos, long dstAddr, long length) {
|
||||||
|
unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy and unconditionally byte swap 32 bit elements from off-heap memory to a heap array
|
||||||
|
*
|
||||||
|
* @param srcAddr
|
||||||
|
* source address
|
||||||
|
* @param dst
|
||||||
|
* destination array, must be a 32-bit primitive array type
|
||||||
|
* @param dstPos
|
||||||
|
* byte offset within the destination array of the first element to write
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyToIntArray(long srcAddr, Object dst, long dstPos, long length) {
|
||||||
|
unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy and unconditionally byte swap 64 bit elements from a heap array to off-heap memory
|
||||||
|
*
|
||||||
|
* @param src
|
||||||
|
* the source array, must be a 64-bit primitive array type
|
||||||
|
* @param srcPos
|
||||||
|
* byte offset within source array of the first element to read
|
||||||
|
* @param dstAddr
|
||||||
|
* destination address
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyFromLongArray(Object src, long srcPos, long dstAddr, long length) {
|
||||||
|
unsafe.copySwapMemory(src, unsafe.arrayBaseOffset(src.getClass()) + srcPos, null, dstAddr, length, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy and unconditionally byte swap 64 bit elements from off-heap memory to a heap array
|
||||||
|
*
|
||||||
|
* @param srcAddr
|
||||||
|
* source address
|
||||||
|
* @param dst
|
||||||
|
* destination array, must be a 64-bit primitive array type
|
||||||
|
* @param dstPos
|
||||||
|
* byte offset within the destination array of the first element to write
|
||||||
|
* @param length
|
||||||
|
* number of bytes to copy
|
||||||
|
*/
|
||||||
|
static void copyToLongArray(long srcAddr, Object dst, long dstPos, long length) {
|
||||||
|
unsafe.copySwapMemory(null, srcAddr, dst, unsafe.arrayBaseOffset(dst.getClass()) + dstPos, length, 8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -458,6 +458,78 @@ public final class Unsafe {
|
|||||||
copyMemory(null, srcAddress, null, destAddress, bytes);
|
copyMemory(null, srcAddress, null, destAddress, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isPrimitiveArray(Class<?> c) {
|
||||||
|
Class<?> componentType = c.getComponentType();
|
||||||
|
return componentType != null && componentType.isPrimitive();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* <p>This method determines each block's base address by means of two parameters,
|
||||||
|
* and so it provides (in effect) a <em>double-register</em> addressing mode,
|
||||||
|
* as discussed in {@link #getInt(Object,long)}. When the object reference is null,
|
||||||
|
* the offset supplies an absolute base address.
|
||||||
|
*
|
||||||
|
* @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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
copySwapMemory0(srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all elements from one block of memory to another block, byte swapping the
|
||||||
|
* elements on the fly.
|
||||||
|
*
|
||||||
|
* This provides a <em>single-register</em> addressing mode, as
|
||||||
|
* discussed in {@link #getInt(Object,long)}.
|
||||||
|
*
|
||||||
|
* Equivalent to {@code copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize)}.
|
||||||
|
*/
|
||||||
|
public void copySwapMemory(long srcAddress, long destAddress, long bytes, long elemSize) {
|
||||||
|
copySwapMemory(null, srcAddress, null, destAddress, bytes, elemSize);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disposes of a block of native memory, as obtained from {@link
|
* Disposes of a block of native memory, as obtained from {@link
|
||||||
* #allocateMemory} or {@link #reallocateMemory}. The address passed to
|
* #allocateMemory} or {@link #reallocateMemory}. The address passed to
|
||||||
@ -1159,7 +1231,12 @@ public final class Unsafe {
|
|||||||
/** @see #getLongUnaligned(Object, long) */
|
/** @see #getLongUnaligned(Object, long) */
|
||||||
@HotSpotIntrinsicCandidate
|
@HotSpotIntrinsicCandidate
|
||||||
public final char getCharUnaligned(Object o, long offset) {
|
public final char getCharUnaligned(Object o, long offset) {
|
||||||
return (char)getShortUnaligned(o, offset);
|
if ((offset & 1) == 0) {
|
||||||
|
return getChar(o, offset);
|
||||||
|
} else {
|
||||||
|
return (char)makeShort(getByte(o, offset),
|
||||||
|
getByte(o, offset + 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see #getLongUnaligned(Object, long, boolean) */
|
/** @see #getLongUnaligned(Object, long, boolean) */
|
||||||
|
@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
*
|
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License version 2 only, as
|
|
||||||
* published by the Free Software Foundation. Oracle designates this
|
|
||||||
* particular file as subject to the "Classpath" exception as provided
|
|
||||||
* by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
*
|
|
||||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
* version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
* accompanied this code).
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License version
|
|
||||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
* or visit www.oracle.com if you need additional information or have any
|
|
||||||
* questions.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "jni.h"
|
|
||||||
#include "jni_util.h"
|
|
||||||
#include "jlong.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define MBYTE 1048576
|
|
||||||
|
|
||||||
#define GETCRITICAL_OR_RETURN(bytes, env, obj) { \
|
|
||||||
bytes = (*env)->GetPrimitiveArrayCritical(env, obj, NULL); \
|
|
||||||
if (bytes == NULL) { \
|
|
||||||
if ((*env)->ExceptionOccurred(env) == NULL) \
|
|
||||||
JNU_ThrowInternalError(env, "Unable to get array"); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define RELEASECRITICAL(bytes, env, obj, mode) { \
|
|
||||||
(*env)->ReleasePrimitiveArrayCritical(env, obj, bytes, mode); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SWAPSHORT(x) ((jshort)(((x) << 8) | (((x) >> 8) & 0xff)))
|
|
||||||
#define SWAPINT(x) ((jint)((SWAPSHORT((jshort)(x)) << 16) | \
|
|
||||||
(SWAPSHORT((jshort)((x) >> 16)) & 0xffff)))
|
|
||||||
#define SWAPLONG(x) ((jlong)(((jlong)SWAPINT((jint)(x)) << 32) | \
|
|
||||||
((jlong)SWAPINT((jint)((x) >> 32)) & 0xffffffff)))
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyFromShortArray(JNIEnv *env, jclass clazz, jobject src,
|
|
||||||
jlong srcPos, jlong dstAddr, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jshort *srcShort, *dstShort, *endShort;
|
|
||||||
jshort tmpShort;
|
|
||||||
|
|
||||||
dstShort = (jshort *)jlong_to_ptr(dstAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, src);
|
|
||||||
|
|
||||||
srcShort = (jshort *)(bytes + srcPos);
|
|
||||||
endShort = srcShort + (size / sizeof(jshort));
|
|
||||||
while (srcShort < endShort) {
|
|
||||||
tmpShort = *srcShort++;
|
|
||||||
*dstShort++ = SWAPSHORT(tmpShort);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, src, JNI_ABORT);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
srcPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyToShortArray(JNIEnv *env, jclass clazz, jlong srcAddr,
|
|
||||||
jobject dst, jlong dstPos, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jshort *srcShort, *dstShort, *endShort;
|
|
||||||
jshort tmpShort;
|
|
||||||
|
|
||||||
srcShort = (jshort *)jlong_to_ptr(srcAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, dst);
|
|
||||||
|
|
||||||
dstShort = (jshort *)(bytes + dstPos);
|
|
||||||
endShort = srcShort + (size / sizeof(jshort));
|
|
||||||
while (srcShort < endShort) {
|
|
||||||
tmpShort = *srcShort++;
|
|
||||||
*dstShort++ = SWAPSHORT(tmpShort);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, dst, 0);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
dstPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyFromIntArray(JNIEnv *env, jclass clazz, jobject src,
|
|
||||||
jlong srcPos, jlong dstAddr, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jint *srcInt, *dstInt, *endInt;
|
|
||||||
jint tmpInt;
|
|
||||||
|
|
||||||
dstInt = (jint *)jlong_to_ptr(dstAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, src);
|
|
||||||
|
|
||||||
srcInt = (jint *)(bytes + srcPos);
|
|
||||||
endInt = srcInt + (size / sizeof(jint));
|
|
||||||
while (srcInt < endInt) {
|
|
||||||
tmpInt = *srcInt++;
|
|
||||||
*dstInt++ = SWAPINT(tmpInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, src, JNI_ABORT);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
srcPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyToIntArray(JNIEnv *env, jclass clazz, jlong srcAddr,
|
|
||||||
jobject dst, jlong dstPos, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jint *srcInt, *dstInt, *endInt;
|
|
||||||
jint tmpInt;
|
|
||||||
|
|
||||||
srcInt = (jint *)jlong_to_ptr(srcAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, dst);
|
|
||||||
|
|
||||||
dstInt = (jint *)(bytes + dstPos);
|
|
||||||
endInt = srcInt + (size / sizeof(jint));
|
|
||||||
while (srcInt < endInt) {
|
|
||||||
tmpInt = *srcInt++;
|
|
||||||
*dstInt++ = SWAPINT(tmpInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, dst, 0);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
dstPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyFromLongArray(JNIEnv *env, jclass clazz, jobject src,
|
|
||||||
jlong srcPos, jlong dstAddr, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jlong *srcLong, *dstLong, *endLong;
|
|
||||||
jlong tmpLong;
|
|
||||||
|
|
||||||
dstLong = (jlong *)jlong_to_ptr(dstAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, src);
|
|
||||||
|
|
||||||
srcLong = (jlong *)(bytes + srcPos);
|
|
||||||
endLong = srcLong + (size / sizeof(jlong));
|
|
||||||
while (srcLong < endLong) {
|
|
||||||
tmpLong = *srcLong++;
|
|
||||||
*dstLong++ = SWAPLONG(tmpLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, src, JNI_ABORT);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
srcPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_java_nio_Bits_copyToLongArray(JNIEnv *env, jclass clazz, jlong srcAddr,
|
|
||||||
jobject dst, jlong dstPos, jlong length)
|
|
||||||
{
|
|
||||||
jbyte *bytes;
|
|
||||||
size_t size;
|
|
||||||
jlong *srcLong, *dstLong, *endLong;
|
|
||||||
jlong tmpLong;
|
|
||||||
|
|
||||||
srcLong = (jlong *)jlong_to_ptr(srcAddr);
|
|
||||||
|
|
||||||
while (length > 0) {
|
|
||||||
size = (length < MBYTE) ? (size_t)length : (size_t)MBYTE;
|
|
||||||
|
|
||||||
GETCRITICAL_OR_RETURN(bytes, env, dst);
|
|
||||||
|
|
||||||
dstLong = (jlong *)(bytes + dstPos);
|
|
||||||
endLong = srcLong + (size / sizeof(jlong));
|
|
||||||
while (srcLong < endLong) {
|
|
||||||
tmpLong = *srcLong++;
|
|
||||||
*dstLong++ = SWAPLONG(tmpLong);
|
|
||||||
}
|
|
||||||
|
|
||||||
RELEASECRITICAL(bytes, env, dst, 0);
|
|
||||||
|
|
||||||
length -= size;
|
|
||||||
dstPos += size;
|
|
||||||
}
|
|
||||||
}
|
|
711
jdk/test/jdk/internal/misc/Unsafe/CopySwap.java
Normal file
711
jdk/test/jdk/internal/misc/Unsafe/CopySwap.java
Normal file
@ -0,0 +1,711 @@
|
|||||||
|
/*
|
||||||
|
* 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.copySwapMemory
|
||||||
|
* @modules java.base/jdk.internal.misc
|
||||||
|
*/
|
||||||
|
public class CopySwap {
|
||||||
|
private static final boolean DEBUG = Boolean.getBoolean("CopySwap.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 CopySwap() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 in a heap array 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 size) {
|
||||||
|
for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) {
|
||||||
|
byte expected = (byte)getVerificationDataForOffset(elemOffset, 1);
|
||||||
|
|
||||||
|
byte actual;
|
||||||
|
if (ptr.isOnHeap()) {
|
||||||
|
actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset);
|
||||||
|
} else {
|
||||||
|
actual = UNSAFE.getByte(ptr.getOffset() + elemOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected != actual) {
|
||||||
|
throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) +
|
||||||
|
" size: 0x" + Long.toHexString(size) +
|
||||||
|
" elemOffset: 0x" + Long.toHexString(elemOffset) +
|
||||||
|
" 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
|
||||||
|
* copySwapMemory to fill part of the destination buffer with
|
||||||
|
* swapped 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
|
||||||
|
* @param elemSize the size (in bytes) of the elements to byte swap
|
||||||
|
*
|
||||||
|
* @throws RuntimeException if an error is found
|
||||||
|
*/
|
||||||
|
private void testCopySwap(GenericPointer src, long srcOffset,
|
||||||
|
GenericPointer dst, long dstOffset,
|
||||||
|
long bufSize, long copyBytes, long elemSize) {
|
||||||
|
if (!isAligned(copyBytes, elemSize)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")");
|
||||||
|
}
|
||||||
|
if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")");
|
||||||
|
}
|
||||||
|
if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")");
|
||||||
|
}
|
||||||
|
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, elemSize);
|
||||||
|
if (!src.equals(dst)) {
|
||||||
|
initVerificationData(dst, bufSize, elemSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println("===before===");
|
||||||
|
for (int offset = 0; offset < bufSize; offset += elemSize) {
|
||||||
|
long srcValue = getArrayElem(src, offset, elemSize);
|
||||||
|
long dstValue = getArrayElem(dst, offset, elemSize);
|
||||||
|
|
||||||
|
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.copySwapMemory(src.getObject(),
|
||||||
|
src.getOffset() + srcOffset,
|
||||||
|
dst.getObject(),
|
||||||
|
dst.getOffset() + dstOffset,
|
||||||
|
copyBytes,
|
||||||
|
elemSize);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println("===after===");
|
||||||
|
for (int offset = 0; offset < bufSize; offset += elemSize) {
|
||||||
|
long srcValue = getArrayElem(src, offset, elemSize);
|
||||||
|
long dstValue = getArrayElem(dst, offset, elemSize);
|
||||||
|
|
||||||
|
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, dstOffset);
|
||||||
|
|
||||||
|
// Verify swapped data
|
||||||
|
verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize);
|
||||||
|
|
||||||
|
// Verify that the back back padding is unchanged
|
||||||
|
long frontAndDataBytes = dstOffset + copyBytes;
|
||||||
|
long trailingBytes = bufSize - frontAndDataBytes;
|
||||||
|
verifyUnswappedData(dst, frontAndDataBytes, trailingBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test various configurations copy-swapping 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 {
|
||||||
|
testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize);
|
||||||
|
} 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 copy swaps work
|
||||||
|
*/
|
||||||
|
private void testSmallCopy() {
|
||||||
|
int smallBufSize = SMALL_COPY_SIZE;
|
||||||
|
|
||||||
|
// Test various element types and heap/native combinations
|
||||||
|
for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) {
|
||||||
|
testElemSize(smallBufSize, elemSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that large copy swaps 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.copySwapMemory(null, buf, null, buf, size, 8);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("copySwapMemory 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 various illegal element sizes
|
||||||
|
for (int elemSize = 2; elemSize <= 8; elemSize <<= 1) {
|
||||||
|
long[] illegalSizes = { -1, 1, elemSize - 1, elemSize + 1, elemSize * 2 - 1 };
|
||||||
|
for (long size : illegalSizes) {
|
||||||
|
try {
|
||||||
|
// Check that illegal elemSize throws an IAE
|
||||||
|
UNSAFE.copySwapMemory(null, buf, null, buf, size, elemSize);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw IAE for size=" + size + " elemSize=" + elemSize);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that negative srcOffset throws an IAE
|
||||||
|
UNSAFE.copySwapMemory(arr, -1, arr, UNSAFE.arrayBaseOffset(arr.getClass()), 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw IAE for srcOffset=-1");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that negative dstOffset throws an IAE
|
||||||
|
UNSAFE.copySwapMemory(arr, UNSAFE.arrayBaseOffset(arr.getClass()), arr, -1, 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw IAE for destOffset=-1");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
long illegalElemSizes[] = { 0, 1, 3, 5, 6, 7, 9, 10, -1 };
|
||||||
|
for (long elemSize : illegalElemSizes) {
|
||||||
|
try {
|
||||||
|
// Check that elemSize 1 throws an IAE
|
||||||
|
UNSAFE.copySwapMemory(null, buf, null, buf, 16, elemSize);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw NPE");
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that a NULL source throws NPE
|
||||||
|
UNSAFE.copySwapMemory(null, 0, null, buf, 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw NPE");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that a NULL destination throws NPE
|
||||||
|
UNSAFE.copySwapMemory(null, buf, null, 0, 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw NPE");
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check that a reference array destination throws IAE
|
||||||
|
UNSAFE.copySwapMemory(null, buf, new Object[16], UNSAFE.arrayBaseOffset(Object[].class), 16, 8);
|
||||||
|
throw new RuntimeException("copySwapMemory failed to throw NPE");
|
||||||
|
} 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.copySwapMemory(null, invalidPtr, null, buf, 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory 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.copySwapMemory(null, buf, null, invalidPtr, 16, 2);
|
||||||
|
throw new RuntimeException("copySwapMemory 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) {
|
||||||
|
CopySwap cs = new CopySwap();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user