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