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 }