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 java.nio.BufferOverflowException; 27 import java.nio.BufferUnderflowException; 28 import java.nio.ByteBuffer; 29 import static java.nio.ByteOrder.BIG_ENDIAN; 30 import static java.nio.ByteOrder.LITTLE_ENDIAN; 31 import java.nio.ByteOrder; 32 import java.util.Arrays; 33 import java.util.Random; 34 import jdk.test.lib.Utils; 35 36 /** 37 * @test 38 * @bug 8026049 39 * @modules java.base/jdk.internal.misc 40 * @library /testlibrary 41 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses -Djdk.test.lib.random.seed=0 HeapByteBufferTest 42 * @run main/othervm -Djdk.test.lib.random.seed=0 HeapByteBufferTest 43 * @summary Verify that byte buffers are correctly accessed. 44 */ 45 46 // A wrapper for a ByteBuffer which maintains a backing array and a 47 // position. Whenever this wrapper is written the backing array and 48 // the wrapped byte buffer are updated together, and whenever it is 49 // read we check that the ByteBuffer and the backing array are identical. 50 51 class MyByteBuffer { 52 final ByteBuffer buf; 53 final byte[] bytes; 54 int pos; 55 ByteOrder byteOrder = BIG_ENDIAN; 56 57 MyByteBuffer(ByteBuffer buf, byte[] bytes) { 58 this.buf = buf; 59 this.bytes = Arrays.copyOf(bytes, bytes.length); 60 pos = 0; 61 } 62 63 public final MyByteBuffer order(ByteOrder bo) { 64 byteOrder = bo; 65 buf.order(bo); 66 return this; 67 } 68 69 static MyByteBuffer wrap(byte[] bytes) { 70 return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes); 71 } 72 73 int capacity() { return bytes.length; } 74 int position() { 75 if (buf.position() != pos) 76 throw new RuntimeException(); 77 return buf.position(); 78 } 79 80 byte[] array() { return buf.array(); } 81 byte[] backingArray() { return bytes; } 82 83 private static byte long7(long x) { return (byte)(x >> 56); } 84 private static byte long6(long x) { return (byte)(x >> 48); } 85 private static byte long5(long x) { return (byte)(x >> 40); } 86 private static byte long4(long x) { return (byte)(x >> 32); } 87 private static byte long3(long x) { return (byte)(x >> 24); } 88 private static byte long2(long x) { return (byte)(x >> 16); } 89 private static byte long1(long x) { return (byte)(x >> 8); } 90 private static byte long0(long x) { return (byte)(x ); } 91 92 private static byte int3(int x) { return (byte)(x >> 24); } 93 private static byte int2(int x) { return (byte)(x >> 16); } 94 private static byte int1(int x) { return (byte)(x >> 8); } 95 private static byte int0(int x) { return (byte)(x ); } 96 97 private static byte short1(short x) { return (byte)(x >> 8); } 98 private static byte short0(short x) { return (byte)(x ); } 99 100 byte _get(long i) { return bytes[(int)i]; } 101 void _put(long i, byte x) { bytes[(int)i] = x; } 102 103 private void putLongX(long a, long x) { 104 if (byteOrder == BIG_ENDIAN) { 105 x = Long.reverseBytes(x); 106 } 107 _put(a + 7, long7(x)); 108 _put(a + 6, long6(x)); 109 _put(a + 5, long5(x)); 110 _put(a + 4, long4(x)); 111 _put(a + 3, long3(x)); 112 _put(a + 2, long2(x)); 113 _put(a + 1, long1(x)); 114 _put(a , long0(x)); 115 } 116 117 private void putIntX(long a, int x) { 118 if (byteOrder == BIG_ENDIAN) { 119 x = Integer.reverseBytes(x); 120 } 121 _put(a + 3, int3(x)); 122 _put(a + 2, int2(x)); 123 _put(a + 1, int1(x)); 124 _put(a , int0(x)); 125 } 126 127 private void putShortX(int bi, short x) { 128 if (byteOrder == BIG_ENDIAN) { 129 x = Short.reverseBytes(x); 130 } 131 _put(bi , short0(x)); 132 _put(bi + 1, short1(x)); 133 } 134 135 static private int makeInt(byte b3, byte b2, byte b1, byte b0) { 136 return (((b3 ) << 24) | 137 ((b2 & 0xff) << 16) | 138 ((b1 & 0xff) << 8) | 139 ((b0 & 0xff) )); 140 } 141 int getIntX(long a) { 142 int x = makeInt(_get(a + 3), 143 _get(a + 2), 144 _get(a + 1), 145 _get(a)); 146 if (byteOrder == BIG_ENDIAN) { 147 x = Integer.reverseBytes(x); 148 } 149 return x; 150 } 151 152 static private long makeLong(byte b7, byte b6, byte b5, byte b4, 153 byte b3, byte b2, byte b1, byte b0) 154 { 155 return ((((long)b7 ) << 56) | 156 (((long)b6 & 0xff) << 48) | 157 (((long)b5 & 0xff) << 40) | 158 (((long)b4 & 0xff) << 32) | 159 (((long)b3 & 0xff) << 24) | 160 (((long)b2 & 0xff) << 16) | 161 (((long)b1 & 0xff) << 8) | 162 (((long)b0 & 0xff) )); 163 } 164 165 long getLongX(long a) { 166 long x = makeLong(_get(a + 7), 167 _get(a + 6), 168 _get(a + 5), 169 _get(a + 4), 170 _get(a + 3), 171 _get(a + 2), 172 _get(a + 1), 173 _get(a)); 174 if (byteOrder == BIG_ENDIAN) { 175 x = Long.reverseBytes(x); 176 } 177 return x; 178 } 179 180 static private short makeShort(byte b1, byte b0) { 181 return (short)((b1 << 8) | (b0 & 0xff)); 182 } 183 184 short getShortX(long a) { 185 short x = makeShort(_get(a + 1), 186 _get(a )); 187 if (byteOrder == BIG_ENDIAN) { 188 x = Short.reverseBytes(x); 189 } 190 return x; 191 } 192 193 double getDoubleX(long a) { 194 long x = getLongX(a); 195 return Double.longBitsToDouble(x); 196 } 197 198 double getFloatX(long a) { 199 int x = getIntX(a); 200 return Float.intBitsToFloat(x); 201 } 202 203 void ck(long x, long y) { 204 if (x != y) { 205 throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); 206 } 207 } 208 209 void ck(double x, double y) { 210 if (x == x && y == y && x != y) { 211 ck(x, y); 212 } 213 } 214 215 long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); } 216 int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); } 217 short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); } 218 char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); } 219 double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); } 220 float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); } 221 222 void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); } 223 void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); } 224 void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); } 225 void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); } 226 void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); } 227 void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); } 228 229 long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; } 230 int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; } 231 short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; } 232 char getChar() { ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; } 233 double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; } 234 float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; } 235 236 void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); } 237 void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); } 238 void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); } 239 void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); } 240 void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); } 241 void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); } 242 243 void rewind() { pos = 0; buf.rewind(); } 244 } 245 246 public class HeapByteBufferTest implements Runnable { 247 248 Random random = Utils.getRandomInstance(); 249 MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]); 250 251 int randomOffset(Random r, MyByteBuffer buf, int size) { 252 return r.nextInt(buf.capacity() - size); 253 } 254 255 long iterations; 256 257 HeapByteBufferTest(long iterations) { 258 this.iterations = iterations; 259 } 260 261 // The core of the test. Walk over the buffer reading and writing 262 // random data, XORing it as we go. We can detect writes in the 263 // wrong place, writes which are too long or too short, and reads 264 // or writes of the wrong data, 265 void step(Random r) { 266 data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN); 267 268 data.rewind(); 269 while (data.position() < data.capacity()) 270 data.putLong(data.getLong() ^ random.nextLong()); 271 272 data.rewind(); 273 while (data.position() < data.capacity()) 274 data.putInt(data.getInt() ^ random.nextInt()); 275 276 data.rewind(); 277 while (data.position() < data.capacity()) 278 data.putShort((short)(data.getShort() ^ random.nextInt())); 279 280 data.rewind(); 281 while (data.position() < data.capacity()) 282 data.putChar((char)(data.getChar() ^ random.nextInt())); 283 284 data.rewind(); 285 while (data.position() < data.capacity()) { 286 data.putDouble(combine(data.getDouble(), random.nextLong())); 287 } 288 289 data.rewind(); 290 while (data.position() < data.capacity()) 291 data.putFloat(combine(data.getFloat(), random.nextInt())); 292 293 for (int i = 0; i < 100; i++) { 294 int offset = randomOffset(r, data, 8); 295 data.putLong(offset, data.getLong(offset) ^ random.nextLong()); 296 } 297 for (int i = 0; i < 100; i++) { 298 int offset = randomOffset(r, data, 4); 299 data.putInt(offset, data.getInt(offset) ^ random.nextInt()); 300 } 301 for (int i = 0; i < 100; i++) { 302 int offset = randomOffset(r, data, 2); 303 data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt())); 304 } 305 for (int i = 0; i < 100; i++) { 306 int offset = randomOffset(r, data, 2); 307 data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt())); 308 } 309 for (int i = 0; i < 100; i++) { 310 int offset = randomOffset(r, data, 8); 311 data.putDouble(offset, combine(data.getDouble(offset), random.nextLong())); 312 } 313 for (int i = 0; i < 100; i++) { 314 int offset = randomOffset(r, data, 4); 315 data.putFloat(offset, combine(data.getFloat(offset), random.nextInt())); 316 } 317 } 318 319 // XOR the bit pattern of a double and a long, returning the 320 // result as a double. 321 // 322 // We convert signalling NaNs to quiet NaNs. We need to do this 323 // because some platforms (in particular legacy 80x87) do not 324 // provide transparent conversions between integer and 325 // floating-point types even when using raw conversions but 326 // quietly convert sNaN to qNaN. This causes spurious test 327 // failures when the template interpreter uses 80x87 and the JITs 328 // use XMM registers. 329 // 330 public double combine(double prev, long bits) { 331 bits ^= Double.doubleToRawLongBits(prev); 332 double result = Double.longBitsToDouble(bits); 333 if (Double.isNaN(result)) { 334 result = Double.longBitsToDouble(bits | 0x8000000000000l); 335 } 336 return result; 337 } 338 339 // XOR the bit pattern of a float and an int, returning the result 340 // as a float. Convert sNaNs to qNaNs. 341 public Float combine(float prev, int bits) { 342 bits ^= Float.floatToRawIntBits(prev); 343 Float result = Float.intBitsToFloat(bits); 344 if (Float.isNaN(result)) { 345 result = Float.intBitsToFloat(bits | 0x400000); 346 } 347 return result; 348 } 349 350 enum PrimitiveType { 351 BYTE(1), CHAR(2), SHORT(2), INT(4), LONG(8), FLOAT(4), DOUBLE(8); 352 353 public final int size; 354 PrimitiveType(int size) { 355 this.size = size; 356 } 357 } 358 359 void getOne(ByteBuffer b, PrimitiveType t) { 360 switch (t) { 361 case BYTE: b.get(); break; 362 case CHAR: b.getChar(); break; 363 case SHORT: b.getShort(); break; 364 case INT: b.getInt(); break; 365 case LONG: b.getLong(); break; 366 case FLOAT: b.getFloat(); break; 367 case DOUBLE: b.getDouble(); break; 368 } 369 } 370 371 void putOne(ByteBuffer b, PrimitiveType t) { 372 switch (t) { 373 case BYTE: b.put((byte)0); break; 374 case CHAR: b.putChar('0'); break; 375 case SHORT: b.putShort((short)0); break; 376 case INT: b.putInt(0); break; 377 case LONG: b.putLong(0); break; 378 case FLOAT: b.putFloat(0); break; 379 case DOUBLE: b.putDouble(0); break; 380 } 381 } 382 383 void getOne(ByteBuffer b, PrimitiveType t, int index) { 384 switch (t) { 385 case BYTE: b.get(index); break; 386 case CHAR: b.getChar(index); break; 387 case SHORT: b.getShort(index); break; 388 case INT: b.getInt(index); break; 389 case LONG: b.getLong(index); break; 390 case FLOAT: b.getFloat(index); break; 391 case DOUBLE: b.getDouble(index); break; 392 } 393 } 394 395 void putOne(ByteBuffer b, PrimitiveType t, int index) { 396 switch (t) { 397 case BYTE: b.put(index, (byte)0); break; 398 case CHAR: b.putChar(index, '0'); break; 399 case SHORT: b.putShort(index, (short)0); break; 400 case INT: b.putInt(index, 0); break; 401 case LONG: b.putLong(index, 0); break; 402 case FLOAT: b.putFloat(index, 0); break; 403 case DOUBLE: b.putDouble(index, 0); break; 404 } 405 } 406 407 void checkBoundaryConditions() { 408 for (int i = 0; i < 100; i++) { 409 int bufSize = random.nextInt(16); 410 byte[] bytes = new byte[bufSize]; 411 ByteBuffer buf = ByteBuffer.wrap(bytes); 412 for (int j = 0; j < 100; j++) { 413 int offset = random.nextInt(32) - 8; 414 for (PrimitiveType t : PrimitiveType.values()) { 415 int threw = 0; 416 try { 417 try { 418 buf.position(offset); 419 getOne(buf, t); 420 } catch (BufferUnderflowException e) { 421 if (offset + t.size < bufSize) 422 throw new RuntimeException 423 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 424 threw++; 425 } catch (IllegalArgumentException e) { 426 if (offset >= 0 && offset + t.size < bufSize) 427 throw new RuntimeException 428 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 429 threw++; 430 } 431 432 try { 433 buf.position(offset); 434 putOne(buf, t); 435 } catch (BufferOverflowException e) { 436 if (offset + t.size < bufSize) 437 throw new RuntimeException 438 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 439 threw++; 440 } catch (IllegalArgumentException e) { 441 if (offset >= 0 && offset + t.size < bufSize) 442 throw new RuntimeException 443 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 444 threw++; 445 } 446 447 try { 448 putOne(buf, t, offset); 449 } catch (IndexOutOfBoundsException e) { 450 if (offset >= 0 && offset + t.size < bufSize) 451 throw new RuntimeException 452 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 453 threw++; 454 } 455 456 try { 457 getOne(buf, t, offset); 458 } catch (IndexOutOfBoundsException e) { 459 if (offset >= 0 && offset + t.size < bufSize) 460 throw new RuntimeException 461 ("type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, e); 462 threw++; 463 } 464 465 if (threw == 0) { 466 // Make sure that we should not have thrown. 467 if (offset < 0 || offset + t.size > bufSize) { 468 throw new RuntimeException 469 ("should have thrown but did not, type = " + t 470 + ", offset = " + offset + ", bufSize = " + bufSize); 471 } 472 } else if (threw != 4) { 473 // If one of the {get,put} operations threw 474 // due to an invalid offset then all four of 475 // them should have thrown. 476 throw new RuntimeException 477 ("should have thrown but at least one did not, type = " + t 478 + ", offset = " + offset + ", bufSize = " + bufSize); 479 } 480 } catch (Throwable th) { 481 throw new RuntimeException 482 ("unexpected throw: type = " + t + ", offset = " + offset + ", bufSize = " + bufSize, th); 483 484 } 485 } 486 } 487 } 488 } 489 490 public void run() { 491 checkBoundaryConditions(); 492 493 for (int i = 0; i < data.capacity(); i += 8) { 494 data.putLong(i, random.nextLong()); 495 } 496 497 for (int i = 0; i < iterations; i++) { 498 step(random); 499 } 500 501 if (!Arrays.equals(data.array(), data.backingArray())) { 502 throw new RuntimeException(); 503 } 504 } 505 506 public static void main(String[] args) { 507 // The number of iterations is high to ensure that tiered 508 // compilation kicks in all the way up to C2. 509 long iterations = 100000; 510 if (args.length > 0) 511 iterations = Long.parseLong(args[0]); 512 513 new HeapByteBufferTest(iterations).run(); 514 } 515 }