8193085: Vectorize the nio Buffer equals and compareTo implementations

Reviewed-by: alanb
This commit is contained in:
Paul Sandoz 2017-12-20 09:14:52 -08:00
parent 038b5f571c
commit fb9db6b02d
13 changed files with 1122 additions and 195 deletions

View file

@ -63,38 +63,38 @@ class Bits { // package-private
// -- Unsafe access --
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
static Unsafe unsafe() {
return unsafe;
return UNSAFE;
}
// -- Processor and memory-system properties --
private static final ByteOrder byteOrder
= unsafe.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
private static final ByteOrder BYTE_ORDER
= UNSAFE.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
static ByteOrder byteOrder() {
return byteOrder;
return BYTE_ORDER;
}
private static int pageSize = -1;
private static int PAGE_SIZE = -1;
static int pageSize() {
if (pageSize == -1)
pageSize = unsafe().pageSize();
return pageSize;
if (PAGE_SIZE == -1)
PAGE_SIZE = unsafe().pageSize();
return PAGE_SIZE;
}
static int pageCount(long size) {
return (int)(size + (long)pageSize() - 1L) / pageSize();
}
private static boolean unaligned = unsafe.unalignedAccess();
private static boolean UNALIGNED = UNSAFE.unalignedAccess();
static boolean unaligned() {
return unaligned;
return UNALIGNED;
}
@ -103,11 +103,11 @@ class Bits { // package-private
// A user-settable upper limit on the maximum amount of allocatable
// direct buffer memory. This value may be changed during VM
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
private static volatile long maxMemory = VM.maxDirectMemory();
private static final AtomicLong reservedMemory = new AtomicLong();
private static final AtomicLong totalCapacity = new AtomicLong();
private static final AtomicLong count = new AtomicLong();
private static volatile boolean memoryLimitSet;
private static volatile long MAX_MEMORY = VM.maxDirectMemory();
private static final AtomicLong RESERVED_MEMORY = new AtomicLong();
private static final AtomicLong TOTAL_CAPACITY = new AtomicLong();
private static final AtomicLong COUNT = new AtomicLong();
private static volatile boolean MEMORY_LIMIT_SET;
// max. number of sleeps during try-reserving with exponentially
// increasing delay before throwing OutOfMemoryError:
@ -120,9 +120,9 @@ class Bits { // package-private
// which a process may access. All sizes are specified in bytes.
static void reserveMemory(long size, int cap) {
if (!memoryLimitSet && VM.initLevel() >= 1) {
maxMemory = VM.maxDirectMemory();
memoryLimitSet = true;
if (!MEMORY_LIMIT_SET && VM.initLevel() >= 1) {
MAX_MEMORY = VM.maxDirectMemory();
MEMORY_LIMIT_SET = true;
}
// optimist!
@ -200,10 +200,10 @@ class Bits { // package-private
// actual memory usage, which will differ when buffers are page
// aligned.
long totalCap;
while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
reservedMemory.addAndGet(size);
count.incrementAndGet();
while (cap <= MAX_MEMORY - (totalCap = TOTAL_CAPACITY.get())) {
if (TOTAL_CAPACITY.compareAndSet(totalCap, totalCap + cap)) {
RESERVED_MEMORY.addAndGet(size);
COUNT.incrementAndGet();
return true;
}
}
@ -213,9 +213,9 @@ class Bits { // package-private
static void unreserveMemory(long size, int cap) {
long cnt = count.decrementAndGet();
long reservedMem = reservedMemory.addAndGet(-size);
long totalCap = totalCapacity.addAndGet(-cap);
long cnt = COUNT.decrementAndGet();
long reservedMem = RESERVED_MEMORY.addAndGet(-size);
long totalCap = TOTAL_CAPACITY.addAndGet(-cap);
assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
}
@ -234,15 +234,15 @@ class Bits { // package-private
}
@Override
public long getCount() {
return Bits.count.get();
return Bits.COUNT.get();
}
@Override
public long getTotalCapacity() {
return Bits.totalCapacity.get();
return Bits.TOTAL_CAPACITY.get();
}
@Override
public long getMemoryUsed() {
return Bits.reservedMemory.get();
return Bits.RESERVED_MEMORY.get();
}
};
}

View file

@ -26,6 +26,7 @@
package java.nio;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.Unsafe;
import java.util.Spliterator;
@ -181,6 +182,8 @@ import java.util.Spliterator;
*/
public abstract class Buffer {
// Cached unsafe-access object
static final Unsafe UNSAFE = Bits.unsafe();
/**
* The characteristics of Spliterators that traverse and split elements
@ -616,6 +619,14 @@ public abstract class Buffer {
// -- Package-private methods for bounds checking, etc. --
/**
*
* @return the base reference, paired with the address
* field, which in combination can be used for unsafe access into a heap
* buffer or direct byte buffer (and views of).
*/
abstract Object base();
/**
* Checks the current position against the limit, throwing a {@link
* BufferUnderflowException} if it is not smaller than the limit, and then

View file

@ -0,0 +1,198 @@
/*
* Copyright (c) 2017, 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.
*/
package java.nio;
import jdk.internal.util.ArraysSupport;
/**
* Mismatch methods for buffers
*/
final class BufferMismatch {
static int mismatch(ByteBuffer a, int aOff, ByteBuffer b, int bOff, int length) {
int i = 0;
if (length > 7) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + aOff,
b.base(), b.address + bOff,
length,
ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
if (i >= 0) return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a.get(aOff + i) != b.get(bOff + i))
return i;
}
return -1;
}
static int mismatch(CharBuffer a, int aOff, CharBuffer b, int bOff, int length) {
int i = 0;
// Ensure only heap or off-heap buffer instances use the
// vectorized mismatch. If either buffer is a StringCharBuffer
// (order is null) then the slow path is taken
if (length > 3 && a.charRegionOrder() == b.charRegionOrder()
&& a.charRegionOrder() != null && b.charRegionOrder() != null) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE);
if (i >= 0) return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a.get(aOff + i) != b.get(bOff + i))
return i;
}
return -1;
}
static int mismatch(ShortBuffer a, int aOff, ShortBuffer b, int bOff, int length) {
int i = 0;
if (length > 3 && a.order() == b.order()) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE);
if (i >= 0) return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a.get(aOff + i) != b.get(bOff + i))
return i;
}
return -1;
}
static int mismatch(IntBuffer a, int aOff, IntBuffer b, int bOff, int length) {
int i = 0;
if (length > 1 && a.order() == b.order()) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE);
if (i >= 0) return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a.get(aOff + i) != b.get(bOff + i))
return i;
}
return -1;
}
static int mismatch(FloatBuffer a, int aOff, FloatBuffer b, int bOff, int length) {
int i = 0;
if (length > 1 && a.order() == b.order()) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE);
// Mismatched
if (i >= 0) {
// Check if mismatch is not associated with two NaN values; and
// is not associated with +0 and -0
float av = a.get(aOff + i);
float bv = b.get(bOff + i);
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
return i;
// Fall back to slow mechanism
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
// However, requires that returned value be relative to input ranges
i++;
}
// Matched
else {
i = length - ~i;
}
}
for (; i < length; i++) {
float av = a.get(aOff + i);
float bv = b.get(bOff + i);
if (av != bv && (!Float.isNaN(av) || !Float.isNaN(bv)))
return i;
}
return -1;
}
static int mismatch(LongBuffer a, int aOff, LongBuffer b, int bOff, int length) {
int i = 0;
if (length > 0 && a.order() == b.order()) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE);
return i >= 0 ? i : -1;
}
for (; i < length; i++) {
if (a.get(aOff + i) != b.get(bOff + i))
return i;
}
return -1;
}
static int mismatch(DoubleBuffer a, int aOff, DoubleBuffer b, int bOff, int length) {
int i = 0;
if (length > 0 && a.order() == b.order()) {
i = ArraysSupport.vectorizedMismatch(
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
length,
ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE);
// Mismatched
if (i >= 0) {
// Check if mismatch is not associated with two NaN values; and
// is not associated with +0 and -0
double av = a.get(aOff + i);
double bv = b.get(bOff + i);
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
return i;
// Fall back to slow mechanism
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
// However, requires that returned value be relative to input ranges
i++;
}
// Matched
else {
return -1;
}
}
for (; i < length; i++) {
double av = a.get(aOff + i);
double bv = b.get(bOff + i);
if (av != bv && (!Double.isNaN(av) || !Double.isNaN(bv)))
return i;
}
return -1;
}
}

