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