blob: f300b2108c5378e39e4e9027cfd5d5afc8b00eef [file] [log] [blame]
David Brazdilfc6a86a2015-06-26 10:33:45 +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 LBuilder;
16
17.super Ljava/lang/Object;
18
19# Basic test case with two try blocks and three catch handlers, one of which
20# is shared by the two tries.
21
22## CHECK-START: int Builder.testMultipleTryCatch(int, int, int) builder (after)
23
24## CHECK: name "B0"
25## CHECK: successors "<<BEnterTry1:B\d+>>"
26## CHECK: <<Minus1:i\d+>> IntConstant -1
27## CHECK: <<Minus2:i\d+>> IntConstant -2
28## CHECK: <<Minus3:i\d+>> IntConstant -3
29
30## CHECK: name "<<BTry1:B\d+>>"
31## CHECK: predecessors "<<BEnterTry1>>"
32## CHECK: successors "<<BExitTry1:B\d+>>"
33## CHECK: DivZeroCheck
34
35## CHECK: name "<<BAdd:B\d+>>"
36## CHECK: predecessors "<<BExitTry1>>"
37## CHECK: successors "<<BEnterTry2:B\d+>>"
38## CHECK: Add
39
40## CHECK: name "<<BTry2:B\d+>>"
41## CHECK: predecessors "<<BEnterTry2>>"
42## CHECK: successors "<<BExitTry2:B\d+>>"
43## CHECK: DivZeroCheck
44
45## CHECK: name "<<BReturn:B\d+>>"
46## CHECK: predecessors "<<BExitTry2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>" "<<BCatch3:B\d+>>"
47## CHECK: Return
48
49## CHECK: name "<<BCatch1>>"
50## CHECK: predecessors "<<BEnterTry1>>" "<<BExitTry1>>"
51## CHECK: successors "<<BReturn>>"
52## CHECK: flags "catch_block"
53## CHECK: StoreLocal [v0,<<Minus1>>]
54
55## CHECK: name "<<BCatch2>>"
56## CHECK: predecessors "<<BEnterTry2>>" "<<BExitTry2>>"
57## CHECK: successors "<<BReturn>>"
58## CHECK: flags "catch_block"
59## CHECK: StoreLocal [v0,<<Minus2>>]
60
61## CHECK: name "<<BCatch3>>"
62## CHECK: predecessors "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
63## CHECK: successors "<<BReturn>>"
64## CHECK: flags "catch_block"
65## CHECK: StoreLocal [v0,<<Minus3>>]
66
67## CHECK: name "<<BEnterTry1>>"
68## CHECK: predecessors "B0"
69## CHECK: successors "<<BTry1>>"
70## CHECK: xhandlers "<<BCatch1>>" "<<BCatch3>>"
71## CHECK: TryBoundary is_entry:true is_exit:false
72
73## CHECK: name "<<BExitTry1>>"
74## CHECK: predecessors "<<BTry1>>"
75## CHECK: successors "<<BAdd>>"
76## CHECK: xhandlers "<<BCatch1>>" "<<BCatch3>>"
77## CHECK: TryBoundary is_entry:false is_exit:true
78
79## CHECK: name "<<BEnterTry2>>"
80## CHECK: predecessors "<<BAdd>>"
81## CHECK: successors "<<BTry2>>"
82## CHECK: xhandlers "<<BCatch2>>" "<<BCatch3>>"
83## CHECK: TryBoundary is_entry:true is_exit:false
84
85## CHECK: name "<<BExitTry2>>"
86## CHECK: predecessors "<<BTry2>>"
87## CHECK: successors "<<BReturn>>"
88## CHECK: xhandlers "<<BCatch2>>" "<<BCatch3>>"
89## CHECK: TryBoundary is_entry:false is_exit:true
90
91.method public static testMultipleTryCatch(III)I
92 .registers 3
93
94 :try_start_1
95 div-int/2addr p0, p1
96 :try_end_1
97 .catch Ljava/lang/ArithmeticException; {:try_start_1 .. :try_end_1} :catch_arith
98 .catchall {:try_start_1 .. :try_end_1} :catch_other
99
100 add-int/2addr p0, p0
101
102 :try_start_2
103 div-int/2addr p0, p2
104 :try_end_2
105 .catch Ljava/lang/OutOfMemoryError; {:try_start_2 .. :try_end_2} :catch_mem
106 .catchall {:try_start_2 .. :try_end_2} :catch_other
107
108 :return
109 return p0
110
111 :catch_arith
112 const/4 p0, -0x1
113 goto :return
114
115 :catch_mem
116 const/4 p0, -0x2
117 goto :return
118
119 :catch_other
120 const/4 p0, -0x3
121 goto :return
122.end method
123
124# Test that multiple try-entry blocks are generated if there are multiple entry
125# points into the try block.
126
127## CHECK-START: int Builder.testMultipleEntries(int, int, int, int) builder (after)
128
129## CHECK: name "B0"
130## CHECK: successors "<<BIf:B\d+>>"
131## CHECK: <<Minus1:i\d+>> IntConstant -1
132
133## CHECK: name "<<BIf>>"
134## CHECK: predecessors "B0"
135## CHECK: successors "<<BEnterTry2:B\d+>>" "<<BThen:B\d+>>"
136## CHECK: If
137
138## CHECK: name "<<BThen>>"
139## CHECK: predecessors "<<BIf>>"
140## CHECK: successors "<<BEnterTry1:B\d+>>"
141## CHECK: Div
142
143## CHECK: name "<<BTry1:B\d+>>"
144## CHECK: predecessors "<<BEnterTry1>>"
145## CHECK: successors "<<BTry2:B\d+>>"
146## CHECK: Div
147
148## CHECK: name "<<BTry2>>"
149## CHECK: predecessors "<<BEnterTry2>>" "<<BTry1>>"
150## CHECK: successors "<<BExitTry:B\d+>>"
151## CHECK: Div
152
153## CHECK: name "<<BReturn:B\d+>>"
154## CHECK: predecessors "<<BExitTry>>" "<<BCatch:B\d+>>"
155## CHECK: Return
156
157## CHECK: name "<<BCatch>>"
158## CHECK: predecessors "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry>>"
159## CHECK: successors "<<BReturn>>"
160## CHECK: flags "catch_block"
161## CHECK: StoreLocal [v0,<<Minus1>>]
162
163## CHECK: name "<<BEnterTry1>>"
164## CHECK: predecessors "<<BThen>>"
165## CHECK: successors "<<BTry1>>"
166## CHECK: xhandlers "<<BCatch>>"
167## CHECK: TryBoundary is_entry:true is_exit:false
168
169## CHECK: name "<<BEnterTry2>>"
170## CHECK: predecessors "<<BIf>>"
171## CHECK: successors "<<BTry2>>"
172## CHECK: xhandlers "<<BCatch>>"
173## CHECK: TryBoundary is_entry:true is_exit:false
174
175## CHECK: name "<<BExitTry>>"
176## CHECK: predecessors "<<BTry2>>"
177## CHECK: successors "<<BReturn>>"
178## CHECK: xhandlers "<<BCatch>>"
179## CHECK: TryBoundary is_entry:false is_exit:true
180
181.method public static testMultipleEntries(IIII)I
182 .registers 4
183
184 if-eqz p2, :else
185
186 div-int/2addr p0, p1
187
188 :try_start
189 div-int/2addr p0, p2
190
191 :else
192 div-int/2addr p0, p3
193 :try_end
194 .catchall {:try_start .. :try_end} :catch_all
195
196 :return
197 return p0
198
199 :catch_all
200 const/4 p0, -0x1
201 goto :return
202
203.end method
204
205# Test that multiple try-exit blocks are generated if (normal) control flow can
206# jump out of the try block at multiple points.
207
208## CHECK-START: int Builder.testMultipleExits(int, int) builder (after)
209
210## CHECK: name "B0"
211## CHECK: successors "<<BEnterTry:B\d+>>"
212## CHECK: <<Minus1:i\d+>> IntConstant -1
213## CHECK: <<Minus2:i\d+>> IntConstant -2
214
215## CHECK: name "<<BTry:B\d+>>"
216## CHECK: predecessors "<<BEnterTry>>"
217## CHECK: successors "<<BExitTry1:B\d+>>" "<<BExitTry2:B\d+>>"
218## CHECK: Div
219## CHECK: If
220
221## CHECK: name "<<BReturn:B\d+>>"
222## CHECK: predecessors "<<BExitTry2>>" "<<BThen:B\d+>>" "<<BCatch:B\d+>>"
223## CHECK: Return
224
225## CHECK: name "<<BThen>>"
226## CHECK: predecessors "<<BExitTry1>>"
227## CHECK: successors "<<BReturn>>"
228## CHECK: StoreLocal [v0,<<Minus1>>]
229
230## CHECK: name "<<BCatch>>"
231## CHECK: predecessors "<<BEnterTry>>" "<<BExitTry1>>" "<<BExitTry2>>"
232## CHECK: successors "<<BReturn>>"
233## CHECK: flags "catch_block"
234## CHECK: StoreLocal [v0,<<Minus2>>]
235
236## CHECK: name "<<BEnterTry>>"
237## CHECK: predecessors "B0"
238## CHECK: successors "<<BTry>>"
239## CHECK: xhandlers "<<BCatch>>"
240## CHECK: TryBoundary is_entry:true is_exit:false
241
242## CHECK: name "<<BExitTry1>>"
243## CHECK: predecessors "<<BTry>>"
244## CHECK: successors "<<BThen>>"
245## CHECK: xhandlers "<<BCatch>>"
246## CHECK: TryBoundary is_entry:false is_exit:true
247
248## CHECK: name "<<BExitTry2>>"
249## CHECK: predecessors "<<BTry>>"
250## CHECK: successors "<<BReturn>>"
251## CHECK: xhandlers "<<BCatch>>"
252## CHECK: TryBoundary is_entry:false is_exit:true
253
254.method public static testMultipleExits(II)I
255 .registers 2
256
257 :try_start
258 div-int/2addr p0, p1
259 if-eqz p0, :then
260 :try_end
261 .catchall {:try_start .. :try_end} :catch_all
262
263 :return
264 return p0
265
266 :then
267 const/4 p0, -0x1
268 goto :return
269
270 :catch_all
271 const/4 p0, -0x2
272 goto :return
273.end method
274
275# Test that only one TryBoundary is inserted when an edge connects two different
276# try ranges.
277
278## CHECK-START: int Builder.testSharedBoundary(int, int, int) builder (after)
279
280## CHECK: name "B0"
281## CHECK: successors "<<BEnter1:B\d+>>"
282## CHECK: <<Minus1:i\d+>> IntConstant -1
283## CHECK: <<Minus2:i\d+>> IntConstant -2
284
285## CHECK: name "<<BTry1:B\d+>>"
286## CHECK: predecessors "<<BEnter1>>"
287## CHECK: successors "<<BExit1Enter2:B\d+>>"
288## CHECK: Div
289
290## CHECK: name "<<BTry2:B\d+>>"
291## CHECK: predecessors "<<BExit1Enter2>>"
292## CHECK: successors "<<BExit2:B\d+>>"
293## CHECK: Div
294
295## CHECK: name "<<BReturn:B\d+>>"
296## CHECK: predecessors "<<BExit2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
297## CHECK: Return
298
299## CHECK: name "<<BCatch1>>"
300## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2>>"
301## CHECK: successors "<<BReturn>>"
302## CHECK: flags "catch_block"
303## CHECK: StoreLocal [v0,<<Minus1>>]
304
305## CHECK: name "<<BCatch2>>"
306## CHECK: predecessors "<<BExit1Enter2>>" "<<BExit2>>"
307## CHECK: successors "<<BReturn>>"
308## CHECK: flags "catch_block"
309## CHECK: StoreLocal [v0,<<Minus2>>]
310
311## CHECK: name "<<BEnter1>>"
312## CHECK: predecessors "B0"
313## CHECK: successors "<<BTry1>>"
314## CHECK: xhandlers "<<BCatch1>>"
315## CHECK: TryBoundary is_entry:true is_exit:false
316
317## CHECK: name "<<BExit1Enter2>>"
318## CHECK: predecessors "<<BTry1>>"
319## CHECK: successors "<<BTry2>>"
320## CHECK: xhandlers "<<BCatch1>>" "<<BCatch2>>"
321## CHECK: TryBoundary is_entry:true is_exit:true
322
323## CHECK: name "<<BExit2>>"
324## CHECK: predecessors "<<BTry2>>"
325## CHECK: successors "<<BReturn>>"
326## CHECK: xhandlers "<<BCatch2>>"
327## CHECK: TryBoundary is_entry:false is_exit:true
328
329.method public static testSharedBoundary(III)I
330 .registers 3
331
332 :try_start_1
333 div-int/2addr p0, p1
334 :try_end_1
335 .catchall {:try_start_1 .. :try_end_1} :catch_all_1
336
337 :try_start_2
338 div-int/2addr p0, p2
339 :try_end_2
340 .catchall {:try_start_2 .. :try_end_2} :catch_all_2
341
342 :return
343 return p0
344
345 :catch_all_1
346 const/4 p0, -0x1
347 goto :return
348
349 :catch_all_2
350 const/4 p0, -0x2
351 goto :return
352.end method
353
354# Same as previous test, only the blocks are processed in the opposite order.
355
356## CHECK-START: int Builder.testSharedBoundary_Reverse(int, int, int) builder (after)
357
358## CHECK: name "B0"
359## CHECK: successors "<<BGoto:B\d+>>"
360## CHECK: <<Minus1:i\d+>> IntConstant -1
361## CHECK: <<Minus2:i\d+>> IntConstant -2
362
363## CHECK: name "<<BGoto>>"
364## CHECK: successors "<<BEnter2:B\d+>>"
365## CHECK: Goto
366
367## CHECK: name "<<BTry1:B\d+>>"
368## CHECK: predecessors "<<BExit2Enter1:B\d+>>"
369## CHECK: successors "<<BExit1:B\d+>>"
370## CHECK: Div
371
372## CHECK: name "<<BTry2:B\d+>>"
373## CHECK: predecessors "<<BEnter2>>"
374## CHECK: successors "<<BExit2Enter1>>"
375## CHECK: Div
376
377## CHECK: name "<<BReturn:B\d+>>"
378## CHECK: predecessors "<<BExit1>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
379## CHECK: Return
380
381## CHECK: name "<<BCatch1>>"
382## CHECK: predecessors "<<BExit2Enter1>>" "<<BExit1>>"
383## CHECK: successors "<<BReturn>>"
384## CHECK: flags "catch_block"
385## CHECK: StoreLocal [v0,<<Minus1>>]
386
387## CHECK: name "<<BCatch2>>"
388## CHECK: predecessors "<<BEnter2>>" "<<BExit2Enter1>>"
389## CHECK: successors "<<BReturn>>"
390## CHECK: flags "catch_block"
391## CHECK: StoreLocal [v0,<<Minus2>>]
392
393## CHECK: name "<<BExit2Enter1>>"
394## CHECK: predecessors "<<BTry2>>"
395## CHECK: successors "<<BTry1>>"
396## CHECK: xhandlers "<<BCatch1>>" "<<BCatch2>>"
397## CHECK: TryBoundary is_entry:true is_exit:true
398
399## CHECK: name "<<BExit1>>"
400## CHECK: predecessors "<<BTry1>>"
401## CHECK: successors "<<BReturn>>"
402## CHECK: xhandlers "<<BCatch1>>"
403## CHECK: TryBoundary is_entry:false is_exit:true
404
405## CHECK: name "<<BEnter2>>"
406## CHECK: predecessors "<<BGoto>>"
407## CHECK: successors "<<BTry2>>"
408## CHECK: xhandlers "<<BCatch2>>"
409## CHECK: TryBoundary is_entry:true is_exit:false
410
411.method public static testSharedBoundary_Reverse(III)I
412 .registers 3
413
414 goto :try_start_2
415
416 :try_start_1
417 div-int/2addr p0, p1
418 goto :return
419 :try_end_1
420 .catchall {:try_start_1 .. :try_end_1} :catch_all_1
421
422 :try_start_2
423 div-int/2addr p0, p2
424 goto :try_start_1
425 :try_end_2
426 .catchall {:try_start_2 .. :try_end_2} :catch_all_2
427
428 :return
429 return p0
430
431 :catch_all_1
432 const/4 p0, -0x1
433 goto :return
434
435 :catch_all_2
436 const/4 p0, -0x2
437 goto :return
438.end method
439
440# Test that nested tries are split into non-overlapping blocks and TryBoundary
441# blocks are correctly created between them.
442
443## CHECK-START: int Builder.testNestedTry(int, int, int, int) builder (after)
444
445## CHECK: name "B0"
446## CHECK: <<Minus1:i\d+>> IntConstant -1
447## CHECK: <<Minus2:i\d+>> IntConstant -2
448
449## CHECK: name "<<BTry1:B\d+>>"
450## CHECK: predecessors "<<BEnter1:B\d+>>"
451## CHECK: successors "<<BExit1Enter2:B\d+>>"
452## CHECK: Div
453
454## CHECK: name "<<BTry2:B\d+>>"
455## CHECK: predecessors "<<BExit1Enter2>>"
456## CHECK: successors "<<BExit2Enter3:B\d+>>"
457## CHECK: Div
458
459## CHECK: name "<<BTry3:B\d+>>"
460## CHECK: predecessors "<<BExit2Enter3>>"
461## CHECK: successors "<<BExit3:B\d+>>"
462## CHECK: Div
463
464## CHECK: name "<<BReturn:B\d+>>"
465## CHECK: predecessors "<<BExit3>>" "<<BCatchArith:B\d+>>" "<<BCatchAll:B\d+>>"
466
467## CHECK: name "<<BCatchArith>>"
468## CHECK: predecessors "<<BExit1Enter2>>" "<<BExit2Enter3>>"
469## CHECK: successors "<<BReturn>>"
470## CHECK: flags "catch_block"
471## CHECK: StoreLocal [v0,<<Minus1>>]
472
473## CHECK: name "<<BCatchAll>>"
474## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2>>" "<<BExit2Enter3>>" "<<BExit3>>"
475## CHECK: successors "<<BReturn>>"
476## CHECK: flags "catch_block"
477## CHECK: StoreLocal [v0,<<Minus2>>]
478
479## CHECK: name "<<BEnter1>>"
480## CHECK: predecessors "B0"
481## CHECK: successors "<<BTry1>>"
482## CHECK: xhandlers "<<BCatchAll>>"
483## CHECK: TryBoundary is_entry:true is_exit:false
484
485## CHECK: name "<<BExit1Enter2>>"
486## CHECK: predecessors "<<BTry1>>"
487## CHECK: successors "<<BTry2>>"
488## CHECK: xhandlers "<<BCatchAll>>" "<<BCatchArith>>"
489## CHECK: TryBoundary is_entry:true is_exit:true
490
491## CHECK: name "<<BExit2Enter3>>"
492## CHECK: predecessors "<<BTry2>>"
493## CHECK: successors "<<BTry3>>"
494## CHECK: xhandlers "<<BCatchArith>>" "<<BCatchAll>>"
495## CHECK: TryBoundary is_entry:true is_exit:true
496
497## CHECK: name "<<BExit3>>"
498## CHECK: predecessors "<<BTry3>>"
499## CHECK: successors "<<BReturn>>"
500## CHECK: xhandlers "<<BCatchAll>>"
501## CHECK: TryBoundary is_entry:false is_exit:true
502
503.method public static testNestedTry(IIII)I
504 .registers 4
505
506 :try_start_1
507 div-int/2addr p0, p1
508
509 :try_start_2
510 div-int/2addr p0, p2
511 :try_end_2
512 .catch Ljava/lang/ArithmeticException; {:try_start_2 .. :try_end_2} :catch_arith
513
514 div-int/2addr p0, p3
515 :try_end_1
516 .catchall {:try_start_1 .. :try_end_1} :catch_all
517
518 :return
519 return p0
520
521 :catch_arith
522 const/4 p0, -0x1
523 goto :return
524
525 :catch_all
526 const/4 p0, -0x2
527 goto :return
528.end method
529
530# Test control flow that enters a try block, leaves it and returns again.
531
532## CHECK-START: int Builder.testIncontinuousTry(int, int, int, int) builder (after)
533
534## CHECK: name "B0"
535## CHECK: <<Minus1:i\d+>> IntConstant -1
536
537## CHECK: name "<<BTry1:B\d+>>"
538## CHECK: predecessors "<<BEnterTry1:B\d+>>"
539## CHECK: successors "<<BExitTry1:B\d+>>"
540## CHECK: Div
541
542## CHECK: name "<<BTry2:B\d+>>"
543## CHECK: predecessors "<<BEnterTry2:B\d+>>"
544## CHECK: successors "<<BExitTry2:B\d+>>"
545## CHECK: Div
546
547## CHECK: name "<<BReturn:B\d+>>"
548## CHECK: predecessors "<<BExitTry2>>" "<<BCatch:B\d+>>"
549
550## CHECK: name "<<BOutside:B\d+>>"
551## CHECK: predecessors "<<BExitTry1>>"
552## CHECK: successors "<<BEnterTry2>>"
553## CHECK: Div
554
555## CHECK: name "<<BCatch>>"
556## CHECK: predecessors "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
557## CHECK: successors "<<BReturn>>"
558## CHECK: flags "catch_block"
559## CHECK: StoreLocal [v0,<<Minus1>>]
560
561## CHECK: name "<<BEnterTry1>>"
562## CHECK: predecessors "B0"
563## CHECK: successors "<<BTry1>>"
564## CHECK: xhandlers "<<BCatch>>"
565## CHECK: TryBoundary is_entry:true is_exit:false
566
567## CHECK: name "<<BExitTry1>>"
568## CHECK: predecessors "<<BTry1>>"
569## CHECK: successors "<<BOutside>>"
570## CHECK: xhandlers "<<BCatch>>"
571## CHECK: TryBoundary is_entry:false is_exit:true
572
573## CHECK: name "<<BEnterTry2>>"
574## CHECK: predecessors "<<BOutside>>"
575## CHECK: successors "<<BTry2>>"
576## CHECK: xhandlers "<<BCatch>>"
577## CHECK: TryBoundary is_entry:true is_exit:false
578
579## CHECK: name "<<BExitTry2>>"
580## CHECK: predecessors "<<BTry2>>"
581## CHECK: successors "<<BReturn>>"
582## CHECK: xhandlers "<<BCatch>>"
583## CHECK: TryBoundary is_entry:false is_exit:true
584
585.method public static testIncontinuousTry(IIII)I
586 .registers 4
587
588 :try_start
589 div-int/2addr p0, p1
590 goto :outside
591
592 :inside
593 div-int/2addr p0, p3
594 :try_end
595 .catchall {:try_start .. :try_end} :catch_all
596
597 :return
598 return p0
599
600 :outside
601 div-int/2addr p0, p2
602 goto :inside
603
604 :catch_all
605 const/4 p0, -0x1
606 goto :return
607.end method
608
609# Test that a TryBoundary is inserted between a Throw instruction and the exit
610# block when covered by a try range.
611
612## CHECK-START: int Builder.testThrow(java.lang.Exception) builder (after)
613
614## CHECK: name "B0"
615## CHECK: successors "<<BEnterTry:B\d+>>"
616## CHECK: <<Minus1:i\d+>> IntConstant -1
617
618## CHECK: name "<<BTry:B\d+>>"
619## CHECK: predecessors "<<BEnterTry>>"
620## CHECK: successors "<<BExitTry:B\d+>>"
621## CHECK: Throw
622
623## CHECK: name "<<BCatch:B\d+>>"
624## CHECK: predecessors "<<BEnterTry>>" "<<BExitTry>>"
625## CHECK: successors "<<BExit:B\d+>>"
626## CHECK: flags "catch_block"
627## CHECK: StoreLocal [v0,<<Minus1>>]
628
629## CHECK: name "<<BEnterTry>>"
630## CHECK: predecessors "B0"
631## CHECK: successors "<<BTry>>"
632## CHECK: xhandlers "<<BCatch>>"
633## CHECK: TryBoundary is_entry:true is_exit:false
634
635## CHECK: name "<<BExitTry>>"
636## CHECK: predecessors "<<BTry>>"
637## CHECK: successors "<<BExit>>"
638## CHECK: xhandlers "<<BCatch>>"
639## CHECK: TryBoundary is_entry:false is_exit:true
640
641## CHECK: name "<<BExit>>"
642## CHECK: predecessors "<<BExitTry>>" "<<BCatch>>"
643## CHECK: Exit
644
645.method public static testThrow(Ljava/lang/Exception;)I
646 .registers 2
647
648 :try_start
649 throw p0
650 :try_end
651 .catchall {:try_start .. :try_end} :catch_all
652
653 :catch_all
654 const/4 v0, -0x1
655 return v0
656.end method
657
658# Test graph with a throw/catch loop.
659
660## CHECK-START: int Builder.testCatchLoop(int, int, int) builder (after)
661
662## CHECK: name "B0"
663## CHECK: successors "<<BEnterTry:B\d+>>"
664
665## CHECK: name "<<BTry:B\d+>>"
666## CHECK: predecessors "<<BEnterTry>>" "<<BEnterTry>>" "<<BExitTry:B\d+>>"
667## CHECK: successors "<<BExitTry>>"
668## CHECK: flags "catch_block"
669## CHECK: Div
670
671## CHECK: name "<<BReturn:B\d+>>"
672## CHECK: predecessors "<<BExitTry>>"
673
674## CHECK: name "<<BEnterTry>>"
675## CHECK: predecessors "B0"
676## CHECK: successors "<<BTry>>"
677## CHECK: xhandlers "<<BTry>>"
678## CHECK: TryBoundary is_entry:true is_exit:false
679
680## CHECK: name "<<BExitTry>>"
681## CHECK: predecessors "<<BTry>>"
682## CHECK: successors "<<BReturn>>"
683## CHECK: xhandlers "<<BTry>>"
684## CHECK: TryBoundary is_entry:false is_exit:true
685
686.method public static testCatchLoop(III)I
687 .registers 4
688
689 :try_start
690 :catch_all
691 div-int/2addr p0, p2
692 :try_end
693 .catchall {:try_start .. :try_end} :catch_all
694
695 :return
696 return p0
697.end method
698
699# Test that handler edges are not split. In this scenario, the catch block is
700# only the handler of the try block.
701
702## CHECK-START: int Builder.testHandlerEdge1(int, int, int) builder (after)
703
704## CHECK: name "B0"
705## CHECK: successors "<<BEnterTry:B\d+>>"
706
707## CHECK: name "<<BTry:B\d+>>"
708## CHECK: predecessors "<<BEnterTry>>"
709## CHECK: successors "<<BCatch:B\d+>>"
710## CHECK: Div
711
712## CHECK: name "<<BCatch>>"
713## CHECK: predecessors "<<BTry>>" "<<BEnterTry>>" "<<BExitTry:B\d+>>"
714## CHECK: successors "<<BExitTry>>"
715## CHECK: flags "catch_block"
716## CHECK: Div
717
718## CHECK: name "<<BReturn:B\d+>>"
719## CHECK: predecessors "<<BExitTry>>"
720
721## CHECK: name "<<BEnterTry>>"
722## CHECK: predecessors "B0"
723## CHECK: successors "<<BTry>>"
724## CHECK: xhandlers "<<BCatch>>"
725## CHECK: TryBoundary is_entry:true is_exit:false
726
727## CHECK: name "<<BExitTry>>"
728## CHECK: predecessors "<<BCatch>>"
729## CHECK: successors "<<BReturn>>"
730## CHECK: xhandlers "<<BCatch>>"
731## CHECK: TryBoundary is_entry:false is_exit:true
732
733.method public static testHandlerEdge1(III)I
734 .registers 4
735
736 :try_start
737 div-int/2addr p0, p1
738
739 :catch_all
740 div-int/2addr p0, p2
741 :try_end
742 .catchall {:try_start .. :try_end} :catch_all
743
744 return p0
745.end method
746
747# Test that handler edges are not split. In this scenario, the catch block is
748# the handler and also the successor of the try block.
749
750## CHECK-START: int Builder.testHandlerEdge2(int, int, int) builder (after)
751
752## CHECK: name "B0"
753## CHECK: successors "<<BEnter1:B\d+>>"
754
755## CHECK: name "<<BTry1:B\d+>>"
756## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2:B\d+>>" "<<BExit2:B\d+>>"
757## CHECK: successors "<<BExit1Enter2>>"
758## CHECK: flags "catch_block"
759## CHECK: Div
760
761## CHECK: name "<<BTry2:B\d+>>"
762## CHECK: predecessors "<<BExit1Enter2>>" "<<BEnter1>>" "<<BExit1Enter2>>"
763## CHECK: successors "<<BExit2>>"
764## CHECK: flags "catch_block"
765## CHECK: Div
766
767## CHECK: name "<<BReturn:B\d+>>"
768## CHECK: predecessors "<<BExit2>>"
769## CHECK: Return
770
771## CHECK: name "<<BEnter1>>"
772## CHECK: predecessors "B0"
773## CHECK: successors "<<BTry1>>"
774## CHECK: xhandlers "<<BTry2>>"
775## CHECK: TryBoundary is_entry:true is_exit:false
776
777## CHECK: name "<<BExit1Enter2>>"
778## CHECK: predecessors "<<BTry1>>"
779## CHECK: successors "<<BTry2>>"
780## CHECK: xhandlers "<<BTry2>>" "<<BTry1>>"
781## CHECK: TryBoundary is_entry:true is_exit:true
782
783## CHECK: name "<<BExit2>>"
784## CHECK: predecessors "<<BTry2>>"
785## CHECK: successors "<<BReturn>>"
786## CHECK: xhandlers "<<BTry1>>"
787## CHECK: TryBoundary is_entry:false is_exit:true
788
789.method public static testHandlerEdge2(III)I
790 .registers 4
791
792 :try_start_1
793 :catch_all_1
794 div-int/2addr p0, p1
795 :try_end_1
796 .catchall {:try_start_1 .. :try_end_1} :catch_all_2
797
798 :try_start_2
799 :catch_all_2
800 div-int/2addr p0, p2
801 :try_end_2
802 .catchall {:try_start_2 .. :try_end_2} :catch_all_1
803
804 return p0
805.end method
806
807# Test that a MOVE_RESULT instruction is placed into the same block as the
808# INVOKE it follows, even if there is a try boundary between them.
809
810## CHECK-START: int Builder.testMoveResult_Invoke(int, int, int) builder (after)
811
812## CHECK: <<Res:i\d+>> InvokeStaticOrDirect
813## CHECK-NEXT: StoreLocal [v0,<<Res>>]
814
815.method public static testMoveResult_Invoke(III)I
816 .registers 3
817
818 :try_start
819 invoke-static {p0, p1, p2}, LBuilder;->testCatchLoop(III)I
820 :try_end
821 .catchall {:try_start .. :try_end} :catch_all
822
823 move-result p0
824
825 :return
826 return p0
827
828 :catch_all
829 const/4 p0, -0x1
830 goto :return
831.end method
832
833# Test that a MOVE_RESULT instruction is placed into the same block as the
834# FILLED_NEW_ARRAY it follows, even if there is a try boundary between them.
835
836## CHECK-START: int[] Builder.testMoveResult_FilledNewArray(int, int, int) builder (after)
837
838## CHECK: <<Res:l\d+>> NewArray
839## CHECK-NEXT: Temporary
840## CHECK-NEXT: <<Local1:i\d+>> LoadLocal [v0]
841## CHECK-NEXT: ArraySet [<<Res>>,{{i\d+}},<<Local1>>]
842## CHECK-NEXT: <<Local2:i\d+>> LoadLocal [v1]
843## CHECK-NEXT: ArraySet [<<Res>>,{{i\d+}},<<Local2>>]
844## CHECK-NEXT: <<Local3:i\d+>> LoadLocal [v2]
845## CHECK-NEXT: ArraySet [<<Res>>,{{i\d+}},<<Local3>>]
846## CHECK-NEXT: StoreLocal [v0,<<Res>>]
847
848.method public static testMoveResult_FilledNewArray(III)[I
849 .registers 3
850
851 :try_start
852 filled-new-array {p0, p1, p2}, [I
853 :try_end
854 .catchall {:try_start .. :try_end} :catch_all
855
856 move-result-object p0
857
858 :return
859 return-object p0
860
861 :catch_all
862 const/4 p0, 0x0
863 goto :return
864.end method
865
866# Test case for ReturnVoid inside a try block. Builder needs to move it outside
867# the try block so as to not split the ReturnVoid-Exit edge.
868# This invariant is enforced by GraphChecker.
869
870.method public static testReturnVoidInTry(II)V
871 .registers 2
872
873 :catch_all
874 :try_start
875 return-void
876 :try_end
877 .catchall {:try_start .. :try_end} :catch_all
878.end method
879
880# Test case for Return inside a try block. Builder needs to move it outside the
881# try block so as to not split the Return-Exit edge.
882# This invariant is enforced by GraphChecker.
883
884.method public static testReturnInTry(II)I
885 .registers 2
886
887 :try_start
888 div-int/2addr p0, p1
889 return p0
890 :try_end
891 .catchall {:try_start .. :try_end} :catch_all
892
893 :catch_all
894 const/4 v0, 0x0
895 return v0
896.end method
897
898# Test a (dead) try block which flows out of the method. The block will be
899# removed by DCE but needs to pass post-builder GraphChecker.
900
901## CHECK-START: int Builder.testDeadEndTry(int) builder (after)
902## CHECK-NOT: TryBoundary is_exit:true
903
904.method public static testDeadEndTry(I)I
905 .registers 1
906
907 return p0
908
909 :catch_all
910 nop
911
912 :try_start
913 nop
914 :try_end
915 .catchall {:try_start .. :try_end} :catch_all
916.end method