Home | History | Annotate | Download | only in src
      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 
     22   public static void assertIntEquals(int expected, int result) {
     23     if (expected != result) {
     24       throw new Error("Expected: " + expected + ", found: " + result);
     25     }
     26   }
     27 
     28   public static void assertBooleanEquals(boolean expected, boolean result) {
     29     if (expected != result) {
     30       throw new Error("Expected: " + expected + ", found: " + result);
     31     }
     32   }
     33 
     34   public static void assertCharEquals(char expected, char result) {
     35     if (expected != result) {
     36       throw new Error("Expected: " + expected + ", found: " + result);
     37     }
     38   }
     39 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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>>]
    310   public static boolean stringEqualsNull() {
    311     String o = (String)myObject;
    312     return $inline$callStringEquals(o, o);
    313   }
    314 
    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
    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
    427   public static boolean stringArgumentIsString() {
    428     return "foo".equals(myString);
    429   }
    430 
    431   static String myString;
    432   static Object myObject;
    433 
    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