8162458: Buffer view implementations use incorrect offset for Unsafe access
authorpsandoz
Fri, 29 Jul 2016 10:18:47 +0200
changeset 40195 a13e4945de1d
parent 40194 7b26e83709cd
child 40197 569ee5564d5a
8162458: Buffer view implementations use incorrect offset for Unsafe access Reviewed-by: alanb
jdk/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
jdk/test/java/nio/Buffer/ByteBufferViews.java
--- a/jdk/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template	Wed Jul 27 13:33:55 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template	Fri Jul 29 10:18:47 2016 +0200
@@ -40,7 +40,6 @@
     private static final Unsafe unsafe = Bits.unsafe();
 
     protected final ByteBuffer bb;
-    protected final int offset;
 
 #end[rw]
 
@@ -55,7 +54,7 @@
         this.limit(cap);
         int pos = this.position();
         assert (pos <= cap);
-        offset = pos;
+        address = bb.address;
 #else[rw]
         super(bb);
 #end[rw]
@@ -63,14 +62,15 @@
 
     ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb,
                                      int mark, int pos, int lim, int cap,
-                                     int off)
+                                     long addr)
     {
 #if[rw]
         super(mark, pos, lim, cap);
         this.bb = bb;
-        offset = off;
+        address = addr;
+        assert address >= bb.address;
 #else[rw]
-        super(bb, mark, pos, lim, cap, off);
+        super(bb, mark, pos, lim, cap, addr);
 #end[rw]
     }
 
@@ -79,9 +79,8 @@
         int lim = this.limit();
         assert (pos <= lim);
         int rem = (pos <= lim ? lim - pos : 0);
-        int off = (pos << $LG_BYTES_PER_VALUE$) + offset;
-        assert (off >= 0);
-        return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, off);
+        long addr = byteOffset(pos);
+        return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr);
     }
 
     public $Type$Buffer duplicate() {
@@ -90,7 +89,7 @@
                                                     this.position(),
                                                     this.limit(),
                                                     this.capacity(),
-                                                    offset);
+                                                    address);
     }
 
     public $Type$Buffer asReadOnlyBuffer() {
@@ -100,7 +99,7 @@
                                                  this.position(),
                                                  this.limit(),
                                                  this.capacity(),
-                                                 offset);
+                                                 address);
 #else[rw]
         return duplicate();
 #end[rw]
@@ -108,12 +107,13 @@
 
 #if[rw]
 
-    protected int ix(int i) {
-        return (i << $LG_BYTES_PER_VALUE$) + offset;
+    private int ix(int i) {
+        int off = (int) (address - bb.address);
+        return (i << $LG_BYTES_PER_VALUE$) + off;
     }
 
-    private long byteOffset(long i) {
-        return (i << $LG_BYTES_PER_VALUE$) + bb.address + offset;
+    protected long byteOffset(long i) {
+        return (i << $LG_BYTES_PER_VALUE$) + address;
     }
 
     public $type$ get() {
@@ -226,7 +226,7 @@
                                                   pos + start,
                                                   pos + end,
                                                   capacity(),
-                                                  offset);
+                                                  address);
     }
 
 #end[char]
--- a/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template	Wed Jul 27 13:33:55 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template	Fri Jul 29 10:18:47 2016 +0200
@@ -88,13 +88,13 @@
                                                                        0,
                                                                        size,
                                                                        size,
-                                                                       off))
+                                                                       address + off))
                     : ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this,
                                                                        -1,
                                                                        0,
                                                                        size,
                                                                        size,
-                                                                       off)));
+                                                                       address + off)));
         } else {
             return (nativeByteOrder
                     ? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this,
--- a/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template	Wed Jul 27 13:33:55 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template	Fri Jul 29 10:18:47 2016 +0200
@@ -325,20 +325,20 @@
 
     public CharBuffer asCharBuffer() {
         int size = this.remaining() >> 1;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (CharBuffer)(new ByteBufferAsCharBuffer$RW$B(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               off))
+                                                               addr))
                 : (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               off)));
+                                                               addr)));
     }
 
 
@@ -376,20 +376,20 @@
 
     public ShortBuffer asShortBuffer() {
         int size = this.remaining() >> 1;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (ShortBuffer)(new ByteBufferAsShortBuffer$RW$B(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off))
+                                                                 addr))
                 : (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off)));
+                                                                 addr)));
     }
 
 
