8151163: All Buffer implementations should leverage Unsafe unaligned accessors
authorpsandoz
Fri, 15 Jul 2016 12:36:18 +0200
changeset 39967 69932114a0fc
parent 39965 5955109add86
child 39968 e02d57bd3e01
8151163: All Buffer implementations should leverage Unsafe unaligned accessors Reviewed-by: shade, aph
hotspot/test/compiler/intrinsics/unsafe/ByteBufferTest.java
hotspot/test/compiler/intrinsics/unsafe/DirectByteBufferTest.java
hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/intrinsics/unsafe/ByteBufferTest.java	Fri Jul 15 12:36:18 2016 +0200
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Red Hat Inc. 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.
+ *
+ * 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.
+ */
+
+import jdk.test.lib.Utils;
+
+import java.nio.Buffer;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+import static java.nio.ByteOrder.BIG_ENDIAN;
+import static java.nio.ByteOrder.LITTLE_ENDIAN;
+
+// A wrapper for a ByteBuffer which maintains a backing array and a
+// position.  Whenever this wrapper is written the backing array and
+// the wrapped byte buffer are updated together, and whenever it is
+// read we check that the ByteBuffer and the backing array are identical.
+
+class MyByteBuffer {
+    final ByteBuffer buf;
+    final byte[] bytes;
+    int pos;
+    ByteOrder byteOrder = BIG_ENDIAN;
+
+    MyByteBuffer(ByteBuffer buf) {
+        this.buf = buf;
+        this.bytes = new byte[buf.capacity()];
+        pos = 0;
+    }
+
+    public final MyByteBuffer order(ByteOrder bo) {
+        byteOrder = bo;
+        buf.order(bo);
+        return this;
+    }
+
+    static MyByteBuffer allocate(int capacity) {
+        return new MyByteBuffer(ByteBuffer.allocate(capacity));
+    }
+
+    static MyByteBuffer allocateDirect(int capacity) {
+        return new MyByteBuffer(ByteBuffer.allocateDirect(capacity));
+    }
+
+    int capacity() { return bytes.length; }
+    int position() {
+        if (buf.position() != pos)
+            throw new RuntimeException();
+        return buf.position();
+    }
+
+    byte[] actualArray() {
+        buf.rewind();
+        byte[] actual = new byte[bytes.length];
+        buf.get(actual, 0, actual.length);
+        buf.rewind();
+
+        return actual;
+    }
+    byte[] expectedArray() { return bytes; }
+
+    private static byte long7(long x) { return (byte)(x >> 56); }
+    private static byte long6(long x) { return (byte)(x >> 48); }
+    private static byte long5(long x) { return (byte)(x >> 40); }
+    private static byte long4(long x) { return (byte)(x >> 32); }
+    private static byte long3(long x) { return (byte)(x >> 24); }
+    private static byte long2(long x) { return (byte)(x >> 16); }
+    private static byte long1(long x) { return (byte)(x >>  8); }
+    private static byte long0(long x) { return (byte)(x      ); }
+
+    private static byte int3(int x) { return (byte)(x >> 24); }
+    private static byte int2(int x) { return (byte)(x >> 16); }
+    private static byte int1(int x) { return (byte)(x >>  8); }
+    private static byte int0(int x) { return (byte)(x      ); }
+
+    private static byte short1(short x) { return (byte)(x >> 8); }
+    private static byte short0(short x) { return (byte)(x     ); }
+
+    byte _get(long i) { return bytes[(int)i]; }
+    void _put(long i, byte x) { bytes[(int)i] = x; }
+
+    private void putLongX(long a, long x) {
+        if (byteOrder == BIG_ENDIAN) {
+            x = Long.reverseBytes(x);
+        }
+        _put(a + 7, long7(x));
+        _put(a + 6, long6(x));
+        _put(a + 5, long5(x));
+        _put(a + 4, long4(x));
+        _put(a + 3, long3(x));
+        _put(a + 2, long2(x));
+        _put(a + 1, long1(x));
+        _put(a    , long0(x));
+    }
+
+    private void putIntX(long a, int x) {
+        if (byteOrder == BIG_ENDIAN) {
+            x = Integer.reverseBytes(x);
+        }
+        _put(a + 3, int3(x));
+        _put(a + 2, int2(x));
+        _put(a + 1, int1(x));
+        _put(a    , int0(x));
+    }
+
+    private void putShortX(int bi, short x) {
+        if (byteOrder == BIG_ENDIAN) {
+            x = Short.reverseBytes(x);
+        }
+        _put(bi    , short0(x));
+        _put(bi + 1, short1(x));
+    }
+
+    static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
+        return (((b3       ) << 24) |
+                ((b2 & 0xff) << 16) |
+                ((b1 & 0xff) <<  8) |
+                ((b0 & 0xff)      ));
+    }
+    int getIntX(long a) {
+        int x = makeInt(_get(a + 3),
+                _get(a + 2),
+                _get(a + 1),
+                _get(a));
+        if (byteOrder == BIG_ENDIAN) {
+            x = Integer.reverseBytes(x);
+        }
+        return x;
+    }
+
+    static private long makeLong(byte b7, byte b6, byte b5, byte b4,
+                                 byte b3, byte b2, byte b1, byte b0)
+    {
+        return ((((long)b7       ) << 56) |
+                (((long)b6 & 0xff) << 48) |
+                (((long)b5 & 0xff) << 40) |
+                (((long)b4 & 0xff) << 32) |
+                (((long)b3 & 0xff) << 24) |
+                (((long)b2 & 0xff) << 16) |
+                (((long)b1 & 0xff) <<  8) |
+                (((long)b0 & 0xff)      ));
+    }
+
+    long getLongX(long a) {
+        long x = makeLong(_get(a + 7),
+                _get(a + 6),
+                _get(a + 5),
+                _get(a + 4),
+                _get(a + 3),
+                _get(a + 2),
+                _get(a + 1),
+                _get(a));
+        if (byteOrder == BIG_ENDIAN) {
+            x = Long.reverseBytes(x);
+        }
+        return x;
+    }
+
+    static private short makeShort(byte b1, byte b0) {
+        return (short)((b1 << 8) | (b0 & 0xff));
+    }
+
+    short getShortX(long a) {
+        short x = makeShort(_get(a + 1),
+                            _get(a    ));
+        if (byteOrder == BIG_ENDIAN) {
+            x = Short.reverseBytes(x);
+        }
+        return x;
+    }
+
+    double getDoubleX(long a) {
+        long x = getLongX(a);
+        return Double.longBitsToDouble(x);
+    }
+
+    double getFloatX(long a) {
+        int x = getIntX(a);
+        return Float.intBitsToFloat(x);
+    }
+
+    void ck(long x, long y) {
+        if (x != y) {
+            throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y));
+        }
+    }
+
+    void ck(double x, double y) {
+        if (x == x && y == y && x != y) {
+            ck(x, y);
+        }
+    }
+
+    // Method accessors
+
+    long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); }
+    int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); }
+    short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); }
+    char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); }
+    double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); }
+    float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); }
+
+    void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); }
+    void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); }
+    void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); }
+    void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); }
+    void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); }
+    void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); }
+
+    long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; }
+    int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; }
+    short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; }
+    char getChar() {  ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; }
+    double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; }
+    float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; }
+
+    void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); }
+    void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); }
+    void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); }
+    void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); }
+    void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); }
+    void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); }
+
+    // View accessors
+
+    long getLong(LongBuffer vb, int i) { ck(vb.get(i / 8), getLongX(i)); return vb.get(i / 8); }
+    int getInt(IntBuffer vb, int i) { ck(vb.get(i / 4), getIntX(i)); return vb.get(i / 4); }
+    short getShort(ShortBuffer vb, int i) { ck(vb.get(i / 2), getShortX(i)); return vb.get(i / 2); }
+    char getChar(CharBuffer vb, int i) { ck(vb.get(i / 2), (char)getShortX(i)); return vb.get(i / 2); }
+    double getDouble(DoubleBuffer vb, int i) { ck(vb.get(i / 8), getDoubleX(i)); return vb.get(i / 8); }
+    float getFloat(FloatBuffer vb, int i) { ck(vb.get(i / 4), getFloatX(i)); return vb.get(i / 4); }
+
+    void putLong(LongBuffer vb, int i, long x) { vb.put(i / 8, x); putLongX(i, x); }
+    void putInt(IntBuffer vb, int i, int x) { vb.put(i / 4, x); putIntX(i, x); }
+    void putShort(ShortBuffer vb, int i, short x) { vb.put(i / 2, x); putShortX(i, x); }
+    void putChar(CharBuffer vb, int i, char x) { vb.put(i / 2, x); putShortX(i, (short)x); }
+    void putDouble(DoubleBuffer vb, int i, double x) { vb.put(i / 8, x); putLongX(i, Double.doubleToRawLongBits(x)); }
+    void putFloat(FloatBuffer vb, int i, float x) { vb.put(i / 4, x); putIntX(i, Float.floatToRawIntBits(x)); }
+
+    long getLong(LongBuffer v) { ck(v.get(v.position()), getLongX(pos)); long x = v.get(); pos += 8; return x; }
+    int getInt(IntBuffer v) { ck(v.get(v.position()), getIntX(pos)); int x = v.get(); pos += 4; return x; }
+    short getShort(ShortBuffer v) { ck(v.get(v.position()), getShortX(pos)); short x = v.get(); pos += 2; return x; }
+    char getChar(CharBuffer v) { ck(v.get(v.position()), (char)getShortX(pos)); char x = v.get(); pos += 2; return x; }
+    double getDouble(DoubleBuffer v) { ck(v.get(v.position()), getDoubleX(pos)); double x = v.get(); pos += 8; return x; }
+    float getFloat(FloatBuffer v) { ck(v.get(v.position()), getFloatX(pos)); float x = v.get(); pos += 4; return x; }
+
+    void putLong(LongBuffer v, long x) { putLongX(pos, x); pos += 8; v.put(x); }
+    void putInt(IntBuffer v, int x) { putIntX(pos, x); pos += 4; v.put(x); }
+    void putShort(ShortBuffer v, short x) { putShortX(pos, x); pos += 2; v.put(x); }
+    void putChar(CharBuffer v, char x) { putShortX(pos, (short)x); pos += 2; v.put(x); }
+    void putDouble(DoubleBuffer v, double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; v.put(x); }
+    void putFloat(FloatBuffer v, float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; v.put(x); }
+
+    void rewind() { pos = 0; buf.rewind(); }
+}
+
+public abstract class ByteBufferTest implements Runnable {
+
+    Random random = Utils.getRandomInstance();
+    MyByteBuffer data;
+
+    static int randomOffset(Random r, MyByteBuffer buf, int size) {
+        return r.nextInt(buf.capacity() - size);
+    }
+
+    static int randomAlignedOffset(Random r, MyByteBuffer buf, int unitSize) {
+        return r.nextInt(buf.capacity() / unitSize) * unitSize;
+    }
+
+    long iterations;
+
+    ByteBufferTest(long iterations, boolean direct) {
+        this.iterations = iterations;
+        data = direct
+               ? MyByteBuffer.allocateDirect(1024)
+               : MyByteBuffer.allocate(1024);
+    }
+
+    // The core of the test.  Walk over the buffer reading and writing
+    // random data, XORing it as we go.  We can detect writes in the
+    // wrong place, writes which are too long or too short, and reads
+    // or writes of the wrong data,
+    void step(Random r) {
+        stepUsingAccessors(r);
+        stepUsingViews(r);
+    }
+
+    void stepUsingAccessors(Random r) {
+        data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN);
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putLong(data.getLong() ^ random.nextLong());
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putInt(data.getInt() ^ random.nextInt());
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putShort((short)(data.getShort() ^ random.nextInt()));
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putChar((char)(data.getChar() ^ random.nextInt()));
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putDouble(combine(data.getDouble(), random.nextLong()));
+
+        data.rewind();
+        while (data.position() < data.capacity())
+            data.putFloat(combine(data.getFloat(), random.nextInt()));
+
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Long.BYTES);
+            data.putLong(offset, data.getLong(offset) ^ random.nextLong());
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Integer.BYTES);
+            data.putInt(offset, data.getInt(offset) ^ random.nextInt());
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Short.BYTES);
+            data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Character.BYTES);
+            data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Double.BYTES);
+            data.putDouble(offset, combine(data.getDouble(offset), random.nextLong()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomOffset(r, data, Float.BYTES);
+            data.putFloat(offset, combine(data.getFloat(offset), random.nextInt()));
+        }
+    }
+
+    void stepUsingViews(Random r) {
+        data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN);
+
+        data.rewind();
+        LongBuffer lbuf = data.buf.asLongBuffer();
+        while (lbuf.position() < data.capacity() / Long.BYTES)
+            data.putLong(lbuf, data.getLong(lbuf) ^ random.nextLong());
+
+        data.rewind();
+        IntBuffer ibuf = data.buf.asIntBuffer();
+        while (ibuf.position() < data.capacity() / Integer.BYTES)
+            data.putInt(ibuf, data.getInt(ibuf) ^ random.nextInt());
+
+        data.rewind();
+        ShortBuffer sbuf = data.buf.asShortBuffer();
+        while (sbuf.position() < data.capacity() / Short.BYTES)
+            data.putShort(sbuf, (short)(data.getShort(sbuf) ^ random.nextInt()));
+
+        data.rewind();
+        CharBuffer cbuf = data.buf.asCharBuffer();
+        while (cbuf.position() < data.capacity() / Character.BYTES)
+            data.putChar(cbuf, (char)(data.getChar(cbuf) ^ random.nextInt()));
+
+        data.rewind();
+        DoubleBuffer dbuf = data.buf.asDoubleBuffer();
+        while (dbuf.position() < data.capacity() / Double.BYTES)
+            data.putDouble(dbuf, combine(data.getDouble(dbuf), random.nextLong()));
+
+        data.rewind();
+        FloatBuffer fbuf = data.buf.asFloatBuffer();
+        while (fbuf.position() < data.capacity() / Float.BYTES)
+            data.putFloat(fbuf, combine(data.getFloat(fbuf), random.nextInt()));
+
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Long.BYTES);
+            data.putLong(lbuf, offset, data.getLong(lbuf, offset) ^ random.nextLong());
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Integer.BYTES);
+            data.putInt(ibuf, offset, data.getInt(ibuf, offset) ^ random.nextInt());
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Short.BYTES);
+            data.putShort(sbuf, offset, (short)(data.getShort(sbuf, offset) ^ random.nextInt()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Character.BYTES);
+            data.putChar(cbuf, offset, (char)(data.getChar(cbuf, offset) ^ random.nextInt()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Double.BYTES);
+            data.putDouble(dbuf, offset, combine(data.getDouble(dbuf, offset), random.nextLong()));
+        }
+        for (int i = 0; i < 100; i++) {
+            int offset = randomAlignedOffset(r, data, Float.BYTES);
+            data.putFloat(fbuf, offset, combine(data.getFloat(fbuf, offset), random.nextInt()));
+        }
+    }
+
+    // XOR the bit pattern of a double and a long, returning the
+    // result as a double.
+    //
+    // We convert signalling NaNs to quiet NaNs.  We need to do this
+    // because some platforms (in particular legacy 80x87) do not
+    // provide transparent conversions between integer and
+    // floating-point types even when using raw conversions but
+    // quietly convert sNaN to qNaN.  This causes spurious test
+    // failures when the template interpreter uses 80x87 and the JITs
+    // use XMM registers.
+    //
+    public double combine(double prev, long bits) {
+        bits ^= Double.doubleToRawLongBits(prev);
+        double result = Double.longBitsToDouble(bits);
+        if (Double.isNaN(result)) {
+            result = Double.longBitsToDouble(bits | 0x8000000000000l);
+        }
+        return result;
+    }
+
+    // XOR the bit pattern of a float and an int, returning the result
+    // as a float.  Convert sNaNs to qNaNs.
+    public Float combine(float prev, int bits) {
+        bits ^= Float.floatToRawIntBits(prev);
+        Float result = Float.intBitsToFloat(bits);
+        if (Float.isNaN(result)) {
+            result = Float.intBitsToFloat(bits | 0x400000);
+        }
+        return result;
+    }
+
+    enum PrimitiveType {
+        BYTE(1), CHAR(2), SHORT(2), INT(4), LONG(8), FLOAT(4), DOUBLE(8);
+
+        public final int size;
+        PrimitiveType(int size) {
+            this.size = size;
+        }
+    }
+
+    Buffer asView(ByteBuffer b, PrimitiveType t) {
+        switch (t) {
+            case BYTE: return b;
+            case CHAR: return b.asCharBuffer();
+            case SHORT: return b.asShortBuffer();
+            case INT: return b.asIntBuffer();
+            case LONG: return b.asLongBuffer();
+            case FLOAT: return b.asFloatBuffer();
+            case DOUBLE: return b.asDoubleBuffer();
+        }
+        throw new InternalError("Should not reach here");
+    }
+
+    void getOne(ByteBuffer b, PrimitiveType t) {
+        switch (t) {
+        case BYTE: b.get(); break;
+        case CHAR: b.getChar(); break;
+        case SHORT: b.getShort(); break;
+        case INT: b.getInt(); break;
+        case LONG: b.getLong(); break;
+        case FLOAT: b.getFloat(); break;
+        case DOUBLE: b.getDouble(); break;
+        }
+    }
+
+    void putOne(ByteBuffer b, PrimitiveType t) {
+        switch (t) {
+        case BYTE: b.put((byte)0); break;
+        case CHAR: b.putChar('0'); break;
+        case SHORT: b.putShort((short)0); break;
+        case INT: b.putInt(0); break;
+        case LONG: b.putLong(0); break;
+        case FLOAT: b.putFloat(0); break;
+        case DOUBLE: b.putDouble(0); break;
+        }
+    }
+
+    void asViewGetOne(ByteBuffer b, PrimitiveType t) {
+        switch (t) {
+            case BYTE: b.get(); break;
+            case CHAR: b.asCharBuffer().get(); break;
+            case SHORT: b.asShortBuffer().get(); break;
+            case INT: b.asIntBuffer().get(); break;
+            case LONG: b.asLongBuffer().get(); break;
+            case FLOAT: b.asFloatBuffer().get(); break;
+            case DOUBLE: b.asDoubleBuffer().get(); break;
+        }
+    }
+
+    void asViewPutOne(ByteBuffer b, PrimitiveType t) {
+        switch (t) {
+            case BYTE: b.put((byte)0); break;
+            case CHAR: b.asCharBuffer().put('0'); break;
+            case SHORT: b.asShortBuffer().put((short)0); break;
+            case INT: b.asIntBuffer().put(0); break;
+            case LONG: b.asLongBuffer().put(0); break;
+            case FLOAT: b.asFloatBuffer().put(0); break;
+            case DOUBLE: b.asDoubleBuffer().put(0); break;
+        }
+    }
+
+    void getOne(ByteBuffer b, PrimitiveType t, int index) {
+        switch (t) {
+        case BYTE: b.get(index); break;
+        case CHAR: b.getChar(index); break;
+        case SHORT: b.getShort(index); break;
+        case INT: b.getInt(index); break;
+        case LONG: b.getLong(index); break;
+        case FLOAT: b.getFloat(index); break;
+        case DOUBLE: b.getDouble(index); break;
+        }
+    }
+
+    void putOne(ByteBuffer b, PrimitiveType t, int index) {
+        switch (t) {
+        case BYTE: b.put(index, (byte)0); break;
+        case CHAR: b.putChar(index, '0'); break;
+        case SHORT: b.putShort(index, (short)0); break;
+        case INT: b.putInt(index, 0); break;
+        case LONG: b.putLong(index, 0); break;
+        case FLOAT: b.putFloat(index, 0); break;
+        case DOUBLE: b.putDouble(index, 0); break;
+        }
+    }
+
+    void asViewGetOne(Buffer v, PrimitiveType t, int index) {
+        switch (t) {
+            case BYTE: ((ByteBuffer) v).get(index); break;
+            case CHAR: ((CharBuffer) v).get(index); break;
+            case SHORT: ((ShortBuffer) v).get(index); break;
+            case INT: ((IntBuffer) v).get(index); break;
+            case LONG: ((LongBuffer) v).get(index); break;
+            case FLOAT: ((FloatBuffer) v).get(index); break;
+            case DOUBLE: ((DoubleBuffer) v).get(index); break;
+        }
+    }
+
+    void asViewPutOne(Buffer v, PrimitiveType t, int index) {
+        switch (t) {
+            case BYTE: ((ByteBuffer) v).put(index, (byte)0); break;
+            case CHAR: ((CharBuffer) v).put(index, '0'); break;
+            case SHORT: ((ShortBuffer) v).put(index, (short)0); break;
+            case INT: ((IntBuffer) v).put(index, 0); break;
+            case LONG: ((LongBuffer) v).put(index, 0); break;
+            case FLOAT: ((FloatBuffer) v).put(index, 0); break;
+            case DOUBLE: ((DoubleBuffer) v).put(index, 0); break;
+        }
+    }
+
+    void checkBoundaryConditions() {
+        for (int i = 0; i < 100; i++) {
+            int bufSize = random.nextInt(16);
+            ByteBuffer buf = data.buf.isDirect()
+                    ? ByteBuffer.allocateDirect(bufSize)
+                    : ByteBuffer.allocate(bufSize);
+            for (PrimitiveType t : PrimitiveType.values()) {
+                buf.rewind();
+                Buffer viewBuf = asView(buf, t);
+                for (int j = 0; j < 100; j++) {
+                    int offset = random.nextInt(32) - 8;
+                    int threw = 0;
+                    int checks = 6;
+                    try {
+                        try {
+                            buf.position(offset);
+                            getOne(buf, t);
+                        }
+                        catch (BufferUnderflowException e) {
+                            if (offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+                        catch (IllegalArgumentException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        try {
+                            buf.position(offset);
+                            asViewGetOne(buf, t);
+                        }
+                        catch (BufferUnderflowException e) {
+                            if (offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+                        catch (IllegalArgumentException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        try {
+                            buf.position(offset);
+                            putOne(buf, t);
+                        }
+                        catch (BufferOverflowException e) {
+                            if (offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+                        catch (IllegalArgumentException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        try {
+                            buf.position(offset);
+                            asViewPutOne(buf, t);
+                        }
+                        catch (BufferOverflowException e) {
+                            if (offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+                        catch (IllegalArgumentException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        try {
+                            putOne(buf, t, offset);
+                        }
+                        catch (IndexOutOfBoundsException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        try {
+                            getOne(buf, t, offset);
+                        }
+                        catch (IndexOutOfBoundsException e) {
+                            if (offset >= 0 && offset + t.size < bufSize)
+                                throw new RuntimeException
+                                        ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                            threw++;
+                        }
+
+                        // If offset is aligned access using the view
+                        if (offset % t.size == 0) {
+                            checks = 8;
+                            int viewOffset = offset / t.size;
+
+
+                            try {
+                                asViewPutOne(viewBuf, t, viewOffset);
+                            }
+                            catch (IndexOutOfBoundsException e) {
+                                if (offset >= 0 && offset + t.size < bufSize)
+                                    throw new RuntimeException
+                                            ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                                threw++;
+                            }
+
+                            try {
+                                asViewGetOne(viewBuf, t, viewOffset);
+                            }
+                            catch (IndexOutOfBoundsException e) {
+                                if (offset >= 0 && offset + t.size < bufSize)
+                                    throw new RuntimeException
+                                            ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
+                                threw++;
+                            }
+                        }
+
+                        if (threw == 0) {
+                            // Make sure that we should not have thrown.
+                            if (offset < 0 || offset + t.size > bufSize) {
+                                throw new RuntimeException
+                                        ("should have thrown but did not, type = " + t
+                                         + ", offset = " + offset + ", bufSize = " + bufSize);
+                            }
+                        }
+                        else if (threw != checks) {
+                            // If one of the {get,put} operations threw
+                            // due to an invalid offset then all four of
+                            // them should have thrown.
+                            throw new RuntimeException
+                                    ("should have thrown but at least one did not, type = " + t
+                                     + ", offset = " + offset + ", bufSize = " + bufSize);
+                        }
+                    }
+                    catch (Throwable th) {
+                        throw new RuntimeException
+                                ("unexpected throw: type  = " + t + ", offset = " + offset + ", bufSize = " + bufSize, th);
+
+                    }
+                }
+            }
+        }
+    }
+
+    public void run() {
+        checkBoundaryConditions();
+
+        for (int i = 0; i < data.capacity(); i += 8) {
+            data.putLong(i, random.nextLong());
+        }
+
+        for (int i = 0; i < iterations; i++) {
+            step(random);
+        }
+
+        if (!Arrays.equals(data.actualArray(), data.expectedArray())) {
+            throw new RuntimeException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/intrinsics/unsafe/DirectByteBufferTest.java	Fri Jul 15 12:36:18 2016 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Red Hat Inc. 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 8026049 8151163
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses -Djdk.test.lib.random.seed=0 DirectByteBufferTest
+ * @run main/othervm -Djdk.test.lib.random.seed=0 DirectByteBufferTest
+ * @summary Verify that direct byte buffers are correctly accessed.
+ */
+
+public class DirectByteBufferTest extends ByteBufferTest {
+
+    public DirectByteBufferTest(long iterations, boolean direct) {
+        super(iterations, direct);
+    }
+
+    public static void main(String[] args) {
+        // The number of iterations is high to ensure that tiered
+        // compilation kicks in all the way up to C2.
+        long iterations = 100000;
+        if (args.length > 0)
+            iterations = Long.parseLong(args[0]);
+
+        new DirectByteBufferTest(iterations, true).run();
+    }
+}
--- a/hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java	Tue Jul 12 15:06:18 2016 +0300
+++ b/hotspot/test/compiler/intrinsics/unsafe/HeapByteBufferTest.java	Fri Jul 15 12:36:18 2016 +0200
@@ -1,506 +1,41 @@
-//
-// Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
-// Copyright (c) 2015, Red Hat Inc. 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.
-//
-// 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.
-//
-//
-
-import java.nio.BufferOverflowException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import static java.nio.ByteOrder.BIG_ENDIAN;
-import static java.nio.ByteOrder.LITTLE_ENDIAN;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Random;
-import jdk.test.lib.Utils;
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, Red Hat Inc. 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.
+ *
+ * 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.
+ */
 
 /**
  * @test
- * @bug 8026049
+ * @bug 8026049 8151163
  * @modules java.base/jdk.internal.misc
  * @library /testlibrary
  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses -Djdk.test.lib.random.seed=0 HeapByteBufferTest
  * @run main/othervm -Djdk.test.lib.random.seed=0 HeapByteBufferTest
- * @summary Verify that byte buffers are correctly accessed.
+ * @summary Verify that heap byte buffers are correctly accessed.
  */
 
-// A wrapper for a ByteBuffer which maintains a backing array and a
-// position.  Whenever this wrapper is written the backing array and
-// the wrapped byte buffer are updated together, and whenever it is
-// read we check that the ByteBuffer and the backing array are identical.
-
-class MyByteBuffer {
-    final ByteBuffer buf;
-    final byte[] bytes;
-    int pos;
-    ByteOrder byteOrder = BIG_ENDIAN;
-
-    MyByteBuffer(ByteBuffer buf, byte[] bytes) {
-        this.buf = buf;
-        this.bytes = Arrays.copyOf(bytes, bytes.length);
-        pos = 0;
-    }
-
-    public final MyByteBuffer order(ByteOrder bo) {
-        byteOrder = bo;
-        buf.order(bo);
-        return this;
-    }
-
-    static MyByteBuffer wrap(byte[] bytes) {
-        return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes);
-    }
-
-    int capacity() { return bytes.length; }
-    int position() {
-        if (buf.position() != pos)
-            throw new RuntimeException();
-        return buf.position();
-    }
-
-    byte[] array() { return buf.array(); }
-    byte[] backingArray() { return bytes; }
-
-    private static byte long7(long x) { return (byte)(x >> 56); }
-    private static byte long6(long x) { return (byte)(x >> 48); }
-    private static byte long5(long x) { return (byte)(x >> 40); }
-    private static byte long4(long x) { return (byte)(x >> 32); }
-    private static byte long3(long x) { return (byte)(x >> 24); }
-    private static byte long2(long x) { return (byte)(x >> 16); }
-    private static byte long1(long x) { return (byte)(x >>  8); }
-    private static byte long0(long x) { return (byte)(x      ); }
-
-    private static byte int3(int x) { return (byte)(x >> 24); }
-    private static byte int2(int x) { return (byte)(x >> 16); }
-    private static byte int1(int x) { return (byte)(x >>  8); }
-    private static byte int0(int x) { return (byte)(x      ); }
-
-    private static byte short1(short x) { return (byte)(x >> 8); }
-    private static byte short0(short x) { return (byte)(x     ); }
-
-    byte _get(long i) { return bytes[(int)i]; }
-    void _put(long i, byte x) { bytes[(int)i] = x; }
-
-    private void putLongX(long a, long x) {
-        if (byteOrder == BIG_ENDIAN) {
-            x = Long.reverseBytes(x);
-        }
-        _put(a + 7, long7(x));
-        _put(a + 6, long6(x));
-        _put(a + 5, long5(x));
-        _put(a + 4, long4(x));
-        _put(a + 3, long3(x));
-        _put(a + 2, long2(x));
-        _put(a + 1, long1(x));
-        _put(a    , long0(x));
-    }
-
-    private void putIntX(long a, int x) {
-        if (byteOrder == BIG_ENDIAN) {
-            x = Integer.reverseBytes(x);
-        }
-        _put(a + 3, int3(x));
-        _put(a + 2, int2(x));
-        _put(a + 1, int1(x));
-        _put(a    , int0(x));
-    }
-
-    private void putShortX(int bi, short x) {
-        if (byteOrder == BIG_ENDIAN) {
-            x = Short.reverseBytes(x);
-        }
-        _put(bi    , short0(x));
-        _put(bi + 1, short1(x));
-    }
-
-    static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
-        return (((b3       ) << 24) |
-                ((b2 & 0xff) << 16) |
-                ((b1 & 0xff) <<  8) |
-                ((b0 & 0xff)      ));
-    }
-    int getIntX(long a) {
-        int x = makeInt(_get(a + 3),
-                _get(a + 2),
-                _get(a + 1),
-                _get(a));
-        if (byteOrder == BIG_ENDIAN) {
-            x = Integer.reverseBytes(x);
-        }
-        return x;
-    }
-
-    static private long makeLong(byte b7, byte b6, byte b5, byte b4,
-                                 byte b3, byte b2, byte b1, byte b0)
-    {
-        return ((((long)b7       ) << 56) |
-                (((long)b6 & 0xff) << 48) |
-                (((long)b5 & 0xff) << 40) |
-                (((long)b4 & 0xff) << 32) |
-                (((long)b3 & 0xff) << 24) |
-                (((long)b2 & 0xff) << 16) |
-                (((long)b1 & 0xff) <<  8) |
-                (((long)b0 & 0xff)      ));
-    }
-
-    long getLongX(long a) {
-        long x = makeLong(_get(a + 7),
-                _get(a + 6),
-                _get(a + 5),
-                _get(a + 4),
-                _get(a + 3),
-                _get(a + 2),
-                _get(a + 1),
-                _get(a));
-        if (byteOrder == BIG_ENDIAN) {
-            x = Long.reverseBytes(x);
-        }
-        return x;
-    }
-
-    static private short makeShort(byte b1, byte b0) {
-        return (short)((b1 << 8) | (b0 & 0xff));
-    }
-
-    short getShortX(long a) {
-        short x = makeShort(_get(a + 1),
-                            _get(a    ));
-        if (byteOrder == BIG_ENDIAN) {
-            x = Short.reverseBytes(x);
-        }
-        return x;
-    }
-
-    double getDoubleX(long a) {
-        long x = getLongX(a);
-        return Double.longBitsToDouble(x);
-    }
-
-    double getFloatX(long a) {
-        int x = getIntX(a);
-        return Float.intBitsToFloat(x);
-    }
-
-    void ck(long x, long y) {
-        if (x != y) {
-            throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y));
-        }
-    }
-
-    void ck(double x, double y) {
-        if (x == x && y == y && x != y) {
-            ck(x, y);
-        }
-    }
-
-    long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); }
-    int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); }
-    short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); }
-    char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); }
-    double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); }
-    float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); }
-
-    void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); }
-    void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); }
-    void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); }
-    void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); }
-    void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); }
-    void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); }
-
-    long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; }
-    int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; }
-    short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; }
-    char getChar() {  ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; }
-    double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; }
-    float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; }
-
-    void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); }
-    void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); }
-    void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); }
-    void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); }
-    void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); }
-    void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); }
-
-    void rewind() { pos = 0; buf.rewind(); }
-}
-
-public class HeapByteBufferTest implements Runnable {
-
-    Random random = Utils.getRandomInstance();
-    MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]);
-
-    int randomOffset(Random r, MyByteBuffer buf, int size) {
-        return r.nextInt(buf.capacity() - size);
-    }
-
-    long iterations;
-
-    HeapByteBufferTest(long iterations) {
-        this.iterations = iterations;
-    }
-
-    // The core of the test.  Walk over the buffer reading and writing
-    // random data, XORing it as we go.  We can detect writes in the
-    // wrong place, writes which are too long or too short, and reads
-    // or writes of the wrong data,
-    void step(Random r) {
-        data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN);
-
-        data.rewind();
-        while (data.position() < data.capacity())
-            data.putLong(data.getLong() ^ random.nextLong());
+public class HeapByteBufferTest extends ByteBufferTest {
 
-        data.rewind();
-        while (data.position() < data.capacity())
-            data.putInt(data.getInt() ^ random.nextInt());
-
-        data.rewind();
-        while (data.position() < data.capacity())
-            data.putShort((short)(data.getShort() ^ random.nextInt()));
-
-        data.rewind();
-        while (data.position() < data.capacity())
-            data.putChar((char)(data.getChar() ^ random.nextInt()));
-
-        data.rewind();
-        while (data.position() < data.capacity()) {
-            data.putDouble(combine(data.getDouble(), random.nextLong()));
-        }
-
-        data.rewind();
-        while (data.position() < data.capacity())
-            data.putFloat(combine(data.getFloat(), random.nextInt()));
-
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 8);
-            data.putLong(offset, data.getLong(offset) ^ random.nextLong());
-        }
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 4);
-            data.putInt(offset, data.getInt(offset) ^ random.nextInt());
-        }
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 2);
-            data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt()));
-        }
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 2);
-            data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt()));
-        }
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 8);
-            data.putDouble(offset, combine(data.getDouble(offset), random.nextLong()));
-        }
-        for (int i = 0; i < 100; i++) {
-            int offset = randomOffset(r, data, 4);
-            data.putFloat(offset, combine(data.getFloat(offset), random.nextInt()));
-        }
-    }
-
-    // XOR the bit pattern of a double and a long, returning the
-    // result as a double.
-    //
-    // We convert signalling NaNs to quiet NaNs.  We need to do this
-    // because some platforms (in particular legacy 80x87) do not
-    // provide transparent conversions between integer and
-    // floating-point types even when using raw conversions but
-    // quietly convert sNaN to qNaN.  This causes spurious test
-    // failures when the template interpreter uses 80x87 and the JITs
-    // use XMM registers.
-    //
-    public double combine(double prev, long bits) {
-        bits ^= Double.doubleToRawLongBits(prev);
-        double result = Double.longBitsToDouble(bits);
-        if (Double.isNaN(result)) {
-            result = Double.longBitsToDouble(bits | 0x8000000000000l);
-        }
-        return result;
-    }
-
-    // XOR the bit pattern of a float and an int, returning the result
-    // as a float.  Convert sNaNs to qNaNs.
-    public Float combine(float prev, int bits) {
-        bits ^= Float.floatToRawIntBits(prev);
-        Float result = Float.intBitsToFloat(bits);
-        if (Float.isNaN(result)) {
-            result = Float.intBitsToFloat(bits | 0x400000);
-        }
-        return result;
-    }
-
-    enum PrimitiveType {
-        BYTE(1), CHAR(2), SHORT(2), INT(4), LONG(8), FLOAT(4), DOUBLE(8);
-
-        public final int size;
-        PrimitiveType(int size) {
-            this.size = size;
-        }
-    }
-
-    void getOne(ByteBuffer b, PrimitiveType t) {
-        switch (t) {
-        case BYTE: b.get(); break;
-        case CHAR: b.getChar(); break;
-        case SHORT: b.getShort(); break;
-        case INT: b.getInt(); break;
-        case LONG: b.getLong(); break;
-        case FLOAT: b.getFloat(); break;
-        case DOUBLE: b.getDouble(); break;
-        }
-    }
-
-    void putOne(ByteBuffer b, PrimitiveType t) {
-        switch (t) {
-        case BYTE: b.put((byte)0); break;
-        case CHAR: b.putChar('0'); break;
-        case SHORT: b.putShort((short)0); break;
-        case INT: b.putInt(0); break;
-        case LONG: b.putLong(0); break;
-        case FLOAT: b.putFloat(0); break;
-        case DOUBLE: b.putDouble(0); break;
-        }
-    }
-
-    void getOne(ByteBuffer b, PrimitiveType t, int index) {
-        switch (t) {
-        case BYTE: b.get(index); break;
-        case CHAR: b.getChar(index); break;
-        case SHORT: b.getShort(index); break;
-        case INT: b.getInt(index); break;
-        case LONG: b.getLong(index); break;
-        case FLOAT: b.getFloat(index); break;
-        case DOUBLE: b.getDouble(index); break;
-        }
-    }
-
-    void putOne(ByteBuffer b, PrimitiveType t, int index) {
-        switch (t) {
-        case BYTE: b.put(index, (byte)0); break;
-        case CHAR: b.putChar(index, '0'); break;
-        case SHORT: b.putShort(index, (short)0); break;
-        case INT: b.putInt(index, 0); break;
-        case LONG: b.putLong(index, 0); break;
-        case FLOAT: b.putFloat(index, 0); break;
-        case DOUBLE: b.putDouble(index, 0); break;
-        }
-    }
-
-    void checkBoundaryConditions() {
-        for (int i = 0; i < 100; i++) {
-            int bufSize = random.nextInt(16);
-            byte[] bytes = new byte[bufSize];
-            ByteBuffer buf = ByteBuffer.wrap(bytes);
-            for (int j = 0; j < 100; j++) {
-                int offset = random.nextInt(32) - 8;
-                for (PrimitiveType t : PrimitiveType.values()) {
-                    int threw = 0;
-                    try {
-                        try {
-                            buf.position(offset);
-                            getOne(buf, t);
-                        } catch (BufferUnderflowException e) {
-                            if (offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        } catch (IllegalArgumentException e) {
-                            if (offset >= 0 && offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        }
-
-                        try {
-                            buf.position(offset);
-                            putOne(buf, t);
-                        } catch (BufferOverflowException e) {
-                            if (offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        } catch (IllegalArgumentException e) {
-                            if (offset >= 0 && offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        }
-
-                        try {
-                            putOne(buf, t, offset);
-                        } catch (IndexOutOfBoundsException e) {
-                            if (offset >= 0 && offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        }
-
-                        try {
-                            getOne(buf, t, offset);
-                        } catch (IndexOutOfBoundsException e) {
-                            if (offset >= 0 && offset + t.size < bufSize)
-                                throw new RuntimeException
-                                    ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e);
-                            threw++;
-                        }
-
-                        if (threw == 0) {
-                            // Make sure that we should not have thrown.
-                            if (offset < 0 || offset + t.size > bufSize) {
-                                throw new RuntimeException
-                                    ("should have thrown but did not, type = " + t
-                                     + ", offset = " + offset + ", bufSize = " + bufSize);
-                            }
-                        } else if (threw != 4) {
-                            // If one of the {get,put} operations threw
-                            // due to an invalid offset then all four of
-                            // them should have thrown.
-                            throw new RuntimeException
-                                ("should have thrown but at least one did not, type = " + t
-                                 + ", offset = " + offset + ", bufSize = " + bufSize);
-                        }
-                    } catch (Throwable th) {
-                        throw new RuntimeException
-                            ("unexpected throw: type  = " + t + ", offset = " + offset + ", bufSize = " + bufSize, th);
-
-                    }
-                }
-            }
-        }
-    }
-
-    public void run() {
-        checkBoundaryConditions();
-
-        for (int i = 0; i < data.capacity(); i += 8) {
-            data.putLong(i, random.nextLong());
-        }
-
-        for (int i = 0; i < iterations; i++) {
-            step(random);
-        }
-
-        if (!Arrays.equals(data.array(), data.backingArray())) {
-            throw new RuntimeException();
-        }
+    public HeapByteBufferTest(long iterations, boolean direct) {
+        super(iterations, direct);
     }
 
     public static void main(String[] args) {
@@ -510,6 +45,6 @@
         if (args.length > 0)
             iterations = Long.parseLong(args[0]);
 
-        new HeapByteBufferTest(iterations).run();
+        new HeapByteBufferTest(iterations, false).run();
     }
-}
+}
\ No newline at end of file