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