8149469: ByteBuffer API and implementation enhancements for VarHandles

Reviewed-by: chegar, alanb
This commit is contained in:
Paul Sandoz 2016-03-24 11:21:18 +01:00
parent 2954d94462
commit 4485394e3d
14 changed files with 1020 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,9 +25,10 @@
package java.nio;
import java.util.Spliterator;
import jdk.internal.HotSpotIntrinsicCandidate;
import java.util.Spliterator;
/**
* A container for data of a specific primitive type.
*
@ -188,7 +189,15 @@ public abstract class Buffer {
private int limit;
private int capacity;
// Used only by direct buffers
// Used by heap byte buffers or direct buffers with Unsafe access
// For heap byte buffers this field will be the address relative to the
// array base address and offset into that array. The address might
// not align on a word boundary for slices, nor align at a long word
// (8 byte) boundary for byte[] allocations on 32-bit systems.
// For direct buffers it is the start address of the memory region. The
// address might not align on a word boundary for slices, nor when created
// using JNI, see NewDirectByteBuffer(void*, long).
// Should ideally be declared final
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;

View File

@ -140,6 +140,7 @@ class Direct$Type$Buffer$RW$$BO$
att = null;
#else[rw]
super(cap);
this.isReadOnly = true;
#end[rw]
}
@ -180,6 +181,7 @@ class Direct$Type$Buffer$RW$$BO$
att = null;
#else[rw]
super(cap, addr, fd, unmapper);
this.isReadOnly = true;
#end[rw]
}
@ -200,6 +202,7 @@ class Direct$Type$Buffer$RW$$BO$
att = db;
#else[rw]
super(db, mark, pos, lim, cap, off);
this.isReadOnly = true;
#end[rw]
}
@ -213,6 +216,15 @@ class Direct$Type$Buffer$RW$$BO$
return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
}
#if[byte]
public $Type$Buffer slice(int pos, int lim) {
assert (pos >= 0);
assert (pos <= lim);
int rem = lim - pos;
return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, pos);
}
#end[byte]
public $Type$Buffer duplicate() {
return new Direct$Type$Buffer$RW$$BO$(this,
this.markValue(),

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -74,6 +74,9 @@ class Heap$Type$Buffer$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
@ -87,6 +90,9 @@ class Heap$Type$Buffer$RW$
super(buf, off, len);
this.isReadOnly = true;
#end[rw]
#if[byte]
this.address = arrayBaseOffset;
#end[byte]
}
protected Heap$Type$Buffer$RW$($type$[] buf,
@ -103,6 +109,9 @@ class Heap$Type$Buffer$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() {
@ -114,6 +123,20 @@ class Heap$Type$Buffer$RW$
this.position() + offset);
}
#if[byte]
$Type$Buffer slice(int pos, int lim) {
assert (pos >= 0);
assert (pos <= lim);
int rem = lim - pos;
return new Heap$Type$Buffer$RW$(hb,
-1,
0,
rem,
rem,
pos + offset);
}
#end[byte]
public $Type$Buffer duplicate() {
return new Heap$Type$Buffer$RW$(hb,
this.markValue(),
@ -144,7 +167,7 @@ class Heap$Type$Buffer$RW$
#if[byte]
private long byteOffset(long i) {
return arrayBaseOffset + i + offset;
return address + i;
}
#end[byte]

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -39,6 +39,7 @@ class StringCharBuffer // package-private
if ((start < 0) || (start > n) || (end < start) || (end > n))
throw new IndexOutOfBoundsException();
str = s;
this.isReadOnly = true;
}
public CharBuffer slice() {
@ -58,6 +59,7 @@ class StringCharBuffer // package-private
int offset) {
super(mark, pos, limit, cap, null, offset);
str = s;
this.isReadOnly = true;
}
public CharBuffer duplicate() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -269,7 +269,7 @@ public abstract class $Type$Buffer
//
final $type$[] hb; // Non-null only for heap buffers
final int offset;
boolean isReadOnly; // Valid only for heap buffers
boolean isReadOnly;
// Creates a new buffer with the given mark, position, limit, capacity,
// backing array, and array offset
@ -530,6 +530,10 @@ public abstract class $Type$Buffer
* it will be read-only if, and only if, this buffer is read-only. </p>
*
* @return The new $type$ buffer
#if[byte]
*
* @see #alignedSlice(int)
#end[byte]
*/
public abstract $Type$Buffer slice();
@ -1611,6 +1615,143 @@ public abstract class $Type$Buffer
return this;
}
/**
* Returns the memory address, pointing to the byte at the given index,
* modulus the given unit size.
*
* <p> A return value greater than zero indicates the address of the byte at
* the index is misaligned for the unit size, and the value's quantity
* indicates how much the index should be rounded up or down to locate a
* byte at an aligned address. Otherwise, a value of {@code 0} indicates
* that the address of the byte at the index is aligned for the unit size.
*
* @apiNote
* This method may be utilized to determine if unit size bytes from an
* index can be accessed atomically, if supported by the native platform.
*
* @implNote
* This implementation throws {@code UnsupportedOperationException} for
* non-direct buffers when the given unit size is greater then {@code 8}.
*
* @param index
* The index to query for alignment offset, must be non-negative, no
* upper bounds check is performed
*
* @param unitSize
* The unit size in bytes, must be a power of {@code 2}
*
* @return The indexed byte's memory address modulus the unit size
*
* @throws IllegalArgumentException
* If the index is negative or the unit size is not a power of
* {@code 2}
*
* @throws UnsupportedOperationException
* If the native platform does not guarantee stable alignment offset
* values for the given unit size when managing the memory regions
* of buffers of the same kind as this buffer (direct or
* non-direct). For example, if garbage collection would result
* in the moving of a memory region covered by a non-direct buffer
* from one location to another and both locations have different
* alignment characteristics.
*
* @see #alignedSlice(int)
* @since 9
*/
public final int alignmentOffset(int index, int unitSize) {
if (index < 0)
throw new IllegalArgumentException("Index less than zero: " + index);
if (unitSize < 1 || (unitSize & (unitSize - 1)) != 0)
throw new IllegalArgumentException("Unit size not a power of two: " + unitSize);
if (unitSize > 8 && !isDirect())
throw new UnsupportedOperationException("Unit size unsupported for non-direct buffers: " + unitSize);
return (int) ((address + index) % unitSize);
}
/**
* Creates a new byte buffer whose content is a shared and aligned
* subsequence of this buffer's content.
*
* <p> The content of the new buffer will start at this buffer's current
* position rounded up to the index of the nearest aligned byte for the
* given unit size, and end at this buffer's limit rounded down to the index
* of the nearest aligned byte for the given unit size.
* If rounding results in out-of-bound values then the new buffer's capacity
* and limit will be zero. If rounding is within bounds the following
* expressions will be true for a new buffer {@code nb} and unit size
* {@code unitSize}:
* <pre>{@code
* nb.alignmentOffset(0, unitSize) == 0
* nb.alignmentOffset(nb.limit(), unitSize) == 0
* }</pre>
*
* <p> Changes to this buffer's content will be visible in the new
* buffer, and vice versa; the two buffers' position, limit, and mark
* values will be independent.
*
* <p> The new buffer's position will be zero, its capacity and its limit
* will be the number of bytes remaining in this buffer or fewer subject to
* alignment, its mark will be undefined, and its byte order will be
* {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}.
*
* The new buffer will be direct if, and only if, this buffer is direct, and
* it will be read-only if, and only if, this buffer is read-only. </p>
*
* @apiNote
* This method may be utilized to create a new buffer where unit size bytes
* from index, that is a multiple of the unit size, may be accessed
* atomically, if supported by the native platform.
*
* @implNote
* This implementation throws {@code UnsupportedOperationException} for
* non-direct buffers when the given unit size is greater then {@code 8}.
*
* @param unitSize
* The unit size in bytes, must be a power of {@code 2}
*
* @return The new byte buffer
*
* @throws IllegalArgumentException
* If the unit size not a power of {@code 2}
*
* @throws UnsupportedOperationException
* If the native platform does not guarantee stable aligned slices
* for the given unit size when managing the memory regions
* of buffers of the same kind as this buffer (direct or
* non-direct). For example, if garbage collection would result
* in the moving of a memory region covered by a non-direct buffer
* from one location to another and both locations have different
* alignment characteristics.
*
* @see #alignmentOffset(int, int)
* @see #slice()
* @since 9
*/
public final ByteBuffer alignedSlice(int unitSize) {
int pos = position();
int lim = limit();
int pos_mod = alignmentOffset(pos, unitSize);
int lim_mod = alignmentOffset(lim, unitSize);
// Round up the position to align with unit size
int aligned_pos = (pos_mod > 0)
? pos + (unitSize - pos_mod)
: pos;
// Round down the limit to align with unit size
int aligned_lim = lim - lim_mod;
if (aligned_pos > lim || aligned_lim < pos) {
aligned_pos = aligned_lim = pos;
}
return slice(aligned_pos, aligned_lim);
}
abstract ByteBuffer slice(int pos, int lim);
// Unchecked accessors, for use by ByteBufferAs-X-Buffer classes
//
abstract byte _get(int i); // package-private

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -336,6 +336,103 @@ public class Basic$Type$
}
private static void testAlign(final ByteBuffer b, boolean direct) {
// index out-of bounds
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(-1, (short) 1));
// unit size values
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(0, (short) 0));
for (int us = 1; us < 65; us++) {
int _us = us;
if ((us & (us - 1)) != 0) {
// unit size not a power of two
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(0, _us));
} else {
if (direct || us <= 8) {
b.alignmentOffset(0, us);
} else {
// unit size > 8 with non-direct buffer
tryCatch(b, UnsupportedOperationException.class, () -> b.alignmentOffset(0, _us));
}
}
}
// Probe for long misalignment at index zero for a newly created buffer
ByteBuffer empty = direct ? ByteBuffer.allocateDirect(0) : ByteBuffer.allocate(0);
int longMisalignmentAtZero = empty.alignmentOffset(0, 8);
if (direct) {
// Freshly created direct byte buffers should be aligned at index 0
// for ref and primitive values (see Unsafe.allocateMemory)
if (longMisalignmentAtZero != 0)
fail("Direct byte buffer misalligned at index 0 for ref and primitive values " + longMisalignmentAtZero);
} else {
// For heap byte buffers misalignment may occur on 32-bit systems
// where Unsafe.ARRAY_BYTE_BASE_OFFSET % 8 == 4 and not 0
// Note the GC will preserve alignment of the base address of the
// array
if (jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET % 8 != longMisalignmentAtZero)
fail("Heap byte buffer misalligned at index 0 for ref and primitive values " + longMisalignmentAtZero);
}
// Ensure test buffer is correctly aligned at index 0
if (b.alignmentOffset(0, 8) != longMisalignmentAtZero)
fail("Test input buffer not correctly aligned at index 0", b);
// Test misalignment values
for (int us : new int[]{1, 2, 4, 8}) {
for (int i = 0; i < us * 2; i++) {
int am = b.alignmentOffset(i, us);
int expectedAm = (longMisalignmentAtZero + i) % us;
if (am != expectedAm)
fail(String.format("b.alignmentOffset(%d, %d) == %d incorrect, expected %d", i, us, am, expectedAm));
}
}
// Created aligned slice to test against
int ap = 8 - longMisalignmentAtZero;
int al = b.limit() - b.alignmentOffset(b.limit(), 8);
ByteBuffer ab = b.position(ap).limit(al).
slice();
if (ab.limit() == 0)
fail("Test input buffer not sufficiently sized to cover an aligned region for all values", b);
if (ab.alignmentOffset(0, 8) != 0)
fail("Aligned test input buffer not correctly aligned at index 0", ab);
for (int us : new int[]{1, 2, 4, 8}) {
for (int p = 1; p < 16; p++) {
int l = ab.limit() - p;
ByteBuffer as = ab.slice().position(p).limit(l).
alignedSlice(us);
ck(as, 0, as.position());
ck(as, as.capacity(), as.limit());
if (b.isDirect() != as.isDirect())
fail("Lost direction", as);
if (b.isReadOnly() != as.isReadOnly())
fail("Lost read-only", as);
if (as.alignmentOffset(0, us) != 0)
fail("Buffer not correctly aligned at index 0", as);
if (as.alignmentOffset(as.limit(), us) != 0)
fail("Buffer not correctly aligned at limit", as);
int p_mod = ab.alignmentOffset(p, us);
int l_mod = ab.alignmentOffset(l, us);
// Round up position
p = (p_mod > 0) ? p + (us - p_mod) : p;
// Round down limit
l = l - l_mod;
int ec = l - p;
if (as.limit() != ec)
fail("Buffer capacity incorrect, expected: " + ec, as);
}
}
}
#end[byte]
private static void fail(String problem,
@ -854,6 +951,11 @@ public class Basic$Type$
relPut(b); // Required by testViews
#if[byte]
// Test alignment
testAlign(b, direct);
#end[byte]
}
#if[char]

