1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
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
16 #include "macros.h"
17 #include "unit_test.h"
18 #include "code_info/code_info_builder.h"
19 #include "codegen.h"
20 #include "panda_runner.h"
21 #include "events/events.h"
22 #include <fstream>
23 #include "libpandabase/utils/utils.h"
24
25 namespace ark::test {
26 class OsrTest : public testing::Test {
27 public:
OsrTest()28 OsrTest()
29 : defaultCompilerNonOptimizing_(compiler::g_options.IsCompilerNonOptimizing()),
30 defaultCompilerInlining_(compiler::g_options.IsCompilerInlining()),
31 defaultCompilerInliningBlacklist_(compiler::g_options.GetCompilerInliningBlacklist()),
32 defaultCompilerRegex_(compiler::g_options.GetCompilerRegex())
33 {
34 }
35
~OsrTest()36 ~OsrTest() override
37 {
38 compiler::g_options.SetCompilerNonOptimizing(defaultCompilerNonOptimizing_);
39 compiler::g_options.SetCompilerInlining(defaultCompilerInlining_);
40 compiler::g_options.SetCompilerInliningBlacklist(defaultCompilerInliningBlacklist_);
41 compiler::g_options.SetCompilerRegex(defaultCompilerRegex_);
42 }
43
44 NO_COPY_SEMANTIC(OsrTest);
45 NO_MOVE_SEMANTIC(OsrTest);
46
SetUp()47 void SetUp() override
48 {
49 #ifndef PANDA_EVENTS_ENABLED
50 GTEST_SKIP();
51 #endif
52 if constexpr (!ArchTraits<RUNTIME_ARCH>::SUPPORT_OSR) {
53 GTEST_SKIP();
54 }
55 }
56
57 protected:
58 static constexpr size_t HOTNESS_THRESHOLD = 4U;
59
60 private:
61 bool defaultCompilerNonOptimizing_;
62 bool defaultCompilerInlining_;
63 arg_list_t defaultCompilerInliningBlacklist_;
64 std::string defaultCompilerRegex_;
65 };
66
67 struct ScopeEvents {
ScopeEventsark::test::ScopeEvents68 ScopeEvents()
69 {
70 Events::Create<Events::MEMORY>();
71 }
~ScopeEventsark::test::ScopeEvents72 ~ScopeEvents()
73 {
74 Events::Destroy();
75 }
76
77 NO_COPY_SEMANTIC(ScopeEvents);
78 NO_MOVE_SEMANTIC(ScopeEvents);
79 };
80
81 static constexpr auto OSR_IN_TOP_FRAME_SOURCE = R"(
82 .function i32 main() {
83 movi v0, 0
84 movi v1, 30
85 movi v2, 0
86 loop:
87 lda v0
88 jeq v1, exit
89 add2 v2
90 sta v2
91 inci v0, 1
92 jmp loop
93 exit:
94 lda v2
95 return
96 }
97 )";
98
99 // NOLINTBEGIN(readability-magic-numbers)
TEST_F(OsrTest,OsrInTopFrameNonOptimizing)100 TEST_F(OsrTest, OsrInTopFrameNonOptimizing)
101 {
102 PandaRunner runner;
103 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
104 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
105 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
106
107 ScopeEvents scopeEvents;
108
109 runner.Run(OSR_IN_TOP_FRAME_SOURCE, 435U);
110 auto events = Events::CastTo<Events::MEMORY>();
111 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
112 ASSERT_EQ(osrEvents.size(), 1U);
113 }
114
TEST_F(OsrTest,OsrInTopFrameOptimizing)115 TEST_F(OsrTest, OsrInTopFrameOptimizing)
116 {
117 PandaRunner runner;
118 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
119 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
120 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
121
122 ScopeEvents scopeEvents;
123
124 runner.Run(OSR_IN_TOP_FRAME_SOURCE, 435U);
125 auto events = Events::CastTo<Events::MEMORY>();
126 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
127 ASSERT_EQ(osrEvents.size(), 1U);
128 }
129
130 static constexpr auto OSR_AFTER_IFRAME_SOURCE = R"(
131 .function i32 main() {
132 call f1
133 return
134 }
135
136 .function i32 f1() {
137 movi v0, 0
138 movi v1, 30
139 movi v2, 0
140 loop:
141 lda v0
142 jeq v1, exit
143 add2 v2
144 sta v2
145 inci v0, 1
146 jmp loop
147 exit:
148 lda v2
149 return
150 }
151 )";
152
TEST_F(OsrTest,OsrAfterIFrameNonOptimizing)153 TEST_F(OsrTest, OsrAfterIFrameNonOptimizing)
154 {
155 PandaRunner runner;
156 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
157 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
158 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
159
160 ScopeEvents scopeEvents;
161 runner.Run(OSR_AFTER_IFRAME_SOURCE, 435U);
162 auto events = Events::CastTo<Events::MEMORY>();
163 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
164 ASSERT_EQ(osrEvents.size(), 1U);
165 }
166
TEST_F(OsrTest,OsrAfterIFrameOptimizing)167 TEST_F(OsrTest, OsrAfterIFrameOptimizing)
168 {
169 PandaRunner runner;
170 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
171 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
172 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
173
174 ScopeEvents scopeEvents;
175 runner.Run(OSR_AFTER_IFRAME_SOURCE, 435U);
176 auto events = Events::CastTo<Events::MEMORY>();
177 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
178 ASSERT_EQ(osrEvents.size(), 1U);
179 }
180
181 static constexpr auto OSR_AFTER_IFRAME_RESTORE_ACC_AFTER_VOID = R"(
182 .function i32 main() {
183 call f1
184 return
185 }
186
187 .function void f1() {
188 movi v0, 0
189 movi v1, 30
190 movi v2, 0
191 loop:
192 lda v0
193 jeq v1, exit
194 add2 v2
195 sta v2
196 inci v0, 1
197 jmp loop
198 exit:
199 lda v2
200 return.void
201 }
202 )";
203
TEST_F(OsrTest,OsrAfterIFrameRestoreAccAfterVoid)204 TEST_F(OsrTest, OsrAfterIFrameRestoreAccAfterVoid)
205 {
206 PandaRunner runner;
207 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
208 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
209 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
210
211 ScopeEvents scopeEvents;
212 runner.Run(OSR_AFTER_IFRAME_RESTORE_ACC_AFTER_VOID, static_cast<ssize_t>(0U));
213 auto events = Events::CastTo<Events::MEMORY>();
214 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
215 ASSERT_EQ(osrEvents.size(), 1U);
216 }
217
218 static constexpr auto OSR_AFTER_CFRAME_SOURCE = R"(
219 .function i32 main() {
220 movi v0, 0
221 movi v1, 11
222 loop:
223 lda v1
224 jeq v0, exit
225 inci v0, 1
226 movi v2, 0
227 call f1, v2
228 jmp loop
229 exit:
230 movi v2, 1
231 call f1, v2
232 return
233 }
234
235 .function i32 f1(i32 a0) {
236 ldai 0
237 jeq a0, exit
238 call f2
239 exit:
240 return
241 }
242
243 .function i32 f2() {
244 movi v0, 0
245 movi v1, 30
246 movi v2, 0
247 loop:
248 lda v0
249 jeq v1, exit
250 add2 v2
251 sta v2
252 inci v0, 1
253 jmp loop
254 exit:
255 lda v2
256 return
257 }
258 )";
259
TEST_F(OsrTest,OsrAfterCFrameNonOptimizing)260 TEST_F(OsrTest, OsrAfterCFrameNonOptimizing)
261 {
262 PandaRunner runner;
263 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
264 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
265 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
266
267 ScopeEvents scopeEvents;
268 runner.Run(OSR_AFTER_CFRAME_SOURCE, 435U);
269 auto events = Events::CastTo<Events::MEMORY>();
270 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
271 ASSERT_EQ(osrEvents.size(), 1U);
272 ASSERT_EQ(osrEvents[0U]->kind, events::OsrEntryKind::AFTER_CFRAME);
273 ASSERT_EQ(osrEvents[0U]->result, events::OsrEntryResult::SUCCESS);
274 }
275
TEST_F(OsrTest,OsrAfterCFrameOptimizing)276 TEST_F(OsrTest, OsrAfterCFrameOptimizing)
277 {
278 PandaRunner runner;
279 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
280 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
281 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
282 runner.GetCompilerOptions().SetCompilerInlining(false);
283
284 ScopeEvents scopeEvents;
285 runner.Run(OSR_AFTER_CFRAME_SOURCE, 435U);
286 auto events = Events::CastTo<Events::MEMORY>();
287 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
288 ASSERT_EQ(osrEvents.size(), 1U);
289 ASSERT_EQ(osrEvents[0U]->kind, events::OsrEntryKind::AFTER_CFRAME);
290 ASSERT_EQ(osrEvents[0U]->result, events::OsrEntryResult::SUCCESS);
291 }
292
TEST_F(OsrTest,OsrAfterCFrameOptimizingWithInlining)293 TEST_F(OsrTest, OsrAfterCFrameOptimizingWithInlining)
294 {
295 PandaRunner runner;
296 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
297 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
298 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
299 runner.GetCompilerOptions().SetCompilerInlining(true);
300 runner.GetCompilerOptions().SetCompilerInliningBlacklist({"_GLOBAL::f2"});
301
302 ScopeEvents scopeEvents;
303 runner.Run(OSR_AFTER_CFRAME_SOURCE, 435U);
304 auto events = Events::CastTo<Events::MEMORY>();
305 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
306 auto found = events->Find<events::EventsMemory::InlineEvent>(
307 [](const auto &event) { return event.caller == "_GLOBAL::main" && event.callee == "_GLOBAL::f1"; });
308 ASSERT_TRUE(found);
309 ASSERT_EQ(osrEvents.size(), 1U);
310 ASSERT_EQ(osrEvents[0U]->kind, events::OsrEntryKind::AFTER_CFRAME);
311 ASSERT_EQ(osrEvents[0U]->result, events::OsrEntryResult::SUCCESS);
312 }
313
TEST_F(OsrTest,MainOsrCatchThrow)314 TEST_F(OsrTest, MainOsrCatchThrow)
315 {
316 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
317 static constexpr auto SOURCE = R"(
318 .record panda.ArrayIndexOutOfBoundsException <external>
319
320 .function i32 main() {
321 movi v0, 0
322 movi v1, 15
323 newarr v1, v1, i32[]
324 movi v2, 20
325 loop:
326 try_begin:
327 lda v2
328 jeq v0, exit
329 inci v0, 1
330 lda v0
331 starr v1, v0
332 jmp loop
333 try_end:
334 exit:
335 ldai 1
336 return
337
338 catch_block1_begin:
339 ldai 123
340 return
341
342 .catch panda.ArrayIndexOutOfBoundsException, try_begin, try_end, catch_block1_begin
343 }
344 )";
345
346 PandaRunner runner;
347 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
348 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
349 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
350
351 ScopeEvents scopeEvents;
352 runner.Run(SOURCE, 123U);
353 auto events = Events::CastTo<Events::MEMORY>();
354 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
355 ASSERT_EQ(osrEvents.size(), 1U);
356 ASSERT_EQ(osrEvents[0U]->kind, events::OsrEntryKind::TOP_FRAME);
357 ASSERT_EQ(osrEvents[0U]->result, events::OsrEntryResult::SUCCESS);
358 auto deoptEvents = events->Select<events::EventsMemory::DeoptimizationEvent>();
359 ASSERT_EQ(deoptEvents.size(), 1U);
360 ASSERT_EQ(deoptEvents[0U]->after, events::DeoptimizationAfter::TOP);
361 }
362
363 static constexpr auto MAIN_OSR_CATCH_F1_THROW_SOURCE = R"(
364 .record panda.ArrayIndexOutOfBoundsException <external>
365
366 .function i32 main() {
367 movi v0, 0
368 movi v1, 15
369 newarr v1, v1, i32[]
370 movi v2, 20
371 loop:
372 try_begin:
373 lda v2
374 jeq v0, exit
375 inci v0, 1
376 call f1, v1, v0
377 jmp loop
378 try_end:
379 exit:
380 ldai 1
381 return
382
383 catch_block1_begin:
384 ldai 123
385 return
386
387 .catch panda.ArrayIndexOutOfBoundsException, try_begin, try_end, catch_block1_begin
388 }
389
390 .function void f1(i32[] a0, i32 a1) {
391 lda a1
392 starr a0, a1
393 return.void
394 }
395 )";
396
TEST_F(OsrTest,MainOsrCatchF1Throw)397 TEST_F(OsrTest, MainOsrCatchF1Throw)
398 {
399 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
400 PandaRunner runner;
401 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
402 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
403 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
404 runner.GetCompilerOptions().SetCompilerInlining(false);
405 runner.GetCompilerOptions().SetCompilerRegex("(?!_GLOBAL::f1).*");
406
407 ScopeEvents scopeEvents;
408 runner.Run(MAIN_OSR_CATCH_F1_THROW_SOURCE, 123U);
409 auto events = Events::CastTo<Events::MEMORY>();
410 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
411 ASSERT_EQ(osrEvents.size(), 1);
412 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::TOP_FRAME);
413 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
414 auto deoptEvents = events->Select<events::EventsMemory::DeoptimizationEvent>();
415 ASSERT_EQ(deoptEvents.size(), 1);
416 ASSERT_EQ(deoptEvents[0]->after, events::DeoptimizationAfter::TOP);
417 }
418
TEST_F(OsrTest,MainOsrCatchF1ThrowCompiled)419 TEST_F(OsrTest, MainOsrCatchF1ThrowCompiled)
420 {
421 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
422 PandaRunner runner;
423 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
424 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
425 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
426 runner.GetCompilerOptions().SetCompilerInlining(false);
427
428 ScopeEvents scopeEvents;
429 runner.Run(MAIN_OSR_CATCH_F1_THROW_SOURCE, 123U);
430 auto events = Events::CastTo<Events::MEMORY>();
431 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
432 ASSERT_EQ(osrEvents.size(), 1);
433 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::TOP_FRAME);
434 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
435 auto exceptionEvents = events->Select<events::EventsMemory::ExceptionEvent>();
436 ASSERT_EQ(exceptionEvents.size(), 1);
437 ASSERT_EQ(exceptionEvents[0]->type, events::ExceptionType::BOUND_CHECK);
438 }
439
440 static constexpr auto MAIN_CATCH_F1_OSR_THROW_SOURCE = R"(
441 .record panda.ArrayIndexOutOfBoundsException <external>
442
443 .function i32 main() {
444 movi v1, 15
445 newarr v1, v1, i32[]
446 try_begin:
447 call f1, v1
448 try_end:
449 ldai 1
450 return
451
452 catch_block1_begin:
453 ldai 123
454 return
455
456 .catch panda.ArrayIndexOutOfBoundsException, try_begin, try_end, catch_block1_begin
457 }
458
459 .function void f1(i32[] a0) {
460 movi v0, 0
461 movi v2, 20
462 loop:
463 lda v2
464 jeq v0, exit
465 inci v0, 1
466 starr a0, v0
467 jmp loop
468 exit:
469 return.void
470 }
471 )";
472
TEST_F(OsrTest,MainCatchF1OsrThrow)473 TEST_F(OsrTest, MainCatchF1OsrThrow)
474 {
475 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
476 PandaRunner runner;
477 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
478 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
479 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
480 runner.GetCompilerOptions().SetCompilerInlining(false);
481
482 ScopeEvents scopeEvents;
483 runner.Run(MAIN_CATCH_F1_OSR_THROW_SOURCE, 123U);
484 auto events = Events::CastTo<Events::MEMORY>();
485 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
486 ASSERT_EQ(osrEvents.size(), 1U);
487 ASSERT_EQ(osrEvents[0U]->kind, events::OsrEntryKind::AFTER_IFRAME);
488 ASSERT_EQ(osrEvents[0U]->result, events::OsrEntryResult::SUCCESS);
489 auto exceptionEvents = events->Select<events::EventsMemory::ExceptionEvent>();
490 ASSERT_EQ(exceptionEvents.size(), 1U);
491 ASSERT_EQ(exceptionEvents[0U]->type, events::ExceptionType::BOUND_CHECK);
492 }
493
494 static constexpr auto MAIN_CATCH_F1_OSR_F2_THROW_SOURCE = R"(
495 .record panda.ArrayIndexOutOfBoundsException <external>
496
497 .function i32 main() {
498 movi v1, 15
499 newarr v1, v1, i32[]
500 try_begin:
501 call f1, v1
502 try_end:
503 ldai 1
504 return
505
506 catch_block1_begin:
507 ldai 123
508 return
509
510 .catch panda.ArrayIndexOutOfBoundsException, try_begin, try_end, catch_block1_begin
511 }
512
513 .function void f1(i32[] a0) {
514 movi v0, 0
515 movi v2, 20
516 loop:
517 lda v2
518 jeq v0, exit
519 inci v0, 1
520 call f2, a0, v0
521 jmp loop
522 exit:
523 return.void
524 }
525
526 .function void f2(i32[] a0, i32 a1) {
527 lda a1
528 starr a0, a1
529 return.void
530 }
531 )";
532
TEST_F(OsrTest,MainCatchF1OsrF2Throw)533 TEST_F(OsrTest, MainCatchF1OsrF2Throw)
534 {
535 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
536 PandaRunner runner;
537 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
538 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
539 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
540 runner.GetCompilerOptions().SetCompilerInlining(false);
541 runner.GetCompilerOptions().SetCompilerRegex("(?!_GLOBAL::f2).*");
542
543 ScopeEvents scopeEvents;
544 runner.Run(MAIN_CATCH_F1_OSR_F2_THROW_SOURCE, 123U);
545 auto events = Events::CastTo<Events::MEMORY>();
546 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
547 ASSERT_EQ(osrEvents.size(), 1);
548 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::AFTER_IFRAME);
549 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
550 auto deoptEvents = events->Select<events::EventsMemory::DeoptimizationEvent>();
551 // Since f1 hasn't catch handler, it shouldn't be deoptimized
552 ASSERT_EQ(deoptEvents.size(), 0);
553 auto exceptionEvents = events->Select<events::EventsMemory::ExceptionEvent>();
554 ASSERT_EQ(exceptionEvents.size(), 0);
555 }
556
TEST_F(OsrTest,MainCatchF1OsrF2ThrowCompiled)557 TEST_F(OsrTest, MainCatchF1OsrF2ThrowCompiled)
558 {
559 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
560 PandaRunner runner;
561 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
562 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
563 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
564 runner.GetCompilerOptions().SetCompilerInlining(false);
565
566 ScopeEvents scopeEvents;
567 runner.Run(MAIN_CATCH_F1_OSR_F2_THROW_SOURCE, 123U);
568 auto events = Events::CastTo<Events::MEMORY>();
569 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
570 ASSERT_EQ(osrEvents.size(), 1);
571 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::AFTER_IFRAME);
572 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
573 auto exceptionEvents = events->Select<events::EventsMemory::ExceptionEvent>();
574 ASSERT_EQ(exceptionEvents.size(), 1);
575 ASSERT_EQ(exceptionEvents[0]->type, events::ExceptionType::BOUND_CHECK);
576 }
577
578 static constexpr auto MAIN_F1_OSR_CATCH_F2_THROW_SOURCE = R"(
579 .record panda.ArrayIndexOutOfBoundsException <external>
580
581 .function i32 main() {
582 movi v1, 15
583 newarr v1, v1, i32[]
584 call f1, v1
585 return
586 }
587
588 .function i32 f1(i32[] a0) {
589 movi v0, 0
590 movi v2, 20
591 loop:
592 try_begin:
593 lda v2
594 jeq v0, exit
595 inci v0, 1
596 call f2, a0, v0
597 jmp loop
598 try_end:
599
600 exit:
601 ldai 1
602 return
603
604 catch_block1_begin:
605 ldai 123
606 return
607
608 .catch panda.ArrayIndexOutOfBoundsException, try_begin, try_end, catch_block1_begin
609 }
610
611 .function void f2(i32[] a0, i32 a1) {
612 lda a1
613 starr a0, a1
614 return.void
615 }
616 )";
617
TEST_F(OsrTest,MainF1OsrCatchF2Throw)618 TEST_F(OsrTest, MainF1OsrCatchF2Throw)
619 {
620 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
621 PandaRunner runner;
622 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
623 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
624 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
625 runner.GetCompilerOptions().SetCompilerInlining(false);
626 runner.GetCompilerOptions().SetCompilerRegex("(?!_GLOBAL::f2).*");
627
628 ScopeEvents scopeEvents;
629 runner.Run(MAIN_F1_OSR_CATCH_F2_THROW_SOURCE, 123U);
630 auto events = Events::CastTo<Events::MEMORY>();
631 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
632 ASSERT_EQ(osrEvents.size(), 1);
633 ASSERT_EQ(osrEvents[0]->methodName, "_GLOBAL::f1");
634 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::AFTER_IFRAME);
635 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
636 auto deoptEvents = events->Select<events::EventsMemory::DeoptimizationEvent>();
637 ASSERT_EQ(deoptEvents.size(), 1);
638 ASSERT_EQ(deoptEvents[0]->methodName, "_GLOBAL::f1");
639 ASSERT_EQ(deoptEvents[0]->after, events::DeoptimizationAfter::IFRAME);
640 }
641
TEST_F(OsrTest,MainF1OsrCatchF2ThrowCompiled)642 TEST_F(OsrTest, MainF1OsrCatchF2ThrowCompiled)
643 {
644 GTEST_SKIP() << "Should be skipped until try-catch processing re-designed in OSR";
645 PandaRunner runner;
646 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(HOTNESS_THRESHOLD);
647 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
648 runner.GetCompilerOptions().SetCompilerNonOptimizing(false);
649 runner.GetCompilerOptions().SetCompilerInlining(false);
650
651 ScopeEvents scopeEvents;
652 runner.Run(MAIN_F1_OSR_CATCH_F2_THROW_SOURCE, 123U);
653 auto events = Events::CastTo<Events::MEMORY>();
654 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
655 ASSERT_EQ(osrEvents.size(), 1);
656 ASSERT_EQ(osrEvents[0]->methodName, "_GLOBAL::f1");
657 ASSERT_EQ(osrEvents[0]->kind, events::OsrEntryKind::AFTER_IFRAME);
658 ASSERT_EQ(osrEvents[0]->result, events::OsrEntryResult::SUCCESS);
659 auto deoptEvents = events->Select<events::EventsMemory::DeoptimizationEvent>();
660 auto exceptionEvents = events->Select<events::EventsMemory::ExceptionEvent>();
661 ASSERT_EQ(exceptionEvents.size(), 1);
662 ASSERT_EQ(exceptionEvents[0]->methodName, "_GLOBAL::f2");
663 ASSERT_EQ(exceptionEvents[0]->type, events::ExceptionType::BOUND_CHECK);
664 }
665
666 #if !defined(USE_ADDRESS_SANITIZER) && defined(PANDA_TARGET_AMD64)
TEST_F(OsrTest,BoundTest)667 TEST_F(OsrTest, BoundTest)
668 {
669 PandaRunner runner;
670 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(0);
671 runner.GetRuntimeOptions().SetCompilerEnableJit(true);
672 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
673
674 PandaString start =
675 " .function i64 main(i64 a0) {"
676 " lda a0";
677
678 PandaString end =
679 " return "
680 " }"
681 " ";
682
683 std::stringstream text("");
684
685 uint64_t instsPerByte = 32;
686 uint64_t maxBitsInInst = GetInstructionSizeBits(RUNTIME_ARCH);
687 uint64_t instCount = runner.GetCompilerOptions().GetCompilerMaxGenCodeSize() / (instsPerByte * maxBitsInInst);
688
689 for (uint64_t i = 0; i < instCount; ++i) {
690 text << " addi 1\n";
691 }
692
693 std::string boundTest = std::string(start) + std::string(text.str()) + std::string(end);
694
695 ScopeEvents scopeEvents;
696
697 runner.Run(boundTest, 123_I);
698 auto events = Events::CastTo<Events::MEMORY>();
699 auto osrEvents = events->Select<events::EventsMemory::OsrEntryEvent>();
700 ASSERT_EQ(osrEvents.size(), 1);
701 }
702 #endif
703 // NOLINTEND(readability-magic-numbers)
704
705 } // namespace ark::test
706