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