1 /*
2  * Copyright (C) 2015 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 
19 public class Main {
20   public static boolean doThrow = false;
21 
assertIntEquals(int expected, int result)22   public static void assertIntEquals(int expected, int result) {
23     if (expected != result) {
24       throw new Error("Expected: " + expected + ", found: " + result);
25     }
26   }
27 
assertBooleanEquals(boolean expected, boolean result)28   public static void assertBooleanEquals(boolean expected, boolean result) {
29     if (expected != result) {
30       throw new Error("Expected: " + expected + ", found: " + result);
31     }
32   }
33 
assertCharEquals(char expected, char result)34   public static void assertCharEquals(char expected, char result) {
35     if (expected != result) {
36       throw new Error("Expected: " + expected + ", found: " + result);
37     }
38   }
39 
assertStringContains(String searchTerm, String result)40   public static void assertStringContains(String searchTerm, String result) {
41     if (result == null || !result.contains(searchTerm)) {
42       throw new Error("Search term: " + searchTerm + ", not found in: " + result);
43     }
44   }
45 
main(String[] args)46   public static void main(String[] args) {
47     stringEqualsSame();
48     stringArgumentNotNull("Foo");
49 
50     assertIntEquals(0, $opt$noinline$getStringLength(""));
51     assertIntEquals(3, $opt$noinline$getStringLength("abc"));
52     assertIntEquals(10, $opt$noinline$getStringLength("0123456789"));
53 
54     assertBooleanEquals(true, $opt$noinline$isStringEmpty(""));
55     assertBooleanEquals(false, $opt$noinline$isStringEmpty("abc"));
56     assertBooleanEquals(false, $opt$noinline$isStringEmpty("0123456789"));
57 
58     assertCharEquals('a', $opt$noinline$stringCharAt("a", 0));
59     assertCharEquals('a', $opt$noinline$stringCharAt("abc", 0));
60     assertCharEquals('b', $opt$noinline$stringCharAt("abc", 1));
61     assertCharEquals('c', $opt$noinline$stringCharAt("abc", 2));
62     assertCharEquals('7', $opt$noinline$stringCharAt("0123456789", 7));
63 
64     try {
65       $opt$noinline$stringCharAt("abc", -1);
66       throw new Error("Should throw SIOOB.");
67     } catch (StringIndexOutOfBoundsException sioob) {
68       assertStringContains("java.lang.String.charAt", sioob.getStackTrace()[0].toString());
69       assertStringContains("Main.$opt$noinline$stringCharAt", sioob.getStackTrace()[1].toString());
70     }
71     try {
72       $opt$noinline$stringCharAt("abc", 3);
73       throw new Error("Should throw SIOOB.");
74     } catch (StringIndexOutOfBoundsException sioob) {
75       assertStringContains("java.lang.String.charAt", sioob.getStackTrace()[0].toString());
76       assertStringContains("Main.$opt$noinline$stringCharAt", sioob.getStackTrace()[1].toString());
77     }
78     try {
79       $opt$noinline$stringCharAt("abc", Integer.MAX_VALUE);
80       throw new Error("Should throw SIOOB.");
81     } catch (StringIndexOutOfBoundsException sioob) {
82       assertStringContains("java.lang.String.charAt", sioob.getStackTrace()[0].toString());
83       assertStringContains("Main.$opt$noinline$stringCharAt", sioob.getStackTrace()[1].toString());
84     }
85 
86     assertCharEquals('7', $opt$noinline$stringCharAtCatch("0123456789", 7));
87     assertCharEquals('7', $noinline$runSmaliTest("stringCharAtCatch", "0123456789", 7));
88     assertCharEquals('\0', $opt$noinline$stringCharAtCatch("0123456789", 10));
89     assertCharEquals('\0', $noinline$runSmaliTest("stringCharAtCatch","0123456789", 10));
90 
91     assertIntEquals('a' + 'b' + 'c', $opt$noinline$stringSumChars("abc"));
92     assertIntEquals('a' + 'b' + 'c', $opt$noinline$stringSumLeadingChars("abcdef", 3));
93     try {
94       $opt$noinline$stringSumLeadingChars("abcdef", 7);
95       throw new Error("Should throw SIOOB.");
96     } catch (StringIndexOutOfBoundsException sioob) {
97       assertStringContains("java.lang.String.charAt", sioob.getStackTrace()[0].toString());
98       assertStringContains("Main.$opt$noinline$stringSumLeadingChars",
99                            sioob.getStackTrace()[1].toString());
100     }
101     assertIntEquals('a' + 'b' + 'c' + 'd', $opt$noinline$stringSum4LeadingChars("abcdef"));
102     try {
103       $opt$noinline$stringSum4LeadingChars("abc");
104       throw new Error("Should throw SIOOB.");
105     } catch (StringIndexOutOfBoundsException sioob) {
106       assertStringContains("java.lang.String.charAt", sioob.getStackTrace()[0].toString());
107       assertStringContains("Main.$opt$noinline$stringSum4LeadingChars",
108                            sioob.getStackTrace()[1].toString());
109     }
110   }
111 
112   /// CHECK-START: int Main.$opt$noinline$getStringLength(java.lang.String) instruction_simplifier (before)
113   /// CHECK-DAG:  <<Length:i\d+>>   InvokeVirtual intrinsic:StringLength
114   /// CHECK-DAG:                    Return [<<Length>>]
115 
116   /// CHECK-START: int Main.$opt$noinline$getStringLength(java.lang.String) instruction_simplifier (after)
117   /// CHECK-DAG:  <<String:l\d+>>   ParameterValue
118   /// CHECK-DAG:  <<NullCk:l\d+>>   NullCheck [<<String>>]
119   /// CHECK-DAG:  <<Length:i\d+>>   ArrayLength [<<NullCk>>] is_string_length:true
120   /// CHECK-DAG:                    Return [<<Length>>]
121 
122   /// CHECK-START: int Main.$opt$noinline$getStringLength(java.lang.String) instruction_simplifier (after)
123   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringLength
124 
$opt$noinline$getStringLength(String s)125   static public int $opt$noinline$getStringLength(String s) {
126     if (doThrow) { throw new Error(); }
127     return s.length();
128   }
129 
130   /// CHECK-START: boolean Main.$opt$noinline$isStringEmpty(java.lang.String) instruction_simplifier (before)
131   /// CHECK-DAG:  <<IsEmpty:z\d+>>  InvokeVirtual intrinsic:StringIsEmpty
132   /// CHECK-DAG:                    Return [<<IsEmpty>>]
133 
134   /// CHECK-START: boolean Main.$opt$noinline$isStringEmpty(java.lang.String) instruction_simplifier (after)
135   /// CHECK-DAG:  <<String:l\d+>>   ParameterValue
136   /// CHECK-DAG:  <<Const0:i\d+>>   IntConstant 0
137   /// CHECK-DAG:  <<NullCk:l\d+>>   NullCheck [<<String>>]
138   /// CHECK-DAG:  <<Length:i\d+>>   ArrayLength [<<NullCk>>] is_string_length:true
139   /// CHECK-DAG:  <<IsEmpty:z\d+>>  Equal [<<Length>>,<<Const0>>]
140   /// CHECK-DAG:                    Return [<<IsEmpty>>]
141 
142   /// CHECK-START: boolean Main.$opt$noinline$isStringEmpty(java.lang.String) instruction_simplifier (after)
143   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringIsEmpty
144 
$opt$noinline$isStringEmpty(String s)145   static public boolean $opt$noinline$isStringEmpty(String s) {
146     if (doThrow) { throw new Error(); }
147     return s.isEmpty();
148   }
149 
150   /// CHECK-START: char Main.$opt$noinline$stringCharAt(java.lang.String, int) instruction_simplifier (before)
151   /// CHECK-DAG:  <<Char:c\d+>>     InvokeVirtual intrinsic:StringCharAt
152   /// CHECK-DAG:                    Return [<<Char>>]
153 
154   /// CHECK-START: char Main.$opt$noinline$stringCharAt(java.lang.String, int) instruction_simplifier (after)
155   /// CHECK-DAG:  <<String:l\d+>>   ParameterValue
156   /// CHECK-DAG:  <<Pos:i\d+>>      ParameterValue
157   /// CHECK-DAG:  <<NullCk:l\d+>>   NullCheck [<<String>>]
158   /// CHECK-DAG:  <<Length:i\d+>>   ArrayLength [<<NullCk>>] is_string_length:true
159   /// CHECK-DAG:  <<Bounds:i\d+>>   BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
160   /// CHECK-DAG:  <<Char:c\d+>>     ArrayGet [<<NullCk>>,<<Bounds>>] is_string_char_at:true
161   /// CHECK-DAG:                    Return [<<Char>>]
162 
163   /// CHECK-START: char Main.$opt$noinline$stringCharAt(java.lang.String, int) instruction_simplifier (after)
164   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringCharAt
165 
$opt$noinline$stringCharAt(String s, int pos)166   static public char $opt$noinline$stringCharAt(String s, int pos) {
167     if (doThrow) { throw new Error(); }
168     return s.charAt(pos);
169   }
170 
171   /// CHECK-START: char Main.$opt$noinline$stringCharAtCatch(java.lang.String, int) instruction_simplifier (before)
172   /// CHECK-DAG:  <<Int:i\d+>>      IntConstant 0
173   /// CHECK-DAG:  <<Char:c\d+>>     InvokeVirtual intrinsic:StringCharAt
174 
175   //                                The return value can come from a Phi should the two returns be merged.
176   //                                Please refer to the Smali code for a more detailed verification.
177 
178   /// CHECK-DAG:                    Return [{{(c|i)\d+}}]
179 
180   /// CHECK-START: char Main.$opt$noinline$stringCharAtCatch(java.lang.String, int) instruction_simplifier (after)
181   /// CHECK-DAG:  <<String:l\d+>>   ParameterValue
182   /// CHECK-DAG:  <<Pos:i\d+>>      ParameterValue
183   /// CHECK-DAG:  <<Int:i\d+>>      IntConstant 0
184   /// CHECK-DAG:  <<NullCk:l\d+>>   NullCheck [<<String>>]
185   /// CHECK-DAG:  <<Length:i\d+>>   ArrayLength [<<NullCk>>] is_string_length:true
186   /// CHECK-DAG:  <<Bounds:i\d+>>   BoundsCheck [<<Pos>>,<<Length>>] is_string_char_at:true
187   /// CHECK-DAG:  <<Char:c\d+>>     ArrayGet [<<NullCk>>,<<Bounds>>] is_string_char_at:true
188   /// CHECK-DAG:                    Return [{{(c|i)\d+}}]
189 
190   /// CHECK-START: char Main.$opt$noinline$stringCharAtCatch(java.lang.String, int) instruction_simplifier (after)
191   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringCharAt
192 
$opt$noinline$stringCharAtCatch(String s, int pos)193   static public char $opt$noinline$stringCharAtCatch(String s, int pos) {
194     if (doThrow) { throw new Error(); }
195     try {
196       return s.charAt(pos);
197     } catch (StringIndexOutOfBoundsException ignored) {
198       return '\0';
199     }
200   }
201 
202   /// CHECK-START: int Main.$opt$noinline$stringSumChars(java.lang.String) instruction_simplifier (before)
203   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringLength
204   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
205 
206   /// CHECK-START: int Main.$opt$noinline$stringSumChars(java.lang.String) instruction_simplifier (after)
207   /// CHECK-DAG:                    ArrayLength is_string_length:true
208   /// CHECK-DAG:                    ArrayLength is_string_length:true
209   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
210   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
211 
212   /// CHECK-START: int Main.$opt$noinline$stringSumChars(java.lang.String) instruction_simplifier (after)
213   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringLength
214   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringCharAt
215 
216   /// CHECK-START: int Main.$opt$noinline$stringSumChars(java.lang.String) GVN (after)
217   /// CHECK-DAG:                    ArrayLength is_string_length:true
218   /// CHECK-NOT:                    ArrayLength is_string_length:true
219 
220   /// CHECK-START: int Main.$opt$noinline$stringSumChars(java.lang.String) BCE (after)
221   /// CHECK-NOT:                    BoundsCheck
222 
$opt$noinline$stringSumChars(String s)223   static public int $opt$noinline$stringSumChars(String s) {
224     if (doThrow) { throw new Error(); }
225     int sum = 0;
226     int len = s.length();
227     for (int i = 0; i < len; ++i) {
228       sum += s.charAt(i);
229     }
230     return sum;
231   }
232 
233   /// CHECK-START: int Main.$opt$noinline$stringSumLeadingChars(java.lang.String, int) instruction_simplifier (before)
234   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
235 
236   /// CHECK-START: int Main.$opt$noinline$stringSumLeadingChars(java.lang.String, int) instruction_simplifier (after)
237   /// CHECK-DAG:                    ArrayLength is_string_length:true
238   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
239   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
240 
241   /// CHECK-START: int Main.$opt$noinline$stringSumLeadingChars(java.lang.String, int) instruction_simplifier (after)
242   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringCharAt
243 
244   /// CHECK-START: int Main.$opt$noinline$stringSumLeadingChars(java.lang.String, int) BCE (after)
245   /// CHECK-DAG:                    Deoptimize env:[[{{[^\]]*}}]]
246 
247   /// CHECK-START: int Main.$opt$noinline$stringSumLeadingChars(java.lang.String, int) BCE (after)
248   /// CHECK-NOT:                    BoundsCheck is_string_char_at:true
249 
$opt$noinline$stringSumLeadingChars(String s, int n)250   static public int $opt$noinline$stringSumLeadingChars(String s, int n) {
251     if (doThrow) { throw new Error(); }
252     int sum = 0;
253     for (int i = 0; i < n; ++i) {
254       sum += s.charAt(i);
255     }
256     return sum;
257   }
258 
259   /// CHECK-START: int Main.$opt$noinline$stringSum4LeadingChars(java.lang.String) instruction_simplifier (before)
260   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
261   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
262   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
263   /// CHECK-DAG:                    InvokeVirtual intrinsic:StringCharAt
264 
265   /// CHECK-START: int Main.$opt$noinline$stringSum4LeadingChars(java.lang.String) instruction_simplifier (after)
266   /// CHECK-DAG:                    ArrayLength is_string_length:true
267   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
268   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
269   /// CHECK-DAG:                    ArrayLength is_string_length:true
270   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
271   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
272   /// CHECK-DAG:                    ArrayLength is_string_length:true
273   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
274   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
275   /// CHECK-DAG:                    ArrayLength is_string_length:true
276   /// CHECK-DAG:                    BoundsCheck is_string_char_at:true
277   /// CHECK-DAG:                    ArrayGet is_string_char_at:true
278 
279   /// CHECK-START: int Main.$opt$noinline$stringSum4LeadingChars(java.lang.String) instruction_simplifier (after)
280   /// CHECK-NOT:                    InvokeVirtual intrinsic:StringCharAt
281 
282   /// CHECK-START: int Main.$opt$noinline$stringSum4LeadingChars(java.lang.String) BCE (after)
283   /// CHECK-DAG:                    Deoptimize env:[[{{[^\]]*}}]]
284 
285   /// CHECK-START: int Main.$opt$noinline$stringSum4LeadingChars(java.lang.String) BCE (after)
286   /// CHECK-NOT:                    BoundsCheck is_string_char_at:true
287 
$opt$noinline$stringSum4LeadingChars(String s)288   static public int $opt$noinline$stringSum4LeadingChars(String s) {
289     if (doThrow) { throw new Error(); }
290     int sum = s.charAt(0) + s.charAt(1) + s.charAt(2) + s.charAt(3);
291     return sum;
292   }
293 
294   /// CHECK-START: boolean Main.stringEqualsSame() instruction_simplifier (before)
295   /// CHECK:      InvokeStaticOrDirect
296 
297   /// CHECK-START: boolean Main.stringEqualsSame() register (before)
298   /// CHECK:      <<Const1:i\d+>> IntConstant 1
299   /// CHECK:      Return [<<Const1>>]
300 
301   /// CHECK-START: boolean Main.stringEqualsSame() register (before)
302   /// CHECK-NOT:  InvokeStaticOrDirect
stringEqualsSame()303   public static boolean stringEqualsSame() {
304     return $inline$callStringEquals("obj", "obj");
305   }
306 
307   /// CHECK-START: boolean Main.stringEqualsNull() register (after)
308   /// CHECK:      <<Invoke:z\d+>> InvokeVirtual
309   /// CHECK:      Return [<<Invoke>>]
stringEqualsNull()310   public static boolean stringEqualsNull() {
311     String o = (String)myObject;
312     return $inline$callStringEquals(o, o);
313   }
314 
$inline$callStringEquals(String a, String b)315   public static boolean $inline$callStringEquals(String a, String b) {
316     return a.equals(b);
317   }
318 
319   /// CHECK-START-X86: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
320   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
321   /// CHECK-NOT:      test
322 
323   /// CHECK-START-X86_64: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
324   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
325   /// CHECK-NOT:      test
326 
327   /// CHECK-START-ARM: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
328   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
329   // CompareAndBranchIfZero() may emit either CBZ or CMP+BEQ.
330   /// CHECK-NOT:      cbz
331   /// CHECK-NOT:      cmp {{r\d+}}, #0
332   // Terminate the scope for the CHECK-NOT search at the reference or length comparison,
333   // whichever comes first.
334   /// CHECK:          cmp {{r\d+}}, {{r\d+}}
335 
336   /// CHECK-START-ARM64: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
337   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
338   /// CHECK-NOT:      cbz
339   // Terminate the scope for the CHECK-NOT search at the reference or length comparison,
340   // whichever comes first.
341   /// CHECK:          cmp {{w.*,}} {{w.*|#.*}}
342 
343   /// CHECK-START-MIPS: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
344   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
345   /// CHECK-NOT:      beq zero,
346   /// CHECK-NOT:      beqz
347   /// CHECK-NOT:      beqzc
348   // Terminate the scope for the CHECK-NOT search at the class field or length comparison,
349   // whichever comes first.
350   /// CHECK:          lw
351 
352   /// CHECK-START-MIPS64: boolean Main.stringArgumentNotNull(java.lang.Object) disassembly (after)
353   /// CHECK:          InvokeVirtual {{.*\.equals.*}} intrinsic:StringEquals
354   /// CHECK-NOT:      beqzc
355   // Terminate the scope for the CHECK-NOT search at the reference comparison.
356   /// CHECK:          beqc
stringArgumentNotNull(Object obj)357   public static boolean stringArgumentNotNull(Object obj) {
358     obj.getClass();
359     return "foo".equals(obj);
360   }
361 
362   // Test is very brittle as it depends on the order we emit instructions.
363   /// CHECK-START-X86: boolean Main.stringArgumentIsString() disassembly (after)
364   /// CHECK:          InvokeVirtual intrinsic:StringEquals
365   /// CHECK:          test
366   /// CHECK:          jz/eq
367   // Check that we don't try to compare the classes.
368   /// CHECK-NOT:      mov
369   /// CHECK:          cmp
370 
371   // Test is very brittle as it depends on the order we emit instructions.
372   /// CHECK-START-X86_64: boolean Main.stringArgumentIsString() disassembly (after)
373   /// CHECK:          InvokeVirtual intrinsic:StringEquals
374   /// CHECK:          test
375   /// CHECK:          jz/eq
376   // Check that we don't try to compare the classes.
377   /// CHECK-NOT:      mov
378   /// CHECK:          cmp
379 
380   // Test is brittle as it depends on the class offset being 0.
381   /// CHECK-START-ARM: boolean Main.stringArgumentIsString() disassembly (after)
382   /// CHECK:          InvokeVirtual intrinsic:StringEquals
383   /// CHECK:          {{cbz|cmp}}
384   // Check that we don't try to compare the classes.
385   // The dissassembler currently explicitly emits the offset 0 but don't rely on it.
386   // We want to terminate the CHECK-NOT search after two CMPs, one for reference
387   // equality and one for length comparison but these may be emitted in different order,
388   // so repeat the check twice.
389   /// CHECK-NOT:      ldr{{(|.w)}} {{r\d+}}, [{{r\d+}}]
390   /// CHECK-NOT:      ldr{{(|.w)}} {{r\d+}}, [{{r\d+}}, #0]
391   /// CHECK:          cmp {{r\d+}}, {{r\d+}}
392   /// CHECK-NOT:      ldr{{(|.w)}} {{r\d+}}, [{{r\d+}}]
393   /// CHECK-NOT:      ldr{{(|.w)}} {{r\d+}}, [{{r\d+}}, #0]
394   /// CHECK:          cmp {{r\d+}}, {{r\d+}}
395 
396   // Test is brittle as it depends on the class offset being 0.
397   /// CHECK-START-ARM64: boolean Main.stringArgumentIsString() disassembly (after)
398   /// CHECK:          InvokeVirtual intrinsic:StringEquals
399   /// CHECK:          cbz
400   // Check that we don't try to compare the classes.
401   // The dissassembler currently does not explicitly emits the offset 0 but don't rely on it.
402   // We want to terminate the CHECK-NOT search after two CMPs, one for reference
403   // equality and one for length comparison but these may be emitted in different order,
404   // so repeat the check twice.
405   /// CHECK-NOT:      ldr {{w\d+}}, [{{x\d+}}]
406   /// CHECK-NOT:      ldr {{w\d+}}, [{{x\d+}}, #0]
407   /// CHECK:          cmp {{w\d+}}, {{w\d+|#.*}}
408   /// CHECK-NOT:      ldr {{w\d+}}, [{{x\d+}}]
409   /// CHECK-NOT:      ldr {{w\d+}}, [{{x\d+}}, #0]
410   /// CHECK:          cmp {{w\d+}}, {{w\d+|#.*}}
411 
412   // Test is brittle as it depends on the class offset being 0.
413   /// CHECK-START-MIPS: boolean Main.stringArgumentIsString() disassembly (after)
414   /// CHECK:          InvokeVirtual intrinsic:StringEquals
415   /// CHECK:          beq{{(zc)?}}
416   // Check that we don't try to compare the classes.
417   /// CHECK-NOT:      lw {{r\d+}}, +0({{r\d+}})
418   /// CHECK:          bne{{c?}}
419 
420   // Test is brittle as it depends on the class offset being 0.
421   /// CHECK-START-MIPS64: boolean Main.stringArgumentIsString() disassembly (after)
422   /// CHECK:          InvokeVirtual intrinsic:StringEquals
423   /// CHECK:          beqzc
424   // Check that we don't try to compare the classes.
425   /// CHECK-NOT:      lw {{r\d+}}, +0({{r\d+}})
426   /// CHECK:          bnec
stringArgumentIsString()427   public static boolean stringArgumentIsString() {
428     return "foo".equals(myString);
429   }
430 
431   static String myString;
432   static Object myObject;
433 
$noinline$runSmaliTest(String name, String str, int pos)434   public static char $noinline$runSmaliTest(String name, String str, int pos) {
435     try {
436       Class<?> c = Class.forName("SmaliTests");
437       Method m = c.getMethod(name, String.class, int.class);
438       return (Character) m.invoke(null, str, pos);
439     } catch (Exception ex) {
440       throw new Error(ex);
441     }
442   }
443 }
444