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