• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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