Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 import java.lang.reflect.Array;
     18 import java.lang.reflect.Field;
     19 import java.lang.reflect.Method;
     20 import java.lang.reflect.Modifier;
     21 
     22 // Baseline class. This has no final fields, so there are no additional freezes
     23 // in its constructor.
     24 //
     25 // The new-instance itself always has 1 freeze for the happens-before on the object header
     26 // write (i.e. [obj.class = X] happens-before any access to obj).
     27 //
     28 // Total freezes for "new Base()": 1.
     29 class Base {
     30   int w0;
     31   int w1;
     32   int w2;
     33   int w3;
     34 
     35   @Override
     36   public String toString() {
     37     return getClass().getName() + "(" + baseString() + ")";
     38   }
     39 
     40   protected String baseString() {
     41     return String.format("w0: %d, w1: %d, w2: %d, w3: %d", w0, w1, w2, w3);
     42   }
     43 }
     44 
     45 // This has a final field in its constructor, so there must be a field freeze
     46 // at the end of <init>.
     47 //
     48 // Total freezes for "new OneFinal()": 2.
     49 class OneFinal extends Base {
     50   final int x;
     51   OneFinal(int x) {
     52     this.x = x;
     53   }
     54 
     55   @Override
     56   protected String baseString() {
     57     return String.format("%s, x: %d", super.baseString(), x);
     58   }
     59 }
     60 
     61 class Assert {
     62   public static void stringEquals(String expected, Object actual) {
     63     stringEquals$noinline$(expected, actual);
     64   }
     65 
     66   // Forbid compiler from inlining this to avoid overly clever optimizations.
     67   private static void stringEquals$noinline$(String expected, Object actual) {
     68     String actualStr = Main.valueToString(actual);
     69     if (!expected.equals(actualStr)) {
     70       throw new AssertionError("Expected: " + expected + ", actual: " + actualStr);
     71     }
     72   }
     73 }
     74 
     75 interface Test {
     76   public void exercise();
     77   public void check();
     78 }
     79 
     80 class TestOneFinal implements Test {
     81   // Initialize at least once before actual test.
     82   public static Object external;
     83 
     84   /// CHECK-START: void TestOneFinal.exercise() constructor_fence_redundancy_elimination (before)
     85   /// CHECK: <<NewInstance:l\d+>>     NewInstance
     86   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
     87   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
     88   /// CHECK-NOT:                      ConstructorFence
     89   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
     90 
     91   /// CHECK-START: void TestOneFinal.exercise() constructor_fence_redundancy_elimination (after)
     92   /// CHECK: <<NewInstance:l\d+>>     NewInstance
     93   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
     94   /// CHECK-NOT:                      ConstructorFence
     95   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
     96   @Override
     97   public void exercise() {
     98       Base b = new OneFinal(1);
     99       // 1 store, 2 freezes.
    100 
    101       // Stores to 'b' do not escape b.
    102       b.w0 = 1;
    103       b.w1 = 2;
    104       b.w2 = 3;
    105 
    106       // Publish the result to a global so that it is not LSE-eliminated.
    107       external = b;
    108   }
    109 
    110   @Override
    111   public void check() {
    112     Assert.stringEquals("OneFinal(w0: 1, w1: 2, w2: 3, w3: 0, x: 1)", external);
    113   }
    114 }
    115 
    116 // This has a final field in its constructor, so there must be a field freeze
    117 // at the end of <init>. The previous base class's freezes accumulate on top
    118 // of this one.
    119 //
    120 // Total freezes for "new TwoFinal()": 3.
    121 class TwoFinal extends OneFinal {
    122   final int y;
    123   TwoFinal(int x, int y) {
    124     super(x);
    125     this.y = y;
    126   }
    127 
    128   @Override
    129   protected String baseString() {
    130     return String.format("%s, y: %d", super.baseString(), y);
    131   }
    132 }
    133 
    134 // This has a final field in its constructor, so there must be a field freeze
    135 // at the end of <init>. The previous base class's freezes accumulate on top
    136 // of this one.
    137 //
    138 // Total freezes for "new ThreeFinal()": 4.
    139 class ThreeFinal extends TwoFinal {
    140   final int z;
    141   ThreeFinal(int x, int y, int z) {
    142     super(x, y);
    143     this.z = z;
    144   }
    145 
    146   @Override
    147   protected String baseString() {
    148     return String.format("%s, z: %d", super.baseString(), z);
    149   }
    150 }
    151 
    152 class TestThreeFinal implements Test {
    153   // Initialize at least once before actual test.
    154   public static Object external;
    155 
    156   /// CHECK-START: void TestThreeFinal.exercise() constructor_fence_redundancy_elimination (before)
    157   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    158   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    159   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    160   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    161   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    162   /// CHECK-NOT:                      ConstructorFence
    163   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    164 
    165   /// CHECK-START: void TestThreeFinal.exercise() constructor_fence_redundancy_elimination (after)
    166   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    167   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    168   /// CHECK-NOT:                      ConstructorFence
    169   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    170   @Override
    171   public void exercise() {
    172     Base b = new ThreeFinal(1, 1, 2);
    173     // 3 store, 4 freezes.
    174 
    175     // Stores to 'b' do not escape b.
    176     b.w0 = 3;
    177 
    178     // Publish the result to a global so that it is not LSE-eliminated.
    179     external = b;
    180   }
    181 
    182   @Override
    183   public void check() {
    184     Assert.stringEquals("ThreeFinal(w0: 3, w1: 0, w2: 0, w3: 0, x: 1, y: 1, z: 2)", external);
    185   }
    186 }
    187 
    188 // Ensure "freezes" between multiple new-instances are optimized out.
    189 class TestMultiAlloc implements Test {
    190   public static Object external;
    191   public static Object external2;
    192 
    193   /// CHECK-START: void TestMultiAlloc.exercise() constructor_fence_redundancy_elimination (before)
    194   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    195   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    196   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    197   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    198   /// CHECK-NOT:                      ConstructorFence
    199   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    200   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    201 
    202   /// CHECK-START: void TestMultiAlloc.exercise() constructor_fence_redundancy_elimination (after)
    203   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    204   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    205   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>,<<NewInstance>>]
    206   /// CHECK-NOT:                      ConstructorFence
    207   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    208   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    209   @Override
    210   public void exercise() {
    211     // 1 freeze
    212     Base b = new Base();
    213     // 1 freeze
    214     Base b2 = new Base();
    215 
    216     // Merge 2 freezes above into 1 constructor fence.
    217     external = b;
    218     external2 = b2;
    219   }
    220 
    221   @Override
    222   public void check() {
    223     Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    224     Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external2);
    225   }
    226 }
    227 
    228 // Ensure "freezes" between multiple new-instances are optimized out.
    229 class TestThreeFinalTwice implements Test {
    230   // Initialize at least once before actual test.
    231   public static Object external;
    232   public static Object external2;
    233 
    234   /// CHECK-START: void TestThreeFinalTwice.exercise() constructor_fence_redundancy_elimination (before)
    235   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    236   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    237   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    238   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    239   /// CHECK-DAG:                      ConstructorFence [<<NewInstance>>]
    240   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    241   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    242   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    243   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    244   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    245   /// CHECK-NOT:                      ConstructorFence
    246   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    247   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    248 
    249   /// CHECK-START: void TestThreeFinalTwice.exercise() constructor_fence_redundancy_elimination (after)
    250   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    251   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    252   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>,<<NewInstance>>]
    253   /// CHECK-NOT:                      ConstructorFence
    254   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    255   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    256   @Override
    257   public void exercise() {
    258     Base b = new ThreeFinal(1, 1, 2);
    259     // 3 store, 4 freezes.
    260 
    261     // Stores to 'b' do not escape b.
    262     b.w0 = 3;
    263 
    264     Base b2 = new ThreeFinal(4, 5, 6);
    265     // 3 store, 4 freezes.
    266 
    267     // Stores to 'b2' do not escape b2.
    268     b2.w0 = 7;
    269 
    270     // Publish the result to a global so that it is not LSE-eliminated.
    271     // Publishing is done at the end to give freezes above a chance to merge.
    272     external = b;
    273     external2 = b2;
    274   }
    275 
    276   @Override
    277   public void check() {
    278     Assert.stringEquals("ThreeFinal(w0: 3, w1: 0, w2: 0, w3: 0, x: 1, y: 1, z: 2)", external);
    279     Assert.stringEquals("ThreeFinal(w0: 7, w1: 0, w2: 0, w3: 0, x: 4, y: 5, z: 6)", external2);
    280   }
    281 }
    282 
    283 class TestNonEscaping {
    284   // Prevent constant folding.
    285   static boolean test;
    286 
    287   static Object external;
    288   static Object external2;
    289   static Object external3;
    290   static Object external4;
    291 
    292   static class Invoke implements Test {
    293     /// CHECK-START: void TestNonEscaping$Invoke.exercise() constructor_fence_redundancy_elimination (before)
    294     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    295     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    296     /// CHECK:                          InvokeStaticOrDirect
    297     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    298     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    299     /// CHECK-NOT:                      ConstructorFence
    300 
    301     /// CHECK-START: void TestNonEscaping$Invoke.exercise() constructor_fence_redundancy_elimination (after)
    302     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    303     /// CHECK:                          InvokeStaticOrDirect
    304     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    305     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>,<<NewInstance>>]
    306     /// CHECK-NOT:                      ConstructorFence
    307     @Override
    308     public void exercise() {
    309       Base b = new Base();
    310 
    311       // b cannot possibly escape into this invoke because it hasn't escaped onto the heap earlier,
    312       // and the invoke doesn't take it as a parameter.
    313       noEscape$noinline$();
    314 
    315       // Remove the Constructor Fence for b, merging into the fence for b2.
    316       Base b2 = new Base();
    317 
    318       // Do not LSE-eliminate b,b2
    319       external = b;
    320       external2 = b2;
    321     }
    322 
    323     @Override
    324     public void check() {
    325       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    326       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external2);
    327     }
    328   }
    329 
    330   public static int[] array = new int[1];
    331   static Base base = new Base();
    332 
    333   static class Store implements Test {
    334     /// CHECK-START: void TestNonEscaping$Store.exercise() constructor_fence_redundancy_elimination (before)
    335     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    336     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    337     /// CHECK-DAG:                      ArraySet
    338     /// CHECK-DAG:                      StaticFieldSet
    339     /// CHECK-DAG:                      InstanceFieldSet
    340     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    341     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    342     /// CHECK-NOT:                      ConstructorFence
    343 
    344     /// CHECK-START: void TestNonEscaping$Store.exercise() constructor_fence_redundancy_elimination (after)
    345     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    346     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    347     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>,<<NewInstance>>]
    348     /// CHECK-NOT:                        ConstructorFence
    349     @Override
    350     public void exercise() {
    351       Base b = new Base();
    352 
    353       // Stores of inputs other than the fence target do not publish 'b'.
    354       array[0] = b.w0;  // aput
    355       external = array; // sput
    356       base.w0 = b.w0;   // iput
    357 
    358       // Remove the Constructor Fence for b, merging into the fence for b2.
    359       Base b2 = new Base();
    360 
    361       // Do not LSE-eliminate b,b2
    362       external3 = b;
    363       external4 = b2;
    364     }
    365 
    366     @Override
    367     public void check() {
    368       Assert.stringEquals("[0]", array);
    369       Assert.stringEquals("[0]", external);
    370       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", base);
    371       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    372       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    373     }
    374   }
    375 
    376   private static void noEscape$noinline$() {
    377   }
    378 }
    379 
    380 class TestDontOptimizeAcrossBlocks implements Test {
    381   // Prevent constant folding.
    382   static boolean test;
    383 
    384   static Object external;
    385   static Object external3;
    386 
    387   /// CHECK-START: void TestDontOptimizeAcrossBlocks.exercise() constructor_fence_redundancy_elimination (before)
    388   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    389   /// CHECK:                          ConstructorFence [<<NewInstance>>]
    390   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    391   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    392   /// CHECK-NOT:                      ConstructorFence
    393   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    394   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    395 
    396   /// CHECK-START: void TestDontOptimizeAcrossBlocks.exercise() constructor_fence_redundancy_elimination (after)
    397   /// CHECK: <<NewInstance:l\d+>>     NewInstance
    398   /// CHECK:                          ConstructorFence [<<NewInstance>>]
    399   /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    400   /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    401   /// CHECK-NOT:                      ConstructorFence
    402   /// CHECK-DAG:                      StaticFieldSet [<<External:l\d+>>,<<NewInstance>>]
    403   /// CHECK-DAG:                      StaticFieldSet [<<External2:l\d+>>,<<NewInstance2>>]
    404   @Override
    405   public void exercise() {
    406     Base b = new Base();
    407 
    408     // Do not move constructor fence across this block, even though 'b' is not published yet.
    409     if (test) {
    410       external = null;
    411     }
    412 
    413     Base b2 = new Base();
    414     external = b2;
    415     external3 = b;
    416   }
    417 
    418   @Override
    419   public void check() {
    420     Assert.stringEquals("false", test);
    421     Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    422     Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    423   }
    424 }
    425 
    426 class TestDontOptimizeAcrossEscape {
    427   // Prevent constant folding.
    428   static boolean test;
    429 
    430   static Object external;
    431   static Object external2;
    432   static Object external3;
    433   static Object external4;
    434 
    435   static class Invoke implements Test {
    436     /// CHECK-START: void TestDontOptimizeAcrossEscape$Invoke.exercise() constructor_fence_redundancy_elimination (before)
    437     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    438     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    439     /// CHECK:                          InvokeStaticOrDirect
    440     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    441     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    442     /// CHECK-NOT:                      ConstructorFence
    443 
    444     /// CHECK-START: void TestDontOptimizeAcrossEscape$Invoke.exercise() constructor_fence_redundancy_elimination (after)
    445     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    446     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    447     /// CHECK:                          InvokeStaticOrDirect
    448     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    449     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    450     /// CHECK-NOT:                      ConstructorFence
    451     @Override
    452     public void exercise() {
    453       Base b = new Base();
    454       // Do not optimize across invokes into which the fence target escapes.
    455       invoke$noinline$(b);
    456 
    457       Base b2 = new Base();
    458 
    459       // Do not LSE-eliminate b,b2
    460       external = b;
    461       external2 = b2;
    462     }
    463 
    464     private static void invoke$noinline$(Object b) {
    465       // Even though 'b' does not escape this method, we conservatively assume all parameters
    466       // of an invoke escape.
    467     }
    468 
    469     @Override
    470     public void check() {
    471       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    472       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external2);
    473     }
    474   }
    475 
    476   public static Object[] array = new Object[3];
    477   static Base base = new Base();
    478 
    479   static class InstanceEscaper {
    480     public Object holder;
    481 
    482     @Override
    483     public String toString() {
    484       return getClass().getName() + "(" + baseString() + ")";
    485     }
    486 
    487     protected String baseString() {
    488       return String.format("holder: %s", Main.valueToString(holder));
    489     }
    490   }
    491 
    492   static InstanceEscaper instanceEscaper = new InstanceEscaper();
    493 
    494   static class StoreIput implements Test {
    495     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreIput.exercise() constructor_fence_redundancy_elimination (before)
    496     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    497     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    498     /// CHECK-DAG:                      InstanceFieldSet
    499     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    500     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    501     /// CHECK-NOT:                      ConstructorFence
    502 
    503     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreIput.exercise() constructor_fence_redundancy_elimination (after)
    504     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    505     /// CHECK:                            ConstructorFence [<<NewInstance>>]
    506     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    507     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>]
    508     /// CHECK-NOT:                        ConstructorFence
    509     @Override
    510     public void exercise() {
    511       Base b = new Base();
    512 
    513       // A store of 'b' into another instance will publish 'b'.
    514       instanceEscaper.holder = b;
    515 
    516       // Do not remove any constructor fences above.
    517       Base b2 = new Base();
    518 
    519       // Do not LSE-eliminate b,b2
    520       external3 = b;
    521       external4 = b2;
    522     }
    523 
    524     @Override
    525     public void check() {
    526       Assert.stringEquals(
    527           "TestDontOptimizeAcrossEscape$InstanceEscaper(holder: Base(w0: 0, w1: 0, w2: 0, w3: 0))",
    528           instanceEscaper);
    529       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    530       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    531     }
    532   }
    533 
    534   static class StoreAput implements Test {
    535     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreAput.exercise() constructor_fence_redundancy_elimination (before)
    536     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    537     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    538     /// CHECK-DAG:                      ArraySet
    539     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    540     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    541     /// CHECK-NOT:                      ConstructorFence
    542 
    543     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreAput.exercise() constructor_fence_redundancy_elimination (after)
    544     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    545     /// CHECK:                            ConstructorFence [<<NewInstance>>]
    546     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    547     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>]
    548     /// CHECK-NOT:                        ConstructorFence
    549     @Override
    550     public void exercise() {
    551       Base b = new Base();
    552 
    553       // A store of 'b' into another array will publish 'b'.
    554       array[0] = b;  // aput
    555 
    556       // Do not remove any constructor fences above.
    557       Base b2 = new Base();
    558 
    559       // Do not LSE-eliminate b,b2
    560       external3 = b;
    561       external4 = b2;
    562     }
    563 
    564     @Override
    565     public void check() {
    566       Assert.stringEquals("[Base(w0: 0, w1: 0, w2: 0, w3: 0),<null>,<null>]", array);
    567       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    568       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    569     }
    570   }
    571 
    572   static class StoreSput implements Test {
    573     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreSput.exercise() constructor_fence_redundancy_elimination (before)
    574     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    575     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    576     /// CHECK-DAG:                      StaticFieldSet
    577     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    578     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    579     /// CHECK-NOT:                      ConstructorFence
    580 
    581     /// CHECK-START: void TestDontOptimizeAcrossEscape$StoreSput.exercise() constructor_fence_redundancy_elimination (after)
    582     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    583     /// CHECK:                            ConstructorFence [<<NewInstance>>]
    584     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    585     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>]
    586     /// CHECK-NOT:                        ConstructorFence
    587     @Override
    588     public void exercise() {
    589       Base b = new Base();
    590 
    591       // A store of 'b' into a static will publish 'b'.
    592       external = b;
    593 
    594       // Do not remove any constructor fences above.
    595       Base b2 = new Base();
    596 
    597       // Do not LSE-eliminate b,b2
    598       external3 = b;
    599       external4 = b2;
    600     }
    601 
    602     @Override
    603     public void check() {
    604       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    605       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    606       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    607     }
    608   }
    609 
    610   static class Deopt implements Test {
    611     /// CHECK-START: void TestDontOptimizeAcrossEscape$Deopt.exercise() constructor_fence_redundancy_elimination (before)
    612     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    613     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    614     /// CHECK-DAG:                      Deoptimize
    615     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    616     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    617     /// CHECK-NOT:                      ConstructorFence
    618 
    619     /// CHECK-START: void TestDontOptimizeAcrossEscape$Deopt.exercise() constructor_fence_redundancy_elimination (after)
    620     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    621     /// CHECK:                            ConstructorFence [<<NewInstance>>]
    622     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    623     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>]
    624     /// CHECK-NOT:                        ConstructorFence
    625     @Override
    626     public void exercise() {
    627       Base b = new Base();
    628 
    629       // An array access generates a Deopt to avoid doing bounds check.
    630       array[0] = external;  // aput
    631       array[1] = external;  // aput
    632       array[2] = external;  // aput
    633 
    634       // Do not remove any constructor fences above.
    635       Base b2 = new Base();
    636 
    637       // Do not LSE-eliminate b,b2
    638       external3 = b;
    639       external4 = b2;
    640     }
    641 
    642     @Override
    643     public void check() {
    644       Assert.stringEquals("[Base(w0: 0, w1: 0, w2: 0, w3: 0),"
    645               + "Base(w0: 0, w1: 0, w2: 0, w3: 0),"
    646               + "Base(w0: 0, w1: 0, w2: 0, w3: 0)]",
    647           array);
    648       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    649       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    650     }
    651   }
    652 
    653   static class Select implements Test {
    654     /// CHECK-START: void TestDontOptimizeAcrossEscape$Select.exercise() constructor_fence_redundancy_elimination (before)
    655     /// CHECK: <<NewInstance:l\d+>>     NewInstance
    656     /// CHECK:                          ConstructorFence [<<NewInstance>>]
    657     /// CHECK-DAG:                      Select
    658     /// CHECK: <<NewInstance2:l\d+>>    NewInstance
    659     /// CHECK-DAG:                      ConstructorFence [<<NewInstance2>>]
    660     /// CHECK-NOT:                      ConstructorFence
    661 
    662     /// CHECK-START: void TestDontOptimizeAcrossEscape$Select.exercise() constructor_fence_redundancy_elimination (after)
    663     /// CHECK-DAG: <<NewInstance:l\d+>>   NewInstance
    664     /// CHECK:                            ConstructorFence [<<NewInstance>>]
    665     /// CHECK-DAG: <<NewInstance2:l\d+>>  NewInstance
    666     /// CHECK-DAG:                        ConstructorFence [<<NewInstance2>>]
    667     /// CHECK-NOT:                        ConstructorFence
    668     @Override
    669     public void exercise() {
    670       Base b = new Base();
    671 
    672       boolean localTest = test;
    673       Object localExternal = external3;
    674 
    675       // Selecting 'b' creates an alias, which we conservatively assume escapes immediately.
    676       external = localTest ? b : localExternal;
    677 
    678       // Do not remove any constructor fences above.
    679       Base b2 = new Base();
    680 
    681       // Do not LSE-eliminate b,b2
    682       external3 = b;
    683       external4 = b2;
    684     }
    685 
    686     @Override
    687     public void check() {
    688       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external);
    689       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external3);
    690       Assert.stringEquals("Base(w0: 0, w1: 0, w2: 0, w3: 0)", external4);
    691     }
    692   }
    693 
    694   static class MakeBoundTypeTest implements Test {
    695     public static Object makeBoundType;
    696     public static Object makeBoundTypeSub;
    697 
    698     @Override
    699     public void exercise() {
    700       // Note: MakeBoundType is special and we have to call the constructor directly
    701       // to prevent inlining it.
    702       try {
    703         makeBoundType = exerciseNewInstance(MakeBoundType.class, 123);
    704         makeBoundTypeSub = exerciseNewInstance(MakeBoundTypeSub.class, 123);
    705       } catch (Exception e) {
    706         throw new RuntimeException(e);
    707       }
    708     }
    709 
    710     @Override
    711     public void check() {
    712       Assert.stringEquals(
    713           "TestDontOptimizeAcrossEscape$MakeBoundTypeTest$MakeBoundType(abcdefgh: 123, x: 2)",
    714           makeBoundType);
    715       Assert.stringEquals(
    716           "TestDontOptimizeAcrossEscape$MakeBoundTypeTest$MakeBoundTypeSub(abcdefgh: 123, x: 1)",
    717           makeBoundTypeSub);
    718     }
    719 
    720     // Make a new instance of 'klass'.
    721     private static <T> T exerciseNewInstance(Class<T> klass, int params) throws Exception {
    722       return klass.cast(klass.getDeclaredConstructor(int.class).newInstance(params));
    723     }
    724 
    725     /// CHECK-START: void TestDontOptimizeAcrossEscape$MakeBoundTypeTest$MakeBoundType.<init>(int) constructor_fence_redundancy_elimination (before)
    726     /// CHECK-DAG: <<This:l\d+>>         ParameterValue
    727     /// CHECK-DAG: <<NewInstance:l\d+>>  NewInstance
    728     /// CHECK:                           ConstructorFence [<<NewInstance>>]
    729     /// CHECK-DAG:                       BoundType
    730     /// CHECK-DAG:                       ConstructorFence [<<This>>]
    731     /// CHECK-NOT:                       ConstructorFence
    732 
    733     /// CHECK-START: void TestDontOptimizeAcrossEscape$MakeBoundTypeTest$MakeBoundType.<init>(int) constructor_fence_redundancy_elimination (after)
    734     /// CHECK-DAG: <<This:l\d+>>         ParameterValue
    735     /// CHECK-DAG: <<NewInstance:l\d+>>  NewInstance
    736     /// CHECK:                           ConstructorFence [<<NewInstance>>]
    737     /// CHECK-DAG:                       BoundType
    738     /// CHECK-DAG:                       ConstructorFence [<<This>>]
    739     /// CHECK-NOT:                       ConstructorFence
    740     static class MakeBoundType {
    741       final int abcdefgh;
    742       int x;
    743 
    744       MakeBoundType(int param) {
    745         abcdefgh = param;
    746 
    747         Base b = new Base();
    748         // constructor-fence(b)
    749 
    750         if (this instanceof MakeBoundTypeSub) {
    751           // Create a "BoundType(this)" which prevents
    752           // a merged constructor-fence(this, b)
    753           x = 1;
    754         } else {
    755           x = 2;
    756         }
    757 
    758         // publish(b).
    759         external = b;
    760 
    761         // constructor-fence(this)
    762       }
    763 
    764       @Override
    765       public String toString() {
    766         return getClass().getName() + "(" + baseString() + ")";
    767       }
    768 
    769       protected String baseString() {
    770         return String.format("abcdefgh: %d, x: %d", abcdefgh, x);
    771       }
    772     }
    773 
    774     static class MakeBoundTypeSub extends MakeBoundType {
    775       MakeBoundTypeSub(int xyz) {
    776         super(xyz);
    777       }
    778     }
    779   }
    780 }
    781 
    782 public class Main {
    783   public static void main(String[] args) throws Exception {
    784     // Ensure that all of this code does not get optimized out into a no-op
    785     // by actually running the code with reflection, then validating
    786     // the result by asserting it against a string.
    787     Class<? extends Test>[] testClasses = new Class[] {
    788       TestOneFinal.class,
    789       TestThreeFinal.class,
    790       TestMultiAlloc.class,
    791       TestThreeFinalTwice.class,
    792       TestNonEscaping.Invoke.class,
    793       TestNonEscaping.Store.class,
    794       TestDontOptimizeAcrossBlocks.class,
    795       TestDontOptimizeAcrossEscape.Invoke.class,
    796       TestDontOptimizeAcrossEscape.StoreIput.class,
    797       TestDontOptimizeAcrossEscape.StoreAput.class,
    798       TestDontOptimizeAcrossEscape.StoreSput.class,
    799       TestDontOptimizeAcrossEscape.Deopt.class,
    800       TestDontOptimizeAcrossEscape.Select.class,
    801       TestDontOptimizeAcrossEscape.MakeBoundTypeTest.class,
    802     };
    803 
    804     for (Class<? extends Test> klass : testClasses) {
    805       exerciseTestClass(klass);
    806     }
    807   }
    808 
    809   /**
    810    * Invoke Test#exercise(), then Test#check().
    811    * @throws AssertionError if test fails.
    812    */
    813   private static void exerciseTestClass(Class<? extends Test> klass) throws Exception {
    814     Test instance = klass.cast(klass.getDeclaredConstructor().newInstance());
    815 
    816     // Use reflection as a best-effort to avoid compiler optimizations (e.g. inlining).
    817     instance.getClass().getDeclaredMethod("exercise").invoke(instance);
    818     instance.getClass().getDeclaredMethod("check").invoke(instance);
    819   }
    820 
    821   // Print an object, with special handling for array and null.
    822   public static String valueToString(Object val) {
    823     if (val == null) {
    824       return "<null>";
    825     }
    826     if (val.getClass().isArray()) {
    827       String fmt = "[";
    828       int length = Array.getLength(val);
    829       for (int i = 0; i < length; ++i) {
    830         Object arrayElement = Array.get(val, i);
    831         fmt += valueToString(arrayElement);
    832 
    833         if (i != length - 1) {
    834           fmt += ",";
    835         }
    836       }
    837       fmt += "]";
    838 
    839       return fmt;
    840     }
    841 
    842     return val.toString();
    843   }
    844 }
    845