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 }