This commit is contained in:
Lana Steuck 2018-01-04 04:22:28 +00:00
commit c8c8cd7238
121 changed files with 2574 additions and 913 deletions

View file

@ -25,7 +25,9 @@
package java.io;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
@ -229,30 +231,55 @@ public abstract class InputStream implements Closeable {
* @since 9
*/
public byte[] readAllBytes() throws IOException {
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int capacity = buf.length;
int nread = 0;
List<byte[]> bufs = null;
byte[] result = null;
int total = 0;
int n;
for (;;) {
// read to EOF which may read more or less than initial buffer size
while ((n = read(buf, nread, capacity - nread)) > 0)
do {
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int nread = 0;
// read to EOF which may read more or less than buffer size
while ((n = read(buf, nread, buf.length - nread)) > 0) {
nread += n;
// if the last call to read returned -1, then we're done
if (n < 0)
break;
// need to allocate a larger buffer
if (capacity <= MAX_BUFFER_SIZE - capacity) {
capacity = capacity << 1;
} else {
if (capacity == MAX_BUFFER_SIZE)
throw new OutOfMemoryError("Required array size too large");
capacity = MAX_BUFFER_SIZE;
}
buf = Arrays.copyOf(buf, capacity);
if (nread > 0) {
if (MAX_BUFFER_SIZE - total < nread) {
throw new OutOfMemoryError("Required array size too large");
}
total += nread;
if (result == null) {
result = buf;
} else {
if (bufs == null) {
bufs = new ArrayList<>();
bufs.add(result);
}
bufs.add(buf);
}
}
} while (n >= 0); // if the last call to read returned -1, then break
if (bufs == null) {
if (result == null) {
return new byte[0];
}
return result.length == total ?
result : Arrays.copyOf(result, total);
}
return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
result = new byte[total];
int offset = 0;
int remaining = total;
for (byte[] b : bufs) {
int len = Math.min(b.length, remaining);
System.arraycopy(b, 0, result, offset, len);
offset += len;
remaining -= len;
}
return result;
}
/**

View file

@ -140,14 +140,6 @@ public abstract class Reference<T> {
}
}
/*
* system property to disable clearing before enqueuing.
*/
private static final class ClearBeforeEnqueue {
static final boolean DISABLE =
Boolean.getBoolean("jdk.lang.ref.disableClearBeforeEnqueue");
}
/*
* Atomically get and clear (set to null) the VM's pending list.
*/
@ -299,8 +291,7 @@ public abstract class Reference<T> {
* it was not registered with a queue when it was created
*/
public boolean enqueue() {
if (!ClearBeforeEnqueue.DISABLE)
this.referent = null;
this.referent = null;
return this.queue.enqueue(this);
}

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

@ -2954,22 +2954,6 @@ public final class Files {
return newBufferedWriter(path, StandardCharsets.UTF_8, options);
}
/**
* Reads all bytes from an input stream and writes them to an output stream.
*/
private static long copy(InputStream source, OutputStream sink)
throws IOException
{
long nread = 0L;
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = source.read(buf)) > 0) {
sink.write(buf, 0, n);
nread += n;
}
return nread;
}
/**
* Copies all bytes from an input stream to a file. On return, the input
* stream will be at end of stream.
@ -3082,7 +3066,7 @@ public final class Files {
// do the copy
try (OutputStream out = ostream) {
return copy(in, out);
return in.transferTo(out);
}
}
@ -3124,7 +3108,7 @@ public final class Files {
Objects.requireNonNull(out);
try (InputStream in = newInputStream(source)) {
return copy(in, out);
return in.transferTo(out);
}
}

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;
}
}

View file

@ -204,58 +204,70 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* known concrete subclasses {@code ListResourceBundle} and
* {@code PropertyResourceBundle} are thread-safe.
*
* <h3><a id="bundleprovider">Resource Bundles in Named Modules</a></h3>
* <h3><a id="resource-bundle-modules">Resource Bundles and Named Modules</a></h3>
*
* When resource bundles are deployed in named modules, the following
* module-specific requirements and restrictions are applied.
* Resource bundles can be deployed in modules in the following ways:
*
* <ul>
* <li>Code in a named module that calls {@link #getBundle(String, Locale)}
* will locate resource bundles in the caller's module (<em>caller module</em>).</li>
* <li>If resource bundles are deployed in named modules separate from
* the caller module, those resource bundles need to be loaded from service
* providers of {@link ResourceBundleProvider}. The caller module must declare
* "{@code uses}" and the service interface name is the concatenation of the
* package name of the base name, string "{@code .spi.}", the simple class
* name of the base name, and the string "{@code Provider}". The
* <em>bundle provider modules</em> containing resource bundles must
* declare "{@code provides}" with the service interface name and
* its implementation class name. For example, if the base name is
* "{@code com.example.app.MyResources}", the caller module must declare
* "{@code uses com.example.app.spi.MyResourcesProvider;}" and a module containing resource
* bundles must declare "{@code provides com.example.app.spi.MyResourcesProvider
* with com.example.app.internal.MyResourcesProviderImpl;}"
* where {@code com.example.app.internal.MyResourcesProviderImpl} is an
* implementation class of {@code com.example.app.spi.MyResourcesProvider}.</li>
* <li>If you want to use non-standard formats in named modules, such as XML,
* {@link ResourceBundleProvider} needs to be used.</li>
* <li>The {@code getBundle} method with a {@code ClassLoader} may not be able to
* find resource bundles using the given {@code ClassLoader} in named modules.
* The {@code getBundle} method with a {@code Module} can be used, instead.</li>
* <li>{@code ResourceBundle.Control} is <em>not</em> supported in named modules.
* If the {@code getBundle} method with a {@code ResourceBundle.Control} is called
* in a named module, the method will throw an {@code UnsupportedOperationException}.
* Any service providers of {@link ResourceBundleControlProvider} are ignored in
* named modules.
* </li>
* </ul>
* <h4>Resource bundles together with an application</h4>
*
* <h3><a id="RBP_support">ResourceBundleProvider Service Providers</a></h3>
* Resource bundles can be deployed together with an application in the same
* module. In that case, the resource bundles are loaded
* by code in the module by calling the {@link #getBundle(String)}
* or {@link #getBundle(String, Locale)} method.
*
* The {@code getBundle} factory methods load service providers of
* {@link ResourceBundleProvider}, if available, using {@link ServiceLoader}.
* The service type is designated by
* {@code <package name> + ".spi." + <simple name> + "Provider"}. For
* example, if the base name is "{@code com.example.app.MyResources}", the service
* type is {@code com.example.app.spi.MyResourcesProvider}.
* <p>
* In named modules, the loaded service providers for the given base name are
* used to load resource bundles. If no service provider is available, or if
* none of the service providers returns a resource bundle and the caller module
* doesn't have its own service provider, the {@code getBundle} factory method
* searches for resource bundles that are local in the caller module and that
* are visible to the class loader of the caller module. The resource bundle
* formats for local module searching are "java.class" and "java.properties".
* <h4><a id="service-providers">Resource bundles as service providers</a></h4>
*
* Resource bundles can be deployed in one or more <em>service provider modules</em>
* and they can be located using {@link ServiceLoader}.
* A {@linkplain ResourceBundleProvider service} interface or class must be
* defined. The caller module declares that it uses the service, the service
* provider modules declare that they provide implementations of the service.
* Refer to {@link ResourceBundleProvider} for developing resource bundle
* services and deploying resource bundle providers.
* The module obtaining the resource bundle can be a resource bundle
* provider itself; in which case this module only locates the resource bundle
* via service provider mechanism.
*
* <p>A {@linkplain ResourceBundleProvider resource bundle provider} can
* provide resource bundles in any format such XML which replaces the need
* of {@link Control ResourceBundle.Control}.
*
* <h4><a id="other-modules">Resource bundles in other modules and class path</a></h4>
*
* Resource bundles in a named module may be <em>encapsulated</em> so that
* it cannot be located by code in other modules. Resource bundles
* in unnamed modules and class path are open for any module to access.
* Resource bundle follows the resource encapsulation rules as specified
* in {@link Module#getResourceAsStream(String)}.
*
* <p>The {@code getBundle} factory methods with no {@code Control} parameter
* locate and load resource bundles from
* {@linkplain ResourceBundleProvider service providers}.
* It may continue the search as if calling {@link Module#getResourceAsStream(String)}
* to find the named resource from a given module and calling
* {@link ClassLoader#getResourceAsStream(String)}; refer to
* the specification of the {@code getBundle} method for details.
* Only non-encapsulated resource bundles of "{@code java.class}"
* or "{@code java.properties}" format are searched.
*
* <p>If the caller module is a
* <a href="{@docRoot}/java/util/spi/ResourceBundleProvider.html#obtain-resource-bundle">
* resource bundle provider</a>, it does not fall back to the
* class loader search.
*
* <h4>Resource bundles in automatic modules</h4>
*
* A common format of resource bundles is in {@linkplain PropertyResourceBundle
* .properties} file format. Typically {@code .properties} resource bundles
* are packaged in a JAR file. Resource bundle only JAR file can be readily
* deployed as an <a href="{@docRoot}/java/lang/module/ModuleFinder.html#automatic-modules">
* automatic module</a>. For example, if the JAR file contains the
* entry "{@code p/q/Foo_ja.properties}" and no {@code .class} entry,
* when resolved and defined as an automatic module, no package is derived
* for this module. This allows resource bundles in {@code .properties}
* format packaged in one or more JAR files that may contain entries
* in the same directory and can be resolved successfully as
* automatic modules.
*
* <h3>ResourceBundle.Control</h3>
*
@ -268,6 +280,14 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
* {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
* factory method for details.
*
* <p> {@link ResourceBundle.Control} is designed for an application deployed
* in an unnamed module, for example to support resource bundles in
* non-standard formats or package localized resources in a non-traditional
* convention. {@link ResourceBundleProvider} is the replacement for
* {@code ResourceBundle.Control} when migrating to modules.
* {@code UnsupportedOperationException} will be thrown when a factory
* method that takes the {@code ResourceBundle.Control} parameter is called.
*
* <p><a id="modify_default_behavior">For the {@code getBundle} factory</a>
* methods that take no {@link Control} instance, their <a
* href="#default_behavior"> default behavior</a> of resource bundle loading
@ -815,14 +835,10 @@ public abstract class ResourceBundle {
/**
* Gets a resource bundle using the specified base name, the default locale,
* and the caller's class loader. Calling this method is equivalent to calling
* and the caller module. Calling this method is equivalent to calling
* <blockquote>
* <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
* <code>getBundle(baseName, Locale.getDefault(), callerModule)</code>,
* </blockquote>
* except that <code>getClassLoader()</code> is run with the security
* privileges of <code>ResourceBundle</code>.
* See {@link #getBundle(String, Locale, ClassLoader) getBundle}
* for a complete description of the search and instantiation strategy.
*
* @param baseName the base name of the resource bundle, a fully qualified class name
* @exception java.lang.NullPointerException
@ -830,6 +846,9 @@ public abstract class ResourceBundle {
* @exception MissingResourceException
* if no resource bundle for the specified base name can be found
* @return a resource bundle for the given base name and the default locale
*
* @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
* @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
*/
@CallerSensitive
public static final ResourceBundle getBundle(String baseName)
@ -887,14 +906,10 @@ public abstract class ResourceBundle {
/**
* Gets a resource bundle using the specified base name and locale,
* and the caller's class loader. Calling this method is equivalent to calling
* and the caller module. Calling this method is equivalent to calling
* <blockquote>
* <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
* <code>getBundle(baseName, locale, callerModule)</code>,
* </blockquote>
* except that <code>getClassLoader()</code> is run with the security
* privileges of <code>ResourceBundle</code>.
* See {@link #getBundle(String, Locale, ClassLoader) getBundle}
* for a complete description of the search and instantiation strategy.
*
* @param baseName
* the base name of the resource bundle, a fully qualified class name
@ -905,6 +920,9 @@ public abstract class ResourceBundle {
* @exception MissingResourceException
* if no resource bundle for the specified base name can be found
* @return a resource bundle for the given base name and locale
*
* @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
* @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
*/
@CallerSensitive
public static final ResourceBundle getBundle(String baseName,
@ -922,19 +940,6 @@ public abstract class ResourceBundle {
* <code>getBundle(baseName, Locale.getDefault(), module)</code>
* </blockquote>
*
* <p> Resource bundles in named modules may be encapsulated. When
* the resource bundle is loaded from a provider, the caller module
* must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
* to declare that the module uses implementations of
* {@code <package name> + ".spi." + <simple name> + "Provider"}.
* Otherwise, it will load the resource bundles that are local in the
* given module or that are visible to the class loader of the given module
* (refer to the <a href="#bundleprovider">Resource Bundles in Named Modules</a>
* section for details).
* When the resource bundle is loaded from the specified module, it is
* subject to the encapsulation rules specified by
* {@link Module#getResourceAsStream Module.getResourceAsStream}.
*
* @param baseName the base name of the resource bundle,
* a fully qualified class name
* @param module the module for which the resource bundle is searched
@ -950,6 +955,8 @@ public abstract class ResourceBundle {
* @since 9
* @spec JPMS
* @see ResourceBundleProvider
* @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
* @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Module module) {
@ -963,14 +970,15 @@ public abstract class ResourceBundle {
* on behalf of the specified module.
*
* <p> Resource bundles in named modules may be encapsulated. When
* the resource bundle is loaded from a provider, the caller module
* the resource bundle is loaded from a
* {@linkplain ResourceBundleProvider service provider}, the caller module
* must have an appropriate <i>uses</i> clause in its <i>module descriptor</i>
* to declare that the module uses implementations of
* {@code <package name> + ".spi." + <simple name> + "Provider"}.
* to declare that the module uses of {@link ResourceBundleProvider}
* for the named resource bundle.
* Otherwise, it will load the resource bundles that are local in the
* given module or that are visible to the class loader of the given module
* (refer to the <a href="#bundleprovider">Resource Bundles in Named Modules</a>
* section for details).
* given module as if calling {@link Module#getResourceAsStream(String)}
* or that are visible to the class loader of the given module
* as if calling {@link ClassLoader#getResourceAsStream(String)}.
* When the resource bundle is loaded from the specified module, it is
* subject to the encapsulation rules specified by
* {@link Module#getResourceAsStream Module.getResourceAsStream}.
@ -1000,6 +1008,8 @@ public abstract class ResourceBundle {
* @return a resource bundle for the given base name and locale in the module
* @since 9
* @spec JPMS
* @see <a href="#default_behavior">Resource Bundle Search and Loading Strategy</a>
* @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
@ -1060,28 +1070,25 @@ public abstract class ResourceBundle {
* Gets a resource bundle using the specified base name, locale, and class
* loader.
*
* <p>This method behaves the same as calling
* {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
* default instance of {@link Control} unless another {@link Control} is
* provided with the {@link ResourceBundleControlProvider} SPI. Refer to the
* description of <a href="#modify_default_behavior">modifying the default
* behavior</a>.
* <p>When this method is called from a named module and the given
* loader is the class loader of the caller module, this is equivalent
* to calling:
* <blockquote><pre>
* getBundle(baseName, targetLocale, callerModule)
* </pre></blockquote>
*
* <p><a id="default_behavior">The following describes the default
* behavior</a>.
* otherwise, this is equivalent to calling:
* <blockquote><pre>
* getBundle(baseName, targetLocale, loader, control)
* </pre></blockquote>
* where {@code control} is the default instance of {@link Control} unless
* a {@code Control} instance is provided by
* {@link ResourceBundleControlProvider} SPI. Refer to the
* description of <a href="#modify_default_behavior">modifying the default
* behavior</a>. The following describes the default behavior.
*
* <p>
* Resource bundles in a named module are private to that module. If
* the caller is in a named module, this method will find resource bundles
* from the service providers of {@link java.util.spi.ResourceBundleProvider}
* if any. Otherwise, it will load the resource bundles that are visible to
* the given {@code loader} (refer to the
* <a href="#bundleprovider">Resource Bundles in Named Modules</a> section
* for details).
* If the caller is in a named module and the given {@code loader} is
* different than the caller's class loader, or if the caller is not in
* a named module, this method will not find resource bundles from named
* modules.
* <b><a id="default_behavior">Resource Bundle Search and Loading Strategy</a></b>
*
* <p><code>getBundle</code> uses the base name, the specified locale, and
* the default locale (obtained from {@link java.util.Locale#getDefault()
@ -1201,7 +1208,7 @@ public abstract class ResourceBundle {
*
* <p><b>Note:</b>The <code>baseName</code> argument should be a fully
* qualified class name. However, for compatibility with earlier versions,
* Sun's Java SE Runtime Environments do not verify this, and so it is
* Java SE Runtime Environments do not verify this, and so it is
* possible to access <code>PropertyResourceBundle</code>s by specifying a
* path name (using "/") instead of a fully qualified class name (using
* ".").
@ -1248,7 +1255,7 @@ public abstract class ResourceBundle {
*
* @apiNote If the caller module is a named module and the given
* {@code loader} is the caller module's class loader, this method is
* equivalent to {@code getBundle(baseName, locale)}; otherwise, it will not
* equivalent to {@code getBundle(baseName, locale)}; otherwise, it may not
* find resource bundles from named modules.
* Use {@link #getBundle(String, Locale, Module)} to load resource bundles
* on behalf on a specific module instead.
@ -1264,6 +1271,7 @@ public abstract class ResourceBundle {
* @since 1.2
* @revised 9
* @spec JPMS
* @see <a href="#resource-bundle-modules">Resource Bundles and Named Modules</a>
*/
@CallerSensitive
public static ResourceBundle getBundle(String baseName, Locale locale,
@ -1278,9 +1286,9 @@ public abstract class ResourceBundle {
/**
* Returns a resource bundle using the specified base name, target
* locale, class loader and control. Unlike the {@linkplain
* #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
* factory methods with no <code>control</code> argument}, the given
* locale, class loader and control. Unlike the {@link
* #getBundle(String, Locale, ClassLoader) getBundle}
* factory methods with no {@code control} argument, the given
* <code>control</code> specifies how to locate and instantiate resource
* bundles. Conceptually, the bundle loading process with the given
* <code>control</code> is performed in the following steps.
@ -2365,7 +2373,14 @@ public abstract class ResourceBundle {
* the callback methods provides the information necessary for the
* factory methods to perform the <a
* href="./ResourceBundle.html#default_behavior">default behavior</a>.
* <a href="#note">Note that this class is not supported in named modules.</a>
*
* <p> {@link ResourceBundle.Control} is designed for an application deployed
* in an unnamed module, for example to support resource bundles in
* non-standard formats or package localized resources in a non-traditional
* convention. {@link ResourceBundleProvider} is the replacement for
* {@code ResourceBundle.Control} when migrating to modules.
* {@code UnsupportedOperationException} will be thrown when a factory
* method that takes the {@code ResourceBundle.Control} parameter is called.
*
* <p>In addition to the callback methods, the {@link
* #toBundleName(String, Locale) toBundleName} and {@link
@ -2501,8 +2516,8 @@ public abstract class ResourceBundle {
* }
* </pre>
*
* @apiNote <a id="note">{@code ResourceBundle.Control} is not supported
* in named modules.</a> If the {@code ResourceBundle.getBundle} method with
* @apiNote {@code ResourceBundle.Control} is not supported
* in named modules. If the {@code ResourceBundle.getBundle} method with
* a {@code ResourceBundle.Control} is called in a named module, the method
* will throw an {@link UnsupportedOperationException}. Any service providers
* of {@link ResourceBundleControlProvider} are ignored in named modules.

View file

@ -45,42 +45,46 @@ import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
*
* <p>
* Resource bundles can be packaged in one or more
* named modules, <em>bundle modules</em>. The <em>consumer</em> of the
* named modules, <em>service provider modules</em>. The <em>consumer</em> of the
* resource bundle is the one calling {@link ResourceBundle#getBundle(String)}.
* In order for the consumer module to load a resource bundle
* "{@code com.example.app.MyResources}" provided by another module,
* it will use the {@linkplain java.util.ServiceLoader service loader}
* mechanism. A service interface named "{@code com.example.app.MyResourcesProvider}"
* must be defined and a <em>bundle provider module</em> will provide an
* implementation class of "{@code com.example.app.MyResourcesProvider}"
* mechanism. A service interface named "{@code com.example.app.spi.MyResourcesProvider}"
* must be defined and a <em>service provider module</em> will provide an
* implementation class of "{@code com.example.app.spi.MyResourcesProvider}"
* as follows:
*
* <pre><code>
* import com.example.app.MyResourcesProvider;
* <blockquote><pre>
* {@code import com.example.app.spi.MyResourcesProvider;
* class MyResourcesProviderImpl extends AbstractResourceBundleProvider
* implements MyResourcesProvider
* {
* public MyResourcesProviderImpl() {
* super("java.properties");
* }
* // this provider maps the resource bundle to per-language package
* protected String toBundleName(String baseName, Locale locale) {
* // return the bundle name per the naming of the resource bundle
* :
* return "p." + locale.getLanguage() + "." + baseName;
* }
*
* public ResourceBundle getBundle(String baseName, Locale locale) {
* // this module only provides bundles in french
* // this module only provides bundles in French
* if (locale.equals(Locale.FRENCH)) {
* return super.getBundle(baseName, locale);
* }
* // otherwise return null
* return null;
* }
* }</code></pre>
* }}</pre></blockquote>
*
* @see <a href="../ResourceBundle.html#bundleprovider">
* Resource Bundles in Named Modules</a>
* @see <a href="../ResourceBundle.html#RBP_support">
* ResourceBundleProvider Service Providers</a>
* Refer to {@link ResourceBundleProvider} for details.
*
* @see <a href="../ResourceBundle.html#resource-bundle-modules">
* Resource Bundles and Named Modules</a>
* @since 9
* @spec JPMS
*/
public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
private static final JavaUtilResourceBundleAccess RB_ACCESS =

View file

@ -29,33 +29,117 @@ import java.util.Locale;
import java.util.ResourceBundle;
/**
* {@code ResourceBundleProvider} is a provider interface that is used for
* loading resource bundles for named modules. Implementation classes of
* this interface are loaded with {@link java.util.ServiceLoader ServiceLoader}
* during a call to the
* {@link ResourceBundle#getBundle(String, Locale, ClassLoader)
* ResourceBundle.getBundle} method. The provider service type is determined by
* {@code <package name> + ".spi." + <simple name> + "Provider"}.
* {@code ResourceBundleProvider} is a service provider interface for
* resource bundles. It is used by
* {@link ResourceBundle#getBundle(String) ResourceBundle.getBundle}
* factory methods to locate and load the service providers that are deployed as
* modules via {@link java.util.ServiceLoader ServiceLoader}.
*
* <p>
* For example, if the base name is "com.example.app.MyResources",
* {@code com.example.app.spi.MyResourcesProvider} will be the provider service type:
* <pre>{@code
* <h3>Developing resource bundle services</h3>
*
* A service for a resource bundle of a given <em>{@code baseName}</em> must have
* a fully-qualified class name of the form:
* <blockquote>
* {@code <package of baseName> + ".spi." + <simple name of baseName> + "Provider"}
* </blockquote>
*
* The service type is in a {@code spi} subpackage as it may be packaged in
* a module separate from the resource bundle providers.
* For example, the service for a resource bundle named
* {@code com.example.app.MyResources} must be
* {@code com.example.app.spi.MyResourcesProvider}:
*
* <blockquote><pre>
* {@code package com.example.app.spi;
* public interface MyResourcesProvider extends ResourceBundleProvider {
* }
* }</pre>
* }</pre></blockquote>
*
* <p>
* This providers's {@link #getBundle(String, Locale) getBundle} method is called
* through the resource bundle loading process instead of {@link
* java.util.ResourceBundle.Control#newBundle(String, Locale, String, ClassLoader, boolean)
* ResourceBundle.Control.newBundle()}. Refer to {@link ResourceBundle} for
* details.
* <h3>Deploying resource bundle service providers</h3>
*
* @see <a href="../ResourceBundle.html#bundleprovider">
* Resource Bundles in Named Modules</a>
* @see <a href="../ResourceBundle.html#RBP_support">
* ResourceBundleProvider Service Providers</a>
* Resource bundles can be deployed in one or more service providers
* in modules. For example, a provider for a service
* named "{@code com.example.app.spi.MyResourcesProvider}"
* has the following implementation class:
*
* <blockquote><pre>
* {@code import com.example.app.spi.MyResourcesProvider;
* class MyResourcesProviderImpl extends AbstractResourceBundleProvider
* implements MyResourcesProvider
* {
* public MyResourcesProviderImpl() {
* super("java.properties");
* }
* // this provider maps the resource bundle to per-language package
* protected String toBundleName(String baseName, Locale locale) {
* return "p." + locale.getLanguage() + "." + baseName;
* }
*
* public ResourceBundle getBundle(String baseName, Locale locale) {
* // this module only provides bundles in French
* if (locale.equals(Locale.FRENCH)) {
* return super.getBundle(baseName, locale);
* }
* // otherwise return null
* return null;
* }
* }}</pre></blockquote>
*
* This example provides "{@code com.example.app.MyResources}"
* resource bundle of the French locale. Traditionally resource bundles of
* all locales are packaged in the same package as the resource bundle base name.
* When deploying resource bundles in more than one modules and two modules
* containing a package of the same name, <em>split package</em>,
* is not supported, resource bundles in each module can be packaged in
* a different package as shown in this example where this provider packages
* the resource bundles in per-language package, i.e. {@code com.example.app.fr}
* for French locale.
*
* <p> A provider can provide more than one services, each of which is a service
* for a resource bundle of a different base name.
*
* <p>{@link AbstractResourceBundleProvider}
* provides the basic implementation for {@code ResourceBundleProvider}
* and a subclass can override the {@link
* AbstractResourceBundleProvider#toBundleName(String, Locale) toBundleName}
* method to return a provider-specific location of the resource to be loaded,
* for example, per-language package.
* A provider can override {@link #getBundle ResourceBundleProvider.getBundle}
* method for example to only search the known supported locales or
* return resource bundles in other formats such as XML.
*
* <p>The module declaration of this provider module specifies the following
* directive:
* <pre>
* provides com.example.app.spi.MyResourcesProvider with com.example.impl.MyResourcesProviderImpl;
* </pre>
*
* <h3><a id="obtain-resource-bundle">Obtaining resource bundles from providers</a></h3>
*
* The module declaration of the <em>consumer module</em> that calls one of the
* {@code ResourceBundle.getBundle} factory methods to obtain a resource
* bundle from service providers must specify the following directive:
* <pre>
* uses com.example.app.spi.MyResourcesProvider;
* </pre>
*
* {@link ResourceBundle#getBundle(String, Locale)
* ResourceBundle.getBundle("com.example.app.MyResource", locale)}
* locates and loads the providers for {@code com.example.app.spi.MyResourcesProvider}
* service and then invokes {@link #getBundle(String, Locale)
* ResourceBundleProvider.getBundle("com.example.app.MyResource", locale)} to
* find the resource bundle of the given base name and locale.
* If the consumer module is a resource bundle service provider for
* {@code com.example.app.spi.MyResourcesProvider}, {@code ResourceBundle.getBundle}
* will locate resource bundles only from service providers.
* Otherwise, {@code ResourceBundle.getBundle} may continue the search of
* the resource bundle in other modules and class path per the specification
* of the {@code ResourceBundle.getBundle} method being called.
*
* @see AbstractResourceBundleProvider
* @see <a href="../ResourceBundle.html#resource-bundle-modules">
* Resource Bundles and Named Modules</a>
* @see java.util.ServiceLoader
* @since 9
* @spec JPMS
*/