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 public class Main {
     18 
     19   public static void main(String[] args) {
     20     testSimpleUse();
     21     testTwoUses();
     22     testFieldStores(doThrow);
     23     testFieldStoreCycle();
     24     testArrayStores();
     25     testOnlyStoreUses();
     26     testNoUse();
     27     testPhiInput();
     28     testVolatileStore();
     29     doThrow = true;
     30     try {
     31       testInstanceSideEffects();
     32     } catch (Error e) {
     33       // expected
     34       System.out.println(e.getMessage());
     35     }
     36     try {
     37       testStaticSideEffects();
     38     } catch (Error e) {
     39       // expected
     40       System.out.println(e.getMessage());
     41     }
     42 
     43     try {
     44       testStoreStore(doThrow);
     45     } catch (Error e) {
     46       // expected
     47       System.out.println(e.getMessage());
     48     }
     49   }
     50 
     51   /// CHECK-START: void Main.testSimpleUse() code_sinking (before)
     52   /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
     53   /// CHECK: <<New:l\d+>>       NewInstance [<<LoadClass>>]
     54   /// CHECK:                    ConstructorFence [<<New>>]
     55   /// CHECK:                    If
     56   /// CHECK:                    begin_block
     57   /// CHECK:                    Throw
     58 
     59   /// CHECK-START: void Main.testSimpleUse() code_sinking (after)
     60   /// CHECK-NOT:                NewInstance
     61   /// CHECK:                    If
     62   /// CHECK:                    begin_block
     63   /// CHECK: <<Error:l\d+>>     LoadClass class_name:java.lang.Error
     64   /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
     65   /// CHECK-NOT:                begin_block
     66   /// CHECK: <<New:l\d+>>       NewInstance [<<LoadClass>>]
     67   /// CHECK:                    ConstructorFence [<<New>>]
     68   /// CHECK-NOT:                begin_block
     69   /// CHECK:                    NewInstance [<<Error>>]
     70   /// CHECK:                    Throw
     71   public static void testSimpleUse() {
     72     Object o = new Object();
     73     if (doThrow) {
     74       throw new Error(o.toString());
     75     }
     76   }
     77 
     78   /// CHECK-START: void Main.testTwoUses() code_sinking (before)
     79   /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
     80   /// CHECK:                    NewInstance [<<LoadClass>>]
     81   /// CHECK:                    If
     82   /// CHECK:                    begin_block
     83   /// CHECK:                    Throw
     84 
     85   /// CHECK-START: void Main.testTwoUses() code_sinking (after)
     86   /// CHECK-NOT:                NewInstance
     87   /// CHECK:                    If
     88   /// CHECK:                    begin_block
     89   /// CHECK: <<Error:l\d+>>     LoadClass class_name:java.lang.Error
     90   /// CHECK: <<LoadClass:l\d+>> LoadClass class_name:java.lang.Object
     91   /// CHECK-NOT:                begin_block
     92   /// CHECK:                    NewInstance [<<LoadClass>>]
     93   /// CHECK-NOT:                begin_block
     94   /// CHECK:                    NewInstance [<<Error>>]
     95   /// CHECK:                    Throw
     96   public static void testTwoUses() {
     97     Object o = new Object();
     98     if (doThrow) {
     99       throw new Error(o.toString() + o.toString());
    100     }
    101   }
    102 
    103   /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (before)
    104   /// CHECK: <<Int42:i\d+>>       IntConstant 42
    105   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
    106   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    107   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    108   /// CHECK:                      If
    109   /// CHECK:                      begin_block
    110   /// CHECK:                      Throw
    111 
    112   /// CHECK-START: void Main.testFieldStores(boolean) code_sinking (after)
    113   /// CHECK: <<Int42:i\d+>>       IntConstant 42
    114   /// CHECK-NOT:                  NewInstance
    115   /// CHECK:                      If
    116   /// CHECK:                      begin_block
    117   /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
    118   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
    119   /// CHECK-NOT:                  begin_block
    120   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    121   /// CHECK-NOT:                  begin_block
    122   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    123   /// CHECK-NOT:                  begin_block
    124   /// CHECK:                      NewInstance [<<Error>>]
    125   /// CHECK:                      Throw
    126   public static void testFieldStores(boolean doThrow) {
    127     Main m = new Main();
    128     m.intField = 42;
    129     if (doThrow) {
    130       throw new Error(m.toString());
    131     }
    132   }
    133 
    134   /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (before)
    135   /// CHECK: <<LoadClass:l\d+>>    LoadClass class_name:Main
    136   /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
    137   /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
    138   /// CHECK:                       InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
    139   /// CHECK:                       InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
    140   /// CHECK:                       If
    141   /// CHECK:                       begin_block
    142   /// CHECK:                       Throw
    143 
    144   // TODO(ngeoffray): Handle allocation/store cycles.
    145   /// CHECK-START: void Main.testFieldStoreCycle() code_sinking (after)
    146   /// CHECK: begin_block
    147   /// CHECK: <<LoadClass:l\d+>>    LoadClass class_name:Main
    148   /// CHECK: <<NewInstance1:l\d+>> NewInstance [<<LoadClass>>]
    149   /// CHECK: <<NewInstance2:l\d+>> NewInstance [<<LoadClass>>]
    150   /// CHECK:                       InstanceFieldSet [<<NewInstance1>>,<<NewInstance2>>]
    151   /// CHECK:                       InstanceFieldSet [<<NewInstance2>>,<<NewInstance1>>]
    152   /// CHECK:                       If
    153   /// CHECK:                       begin_block
    154   /// CHECK:                       Throw
    155   public static void testFieldStoreCycle() {
    156     Main m1 = new Main();
    157     Main m2 = new Main();
    158     m1.objectField = m2;
    159     m2.objectField = m1;
    160     if (doThrow) {
    161       throw new Error(m1.toString() + m2.toString());
    162     }
    163   }
    164 
    165   /// CHECK-START: void Main.testArrayStores() code_sinking (before)
    166   /// CHECK: <<Int1:i\d+>>        IntConstant 1
    167   /// CHECK: <<Int0:i\d+>>        IntConstant 0
    168   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object[]
    169   /// CHECK: <<NewArray:l\d+>>    NewArray [<<LoadClass>>,<<Int1>>]
    170   /// CHECK:                      ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
    171   /// CHECK:                      If
    172   /// CHECK:                      begin_block
    173   /// CHECK:                      Throw
    174 
    175   /// CHECK-START: void Main.testArrayStores() code_sinking (after)
    176   /// CHECK: <<Int1:i\d+>>        IntConstant 1
    177   /// CHECK: <<Int0:i\d+>>        IntConstant 0
    178   /// CHECK-NOT:                  NewArray
    179   /// CHECK:                      If
    180   /// CHECK:                      begin_block
    181   /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
    182   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object[]
    183   /// CHECK-NOT:                  begin_block
    184   /// CHECK: <<NewArray:l\d+>>    NewArray [<<LoadClass>>,<<Int1>>]
    185   /// CHECK-NOT:                  begin_block
    186   /// CHECK:                      ArraySet [<<NewArray>>,<<Int0>>,<<NewArray>>]
    187   /// CHECK-NOT:                  begin_block
    188   /// CHECK:                      NewInstance [<<Error>>]
    189   /// CHECK:                      Throw
    190   public static void testArrayStores() {
    191     Object[] o = new Object[1];
    192     o[0] = o;
    193     if (doThrow) {
    194       throw new Error(o.toString());
    195     }
    196   }
    197 
    198   // Make sure code sinking does not crash on dead allocations.
    199   public static void testOnlyStoreUses() {
    200     Main m = new Main();
    201     Object[] o = new Object[1];  // dead allocation, should eventually be removed b/35634932.
    202     o[0] = m;
    203     o = null;  // Avoid environment uses for the array allocation.
    204     if (doThrow) {
    205       throw new Error(m.toString());
    206     }
    207   }
    208 
    209   // Make sure code sinking does not crash on dead code.
    210   public static void testNoUse() {
    211     Main m = new Main();
    212     boolean load = Main.doLoop;  // dead code, not removed because of environment use.
    213     // Ensure one environment use for the static field
    214     $opt$noinline$foo();
    215     load = false;
    216     if (doThrow) {
    217       throw new Error(m.toString());
    218     }
    219   }
    220 
    221   // Make sure we can move code only used by a phi.
    222   /// CHECK-START: void Main.testPhiInput() code_sinking (before)
    223   /// CHECK: <<Null:l\d+>>        NullConstant
    224   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object
    225   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    226   /// CHECK:                      If
    227   /// CHECK:                      begin_block
    228   /// CHECK:                      Phi [<<Null>>,<<NewInstance>>]
    229   /// CHECK:                      Throw
    230 
    231   /// CHECK-START: void Main.testPhiInput() code_sinking (after)
    232   /// CHECK: <<Null:l\d+>>        NullConstant
    233   /// CHECK-NOT:                  NewInstance
    234   /// CHECK:                      If
    235   /// CHECK:                      begin_block
    236   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:java.lang.Object
    237   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    238   /// CHECK:                      begin_block
    239   /// CHECK:                      Phi [<<Null>>,<<NewInstance>>]
    240   /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
    241   /// CHECK:                      NewInstance [<<Error>>]
    242   /// CHECK:                      Throw
    243   public static void testPhiInput() {
    244     Object f = new Object();
    245     if (doThrow) {
    246       Object o = null;
    247       int i = 2;
    248       if (doLoop) {
    249         o = f;
    250         i = 42;
    251       }
    252       throw new Error(o.toString() + i);
    253     }
    254   }
    255 
    256   static void $opt$noinline$foo() {}
    257 
    258   // Check that we do not move volatile stores.
    259   /// CHECK-START: void Main.testVolatileStore() code_sinking (before)
    260   /// CHECK: <<Int42:i\d+>>        IntConstant 42
    261   /// CHECK: <<LoadClass:l\d+>>    LoadClass class_name:Main
    262   /// CHECK: <<NewInstance:l\d+>>  NewInstance [<<LoadClass>>]
    263   /// CHECK:                       InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    264   /// CHECK:                       If
    265   /// CHECK:                       begin_block
    266   /// CHECK:                       Throw
    267 
    268   /// CHECK-START: void Main.testVolatileStore() code_sinking (after)
    269   /// CHECK: <<Int42:i\d+>>        IntConstant 42
    270   /// CHECK: <<LoadClass:l\d+>>    LoadClass class_name:Main
    271   /// CHECK: <<NewInstance:l\d+>>  NewInstance [<<LoadClass>>]
    272   /// CHECK:                       InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    273   /// CHECK:                       If
    274   /// CHECK:                       begin_block
    275   /// CHECK:                       Throw
    276   public static void testVolatileStore() {
    277     Main m = new Main();
    278     m.volatileField = 42;
    279     if (doThrow) {
    280       throw new Error(m.toString());
    281     }
    282   }
    283 
    284   public static void testInstanceSideEffects() {
    285     int a = mainField.intField;
    286     $noinline$changeIntField();
    287     if (doThrow) {
    288       throw new Error("" + a);
    289     }
    290   }
    291 
    292   static void $noinline$changeIntField() {
    293     mainField.intField = 42;
    294   }
    295 
    296   public static void testStaticSideEffects() {
    297     Object o = obj;
    298     $noinline$changeStaticObjectField();
    299     if (doThrow) {
    300       throw new Error(o.getClass().toString());
    301     }
    302   }
    303 
    304   static void $noinline$changeStaticObjectField() {
    305     obj = new Main();
    306   }
    307 
    308   // Test that we preserve the order of stores.
    309   /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (before)
    310   /// CHECK: <<Int42:i\d+>>       IntConstant 42
    311   /// CHECK: <<Int43:i\d+>>       IntConstant 43
    312   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
    313   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    314   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    315   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int43>>]
    316   /// CHECK:                      If
    317   /// CHECK:                      begin_block
    318   /// CHECK:                      Throw
    319 
    320   /// CHECK-START: void Main.testStoreStore(boolean) code_sinking (after)
    321   /// CHECK: <<Int42:i\d+>>       IntConstant 42
    322   /// CHECK: <<Int43:i\d+>>       IntConstant 43
    323   /// CHECK-NOT:                  NewInstance
    324   /// CHECK:                      If
    325   /// CHECK:                      begin_block
    326   /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
    327   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
    328   /// CHECK-NOT:                  begin_block
    329   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
    330   /// CHECK-NOT:                  begin_block
    331   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
    332   /// CHECK-NOT:                  begin_block
    333   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int43>>]
    334   /// CHECK-NOT:                  begin_block
    335   /// CHECK:                      NewInstance [<<Error>>]
    336   /// CHECK:                      Throw
    337   public static void testStoreStore(boolean doThrow) {
    338     Main m = new Main();
    339     m.intField = 42;
    340     m.intField2 = 43;
    341     if (doThrow) {
    342       throw new Error(m.$opt$noinline$toString());
    343     }
    344   }
    345 
    346   public String $opt$noinline$toString() {
    347     return "" + intField;
    348   }
    349 
    350   volatile int volatileField;
    351   int intField;
    352   int intField2;
    353   Object objectField;
    354   static boolean doThrow;
    355   static boolean doLoop;
    356   static Main mainField = new Main();
    357   static Object obj = new Object();
    358 }
    359