View file

@ -36,9 +36,6 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#if[rw]
// Cached unsafe-access object
private static final Unsafe unsafe = Bits.unsafe();
protected final ByteBuffer bb;
#end[rw]
@ -74,6 +71,11 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#end[rw]
}
@Override
Object base() {
return bb.hb;
}
public $Type$Buffer slice() {
int pos = this.position();
int lim = this.limit();
@ -117,20 +119,20 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
}
public $type$ get() {
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
{#if[boB]?true:false});
return $fromBits$(x);
}
public $type$ get(int i) {
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
{#if[boB]?true:false});
return $fromBits$(x);
}
#if[streamableType]
$type$ getUnchecked(int i) {
$memtype$ x = unsafe.get$Memtype$Unaligned(bb.hb, byteOffset(i),
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(i),
{#if[boB]?true:false});
return $fromBits$(x);
}
@ -141,7 +143,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put($type$ x) {
#if[rw]
$memtype$ y = $toBits$(x);
unsafe.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
{#if[boB]?true:false});
return this;
#else[rw]
@ -152,7 +154,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
$memtype$ y = $toBits$(x);
unsafe.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
{#if[boB]?true:false});
return this;
#else[rw]
@ -241,4 +243,9 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#end[boL]
}
#if[char]
ByteOrder charRegionOrder() {
return order();
}
#end[char]
}

View file

@ -32,7 +32,7 @@ class XXX {
#if[rw]
private $type$ get$Type$(long a) {
$memtype$ x = unsafe.get$Memtype$Unaligned(null, a, bigEndian);
$memtype$ x = UNSAFE.get$Memtype$Unaligned(null, a, bigEndian);
return $fromBits$(x);
}
@ -49,7 +49,7 @@ class XXX {
private ByteBuffer put$Type$(long a, $type$ x) {
#if[rw]
$memtype$ y = $toBits$(x);
unsafe.put$Memtype$Unaligned(null, a, y, bigEndian);
UNSAFE.put$Memtype$Unaligned(null, a, y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -81,7 +81,7 @@ class XXX {
int rem = (off <= lim ? lim - off : 0);
int size = rem >> $LG_BYTES_PER_VALUE$;
if (!unaligned && ((address + off) % $BYTES_PER_VALUE$ != 0)) {
if (!UNALIGNED && ((address + off) % $BYTES_PER_VALUE$ != 0)) {
return (bigEndian
? ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$B(this,
-1,

View file

@ -28,7 +28,6 @@
package java.nio;
import java.io.FileDescriptor;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.ref.Cleaner;
import sun.nio.ch.DirectBuffer;
@ -45,14 +44,11 @@ class Direct$Type$Buffer$RW$$BO$
#if[rw]
// Cached unsafe-access object
protected static final Unsafe unsafe = Bits.unsafe();
// Cached array base offset
private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class);
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class);
// Cached unaligned-access capability
protected static final boolean unaligned = Bits.unaligned();
protected static final boolean UNALIGNED = Bits.unaligned();
// Base address, used in all indexing calculations
// NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
@ -73,8 +69,6 @@ class Direct$Type$Buffer$RW$$BO$
implements Runnable
{
private static Unsafe unsafe = Unsafe.getUnsafe();
private long address;
private long size;
private int capacity;
@ -91,7 +85,7 @@ class Direct$Type$Buffer$RW$$BO$
// Paranoia
return;
}
unsafe.freeMemory(address);
UNSAFE.freeMemory(address);
address = 0;
Bits.unreserveMemory(size, capacity);
}
@ -124,12 +118,12 @@ class Direct$Type$Buffer$RW$$BO$
long base = 0;
try {
base = unsafe.allocateMemory(size);
base = UNSAFE.allocateMemory(size);
} catch (OutOfMemoryError x) {
Bits.unreserveMemory(size, cap);
throw x;
}
unsafe.setMemory(base, size, (byte) 0);
UNSAFE.setMemory(base, size, (byte) 0);
if (pa && (base % ps != 0)) {
// Round up to page boundary
address = base + ps - (base & (ps - 1));
@ -206,6 +200,11 @@ class Direct$Type$Buffer$RW$$BO$
#end[rw]
}
@Override
Object base() {
return null;
}
public $Type$Buffer slice() {
int pos = this.position();
int lim = this.limit();
@ -258,16 +257,16 @@ class Direct$Type$Buffer$RW$$BO$
}
public $type$ get() {
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex()))));
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(nextGetIndex()))));
}
public $type$ get(int i) {
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i)))));
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(checkIndex(i)))));
}
#if[streamableType]
$type$ getUnchecked(int i) {
return $fromBits$($swap$(unsafe.get$Swaptype$(ix(i))));
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(i))));
}
#end[streamableType]
@ -282,10 +281,10 @@ class Direct$Type$Buffer$RW$$BO$
if (length > rem)
throw new BufferUnderflowException();
long dstOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
long dstOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
#if[!byte]
if (order() != ByteOrder.nativeOrder())
unsafe.copySwapMemory(null,
UNSAFE.copySwapMemory(null,
ix(pos),
dst,
dstOffset,
@ -293,7 +292,7 @@ class Direct$Type$Buffer$RW$$BO$
(long)1 << $LG_BYTES_PER_VALUE$);
else
#end[!byte]
unsafe.copyMemory(null,
UNSAFE.copyMemory(null,
ix(pos),
dst,
dstOffset,
@ -312,7 +311,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put($type$ x) {
#if[rw]
unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
UNSAFE.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -321,7 +320,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
UNSAFE.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -347,7 +346,7 @@ class Direct$Type$Buffer$RW$$BO$
if (srem > rem)
throw new BufferOverflowException();
unsafe.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
UNSAFE.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
sb.position(spos + srem);
position(pos + srem);
} else if (src.hb != null) {
@ -380,10 +379,10 @@ class Direct$Type$Buffer$RW$$BO$
if (length > rem)
throw new BufferOverflowException();
long srcOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
long srcOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
#if[!byte]
if (order() != ByteOrder.nativeOrder())
unsafe.copySwapMemory(src,
UNSAFE.copySwapMemory(src,
srcOffset,
null,
ix(pos),
@ -391,7 +390,7 @@ class Direct$Type$Buffer$RW$$BO$
(long)1 << $LG_BYTES_PER_VALUE$);
else
#end[!byte]
unsafe.copyMemory(src,
UNSAFE.copyMemory(src,
srcOffset,
null,
ix(pos),
@ -413,7 +412,7 @@ class Direct$Type$Buffer$RW$$BO$
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
unsafe.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
UNSAFE.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
position(rem);
limit(capacity());
discardMark();
@ -490,17 +489,22 @@ class Direct$Type$Buffer$RW$$BO$
#end[!byte]
#if[char]
ByteOrder charRegionOrder() {
return order();
}
#end[char]
#if[byte]
byte _get(int i) { // package-private
return unsafe.getByte(address + i);
return UNSAFE.getByte(address + i);
}
void _put(int i, byte b) { // package-private
#if[rw]
unsafe.putByte(address + i, b);
UNSAFE.putByte(address + i, b);
#else[rw]
throw new ReadOnlyBufferException();
#end[rw]

View file

@ -27,8 +27,6 @@
package java.nio;
import jdk.internal.misc.Unsafe;
/**
#if[rw]
* A read/write Heap$Type$Buffer.
@ -43,6 +41,11 @@ import jdk.internal.misc.Unsafe;
class Heap$Type$Buffer$RW$
extends {#if[ro]?Heap}$Type$Buffer
{
// Cached array base offset
private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class);
// Cached array base offset
private static final long ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale($type$[].class);
// For speed these fields are actually declared in X-Buffer;
// these declarations are here as documentation
@ -53,16 +56,6 @@ class Heap$Type$Buffer$RW$
#end[rw]
*/
#if[byte]
// Cached unsafe-access object
private static final Unsafe unsafe = Bits.unsafe();
// Cached array base offset
private static final long arrayBaseOffset = unsafe.arrayBaseOffset($type$[].class);
#end[byte]
Heap$Type$Buffer$RW$(int cap, int lim) { // package-private
#if[rw]
super(-1, 0, lim, cap, new $type$[cap], 0);
@ -70,13 +63,11 @@ class Heap$Type$Buffer$RW$
hb = new $type$[cap];
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
super(cap, lim);
this.isReadOnly = true;
#end[rw]
#if[byte]
this.address = arrayBaseOffset;
#end[byte]
}
Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private
@ -86,13 +77,11 @@ class Heap$Type$Buffer$RW$
hb = buf;
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
super(buf, off, len);
this.isReadOnly = true;
#end[rw]
#if[byte]
this.address = arrayBaseOffset;
#end[byte]
}
protected Heap$Type$Buffer$RW$($type$[] buf,
@ -105,13 +94,11 @@ class Heap$Type$Buffer$RW$
hb = buf;
offset = off;
*/
this.address = ARRAY_BASE_OFFSET + off * ARRAY_INDEX_SCALE;
#else[rw]
super(buf, mark, pos, lim, cap, off);
this.isReadOnly = true;
#end[rw]
#if[byte]
this.address = arrayBaseOffset + off;
#end[byte]
}
public $Type$Buffer slice() {
@ -296,18 +283,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public char getChar() {
return unsafe.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
return UNSAFE.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public char getChar(int i) {
return unsafe.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
return UNSAFE.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putChar(char x) {
#if[rw]
unsafe.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
UNSAFE.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -316,7 +303,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putChar(int i, char x) {
#if[rw]
unsafe.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
UNSAFE.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -347,18 +334,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public short getShort() {
return unsafe.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
return UNSAFE.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public short getShort(int i) {
return unsafe.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
return UNSAFE.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putShort(short x) {
#if[rw]
unsafe.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
UNSAFE.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -367,7 +354,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putShort(int i, short x) {
#if[rw]
unsafe.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
UNSAFE.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -398,18 +385,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public int getInt() {
return unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
return UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
}
public int getInt(int i) {
return unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
return UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
}
#end[rw]
public $Type$Buffer putInt(int x) {
#if[rw]
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -418,7 +405,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putInt(int i, int x) {
#if[rw]
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -449,18 +436,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public long getLong() {
return unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
return UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
}
public long getLong(int i) {
return unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
return UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
}
#end[rw]
public $Type$Buffer putLong(long x) {
#if[rw]
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -469,7 +456,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putLong(int i, long x) {
#if[rw]
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -500,12 +487,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public float getFloat() {
int x = unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
int x = UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
return Float.intBitsToFloat(x);
}
public float getFloat(int i) {
int x = unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
int x = UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
return Float.intBitsToFloat(x);
}
@ -514,7 +501,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(float x) {
#if[rw]
int y = Float.floatToRawIntBits(x);
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -524,7 +511,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(int i, float x) {
#if[rw]
int y = Float.floatToRawIntBits(x);
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -555,12 +542,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public double getDouble() {
long x = unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
long x = UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
return Double.longBitsToDouble(x);
}
public double getDouble(int i) {
long x = unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
long x = UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
return Double.longBitsToDouble(x);
}
@ -569,7 +556,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(double x) {
#if[rw]
long y = Double.doubleToRawLongBits(x);
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -579,7 +566,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(int i, double x) {
#if[rw]
long y = Double.doubleToRawLongBits(x);
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -643,7 +630,11 @@ class Heap$Type$Buffer$RW$
public ByteOrder order() {
return ByteOrder.nativeOrder();
}
#end[!byte]
#if[char]
ByteOrder charRegionOrder() {
return order();
}
#end[char]
}

View file

@ -127,4 +127,30 @@ class StringCharBuffer // package-private
return ByteOrder.nativeOrder();
}
ByteOrder charRegionOrder() {
return null;
}
public boolean equals(Object ob) {
if (this == ob)
return true;
if (!(ob instanceof CharBuffer))
return false;
CharBuffer that = (CharBuffer)ob;
if (this.remaining() != that.remaining())
return false;
return BufferMismatch.mismatch(this, this.position(),
that, that.position(),
this.remaining()) < 0;
}
public int compareTo(CharBuffer that) {
int i = BufferMismatch.mismatch(this, this.position(),
that, that.position(),
Math.min(this.remaining(), that.remaining()));
if (i >= 0) {
return Character.compare(this.get(this.position() + i), that.get(this.position() + i));
}
return this.remaining() - that.remaining();
}
}

View file

@ -36,6 +36,8 @@ import java.util.stream.StreamSupport;
import java.util.stream.$Streamtype$Stream;
#end[streamableType]
import jdk.internal.util.ArraysSupport;
/**
* $A$ $type$ buffer.
*
@ -287,6 +289,11 @@ public abstract class $Type$Buffer
this(mark, pos, lim, cap, null, 0);
}
@Override
Object base() {
return hb;
}
#if[byte]
/**
@ -1297,19 +1304,9 @@ public abstract class $Type$Buffer
$Type$Buffer that = ($Type$Buffer)ob;
if (this.remaining() != that.remaining())
return false;
int p = this.position();
for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
if (!equals(this.get(i), that.get(j)))
return false;
return true;
}
private static boolean equals($type$ x, $type$ y) {
#if[floatingPointType]
return (x == y) || ($Fulltype$.isNaN(x) && $Fulltype$.isNaN(y));
#else[floatingPointType]
return x == y;
#end[floatingPointType]
return BufferMismatch.mismatch(this, this.position(),
that, that.position(),
this.remaining()) < 0;
}
/**
@ -1336,11 +1333,11 @@ public abstract class $Type$Buffer
* is less than, equal to, or greater than the given buffer
*/
public int compareTo($Type$Buffer that) {
int n = this.position() + Math.min(this.remaining(), that.remaining());
for (int i = this.position(), j = that.position(); i < n; i++, j++) {
int cmp = compare(this.get(i), that.get(j));
if (cmp != 0)
return cmp;
int i = BufferMismatch.mismatch(this, this.position(),
that, that.position(),
Math.min(this.remaining(), that.remaining()));
if (i >= 0) {
return compare(this.get(this.position() + i), that.get(this.position() + i));
}
return this.remaining() - that.remaining();
}
@ -1571,6 +1568,12 @@ public abstract class $Type$Buffer
#end[!byte]
#if[char]
// The order or null if the buffer does not cover a memory region,
// such as StringCharBuffer
abstract ByteOrder charRegionOrder();
#end[char]
#if[byte]
boolean bigEndian // package-private

View file

@ -26,6 +26,7 @@
package java.util;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.util.ArraysSupport;
import java.lang.reflect.Array;
import java.util.concurrent.ForkJoinPool;

View file

@ -1,545 +0,0 @@
/*
* Copyright (c) 2015, 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.
*/
package java.util;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.misc.Unsafe;
/**
* Utility methods to find a mismatch between two primitive arrays.
*
* <p>Array equality and lexicographical comparison can be built on top of
* array mismatch functionality.
*
* <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages
* vector-based techniques to access and compare the contents of two arrays.
* The Java implementation uses {@code Unsafe.getLongUnaligned} to access the
* content of an array, thus access is supported on platforms that do not
* support unaligned access. For a byte[] array, 8 bytes (64 bits) can be
* accessed and compared as a unit rather than individually, which increases
* the performance when the method is compiled by the HotSpot VM. On supported
* platforms the mismatch implementation is intrinsified to leverage SIMD
* instructions. So for a byte[] array, 16 bytes (128 bits), 32 bytes
* (256 bits), and perhaps in the future even 64 bytes (512 bits), platform
* permitting, can be accessed and compared as a unit, which further increases
* the performance over the Java implementation.
*
* <p>None of the mismatch methods perform array bounds checks. It is the
* responsibility of the caller (direct or otherwise) to perform such checks
* before calling this method.
*/
class ArraysSupport {
static final Unsafe U = Unsafe.getUnsafe();
private static final boolean BIG_ENDIAN = U.isBigEndian();
private static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
private static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
private static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
private static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
private static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
private static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
private static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
private static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);
private static int exactLog2(int scale) {
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
return Integer.numberOfTrailingZeros(scale);
}
private ArraysSupport() {}
/**
* Find the relative index of the first mismatching pair of elements in two
* primitive arrays of the same component type. Pairs of elements will be
* tested in order relative to given offsets into both arrays.
*
* <p>This method does not perform type checks or bounds checks. It is the
* responsibility of the caller to perform such checks before calling this
* method.
*
* <p>The given offsets, in bytes, need not be aligned according to the
* given log<sub>2</sub> size the array elements. More specifically, an
* offset modulus the size need not be zero.
*
* @param a the first array to be tested for mismatch, or {@code null} for
* direct memory access
* @param aOffset the relative offset, in bytes, from the base address of
* the first array to test from, otherwise if the first array is
* {@code null}, an absolute address pointing to the first element to test.
* @param b the second array to be tested for mismatch, or {@code null} for
* direct memory access
* @param bOffset the relative offset, in bytes, from the base address of
* the second array to test from, otherwise if the second array is
* {@code null}, an absolute address pointing to the first element to test.
* @param length the number of array elements to test
* @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that
* corresponds to the size, in bytes, of an array element.
* @return if a mismatch is found a relative index, between 0 (inclusive)
* and {@code length} (exclusive), of the first mismatching pair of elements
* in the two arrays. Otherwise, if a mismatch is not found the bitwise
* compliment of the number of remaining pairs of elements to be checked in
* the tail of the two arrays.
*/
@HotSpotIntrinsicCandidate
static int vectorizedMismatch(Object a, long aOffset,
Object b, long bOffset,
int length,
int log2ArrayIndexScale) {
// assert a.getClass().isArray();
// assert b.getClass().isArray();
// assert 0 <= length <= sizeOf(a)
// assert 0 <= length <= sizeOf(b)
// assert 0 <= log2ArrayIndexScale <= 3
int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale;
int wi = 0;
for (; wi < length >> log2ValuesPerWidth; wi++) {
long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
long av = U.getLongUnaligned(a, aOffset + bi);
long bv = U.getLongUnaligned(b, bOffset + bi);
if (av != bv) {
long x = av ^ bv;
int o = BIG_ENDIAN
? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
: Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
return (wi << log2ValuesPerWidth) + o;
}
}
// Calculate the tail of remaining elements to check
int tail = length - (wi << log2ValuesPerWidth);
if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) {
int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale);
// Handle 4 bytes or 2 chars in the tail using int width
if (tail >= wordTail) {
long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
int av = U.getIntUnaligned(a, aOffset + bi);
int bv = U.getIntUnaligned(b, bOffset + bi);
if (av != bv) {
int x = av ^ bv;
int o = BIG_ENDIAN
? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
: Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
return (wi << log2ValuesPerWidth) + o;
}
tail -= wordTail;
}
return ~tail;
}
else {
return ~tail;
}
}
// Booleans
// Each boolean element takes up one byte
static int mismatch(boolean[] a,
boolean[] b,
int length) {
int i = 0;
if (length > 7) {
i = vectorizedMismatch(
a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[i] != b[i])
return i;
}
return -1;
}
static int mismatch(boolean[] a, int aFromIndex,
boolean[] b, int bFromIndex,
int length) {
int i = 0;
if (length > 7) {
int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;
int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex;
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i])
return i;
}
return -1;
}
// Bytes
/**
* Find the index of a mismatch between two arrays.
*
* <p>This method does not perform bounds checks. It is the responsibility
* of the caller to perform such bounds checks before calling this method.
*
* @param a the first array to be tested for a mismatch
* @param b the second array to be tested for a mismatch
* @param length the number of bytes from each array to check
* @return the index of a mismatch between the two arrays, otherwise -1 if
* no mismatch. The index will be within the range of (inclusive) 0 to
* (exclusive) the smaller of the two array lengths.
*/
static int mismatch(byte[] a,
byte[] b,
int length) {
// ISSUE: defer to index receiving methods if performance is good
// assert length <= a.length
// assert length <= b.length
int i = 0;
if (length > 7) {
i = vectorizedMismatch(
a, Unsafe.ARRAY_BYTE_BASE_OFFSET,
b, Unsafe.ARRAY_BYTE_BASE_OFFSET,
length, LOG2_ARRAY_BYTE_INDEX_SCALE);
if (i >= 0)
return i;
// Align to tail
i = length - ~i;
// assert i >= 0 && i <= 7;
}
// Tail < 8 bytes
for (; i < length; i++) {
if (a[i] != b[i])
return i;
}
return -1;
}
/**
* Find the relative index of a mismatch between two arrays starting from
* given indexes.
*
* <p>This method does not perform bounds checks. It is the responsibility
* of the caller to perform such bounds checks before calling this method.
*
* @param a the first array to be tested for a mismatch
* @param aFromIndex the index of the first element (inclusive) in the first
* array to be compared
* @param b the second array to be tested for a mismatch
* @param bFromIndex the index of the first element (inclusive) in the
* second array to be compared
* @param length the number of bytes from each array to check
* @return the relative index of a mismatch between the two arrays,
* otherwise -1 if no mismatch. The index will be within the range of
* (inclusive) 0 to (exclusive) the smaller of the two array bounds.
*/
static int mismatch(byte[] a, int aFromIndex,
byte[] b, int bFromIndex,
int length) {
// assert 0 <= aFromIndex < a.length
// assert 0 <= aFromIndex + length <= a.length
// assert 0 <= bFromIndex < b.length
// assert 0 <= bFromIndex + length <= b.length
// assert length >= 0
int i = 0;
if (length > 7) {
int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex;
int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex;
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_BYTE_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i])
return i;
}
return -1;
}
// Chars
static int mismatch(char[] a,
char[] b,
int length) {
int i = 0;
if (length > 3) {
i = vectorizedMismatch(
a, Unsafe.ARRAY_CHAR_BASE_OFFSET,
b, Unsafe.ARRAY_CHAR_BASE_OFFSET,
length, LOG2_ARRAY_CHAR_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[i] != b[i])
return i;
}
return -1;
}
static int mismatch(char[] a, int aFromIndex,
char[] b, int bFromIndex,
int length) {
int i = 0;
if (length > 3) {
int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_CHAR_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i])
return i;
}
return -1;
}
// Shorts
static int mismatch(short[] a,
short[] b,
int length) {
int i = 0;
if (length > 3) {
i = vectorizedMismatch(
a, Unsafe.ARRAY_SHORT_BASE_OFFSET,
b, Unsafe.ARRAY_SHORT_BASE_OFFSET,
length, LOG2_ARRAY_SHORT_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[i] != b[i])
return i;
}
return -1;
}
static int mismatch(short[] a, int aFromIndex,
short[] b, int bFromIndex,
int length) {
int i = 0;
if (length > 3) {
int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_SHORT_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i])
return i;
}
return -1;
}
// Ints
static int mismatch(int[] a,
int[] b,
int length) {
int i = 0;
if (length > 1) {
i = vectorizedMismatch(
a, Unsafe.ARRAY_INT_BASE_OFFSET,
b, Unsafe.ARRAY_INT_BASE_OFFSET,
length, LOG2_ARRAY_INT_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[i] != b[i])
return i;
}
return -1;
}
static int mismatch(int[] a, int aFromIndex,
int[] b, int bFromIndex,
int length) {
int i = 0;
if (length > 1) {
int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_INT_INDEX_SCALE);
if (i >= 0)
return i;
i = length - ~i;
}
for (; i < length; i++) {
if (a[aFromIndex + i] != b[bFromIndex + i])
return i;
}
return -1;
}
// Floats
static int mismatch(float[] a,
float[] b,
int length) {
return mismatch(a, 0, b, 0, length);
}
static int mismatch(float[] a, int aFromIndex,
float[] b, int bFromIndex,
int length) {
int i = 0;
if (length > 1) {
int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_FLOAT_INDEX_SCALE);
// Mismatched
if (i >= 0) {
// Check if mismatch is not associated with two NaN values
if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i]))
return i;
// Mismatch on two different NaN values that are normalized to match
// Fall back to slow mechanism
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
// However, requires that returned value be relative to input ranges
i++;
}
// Matched
else {
i = length - ~i;
}
}
for (; i < length; i++) {
if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i]))
return i;
}
return -1;
}
// 64 bit sizes
// Long
static int mismatch(long[] a,
long[] b,
int length) {
if (length == 0) {
return -1;
}
int i = vectorizedMismatch(
a, Unsafe.ARRAY_LONG_BASE_OFFSET,
b, Unsafe.ARRAY_LONG_BASE_OFFSET,
length, LOG2_ARRAY_LONG_INDEX_SCALE);
return i >= 0 ? i : -1;
}
static int mismatch(long[] a, int aFromIndex,
long[] b, int bFromIndex,
int length) {
if (length == 0) {
return -1;
}
int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
int i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_LONG_INDEX_SCALE);
return i >= 0 ? i : -1;
}
// Double
static int mismatch(double[] a,
double[] b,
int length) {
return mismatch(a, 0, b, 0, length);
}
static int mismatch(double[] a, int aFromIndex,
double[] b, int bFromIndex,
int length) {
if (length == 0) {
return -1;
}
int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
int i = vectorizedMismatch(
a, aOffset,
b, bOffset,
length, LOG2_ARRAY_DOUBLE_INDEX_SCALE);
if (i >= 0) {
// Check if mismatch is not associated with two NaN values
if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i]))
return i;
// Mismatch on two different NaN values that are normalized to match
// Fall back to slow mechanism
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
// However, requires that returned value be relative to input ranges
i++;
for (; i < length; i++) {
if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i]))
return i;
}
}
return -1;
}
}