1 //
   2 // Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
   3 // Copyright (c) 2015, Red Hat Inc. All rights reserved.
   4 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 //
   6 // This code is free software; you can redistribute it and/or modify it
   7 // under the terms of the GNU General Public License version 2 only, as
   8 // published by the Free Software Foundation.
   9 //
  10 // This code is distributed in the hope that it will be useful, but WITHOUT
  11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13 // version 2 for more details (a copy is included in the LICENSE file that
  14 // accompanied this code).
  15 //
  16 // You should have received a copy of the GNU General Public License version
  17 // 2 along with this work; if not, write to the Free Software Foundation,
  18 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19 //
  20 // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21 // or visit www.oracle.com if you need additional information or have any
  22 // questions.
  23 //
  24 //
  25 
  26 
  27 import static java.lang.Math.abs;
  28 import java.nio.ByteBuffer;
  29 import java.nio.ByteOrder;
  30 import static java.nio.ByteOrder.BIG_ENDIAN;
  31 import static java.nio.ByteOrder.LITTLE_ENDIAN;
  32 import java.util.SplittableRandom;
  33 import java.util.Arrays;
  34 
  35 /**
  36  * @test
  37  * @bug 8026049
  38  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses HeapByteBufferTest
  39  * @run main/othervm HeapByteBufferTest
  40  * @summary Verify that byte buffers are correctly accessed.
  41  */
  42 
  43 // A wrapper for a ByteBuffer which maintains a backing array and a
  44 // position.  Whenever this wrapper is written the backing array and
  45 // the wrapped byte buffer are updated together, and whenever it is
  46 // read we check that the ByteBuffer and the backing array are identical.
  47 
  48 class MyByteBuffer {
  49     final ByteBuffer buf;
  50     final byte[] bytes;
  51     int pos;
  52     ByteOrder byteOrder = BIG_ENDIAN;
  53 
  54     MyByteBuffer(ByteBuffer buf, byte[] bytes) {
  55         this.buf = buf;
  56         this.bytes = Arrays.copyOf(bytes, bytes.length);
  57         pos = 0;
  58     }
  59 
  60     public final MyByteBuffer order(ByteOrder bo) {
  61         byteOrder = bo;
  62         buf.order(bo);
  63         return this;
  64     }
  65 
  66     static MyByteBuffer wrap(byte[] bytes) {
  67         return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes);
  68     }
  69 
  70     int capacity() { return bytes.length; }
  71     int position() {
  72         if (buf.position() != pos)
  73             throw new RuntimeException();
  74         return buf.position();
  75     }
  76 
  77     byte[] array() { return buf.array(); }
  78     byte[] backingArray() { return bytes; }
  79 
  80     private static byte long7(long x) { return (byte)(x >> 56); }
  81     private static byte long6(long x) { return (byte)(x >> 48); }
  82     private static byte long5(long x) { return (byte)(x >> 40); }
  83     private static byte long4(long x) { return (byte)(x >> 32); }
  84     private static byte long3(long x) { return (byte)(x >> 24); }
  85     private static byte long2(long x) { return (byte)(x >> 16); }
  86     private static byte long1(long x) { return (byte)(x >>  8); }
  87     private static byte long0(long x) { return (byte)(x      ); }
  88 
  89     private static byte int3(int x) { return (byte)(x >> 24); }
  90     private static byte int2(int x) { return (byte)(x >> 16); }
  91     private static byte int1(int x) { return (byte)(x >>  8); }
  92     private static byte int0(int x) { return (byte)(x      ); }
  93 
  94     private static byte short1(short x) { return (byte)(x >> 8); }
  95     private static byte short0(short x) { return (byte)(x     ); }
  96 
  97     byte _get(long i) { return bytes[(int)i]; }
  98     void _put(long i, byte x) { bytes[(int)i] = x; }
  99 
 100     private void putLongX(long a, long x) {
 101         if (byteOrder == BIG_ENDIAN) {
 102             x = Long.reverseBytes(x);
 103         }
 104         _put(a + 7, long7(x));
 105         _put(a + 6, long6(x));
 106         _put(a + 5, long5(x));
 107         _put(a + 4, long4(x));
 108         _put(a + 3, long3(x));
 109         _put(a + 2, long2(x));
 110         _put(a + 1, long1(x));
 111         _put(a    , long0(x));
 112     }
 113 
 114     private void putIntX(long a, int x) {
 115         if (byteOrder == BIG_ENDIAN) {
 116             x = Integer.reverseBytes(x);
 117         }
 118         _put(a + 3, int3(x));
 119         _put(a + 2, int2(x));
 120         _put(a + 1, int1(x));
 121         _put(a    , int0(x));
 122     }
 123 
 124     private void putShortX(int bi, short x) {
 125         if (byteOrder == BIG_ENDIAN) {
 126             x = Short.reverseBytes(x);
 127         }
 128         _put(bi    , short0(x));
 129         _put(bi + 1, short1(x));
 130     }
 131 
 132     static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
 133         return (((b3       ) << 24) |
 134                 ((b2 & 0xff) << 16) |
 135                 ((b1 & 0xff) <<  8) |
 136                 ((b0 & 0xff)      ));
 137     }
 138     int getIntX(long a) {
 139         int x = makeInt(_get(a + 3),
 140                 _get(a + 2),
 141                 _get(a + 1),
 142                 _get(a));
 143         if (byteOrder == BIG_ENDIAN) {
 144             x = Integer.reverseBytes(x);
 145         }
 146         return x;
 147     }
 148 
 149     static private long makeLong(byte b7, byte b6, byte b5, byte b4,
 150                                  byte b3, byte b2, byte b1, byte b0)
 151     {
 152         return ((((long)b7       ) << 56) |
 153                 (((long)b6 & 0xff) << 48) |
 154                 (((long)b5 & 0xff) << 40) |
 155                 (((long)b4 & 0xff) << 32) |
 156                 (((long)b3 & 0xff) << 24) |
 157                 (((long)b2 & 0xff) << 16) |
 158                 (((long)b1 & 0xff) <<  8) |
 159                 (((long)b0 & 0xff)      ));
 160     }
 161 
 162     long getLongX(long a) {
 163         long x = makeLong(_get(a + 7),
 164                 _get(a + 6),
 165                 _get(a + 5),
 166                 _get(a + 4),
 167                 _get(a + 3),
 168                 _get(a + 2),
 169                 _get(a + 1),
 170                 _get(a));
 171         if (byteOrder == BIG_ENDIAN) {
 172             x = Long.reverseBytes(x);
 173         }
 174         return x;
 175     }
 176 
 177     static private short makeShort(byte b1, byte b0) {
 178         return (short)((b1 << 8) | (b0 & 0xff));
 179     }
 180 
 181     short getShortX(long a) {
 182         short x = makeShort(_get(a + 1),
 183                             _get(a    ));
 184         if (byteOrder == BIG_ENDIAN) {
 185             x = Short.reverseBytes(x);
 186         }
 187         return x;
 188     }
 189 
 190     double getDoubleX(long a) {
 191         long x = getLongX(a);
 192         return Double.longBitsToDouble(x);
 193     }
 194 
 195     double getFloatX(long a) {
 196         int x = getIntX(a);
 197         return Float.intBitsToFloat(x);
 198     }
 199 
 200     void ck(long x, long y) {
 201         if (x != y) {
 202             throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y));
 203         }
 204     }
 205 
 206     void ck(double x, double y) {
 207         if (x == x && y == y && x != y) {
 208             ck(x, y);
 209         }
 210     }
 211 
 212     long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); }
 213     int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); }
 214     short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); }
 215     char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); }
 216     double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); }
 217     float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); }
 218 
 219     void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); }
 220     void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); }
 221     void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); }
 222     void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); }
 223     void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); }
 224     void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); }
 225 
 226     long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; }
 227     int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; }
 228     short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; }
 229     char getChar() {  ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; }
 230     double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; }
 231     float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; }
 232 
 233     void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); }
 234     void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); }
 235     void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); }
 236     void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); }
 237     void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); }
 238     void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); }
 239 
 240     void rewind() { pos = 0; buf.rewind(); }
 241 }
 242 
 243 public class HeapByteBufferTest implements Runnable {
 244 
 245     SplittableRandom random = new SplittableRandom();
 246     MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]);
 247 
 248     int randomOffset(SplittableRandom r, MyByteBuffer buf, int size) {
 249         return abs(r.nextInt()) % (buf.capacity() - size);
 250     }
 251 
 252     long iterations;
 253 
 254     HeapByteBufferTest(long iterations) {
 255         this.iterations = iterations;
 256     }
 257 
 258     // The core of the test.  Walk over the buffer reading and writing
 259     // random data, XORing it as we go.  We can detect writes in the
 260     // wrong place, writes which are too long or too short, and reads
 261     // or writes of the wrong data,
 262     void step(SplittableRandom r) {
 263         data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN);
 264 
 265         data.rewind();
 266         while (data.position() < data.capacity())
 267             data.putLong(data.getLong() ^ random.nextLong());
 268 
 269         data.rewind();
 270         while (data.position() < data.capacity())
 271             data.putInt(data.getInt() ^ random.nextInt());
 272 
 273         data.rewind();
 274         while (data.position() < data.capacity())
 275             data.putShort((short)(data.getShort() ^ random.nextInt()));
 276 
 277         data.rewind();
 278         while (data.position() < data.capacity())
 279             data.putChar((char)(data.getChar() ^ random.nextInt()));
 280 
 281         data.rewind();
 282         while (data.position() < data.capacity()) {
 283             data.putDouble(combine(data.getDouble(), random.nextLong()));
 284         }
 285 
 286         data.rewind();
 287         while (data.position() < data.capacity())
 288             data.putFloat(combine(data.getFloat(), random.nextInt()));
 289 
 290         for (int i = 0; i < 100; i++) {
 291             int offset = randomOffset(r, data, 8);
 292             data.putLong(offset, data.getLong(offset) ^ random.nextLong());
 293         }
 294         for (int i = 0; i < 100; i++) {
 295             int offset = randomOffset(r, data, 4);
 296             data.putInt(offset, data.getInt(offset) ^ random.nextInt());
 297         }
 298         for (int i = 0; i < 100; i++) {
 299             int offset = randomOffset(r, data, 4);
 300             data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt()));
 301         }
 302         for (int i = 0; i < 100; i++) {
 303             int offset = randomOffset(r, data, 4);
 304             data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt()));
 305         }
 306         for (int i = 0; i < 100; i++) {
 307             int offset = randomOffset(r, data, 8);
 308             data.putDouble(offset, combine(data.getDouble(offset), random.nextLong()));
 309         }
 310         for (int i = 0; i < 100; i++) {
 311             int offset = randomOffset(r, data, 4);
 312             data.putFloat(offset, combine(data.getFloat(offset), random.nextInt()));
 313         }
 314     }
 315 
 316     // XOR the bit pattern of a double and a long, returning the
 317     // result as a double.
 318     //
 319     // We convert signalling NaNs to quiet NaNs.  We need to do this
 320     // because some platforms (in particular legacy 80x87) do not
 321     // provide transparent conversions between integer and
 322     // floating-point types even when using raw conversions but
 323     // quietly convert sNaN to qNaN.  This causes spurious test
 324     // failures when the template interpreter uses 80x87 and the JITs
 325     // use XMM registers.
 326     //
 327     public double combine(double prev, long bits) {
 328         bits ^= Double.doubleToRawLongBits(prev);
 329         double result = Double.longBitsToDouble(bits);
 330         if (Double.isNaN(result)) {
 331             result = Double.longBitsToDouble(bits | 0x8000000000000l);
 332         }
 333         return result;
 334     }
 335 
 336     // XOR the bit pattern of a float and an int, returning the result
 337     // as a float.  Convert sNaNs to qNaNs.
 338     public Float combine(float prev, int bits) {
 339         bits ^= Float.floatToRawIntBits(prev);
 340         Float result = Float.intBitsToFloat(bits);
 341         if (Float.isNaN(result)) {
 342             result = Float.intBitsToFloat(bits | 0x400000);
 343         }
 344         return result;
 345     }
 346 
 347     public void run() {
 348         SplittableRandom r = new SplittableRandom();
 349 
 350         for (int i = 0; i < data.capacity(); i += 8) {
 351             data.putLong(i, random.nextLong());
 352         }
 353 
 354         for (int i = 0; i < iterations; i++) {
 355             step(r);
 356         }
 357 
 358         if (!Arrays.equals(data.array(), data.backingArray())) {
 359             throw new RuntimeException();
 360         }
 361     }
 362 
 363     public static void main(String[] args) {
 364         // The number of iterations is high to ensure that tiered
 365         // compilation kicks in all the way up to C2.
 366         long iterations = 100000;
 367         if (args.length > 0)
 368             iterations = Long.parseLong(args[0]);
 369 
 370         new HeapByteBufferTest(iterations).run();
 371     }
 372 }