blob: 02b647dea2465089e165cfa32cf4d7688ca370e4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.datasketches.memory;
import static org.apache.datasketches.memory.UnsafeUtil.CHAR_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.DOUBLE_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.FLOAT_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.INT_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.LONG_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.SHORT_SHIFT;
import static org.apache.datasketches.memory.UnsafeUtil.checkBounds;
import static org.apache.datasketches.memory.UnsafeUtil.unsafe;
/**
* @author Lee Rhodes
*/
final class CompareAndCopy {
/**
* Don't use {@link sun.misc.Unsafe#copyMemory} to copy blocks of memory larger than this
* threshold, because internally it doesn't have safepoint polls, that may cause long
* "Time To Safe Point" pauses in the application. This has been fixed in JDK 9 (see
* https://bugs.openjdk.java.net/browse/JDK-8149596 and
* https://bugs.openjdk.java.net/browse/JDK-8141491), but not in JDK 8, so the Memory library
* should keep having this boilerplate as long as it supports Java 8.
*
* <p>A reference to this can be found in {@link java.nio.Bits}.</p>
*/
static final int UNSAFE_COPY_THRESHOLD_BYTES = 1024 * 1024;
private CompareAndCopy() { }
static int compare(
final BaseState state1, final long offsetBytes1, final long lengthBytes1,
final BaseState state2, final long offsetBytes2, final long lengthBytes2) {
state1.checkValid();
checkBounds(offsetBytes1, lengthBytes1, state1.getCapacity());
state2.checkValid();
checkBounds(offsetBytes2, lengthBytes2, state2.getCapacity());
final long cumOff1 = state1.getCumulativeOffset(offsetBytes1);
final long cumOff2 = state2.getCumulativeOffset(offsetBytes2);
final Object arr1 = state1.getUnsafeObject();
final Object arr2 = state2.getUnsafeObject();
if ((arr1 != arr2) || (cumOff1 != cumOff2)) {
final long lenBytes = Math.min(lengthBytes1, lengthBytes2);
for (long i = 0; i < lenBytes; i++) {
final int byte1 = unsafe.getByte(arr1, cumOff1 + i);
final int byte2 = unsafe.getByte(arr2, cumOff2 + i);
if (byte1 < byte2) { return -1; }
if (byte1 > byte2) { return 1; }
}
}
return Long.compare(lengthBytes1, lengthBytes2);
}
static boolean equals(final BaseState state1, final BaseState state2) {
final long cap1 = state1.getCapacity();
final long cap2 = state2.getCapacity();
return (cap1 == cap2) && equals(state1, 0, state2, 0, cap1);
}
//Developer notes: this is subtlely different from (campare == 0) in that this has an early
// stop if the arrays and offsets are the same as there is only one length. Also this can take
// advantage of chunking with longs, while compare cannot.
static boolean equals(
final BaseState state1, final long offsetBytes1,
final BaseState state2, final long offsetBytes2, long lengthBytes) {
state1.checkValid();
checkBounds(offsetBytes1, lengthBytes, state1.getCapacity());
state2.checkValid();
checkBounds(offsetBytes2, lengthBytes, state2.getCapacity());
long cumOff1 = state1.getCumulativeOffset(offsetBytes1);
long cumOff2 = state2.getCumulativeOffset(offsetBytes2);
final Object arr1 = state1.getUnsafeObject(); //could be null
final Object arr2 = state2.getUnsafeObject(); //could be null
if ((arr1 == arr2) && (cumOff1 == cumOff2)) { return true; }
while (lengthBytes >= Long.BYTES) {
final int chunk = (int) Math.min(lengthBytes, UNSAFE_COPY_THRESHOLD_BYTES);
// int-counted loop to avoid safepoint polls (otherwise why we chunk by
// UNSAFE_COPY_MEMORY_THRESHOLD)
int i = 0;
for (; i <= (chunk - Long.BYTES); i += Long.BYTES) {
final long v1 = unsafe.getLong(arr1, cumOff1 + i);
final long v2 = unsafe.getLong(arr2, cumOff2 + i);
if (v1 != v2) { return false; }
}
lengthBytes -= i;
cumOff1 += i;
cumOff2 += i;
}
//check the remainder bytes, if any
return (lengthBytes == 0) || equalsByBytes(arr1, cumOff1, arr2, cumOff2, (int) lengthBytes);
}
//use only for short runs
private static boolean equalsByBytes(final Object arr1, final long cumOff1, final Object arr2,
final long cumOff2, final int lenBytes) {
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lenBytes; i++) {
final int v1 = unsafe.getByte(arr1, cumOff1 + i);
final int v2 = unsafe.getByte(arr2, cumOff2 + i);
if (v1 != v2) { return false; }
}
return true;
}
static void copy(final BaseState srcState, final long srcOffsetBytes,
final BaseState dstState, final long dstOffsetBytes, final long lengthBytes) {
srcState.checkValid();
checkBounds(srcOffsetBytes, lengthBytes, srcState.getCapacity());
dstState.checkValid();
checkBounds(dstOffsetBytes, lengthBytes, dstState.getCapacity());
final long srcAdd = srcState.getCumulativeOffset(srcOffsetBytes);
final long dstAdd = dstState.getCumulativeOffset(dstOffsetBytes);
copyMemory(srcState.getUnsafeObject(), srcAdd, dstState.getUnsafeObject(), dstAdd,
lengthBytes);
}
//Used by all of the get/put array methods in Buffer and Memory classes
static final void copyMemoryCheckingDifferentObject(final Object srcUnsafeObj,
final long srcAdd, final Object dstUnsafeObj, final long dstAdd, final long lengthBytes) {
if (srcUnsafeObj != dstUnsafeObj) {
copyNonOverlappingMemoryWithChunking(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd,
lengthBytes);
} else {
throw new IllegalArgumentException("Not expecting to copy to/from array which is the "
+ "underlying object of the memory at the same time");
}
}
//only valid and bounds checks have been performed at this point
private static void copyMemory(final Object srcUnsafeObj, final long srcAdd,
final Object dstUnsafeObj, final long dstAdd, final long lengthBytes) {
if (srcUnsafeObj != dstUnsafeObj) {
//either srcArray != dstArray OR one of them is off-heap
copyNonOverlappingMemoryWithChunking(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd,
lengthBytes);
} else { //either srcArray == dstArray OR both src and dst are off-heap
copyMemoryOverlapAddressCheck(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd, lengthBytes);
}
}
/**
* At this point either srcArray == dstArray OR both src and dst are off-heap.
* Performs overlapping address check. If addresses do not overlap, proceed to
* {@link #copyNonOverlappingMemoryWithChunking(Object, long, Object, long, long)}; otherwise
* fall back on <i>Unsafe.copyMemory(...)</i> tolerating potentially long
* Time to Safe Point pauses.
* If srcAdd == dstAdd an exception will be thrown.
* @param srcUnsafeObj The source array object, it may be null.
* @param srcAdd The cumulative source offset
* @param dstUnsafeObj The destination array object, it may be null
* @param dstAdd The cumulative destination offset
* @param lengthBytes The length to be copied in bytes
*/
private static void copyMemoryOverlapAddressCheck(final Object srcUnsafeObj, final long srcAdd,
final Object dstUnsafeObj, final long dstAdd, final long lengthBytes) {
if (((srcAdd + lengthBytes) <= dstAdd) || ((dstAdd + lengthBytes) <= srcAdd)) {
copyNonOverlappingMemoryWithChunking(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd,
lengthBytes);
return;
}
if (srcAdd == dstAdd) {
throw new IllegalArgumentException(
"Attempt to copy a block of memory exactly in-place, should be a bug");
}
// If regions do overlap, fall back to unsafe.copyMemory, tolerating potentially long
// Time to Safe Point pauses.
unsafe.copyMemory(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd, lengthBytes);
}
/**
* This copies only non-overlapping memory in chunks to avoid safepoint delays.
* Java 9 may not require the chunking.
* @param srcUnsafeObj The source array object, it may be null.
* @param srcAdd The cumulative source offset
* @param dstUnsafeObj The destination array object, it may be null
* @param dstAdd The cumulative destination offset
* @param lengthBytes The length to be copied in bytes
* @see #UNSAFE_COPY_THRESHOLD_BYTES
*/
private static void copyNonOverlappingMemoryWithChunking(final Object srcUnsafeObj,
long srcAdd, final Object dstUnsafeObj, long dstAdd, long lengthBytes) {
while (lengthBytes > 0) {
final long chunk = Math.min(lengthBytes, UNSAFE_COPY_THRESHOLD_BYTES);
unsafe.copyMemory(srcUnsafeObj, srcAdd, dstUnsafeObj, dstAdd, chunk);
lengthBytes -= chunk;
srcAdd += chunk;
dstAdd += chunk;
}
}
static void getNonNativeChars(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final char[] dstArray, int dstOffsetChars,
int lengthChars) {
checkBounds(dstOffsetChars, lengthChars, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkChars = (int) (chunkBytes >> CHAR_SHIFT);
getCharArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetChars, chunkChars);
cumOffsetBytes += chunkBytes;
dstOffsetChars += chunkChars;
copyBytes -= chunkBytes;
lengthChars -= chunkChars;
}
getCharArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetChars, lengthChars);
}
private static void getCharArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final char[] dstArray, final int dstOffsetChars, final int lengthChars) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthChars; i++) {
dstArray[dstOffsetChars + i] = Character.reverseBytes(
unsafe.getChar(unsafeObj, cumOffsetBytes + (((long) i) << CHAR_SHIFT)));
}
}
static void getNonNativeDoubles(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final double[] dstArray, int dstOffsetDoubles,
int lengthDoubles) {
checkBounds(dstOffsetDoubles, lengthDoubles, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkDoubles = (int) (chunkBytes >> DOUBLE_SHIFT);
getDoubleArrayChunk(unsafeObj, cumOffsetBytes,
dstArray, dstOffsetDoubles, chunkDoubles);
cumOffsetBytes += chunkBytes;
dstOffsetDoubles += chunkDoubles;
copyBytes -= chunkBytes;
lengthDoubles -= chunkDoubles;
}
getDoubleArrayChunk(unsafeObj, cumOffsetBytes,
dstArray, dstOffsetDoubles, lengthDoubles);
}
private static void getDoubleArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final double[] dstArray, final int dstOffsetDoubles, final int lengthDoubles) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthDoubles; i++) {
dstArray[dstOffsetDoubles + i] = Double.longBitsToDouble(Long.reverseBytes(
unsafe.getLong(unsafeObj, cumOffsetBytes + (((long) i) << DOUBLE_SHIFT))));
}
}
static void getNonNativeFloats(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final float[] dstArray, int dstOffsetFloats,
int lengthFloats) {
checkBounds(dstOffsetFloats, lengthFloats, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkFloats = (int) (chunkBytes >> FLOAT_SHIFT);
getFloatArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetFloats, chunkFloats);
cumOffsetBytes += chunkBytes;
dstOffsetFloats += chunkFloats;
copyBytes -= chunkBytes;
lengthFloats -= chunkFloats;
}
getFloatArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetFloats, lengthFloats);
}
private static void getFloatArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final float[] dstArray, final int dstOffsetFloats, final int lengthFloats) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthFloats; i++) {
dstArray[dstOffsetFloats + i] = Float.intBitsToFloat(Integer.reverseBytes(
unsafe.getInt(unsafeObj, cumOffsetBytes + (((long) i) << FLOAT_SHIFT))));
}
}
static void getNonNativeInts(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final int[] dstArray, int dstOffsetInts,
int lengthInts) {
checkBounds(dstOffsetInts, lengthInts, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkInts = (int) (chunkBytes >> INT_SHIFT);
getIntArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetInts, chunkInts);
cumOffsetBytes += chunkBytes;
dstOffsetInts += chunkInts;
copyBytes -= chunkBytes;
lengthInts -= chunkInts;
}
getIntArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetInts, lengthInts);
}
private static void getIntArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final int[] dstArray, final int dstOffsetInts, final int lengthInts) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthInts; i++) {
dstArray[dstOffsetInts + i] = Integer.reverseBytes(
unsafe.getInt(unsafeObj, cumOffsetBytes + (((long) i) << INT_SHIFT)));
}
}
static void getNonNativeLongs(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final long[] dstArray, int dstOffsetLongs,
int lengthLongs) {
checkBounds(dstOffsetLongs, lengthLongs, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkLongs = (int) (chunkBytes >> LONG_SHIFT);
getLongArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetLongs, chunkLongs);
cumOffsetBytes += chunkBytes;
dstOffsetLongs += chunkLongs;
copyBytes -= chunkBytes;
lengthLongs -= chunkLongs;
}
getLongArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetLongs, lengthLongs);
}
private static void getLongArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final long[] dstArray, final int dstOffsetLongs, final int lengthLongs) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthLongs; i++) {
dstArray[dstOffsetLongs + i] = Long.reverseBytes(
unsafe.getLong(unsafeObj, cumOffsetBytes + (((long) i) << LONG_SHIFT)));
}
}
static void getNonNativeShorts(final Object unsafeObj, long cumOffsetBytes,
long copyBytes, final short[] dstArray, int dstOffsetShorts,
int lengthShorts) {
checkBounds(dstOffsetShorts, lengthShorts, dstArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkShorts = (int) (chunkBytes >> SHORT_SHIFT);
getShortArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetShorts, chunkShorts);
cumOffsetBytes += chunkBytes;
dstOffsetShorts += chunkShorts;
copyBytes -= chunkBytes;
lengthShorts -= chunkShorts;
}
getShortArrayChunk(unsafeObj, cumOffsetBytes, dstArray, dstOffsetShorts, lengthShorts);
}
private static void getShortArrayChunk(final Object unsafeObj, final long cumOffsetBytes,
final short[] dstArray, final int dstOffsetShorts, final int lengthShorts) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthShorts; i++) {
dstArray[dstOffsetShorts + i] = Short.reverseBytes(
unsafe.getShort(unsafeObj, cumOffsetBytes + (((long) i) << SHORT_SHIFT)));
}
}
static void putNonNativeChars(final char[] srcArray, int srcOffsetChars, int lengthChars,
long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetChars, lengthChars, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkChars = (int) (chunkBytes >> CHAR_SHIFT);
putCharArrayChunk(srcArray, srcOffsetChars, chunkChars, unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetChars += chunkChars;
copyBytes -= chunkBytes;
lengthChars -= chunkChars;
}
putCharArrayChunk(srcArray, srcOffsetChars, lengthChars, unsafeObj, cumOffsetBytes);
}
private static void putCharArrayChunk(final char[] srcArray, final int srcOffsetChars,
final int lengthChars, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthChars; i++) {
unsafe.putChar(unsafeObj, cumOffsetBytes + (((long) i) << CHAR_SHIFT),
Character.reverseBytes(srcArray[srcOffsetChars + i]));
}
}
static void putNonNativeDoubles(final double[] srcArray, int srcOffsetDoubles,
int lengthDoubles, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetDoubles, lengthDoubles, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkDoubles = (int) (chunkBytes >> DOUBLE_SHIFT);
putDoubleArrayChunk(srcArray, srcOffsetDoubles, chunkDoubles,
unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetDoubles += chunkDoubles;
copyBytes -= chunkBytes;
lengthDoubles -= chunkDoubles;
}
putDoubleArrayChunk(srcArray, srcOffsetDoubles, lengthDoubles,
unsafeObj, cumOffsetBytes);
}
private static void putDoubleArrayChunk(final double[] srcArray, final int srcOffsetDoubles,
final int lengthDoubles, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthDoubles; i++) {
unsafe.putLong(unsafeObj, cumOffsetBytes + (((long) i) << DOUBLE_SHIFT),
Long.reverseBytes(Double.doubleToRawLongBits(srcArray[srcOffsetDoubles + i])));
}
}
static void putNonNativeFloats(final float[] srcArray, int srcOffsetFloats,
int lengthFloats, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetFloats, lengthFloats, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkFloats = (int) (chunkBytes >> FLOAT_SHIFT);
putFloatArrayChunk(srcArray, srcOffsetFloats, chunkFloats, unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetFloats += chunkFloats;
copyBytes -= chunkBytes;
lengthFloats -= chunkFloats;
}
putFloatArrayChunk(srcArray, srcOffsetFloats, lengthFloats, unsafeObj, cumOffsetBytes);
}
private static void putFloatArrayChunk(final float[] srcArray, final int srcOffsetFloats,
final int lengthFloats, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthFloats; i++) {
unsafe.putInt(unsafeObj, cumOffsetBytes + (((long) i) << FLOAT_SHIFT),
Integer.reverseBytes(Float.floatToRawIntBits(srcArray[srcOffsetFloats + i])));
}
}
static void putNonNativeInts(final int[] srcArray, int srcOffsetInts, int lengthInts,
long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetInts, lengthInts, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkInts = (int) (chunkBytes >> INT_SHIFT);
putIntArrayChunk(srcArray, srcOffsetInts, chunkInts, unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetInts += chunkInts;
copyBytes -= chunkBytes;
lengthInts -= chunkInts;
}
putIntArrayChunk(srcArray, srcOffsetInts, lengthInts, unsafeObj, cumOffsetBytes);
}
private static void putIntArrayChunk(final int[] srcArray, final int srcOffsetInts,
final int lengthInts, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthInts; i++) {
unsafe.putInt(unsafeObj, cumOffsetBytes + (((long) i) << INT_SHIFT),
Integer.reverseBytes(srcArray[srcOffsetInts + i]));
}
}
static void putNonNativeLongs(final long[] srcArray, int srcOffsetLongs, int lengthLongs,
long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetLongs, lengthLongs, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkLongs = (int) (chunkBytes >> LONG_SHIFT);
putLongArrayChunk(srcArray, srcOffsetLongs, chunkLongs, unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetLongs += chunkLongs;
copyBytes -= chunkBytes;
lengthLongs -= chunkLongs;
}
putLongArrayChunk(srcArray, srcOffsetLongs, lengthLongs, unsafeObj, cumOffsetBytes);
}
private static void putLongArrayChunk(final long[] srcArray, final int srcOffsetLongs,
final int lengthLongs, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthLongs; i++) {
unsafe.putLong(unsafeObj, cumOffsetBytes + (((long) i) << LONG_SHIFT),
Long.reverseBytes(srcArray[srcOffsetLongs + i]));
}
}
static void putNonNativeShorts(final short[] srcArray, int srcOffsetShorts,
int lengthShorts, long copyBytes, final Object unsafeObj, long cumOffsetBytes) {
checkBounds(srcOffsetShorts, lengthShorts, srcArray.length);
while (copyBytes > UNSAFE_COPY_THRESHOLD_BYTES) {
final long chunkBytes = Math.min(copyBytes, UNSAFE_COPY_THRESHOLD_BYTES);
final int chunkShorts = (int) (chunkBytes >> SHORT_SHIFT);
putShortArrayChunk(srcArray, srcOffsetShorts, chunkShorts, unsafeObj, cumOffsetBytes);
cumOffsetBytes += chunkBytes;
srcOffsetShorts += chunkShorts;
copyBytes -= chunkBytes;
lengthShorts -= chunkShorts;
}
putShortArrayChunk(srcArray, srcOffsetShorts, lengthShorts, unsafeObj, cumOffsetBytes);
}
private static void putShortArrayChunk(final short[] srcArray, final int srcOffsetShorts,
final int lengthShorts, final Object unsafeObj, final long cumOffsetBytes) {
// JDK 9 adds native intrinsics for such bulk non-native ordered primitive memory copy.
// TODO-JDK9 use them when the library adds support for JDK 9
// int-counted loop to avoid safepoint polls
for (int i = 0; i < lengthShorts; i++) {
unsafe.putShort(unsafeObj, cumOffsetBytes + (((long) i) << SHORT_SHIFT),
Short.reverseBytes(srcArray[srcOffsetShorts + i]));
}
}
}