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