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