mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
Merge
This commit is contained in:
commit
8f528fba93
608 changed files with 7528 additions and 3300 deletions
|
@ -27,6 +27,7 @@ package java.io;
|
|||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class implements an output stream in which the data is
|
||||
|
@ -147,10 +148,7 @@ public class ByteArrayOutputStream extends OutputStream {
|
|||
* @param len the number of bytes to write.
|
||||
*/
|
||||
public synchronized void write(byte b[], int off, int len) {
|
||||
if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) - b.length > 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
ensureCapacity(count + len);
|
||||
System.arraycopy(b, off, buf, count, len);
|
||||
count += len;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, 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
|
||||
|
@ -2256,7 +2256,7 @@ public class File
|
|||
private transient volatile Path filePath;
|
||||
|
||||
/**
|
||||
* Returns a {@link Path java.nio.file.Path} object constructed from the
|
||||
* Returns a {@link Path java.nio.file.Path} object constructed from
|
||||
* this abstract path. The resulting {@code Path} is associated with the
|
||||
* {@link java.nio.file.FileSystems#getDefault default-filesystem}.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, 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
|
||||
|
@ -25,7 +25,9 @@
|
|||
|
||||
package java.io;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -53,6 +55,93 @@ public abstract class InputStream implements Closeable {
|
|||
|
||||
private static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
|
||||
/**
|
||||
* Returns a new {@code InputStream} that reads no bytes. The returned
|
||||
* stream is initially open. The stream is closed by calling the
|
||||
* {@code close()} method. Subsequent calls to {@code close()} have no
|
||||
* effect.
|
||||
*
|
||||
* <p> While the stream is open, the {@code available()}, {@code read()},
|
||||
* {@code read(byte[])}, {@code read(byte[], int, int)},
|
||||
* {@code readAllBytes()}, {@code readNBytes()}, {@code skip()}, and
|
||||
* {@code transferTo()} methods all behave as if end of stream has been
|
||||
* reached. After the stream has been closed, these methods all throw
|
||||
* {@code IOException}.
|
||||
*
|
||||
* <p> The {@code markSupported()} method returns {@code false}. The
|
||||
* {@code mark()} method does nothing, and the {@code reset()} method
|
||||
* throws {@code IOException}.
|
||||
*
|
||||
* @return an {@code InputStream} which contains no bytes
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public static InputStream nullInputStream() {
|
||||
return new InputStream() {
|
||||
private volatile boolean closed;
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available () throws IOException {
|
||||
ensureOpen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
ensureOpen();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
ensureOpen();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readAllBytes() throws IOException {
|
||||
ensureOpen();
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readNBytes(byte[] b, int off, int len)
|
||||
throws IOException {
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
ensureOpen();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
ensureOpen();
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long transferTo(OutputStream out) throws IOException {
|
||||
Objects.requireNonNull(out);
|
||||
ensureOpen();
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from the input stream. The value byte is
|
||||
* returned as an <code>int</code> in the range <code>0</code> to
|
||||
|
@ -164,7 +253,6 @@ public abstract class InputStream implements Closeable {
|
|||
* @see java.io.InputStream#read()
|
||||
*/
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
Objects.requireNonNull(b);
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
|
@ -229,30 +317,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,7 +412,6 @@ public abstract class InputStream implements Closeable {
|
|||
* @since 9
|
||||
*/
|
||||
public int readNBytes(byte[] b, int off, int len) throws IOException {
|
||||
Objects.requireNonNull(b);
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
|
||||
int n = 0;
|
||||
|
|
|
@ -1296,7 +1296,6 @@ public class ObjectInputStream
|
|||
* @throws InvalidClassException if the filter rejects creation
|
||||
*/
|
||||
private void checkArray(Class<?> arrayType, int arrayLength) throws InvalidClassException {
|
||||
Objects.requireNonNull(arrayType);
|
||||
if (! arrayType.isArray()) {
|
||||
throw new IllegalArgumentException("not an array type");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2018, 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
|
||||
|
@ -46,6 +46,51 @@ import java.util.Objects;
|
|||
* @since 1.0
|
||||
*/
|
||||
public abstract class OutputStream implements Closeable, Flushable {
|
||||
/**
|
||||
* Returns a new {@code OutputStream} which discards all bytes. The
|
||||
* returned stream is initially open. The stream is closed by calling
|
||||
* the {@code close()} method. Subsequent calls to {@code close()} have
|
||||
* no effect.
|
||||
*
|
||||
* <p> While the stream is open, the {@code write(int)}, {@code
|
||||
* write(byte[])}, and {@code write(byte[], int, int)} methods do nothing.
|
||||
* After the stream has been closed, these methods all throw {@code
|
||||
* IOException}.
|
||||
*
|
||||
* <p> The {@code flush()} method does nothing.
|
||||
*
|
||||
* @return an {@code OutputStream} which discards all bytes
|
||||
*
|
||||
* @since 11
|
||||
*/
|
||||
public static OutputStream nullOutputStream() {
|
||||
return new OutputStream() {
|
||||
private volatile boolean closed;
|
||||
|
||||
private void ensureOpen() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Stream closed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
ensureOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
ensureOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this output stream. The general
|
||||
* contract for <code>write</code> is that one byte is written
|
||||
|
@ -106,7 +151,6 @@ public abstract class OutputStream implements Closeable, Flushable {
|
|||
* stream is closed.
|
||||
*/
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
Objects.requireNonNull(b);
|
||||
Objects.checkFromIndexSize(off, len, b.length);
|
||||
// len == 0 condition implicitly handled by loop bounds
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2018, 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
|
||||
|
@ -1099,16 +1099,23 @@ public class Runtime {
|
|||
m.group(VersionPattern.OPT_GROUP));
|
||||
|
||||
// empty '+'
|
||||
if ((m.group(VersionPattern.PLUS_GROUP) != null)
|
||||
&& !build.isPresent()) {
|
||||
if (optional.isPresent()) {
|
||||
if (pre.isPresent())
|
||||
throw new IllegalArgumentException("'+' found with"
|
||||
+ " pre-release and optional components:'" + s
|
||||
+ "'");
|
||||
if (!build.isPresent()) {
|
||||
if (m.group(VersionPattern.PLUS_GROUP) != null) {
|
||||
if (optional.isPresent()) {
|
||||
if (pre.isPresent())
|
||||
throw new IllegalArgumentException("'+' found with"
|
||||
+ " pre-release and optional components:'" + s
|
||||
+ "'");
|
||||
} else {
|
||||
throw new IllegalArgumentException("'+' found with neither"
|
||||
+ " build or optional components: '" + s + "'");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("'+' found with neither"
|
||||
+ " build or optional components: '" + s + "'");
|
||||
if (optional.isPresent() && !pre.isPresent()) {
|
||||
throw new IllegalArgumentException("optional component"
|
||||
+ " must be preceeded by a pre-release component"
|
||||
+ " or '+': '" + s + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Version(List.of(version), pre, build, optional);
|
||||
|
|
|
@ -1667,6 +1667,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
|||
/** Craft a LambdaForm customized for this particular MethodHandle */
|
||||
/*non-public*/
|
||||
void customize() {
|
||||
final LambdaForm form = this.form;
|
||||
if (form.customized == null) {
|
||||
LambdaForm newForm = form.customize(this);
|
||||
updateForm(newForm);
|
||||
|
|
|
@ -3766,6 +3766,7 @@ assertEquals("xy", h3.invoke("x", "y", 1, "a", "b", "c"));
|
|||
* specified in the elements of the {@code filters} array.
|
||||
* The first element of the filter array corresponds to the {@code pos}
|
||||
* argument of the target, and so on in sequence.
|
||||
* The filter functions are invoked in left to right order.
|
||||
* <p>
|
||||
* Null arguments in the array are treated as identity functions,
|
||||
* and the corresponding arguments left unchanged.
|
||||
|
@ -3836,11 +3837,12 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
|
|||
MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
|
||||
filterArgumentsCheckArity(target, pos, filters);
|
||||
MethodHandle adapter = target;
|
||||
int curPos = pos-1; // pre-incremented
|
||||
for (MethodHandle filter : filters) {
|
||||
curPos += 1;
|
||||
// process filters in reverse order so that the invocation of
|
||||
// the resulting adapter will invoke the filters in left-to-right order
|
||||
for (int i = filters.length - 1; i >= 0; --i) {
|
||||
MethodHandle filter = filters[i];
|
||||
if (filter == null) continue; // ignore null elements of filters
|
||||
adapter = filterArgument(adapter, curPos, filter);
|
||||
adapter = filterArgument(adapter, pos + i, filter);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
|
|
@ -2521,7 +2521,7 @@ public class ModuleDescriptor
|
|||
* the {@code packageFinder} throws an {@link UncheckedIOException} then
|
||||
* {@link IOException} cause will be re-thrown. </p>
|
||||
*
|
||||
* <p> The module descriptor is read from the buffer stating at index
|
||||
* <p> The module descriptor is read from the buffer starting at index
|
||||
* {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
|
||||
* position} when this method is invoked. Upon return the buffer's position
|
||||
* will be equal to {@code p + n} where {@code n} is the number of bytes
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, 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
|
||||
|
@ -317,10 +317,9 @@ public class InetSocketAddress
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets the {@code InetAddress}.
|
||||
*
|
||||
* @return the InetAdress or {@code null} if it is unresolved.
|
||||
* @return the InetAddress or {@code null} if it is unresolved.
|
||||
*/
|
||||
public final InetAddress getAddress() {
|
||||
return holder.getAddress();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
198
src/java.base/share/classes/java/nio/BufferMismatch.java
Normal file
198
src/java.base/share/classes/java/nio/BufferMismatch.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1550,7 +1550,6 @@ public class ArrayList<E> extends AbstractList<E>
|
|||
setBit(deathRow, i - beg);
|
||||
if (modCount != expectedModCount)
|
||||
throw new ConcurrentModificationException();
|
||||
expectedModCount++;
|
||||
modCount++;
|
||||
int w = beg;
|
||||
for (i = beg; i < end; i++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1023,7 +1023,6 @@ public class Vector<E>
|
|||
setBit(deathRow, i - beg);
|
||||
if (modCount != expectedModCount)
|
||||
throw new ConcurrentModificationException();
|
||||
expectedModCount++;
|
||||
modCount++;
|
||||
int w = beg;
|
||||
for (i = beg; i < end; i++)
|
||||
|
|
|
@ -245,8 +245,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
|||
Future<T> f = futures.get(i);
|
||||
if (!f.isDone()) {
|
||||
try { f.get(); }
|
||||
catch (CancellationException ignore) {}
|
||||
catch (ExecutionException ignore) {}
|
||||
catch (CancellationException | ExecutionException ignore) {}
|
||||
}
|
||||
}
|
||||
return futures;
|
||||
|
@ -283,8 +282,7 @@ public abstract class AbstractExecutorService implements ExecutorService {
|
|||
Future<T> f = futures.get(j);
|
||||
if (!f.isDone()) {
|
||||
try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
|
||||
catch (CancellationException ignore) {}
|
||||
catch (ExecutionException ignore) {}
|
||||
catch (CancellationException | ExecutionException ignore) {}
|
||||
catch (TimeoutException timedOut) {
|
||||
break timedOut;
|
||||
}
|
||||
|
|
|
@ -717,12 +717,12 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
*/
|
||||
static Class<?> comparableClassFor(Object x) {
|
||||
if (x instanceof Comparable) {
|
||||
Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
|
||||
Class<?> c; Type[] ts, as; ParameterizedType p;
|
||||
if ((c = x.getClass()) == String.class) // bypass checks
|
||||
return c;
|
||||
if ((ts = c.getGenericInterfaces()) != null) {
|
||||
for (int i = 0; i < ts.length; ++i) {
|
||||
if (((t = ts[i]) instanceof ParameterizedType) &&
|
||||
for (Type t : ts) {
|
||||
if ((t instanceof ParameterizedType) &&
|
||||
((p = (ParameterizedType)t).getRawType() ==
|
||||
Comparable.class) &&
|
||||
(as = p.getActualTypeArguments()) != null &&
|
||||
|
@ -2328,15 +2328,15 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
* @param check if <0, don't check resize, if <= 1 only check if uncontended
|
||||
*/
|
||||
private final void addCount(long x, int check) {
|
||||
CounterCell[] as; long b, s;
|
||||
if ((as = counterCells) != null ||
|
||||
CounterCell[] cs; long b, s;
|
||||
if ((cs = counterCells) != null ||
|
||||
!U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
|
||||
CounterCell a; long v; int m;
|
||||
CounterCell c; long v; int m;
|
||||
boolean uncontended = true;
|
||||
if (as == null || (m = as.length - 1) < 0 ||
|
||||
(a = as[ThreadLocalRandom.getProbe() & m]) == null ||
|
||||
if (cs == null || (m = cs.length - 1) < 0 ||
|
||||
(c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
|
||||
!(uncontended =
|
||||
U.compareAndSetLong(a, CELLVALUE, v = a.value, v + x))) {
|
||||
U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
|
||||
fullAddCount(x, uncontended);
|
||||
return;
|
||||
}
|
||||
|
@ -2574,13 +2574,12 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
|
||||
final long sumCount() {
|
||||
CounterCell[] as = counterCells; CounterCell a;
|
||||
CounterCell[] cs = counterCells;
|
||||
long sum = baseCount;
|
||||
if (as != null) {
|
||||
for (int i = 0; i < as.length; ++i) {
|
||||
if ((a = as[i]) != null)
|
||||
sum += a.value;
|
||||
}
|
||||
if (cs != null) {
|
||||
for (CounterCell c : cs)
|
||||
if (c != null)
|
||||
sum += c.value;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
@ -2595,9 +2594,9 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
boolean collide = false; // True if last slot nonempty
|
||||
for (;;) {
|
||||
CounterCell[] as; CounterCell a; int n; long v;
|
||||
if ((as = counterCells) != null && (n = as.length) > 0) {
|
||||
if ((a = as[(n - 1) & h]) == null) {
|
||||
CounterCell[] cs; CounterCell c; int n; long v;
|
||||
if ((cs = counterCells) != null && (n = cs.length) > 0) {
|
||||
if ((c = cs[(n - 1) & h]) == null) {
|
||||
if (cellsBusy == 0) { // Try to attach new Cell
|
||||
CounterCell r = new CounterCell(x); // Optimistic create
|
||||
if (cellsBusy == 0 &&
|
||||
|
@ -2623,21 +2622,17 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
else if (!wasUncontended) // CAS already known to fail
|
||||
wasUncontended = true; // Continue after rehash
|
||||
else if (U.compareAndSetLong(a, CELLVALUE, v = a.value, v + x))
|
||||
else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
|
||||
break;
|
||||
else if (counterCells != as || n >= NCPU)
|
||||
else if (counterCells != cs || n >= NCPU)
|
||||
collide = false; // At max size or stale
|
||||
else if (!collide)
|
||||
collide = true;
|
||||
else if (cellsBusy == 0 &&
|
||||
U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
|
||||
try {
|
||||
if (counterCells == as) {// Expand table unless stale
|
||||
CounterCell[] rs = new CounterCell[n << 1];
|
||||
for (int i = 0; i < n; ++i)
|
||||
rs[i] = as[i];
|
||||
counterCells = rs;
|
||||
}
|
||||
if (counterCells == cs) // Expand table unless stale
|
||||
counterCells = Arrays.copyOf(cs, n << 1);
|
||||
} finally {
|
||||
cellsBusy = 0;
|
||||
}
|
||||
|
@ -2646,11 +2641,11 @@ public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
|
|||
}
|
||||
h = ThreadLocalRandom.advanceProbe(h);
|
||||
}
|
||||
else if (cellsBusy == 0 && counterCells == as &&
|
||||
else if (cellsBusy == 0 && counterCells == cs &&
|
||||
U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
|
||||
boolean init = false;
|
||||
try { // Initialize table
|
||||
if (counterCells == as) {
|
||||
if (counterCells == cs) {
|
||||
CounterCell[] rs = new CounterCell[2];
|
||||
rs[h & 1] = new CounterCell(x);
|
||||
counterCells = rs;
|
||||
|
|
|
@ -2204,9 +2204,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
|||
Collection<?> c = (Collection<?>) o;
|
||||
try {
|
||||
return containsAll(c) && c.containsAll(this);
|
||||
} catch (ClassCastException unused) {
|
||||
return false;
|
||||
} catch (NullPointerException unused) {
|
||||
} catch (ClassCastException | NullPointerException unused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2331,9 +2329,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
|||
Collection<?> c = (Collection<?>) o;
|
||||
try {
|
||||
return containsAll(c) && c.containsAll(this);
|
||||
} catch (ClassCastException unused) {
|
||||
return false;
|
||||
} catch (NullPointerException unused) {
|
||||
} catch (ClassCastException | NullPointerException unused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2453,9 +2449,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
|
|||
if (k == null) // pass by markers and headers
|
||||
return true;
|
||||
int c = cpr(cmp, k, hi);
|
||||
if (c > 0 || (c == 0 && !hiInclusive))
|
||||
return false;
|
||||
return true;
|
||||
return c < 0 || (c == 0 && hiInclusive);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -309,9 +309,7 @@ public class ConcurrentSkipListSet<E>
|
|||
Collection<?> c = (Collection<?>) o;
|
||||
try {
|
||||
return containsAll(c) && c.containsAll(this);
|
||||
} catch (ClassCastException unused) {
|
||||
return false;
|
||||
} catch (NullPointerException unused) {
|
||||
} catch (ClassCastException | NullPointerException unused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -508,7 +508,7 @@ public class CopyOnWriteArrayList<E>
|
|||
public boolean remove(Object o) {
|
||||
Object[] snapshot = getArray();
|
||||
int index = indexOf(o, snapshot, 0, snapshot.length);
|
||||
return (index < 0) ? false : remove(o, snapshot, index);
|
||||
return index >= 0 && remove(o, snapshot, index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -587,8 +587,8 @@ public class CopyOnWriteArrayList<E>
|
|||
*/
|
||||
public boolean addIfAbsent(E e) {
|
||||
Object[] snapshot = getArray();
|
||||
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
|
||||
addIfAbsent(e, snapshot);
|
||||
return indexOf(e, snapshot, 0, snapshot.length) < 0
|
||||
&& addIfAbsent(e, snapshot);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -980,13 +980,10 @@ public class CopyOnWriteArrayList<E>
|
|||
|
||||
List<?> list = (List<?>)o;
|
||||
Iterator<?> it = list.iterator();
|
||||
Object[] elements = getArray();
|
||||
for (int i = 0, len = elements.length; i < len; i++)
|
||||
if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
|
||||
for (Object element : getArray())
|
||||
if (!it.hasNext() || !Objects.equals(element, it.next()))
|
||||
return false;
|
||||
if (it.hasNext())
|
||||
return false;
|
||||
return true;
|
||||
return !it.hasNext();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1353,17 +1353,16 @@ public class LinkedBlockingDeque<E>
|
|||
@SuppressWarnings("unchecked")
|
||||
private boolean bulkRemove(Predicate<? super E> filter) {
|
||||
boolean removed = false;
|
||||
Node<E> p = null;
|
||||
final ReentrantLock lock = this.lock;
|
||||
Node<E> p = null;
|
||||
Node<E>[] nodes = null;
|
||||
int n, len = 0;
|
||||
do {
|
||||
// 1. Extract batch of up to 64 elements while holding the lock.
|
||||
long deathRow = 0; // "bitset" of size 64
|
||||
lock.lock();
|
||||
try {
|
||||
if (nodes == null) {
|
||||
if (p == null) p = first;
|
||||
if (nodes == null) { // first batch; initialize
|
||||
p = first;
|
||||
for (Node<E> q = p; q != null; q = succ(q))
|
||||
if (q.item != null && ++len == 64)
|
||||
break;
|
||||
|
@ -1376,6 +1375,7 @@ public class LinkedBlockingDeque<E>
|
|||
}
|
||||
|
||||
// 2. Run the filter on the elements while lock is free.
|
||||
long deathRow = 0L; // "bitset" of size 64
|
||||
for (int i = 0; i < n; i++) {
|
||||
final E e;
|
||||
if ((e = nodes[i].item) != null && filter.test(e))
|
||||
|
@ -1393,6 +1393,7 @@ public class LinkedBlockingDeque<E>
|
|||
unlink(q);
|
||||
removed = true;
|
||||
}
|
||||
nodes[i] = null; // help GC
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
|
|
@ -1060,11 +1060,10 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
|||
int n, len = 0;
|
||||
do {
|
||||
// 1. Extract batch of up to 64 elements while holding the lock.
|
||||
long deathRow = 0; // "bitset" of size 64
|
||||
fullyLock();
|
||||
try {
|
||||
if (nodes == null) {
|
||||
if (p == null) p = head.next;
|
||||
if (nodes == null) { // first batch; initialize
|
||||
p = head.next;
|
||||
for (Node<E> q = p; q != null; q = succ(q))
|
||||
if (q.item != null && ++len == 64)
|
||||
break;
|
||||
|
@ -1077,6 +1076,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
|||
}
|
||||
|
||||
// 2. Run the filter on the elements while lock is free.
|
||||
long deathRow = 0L; // "bitset" of size 64
|
||||
for (int i = 0; i < n; i++) {
|
||||
final E e;
|
||||
if ((e = nodes[i].item) != null && filter.test(e))
|
||||
|
@ -1095,6 +1095,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
|
|||
unlink(q, ancestor);
|
||||
removed = true;
|
||||
}
|
||||
nodes[i] = null; // help GC
|
||||
}
|
||||
} finally {
|
||||
fullyUnlock();
|
||||
|
|
|
@ -772,9 +772,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
|||
Node first = null;
|
||||
restartFromHead: for (;;) {
|
||||
Node h = head, p = h;
|
||||
for (; p != null;) {
|
||||
final Object item;
|
||||
if ((item = p.item) != null) {
|
||||
while (p != null) {
|
||||
if (p.item != null) {
|
||||
if (p.isData) {
|
||||
first = p;
|
||||
break;
|
||||
|
@ -1602,8 +1601,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
|
|||
// Read in elements until trailing null sentinel found
|
||||
Node h = null, t = null;
|
||||
for (Object item; (item = s.readObject()) != null; ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Node newNode = new Node((E) item);
|
||||
Node newNode = new Node(item);
|
||||
if (h == null)
|
||||
h = t = newNode;
|
||||
else
|
||||
|
|
|
@ -269,8 +269,8 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
|||
if (a.getClass() != Object[].class)
|
||||
a = Arrays.copyOf(a, n, Object[].class);
|
||||
if (screen && (n == 1 || this.comparator != null)) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
if (a[i] == null)
|
||||
for (Object elt : a)
|
||||
if (elt == null)
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.queue = a;
|
||||
|
|
|
@ -753,8 +753,10 @@ public class SubmissionPublisher<T> implements Publisher<T>,
|
|||
else
|
||||
pred.next = next;
|
||||
}
|
||||
else
|
||||
else {
|
||||
subs.add(b.subscriber);
|
||||
pred = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
return subs;
|
||||
|
|
|
@ -67,7 +67,7 @@ import jdk.internal.misc.VM;
|
|||
* {@code ThreadLocalRandom.current().nextX(...)} (where
|
||||
* {@code X} is {@code Int}, {@code Long}, etc).
|
||||
* When all usages are of this form, it is never possible to
|
||||
* accidently share a {@code ThreadLocalRandom} across multiple threads.
|
||||
* accidentally share a {@code ThreadLocalRandom} across multiple threads.
|
||||
*
|
||||
* <p>This class also provides additional commonly used bounded random
|
||||
* generation methods.
|
||||
|
|
|
@ -264,13 +264,12 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
* assist in storage reclamation when large numbers of queued tasks
|
||||
* become cancelled.</dd>
|
||||
*
|
||||
* <dt>Finalization</dt>
|
||||
* <dt>Reclamation</dt>
|
||||
*
|
||||
* <dd>A pool that is no longer referenced in a program <em>AND</em>
|
||||
* has no remaining threads will be {@code shutdown} automatically. If
|
||||
* you would like to ensure that unreferenced pools are reclaimed even
|
||||
* if users forget to call {@link #shutdown}, then you must arrange
|
||||
* that unused threads eventually die, by setting appropriate
|
||||
* has no remaining threads may be reclaimed (garbage collected)
|
||||
* without being explicity shutdown. You can configure a pool to allow
|
||||
* all unused threads to eventually die by setting appropriate
|
||||
* keep-alive times, using a lower bound of zero core threads and/or
|
||||
* setting {@link #allowCoreThreadTimeOut(boolean)}. </dd>
|
||||
*
|
||||
|
@ -361,7 +360,7 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
|||
* time, but need not hit each state. The transitions are:
|
||||
*
|
||||
* RUNNING -> SHUTDOWN
|
||||
* On invocation of shutdown(), perhaps implicitly in finalize()
|
||||
* On invocation of shutdown()
|
||||
* (RUNNING or SHUTDOWN) -> STOP
|
||||
* On invocation of shutdownNow()
|
||||
* SHUTDOWN -> TIDYING
|
||||
|
@ -581,9 +580,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
|||
private static final RuntimePermission shutdownPerm =
|
||||
new RuntimePermission("modifyThread");
|
||||
|
||||
/** The context to be used when executing the finalizer, or null. */
|
||||
private final AccessControlContext acc;
|
||||
|
||||
/**
|
||||
* Class Worker mainly maintains interrupt control state for
|
||||
* threads running tasks, along with other minor bookkeeping.
|
||||
|
@ -1300,9 +1296,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
|||
throw new IllegalArgumentException();
|
||||
if (workQueue == null || threadFactory == null || handler == null)
|
||||
throw new NullPointerException();
|
||||
this.acc = (System.getSecurityManager() == null)
|
||||
? null
|
||||
: AccessController.getContext();
|
||||
this.corePoolSize = corePoolSize;
|
||||
this.maximumPoolSize = maximumPoolSize;
|
||||
this.workQueue = workQueue;
|
||||
|
@ -1469,33 +1462,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@code shutdown} when this executor is no longer
|
||||
* referenced and it has no threads.
|
||||
*
|
||||
* <p>This method is invoked with privileges that are restricted by
|
||||
* the security context of the caller that invokes the constructor.
|
||||
*
|
||||
* @deprecated The {@code finalize} method has been deprecated.
|
||||
* Subclasses that override {@code finalize} in order to perform cleanup
|
||||
* should be modified to use alternative cleanup mechanisms and
|
||||
* to remove the overriding {@code finalize} method.
|
||||
* When overriding the {@code finalize} method, its implementation must explicitly
|
||||
* ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
|
||||
* See the specification for {@link Object#finalize()} for further
|
||||
* information about migration options.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
protected void finalize() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm == null || acc == null) {
|
||||
shutdown();
|
||||
} else {
|
||||
PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
|
||||
AccessController.doPrivileged(pa, acc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread factory used to create new threads.
|
||||
*
|
||||
|
|
|
@ -320,7 +320,9 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||
|
||||
// predNext is the apparent node to unsplice. CASes below will
|
||||
// fail if not, in which case, we lost race vs another cancel
|
||||
// or signal, so no further action is necessary.
|
||||
// or signal, so no further action is necessary, although with
|
||||
// a possibility that a cancelled node may transiently remain
|
||||
// reachable.
|
||||
Node predNext = pred.next;
|
||||
|
||||
// Can use unconditional write instead of CAS here.
|
||||
|
@ -912,13 +914,13 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||
* at any time, a {@code true} return does not guarantee that any
|
||||
* other thread will ever acquire.
|
||||
*
|
||||
* <p>In this implementation, this operation returns in
|
||||
* constant time.
|
||||
*
|
||||
* @return {@code true} if there may be other threads waiting to acquire
|
||||
*/
|
||||
public final boolean hasQueuedThreads() {
|
||||
return head != tail;
|
||||
for (Node p = tail, h = head; p != h && p != null; p = p.prev)
|
||||
if (p.waitStatus <= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1067,17 +1069,21 @@ public abstract class AbstractQueuedLongSynchronizer
|
|||
* @since 1.7
|
||||
*/
|
||||
public final boolean hasQueuedPredecessors() {
|
||||
// The correctness of this depends on head being initialized
|
||||
// before tail and on head.next being accurate if the current
|
||||
// thread is first in queue.
|
||||
Node t = tail; // Read fields in reverse initialization order
|
||||
Node h = head;
|
||||
Node s;
|
||||
return h != t &&
|
||||
((s = h.next) == null || s.thread != Thread.currentThread());
|
||||
Node h, s;
|
||||
if ((h = head) != null) {
|
||||
if ((s = h.next) == null || s.waitStatus > 0) {
|
||||
s = null; // traverse in case of concurrent cancellation
|
||||
for (Node p = tail; p != h && p != null; p = p.prev) {
|
||||
if (p.waitStatus <= 0)
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
if (s != null && s.thread != Thread.currentThread())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Instrumentation and monitoring methods
|
||||
|
||||
/**
|
||||
|
|
|
@ -800,7 +800,9 @@ public abstract class AbstractQueuedSynchronizer
|
|||
|
||||
// predNext is the apparent node to unsplice. CASes below will
|
||||
// fail if not, in which case, we lost race vs another cancel
|
||||
// or signal, so no further action is necessary.
|
||||
// or signal, so no further action is necessary, although with
|
||||
// a possibility that a cancelled node may transiently remain
|
||||
// reachable.
|
||||
Node predNext = pred.next;
|
||||
|
||||
// Can use unconditional write instead of CAS here.
|
||||
|
@ -1392,13 +1394,13 @@ public abstract class AbstractQueuedSynchronizer
|
|||
* at any time, a {@code true} return does not guarantee that any
|
||||
* other thread will ever acquire.
|
||||
*
|
||||
* <p>In this implementation, this operation returns in
|
||||
* constant time.
|
||||
*
|
||||
* @return {@code true} if there may be other threads waiting to acquire
|
||||
*/
|
||||
public final boolean hasQueuedThreads() {
|
||||
return head != tail;
|
||||
for (Node p = tail, h = head; p != h && p != null; p = p.prev)
|
||||
if (p.waitStatus <= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1547,17 +1549,21 @@ public abstract class AbstractQueuedSynchronizer
|
|||
* @since 1.7
|
||||
*/
|
||||
public final boolean hasQueuedPredecessors() {
|
||||
// The correctness of this depends on head being initialized
|
||||
// before tail and on head.next being accurate if the current
|
||||
// thread is first in queue.
|
||||
Node t = tail; // Read fields in reverse initialization order
|
||||
Node h = head;
|
||||
Node s;
|
||||
return h != t &&
|
||||
((s = h.next) == null || s.thread != Thread.currentThread());
|
||||
Node h, s;
|
||||
if ((h = head) != null) {
|
||||
if ((s = h.next) == null || s.waitStatus > 0) {
|
||||
s = null; // traverse in case of concurrent cancellation
|
||||
for (Node p = tail; p != h && p != null; p = p.prev) {
|
||||
if (p.waitStatus <= 0)
|
||||
s = p;
|
||||
}
|
||||
}
|
||||
if (s != null && s.thread != Thread.currentThread())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Instrumentation and monitoring methods
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2018, 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
|
||||
|
@ -953,6 +953,12 @@ public final class Pattern
|
|||
*/
|
||||
private int flags;
|
||||
|
||||
/**
|
||||
* The temporary pattern flags used during compiling. The flags might be turn
|
||||
* on and off by embedded flag.
|
||||
*/
|
||||
private transient int flags0;
|
||||
|
||||
/**
|
||||
* Boolean indicating this Pattern is compiled; this is necessary in order
|
||||
* to lazily compile deserialized Patterns.
|
||||
|
@ -1137,7 +1143,7 @@ public final class Pattern
|
|||
* @return The match flags specified when this pattern was compiled
|
||||
*/
|
||||
public int flags() {
|
||||
return flags;
|
||||
return flags0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1369,6 +1375,9 @@ public final class Pattern
|
|||
// Read in all fields
|
||||
s.defaultReadObject();
|
||||
|
||||
// reset the flags
|
||||
flags0 = flags;
|
||||
|
||||
// Initialize counts
|
||||
capturingGroupCount = 1;
|
||||
localCount = 0;
|
||||
|
@ -1400,6 +1409,9 @@ public final class Pattern
|
|||
if ((flags & UNICODE_CHARACTER_CLASS) != 0)
|
||||
flags |= UNICODE_CASE;
|
||||
|
||||
// 'flags' for compiling
|
||||
flags0 = flags;
|
||||
|
||||
// Reset group index count
|
||||
capturingGroupCount = 1;
|
||||
localCount = 0;
|
||||
|
@ -1841,7 +1853,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
* Indicates whether a particular flag is set or not.
|
||||
*/
|
||||
private boolean has(int f) {
|
||||
return (flags & f) != 0;
|
||||
return (flags0 & f) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2718,7 +2730,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
ch == 0x53 || ch == 0x73 || //S and s
|
||||
ch == 0x4b || ch == 0x6b || //K and k
|
||||
ch == 0xc5 || ch == 0xe5))) { //A+ring
|
||||
bits.add(ch, flags());
|
||||
bits.add(ch, flags0);
|
||||
return null;
|
||||
}
|
||||
return single(ch);
|
||||
|
@ -2931,7 +2943,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
boolean capturingGroup = false;
|
||||
Node head = null;
|
||||
Node tail = null;
|
||||
int save = flags;
|
||||
int save = flags0;
|
||||
int saveTCNCount = topClosureNodes.size();
|
||||
root = null;
|
||||
int ch = next();
|
||||
|
@ -3032,7 +3044,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
}
|
||||
|
||||
accept(')', "Unclosed group");
|
||||
flags = save;
|
||||
flags0 = save;
|
||||
|
||||
// Check for quantifiers
|
||||
Node node = closure(head);
|
||||
|
@ -3135,28 +3147,28 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
for (;;) {
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
flags |= CASE_INSENSITIVE;
|
||||
flags0 |= CASE_INSENSITIVE;
|
||||
break;
|
||||
case 'm':
|
||||
flags |= MULTILINE;
|
||||
flags0 |= MULTILINE;
|
||||
break;
|
||||
case 's':
|
||||
flags |= DOTALL;
|
||||
flags0 |= DOTALL;
|
||||
break;
|
||||
case 'd':
|
||||
flags |= UNIX_LINES;
|
||||
flags0 |= UNIX_LINES;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= UNICODE_CASE;
|
||||
flags0 |= UNICODE_CASE;
|
||||
break;
|
||||
case 'c':
|
||||
flags |= CANON_EQ;
|
||||
flags0 |= CANON_EQ;
|
||||
break;
|
||||
case 'x':
|
||||
flags |= COMMENTS;
|
||||
flags0 |= COMMENTS;
|
||||
break;
|
||||
case 'U':
|
||||
flags |= (UNICODE_CHARACTER_CLASS | UNICODE_CASE);
|
||||
flags0 |= (UNICODE_CHARACTER_CLASS | UNICODE_CASE);
|
||||
break;
|
||||
case '-': // subFlag then fall through
|
||||
ch = next();
|
||||
|
@ -3178,28 +3190,28 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||
for (;;) {
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
flags &= ~CASE_INSENSITIVE;
|
||||
flags0 &= ~CASE_INSENSITIVE;
|
||||
break;
|
||||
case 'm':
|
||||
flags &= ~MULTILINE;
|
||||
flags0 &= ~MULTILINE;
|
||||
break;
|
||||
case 's':
|
||||
flags &= ~DOTALL;
|
||||
flags0 &= ~DOTALL;
|
||||
break;
|
||||
case 'd':
|
||||
flags &= ~UNIX_LINES;
|
||||
flags0 &= ~UNIX_LINES;
|
||||
break;
|
||||
case 'u':
|
||||
flags &= ~UNICODE_CASE;
|
||||
flags0 &= ~UNICODE_CASE;
|
||||
break;
|
||||
case 'c':
|
||||
flags &= ~CANON_EQ;
|
||||
flags0 &= ~CANON_EQ;
|
||||
break;
|
||||
case 'x':
|
||||
flags &= ~COMMENTS;
|
||||
flags0 &= ~COMMENTS;
|
||||
break;
|
||||
case 'U':
|
||||
flags &= ~(UNICODE_CHARACTER_CLASS | UNICODE_CASE);
|
||||
flags0 &= ~(UNICODE_CHARACTER_CLASS | UNICODE_CASE);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue