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