blob: d080a0c94b665dab7a855b804da16084522296fc [file] [log] [blame]
David Brazdil77a48ae2015-09-15 12:34:04 +00001# Copyright (C) 2015 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 LRuntime;
16.super Ljava/lang/Object;
17
18# The following tests all share the same structure, signature and return values:
19# - foo(false, false): normal path, returns 42
20# - foo(true, false): exceptional path #1, returns 3
21# - foo(false, true): exceptional path #2, returns 8
22# - foo(true, true): undefined
23
24
25# Test register allocation of 32-bit core intervals crossing catch block positions.
26
27## CHECK-START: int Runtime.testUseAfterCatch_int(boolean, boolean) register (after)
28## CHECK-NOT: Phi is_catch_phi:true
29
30.method public static testUseAfterCatch_int(ZZ)I
31 .registers 6
32
33 sget-object v0, LRuntime;->intArray:[I
34 const/4 v1, 0
35 aget v1, v0, v1
36 const/4 v2, 1
37 aget v2, v0, v2
38 const/4 v3, 2
39 aget v3, v0, v3
40
41 :try_start
42 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
43 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
44 :try_end
45 .catchall {:try_start .. :try_end} :catch_all
46
47 return v3 # Normal path return.
48
49 :catch_all
50 if-eqz p0, :second_throw
51 return v1 # Exceptional path #1 return.
52
53 :second_throw
54 return v2 # Exceptional path #2 return.
55.end method
56
57
58# Test register allocation of 64-bit core intervals crossing catch block positions.
59
60# The sum of the low and high 32 bits treated as integers is returned to prove
61# that both vregs allocated correctly.
62
63## CHECK-START: int Runtime.testUseAfterCatch_long(boolean, boolean) register (after)
64## CHECK-NOT: Phi is_catch_phi:true
65
66.method public static testUseAfterCatch_long(ZZ)I
67 .registers 10
68
69 sget-object v0, LRuntime;->longArray:[J
70 const/4 v1, 0
71 aget-wide v1, v0, v1
72 const/4 v3, 1
73 aget-wide v3, v0, v3
74 const/4 v5, 2
75 aget-wide v5, v0, v5
76
77 :try_start
78 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
79 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
80 :try_end
81 .catchall {:try_start .. :try_end} :catch_all
82
83 const v0, 32
84 ushr-long v7, v5, v0
85 long-to-int v5, v5
86 long-to-int v7, v7
87 add-int/2addr v5, v7
88 return v5 # Normal path return.
89
90 :catch_all
91 const v0, 32
92 if-eqz p0, :second_throw
93
94 ushr-long v7, v1, v0
95 long-to-int v1, v1
96 long-to-int v7, v7
97 add-int/2addr v1, v7
98 return v1 # Exceptional path #1 return.
99
100 :second_throw
101 ushr-long v7, v3, v0
102 long-to-int v3, v3
103 long-to-int v7, v7
104 add-int/2addr v3, v7
105 return v3 # Exceptional path #2 return.
106.end method
107
108
109# Test register allocation of 32-bit floating-point intervals crossing catch block positions.
110
111## CHECK-START: int Runtime.testUseAfterCatch_float(boolean, boolean) register (after)
112## CHECK-NOT: Phi is_catch_phi:true
113
114.method public static testUseAfterCatch_float(ZZ)I
115 .registers 6
116
117 sget-object v0, LRuntime;->floatArray:[F
118 const/4 v1, 0
119 aget v1, v0, v1
120 const/4 v2, 1
121 aget v2, v0, v2
122 const/4 v3, 2
123 aget v3, v0, v3
124
125 :try_start
126 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
127 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
128 :try_end
129 .catchall {:try_start .. :try_end} :catch_all
130
131 float-to-int v3, v3
132 return v3 # Normal path return.
133
134 :catch_all
135 if-eqz p0, :second_throw
136 float-to-int v1, v1
137 return v1 # Exceptional path #1 return.
138
139 :second_throw
140 float-to-int v2, v2
141 return v2 # Exceptional path #2 return.
142.end method
143
144
145# Test register allocation of 64-bit floating-point intervals crossing catch block positions.
146
147## CHECK-START: int Runtime.testUseAfterCatch_double(boolean, boolean) register (after)
148## CHECK-NOT: Phi is_catch_phi:true
149
150.method public static testUseAfterCatch_double(ZZ)I
151 .registers 10
152
153 sget-object v0, LRuntime;->doubleArray:[D
154 const/4 v1, 0
155 aget-wide v1, v0, v1
156 const/4 v3, 1
157 aget-wide v3, v0, v3
158 const/4 v5, 2
159 aget-wide v5, v0, v5
160
161 :try_start
162 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
163 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
164 :try_end
165 .catchall {:try_start .. :try_end} :catch_all
166
167 double-to-int v5, v5
168 return v5 # Normal path return.
169
170 :catch_all
171 if-eqz p0, :second_throw
172 double-to-int v1, v1
173 return v1 # Exceptional path #1 return.
174
175 :second_throw
176 double-to-int v3, v3
177 return v3 # Exceptional path #2 return.
178.end method
179
180
181# Test catch-phi runtime support for constant values.
182
183# Register v0 holds different constants at two throwing instructions. Runtime is
184# expected to load them from stack map and copy to the catch phi's location.
185
186## CHECK-START: int Runtime.testCatchPhi_const(boolean, boolean) register (after)
187## CHECK-DAG: <<Const3:i\d+>> IntConstant 3
188## CHECK-DAG: <<Const8:i\d+>> IntConstant 8
189## CHECK-DAG: Phi [<<Const3>>,<<Const8>>] is_catch_phi:true
190
191.method public static testCatchPhi_const(ZZ)I
192 .registers 3
193
194 :try_start
195 const v0, 3
196 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
197
198 const v0, 8
199 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
200 :try_end
201 .catchall {:try_start .. :try_end} :catch_all
202
203 const v0, 42
204 return v0 # Normal path return.
205
206 :catch_all
207 return v0 # Exceptional path #1/#2 return.
208.end method
209
210
211# Test catch-phi runtime support for 32-bit values stored in core registers.
212
213# Register v0 holds different integer values at two throwing instructions.
214# Runtime is expected to find their location in the stack map and copy the value
215# to the location of the catch phi.
216
217## CHECK-START: int Runtime.testCatchPhi_int(boolean, boolean) register (after)
218## CHECK-DAG: <<Val1:i\d+>> ArrayGet
219## CHECK-DAG: <<Val2:i\d+>> ArrayGet
220## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
221
222.method public static testCatchPhi_int(ZZ)I
223 .registers 6
224
225 sget-object v0, LRuntime;->intArray:[I
226 const/4 v1, 0
227 aget v1, v0, v1
228 const/4 v2, 1
229 aget v2, v0, v2
230 const/4 v3, 2
231 aget v3, v0, v3
232
233 :try_start
234 move v0, v1 # Set catch phi value
235 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
236
237 move v0, v2 # Set catch phi value
238 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
239 :try_end
240 .catchall {:try_start .. :try_end} :catch_all
241
242 return v3 # Normal path return.
243
244 :catch_all
245 return v0 # Exceptional path #1/#2 return.
246.end method
247
248
249# Test catch-phi runtime support for 64-bit values stored in core registers.
250
251# Register pair (v0, v1) holds different long values at two throwing instructions.
252# Runtime is expected to find their location in the stack map and copy the value
253# to the location of the catch phi. The sum of the low and high 32 bits treated
254# as integers is returned to prove that both vregs were copied.
255
256# Note: values will be spilled on x86 because of too few callee-save core registers.
257
258## CHECK-START: int Runtime.testCatchPhi_long(boolean, boolean) register (after)
259## CHECK-DAG: <<Val1:j\d+>> ArrayGet
260## CHECK-DAG: <<Val2:j\d+>> ArrayGet
261## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
262
263.method public static testCatchPhi_long(ZZ)I
264 .registers 10
265
266 sget-object v0, LRuntime;->longArray:[J
267 const/4 v2, 0
268 aget-wide v2, v0, v2
269 const/4 v4, 1
270 aget-wide v4, v0, v4
271 const/4 v6, 2
272 aget-wide v6, v0, v6
273
274 :try_start
275 move-wide v0, v2 # Set catch phi value
276 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
277
278 move-wide v0, v4 # Set catch phi value
279 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
280 :try_end
281 .catchall {:try_start .. :try_end} :catch_all
282
283 const v2, 32
284 ushr-long v2, v6, v2
285 long-to-int v2, v2
286 long-to-int v6, v6
287 add-int/2addr v6, v2
288 return v6 # Normal path return.
289
290 :catch_all
291 const v2, 32
292 ushr-long v2, v0, v2
293 long-to-int v2, v2
294 long-to-int v0, v0
295 add-int/2addr v0, v2
296 return v0 # Exceptional path #1/#2 return.
297.end method
298
299
300# Test catch-phi runtime support for 32-bit values stored in FPU registers.
301
302# Register v0 holds different float values at two throwing instructions. Runtime
303# is expected to find their location in the stack map and copy the value to the
304# location of the catch phi. The value is converted to int and returned.
305
306# Note: values will be spilled on x86 as there are no callee-save FPU registers.
307
308## CHECK-START: int Runtime.testCatchPhi_float(boolean, boolean) register (after)
309## CHECK-DAG: <<Val1:f\d+>> ArrayGet
310## CHECK-DAG: <<Val2:f\d+>> ArrayGet
311## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
312
313.method public static testCatchPhi_float(ZZ)I
314 .registers 6
315
316 sget-object v0, LRuntime;->floatArray:[F
317 const/4 v1, 0
318 aget v1, v0, v1
319 const/4 v2, 1
320 aget v2, v0, v2
321 const/4 v3, 2
322 aget v3, v0, v3
323
324 :try_start
325 move v0, v1 # Set catch phi value
326 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
327
328 move v0, v2 # Set catch phi value
329 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
330 :try_end
331 .catchall {:try_start .. :try_end} :catch_all
332
333 float-to-int v3, v3
334 return v3 # Normal path return.
335
336 :catch_all
337 float-to-int v0, v0
338 return v0 # Exceptional path #1/#2 return.
339.end method
340
341
342# Test catch-phi runtime support for 64-bit values stored in FPU registers.
343
344# Register pair (v0, v1) holds different double values at two throwing instructions.
345# Runtime is expected to find their location in the stack map and copy the value
346# to the location of the catch phi. The value is converted to int and returned.
347# Values were chosen so that all 64 bits are used.
348
349# Note: values will be spilled on x86 as there are no callee-save FPU registers.
350
351## CHECK-START: int Runtime.testCatchPhi_double(boolean, boolean) register (after)
352## CHECK-DAG: <<Val1:d\d+>> ArrayGet
353## CHECK-DAG: <<Val2:d\d+>> ArrayGet
354## CHECK-DAG: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
355
356.method public static testCatchPhi_double(ZZ)I
357 .registers 10
358
359 sget-object v0, LRuntime;->doubleArray:[D
360 const/4 v2, 0
361 aget-wide v2, v0, v2
362 const/4 v4, 1
363 aget-wide v4, v0, v4
364 const/4 v6, 2
365 aget-wide v6, v0, v6
366
367 :try_start
368 move-wide v0, v2 # Set catch phi value
369 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
370
371 move-wide v0, v4 # Set catch phi value
372 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
373 :try_end
374 .catchall {:try_start .. :try_end} :catch_all
375
376 double-to-int v6, v6
377 return v6
378
379 :catch_all
380 double-to-int v0, v0
381 return v0
382.end method
383
384# Test catch-phi runtime support for 32-bit values stored on the stack.
385
386# Register v0 holds different integer values at two throwing instructions.
387# These values were forced to spill by an always-throwing try/catch after their
388# definition. Runtime is expected to find their location in the stack map and
389# copy the value to the location of the catch phi. The value is then returned.
390
391## CHECK-START: int Runtime.testCatchPhi_singleSlot(boolean, boolean) register (after)
392## CHECK: <<Val1:i\d+>> ArrayGet
393## CHECK-NEXT: ParallelMove moves:[{{.*->}}{{\d+}}(sp)]
394## CHECK: <<Val2:i\d+>> ArrayGet
395## CHECK-NEXT: ParallelMove moves:[{{.*->}}{{\d+}}(sp)]
396## CHECK: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
397
398.method public static testCatchPhi_singleSlot(ZZ)I
399 .registers 6
400
401 sget-object v0, LRuntime;->intArray:[I
402 const/4 v1, 0
403 aget v1, v0, v1
404 const/4 v2, 1
405 aget v2, v0, v2
406 const/4 v3, 2
407 aget v3, v0, v3
408
409 # Insert a try/catch to force v1,v2,v3 to spill.
410 :try_start_spill
411 const/4 v0, 1
412 invoke-static {v0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
413 :try_end_spill
414 .catchall {:try_start_spill .. :try_end_spill} :catch_all_spill
415 return v0 # Unreachable
416 :catch_all_spill # Catch and continue
417
418 :try_start
419 move v0, v1 # Set catch phi value
420 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
421
422 move v0, v2 # Set catch phi value
423 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
424 :try_end
425 .catchall {:try_start .. :try_end} :catch_all
426
427 return v3 # Normal path return.
428
429 :catch_all
430 return v0 # Exceptional path #1/#2 return.
431.end method
432
433# Test catch-phi runtime support for 64-bit values stored on the stack.
434
435# Register pair (v0, v1) holds different double values at two throwing instructions.
436# These values were forced to spill by an always-throwing try/catch after their
437# definition. Runtime is expected to find their location in the stack map and
438# copy the value to the location of the catch phi. The value is converted to int
439# and returned. Values were chosen so that all 64 bits are used.
440
441## CHECK-START: int Runtime.testCatchPhi_doubleSlot(boolean, boolean) register (after)
442## CHECK: <<Val1:d\d+>> ArrayGet
443## CHECK-NEXT: ParallelMove moves:[{{.*->}}2x{{\d+}}(sp)]
444## CHECK: <<Val2:d\d+>> ArrayGet
445## CHECK-NEXT: ParallelMove moves:[{{.*->}}2x{{\d+}}(sp)]
446## CHECK: Phi [<<Val1>>,<<Val2>>] is_catch_phi:true
447
448.method public static testCatchPhi_doubleSlot(ZZ)I
449 .registers 10
450
451 sget-object v0, LRuntime;->doubleArray:[D
452 const/4 v2, 0
453 aget-wide v2, v0, v2
454 const/4 v4, 1
455 aget-wide v4, v0, v4
456 const/4 v6, 2
457 aget-wide v6, v0, v6
458
459 # Insert a try/catch to force (v2, v3), (v4, v5), (v6, v7) to spill.
460 :try_start_spill
461 const/4 v0, 1
462 invoke-static {v0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
463 :try_end_spill
464 .catchall {:try_start_spill .. :try_end_spill} :catch_all_spill
465 return v0 # Unreachable
466 :catch_all_spill # Catch and continue
467
468 :try_start
469 move-wide v0, v2 # Set catch phi value
470 invoke-static {p0}, LRuntime;->$noinline$ThrowIfTrue(Z)V
471
472 move-wide v0, v4 # Set catch phi value
473 invoke-static {p1}, LRuntime;->$noinline$ThrowIfTrue(Z)V
474 :try_end
475 .catchall {:try_start .. :try_end} :catch_all
476
477 double-to-int v6, v6
478 return v6 # Normal path return.
479
480 :catch_all
481 double-to-int v0, v0
482 return v0 # Exceptional path #1/#2 return.
483.end method
484
485
486
487# Helper methods and initialization.
488
489.method public static $noinline$ThrowIfTrue(Z)V
490 .registers 2
491 if-nez p0, :throw
492 return-void
493
494 :throw
495 new-instance v0, Ljava/lang/Exception;
496 invoke-direct {v0}, Ljava/lang/Exception;-><init>()V
497 throw v0
498.end method
499
500.method public static constructor <clinit>()V
501 .registers 2
502
503 const/4 v1, 4
504
505 new-array v0, v1, [I
506 fill-array-data v0, :array_int
507 sput-object v0, LRuntime;->intArray:[I
508
509 new-array v0, v1, [J
510 fill-array-data v0, :array_long
511 sput-object v0, LRuntime;->longArray:[J
512
513 new-array v0, v1, [F
514 fill-array-data v0, :array_float
515 sput-object v0, LRuntime;->floatArray:[F
516
517 new-array v0, v1, [D
518 fill-array-data v0, :array_double
519 sput-object v0, LRuntime;->doubleArray:[D
520
521 return-void
522
523:array_int
524.array-data 4
525 0x03 # int 3
526 0x08 # int 8
527 0x2a # int 42
528.end array-data
529
530:array_long
531.array-data 8
532 0x0000000100000002L # long (1 << 32) + 2
533 0x0000000500000003L # long (5 << 32) + 3
534 0x0000001e0000000cL # long (30 << 32) + 12
535.end array-data
536
537:array_float
538.array-data 4
539 0x40400000 # float 3
540 0x41000000 # float 8
541 0x42280000 # float 42
542.end array-data
543
544:array_double
545.array-data 8
546 0x400b333333333333L # double 3.4
547 0x4020cccccccccccdL # double 8.4
548 0x4045333333333333L # double 42.4
549.end array-data
550.end method
551
Artem Serovd1aa7d02018-06-22 11:35:46 +0100552
553## CHECK-START-{ARM,ARM64}: int Runtime.testIntAddressCatch(int, int[]) GVN$after_arch (after)
554## CHECK-DAG: <<Const1:i\d+>> IntConstant 1
555## CHECK-DAG: <<Offset:i\d+>> IntConstant 12
556## CHECK-DAG: <<IndexParam:i\d+>> ParameterValue
557## CHECK-DAG: <<Array:l\d+>> ParameterValue
558
559## CHECK-DAG: <<NullCh1:l\d+>> NullCheck [<<Array>>]
560## CHECK-DAG: <<Length:i\d+>> ArrayLength
561## CHECK-DAG: <<BoundsCh1:i\d+>> BoundsCheck [<<IndexParam>>,<<Length>>]
562## CHECK-DAG: <<IntAddr1:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
563## CHECK-DAG: ArrayGet [<<IntAddr1>>,<<BoundsCh1>>]
564## CHECK-DAG: TryBoundary
565
566## CHECK-DAG: <<Xplus1:i\d+>> Add [<<IndexParam>>,<<Const1>>]
567## CHECK-DAG: <<BoundsCh2:i\d+>> BoundsCheck [<<Xplus1>>,<<Length>>]
568## CHECK-DAG: ArrayGet [<<IntAddr1>>,<<BoundsCh2>>]
569## CHECK-DAG: TryBoundary
570
571## CHECK-DAG: <<Phi:i\d+>> Phi [<<Xplus1>>]
572## CHECK-DAG: <<Phiplus1:i\d+>> Add [<<Phi>>,<<Const1>>]
573## CHECK-DAG: <<BoundsCh3:i\d+>> BoundsCheck [<<Phiplus1>>,<<Length>>]
574## CHECK-DAG: <<IntAddr3:i\d+>> IntermediateAddress [<<NullCh1>>,<<Offset>>]
575## CHECK-DAG: ArrayGet [<<IntAddr3>>,<<BoundsCh3>>]
576
577## CHECK-START-{ARM,ARM64}: int Runtime.testIntAddressCatch(int, int[]) GVN$after_arch (after)
578## CHECK: NullCheck
579## CHECK-NOT: NullCheck
580
581## CHECK-START-{ARM,ARM64}: int Runtime.testIntAddressCatch(int, int[]) GVN$after_arch (after)
582## CHECK: IntermediateAddress
583## CHECK: IntermediateAddress
584## CHECK-NOT: IntermediateAddress
585
586## CHECK-START-{ARM,ARM64}: int Runtime.testIntAddressCatch(int, int[]) GVN$after_arch (after)
587## CHECK: BoundsCheck
588## CHECK: BoundsCheck
589## CHECK: BoundsCheck
590## CHECK-NOT: BoundsCheck
591
592## CHECK-START-{ARM,ARM64}: int Runtime.testIntAddressCatch(int, int[]) GVN$after_arch (after)
593## CHECK: ArrayGet
594## CHECK: ArrayGet
595## CHECK: ArrayGet
596## CHECK-NOT: ArrayGet
597.method public static testIntAddressCatch(I[I)I
598 .registers 4
599 aget v0, p1, p0
600 add-int v1, v0, v0
601
602 :try_start
603 const/4 v0, 0x1
604 add-int p0, p0, v0
605 aget v0, p1, p0
606
607 :try_end
608 .catch Ljava/lang/ArithmException; {:try_start .. :try_end} :catch_block
609
610 :return
611 add-int v1, v1, v0
612 return v1
613
614 :catch_block
615 const/4 v0, 0x1
616 add-int p0, p0, v0
617 aget v0, p1, p0
618
619 goto :return
620.end method
621
David Brazdil77a48ae2015-09-15 12:34:04 +0000622.field public static intArray:[I
623.field public static longArray:[J
624.field public static floatArray:[F
625.field public static doubleArray:[D