1# Copyright (C) 2016 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15.class public LTestCase;
16.super Ljava/lang/Object;
17
18# Test that all vregs holding the new-instance are updated after the
19# StringFactory call.
20
21## CHECK-START: java.lang.String TestCase.vregAliasing(byte[]) register (after)
22## CHECK-DAG:                Return [<<String:l\d+>>]
23## CHECK-DAG:     <<String>> InvokeStaticOrDirect  method_name:java.lang.String.<init>
24
25.method public static vregAliasing([B)Ljava/lang/String;
26   .registers 5
27
28   # Create new instance of String and store it to v0, v1, v2.
29   new-instance v0, Ljava/lang/String;
30   move-object v1, v0
31   move-object v2, v0
32
33   # Call String.<init> on v1.
34   const-string v3, "UTF8"
35   invoke-direct {v1, p0, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
36
37   # Return the object from v2.
38   return-object v2
39
40.end method
41
42# Test usage of String new-instance before it is initialized.
43
44## CHECK-START: void TestCase.compareNewInstance() register (after)
45## CHECK-DAG:     <<Null:l\d+>>   InvokeStaticOrDirect method_name:Main.$noinline$HiddenNull
46## CHECK-DAG:     <<String:l\d+>> NewInstance
47## CHECK-DAG:     <<Cond:z\d+>>   NotEqual [<<Null>>,<<String>>]
48## CHECK-DAG:                     If [<<Cond>>]
49
50.method public static compareNewInstance()V
51   .registers 3
52
53   invoke-static {}, LMain;->$noinline$HiddenNull()Ljava/lang/Object;
54   move-result-object v1
55
56   new-instance v0, Ljava/lang/String;
57   if-ne v0, v1, :return
58
59   # Will throw NullPointerException if this branch is taken.
60   const v1, 0x0
61   const-string v2, "UTF8"
62   invoke-direct {v0, v1, v2}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
63   return-void
64
65   :return
66   return-void
67
68.end method
69
70# Test deoptimization between String's allocation and initialization. When not
71# compiling --debuggable, the NewInstance will be optimized out.
72
73## CHECK-START: int TestCase.deoptimizeNewInstance(int[], byte[]) register (after)
74## CHECK:         <<Null:l\d+>>   NullConstant
75## CHECK:                         Deoptimize env:[[<<Null>>,{{.*]]}}
76## CHECK:                         InvokeStaticOrDirect method_name:java.lang.String.<init>
77
78## CHECK-START-DEBUGGABLE: int TestCase.deoptimizeNewInstance(int[], byte[]) register (after)
79## CHECK:         <<String:l\d+>> NewInstance
80## CHECK:                         Deoptimize env:[[<<String>>,{{.*]]}}
81## CHECK:                         InvokeStaticOrDirect method_name:java.lang.String.<init>
82
83.method public static deoptimizeNewInstance([I[B)I
84   .registers 6
85
86   const v2, 0x0
87   const v1, 0x1
88
89   new-instance v0, Ljava/lang/String; # HNewInstance(String)
90
91   # Deoptimize here if the array is too short.
92   aget v1, p0, v1              # v1 = int_array[0x1]
93   add-int/2addr v2, v1         # v2 = 0x0 + v1
94
95   # Check that we're being executed by the interpreter.
96   invoke-static {}, LMain;->assertIsInterpreted()V
97
98   # String allocation should succeed.
99   const-string v3, "UTF8"
100   invoke-direct {v0, p1, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
101   # Transformed into invoke StringFactory(p1,v3).
102   # The use of v0 is dropped (so HNewInstance(String) ends up having 0 uses and is removed).
103
104   # This ArrayGet will throw ArrayIndexOutOfBoundsException.
105   const v1, 0x4
106   aget v1, p0, v1
107   add-int/2addr v2, v1
108
109   return v2
110
111.end method
112
113# Test that a redundant NewInstance is removed if not used and not compiling
114# --debuggable.
115
116## CHECK-START: java.lang.String TestCase.removeNewInstance(byte[]) register (after)
117## CHECK-NOT:     NewInstance
118## CHECK-NOT:     LoadClass
119
120## CHECK-START-DEBUGGABLE: java.lang.String TestCase.removeNewInstance(byte[]) register (after)
121## CHECK:         NewInstance
122
123.method public static removeNewInstance([B)Ljava/lang/String;
124   .registers 5
125
126   new-instance v0, Ljava/lang/String;
127   const-string v1, "UTF8"
128   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
129   return-object v0
130   # Although it looks like we "use" the new-instance v0 here, the optimizing compiler
131   # transforms all uses of the new-instance into uses of the StringFactory invoke.
132   # therefore the HNewInstance for v0 becomes dead and is removed.
133
134.end method
135
136# Test #1 for irreducible loops and String.<init>.
137.method public static irreducibleLoopAndStringInit1([BZ)Ljava/lang/String;
138   .registers 5
139
140   new-instance v0, Ljava/lang/String;
141
142   # Irreducible loop
143   if-eqz p1, :loop_entry
144   :loop_header
145   xor-int/lit8 p1, p1, 0x1
146   :loop_entry
147   if-eqz p1, :string_init
148   goto :loop_header
149
150   :string_init
151   const-string v1, "UTF8"
152   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
153   return-object v0
154
155.end method
156
157# Test #2 for irreducible loops and String.<init>.
158.method public static irreducibleLoopAndStringInit2([BZ)Ljava/lang/String;
159   .registers 5
160
161   new-instance v0, Ljava/lang/String;
162
163   # Irreducible loop
164   if-eqz p1, :loop_entry
165   :loop_header
166   if-eqz p1, :string_init
167   :loop_entry
168   xor-int/lit8 p1, p1, 0x1
169   goto :loop_header
170
171   :string_init
172   const-string v1, "UTF8"
173   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
174   return-object v0
175
176.end method
177
178# Test #3 for irreducible loops and String.<init> alias.
179.method public static irreducibleLoopAndStringInit3([BZ)Ljava/lang/String;
180   .registers 5
181
182   new-instance v0, Ljava/lang/String;
183   move-object v2, v0
184
185   # Irreducible loop
186   if-eqz p1, :loop_entry
187   :loop_header
188   xor-int/lit8 p1, p1, 0x1
189   :loop_entry
190   if-eqz p1, :string_init
191   goto :loop_header
192
193   :string_init
194   const-string v1, "UTF8"
195   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
196   return-object v2
197
198.end method
199
200# Test with a loop between allocation and String.<init>.
201.method public static loopAndStringInit([BZ)Ljava/lang/String;
202   .registers 5
203
204   new-instance v0, Ljava/lang/String;
205
206   # Loop
207   :loop_header
208   if-eqz p1, :loop_exit
209   xor-int/lit8 p1, p1, 0x1
210   goto :loop_header
211
212   :loop_exit
213   const-string v1, "UTF8"
214   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
215   return-object v0
216
217.end method
218
219# Test with a loop and aliases between allocation and String.<init>.
220.method public static loopAndStringInitAlias([BZ)Ljava/lang/String;
221   .registers 5
222
223   new-instance v0, Ljava/lang/String;
224   move-object v2, v0
225
226   # Loop
227   :loop_header
228   if-eqz p1, :loop_exit
229   xor-int/lit8 p1, p1, 0x1
230   goto :loop_header
231
232   :loop_exit
233   const-string v1, "UTF8"
234   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
235   return-object v2
236
237.end method
238
239# Test deoptimization after String initialization of a phi.
240## CHECK-START: int TestCase.deoptimizeNewInstanceAfterLoop(int[], byte[], int) register (after)
241## CHECK:         <<Invoke:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
242## CHECK:                         Deoptimize env:[[<<Invoke>>,{{.*]]}}
243
244.method public static deoptimizeNewInstanceAfterLoop([I[BI)I
245   .registers 8
246
247   const v2, 0x0
248   const v1, 0x1
249
250   new-instance v0, Ljava/lang/String; # HNewInstance(String)
251   move-object v4, v0
252   # Loop
253   :loop_header
254   if-eqz p2, :loop_exit
255   xor-int/lit8 p2, p2, 0x1
256   goto :loop_header
257
258   :loop_exit
259   const-string v3, "UTF8"
260   invoke-direct {v0, p1, v3}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
261
262   # Deoptimize here if the array is too short.
263   aget v1, p0, v1              # v1 = int_array[0x1]
264   add-int/2addr v2, v1         # v2 = 0x0 + v1
265
266   # Check that we're being executed by the interpreter.
267   invoke-static {}, LMain;->assertIsInterpreted()V
268
269   # Check that the environments contain the right string.
270   invoke-static {p1, v0}, LMain;->assertEqual([BLjava/lang/String;)V
271   invoke-static {p1, v4}, LMain;->assertEqual([BLjava/lang/String;)V
272
273   # This ArrayGet will throw ArrayIndexOutOfBoundsException.
274   const v1, 0x4
275   aget v1, p0, v1
276   add-int/2addr v2, v1
277
278   return v2
279
280.end method
281
282# Test with a loop between allocation and String.<init> and a null check.
283## CHECK-START: java.lang.String TestCase.loopAndStringInitAndTest(byte[], boolean) builder (after)
284## CHECK-DAG:     <<Null:l\d+>>   NullConstant
285## CHECK-DAG:     <<String:l\d+>> NewInstance
286## CHECK-DAG:     <<Cond:z\d+>>   NotEqual [<<String>>,<<Null>>]
287
288## CHECK-START: java.lang.String TestCase.loopAndStringInitAndTest(byte[], boolean) register (after)
289## CHECK-DAG:     <<String:l\d+>> NewInstance
290.method public static loopAndStringInitAndTest([BZ)Ljava/lang/String;
291   .registers 5
292
293   new-instance v0, Ljava/lang/String;
294
295   # Loop
296   :loop_header
297   # Use the new-instance in the only way it can be used.
298   if-nez v0, :loop_exit
299   xor-int/lit8 p1, p1, 0x1
300   goto :loop_header
301
302   :loop_exit
303   const-string v1, "UTF8"
304   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
305   return-object v0
306
307.end method
308
309## CHECK-START: java.lang.String TestCase.loopAndStringInitAndPhi(byte[], boolean) register (after)
310## CHECK-NOT:                    NewInstance
311## CHECK-DAG:   <<Invoke1:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
312## CHECK-DAG:   <<Invoke2:l\d+>> InvokeStaticOrDirect method_name:java.lang.String.<init>
313## CHECK-DAG:   <<Phi:l\d+>>     Phi [<<Invoke2>>,<<Invoke1>>]
314## CHECK-DAG:                    Return [<<Phi>>]
315.method public static loopAndStringInitAndPhi([BZ)Ljava/lang/String;
316   .registers 4
317
318   if-nez p1, :allocate_other
319   new-instance v0, Ljava/lang/String;
320
321   # Loop
322   :loop_header
323   if-eqz p1, :loop_exit
324   goto :loop_header
325
326   :loop_exit
327   const-string v1, "UTF8"
328   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
329   goto : exit
330
331   :allocate_other
332   const-string v1, "UTF8"
333   new-instance v0, Ljava/lang/String;
334   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
335   :exit
336   return-object v0
337
338.end method
339
340.method public static loopAndTwoStringInitAndPhi([BZZ)Ljava/lang/String;
341   .registers 6
342
343   new-instance v0, Ljava/lang/String;
344   new-instance v2, Ljava/lang/String;
345
346   if-nez p2, :allocate_other
347
348   # Loop
349   :loop_header
350   if-eqz p1, :loop_exit
351   goto :loop_header
352
353   :loop_exit
354   const-string v1, "UTF8"
355   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
356   goto :exit
357
358   :allocate_other
359
360   # Loop
361   :loop_header2
362   if-eqz p1, :loop_exit2
363   goto :loop_header2
364
365   :loop_exit2
366   const-string v1, "UTF8"
367   invoke-direct {v2, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
368   move-object v0, v2
369
370   :exit
371   return-object v0
372
373.end method
374
375# Regression test for a new string flowing into a catch phi.
376.method public static stringAndCatch([BZ)Ljava/lang/Object;
377   .registers 4
378
379   const v0, 0x0
380
381   :try_start_a
382   new-instance v0, Ljava/lang/String;
383
384   # Loop
385   :loop_header
386   if-eqz p1, :loop_exit
387   goto :loop_header
388
389   :loop_exit
390   const-string v1, "UTF8"
391   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
392   goto :exit
393   :try_end_a
394   .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
395
396   :catch_a
397   # Initially, we create a catch phi with the potential uninitalized string, which used to
398   # trip the compiler. However, using that catch phi is an error caught by the verifier, so
399   # having the phi is benign.
400   const v0, 0x0
401
402   :exit
403   return-object v0
404
405.end method
406
407# Same test as above, but with a catch phi being used by the string constructor.
408.method public static stringAndCatch2([BZ)Ljava/lang/Object;
409   .registers 4
410
411   const v0, 0x0
412   new-instance v0, Ljava/lang/String;
413
414   :try_start_a
415   const-string v1, "UTF8"
416   :try_end_a
417   .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
418
419   :catch_a
420   const-string v1, "UTF8"
421   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
422   return-object v0
423
424.end method
425
426# Same test as above, but with a catch phi being used by the string constructor and
427# a null test.
428.method public static stringAndCatch3([BZ)Ljava/lang/Object;
429   .registers 4
430
431   const v0, 0x0
432   new-instance v0, Ljava/lang/String;
433
434   :try_start_a
435   const-string v1, "UTF8"
436   :try_end_a
437   .catch Ljava/lang/Exception; {:try_start_a .. :try_end_a} :catch_a
438
439   :catch_a
440   if-eqz v0, :unexpected
441   const-string v1, "UTF8"
442   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
443   goto :exit
444   :unexpected
445   const-string v0, "UTF8"
446   :exit
447   return-object v0
448
449.end method
450
451# Regression test that tripped the compiler.
452.method public static stringAndPhi([BZ)Ljava/lang/Object;
453   .registers 4
454
455   new-instance v0, Ljava/lang/String;
456   const-string v1, "UTF8"
457
458   :loop_header
459   if-nez p1, :unused
460   if-eqz p1, :invoke
461   goto :loop_header
462
463   :invoke
464   invoke-direct {v0, p0, v1}, Ljava/lang/String;-><init>([BLjava/lang/String;)V
465   goto :exit
466
467   :unused
468   const-string v0, "UTF8"
469   if-nez p1, :exit
470   goto :unused
471
472   :exit
473   return-object v0
474
475.end method
476