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 } 157 } 158 } 159 160 public static class NonConstantTest { 161 public static java.util.Random rnd = new java.util.Random(); 162 163 public static void verify(BinaryMethod method) { 164 for (int i = 0; i < 50000; ++i) { 165 int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); 166 Verify.verifyBinary(rnd1, rnd2, method); 167 Verify.verifyBinary(rnd1, rnd2 + 1, method); 168 Verify.verifyBinary(rnd1 + 1, rnd2, method); 169 Verify.verifyBinary(rnd1 - 1, rnd2, method); 170 Verify.verifyBinary(rnd1, rnd2 - 1, method); 171 } 172 } 173 } 174 175 public static class NonConstantLongTest { 176 public static long[] values = { Long.MIN_VALUE, Long.MAX_VALUE, 0, Long.MAX_VALUE - 1831 }; 177 public static java.util.Random rnd = new java.util.Random(); 178 179 public static void verify(BinaryLongMethod method) { 180 for (int i = 0; i < 50000; ++i) { 181 long rnd1 = rnd.nextLong(), rnd2 = rnd.nextLong(); 182 Verify.verifyBinary(rnd1, rnd2, method); 183 Verify.verifyBinary(rnd1, rnd2 + 1, method); 184 Verify.verifyBinary(rnd1 + 1, rnd2, method); 185 Verify.verifyBinary(rnd1 - 1, rnd2, method); 186 Verify.verifyBinary(rnd1, rnd2 - 1, method); 187 Verify.verifyBinary(rnd1 + Long.MAX_VALUE - rnd2, rnd2 + 1, method); 188 Verify.verifyBinary(values[0], values[2], method); 189 Verify.verifyBinary(values[1], values[2], method); 190 Verify.verifyBinary(values[3], 74L, method); 191 } 192 } 193 } 194 195 public static class LoopDependentTest { 196 public static java.util.Random rnd = new java.util.Random(); 197 198 public static void verify(BinaryMethod method) { 199 int rnd1 = rnd.nextInt(), rnd2 = rnd.nextInt(); 200 runTest(rnd1, rnd2, method); 201 } 202 203 private static void runTest(int rnd1, int rnd2, BinaryMethod method) { 204 for (int i = 0; i < 50000; ++i) { 205 Verify.verifyBinary(rnd1 + i, rnd2 + i, method); 206 Verify.verifyBinary(rnd1 + i, rnd2 + (i & 0xff), method); 207 Verify.verifyBinary(rnd1 - i, rnd2 - (i & 0xff), method); 208 Verify.verifyBinary(rnd1 + i + 1, rnd2 + i + 2, method); 209 Verify.verifyBinary(rnd1 + i * 2, rnd2 + i, method); 210 } 211 } 212 } 213 214 public static class ConstantTest { 215 public static void verify(BinaryMethod method) { 216 for (int i = 0; i < 50000; ++i) { 217 Verify.verifyBinary(5, 7, method); 218 Verify.verifyBinary(Integer.MAX_VALUE, 1, method); 219 Verify.verifyBinary(Integer.MIN_VALUE, -1, method); 220 Verify.verifyBinary(Integer.MAX_VALUE, -1, method); 221 Verify.verifyBinary(Integer.MIN_VALUE, 1, method); 222 Verify.verifyBinary(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2, method); 223 Verify.verifyBinary(Integer.MAX_VALUE / 2, (Integer.MAX_VALUE / 2) + 3, method); 224 Verify.verifyBinary(Integer.MAX_VALUE, Integer.MIN_VALUE, method); 225 } 226 } 227 } 228 229 public static class ConstantLongTest { 230 public static void verify(BinaryLongMethod method) { 231 for (int i = 0; i < 50000; ++i) { 232 Verify.verifyBinary(5, 7, method); 233 Verify.verifyBinary(Long.MAX_VALUE, 1, method); 234 Verify.verifyBinary(Long.MIN_VALUE, -1, method); 235 Verify.verifyBinary(Long.MAX_VALUE, -1, method); 236 Verify.verifyBinary(Long.MIN_VALUE, 1, method); 237 Verify.verifyBinary(Long.MAX_VALUE / 2, Long.MAX_VALUE / 2, method); 238 Verify.verifyBinary(Long.MAX_VALUE / 2, (Long.MAX_VALUE / 2) + 3, method); 239 Verify.verifyBinary(Long.MAX_VALUE, Long.MIN_VALUE, method); 240 } 241 } 242 } 243 244 public static interface BinaryMethod { 245 int safeMethod(int a, int b); 246 int checkMethod(int a, int b); 247 int unchecked(int a, int b); 248 String name(); 249 } 250 251 public static interface UnaryMethod { 252 int safeMethod(int value); 253 int checkMethod(int value); 254 int unchecked(int value); 255 String name(); 256 } 257 258 public static interface BinaryLongMethod { 259 long safeMethod(long a, long b); 260 long checkMethod(long a, long b); 261 long unchecked(long a, long b); 262 String name(); 263 } 264 265 public static interface UnaryLongMethod { 266 long safeMethod(long value); 267 long checkMethod(long value); 268 long unchecked(long value); 269 String name(); 270 } 271 272 public static class UnaryToBinary implements BinaryMethod { 273 private final UnaryMethod method; 274 public UnaryToBinary(UnaryMethod method) { 275 this.method = method; 276 } 277 278 @Override 279 public int safeMethod(int a, int b) { 280 return method.safeMethod(a); 281 } 282 283 @Override 284 public int checkMethod(int a, int b) { 285 return method.checkMethod(a); 286 } 287 288 @Override 289 public int unchecked(int a, int b) { 290 return method.unchecked(a); 291 292 } 293 294 @Override 295 public String name() { 296 return method.name(); 297 } 298 } 299 300 public static class UnaryToBinaryLong implements BinaryLongMethod { 301 private final UnaryLongMethod method; 302 public UnaryToBinaryLong(UnaryLongMethod method) { 303 this.method = method; 304 } 305 306 @Override 307 public long safeMethod(long a, long b) { 308 return method.safeMethod(a); 309 } 310 311 @Override 312 public long checkMethod(long a, long b) { 313 return method.checkMethod(a); 314 } 315 316 @Override 317 public long unchecked(long a, long b) { 318 return method.unchecked(a); 319 320 } 321 322 @Override 323 public String name() { 324 return method.name(); 325 } 326 } 327 328 329 public static class AddExactI implements BinaryMethod { 330 @Override 331 public int safeMethod(int x, int y) { 332 int r = x + y; 333 // HD 2-12 Overflow iff both arguments have the opposite sign of the result 334 if (((x ^ r) & (y ^ r)) < 0) { 335 throw new ArithmeticException("integer overflow"); 336 } 337 return r; 338 339 } 340 341 @Override 342 public int checkMethod(int a, int b) { 343 return Math.addExact(a, b); 344 } 345 346 @Override 347 public String name() { 348 return "addExact"; 349 } 350 351 @Override 352 public int unchecked(int a, int b) { 353 return a + b; 354 } 355 } 356 357 public static class AddExactL implements BinaryLongMethod { 358 @Override 359 public long safeMethod(long x, long y) { 360 long r = x + y; 361 // HD 2-12 Overflow iff both arguments have the opposite sign of the result 362 if (((x ^ r) & (y ^ r)) < 0) { 363 throw new ArithmeticException("integer overflow"); 364 } 365 return r; 366 367 } 368 369 @Override 370 public long checkMethod(long a, long b) { 371 return Math.addExact(a, b); 372 } 373 374 @Override 375 public String name() { 376 return "addExactLong"; 377 } 378 379 @Override 380 public long unchecked(long a, long b) { 381 return a + b; 382 } 383 } 384 385 public static class MulExactI implements BinaryMethod { 386 @Override 387 public int safeMethod(int x, int y) { 388 long r = (long)x * (long)y; 389 if ((int)r != r) { 390 throw new ArithmeticException("integer overflow"); 391 } 392 return (int)r; 393 394 } 395 396 @Override 397 public int checkMethod(int a, int b) { 398 return Math.multiplyExact(a, b); 399 } 400 401 @Override 402 public int unchecked(int a, int b) { 403 return a * b; 404 } 405 406 @Override 407 public String name() { 408 return "multiplyExact"; 409 } 410 } 411 412 public static class MulExactL implements BinaryLongMethod { 413 @Override 414 public long safeMethod(long x, long y) { 415 long r = x * y; 416 long ax = Math.abs(x); 417 long ay = Math.abs(y); 418 if (((ax | ay) >>> 31 != 0)) { 419 // Some bits greater than 2^31 that might cause overflow 420 // Check the result using the divide operator 421 // and check for the special case of Long.MIN_VALUE * -1 422 if (((y != 0) && (r / y != x)) || 423 (x == Long.MIN_VALUE && y == -1)) { 424 throw new ArithmeticException("long overflow"); 425 } 426 } 427 return r; 428 } 429 430 @Override 431 public long checkMethod(long a, long b) { 432 return Math.multiplyExact(a, b); 433 } 434 435 @Override 436 public long unchecked(long a, long b) { 437 return a * b; 438 } 439 440 @Override 441 public String name() { 442 return "multiplyExact"; 443 } 444 } 445 446 public static class NegExactL implements UnaryLongMethod { 447 @Override 448 public long safeMethod(long a) { 449 if (a == Long.MIN_VALUE) { 450 throw new ArithmeticException("long overflow"); 451 } 452 453 return -a; 454 455 } 456 457 @Override 458 public long checkMethod(long value) { 459 return Math.negateExact(value); 460 } 461 462 @Override 463 public long unchecked(long value) { 464 return -value; 465 } 466 467 @Override 468 public String name() { 469 return "negateExactLong"; 470 } 471 } 472 473 public static class NegExactI implements UnaryMethod { 474 @Override 475 public int safeMethod(int a) { 476 if (a == Integer.MIN_VALUE) { 477 throw new ArithmeticException("integer overflow"); 478 } 479 480 return -a; 481 482 } 483 484 @Override 485 public int checkMethod(int value) { 486 return Math.negateExact(value); 487 } 488 489 @Override 490 public int unchecked(int value) { 491 return -value; 492 } 493 494 @Override 495 public String name() { 496 return "negateExact"; 497 } 498 } 499 500 public static class SubExactI implements BinaryMethod { 501 @Override 502 public int safeMethod(int x, int y) { 503 int r = x - y; 504 // HD 2-12 Overflow iff the arguments have different signs and 505 // the sign of the result is different than the sign of x 506 if (((x ^ y) & (x ^ r)) < 0) { 507 throw new ArithmeticException("integer overflow"); 508 } 509 return r; 510 } 511 512 @Override 513 public int checkMethod(int a, int b) { 514 return Math.subtractExact(a, b); 515 } 516 517 @Override 518 public int unchecked(int a, int b) { 519 return a - b; 520 } 521 522 @Override 523 public String name() { 524 return "subtractExact"; 525 } 526 } 527 528 public static class SubExactL implements BinaryLongMethod { 529 @Override 530 public long safeMethod(long x, long y) { 531 long r = x - y; 532 // HD 2-12 Overflow iff the arguments have different signs and 533 // the sign of the result is different than the sign of x 534 if (((x ^ y) & (x ^ r)) < 0) { 535 throw new ArithmeticException("integer overflow"); 536 } 537 return r; 538 } 539 540 @Override 541 public long checkMethod(long a, long b) { 542 return Math.subtractExact(a, b); 543 } 544 545 @Override 546 public long unchecked(long a, long b) { 547 return a - b; 548 } 549 550 @Override 551 public String name() { 552 return "subtractExactLong"; 553 } 554 } 555 556 static class IncExactL implements UnaryLongMethod { 557 @Override 558 public long safeMethod(long a) { 559 if (a == Long.MAX_VALUE) { 560 throw new ArithmeticException("long overflow"); 561 } 562 563 return a + 1L; 564 565 } 566 567 @Override 568 public long checkMethod(long value) { 569 return Math.incrementExact(value); 570 } 571 572 @Override 573 public long unchecked(long value) { 574 return value + 1; 575 } 576 577 @Override 578 public String name() { 579 return "incrementExactLong"; 580 } 581 } 582 583 static class IncExactI implements UnaryMethod { 584 @Override 585 public int safeMethod(int a) { 586 if (a == Integer.MAX_VALUE) { 587 throw new ArithmeticException("integer overflow"); 588 } 589 590 return a + 1; 591 } 592 593 @Override 594 public int checkMethod(int value) { 595 return Math.incrementExact(value); 596 } 597 598 @Override 599 public int unchecked(int value) { 600 return value + 1; 601 } 602 603 @Override 604 public String name() { 605 return "incrementExact"; 606 } 607 } 608 609 static class DecExactL implements UnaryLongMethod { 610 @Override 611 public long safeMethod(long a) { 612 if (a == Long.MIN_VALUE) { 613 throw new ArithmeticException("long overflow"); 614 } 615 616 return a - 1L; 617 } 618 619 @Override 620 public long checkMethod(long value) { 621 return Math.decrementExact(value); 622 } 623 624 @Override 625 public long unchecked(long value) { 626 return value - 1; 627 } 628 629 @Override 630 public String name() { 631 return "decExactLong"; 632 } 633 } 634 635 static class DecExactI implements UnaryMethod { 636 @Override 637 public int safeMethod(int a) { 638 if (a == Integer.MIN_VALUE) { 639 throw new ArithmeticException("integer overflow"); 640 } 641 642 return a - 1; 643 } 644 645 @Override 646 public int checkMethod(int value) { 647 return Math.decrementExact(value); 648 } 649 650 @Override 651 public int unchecked(int value) { 652 return value - 1; 653 } 654 655 @Override 656 public String name() { 657 return "decrementExact"; 658 } 659 } 660 661 }