View File

@ -26,6 +26,7 @@
* @bug 4413135 4414911 4416536 4416562 4418782 4471053 4472779 4490253 4523725
* 4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529
* 6221101 6234263 6535542 6591971 6593946 6795561 7190219 7199551 8065556
* 8149469
* @author Mark Reinhold
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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
@ -336,6 +336,103 @@ public class BasicByte
}
private static void testAlign(final ByteBuffer b, boolean direct) {
// index out-of bounds
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(-1, (short) 1));
// unit size values
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(0, (short) 0));
for (int us = 1; us < 65; us++) {
int _us = us;
if ((us & (us - 1)) != 0) {
// unit size not a power of two
tryCatch(b, IllegalArgumentException.class, () -> b.alignmentOffset(0, _us));
} else {
if (direct || us <= 8) {
b.alignmentOffset(0, us);
} else {
// unit size > 8 with non-direct buffer
tryCatch(b, UnsupportedOperationException.class, () -> b.alignmentOffset(0, _us));
}
}
}
// Probe for long misalignment at index zero for a newly created buffer
ByteBuffer empty = direct ? ByteBuffer.allocateDirect(0) : ByteBuffer.allocate(0);
int longMisalignmentAtZero = empty.alignmentOffset(0, 8);
if (direct) {
// Freshly created direct byte buffers should be aligned at index 0
// for ref and primitive values (see Unsafe.allocateMemory)
if (longMisalignmentAtZero != 0)
fail("Direct byte buffer misalligned at index 0 for ref and primitive values " + longMisalignmentAtZero);
} else {
// For heap byte buffers misalignment may occur on 32-bit systems
// where Unsafe.ARRAY_BYTE_BASE_OFFSET % 8 == 4 and not 0
// Note the GC will preserve alignment of the base address of the
// array
if (jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET % 8 != longMisalignmentAtZero)
fail("Heap byte buffer misalligned at index 0 for ref and primitive values " + longMisalignmentAtZero);
}
// Ensure test buffer is correctly aligned at index 0
if (b.alignmentOffset(0, 8) != longMisalignmentAtZero)
fail("Test input buffer not correctly aligned at index 0", b);
// Test misalignment values
for (int us : new int[]{1, 2, 4, 8}) {
for (int i = 0; i < us * 2; i++) {
int am = b.alignmentOffset(i, us);
int expectedAm = (longMisalignmentAtZero + i) % us;
if (am != expectedAm)
fail(String.format("b.alignmentOffset(%d, %d) == %d incorrect, expected %d", i, us, am, expectedAm));
}
}
// Created aligned slice to test against
int ap = 8 - longMisalignmentAtZero;
int al = b.limit() - b.alignmentOffset(b.limit(), 8);
ByteBuffer ab = b.position(ap).limit(al).
slice();
if (ab.limit() == 0)
fail("Test input buffer not sufficiently sized to cover an aligned region for all values", b);
if (ab.alignmentOffset(0, 8) != 0)
fail("Aligned test input buffer not correctly aligned at index 0", ab);
for (int us : new int[]{1, 2, 4, 8}) {
for (int p = 1; p < 16; p++) {
int l = ab.limit() - p;
ByteBuffer as = ab.slice().position(p).limit(l).
alignedSlice(us);
ck(as, 0, as.position());
ck(as, as.capacity(), as.limit());
if (b.isDirect() != as.isDirect())
fail("Lost direction", as);
if (b.isReadOnly() != as.isReadOnly())
fail("Lost read-only", as);
if (as.alignmentOffset(0, us) != 0)
fail("Buffer not correctly aligned at index 0", as);
if (as.alignmentOffset(as.limit(), us) != 0)
fail("Buffer not correctly aligned at limit", as);
int p_mod = ab.alignmentOffset(p, us);
int l_mod = ab.alignmentOffset(l, us);
// Round up position
p = (p_mod > 0) ? p + (us - p_mod) : p;
// Round down limit
l = l - l_mod;
int ec = l - p;
if (as.limit() != ec)
fail("Buffer capacity incorrect, expected: " + ec, as);
}
}
}
private static void fail(String problem,
@ -854,6 +951,11 @@ public class BasicByte
relPut(b); // Required by testViews
// Test alignment
testAlign(b, direct);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicChar
@ -854,6 +951,11 @@ public class BasicChar
relPut(b); // Required by testViews
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicDouble
@ -854,6 +951,11 @@ public class BasicDouble
relPut(b); // Required by testViews
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicFloat
@ -854,6 +951,11 @@ public class BasicFloat
relPut(b); // Required by testViews
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicInt
@ -854,6 +951,11 @@ public class BasicInt
relPut(b); // Required by testViews
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicLong
@ -854,6 +951,11 @@ public class BasicLong
relPut(b); // Required by testViews
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2016, 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,6 +317,103 @@ public class BasicShort
@ -854,6 +951,11 @@ public class BasicShort
relPut(b); // Required by testViews
}