[11] RFR : java.nio.Buffer attachments
David Lloyd
david.lloyd at redhat.com
Fri Mar 2 15:58:19 UTC 2018
One of the major classic difficulties with NIO programming (and
therefore, usage of NIO-based frameworks) is the management of
buffers. This commonly applies specifically to (but is definitely not
limited to) handling of direct ByteBuffers. One of the primary
difficulties relates to the topic of buffer allocation, pooling, and
reuse.
I contend that a well-behaved buffer pool necessarily has the
following characteristics:
• An explicit `free` operation (i.e. not normally relying on GC to come around)
• Some mechanism to help prevent double-free
• Some mechanism to help prevent other pollution of the pool (i.e.
pooling buffers that do not belong to the pool)
• Graceful handling of duplicates, slices, and other types of views
In addition, the following characteristics also may be desirable:
• Allocation of fewer, larger buffer regions backing the pooled
buffers which may be slices of these regions, maybe even to multiple
hierarchical levels
• Some mechanism to signify that the status of a given pooled buffer
can no longer be determined (i.e. fall back to using a GC-based
mechanism to release the buffer)
• Employment of some reasonable amount of fail-safe against usage of
buffers which have been freed, within practical limits
Existing buffer pools may rely on wrapper objects, which tend to be
difficult to use with scatter/gather and add a level of indirection to
common I/O code paths, or (to avoid wrapper objects) they may rely on
heuristic information acquired from the Buffer API (such as capacity,
isDirect, isReadOnly, etc.) to make a guess as to whether the buffer
belongs to the pool, which also comes with several critical
disadvantages. A Buffer attachment API would solve these problems far
more gracefully.
The Buffer attachment API would have to meet the following requirements:
• The attachment must be acquirable for usage by pools and other buffer managers
• Attachments should be protected from interference by buffer users
and other attachment implementations
• No performance degradation to standard I/O and manipulation operations
• Minimal memory overhead in the existing case where no attachment is present
I've attached a patch which adds a buffer API that meets these
requirements. The following implementation points are notable:
• One extra final field is added to java.nio.Buffer to hold the
optional attachment
• The BufferAttachment API is "locked down" allowing only the
implementation of the attachment to create buffers with that
attachment, preventing attachments from being copied to other buffers
by misbehaving code
• While anyone can acquire the BufferAttachment object for a given
Buffer, all of the members of that class are protected, preventing
interference
• Attachments have an opportunity to handle duplicate/slice and view
creation by returning null, returning a copy of the attachment, or
returning the same attachment instance, depending on the desired
behavior
• Only creating ByteBuffers (direct and heap) and wrapping byte arrays
are presently supported; other buffer types can be created as views of
the ByteBuffer, or support can be added (now or at a later time) for
creating them directly
• In particular, the patch does not implement a way to add an
attachment to buffers created via FileChannel mapping or via JNI, or
other such "back-channel" approaches; these features may potentially
be added at a later time
Using this attachment API, it is possible to create buffer pool
implementations with a variety of different behaviors, many of which
meet the above requirements without the drawbacks of wrapper objects.
It may also open the door for JDK-managed smart buffer pools in the
future.
Please review and give feedback at your convenience. Thanks!
--
- DML
-------------- next part --------------
commit 666750c152c3c1e870b5ab591787c7918d9504fe
Author: David M. Lloyd <david.lloyd at redhat.com>
Date: Thu Mar 1 10:39:27 2018 -0600
[JDK-xxxxx] Introduce generic buffer attachments
diff --git a/src/java.base/share/classes/java/nio/Bits.java b/src/java.base/share/classes/java/nio/Bits.java
index fff84e9e58d..0f8c165d0e1 100644
--- a/src/java.base/share/classes/java/nio/Bits.java
+++ b/src/java.base/share/classes/java/nio/Bits.java
@@ -248,7 +248,7 @@ class Bits { // package-private
}
@Override
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
- return new DirectByteBuffer(addr, cap, ob);
+ return new DirectByteBuffer(addr, cap, ob, null);
}
@Override
public void truncate(Buffer buf) {
diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java
index 1217ca78a74..ed388f4a685 100644
--- a/src/java.base/share/classes/java/nio/Buffer.java
+++ b/src/java.base/share/classes/java/nio/Buffer.java
@@ -210,10 +210,12 @@ public abstract class Buffer {
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
+ final BufferAttachment attachment;
+
// Creates a new buffer with the given mark, position, limit, and capacity,
// after checking invariants.
//
- Buffer(int mark, int pos, int lim, int cap) { // package-private
+ Buffer(int mark, int pos, int lim, int cap, BufferAttachment att) { // package-private
if (cap < 0)
throw createCapacityException(cap);
this.capacity = cap;
@@ -225,6 +227,7 @@ public abstract class Buffer {
+ mark + " > " + pos + ")");
this.mark = mark;
}
+ this.attachment = att;
}
/**
@@ -616,6 +619,19 @@ public abstract class Buffer {
*/
public abstract Buffer duplicate();
+ /**
+ * Get the attachment of this buffer, if any.
+ *
+ * @return the attachment
+ */
+ public final BufferAttachment getAttachment() {
+ return attachment;
+ }
+
+ final BufferAttachment splitAtt(int off, int len, boolean ro, Class<? extends Buffer> c) {
+ final BufferAttachment attachment = this.attachment;
+ return attachment == null ? null : attachment.duplicate(this, off, len, ro, c);
+ }
// -- Package-private methods for bounds checking, etc. --
diff --git a/src/java.base/share/classes/java/nio/BufferAttachment.java b/src/java.base/share/classes/java/nio/BufferAttachment.java
new file mode 100644
index 00000000000..a666583a3a2
--- /dev/null
+++ b/src/java.base/share/classes/java/nio/BufferAttachment.java
@@ -0,0 +1,106 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2018 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.nio;
+
+/**
+ * An attachment to a buffer. Buffer attachments are strongly referenced by the
+ * buffers they are attached to, but are not otherwise referenced.
+ * <p>
+ * A buffer attachment has an opportunity to replicate itself when a buffer is
+ * duplicated or sliced or otherwise copied. The circumstances of the copy are
+ * given to the {@link #duplicate(Buffer, int, int, boolean, Class) duplicate()}
+ * method.
+ *
+ * @since 11
+ */
+public abstract class BufferAttachment {
+ /**
+ * Construct a new instance.
+ */
+ protected BufferAttachment() {
+ }
+
+ /**
+ * Duplicate the attachment for a duplicate buffer. If this method returns
+ * {@code null}, the duplicate will have no attachment. The duplicate
+ * buffer may have a different type than the original.
+ * <p>
+ * If this method throws a run-time exception, the exception will propagate
+ * to the caller and the buffer will not be duplicated.
+ *
+ * @param original the original buffer object
+ * @param offset the offset of the duplicate, in the range
+ * {@code 0 <= n <= original.capacity()}
+ * @param length the length of the duplicate, in the range
+ * {@code 0 <= n <= original.capacity() - offset}
+ * @param readOnly {@code true} if the returned buffer is read-only,
+ * {@code false} otherwise
+ * @param duplicateClazz the type of buffer being returned
+ * @return the (possibly {@code null}) buffer attachment object
+ */
+ protected BufferAttachment duplicate(Buffer original, int offset, int length,
+ boolean readOnly, Class<? extends Buffer> duplicateClazz)
+ {
+ return this;
+ }
+
+ /**
+ * Allocate a heap-backed byte buffer in the same manner as {@link ByteBuffer#allocate(int)},
+ * with this object instance as its attachment.
+ *
+ * @param capacity the byte buffer capacity
+ * @return the allocated byte buffer
+ * @see ByteBuffer#allocate(int)
+ */
+ protected final ByteBuffer allocateByteBuffer(int capacity) {
+ if (capacity < 0)
+ throw Buffer.createCapacityException(capacity);
+ return new HeapByteBuffer(capacity, capacity, this);
+ }
+
+ /**
+ * Allocate a direct byte buffer in the same manner as {@link ByteBuffer#allocateDirect(int)},
+ * with this object instance as its attachment.
+ *
+ * @param capacity the byte buffer capacity
+ * @return the allocated byte buffer
+ * @see ByteBuffer#allocateDirect(int)
+ */
+ protected final ByteBuffer allocateDirectByteBuffer(int capacity) {
+ return new DirectByteBuffer(capacity, this);
+ }
+
+ /**
+ * Wrap an array into a byte buffer in the same manner as {@link ByteBuffer#wrap(byte[], int, int)},
+ * with this object instance as its attachment.
+ *
+ * @param bytes the byte array
+ * @param off the offset into the array
+ * @param len the number of bytes to include
+ * @return the wrapped byte buffer
+ * @see ByteBuffer#wrap(byte[], int, int)
+ */
+ protected final ByteBuffer wrap(byte[] bytes, int off, int len) {
+ try {
+ return new HeapByteBuffer(bytes, off, len, this);
+ } catch (IllegalArgumentException x) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+}
diff --git a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
index b390448b110..418046c335b 100644
--- a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
@@ -40,11 +40,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#end[rw]
- ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb) { // package-private
+ ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, BufferAttachment att) { // package-private
#if[rw]
super(-1, 0,
bb.remaining() >> $LG_BYTES_PER_VALUE$,
- bb.remaining() >> $LG_BYTES_PER_VALUE$);
+ bb.remaining() >> $LG_BYTES_PER_VALUE$,
+ att);
this.bb = bb;
// enforce limit == capacity
int cap = this.capacity();
@@ -53,21 +54,21 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
assert (pos <= cap);
address = bb.address;
#else[rw]
- super(bb);
+ super(bb, att);
#end[rw]
}
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb,
int mark, int pos, int lim, int cap,
- long addr)
+ long addr, BufferAttachment att)
{
#if[rw]
- super(mark, pos, lim, cap);
+ super(mark, pos, lim, cap, att);
this.bb = bb;
address = addr;
assert address >= bb.address;
#else[rw]
- super(bb, mark, pos, lim, cap, addr);
+ super(bb, mark, pos, lim, cap, addr, att);
#end[rw]
}
@@ -82,26 +83,43 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
long addr = byteOffset(pos);
- return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr);
+ BufferAttachment att = splitAtt(pos, rem,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
+ return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr, att);
}
public $Type$Buffer duplicate() {
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new ByteBufferAs$Type$Buffer$RW$$BO$(bb,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- address);
+ address,
+ att);
}
public $Type$Buffer asReadOnlyBuffer() {
#if[rw]
+ BufferAttachment att = splitAtt(0, this.capacity(), true, $Type$Buffer.class);
return new ByteBufferAs$Type$BufferR$BO$(bb,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- address);
+ address,
+ att);
#else[rw]
return duplicate();
#end[rw]
@@ -223,12 +241,20 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
if ((start < 0) || (end > len) || (start > end))
throw new IndexOutOfBoundsException();
+ BufferAttachment att = splitAtt(pos, len,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new ByteBufferAsCharBuffer$RW$$BO$(bb,
-1,
pos + start,
pos + end,
capacity(),
- address);
+ address,
+ att);
}
#end[char]
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
index cacadb101df..eb767b11a7d 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
@@ -88,13 +88,27 @@ class XXX {
0,
size,
size,
- address + off))
+ address + off,
+ splitAtt(0, size,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class)))
: ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this,
-1,
0,
size,
size,
- address + off)));
+ address + off,
+ splitAtt(0, size,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class))));
} else {
return (nativeByteOrder
? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this,
@@ -102,13 +116,27 @@ class XXX {
0,
size,
size,
- off))
+ off,
+ splitAtt(0, size,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class)))
: ($Type$Buffer)(new Direct$Type$Buffer$RW$S(this,
-1,
0,
size,
size,
- off)));
+ off,
+ splitAtt(0, size,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class))));
}
}
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
index 5fa9be47b20..9a0e7d68b51 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
@@ -108,9 +108,9 @@ class Direct$Type$Buffer$RW$$BO$
// Primary constructor
//
- Direct$Type$Buffer$RW$(int cap) { // package-private
+ Direct$Type$Buffer$RW$(int cap, BufferAttachment ba) { // package-private
#if[rw]
- super(-1, 0, cap, cap);
+ super(-1, 0, cap, cap, ba);
boolean pa = VM.isDirectMemoryPageAligned();
int ps = Bits.pageSize();
long size = Math.max(1L, (long)cap + (pa ? ps : 0));
@@ -133,7 +133,7 @@ class Direct$Type$Buffer$RW$$BO$
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
#else[rw]
- super(cap);
+ super(cap, ba);
this.isReadOnly = true;
#end[rw]
}
@@ -143,8 +143,8 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked to construct a direct ByteBuffer referring to the block of
// memory. A given arbitrary object may also be attached to the buffer.
//
- Direct$Type$Buffer(long addr, int cap, Object ob) {
- super(-1, 0, cap, cap);
+ Direct$Type$Buffer(long addr, int cap, Object ob, BufferAttachment ba) {
+ super(-1, 0, cap, cap, ba);
address = addr;
cleaner = null;
att = ob;
@@ -154,7 +154,7 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked only by JNI: NewDirectByteBuffer(void*, long)
//
private Direct$Type$Buffer(long addr, int cap) {
- super(-1, 0, cap, cap);
+ super(-1, 0, cap, cap, null);
address = addr;
cleaner = null;
att = null;
@@ -169,7 +169,7 @@ class Direct$Type$Buffer$RW$$BO$
Runnable unmapper)
{
#if[rw]
- super(-1, 0, cap, cap, fd);
+ super(-1, 0, cap, cap, fd, null);
address = addr;
cleaner = Cleaner.create(this, unmapper);
att = null;
@@ -185,17 +185,17 @@ class Direct$Type$Buffer$RW$$BO$
//
Direct$Type$Buffer$RW$$BO$(DirectBuffer db, // package-private
int mark, int pos, int lim, int cap,
- int off)
+ int off, BufferAttachment ba)
{
#if[rw]
- super(mark, pos, lim, cap);
+ super(mark, pos, lim, cap, ba);
address = db.address() + off;
#if[byte]
cleaner = null;
#end[byte]
att = db;
#else[rw]
- super(db, mark, pos, lim, cap, off);
+ super(db, mark, pos, lim, cap, off, ba);
this.isReadOnly = true;
#end[rw]
}
@@ -212,7 +212,14 @@ class Direct$Type$Buffer$RW$$BO$
int rem = (pos <= lim ? lim - pos : 0);
int off = (pos << $LG_BYTES_PER_VALUE$);
assert (off >= 0);
- return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
+ BufferAttachment att = splitAtt(pos, rem,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
+ return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off, att);
}
#if[byte]
@@ -220,27 +227,44 @@ class Direct$Type$Buffer$RW$$BO$
assert (pos >= 0);
assert (pos <= lim);
int rem = lim - pos;
- return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, pos);
+ BufferAttachment att = splitAtt(pos, rem,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
+ return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, pos, att);
}
#end[byte]
public $Type$Buffer duplicate() {
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new Direct$Type$Buffer$RW$$BO$(this,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- 0);
+ 0,
+ att);
}
public $Type$Buffer asReadOnlyBuffer() {
#if[rw]
+ BufferAttachment att = splitAtt(0, this.capacity(), true, $Type$Buffer.class);
return new Direct$Type$BufferR$BO$(this,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- 0);
+ 0,
+ att);
#else[rw]
return duplicate();
#end[rw]
@@ -462,12 +486,20 @@ class Direct$Type$Buffer$RW$$BO$
if ((start < 0) || (end > len) || (start > end))
throw new IndexOutOfBoundsException();
+ BufferAttachment att = splitAtt(pos, len,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ CharBuffer.class);
return new DirectCharBuffer$RW$$BO$(this,
-1,
pos + start,
pos + end,
capacity(),
- offset);
+ offset,
+ att);
}
#end[char]
diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
index 7f2a2597ba3..c702e5dc551 100644
--- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
@@ -56,91 +56,121 @@ class Heap$Type$Buffer$RW$
#end[rw]
*/
- Heap$Type$Buffer$RW$(int cap, int lim) { // package-private
+ Heap$Type$Buffer$RW$(int cap, int lim, BufferAttachment att) { // package-private
#if[rw]
- super(-1, 0, lim, cap, new $type$[cap], 0);
+ super(-1, 0, lim, cap, new $type$[cap], 0, att);
/*
hb = new $type$[cap];
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
- super(cap, lim);
+ super(cap, lim, att);
this.isReadOnly = true;
#end[rw]
}
- Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private
+ Heap$Type$Buffer$RW$($type$[] buf, int off, int len, BufferAttachment att) { // package-private
#if[rw]
- super(-1, off, off + len, buf.length, buf, 0);
+ super(-1, off, off + len, buf.length, buf, 0, att);
/*
hb = buf;
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
- super(buf, off, len);
+ super(buf, off, len, att);
this.isReadOnly = true;
#end[rw]
}
protected Heap$Type$Buffer$RW$($type$[] buf,
int mark, int pos, int lim, int cap,
- int off)
+ int off, BufferAttachment att)
{
#if[rw]
- super(mark, pos, lim, cap, buf, off);
+ super(mark, pos, lim, cap, buf, off, att);
/*
hb = buf;
offset = off;
*/
this.address = ARRAY_BASE_OFFSET + off * ARRAY_INDEX_SCALE;
#else[rw]
- super(buf, mark, pos, lim, cap, off);
+ super(buf, mark, pos, lim, cap, off, att);
this.isReadOnly = true;
#end[rw]
}
public $Type$Buffer slice() {
+ int pos = this.position();
+ int lim = this.limit();
+ assert (pos <= lim);
+ int rem = (pos <= lim ? lim - pos : 0);
+ BufferAttachment att = splitAtt(pos, rem,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new Heap$Type$Buffer$RW$(hb,
-1,
0,
- this.remaining(),
- this.remaining(),
- this.position() + offset);
+ rem,
+ rem,
+ pos + offset,
+ att);
}
#if[byte]
$Type$Buffer slice(int pos, int lim) {
assert (pos >= 0);
assert (pos <= lim);
- int rem = lim - pos;
+ int rem = (pos <= lim ? lim - pos : 0);
+ BufferAttachment att = splitAtt(pos, rem,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new Heap$Type$Buffer$RW$(hb,
-1,
0,
rem,
rem,
- pos + offset);
+ pos + offset,
+ att);
}
#end[byte]
public $Type$Buffer duplicate() {
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ $Type$Buffer.class);
return new Heap$Type$Buffer$RW$(hb,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- offset);
+ offset,
+ att);
}
public $Type$Buffer asReadOnlyBuffer() {
#if[rw]
+ BufferAttachment att = splitAtt(0, this.capacity(), true, $Type$Buffer.class);
return new Heap$Type$BufferR(hb,
this.markValue(),
this.position(),
this.limit(),
this.capacity(),
- offset);
+ offset,
+ att);
#else[rw]
return duplicate();
#end[rw]
@@ -313,19 +343,28 @@ class Heap$Type$Buffer$RW$
public CharBuffer asCharBuffer() {
int size = this.remaining() >> 1;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ CharBuffer.class);
return (bigEndian
? (CharBuffer)(new ByteBufferAsCharBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -364,19 +403,28 @@ class Heap$Type$Buffer$RW$
public ShortBuffer asShortBuffer() {
int size = this.remaining() >> 1;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ ShortBuffer.class);
return (bigEndian
? (ShortBuffer)(new ByteBufferAsShortBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -415,19 +463,28 @@ class Heap$Type$Buffer$RW$
public IntBuffer asIntBuffer() {
int size = this.remaining() >> 2;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ IntBuffer.class);
return (bigEndian
? (IntBuffer)(new ByteBufferAsIntBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -466,19 +523,28 @@ class Heap$Type$Buffer$RW$
public LongBuffer asLongBuffer() {
int size = this.remaining() >> 3;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ LongBuffer.class);
return (bigEndian
? (LongBuffer)(new ByteBufferAsLongBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -521,19 +587,28 @@ class Heap$Type$Buffer$RW$
public FloatBuffer asFloatBuffer() {
int size = this.remaining() >> 2;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ FloatBuffer.class);
return (bigEndian
? (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -576,19 +651,28 @@ class Heap$Type$Buffer$RW$
public DoubleBuffer asDoubleBuffer() {
int size = this.remaining() >> 3;
long addr = address + position();
+ BufferAttachment att = splitAtt(0, this.capacity(),
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ DoubleBuffer.class);
return (bigEndian
? (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$B(this,
-1,
0,
size,
size,
- addr))
+ addr,
+ att))
: (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this,
-1,
0,
size,
size,
- addr)));
+ addr,
+ att)));
}
@@ -614,12 +698,20 @@ class Heap$Type$Buffer$RW$
|| (start > end))
throw new IndexOutOfBoundsException();
int pos = position();
+ BufferAttachment att = splitAtt(pos, end - start,
+#if[rw]
+ false,
+#else[rw]
+ true,
+#end[rw]
+ CharBuffer.class);
return new HeapCharBuffer$RW$(hb,
-1,
pos + start,
pos + end,
capacity(),
- offset);
+ offset,
+ att);
}
#end[char]
diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
index 2f84cbf4549..6cd028babe0 100644
--- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java
+++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
@@ -79,14 +79,14 @@ public abstract class MappedByteBuffer
// This should only be invoked by the DirectByteBuffer constructors
//
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
- FileDescriptor fd)
+ FileDescriptor fd, BufferAttachment ba)
{
- super(mark, pos, lim, cap);
+ super(mark, pos, lim, cap, ba);
this.fd = fd;
}
- MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
- super(mark, pos, lim, cap);
+ MappedByteBuffer(int mark, int pos, int lim, int cap, BufferAttachment ba) { // package-private
+ super(mark, pos, lim, cap, ba);
this.fd = null;
}
diff --git a/src/java.base/share/classes/java/nio/StringCharBuffer.java b/src/java.base/share/classes/java/nio/StringCharBuffer.java
index 26b355bc819..caaa6d78c95 100644
--- a/src/java.base/share/classes/java/nio/StringCharBuffer.java
+++ b/src/java.base/share/classes/java/nio/StringCharBuffer.java
@@ -34,7 +34,7 @@ class StringCharBuffer // package-private
CharSequence str;
StringCharBuffer(CharSequence s, int start, int end) { // package-private
- super(-1, start, end, s.length());
+ super(-1, start, end, s.length(), null);
int n = s.length();
if ((start < 0) || (start > n) || (end < start) || (end > n))
throw new IndexOutOfBoundsException();
@@ -57,7 +57,7 @@ class StringCharBuffer // package-private
int limit,
int cap,
int offset) {
- super(mark, pos, limit, cap, null, offset);
+ super(mark, pos, limit, cap, null, offset, null);
str = s;
this.isReadOnly = true;
}
diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template
index 96e05d6a663..41e13d0c000 100644
--- a/src/java.base/share/classes/java/nio/X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template
@@ -276,17 +276,17 @@ public abstract class $Type$Buffer
// backing array, and array offset
//
$Type$Buffer(int mark, int pos, int lim, int cap, // package-private
- $type$[] hb, int offset)
+ $type$[] hb, int offset, BufferAttachment ba)
{
- super(mark, pos, lim, cap);
+ super(mark, pos, lim, cap, ba);
this.hb = hb;
this.offset = offset;
}
// Creates a new buffer with the given mark, position, limit, and capacity
//
- $Type$Buffer(int mark, int pos, int lim, int cap) { // package-private
- this(mark, pos, lim, cap, null, 0);
+ $Type$Buffer(int mark, int pos, int lim, int cap, BufferAttachment ba) { // package-private
+ this(mark, pos, lim, cap, null, 0, ba);
}
@Override
@@ -314,7 +314,7 @@ public abstract class $Type$Buffer
* If the {@code capacity} is a negative integer
*/
public static $Type$Buffer allocateDirect(int capacity) {
- return new Direct$Type$Buffer(capacity);
+ return new Direct$Type$Buffer(capacity, null);
}
#end[byte]
@@ -345,7 +345,7 @@ public abstract class $Type$Buffer
public static $Type$Buffer allocate(int capacity) {
if (capacity < 0)
throw createCapacityException(capacity);
- return new Heap$Type$Buffer(capacity, capacity);
+ return new Heap$Type$Buffer(capacity, capacity, null);
}
/**
@@ -390,7 +390,7 @@ public abstract class $Type$Buffer
int offset, int length)
{
try {
- return new Heap$Type$Buffer(array, offset, length);
+ return new Heap$Type$Buffer(array, offset, length, null);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
More information about the nio-dev
mailing list