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