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