@@ -427,20 +427,20 @@
 
     public IntBuffer asIntBuffer() {
         int size = this.remaining() >> 2;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (IntBuffer)(new ByteBufferAsIntBuffer$RW$B(this,
                                                              -1,
                                                              0,
                                                              size,
                                                              size,
-                                                             off))
+                                                             addr))
                 : (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this,
                                                              -1,
                                                              0,
                                                              size,
                                                              size,
-                                                             off)));
+                                                             addr)));
     }
 
 
@@ -478,20 +478,20 @@
 
     public LongBuffer asLongBuffer() {
         int size = this.remaining() >> 3;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (LongBuffer)(new ByteBufferAsLongBuffer$RW$B(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               off))
+                                                               addr))
                 : (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this,
                                                                -1,
                                                                0,
                                                                size,
                                                                size,
-                                                               off)));
+                                                               addr)));
     }
 
 
@@ -533,20 +533,20 @@
 
     public FloatBuffer asFloatBuffer() {
         int size = this.remaining() >> 2;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$B(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off))
+                                                                 addr))
                 : (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this,
                                                                  -1,
                                                                  0,
                                                                  size,
                                                                  size,
-                                                                 off)));
+                                                                 addr)));
     }
 
 
@@ -588,20 +588,20 @@
 
     public DoubleBuffer asDoubleBuffer() {
         int size = this.remaining() >> 3;
-        int off = offset + position();
+        long addr = address + position();
         return (bigEndian
                 ? (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$B(this,
                                                                    -1,
                                                                    0,
                                                                    size,
                                                                    size,
-                                                                   off))
+                                                                   addr))
                 : (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this,
                                                                    -1,
                                                                    0,
                                                                    size,
                                                                    size,
-                                                                   off)));
+                                                                   addr)));
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/Buffer/ByteBufferViews.java	Fri Jul 29 10:18:47 2016 +0200
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 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
+ * 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
+ * @summary Binary data and view tests for byte buffers
+ * @bug 8159257
+ * @run testng ByteBufferViews
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.nio.Buffer;
+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.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+
+import static org.testng.Assert.*;
+
+public class ByteBufferViews {
+    static final int SIZE = 32;
+
+    // List of buffer allocator functions
+    static final List<Map.Entry<String, IntFunction<ByteBuffer>>> BYTE_BUFFER_ALLOCATE_FUNCTIONS = List.of(
+            // Heap
+            Map.entry("ByteBuffer.allocate(ba)",
+                      size -> ByteBuffer.allocate(size)),
+            // Aligned
+            Map.entry("ByteBuffer.allocate(size).position(8)",
+                      size -> ByteBuffer.allocate(size).position(8)),
+            Map.entry("ByteBuffer.allocate(size).position(8).slice()",
+                      size -> ByteBuffer.allocate(size).position(8).slice()),
+            Map.entry("ByteBuffer.allocate(size).position(8).slice().duplicate()",
+                      size -> ByteBuffer.allocate(size).position(8).slice().duplicate()),
+            // Unaligned
+            Map.entry("ByteBuffer.allocate(size).position(1)",
+                      size -> ByteBuffer.allocate(size).position(1)),
+            Map.entry("ByteBuffer.allocate(size).position(1).slice()",
+                      size -> ByteBuffer.allocate(size).position(1).slice()),
+            Map.entry("ByteBuffer.allocate(size).position(1).slice().duplicate()",
+                      size -> ByteBuffer.allocate(size).position(1).slice().duplicate()),
+
+            // Off-heap
+            Map.entry("ByteBuffer.allocateDirect(size)",
+                      size -> ByteBuffer.allocateDirect(size)),
+            // Aligned
+            Map.entry("ByteBuffer.allocateDirect(size).position(8)",
+                      size -> ByteBuffer.allocateDirect(size).position(8)),
+            Map.entry("ByteBuffer.allocateDirect(size).position(8).slice()",
+                      size -> ByteBuffer.allocateDirect(size).position(8).slice()),
+            Map.entry("ByteBuffer.allocateDirect(size).position(8).slice().duplicate()",
+                      size -> ByteBuffer.allocateDirect(size).position(8).slice().duplicate()),
+            // Unaligned
+            Map.entry("ByteBuffer.allocateDirect(size).position(1)",
+                      size -> ByteBuffer.allocateDirect(size).position(1)),
+            Map.entry("ByteBuffer.allocateDirect(size).position(1).slice()",
+                      size -> ByteBuffer.allocateDirect(size).position(1).slice()),
+            Map.entry("ByteBuffer.allocateDirect(size).position(1).slice().duplicate()",
+                      size -> ByteBuffer.allocateDirect(size).position(1).slice().duplicate())
+    );
+
+    // List of buffer byte order functions
+    static final List<Map.Entry<String, UnaryOperator<ByteBuffer>>> BYTE_BUFFER_ORDER_FUNCTIONS = List.of(
+            Map.entry("order(ByteOrder.BIG_ENDIAN)",
+                      (ByteBuffer bb) -> bb.order(ByteOrder.BIG_ENDIAN)),
+            Map.entry("order(ByteOrder.LITTLE_ENDIAN)",
+                      (ByteBuffer bb) -> bb.order(ByteOrder.LITTLE_ENDIAN))
+    );
+
+    // Produce a composition of allocation and byte order buffer functions
+    static List<Map.Entry<String, IntFunction<ByteBuffer>>> composeBufferFunctions(
+            List<Map.Entry<String, IntFunction<ByteBuffer>>> af,
+            List<Map.Entry<String, UnaryOperator<ByteBuffer>>> of) {
+        return af.stream().flatMap(afe -> of.stream().
+                map(ofe -> {
+                    String s = afe.getKey() + "." + ofe.getKey();
+                    IntFunction<ByteBuffer> f = size -> ofe.getValue().
+                            apply(afe.getValue().apply(size));
+                    return Map.entry(s, f);
+                })
+        ).collect(Collectors.toList());
+    }
+
+    // List of buffer allocator functions to test
+    static final List<Map.Entry<String, IntFunction<ByteBuffer>>> BYTE_BUFFER_FUNCTIONS =
+            composeBufferFunctions(BYTE_BUFFER_ALLOCATE_FUNCTIONS, BYTE_BUFFER_ORDER_FUNCTIONS);
+
+    // Creates a cross product of test arguments for
+    // buffer allocator functions and buffer view functions
+    static Object[][] product(List<? extends Map.Entry<String, ?>> la,
+                              List<? extends Map.Entry<String, ?>> lb) {
+        return la.stream().flatMap(lae -> lb.stream().
+                map(lbe -> List.of(
+                        lae.getKey() + " -> " + lbe.getKey(),
+                        lae.getValue(),
+                        lbe.getValue()).toArray()
+                )).toArray(Object[][]::new);
+    }
+
+    static void assertValues(int i, Object bValue, Object bbValue, ByteBuffer bb) {
+        if (!bValue.equals(bbValue)) {
+            fail(String.format("Values %s and %s differ at index %d for %s",
+                               bValue, bbValue, i, bb));
+        }
+    }
+
+    static void assertValues(int i, Object bbValue, Object bvValue, ByteBuffer bb, Buffer bv) {
+        if (!bbValue.equals(bvValue)) {
+            fail(String.format("Values %s and %s differ at index %d for %s and %s",
+                               bbValue, bvValue, i, bb, bv));
+        }
+    }
+
+    static ByteBuffer allocate(IntFunction<ByteBuffer> f) {
+        return allocate(f, i -> i);
+    }
+
+    static ByteBuffer allocate(IntFunction<ByteBuffer> f, IntUnaryOperator o) {
+        return fill(f.apply(SIZE), o);
+    }
+
+    static ByteBuffer fill(ByteBuffer bb, IntUnaryOperator o) {
+        for (int i = 0; i < bb.limit(); i++) {
+            bb.put(i, (byte) o.applyAsInt(i));
+        }
+        return bb;
+    }
+
+
+    @DataProvider
+    public static Object[][] shortViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, ShortBuffer>>> bfs = List.of(
+                Map.entry("bb.asShortBuffer()",
+                          bb -> bb.asShortBuffer()),
+                Map.entry("bb.asShortBuffer().slice()",
+                          bb -> bb.asShortBuffer().slice()),
+                Map.entry("bb.asShortBuffer().slice().duplicate()",
+                          bb -> bb.asShortBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "shortViewProvider")
+    public void testShortGet(String desc, IntFunction<ByteBuffer> fbb,
+                             Function<ByteBuffer, ShortBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        ShortBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short fromBytes = getShortFromBytes(bb, o + i * 2);
+            short fromMethodView = bb.getShort(o + i * 2);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            short fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short v = getShortFromBytes(bb, o + i * 2);
+            short a = bb.getShort();
+            assertValues(i, v, a, bb);
+
+            short b = vb.get();
+            assertValues(i, a, b, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "shortViewProvider")
+    public void testShortPut(String desc, IntFunction<ByteBuffer> fbb,
+                             Function<ByteBuffer, ShortBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        ShortBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short fromFilled = bbfilled.getShort(o + i * 2);
+
+            vb.put(i, fromFilled);
+            short fromMethodView = bb.getShort(o + i * 2);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short fromFilled = bbfilled.getShort(o + i * 2);
+
+            vb.put(fromFilled);
+            short fromMethodView = bb.getShort();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short fromFilled = bbfilled.getShort(o + i * 2);
+
+            bb.putShort(o + i * 2, fromFilled);
+            short fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            short fromFilled = bbfilled.getShort(o + i * 2);
+
+            bb.putShort(fromFilled);
+            short fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static short getShortFromBytes(ByteBuffer bb, int i) {
+        int a = bb.get(i) & 0xFF;
+        int b = bb.get(i + 1) & 0xFF;
+
+        if (bb.order() == ByteOrder.BIG_ENDIAN) {
+            return (short) ((a << 8) | b);
+        }
+        else {
+            return (short) ((b << 8) | a);
+        }
+    }
+
+    @DataProvider
+    public static Object[][] charViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, CharBuffer>>> bfs = List.of(
+                Map.entry("bb.asCharBuffer()",
+                          bb -> bb.asCharBuffer()),
+                Map.entry("bb.asCharBuffer().slice()",
+                          bb -> bb.asCharBuffer().slice()),
+                Map.entry("bb.asCharBuffer().slice().duplicate()",
+                          bb -> bb.asCharBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "charViewProvider")
+    public void testCharGet(String desc, IntFunction<ByteBuffer> fbb,
+                            Function<ByteBuffer, CharBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        CharBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromBytes = getCharFromBytes(bb, o + i * 2);
+            char fromMethodView = bb.getChar(o + i * 2);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            char fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromBytes = getCharFromBytes(bb, o + i * 2);
+            char fromMethodView = bb.getChar();
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            char fromBufferView = vb.get();
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "charViewProvider")
+    public void testCharPut(String desc, IntFunction<ByteBuffer> fbb,
+                            Function<ByteBuffer, CharBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        CharBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromFilled = bbfilled.getChar(o + i * 2);
+
+            vb.put(i, fromFilled);
+            char fromMethodView = bb.getChar(o + i * 2);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromFilled = bbfilled.getChar(o + i * 2);
+
+            vb.put(fromFilled);
+            char fromMethodView = bb.getChar();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromFilled = bbfilled.getChar(o + i * 2);
+
+            bb.putChar(o + i * 2, fromFilled);
+            char fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            char fromFilled = bbfilled.getChar(o + i * 2);
+
+            bb.putChar(fromFilled);
+            char fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static char getCharFromBytes(ByteBuffer bb, int i) {
+        return (char) getShortFromBytes(bb, i);
+    }
+
+
+    @DataProvider
+    public static Object[][] intViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, IntBuffer>>> bfs = List.of(
+                Map.entry("bb.asIntBuffer()",
+                          bb -> bb.asIntBuffer()),
+                Map.entry("bb.asIntBuffer().slice()",
+                          bb -> bb.asIntBuffer().slice()),
+                Map.entry("bb.asIntBuffer().slice().duplicate()",
+                          bb -> bb.asIntBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "intViewProvider")
+    public void testIntGet(String desc, IntFunction<ByteBuffer> fbb,
+                           Function<ByteBuffer, IntBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        IntBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int fromBytes = getIntFromBytes(bb, o + i * 4);
+            int fromMethodView = bb.getInt(o + i * 4);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            int fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int v = getIntFromBytes(bb, o + i * 4);
+            int a = bb.getInt();
+            assertValues(i, v, a, bb);
+
+            int b = vb.get();
+            assertValues(i, a, b, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "intViewProvider")
+    public void testIntPut(String desc, IntFunction<ByteBuffer> fbb,
+                           Function<ByteBuffer, IntBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        IntBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int fromFilled = bbfilled.getInt(o + i * 4);
+
+            vb.put(i, fromFilled);
+            int fromMethodView = bb.getInt(o + i * 4);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int fromFilled = bbfilled.getInt(o + i * 4);
+
+            vb.put(fromFilled);
+            int fromMethodView = bb.getInt();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int fromFilled = bbfilled.getInt(o + i * 4);
+
+            bb.putInt(o + i * 4, fromFilled);
+            int fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            int fromFilled = bbfilled.getInt(o + i * 4);
+
+            bb.putInt(fromFilled);
+            int fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static int getIntFromBytes(ByteBuffer bb, int i) {
+        int a = bb.get(i) & 0xFF;
+        int b = bb.get(i + 1) & 0xFF;
+        int c = bb.get(i + 2) & 0xFF;
+        int d = bb.get(i + 3) & 0xFF;
+
+        if (bb.order() == ByteOrder.BIG_ENDIAN) {
+            return ((a << 24) | (b << 16) | (c << 8) | d);
+        }
+        else {
+            return ((d << 24) | (c << 16) | (b << 8) | a);
+        }
+    }
+
+
+    @DataProvider
+    public static Object[][] longViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, LongBuffer>>> bfs = List.of(
+                Map.entry("bb.asLongBuffer()",
+                          bb -> bb.asLongBuffer()),
+                Map.entry("bb.asLongBuffer().slice()",
+                          bb -> bb.asLongBuffer().slice()),
+                Map.entry("bb.asLongBuffer().slice().duplicate()",
+                          bb -> bb.asLongBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "longViewProvider")
+    public void testLongGet(String desc, IntFunction<ByteBuffer> fbb,
+                            Function<ByteBuffer, LongBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        LongBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long fromBytes = getLongFromBytes(bb, o + i * 8);
+            long fromMethodView = bb.getLong(o + i * 8);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            long fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long v = getLongFromBytes(bb, o + i * 8);
+            long a = bb.getLong();
+            assertValues(i, v, a, bb);
+
+            long b = vb.get();
+            assertValues(i, a, b, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "longViewProvider")
+    public void testLongPut(String desc, IntFunction<ByteBuffer> fbb,
+                            Function<ByteBuffer, LongBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        LongBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long fromFilled = bbfilled.getLong(o + i * 8);
+
+            vb.put(i, fromFilled);
+            long fromMethodView = bb.getLong(o + i * 8);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long fromFilled = bbfilled.getLong(o + i * 8);
+
+            vb.put(fromFilled);
+            long fromMethodView = bb.getLong();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long fromFilled = bbfilled.getLong(o + i * 8);
+
+            bb.putLong(o + i * 8, fromFilled);
+            long fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            long fromFilled = bbfilled.getLong(o + i * 8);
+
+            bb.putLong(fromFilled);
+            long fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static long getLongFromBytes(ByteBuffer bb, int i) {
+        long a = bb.get(i) & 0xFF;
+        long b = bb.get(i + 1) & 0xFF;
+        long c = bb.get(i + 2) & 0xFF;
+        long d = bb.get(i + 3) & 0xFF;
+        long e = bb.get(i + 4) & 0xFF;
+        long f = bb.get(i + 5) & 0xFF;
+        long g = bb.get(i + 6) & 0xFF;
+        long h = bb.get(i + 7) & 0xFF;
+
+        if (bb.order() == ByteOrder.BIG_ENDIAN) {
+            return ((a << 56) | (b << 48) | (c << 40) | (d << 32) |
+                    (e << 24) | (f << 16) | (g << 8) | h);
+        }
+        else {
+            return ((h << 56) | (g << 48) | (f << 40) | (e << 32) |
+                    (d << 24) | (c << 16) | (b << 8) | a);
+        }
+    }
+
+
+    @DataProvider
+    public static Object[][] floatViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, FloatBuffer>>> bfs = List.of(
+                Map.entry("bb.asFloatBuffer()",
+                          bb -> bb.asFloatBuffer()),
+                Map.entry("bb.asFloatBuffer().slice()",
+                          bb -> bb.asFloatBuffer().slice()),
+                Map.entry("bb.asFloatBuffer().slice().duplicate()",
+                          bb -> bb.asFloatBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "floatViewProvider")
+    public void testFloatGet(String desc, IntFunction<ByteBuffer> fbb,
+                             Function<ByteBuffer, FloatBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        FloatBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float fromBytes = getFloatFromBytes(bb, o + i * 4);
+            float fromMethodView = bb.getFloat(o + i * 4);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            float fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float v = getFloatFromBytes(bb, o + i * 4);
+            float a = bb.getFloat();
+            assertValues(i, v, a, bb);
+
+            float b = vb.get();
+            assertValues(i, a, b, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "floatViewProvider")
+    public void testFloatPut(String desc, IntFunction<ByteBuffer> fbb,
+                             Function<ByteBuffer, FloatBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        FloatBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float fromFilled = bbfilled.getFloat(o + i * 4);
+
+            vb.put(i, fromFilled);
+            float fromMethodView = bb.getFloat(o + i * 4);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float fromFilled = bbfilled.getFloat(o + i * 4);
+
+            vb.put(fromFilled);
+            float fromMethodView = bb.getFloat();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float fromFilled = bbfilled.getFloat(o + i * 4);
+
+            bb.putFloat(o + i * 4, fromFilled);
+            float fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            float fromFilled = bbfilled.getFloat(o + i * 4);
+
+            bb.putFloat(fromFilled);
+            float fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static float getFloatFromBytes(ByteBuffer bb, int i) {
+        return Float.intBitsToFloat(getIntFromBytes(bb, i));
+    }
+
+
+
+    @DataProvider
+    public static Object[][] doubleViewProvider() {
+        List<Map.Entry<String, Function<ByteBuffer, DoubleBuffer>>> bfs = List.of(
+                Map.entry("bb.asDoubleBuffer()",
+                          bb -> bb.asDoubleBuffer()),
+                Map.entry("bb.asDoubleBuffer().slice()",
+                          bb -> bb.asDoubleBuffer().slice()),
+                Map.entry("bb.asDoubleBuffer().slice().duplicate()",
+                          bb -> bb.asDoubleBuffer().slice().duplicate())
+        );
+
+        return product(BYTE_BUFFER_FUNCTIONS, bfs);
+    }
+
+    @Test(dataProvider = "doubleViewProvider")
+    public void testDoubleGet(String desc, IntFunction<ByteBuffer> fbb,
+                              Function<ByteBuffer, DoubleBuffer> fbi) {
+        ByteBuffer bb = allocate(fbb);
+        DoubleBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double fromBytes = getDoubleFromBytes(bb, o + i * 8);
+            double fromMethodView = bb.getDouble(o + i * 8);
+            assertValues(i, fromBytes, fromMethodView, bb);
+
+            double fromBufferView = vb.get(i);
+            assertValues(i, fromMethodView, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double v = getDoubleFromBytes(bb, o + i * 8);
+            double a = bb.getDouble();
+            assertValues(i, v, a, bb);
+
+            double b = vb.get();
+            assertValues(i, a, b, bb, vb);
+        }
+
+    }
+
+    @Test(dataProvider = "doubleViewProvider")
+    public void testDoublePut(String desc, IntFunction<ByteBuffer> fbb,
+                              Function<ByteBuffer, DoubleBuffer> fbi) {
+        ByteBuffer bbfilled = allocate(fbb);
+        ByteBuffer bb = allocate(fbb, i -> 0);
+        DoubleBuffer vb = fbi.apply(bb);
+        int o = bb.position();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double fromFilled = bbfilled.getDouble(o + i * 8);
+
+            vb.put(i, fromFilled);
+            double fromMethodView = bb.getDouble(o + i * 8);
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double fromFilled = bbfilled.getDouble(o + i * 8);
+
+            vb.put(fromFilled);
+            double fromMethodView = bb.getDouble();
+            assertValues(i, fromFilled, fromMethodView, bb, vb);
+        }
+
+
+        fill(bb, i -> 0);
+        bb.clear().position(o);
+        vb.clear();
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double fromFilled = bbfilled.getDouble(o + i * 8);
+
+            bb.putDouble(o + i * 8, fromFilled);
+            double fromBufferView = vb.get(i);
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+
+        for (int i = 0; i < vb.limit(); i++) {
+            double fromFilled = bbfilled.getDouble(o + i * 8);
+
+            bb.putDouble(fromFilled);
+            double fromBufferView = vb.get();
+            assertValues(i, fromFilled, fromBufferView, bb, vb);
+        }
+    }
+
+    static double getDoubleFromBytes(ByteBuffer bb, int i) {
+        return Double.longBitsToDouble(getLongFromBytes(bb, i));
+    }
+}