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