1/*
2 * Copyright (c) 2023 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 <gtest/gtest.h>
17
18#include "assembly-parser.h"
19#include "bytecode_optimizer/ir_interface.h"
20#include "bytecode_optimizer/runtime_adapter.h"
21#include "libpandabase/mem/arena_allocator.h"
22#include "libpandabase/mem/pool_manager.h"
23#include "libpandafile/class_data_accessor.h"
24#include "libpandafile/class_data_accessor-inl.h"
25#include "libpandafile/method_data_accessor.h"
26#include "libpandafile/file.h"
27#include "macros.h"
28#include "optimizer/ir/graph.h"
29#include "optimizer/ir/inst.h"
30#include "optimizer/ir/runtime_interface.h"
31#include "optimizer/ir_builder/ir_builder.h"
32
33namespace panda::compiler {
34class IrBuilderTest : public testing::Test {
35public:
36    static void SetUpTestCase(void) {};
37    static void TearDownTestCase(void) {};
38    void SetUp() {};
39    void TearDown() {};
40
41    IrBuilderTest()
42    {
43        PoolManager::Initialize(PoolType::MALLOC);
44    }
45
46    ~IrBuilderTest()
47    {
48        PoolManager::Finalize();
49    }
50
51    template <class Callback>
52    void TestBuildGraphFromFunc(pandasm::Program &prog, const char *methodName, const Callback &cb)
53    {
54        pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
55        auto pfile = pandasm::AsmEmitter::Emit(prog, &maps);
56        for (uint32_t id : pfile->GetClasses()) {
57            panda_file::File::EntityId record_id {id};
58            panda_file::ClassDataAccessor cda {*pfile, record_id};
59
60            cda.EnumerateMethods([&prog, maps, methodName, &cb](panda_file::MethodDataAccessor &mda) {
61                auto ir_interface = panda::bytecodeopt::BytecodeOptIrInterface(&maps, &prog);
62                auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
63                if (func_name != methodName) {
64                    return;
65                }
66
67                ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
68                ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
69
70                auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
71                    mda.GetMethodId().GetOffset());
72                panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
73                auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
74                                                   false, nullptr, true, true);
75                graph->RunPass<panda::compiler::IrBuilder>();
76                cb(graph);
77            });
78        }
79    }
80
81    template <class Callback>
82    void TestBuildGraphFromFile(const std::string &pFileName, const Callback &cb)
83    {
84        auto pfile = panda_file::OpenPandaFile(pFileName);
85        for (uint32_t id : pfile->GetClasses()) {
86            panda_file::File::EntityId record_id {id};
87
88            if (pfile->IsExternal(record_id)) {
89                continue;
90            }
91
92            panda_file::ClassDataAccessor cda {*pfile, record_id};
93            cda.EnumerateMethods([&pfile, &cb](panda_file::MethodDataAccessor &mda) {
94                if (!mda.IsExternal()) {
95                    ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
96                    ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
97
98                    auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
99                        mda.GetMethodId().GetOffset());
100                    panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
101                    auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
102                                                       false, nullptr, true, true);
103                    graph->RunPass<panda::compiler::IrBuilder>();
104
105                    auto method_name = std::string(utf::Mutf8AsCString(pfile->GetStringData(mda.GetNameId()).data));
106                    auto pos = method_name.find_last_of("#");
107                    if (pos != std::string::npos) {
108                        method_name = method_name.substr(pos + 1);
109                    }
110                    cb(graph, method_name);
111                }
112            });
113        }
114    }
115};
116
117HWTEST_F(IrBuilderTest, simpleTryCatchAsm, testing::ext::TestSize.Level1)
118{
119    /**
120     *  try {
121     *      a = 1;
122     *  } catch(e) {
123     *      a = 2;
124     *  }
125     */
126    const auto source = R"(
127        .language ECMAScript
128        .function any foo(any a0, any a1, any a2) {
129            mov v0, a0
130            mov v1, a1
131            mov v2, a2
132        try_begin:
133            ldai 0x1
134            trystglobalbyname 0x0, "a"
135        try_end:
136            jmp catch_end
137        catch_begin:
138            sta v4
139            tryldglobalbyname 0x1, "a"
140        catch_end:
141            returnundefined
142        }
143    )";
144
145    panda::pandasm::Parser parser;
146    auto res = parser.Parse(source);
147    auto &prog = res.Value();
148    for (auto &[name, func] : prog.function_table) {
149        auto &catchBlock = func.catch_blocks.emplace_back();
150        catchBlock.try_begin_label = "try_begin";
151        catchBlock.try_end_label = "try_end";
152        catchBlock.catch_begin_label = "catch_begin";
153        catchBlock.catch_end_label = "catch_end";
154    }
155
156    TestBuildGraphFromFunc(prog, "foo:(any,any,any)", [](Graph* graph) {
157        EXPECT_NE(graph, nullptr);
158        for (auto bb : graph->GetBlocksRPO()) {
159            EXPECT_NE(bb, nullptr);
160            if (bb->IsTryBegin()) {
161                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
162                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
163                EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
164                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
165                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
166
167                EXPECT_TRUE(bb->GetFirstInst()->IsTry());
168                continue;
169            }
170
171            if (bb->IsTry()) {
172                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
173                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
174                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
175
176                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
177                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
178                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
179                            RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
180                continue;
181            }
182
183            if (bb->IsTryEnd()) {
184                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
185                EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
186                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
187                EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
188                EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatch());
189                EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatchBegin());
190                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
191                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
192
193                EXPECT_TRUE(bb->IsEmpty());
194                continue;
195            }
196
197            if (bb->IsCatchBegin()) {
198                EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
199                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
200                EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
201                EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
202
203                EXPECT_TRUE(bb->IsEmpty());
204                continue;
205            }
206
207            if (bb->IsCatch() && !bb->IsCatchBegin()) {
208                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
209                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
210
211                EXPECT_TRUE(bb->GetSuccessor(0)->GetFirstInst()->IsSaveState());
212                EXPECT_TRUE(bb->GetSuccessor(0)->GetLastInst()->IsIntrinsic());
213                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetSuccessor(0)->GetLastInst()))->GetIntrinsicId() ==
214                            RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
215
216                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
217                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
218                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
219                            RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
220                continue;
221            }
222        }
223    });
224}
225
226HWTEST_F(IrBuilderTest, nestedTryCatchAsm, testing::ext::TestSize.Level1)
227{
228    /**
229     *  try {
230     *      try {
231     *          a = 1;
232     *      } catch(e) {
233     *          a;
234     *      }
235     *  } catch(e) {
236     *      print(e);
237     *  }
238     */
239    const auto source = R"(
240        .language ECMAScript
241        .function any foo(any a0, any a1, any a2) {
242            mov v2, a2
243            mov v1, a1
244            mov v0, a0
245            lda.str "use strict"
246        LABEL_0:
247        LABEL_1:
248            ldai 1
249            trystglobalbyname 0, "a"
250        LABEL_2:
251            jmp LABEL_3
252        LABEL_4:
253            sta v3
254            tryldglobalbyname 1, "a"
255        LABEL_3:
256        LABEL_5:
257            jmp LABEL_6
258        LABEL_7:
259            sta v4
260            tryldglobalbyname 2, "print"
261            sta v5
262            lda v4
263            sta v6
264            lda v5
265            callarg1 3, v6
266        LABEL_6:
267            returnundefined
268        }
269    )";
270
271    panda::pandasm::Parser parser;
272    auto res = parser.Parse(source);
273    auto &prog = res.Value();
274    EXPECT_TRUE(prog.function_table.size() == 1);
275    for (auto &[name, func] : prog.function_table) {
276        auto &catchBlock1 = func.catch_blocks.emplace_back();
277        catchBlock1.try_begin_label = "LABEL_0";
278        catchBlock1.try_end_label = "LABEL_1";
279        catchBlock1.catch_begin_label = "LABEL_7";
280        catchBlock1.catch_end_label = "LABEL_6";
281
282        auto &catchBlock2 = func.catch_blocks.emplace_back();
283        catchBlock2.try_begin_label = "LABEL_1";
284        catchBlock2.try_end_label = "LABEL_2";
285        catchBlock2.catch_begin_label = "LABEL_4";
286        catchBlock2.catch_end_label = "LABEL_3";
287
288        auto &catchBlock3 = func.catch_blocks.emplace_back();
289        catchBlock3.try_begin_label = "LABEL_2";
290        catchBlock3.try_end_label = "LABEL_5";
291        catchBlock3.catch_begin_label = "LABEL_7";
292        catchBlock3.catch_end_label = "LABEL_6";
293    }
294
295    TestBuildGraphFromFunc(prog, "foo:(any,any,any)", [](Graph* graph) {
296        EXPECT_NE(graph, nullptr);
297        int32_t numOfTry = 0;
298        for (auto bb : graph->GetBlocksRPO()) {
299            EXPECT_NE(bb, nullptr);
300            if (bb->IsTryBegin()) {
301                numOfTry++;
302
303                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
304
305                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
306                EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
307                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
308                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
309
310                EXPECT_TRUE(bb->GetSuccessor(0)->GetTryId() == bb->GetTryId());
311                continue;
312            }
313
314            if (bb->IsTry()) {
315                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
316                if (!bb->GetPredecessor(0)->IsTryBegin()) {
317                    EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
318                    EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
319
320                    EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
321                    EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
322                    EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
323                                RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
324                    continue;
325                }
326
327
328                EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
329                EXPECT_TRUE(bb->GetPredecessor(0)->GetGuestPc() == bb->GetGuestPc());
330                if (bb->GetPredecessor(0)->GetTryId() == 1) {
331                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
332                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
333
334                    EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
335                    EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
336                    EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
337                                RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
338                    continue;
339                }
340
341                EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == 2);
342                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
343                EXPECT_TRUE(bb->IsEmpty());
344
345                for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
346                    EXPECT_TRUE(inst->IsPhi());
347                }
348                continue;
349            }
350
351            if (bb->IsTryEnd()) {
352                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
353                EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
354                EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
355
356                EXPECT_TRUE(bb->IsEmpty());
357
358                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
359                if (bb->GetTryId() == 1) {
360                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryBegin());
361                    EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
362
363                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
364                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
365
366                    for (auto inst : bb->GetSuccessor(1)->AllInsts()) {
367                        EXPECT_TRUE(inst->IsCatchPhi());
368                    }
369                    continue;
370                }
371
372                EXPECT_TRUE(bb->GetTryId() == 2);
373                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
374                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
375                for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
376                    EXPECT_TRUE(inst->IsPhi());
377                }
378                continue;
379            }
380
381            if (bb->IsCatchBegin()) {
382                EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
383                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
384                EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
385
386                EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
387                continue;
388            }
389
390            if (bb->IsCatch() && !bb->IsCatchBegin()) {
391                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
392
393                if (bb->IsTry()) {
394                    EXPECT_TRUE(bb->GetTryId() == 2);
395
396                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
397                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
398                    EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
399
400                    EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
401                    EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
402                    EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
403                                RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
404                    continue;
405                }
406
407                if (bb->IsTryEnd()) {
408                    EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
409                    EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
410
411                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
412                    for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
413                        EXPECT_TRUE(inst->IsPhi());
414                    }
415                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
416                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
417
418                    EXPECT_TRUE(bb->IsEmpty());
419                    continue;
420                }
421
422                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
423                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
424
425                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
426                auto *successor = bb->GetSuccessor(0);
427                EXPECT_TRUE(successor->GetFirstInst()->IsSaveState());
428                EXPECT_TRUE(successor->GetLastInst()->IsIntrinsic());
429                EXPECT_TRUE((static_cast<IntrinsicInst *>(successor->GetLastInst()))->GetIntrinsicId() ==
430                            RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
431                for (auto inst : successor->GetPredecessor(0)->AllInsts()) {
432                    EXPECT_TRUE(inst->IsPhi());
433                }
434
435                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
436                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
437                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
438                            RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8);
439            }
440        }
441
442        EXPECT_EQ(numOfTry, 2);
443    });
444}
445
446HWTEST_F(IrBuilderTest, simpleTryCatchAbc, testing::ext::TestSize.Level1)
447{
448    std::string pFile = GRAPH_TEST_ABC_DIR "simpleTryCatch.abc";
449    const char *testMethodName = "func_main_0";
450    TestBuildGraphFromFile(pFile, [&testMethodName](Graph* graph, std::string &methodName) {
451        if (testMethodName != methodName) {
452            return;
453        }
454
455        EXPECT_NE(graph, nullptr);
456        for (auto bb : graph->GetBlocksRPO()) {
457            EXPECT_NE(bb, nullptr);
458            if (bb->IsTryBegin()) {
459                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
460                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
461                EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
462                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
463                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
464
465                EXPECT_TRUE(bb->GetFirstInst()->IsTry());
466                continue;
467            }
468
469            if (bb->IsTry()) {
470                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
471                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
472                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
473
474                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
475                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
476                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
477                            RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
478                continue;
479            }
480
481            if (bb->IsTryEnd()) {
482                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
483                EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
484                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
485                EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
486                EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatch());
487                EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatchBegin());
488                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
489                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
490
491                EXPECT_TRUE(bb->IsEmpty());
492                continue;
493            }
494
495            if (bb->IsCatchBegin()) {
496                EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
497                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
498                EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
499                EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
500
501                EXPECT_TRUE(bb->IsEmpty());
502                continue;
503            }
504
505            if (bb->IsCatch() && !bb->IsCatchBegin()) {
506                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
507                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
508
509                EXPECT_TRUE(bb->GetSuccessor(0)->GetFirstInst()->IsSaveState());
510                EXPECT_TRUE(bb->GetSuccessor(0)->GetLastInst()->IsIntrinsic());
511                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetSuccessor(0)->GetLastInst()))->GetIntrinsicId() ==
512                            RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
513
514                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
515                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
516                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
517                            RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
518                continue;
519            }
520        }
521    });
522}
523
524HWTEST_F(IrBuilderTest, nestedTryCatchAbc, testing::ext::TestSize.Level1)
525{
526    std::string pFile = GRAPH_TEST_ABC_DIR "nestedTryCatch.abc";
527    const char *testMethodName = "func_main_0";
528    TestBuildGraphFromFile(pFile, [testMethodName](Graph* graph, std::string &methodName) {
529        if (testMethodName != methodName) {
530            return;
531        }
532
533        EXPECT_NE(graph, nullptr);
534        int32_t numOfTry = 0;
535        for (auto bb : graph->GetBlocksRPO()) {
536            EXPECT_NE(bb, nullptr);
537            if (bb->IsTryBegin()) {
538                numOfTry++;
539
540                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
541
542                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
543
544                if (bb->GetTryId() == 0) {
545                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
546                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
547                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
548                    EXPECT_TRUE(bb->GetSuccessor(0)->GetTryId() == bb->GetTryId());
549                }
550
551                if (bb->GetTryId() == 1) {
552                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryBegin());
553                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
554                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
555                }
556
557                continue;
558            }
559
560            if (bb->IsTry()) {
561                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
562                if (bb->GetPredecessor(0)->IsTryBegin()) {
563                    EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
564                    EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == 0);
565                    EXPECT_TRUE(bb->GetPredecessor(0)->GetGuestPc() == bb->GetGuestPc());
566
567                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
568                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
569
570                    EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
571                    EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
572                    EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
573                                RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
574                    continue;
575                }
576
577                if (bb->GetPredecessor(0)->IsTryEnd()) {
578                    EXPECT_FALSE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
579                    EXPECT_TRUE(bb->GetPredecessor(0)->GetGuestPc() == bb->GetGuestPc());
580
581                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
582                    for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
583                        EXPECT_TRUE(inst->IsPhi());
584                    }
585                    continue;
586                }
587
588                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
589                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
590
591                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
592                EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
593
594                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
595                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
596                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
597                            RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
598                continue;
599            }
600
601            if (bb->IsTryEnd()) {
602                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
603                EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
604                EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
605
606                EXPECT_TRUE(bb->IsEmpty());
607
608                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
609                if (bb->GetTryId() == 0) {
610                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
611                    EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
612
613                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
614                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
615
616                    for (auto inst : bb->GetSuccessor(1)->AllInsts()) {
617                        EXPECT_TRUE(inst->IsCatchPhi());
618                    }
619                    continue;
620                }
621
622                EXPECT_TRUE(bb->GetTryId() == 1);
623                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
624                EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
625                for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
626                    EXPECT_TRUE(inst->IsPhi());
627                }
628                continue;
629            }
630
631            if (bb->IsCatchBegin()) {
632                EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
633                EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
634                EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
635
636                EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
637                continue;
638            }
639
640            if (bb->IsCatch() && !bb->IsCatchBegin()) {
641                EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
642
643                if (bb->IsTry()) {
644                    EXPECT_TRUE(bb->GetTryId() == 2);
645
646                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
647                    EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
648                    EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
649
650                    EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
651                    EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
652                    EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
653                                RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
654                    continue;
655                }
656
657                if (bb->IsTryEnd()) {
658                    EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
659                    EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
660
661                    EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
662                    for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
663                        EXPECT_TRUE(inst->IsPhi());
664                    }
665                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
666                    EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
667
668                    EXPECT_TRUE(bb->IsEmpty());
669                    continue;
670                }
671
672                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
673                EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
674
675                EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
676                auto *successor = bb->GetSuccessor(0);
677                EXPECT_TRUE(successor->GetFirstInst()->IsSaveState());
678                EXPECT_TRUE(successor->GetLastInst()->IsIntrinsic());
679                EXPECT_TRUE((static_cast<IntrinsicInst *>(successor->GetLastInst()))->GetIntrinsicId() ==
680                            RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
681                for (auto inst : successor->GetPredecessor(0)->AllInsts()) {
682                    EXPECT_TRUE(inst->IsPhi());
683                }
684
685                EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
686                EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
687                EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
688                            RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8);
689            }
690        }
691
692        EXPECT_EQ(numOfTry, 2);
693    });
694}
695} // namespace panda::compiler