1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 public class Verify { 25 public static String throwWord(boolean threw) { 26 return (threw ? "threw" : "didn't throw"); 27 } 28 29 public static void verifyResult(UnaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int value) { 30 if (exception1 != exception2) { 31 throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value); 32 } 33 if (result1 != result2) { 34 throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); 35 } 36 } 37 38 public static void verifyResult(UnaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long value) { 39 if (exception1 != exception2) { 40 throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version" + throwWord(exception2) + " for: " + value); 41 } 42 if (result1 != result2) { 43 throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); 44 } 45 } 46 47 private static void verifyResult(BinaryMethod method, int result1, int result2, boolean exception1, boolean exception2, int a, int b) { 48 if (exception1 != exception2) { 49 throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); 50 } 51 if (result1 != result2) { 52 throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); 53 } 54 } 55 56 private static void verifyResult(BinaryLongMethod method, long result1, long result2, boolean exception1, boolean exception2, long a, long b) { 57 if (exception1 != exception2) { 58 throw new RuntimeException("Intrinsic version [" + method.name() + "]" + throwWord(exception1) + " exception, NonIntrinsic version " + throwWord(exception2) + " for: " + a + " + " + b); 59 } 60 if (result1 != result2) { 61 throw new RuntimeException("Intrinsic version [" + method.name() + "] returned: " + result1 + " while NonIntrinsic version returned: " + result2); 62 } 63 } 64 65 66 public static void verifyUnary(int a, UnaryMethod method) { 67 boolean exception1 = false, exception2 = false; 68 int result1 = 0, result2 = 0; 69 try { 70 result1 = method.checkMethod(a); 71 } catch (ArithmeticException e) { 72 exception1 = true; 73 } 74 try { 75 result2 = method.safeMethod(a); 76 } catch (ArithmeticException e) { 77 exception2 = true; 78 } 79 80 verifyResult(method, result1, result2, exception1, exception2, a); 81 } 82 83 public static void verifyUnary(long a, UnaryLongMethod method) { 84 boolean exception1 = false, exception2 = false; 85 long result1 = 0, result2 = 0; 86 try { 87 result1 = method.checkMethod(a); 88 } catch (ArithmeticException e) { 89 exception1 = true; 90 } 91 try { 92 result2 = method.safeMethod(a); 93 } catch (ArithmeticException e) { 94 exception2 = true; 95 } 96 97 verifyResult(method, result1, result2, exception1, exception2, a); 98 } 99 100 101 public static void verifyBinary(int a, int b, BinaryMethod method) { 102 boolean exception1 = false, exception2 = false; 103 int result1 = 0, result2 = 0; 104 try { 105 result1 = method.checkMethod(a, b); 106 } catch (ArithmeticException e) { 107 exception1 = true; 108 } 109 try { 110 result2 = method.safeMethod(a, b); 111 } catch (ArithmeticException e) { 112 exception2 = true; 113 } 114 115 verifyResult(method, result1, result2, exception1, exception2, a, b); 116 } 117 118 public static void verifyBinary(long a, long b, BinaryLongMethod method) { 119 boolean exception1 = false, exception2 = false; 120 long result1 = 0, result2 = 0; 121 try { 122 result1 = method.checkMethod(a, b); 123 } catch (ArithmeticException e) { 124 exception1 = true; 125 } 126 try { 127 result2 = method.safeMethod(a, b); 128 } catch (ArithmeticException e) { 129 exception2 = true; 130 } 131 132 verifyResult(method, result1, result2, exception1, exception2, a, b); 133 } 134 135 136 public static class LoadTest { 137 public static java.util.Random rnd = new java.util.Random(); 138 public static int[] values = new int[256]; 139 140 public static void init() { 141 for (int i = 0; i < values.length; ++i) { 142 values[i] = rnd.nextInt(); 143 } 144 } 145 146 public static void verify(BinaryMethod method) { 147 for (int i = 0; i < 50000; ++i) { 148 Verify.verifyBinary(values[i & 255], values[i & 255] - i, method); 149 Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method); 150 Verify.verifyBinary(values[i & 255], values[i & 255], method); 151 if ((i & 1) == 1 && i > 5) { 152 Verify.verifyBinary(values[i & 255] + i, values[i & 255] - i, method); 153 } else { 154 Verify.verifyBinary(values[i & 255] - i, values[i & 255] + i, method); 155 } 156 Verify.verifyBinary(values[i & 255], values[(i + 1) & 255], method); 157 } 158 } 159 } 160 161 public static class NonConstantTest { 162 public static java.util.Random rnd = new java.util.Random(); 163 public static int[] values = new int[] { Integer.MAX_VALUE, Integer.MIN_VALUE }; 164 165 public static void verify(BinaryMethod method) { 166 for (int i = 0; i < 50000; ++i) { 167 int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); 168 Verify.verifyBinary(rnd1, rnd2, method); 169 Verify.verifyBinary(rnd1, rnd2 + 1, method); 170 Verify.verifyBinary(rnd1 + 1, rnd2, method); 171 Verify.verifyBinary(rnd1 - 1, rnd2, method); 172 Verify.verifyBinary(rnd1, rnd2 - 1, method); 173 Verify.verifyBinary(0, values[0], method); 174 Verify.verifyBinary(values[0], 0, method); 175 Verify.verifyBinary(0, values[1], method); 176 Verify.verifyBinary(values[1], 0, method); 177 } 178 } 179 } 180 181 public static class NonConstantLongTest { 182 public static long[] values = { Long.MIN_VALUE, Long.MAX_VALUE, 0, Long.MAX_VALUE - 1831 }; 183 public static java.util.Random rnd = new java.util.Random(); 184 185 public static void verify(BinaryLongMethod method) { 186 for (int i = 0; i < 50000; ++i) { 187 long rnd1 = rnd.nextLong(), rnd2 = rnd.nextLong(); 188 Verify.verifyBinary(rnd1, rnd2, method); 189 Verify.verifyBinary(rnd1, rnd2 + 1, method); 190 Verify.verifyBinary(rnd1 + 1, rnd2, method); 191 Verify.verifyBinary(rnd1 - 1, rnd2, method); 192 Verify.verifyBinary(rnd1, rnd2 - 1, method); 193 Verify.verifyBinary(rnd1 + Long.MAX_VALUE - rnd2, rnd2 + 1, method); 194 Verify.verifyBinary(values[0], values[2], method); 195 Verify.verifyBinary(values[1], values[2], method); 196 Verify.verifyBinary(values[3], 74L, method); 197 } 198 } 199 } 200 201 public static class LoopDependentTest { 202 public static java.util.Random rnd = new java.util.Random(); 203 204 public static void verify(BinaryMethod method) { 205 int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); 206 runTest(rnd1, rnd2, method); 207 } 208 209 private static void runTest(int rnd1, int rnd2, BinaryMethod method) { 210 for (int i = 0; i < 50000; ++i) { 211 Verify.verifyBinary(rnd1 + i, rnd2 + i, method); 212 Verify.verifyBinary(rnd1 + i, rnd2 + (i & 0xff), method); 213 Verify.verifyBinary(rnd1 - i, rnd2 - (i & 0xff), method); 214 Verify.verifyBinary(rnd1 + i + 1, rnd2 + i + 2, method); 215 Verify.verifyBinary(rnd1 + i * 2, rnd2 + i, method); 216 } 217 } 218 } 219 220 public static class ConstantTest { 221 public static void verify(BinaryMethod method) { 222 for (int i = 0; i < 50000; ++i) { 223 Verify.verifyBinary(5, 7, method); 224 Verify.verifyBinary(Integer.MAX_VALUE, 1, method); 225 Verify.verifyBinary(Integer.MIN_VALUE, -1, method); 226 Verify.verifyBinary(Integer.MAX_VALUE, -1, method); 227 Verify.verifyBinary(Integer.MIN_VALUE, 1, method); 228 Verify.verifyBinary(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, method); 229 Verify.verifyBinary(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3, method); 230 Verify.verifyBinary(Integer.MAX_VALUE, Integer.MIN_VALUE, method); 231 } 232 } 233 } 234 235 public static class ConstantLongTest { 236 public static void verify(BinaryLongMethod method) { 237 for (int i = 0; i < 50000; ++i) { 238 Verify.verifyBinary(5, 7, method); 239 Verify.verifyBinary(Long.MAX_VALUE, 1, method); 240 Verify.verifyBinary(Long.MIN_VALUE, -1, method); 241 Verify.verifyBinary(Long.MAX_VALUE, -1, method); 242 Verify.verifyBinary(Long.MIN_VALUE, 1, method); 243 Verify.verifyBinary(Long.MAX_VALUE / 2, Long.MAX_VALUE / 2, method); 244 Verify.verifyBinary(Long.MAX_VALUE / 2, (Long.MAX_VALUE / 2) + 3, method); 245 Verify.verifyBinary(Long.MAX_VALUE, Long.MIN_VALUE, method); 246 } 247 } 248 } 249 250 public static interface BinaryMethod { 251 int safeMethod(int a, int b); 252 int checkMethod(int a, int b); 253 int unchecked(int a, int b); 254 String name(); 255 } 256 257 public static interface UnaryMethod { 258 int safeMethod(int value); 259 int checkMethod(int value); 260 int unchecked(int value); 261 String name(); 262 } 263 264 public static interface BinaryLongMethod { 265 long safeMethod(long a, long b); 266 long checkMethod(long a, long b); 267 long unchecked(long a, long b); 268 String name(); 269 } 270 271 public static interface UnaryLongMethod { 272 long safeMethod(long value); 273 long checkMethod(long value); 274 long unchecked(long value); 275 String name(); 276 } 277 278 public static class UnaryToBinary implements BinaryMethod { 279 private final UnaryMethod method; 280 public UnaryToBinary(UnaryMethod method) { 281 this.method = method; 282 } 283 284 @Override 285 public int safeMethod(int a, int b) { 286 return method.safeMethod(a); 287 } 288 289 @Override 290 public int checkMethod(int a, int b) { 291 return method.checkMethod(a); 292 } 293 294 @Override 295 public int unchecked(int a, int b) { 296 return method.unchecked(a); 297 298 } 299 300 @Override 301 public String name() { 302 return method.name(); 303 } 304 } 305 306 public static class UnaryToBinaryLong implements BinaryLongMethod { 307 private final UnaryLongMethod method; 308 public UnaryToBinaryLong(UnaryLongMethod method) { 309 this.method = method; 310 } 311 312 @Override 313 public long safeMethod(long a, long b) { 314 return method.safeMethod(a); 315 } 316 317 @Override 318 public long checkMethod(long a, long b) { 319 return method.checkMethod(a); 320 } 321 322 @Override 323 public long unchecked(long a, long b) { 324 return method.unchecked(a); 325 326 } 327 328 @Override 329 public String name() { 330 return method.name(); 331 } 332 } 333 334 335 public static class AddExactI implements BinaryMethod { 336 @Override 337 public int safeMethod(int x, int y) { 338 int r = x + y; 339 // HD 2-12 Overflow iff both arguments have the opposite sign of the result 340 if (((x ^ r) & (y ^ r)) < 0) { 341 throw new ArithmeticException("integer overflow"); 342 } 343 return r; 344 345 } 346 347 @Override 348 public int checkMethod(int a, int b) { 349 return Math.addExact(a, b); 350 } 351 352 @Override 353 public String name() { 354 return "addExact"; 355 } 356 357 @Override 358 public int unchecked(int a, int b) { 359 return a + b; 360 } 361 } 362 363 public static class AddExactL implements BinaryLongMethod { 364 @Override 365 public long safeMethod(long x, long y) { 366 long r = x + y; 367 // HD 2-12 Overflow iff both arguments have the opposite sign of the result 368 if (((x ^ r) & (y ^ r)) < 0) { 369 throw new ArithmeticException("integer overflow"); 370 } 371 return r; 372 373 } 374 375 @Override 376 public long checkMethod(long a, long b) { 377 return Math.addExact(a, b); 378 } 379 380 @Override 381 public String name() { 382 return "addExactLong"; 383 } 384 385 @Override 386 public long unchecked(long a, long b) { 387 return a + b; 388 } 389 } 390 391 public static class MulExactI implements BinaryMethod { 392 @Override 393 public int safeMethod(int x, int y) { 394 long r = (long)x * (long)y; 395 if ((int)r != r) { 396 throw new ArithmeticException("integer overflow"); 397 } 398 return (int)r; 399 400 } 401 402 @Override 403 public int checkMethod(int a, int b) { 404 return Math.multiplyExact(a, b); 405 } 406 407 @Override 408 public int unchecked(int a, int b) { 409 return a * b; 410 } 411 412 @Override 413 public String name() { 414 return "multiplyExact"; 415 } 416 } 417 418 public static class MulExactL implements BinaryLongMethod { 419 @Override 420 public long safeMethod(long x, long y) { 421 long r = x * y; 422 long ax = Math.abs(x); 423 long ay = Math.abs(y); 424 if (((ax | ay) >>> 31 != 0)) { 425 // Some bits greater than 2^31 that might cause overflow 426 // Check the result using the divide operator 427 // and check for the special case of Long.MIN_VALUE * -1 428 if (((y != 0) && (r / y != x)) || 429 (x == Long.MIN_VALUE && y == -1)) { 430 throw new ArithmeticException("long overflow"); 431 } 432 } 433 return r; 434 } 435 436 @Override 437 public long checkMethod(long a, long b) { 438 return Math.multiplyExact(a, b); 439 } 440 441 @Override 442 public long unchecked(long a, long b) { 443 return a * b; 444 } 445 446 @Override 447 public String name() { 448 return "multiplyExact"; 449 } 450 } 451 452 public static class NegExactL implements UnaryLongMethod { 453 @Override 454 public long safeMethod(long a) { 455 if (a == Long.MIN_VALUE) { 456 throw new ArithmeticException("long overflow"); 457 } 458 459 return -a; 460 461 } 462 463 @Override 464 public long checkMethod(long value) { 465 return Math.negateExact(value); 466 } 467 468 @Override 469 public long unchecked(long value) { 470 return -value; 471 } 472 473 @Override 474 public String name() { 475 return "negateExactLong"; 476 } 477 } 478 479 public static class NegExactI implements UnaryMethod { 480 @Override 481 public int safeMethod(int a) { 482 if (a == Integer.MIN_VALUE) { 483 throw new ArithmeticException("integer overflow"); 484 } 485 486 return -a; 487 488 } 489 490 @Override 491 public int checkMethod(int value) { 492 return Math.negateExact(value); 493 } 494 495 @Override 496 public int unchecked(int value) { 497 return -value; 498 } 499 500 @Override 501 public String name() { 502 return "negateExact"; 503 } 504 } 505 506 public static class SubExactI implements BinaryMethod { 507 @Override 508 public int safeMethod(int x, int y) { 509 int r = x - y; 510 // HD 2-12 Overflow iff the arguments have different signs and 511 // the sign of the result is different than the sign of x 512 if (((x ^ y) & (x ^ r)) < 0) { 513 throw new ArithmeticException("integer overflow"); 514 } 515 return r; 516 } 517 518 @Override 519 public int checkMethod(int a, int b) { 520 return Math.subtractExact(a, b); 521 } 522 523 @Override 524 public int unchecked(int a, int b) { 525 return a - b; 526 } 527 528 @Override 529 public String name() { 530 return "subtractExact"; 531 } 532 } 533 534 public static class SubExactL implements BinaryLongMethod { 535 @Override 536 public long safeMethod(long x, long y) { 537 long r = x - y; 538 // HD 2-12 Overflow iff the arguments have different signs and 539 // the sign of the result is different than the sign of x 540 if (((x ^ y) & (x ^ r)) < 0) { 541 throw new ArithmeticException("integer overflow"); 542 } 543 return r; 544 } 545 546 @Override 547 public long checkMethod(long a, long b) { 548 return Math.subtractExact(a, b); 549 } 550 551 @Override 552 public long unchecked(long a, long b) { 553 return a - b; 554 } 555 556 @Override 557 public String name() { 558 return "subtractExactLong"; 559 } 560 } 561 562 static class IncExactL implements UnaryLongMethod { 563 @Override 564 public long safeMethod(long a) { 565 if (a == Long.MAX_VALUE) { 566 throw new ArithmeticException("long overflow"); 567 } 568 569 return a + 1L; 570 571 } 572 573 @Override 574 public long checkMethod(long value) { 575 return Math.incrementExact(value); 576 } 577 578 @Override 579 public long unchecked(long value) { 580 return value + 1; 581 } 582 583 @Override 584 public String name() { 585 return "incrementExactLong"; 586 } 587 } 588 589 static class IncExactI implements UnaryMethod { 590 @Override 591 public int safeMethod(int a) { 592 if (a == Integer.MAX_VALUE) { 593 throw new ArithmeticException("integer overflow"); 594 } 595 596 return a + 1; 597 } 598 599 @Override 600 public int checkMethod(int value) { 601 return Math.incrementExact(value); 602 } 603 604 @Override 605 public int unchecked(int value) { 606 return value + 1; 607 } 608 609 @Override 610 public String name() { 611 return "incrementExact"; 612 } 613 } 614 615 static class DecExactL implements UnaryLongMethod { 616 @Override 617 public long safeMethod(long a) { 618 if (a == Long.MIN_VALUE) { 619 throw new ArithmeticException("long overflow"); 620 } 621 622 return a - 1L; 623 } 624 625 @Override 626 public long checkMethod(long value) { 627 return Math.decrementExact(value); 628 } 629 630 @Override 631 public long unchecked(long value) { 632 return value - 1; 633 } 634 635 @Override 636 public String name() { 637 return "decExactLong"; 638 } 639 } 640 641 static class DecExactI implements UnaryMethod { 642 @Override 643 public int safeMethod(int a) { 644 if (a == Integer.MIN_VALUE) { 645 throw new ArithmeticException("integer overflow"); 646 } 647 648 return a - 1; 649 } 650 651 @Override 652 public int checkMethod(int value) { 653 return Math.decrementExact(value); 654 } 655 656 @Override 657 public int unchecked(int value) { 658 return value - 1; 659 } 660 661 @Override 662 public String name() { 663 return "decrementExact"; 664 } 665 } 666 667 }