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#ifndef GRAPH_TEST_H
17#define GRAPH_TEST_H
18
19#include "bytecode_optimizer/ir_interface.h"
20#include "bytecode_optimizer/runtime_adapter.h"
21#include "libpandafile/class_data_accessor.h"
22#include "libpandafile/class_data_accessor-inl.h"
23#include "libpandafile/code_data_accessor-inl.h"
24#include "libpandafile/file.h"
25#include "libpandafile/method_data_accessor.h"
26#include "libpandabase/mem/arena_allocator.h"
27#include "libpandabase/mem/pool_manager.h"
28#include "optimizer/ir/graph.h"
29#include "optimizer/ir/runtime_interface.h"
30#include "optimizer/ir_builder/ir_builder.h"
31
32namespace panda::compiler {
33class GraphTest {
34public:
35    GraphTest()
36    {
37        PoolManager::Initialize(PoolType::MALLOC);
38    }
39
40    ~GraphTest()
41    {
42        PoolManager::Finalize();
43    }
44
45    static bool HasTryCatch(const panda_file::File &panda_file, panda_file::File::EntityId code_id)
46    {
47        panda_file::CodeDataAccessor cda(panda_file, code_id);
48        return cda.GetTriesSize() != 0;
49    }
50
51    template <class Callback>
52    void TestBuildGraphFromFile(const std::string &pfile_name, const Callback &cb, bool skip_try_catch = false)
53    {
54        auto pfile = panda_file::OpenPandaFile(pfile_name);
55        for (uint32_t id : pfile->GetClasses()) {
56            panda_file::File::EntityId record_id {id};
57            if (pfile->IsExternal(record_id)) {
58                continue;
59            }
60
61            panda_file::ClassDataAccessor cda {*pfile, record_id};
62            cda.EnumerateMethods([&pfile, &cb, &skip_try_catch](panda_file::MethodDataAccessor &mda) {
63                if (mda.IsExternal()) {
64                    return;
65                }
66
67                // `skip_try_catch` is required for tests like draw_cfg_test. Currently try-catch optimizations
68                // are disabled, and building graphs directly from abc files containing try-catch blocks may fail.
69                if (skip_try_catch && HasTryCatch(*pfile, mda.GetCodeId().value())) {
70                    return;
71                }
72
73                ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
74                ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
75
76                auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
77                    mda.GetMethodId().GetOffset());
78                panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
79                auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
80                                                    false, nullptr, true, true);
81                graph->RunPass<panda::compiler::IrBuilder>();
82
83                auto method_name = std::string(utf::Mutf8AsCString(pfile->GetStringData(mda.GetNameId()).data));
84                auto pos = method_name.find_last_of("#");
85                if (pos != std::string::npos) {
86                    method_name = method_name.substr(pos + 1);
87                }
88                cb(graph, method_name);
89            });
90        }
91    }
92};
93
94} // namespace panda::compiler
95
96#endif  // GRAPH_TEST_H