1 /*
   2  * Copyright (c) 2014, 2018, 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 /*
  25  * @test TestStableChar
  26  * @summary tests on stable fields and arrays
  27  * @library /test/lib /
  28  * @modules java.base/jdk.internal.misc
  29  * @modules java.base/jdk.internal.vm.annotation
  30  * @build sun.hotspot.WhiteBox
  31  *
  32  * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp
  33  *                                 -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
  34  *                                 -XX:-TieredCompilation
  35  *                                 -XX:+FoldStableValues
  36  *                                 compiler.stable.TestStableChar
  37  * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp
  38  *                                 -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
  39  *                                 -XX:-TieredCompilation
  40  *                                 -XX:-FoldStableValues
  41  *                                 compiler.stable.TestStableChar
  42  *
  43  * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp
  44  *                                 -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
  45  *                                 -XX:+TieredCompilation -XX:TieredStopAtLevel=1
  46  *                                 -XX:+FoldStableValues
  47  *                                 compiler.stable.TestStableChar
  48  * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp
  49  *                                 -XX:CompileOnly=::get,::get1,::get2,::get3,::get4
  50  *                                 -XX:+TieredCompilation -XX:TieredStopAtLevel=1
  51  *                                 -XX:-FoldStableValues
  52  *                                 compiler.stable.TestStableChar
  53  */
  54 
  55 package compiler.stable;
  56 
  57 import jdk.internal.vm.annotation.Stable;
  58 
  59 import java.lang.reflect.InvocationTargetException;
  60 
  61 public class TestStableChar {
  62     static final boolean isStableEnabled    = StableConfiguration.isStableEnabled;
  63 
  64     public static void main(String[] args) throws Exception {
  65         run(DefaultValue.class);
  66         run(CharStable.class);
  67         run(DefaultStaticValue.class);
  68         run(StaticCharStable.class);
  69         run(VolatileCharStable.class);
  70 
  71         // @Stable arrays: Dim 1-4
  72         run(CharArrayDim1.class);
  73         run(CharArrayDim2.class);
  74         run(CharArrayDim3.class);
  75         run(CharArrayDim4.class);
  76 
  77         // @Stable Object field: dynamic arrays
  78         run(ObjectArrayLowerDim0.class);
  79         run(ObjectArrayLowerDim1.class);
  80         run(ObjectArrayLowerDim2.class);
  81 
  82         // Nested @Stable fields
  83         run(NestedStableField.class);
  84         run(NestedStableField1.class);
  85         run(NestedStableField2.class);
  86         run(NestedStableField3.class);
  87 
  88         if (failed) {
  89             throw new Error("TEST FAILED");
  90         }
  91     }
  92 
  93     /* ==================================================== */
  94 
  95     static class DefaultValue {
  96         public @Stable char v;
  97 
  98         public static final DefaultValue c = new DefaultValue();
  99         public static char get() { return c.v; }
 100         public static void test() throws Exception {
 101                        char val1 = get();
 102             c.v = 'a'; char val2 = get();
 103             assertEquals(val1, 0);
 104             assertEquals(val2, 'a');
 105         }
 106     }
 107 
 108     /* ==================================================== */
 109 
 110     static class CharStable {
 111         public @Stable char v;
 112 
 113         public static final CharStable c = new CharStable();
 114         public static char get() { return c.v; }
 115         public static void test() throws Exception {
 116             c.v = 'a'; char val1 = get();
 117             c.v = 'b'; char val2 = get();
 118             assertEquals(val1, 'a');
 119             assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 120         }
 121     }
 122 
 123     /* ==================================================== */
 124 
 125     static class DefaultStaticValue {
 126         public static @Stable char v;
 127 
 128         public static final DefaultStaticValue c = new DefaultStaticValue();
 129         public static char get() { return c.v; }
 130         public static void test() throws Exception {
 131                        char val1 = get();
 132             c.v = 'a'; char val2 = get();
 133             assertEquals(val1, 0);
 134             assertEquals(val2, 'a');
 135         }
 136     }
 137 
 138     /* ==================================================== */
 139 
 140     static class StaticCharStable {
 141         public @Stable char v;
 142 
 143         public static final StaticCharStable c = new StaticCharStable();
 144         public static char get() { return c.v; }
 145         public static void test() throws Exception {
 146             c.v = 'a'; char val1 = get();
 147             c.v = 'b'; char val2 = get();
 148             assertEquals(val1, 'a');
 149             assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 150         }
 151     }
 152 
 153     /* ==================================================== */
 154 
 155     static class VolatileCharStable {
 156         public @Stable volatile char v;
 157 
 158         public static final VolatileCharStable c = new VolatileCharStable();
 159         public static char get() { return c.v; }
 160         public static void test() throws Exception {
 161             c.v = 'a'; char val1 = get();
 162             c.v = 'b'; char val2 = get();
 163             assertEquals(val1, 'a');
 164             assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 165         }
 166     }
 167 
 168     /* ==================================================== */
 169     // @Stable array == field && all components are stable
 170 
 171     static class CharArrayDim1 {
 172         public @Stable char[] v;
 173 
 174         public static final CharArrayDim1 c = new CharArrayDim1();
 175         public static char get() { return c.v[0]; }
 176         public static char get1() { return c.v[10]; }
 177         public static char[] get2() { return c.v; }
 178         public static void test() throws Exception {
 179             {
 180                 c.v = new char[1]; c.v[0] = 'a'; char val1 = get();
 181                                    c.v[0] = 'b'; char val2 = get();
 182                 assertEquals(val1, 'a');
 183                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 184 
 185                 c.v = new char[1]; c.v[0] = 'c'; char val3 = get();
 186                 assertEquals(val3, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 187                                                     : 'c'));
 188             }
 189 
 190             {
 191                 c.v = new char[20]; c.v[10] = 'a'; char val1 = get1();
 192                                     c.v[10] = 'b'; char val2 = get1();
 193                 assertEquals(val1, 'a');
 194                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 195 
 196                 c.v = new char[20]; c.v[10] = 'c'; char val3 = get1();
 197                 assertEquals(val3, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 198                                                     : 'c'));
 199             }
 200 
 201             {
 202                 c.v = new char[1]; char[] val1 = get2();
 203                 c.v = new char[1]; char[] val2 = get2();
 204                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 205             }
 206         }
 207     }
 208 
 209     /* ==================================================== */
 210 
 211     static class CharArrayDim2 {
 212         public @Stable char[][] v;
 213 
 214         public static final CharArrayDim2 c = new CharArrayDim2();
 215         public static char get() { return c.v[0][0]; }
 216         public static char[] get1() { return c.v[0]; }
 217         public static char[][] get2() { return c.v; }
 218         public static void test() throws Exception {
 219             {
 220                 c.v = new char[1][1]; c.v[0][0] = 'a'; char val1 = get();
 221                                       c.v[0][0] = 'b'; char val2 = get();
 222                 assertEquals(val1, 'a');
 223                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 224 
 225                 c.v = new char[1][1]; c.v[0][0] = 'c'; char val3 = get();
 226                 assertEquals(val3, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 227                                                     : 'c'));
 228 
 229                 c.v[0] = new char[1]; c.v[0][0] = 'd'; char val4 = get();
 230                 assertEquals(val4, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 231                                                     : 'd'));
 232             }
 233 
 234             {
 235                 c.v = new char[1][1]; char[] val1 = get1();
 236                 c.v[0] = new char[1]; char[] val2 = get1();
 237                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 238             }
 239 
 240             {
 241                 c.v = new char[1][1]; char[][] val1 = get2();
 242                 c.v = new char[1][1]; char[][] val2 = get2();
 243                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 244             }
 245         }
 246     }
 247 
 248     /* ==================================================== */
 249 
 250     static class CharArrayDim3 {
 251         public @Stable char[][][] v;
 252 
 253         public static final CharArrayDim3 c = new CharArrayDim3();
 254         public static char get() { return c.v[0][0][0]; }
 255         public static char[] get1() { return c.v[0][0]; }
 256         public static char[][] get2() { return c.v[0]; }
 257         public static char[][][] get3() { return c.v; }
 258         public static void test() throws Exception {
 259             {
 260                 c.v = new char[1][1][1]; c.v[0][0][0] = 'a'; char val1 = get();
 261                                          c.v[0][0][0] = 'b'; char val2 = get();
 262                 assertEquals(val1, 'a');
 263                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 264 
 265                 c.v = new char[1][1][1]; c.v[0][0][0] = 'c'; char val3 = get();
 266                 assertEquals(val3, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 267                                                     : 'c'));
 268 
 269                 c.v[0] = new char[1][1]; c.v[0][0][0] = 'd'; char val4 = get();
 270                 assertEquals(val4, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 271                                                     : 'd'));
 272 
 273                 c.v[0][0] = new char[1]; c.v[0][0][0] = 'e'; char val5 = get();
 274                 assertEquals(val5, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 275                                                     : 'e'));
 276             }
 277 
 278             {
 279                 c.v = new char[1][1][1]; char[] val1 = get1();
 280                 c.v[0][0] = new char[1]; char[] val2 = get1();
 281                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 282             }
 283 
 284             {
 285                 c.v = new char[1][1][1]; char[][] val1 = get2();
 286                 c.v[0] = new char[1][1]; char[][] val2 = get2();
 287                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 288             }
 289 
 290             {
 291                 c.v = new char[1][1][1]; char[][][] val1 = get3();
 292                 c.v = new char[1][1][1]; char[][][] val2 = get3();
 293                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 294             }
 295         }
 296     }
 297 
 298     /* ==================================================== */
 299 
 300     static class CharArrayDim4 {
 301         public @Stable char[][][][] v;
 302 
 303         public static final CharArrayDim4 c = new CharArrayDim4();
 304         public static char get() { return c.v[0][0][0][0]; }
 305         public static char[] get1() { return c.v[0][0][0]; }
 306         public static char[][] get2() { return c.v[0][0]; }
 307         public static char[][][] get3() { return c.v[0]; }
 308         public static char[][][][] get4() { return c.v; }
 309         public static void test() throws Exception {
 310             {
 311                 c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'a'; char val1 = get();
 312                                             c.v[0][0][0][0] = 'b'; char val2 = get();
 313                 assertEquals(val1, 'a');
 314                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 315 
 316                 c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'c'; char val3 = get();
 317                 assertEquals(val3, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 318                                                     : 'c'));
 319 
 320                 c.v[0] = new char[1][1][1]; c.v[0][0][0][0] = 'd'; char val4 = get();
 321                 assertEquals(val4, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 322                                                     : 'd'));
 323 
 324                 c.v[0][0] = new char[1][1]; c.v[0][0][0][0] = 'e'; char val5 = get();
 325                 assertEquals(val5, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 326                                                     : 'e'));
 327 
 328                 c.v[0][0][0] = new char[1]; c.v[0][0][0][0] = 'f'; char val6 = get();
 329                 assertEquals(val6, (isStableEnabled ? (isStableEnabled ? 'a' : 'b')
 330                                                     : 'f'));
 331             }
 332 
 333             {
 334                 c.v = new char[1][1][1][1]; char[] val1 = get1();
 335                 c.v[0][0][0] = new char[1]; char[] val2 = get1();
 336                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 337             }
 338 
 339             {
 340                 c.v = new char[1][1][1][1]; char[][] val1 = get2();
 341                 c.v[0][0] = new char[1][1]; char[][] val2 = get2();
 342                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 343             }
 344 
 345             {
 346                 c.v = new char[1][1][1][1]; char[][][] val1 = get3();
 347                 c.v[0] = new char[1][1][1]; char[][][] val2 = get3();
 348                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 349             }
 350 
 351             {
 352                 c.v = new char[1][1][1][1]; char[][][][] val1 = get4();
 353                 c.v = new char[1][1][1][1]; char[][][][] val2 = get4();
 354                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 355             }
 356         }
 357     }
 358 
 359     /* ==================================================== */
 360     // Dynamic Dim is higher than static
 361     static class ObjectArrayLowerDim0 {
 362         public @Stable Object v;
 363 
 364         public static final ObjectArrayLowerDim0 c = new ObjectArrayLowerDim0();
 365         public static char get() { return ((char[])c.v)[0]; }
 366         public static char[] get1() { return (char[])c.v; }
 367 
 368         public static void test() throws Exception {
 369             {
 370                 c.v = new char[1]; ((char[])c.v)[0] = 'a'; char val1 = get();
 371                                    ((char[])c.v)[0] = 'b'; char val2 = get();
 372 
 373                 assertEquals(val1, 'a');
 374                 assertEquals(val2, 'b');
 375             }
 376 
 377             {
 378                 c.v = new char[1]; char[] val1 = get1();
 379                 c.v = new char[1]; char[] val2 = get1();
 380                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 381             }
 382         }
 383     }
 384 
 385     /* ==================================================== */
 386 
 387     static class ObjectArrayLowerDim1 {
 388         public @Stable Object[] v;
 389 
 390         public static final ObjectArrayLowerDim1 c = new ObjectArrayLowerDim1();
 391         public static char get() { return ((char[][])c.v)[0][0]; }
 392         public static char[] get1() { return (char[])(c.v[0]); }
 393         public static Object[] get2() { return c.v; }
 394 
 395         public static void test() throws Exception {
 396             {
 397                 c.v = new char[1][1]; ((char[][])c.v)[0][0] = 'a'; char val1 = get();
 398                                       ((char[][])c.v)[0][0] = 'b'; char val2 = get();
 399 
 400                 assertEquals(val1, 'a');
 401                 assertEquals(val2, 'b');
 402             }
 403 
 404             {
 405                 c.v = new char[1][1]; c.v[0] = new char[0]; char[] val1 = get1();
 406                                       c.v[0] = new char[0]; char[] val2 = get1();
 407 
 408                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 409             }
 410 
 411             {
 412                 c.v = new char[0][0]; Object[] val1 = get2();
 413                 c.v = new char[0][0]; Object[] val2 = get2();
 414 
 415                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 416             }
 417         }
 418     }
 419 
 420     /* ==================================================== */
 421 
 422     static class ObjectArrayLowerDim2 {
 423         public @Stable Object[][] v;
 424 
 425         public static final ObjectArrayLowerDim2 c = new ObjectArrayLowerDim2();
 426         public static char get() { return ((char[][][])c.v)[0][0][0]; }
 427         public static char[] get1() { return (char[])(c.v[0][0]); }
 428         public static char[][] get2() { return (char[][])(c.v[0]); }
 429         public static Object[][] get3() { return c.v; }
 430 
 431         public static void test() throws Exception {
 432             {
 433                 c.v = new char[1][1][1]; ((char[][][])c.v)[0][0][0] = 'a'; char val1 = get();
 434                                          ((char[][][])c.v)[0][0][0] = 'b'; char val2 = get();
 435 
 436                 assertEquals(val1, 'a');
 437                 assertEquals(val2, 'b');
 438             }
 439 
 440             {
 441                 c.v = new char[1][1][1]; c.v[0][0] = new char[0]; char[] val1 = get1();
 442                                          c.v[0][0] = new char[0]; char[] val2 = get1();
 443 
 444                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 445             }
 446 
 447             {
 448                 c.v = new char[1][1][1]; c.v[0] = new char[0][0]; char[][] val1 = get2();
 449                                          c.v[0] = new char[0][0]; char[][] val2 = get2();
 450 
 451                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 452             }
 453 
 454             {
 455                 c.v = new char[0][0][0]; Object[][] val1 = get3();
 456                 c.v = new char[0][0][0]; Object[][] val2 = get3();
 457 
 458                 assertTrue((isStableEnabled ? (val1 == val2) : (val1 != val2)));
 459             }
 460         }
 461     }
 462 
 463     /* ==================================================== */
 464 
 465     static class NestedStableField {
 466         static class A {
 467             public @Stable char a;
 468 
 469         }
 470         public @Stable A v;
 471 
 472         public static final NestedStableField c = new NestedStableField();
 473         public static A get() { return c.v; }
 474         public static char get1() { return get().a; }
 475 
 476         public static void test() throws Exception {
 477             {
 478                 c.v = new A(); c.v.a = 'a'; A val1 = get();
 479                                c.v.a = 'b'; A val2 = get();
 480 
 481                 assertEquals(val1.a, 'b');
 482                 assertEquals(val2.a, 'b');
 483             }
 484 
 485             {
 486                 c.v = new A(); c.v.a = 'a'; char val1 = get1();
 487                                c.v.a = 'b'; char val2 = get1();
 488                 c.v = new A(); c.v.a = 'c'; char val3 = get1();
 489 
 490                 assertEquals(val1, 'a');
 491                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 492                 assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
 493             }
 494         }
 495     }
 496 
 497     /* ==================================================== */
 498 
 499     static class NestedStableField1 {
 500         static class A {
 501             public @Stable char a;
 502             public @Stable A next;
 503         }
 504         public @Stable A v;
 505 
 506         public static final NestedStableField1 c = new NestedStableField1();
 507         public static A get() { return c.v.next.next.next.next.next.next.next; }
 508         public static char get1() { return get().a; }
 509 
 510         public static void test() throws Exception {
 511             {
 512                 c.v = new A(); c.v.next = new A(); c.v.next.next  = c.v;
 513                                c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get();
 514                                c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get();
 515 
 516                 assertEquals(val1.a, 'b');
 517                 assertEquals(val2.a, 'b');
 518             }
 519 
 520             {
 521                 c.v = new A(); c.v.next = c.v;
 522                                c.v.a = 'a'; char val1 = get1();
 523                                c.v.a = 'b'; char val2 = get1();
 524                 c.v = new A(); c.v.next = c.v;
 525                                c.v.a = 'c'; char val3 = get1();
 526 
 527                 assertEquals(val1, 'a');
 528                 assertEquals(val2, (isStableEnabled ? 'a' : 'b'));
 529                 assertEquals(val3, (isStableEnabled ? 'a' : 'c'));
 530             }
 531         }
 532     }
 533    /* ==================================================== */
 534 
 535     static class NestedStableField2 {
 536         static class A {
 537             public @Stable char a;
 538             public @Stable A left;
 539             public         A right;
 540         }
 541 
 542         public @Stable A v;
 543 
 544         public static final NestedStableField2 c = new NestedStableField2();
 545         public static char get() { return c.v.left.left.left.a; }
 546         public static char get1() { return c.v.left.left.right.left.a; }
 547 
 548         public static void test() throws Exception {
 549             {
 550                 c.v = new A(); c.v.left = c.v.right = c.v;
 551                                c.v.a = 'a'; char val1 = get(); char val2 = get1();
 552                                c.v.a = 'b'; char val3 = get(); char val4 = get1();
 553 
 554                 assertEquals(val1, 'a');
 555                 assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
 556 
 557                 assertEquals(val2, 'a');
 558                 assertEquals(val4, 'b');
 559             }
 560         }
 561     }
 562 
 563     /* ==================================================== */
 564 
 565     static class NestedStableField3 {
 566         static class A {
 567             public @Stable char a;
 568             public @Stable A[] left;
 569             public         A[] right;
 570         }
 571 
 572         public @Stable A[] v;
 573 
 574         public static final NestedStableField3 c = new NestedStableField3();
 575         public static char get() { return c.v[0].left[1].left[0].left[1].a; }
 576         public static char get1() { return c.v[1].left[0].left[1].right[0].left[1].a; }
 577 
 578         public static void test() throws Exception {
 579             {
 580                 A elem = new A();
 581                 c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v;
 582                                elem.a = 'a'; char val1 = get(); char val2 = get1();
 583                                elem.a = 'b'; char val3 = get(); char val4 = get1();
 584 
 585                 assertEquals(val1, 'a');
 586                 assertEquals(val3, (isStableEnabled ? 'a' : 'b'));
 587 
 588                 assertEquals(val2, 'a');
 589                 assertEquals(val4, 'b');
 590             }
 591         }
 592     }
 593 
 594     /* ==================================================== */
 595     // Auxiliary methods
 596     static void assertEquals(int i, int j) { if (i != j)  throw new AssertionError(i + " != " + j); }
 597     static void assertTrue(boolean b) { if (!b)  throw new AssertionError(); }
 598 
 599     static boolean failed = false;
 600 
 601     public static void run(Class<?> test) {
 602         Throwable ex = null;
 603         System.out.print(test.getName()+": ");
 604         try {
 605             test.getMethod("test").invoke(null);
 606         } catch (InvocationTargetException e) {
 607             ex = e.getCause();
 608         } catch (Throwable e) {
 609             ex = e;
 610         } finally {
 611             if (ex == null) {
 612                 System.out.println("PASSED");
 613             } else {
 614                 failed = true;
 615                 System.out.println("FAILED");
 616                 ex.printStackTrace(System.out);
 617             }
 618         }
 619     }
 620 }