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