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