1 /*
2  * Copyright (C) 2018 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 /**
18  * Tests for detecting throwing methods for code sinking.
19  */
20 public class Main {
21 
22   //
23   // Some "runtime library" methods.
24   //
25 
doThrow(String par)26   public final void doThrow(String par) {
27     throw new Error("you are null: " + par);
28   }
29 
checkNotNullDirect(Object obj, String par)30   public final void checkNotNullDirect(Object obj, String par) {
31     if (obj == null)
32       throw new Error("you are null: " + par);
33   }
34 
checkNotNullSplit(Object obj, String par)35   public final void checkNotNullSplit(Object obj, String par) {
36     if (obj == null)
37       doThrow(par);
38   }
39 
40   //
41   // Various ways of enforcing non-null parameter.
42   // In all cases, par should be subject to code sinking.
43   //
44 
45   /// CHECK-START: void Main.doit1(int[]) code_sinking (before)
46   /// CHECK: begin_block
47   /// CHECK:   <<Str:l\d+>> LoadString
48   /// CHECK:   <<Tst:z\d+>> Equal
49   /// CHECK:                If [<<Tst>>]
50   /// CHECK: end_block
51   /// CHECK: begin_block
52   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
53   /// CHECK:                Throw
54   /// CHECK: end_block
55   //
56   /// CHECK-START: void Main.doit1(int[]) code_sinking (after)
57   /// CHECK: begin_block
58   /// CHECK:   <<Tst:z\d+>> Equal
59   /// CHECK:                If [<<Tst>>]
60   /// CHECK: end_block
61   /// CHECK: begin_block
62   /// CHECK:   <<Str:l\d+>> LoadString
63   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
64   /// CHECK:                Throw
65   /// CHECK: end_block
doit1(int[] a)66   public void doit1(int[] a) {
67     // Being in the boot image means we know the load string cannot throw. Create one that is
68     // unlikely to be there to ensure we handle that case.
69     String par = "stringUnlikelyToBeInBootImage";
70     if (a == null)
71       throw new Error("you are null: " + par);
72     for (int i = 0; i < a.length; i++) {
73       a[i] = 1;
74     }
75   }
76 
77   /// CHECK-START: void Main.doit2(int[]) code_sinking (before)
78   /// CHECK: begin_block
79   /// CHECK:   <<Str:l\d+>> LoadString
80   /// CHECK:   <<Tst:z\d+>> NotEqual
81   /// CHECK:                If [<<Tst>>]
82   /// CHECK: end_block
83   /// CHECK: begin_block
84   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow
85   /// CHECK: end_block
86   //
87   /// CHECK-START: void Main.doit2(int[]) code_sinking (after)
88   /// CHECK: begin_block
89   /// CHECK:   <<Tst:z\d+>> NotEqual
90   /// CHECK:                If [<<Tst>>]
91   /// CHECK: end_block
92   /// CHECK: begin_block
93   /// CHECK:   <<Str:l\d+>> LoadString
94   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow
95   /// CHECK: end_block
doit2(int[] a)96   public void doit2(int[] a) {
97     // Being in the boot image means we know the load string cannot throw. Create one that is
98     // unlikely to be there to ensure we handle that case.
99     String par = "stringUnlikelyToBeInBootImage";
100     if (a == null)
101       doThrow(par);
102     for (int i = 0; i < a.length; i++) {
103       a[i] = 2;
104     }
105   }
106 
107   /// CHECK-START: void Main.doit3(int[]) code_sinking (before)
108   /// CHECK: begin_block
109   /// CHECK:   <<Str:l\d+>> LoadString
110   /// CHECK:   <<Tst:z\d+>> Equal
111   /// CHECK:                If [<<Tst>>]
112   /// CHECK: end_block
113   /// CHECK: begin_block
114   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
115   /// CHECK:                Throw
116   /// CHECK: end_block
117   //
118   /// CHECK-START: void Main.doit3(int[]) code_sinking (after)
119   /// CHECK: begin_block
120   /// CHECK:   <<Tst:z\d+>> Equal
121   /// CHECK:                If [<<Tst>>]
122   /// CHECK: end_block
123   /// CHECK: begin_block
124   /// CHECK:   <<Str:l\d+>> LoadString
125   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>]
126   /// CHECK:                Throw
127   /// CHECK: end_block
doit3(int[] a)128   public void doit3(int[] a) {
129     // Being in the boot image means we know the load string cannot throw. Create one that is
130     // unlikely to be there to ensure we handle that case.
131     String par = "stringUnlikelyToBeInBootImage";
132     checkNotNullDirect(a, par);
133     for (int i = 0; i < a.length; i++) {
134       a[i] = 3;
135     }
136   }
137 
138   /// CHECK-START: void Main.doit4(int[]) code_sinking (before)
139   /// CHECK: begin_block
140   /// CHECK:   <<Str:l\d+>> LoadString
141   /// CHECK:   <<Tst:z\d+>> NotEqual
142   /// CHECK:                If [<<Tst>>]
143   /// CHECK: end_block
144   /// CHECK: begin_block
145   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow
146   /// CHECK: end_block
147   //
148   /// CHECK-START: void Main.doit4(int[]) code_sinking (after)
149   /// CHECK: begin_block
150   /// CHECK:   <<Tst:z\d+>> NotEqual
151   /// CHECK:                If [<<Tst>>]
152   /// CHECK: end_block
153   /// CHECK: begin_block
154   /// CHECK:   <<Str:l\d+>> LoadString
155   /// CHECK:                InvokeVirtual [{{l\d+}},<<Str>>] method_name:Main.doThrow
156   /// CHECK: end_block
doit4(int[] a)157   public void doit4(int[] a) {
158     // Being in the boot image means we know the load string cannot throw. Create one that is
159     // unlikely to be there to ensure we handle that case.
160     String par = "stringUnlikelyToBeInBootImage";
161     checkNotNullSplit(a, par);
162     for (int i = 0; i < a.length; i++) {
163       a[i] = 4;
164     }
165   }
166 
167   //
168   // Test driver.
169   //
170 
main(String[] args)171   static public void main(String[] args) {
172     int[] a = new int[100];
173     for (int i = 0; i < 100; i++) {
174       a[i] = 0;
175     }
176 
177     Main m = new Main();
178 
179     try {
180       m.doit1(null);
181       System.out.println("should not reach this!");
182     } catch (Error e) {
183       m.doit1(a);
184     }
185     for (int i = 0; i < 100; i++) {
186       expectEquals(1, a[i]);
187     }
188 
189     try {
190       m.doit2(null);
191       System.out.println("should not reach this!");
192     } catch (Error e) {
193       m.doit2(a);
194     }
195     for (int i = 0; i < 100; i++) {
196       expectEquals(2, a[i]);
197     }
198 
199     try {
200       m.doit3(null);
201       System.out.println("should not reach this!");
202     } catch (Error e) {
203       m.doit3(a);
204     }
205     for (int i = 0; i < 100; i++) {
206       expectEquals(3, a[i]);
207     }
208 
209     try {
210       m.doit4(null);
211       System.out.println("should not reach this!");
212     } catch (Error e) {
213       m.doit4(a);
214     }
215     for (int i = 0; i < 100; i++) {
216       expectEquals(4, a[i]);
217     }
218 
219     System.out.println("passed");
220   }
221 
expectEquals(int expected, int result)222   private static void expectEquals(int expected, int result) {
223     if (expected != result) {
224       throw new Error("Expected: " + expected + ", found: " + result);
225     }
226   }
227 }
228