1 /* 2 * Copyright (C) 2016 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.Method; 18 import java.lang.reflect.InvocationTargetException; 19 20 class Test1 { 21 int[] iarr; 22 } 23 24 class Test2 { 25 float[] farr; 26 } 27 28 public class Main { getObjectArray()29 public static Object[] getObjectArray() { return null; } getLongArray()30 public static long[] getLongArray() { return null; } getNull()31 public static Object getNull() { return null; } getNullTest1()32 public static Test1 getNullTest1() { return null; } getNullTest2()33 public static Test2 getNullTest2() { return null; } 34 $noinline$runSmaliTest(String name)35 public static void $noinline$runSmaliTest(String name) throws Throwable { 36 try { 37 Class<?> c = Class.forName("SmaliTests"); 38 Method m = c.getMethod(name); 39 m.invoke(null); 40 } catch (InvocationTargetException ex) { 41 throw ex.getCause(); // re-raise expected exception. 42 } catch (Exception ex) { 43 throw new Error(ex); 44 } 45 } 46 main(String[] args)47 public static void main(String[] args) { 48 try { 49 foo(); 50 throw new Error("Expected NullPointerException"); 51 } catch (NullPointerException e) { 52 // Expected. 53 } 54 try { 55 bar(); 56 throw new Error("Expected NullPointerException"); 57 } catch (NullPointerException e) { 58 // Expected. 59 } 60 try { 61 $noinline$runSmaliTest("bar"); 62 throw new Error("Expected NullPointerException"); 63 } catch (NullPointerException e) { 64 // Expected. 65 } catch (Throwable t) { 66 throw new Error("Unexpected Throwable", t); 67 } 68 try { 69 $noinline$runSmaliTest("bar2"); 70 throw new Error("Expected NullPointerException"); 71 } catch (NullPointerException e) { 72 // Expected. 73 } catch (Throwable t) { 74 throw new Error("Unexpected Throwable", t); 75 } 76 77 try { 78 test1(); 79 throw new Error("Expected NullPointerException"); 80 } catch (NullPointerException e) { 81 // Expected. 82 } 83 } 84 85 /// CHECK-START: void Main.foo() load_store_elimination (after) 86 /// CHECK-DAG: <<Null:l\d+>> NullConstant 87 /// CHECK-DAG: <<Check:l\d+>> NullCheck [<<Null>>] 88 /// CHECK-DAG: <<Get1:j\d+>> ArrayGet [<<Check>>,{{i\d+}}] 89 /// CHECK-DAG: <<Get2:l\d+>> ArrayGet [<<Check>>,{{i\d+}}] foo()90 public static void foo() { 91 longField = getLongArray()[0]; 92 objectField = getObjectArray()[0]; 93 } 94 95 /// CHECK-START: void Main.bar() load_store_elimination (after) 96 /// CHECK-DAG: <<Null:l\d+>> NullConstant 97 /// CHECK-DAG: BoundType [<<Null>>] 98 /// CHECK-DAG: <<CheckL:l\d+>> NullCheck 99 /// CHECK-DAG: <<GetL0:l\d+>> ArrayGet [<<CheckL>>,{{i\d+}}] 100 /// CHECK-DAG: <<GetL1:l\d+>> ArrayGet [<<CheckL>>,{{i\d+}}] 101 /// CHECK-DAG: <<GetL2:l\d+>> ArrayGet [<<CheckL>>,{{i\d+}}] 102 /// CHECK-DAG: <<GetL3:l\d+>> ArrayGet [<<CheckL>>,{{i\d+}}] 103 /// CHECK-DAG: <<CheckJ:l\d+>> NullCheck [<<Null>>] 104 /// CHECK-DAG: <<GetJ0:j\d+>> ArrayGet [<<CheckJ>>,{{i\d+}}] 105 /// CHECK-DAG: <<GetJ1:j\d+>> ArrayGet [<<CheckJ>>,{{i\d+}}] 106 /// CHECK-DAG: <<GetJ2:j\d+>> ArrayGet [<<CheckJ>>,{{i\d+}}] 107 /// CHECK-DAG: <<GetJ3:j\d+>> ArrayGet [<<CheckJ>>,{{i\d+}}] bar()108 public static void bar() { 109 // We create multiple accesses that will lead the bounds check 110 // elimination pass to add a HDeoptimize. Not having the bounds check 111 // makes the ArrayGets look almost the same if it were not for the type! 112 String[] array = (String[])getNull(); 113 objectField = array[0]; 114 objectField = array[1]; 115 objectField = array[2]; 116 objectField = array[3]; 117 long[] longArray = getLongArray(); 118 longField = longArray[0]; 119 longField = longArray[1]; 120 longField = longArray[2]; 121 longField = longArray[3]; 122 } 123 124 /// CHECK-START: float Main.test1() load_store_elimination (after) 125 /// CHECK-DAG: <<Null:l\d+>> NullConstant 126 /// CHECK-DAG: <<Check1:l\d+>> NullCheck [<<Null>>] 127 /// CHECK-DAG: <<FieldGet1:l\d+>> InstanceFieldGet [<<Check1>>] field_name:Test1.iarr 128 /// CHECK-DAG: <<Check2:l\d+>> NullCheck [<<FieldGet1>>] 129 /// CHECK-DAG: <<ArrayGet1:i\d+>> ArrayGet [<<Check2>>,{{i\d+}}] 130 /// CHECK-DAG: <<ArrayGet2:f\d+>> ArrayGet [<<Check2>>,{{i\d+}}] 131 /// CHECK-DAG: Return [<<ArrayGet2>>] test1()132 public static float test1() { 133 Test1 test1 = getNullTest1(); 134 Test2 test2 = getNullTest2(); 135 int[] iarr = test1.iarr; 136 float[] farr = test2.farr; 137 iarr[0] = iarr[1]; 138 return farr[0]; 139 } 140 141 public static long longField; 142 public static Object objectField; 143 } 144