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 "macros.h"
17#if defined(PANDA_TARGET_MOBILE)
18#elif defined(USE_STD_FILESYSTEM)
19#include <filesystem>
20#else
21#include <experimental/filesystem>
22#endif
23#include "optimizer/ir_builder/ir_builder.h"
24#include "optimizer/optimizations/cleanup.h"
25#include "optimizer/code_generator/encode.h"
26#include "include/class_linker.h"
27#include "assembly-parser.h"
28#include "include/runtime.h"
29#include "compiler.h"
30#include "utils/expected.h"
31#include "compiler_options.h"
32#include "unit_test.h"
33
34#include "utils/utf.h"
35
36namespace panda::compiler {
37void PandaRuntimeTest::Initialize([[maybe_unused]] int argc, char **argv)
38{
39    ASSERT(argc > 0);
40    exec_path_ = argv[0];
41}
42
43PandaRuntimeTest::PandaRuntimeTest()
44{
45    ASSERT(exec_path_ != nullptr);
46#if !defined(PANDA_TARGET_MOBILE)
47#if defined(USE_STD_FILESYSTEM)
48    std::filesystem::path exec_name(exec_path_);
49#else
50    std::experimental::filesystem::path exec_name(exec_path_);
51#endif  // defined(USE_STD_FILESYSTEM)
52    std::string pandastdlib_path = exec_name.parent_path() / "../pandastdlib/arkstdlib.abc";
53#else
54    std::string exec_name = "compiler_unit_tests";
55    std::string pandastdlib_path = "../pandastdlib/arkstdlib.abc";
56#endif
57    panda::RuntimeOptions runtime_options(exec_name);
58    runtime_options.SetBootPandaFiles({pandastdlib_path});
59    runtime_options.SetLoadRuntimes({"core"});
60    runtime_options.SetHeapSizeLimit(50_MB);
61    runtime_options.SetEnableAn(true);
62    runtime_options.SetGcType("epsilon");
63    Logger::InitializeDummyLogging();
64    EXPECT_TRUE(panda::Runtime::Create(runtime_options));
65
66    allocator_ = new ArenaAllocator(panda::SpaceType::SPACE_TYPE_INTERNAL);
67    local_allocator_ = new ArenaAllocator(panda::SpaceType::SPACE_TYPE_INTERNAL);
68    builder_ = new IrConstructor();
69
70    graph_ = CreateGraph();
71}
72
73PandaRuntimeTest::~PandaRuntimeTest()
74{
75    delete builder_;
76    delete allocator_;
77    delete local_allocator_;
78    panda::Runtime::Destroy();
79}
80
81RuntimeInterface *PandaRuntimeTest::GetDefaultRuntime()
82{
83    return Graph::GetDefaultRuntime();
84}
85
86std::unique_ptr<const panda_file::File> AsmTest::ParseToFile(const char *source, const char *file_name)
87{
88    panda::pandasm::Parser parser;
89    auto res = parser.Parse(source, file_name);
90    if (parser.ShowError().err != pandasm::Error::ErrorType::ERR_NONE) {
91        std::cerr << "Parse failed: " << parser.ShowError().message << std::endl
92                  << parser.ShowError().whole_line << std::endl;
93        ADD_FAILURE();
94        return nullptr;
95    }
96    return pandasm::AsmEmitter::Emit(res.Value());
97}
98
99bool AsmTest::Parse(const char *source, const char *file_name)
100{
101    auto pfile = ParseToFile(source, file_name);
102    if (pfile == nullptr) {
103        ADD_FAILURE();
104        return false;
105    }
106    GetClassLinker()->AddPandaFile(std::move(pfile));
107    return true;
108}
109
110Graph *AsmTest::BuildGraph(const char *method_name, Graph *graph)
111{
112    auto loader = GetClassLinker();
113    PandaString storage;
114    auto extension = loader->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
115    auto *thread = MTManagedThread::GetCurrent();
116    thread->ManagedCodeBegin();
117    auto klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &storage));
118    thread->ManagedCodeEnd();
119
120    auto method = klass->GetDirectMethod(utf::CStringAsMutf8(method_name));
121    if (method == nullptr) {
122        ADD_FAILURE();
123        return nullptr;
124    }
125    if (graph == nullptr) {
126        graph = CreateGraph();
127    }
128    graph->SetMethod(method);
129    if (!graph->RunPass<IrBuilder>()) {
130        ADD_FAILURE();
131        return nullptr;
132    }
133    return graph;
134}
135
136void AsmTest::CleanUp(Graph *graph)
137{
138    graph->RunPass<Cleanup>();
139}
140
141CommonTest::~CommonTest()
142{
143    // Look at examples in encoder_constructors tests.
144    // Used for destroy MasmHolder.
145    Encoder *encoder = Encoder::Create(allocator_, arch_, false);
146    if (encoder != nullptr) {
147        encoder->~Encoder();
148    }
149    delete builder_;
150    delete allocator_;
151    delete object_allocator_;
152    delete local_allocator_;
153    PoolManager::Finalize();
154
155    panda::mem::MemConfig::Finalize();
156}
157}  // namespace panda::compiler
158
159int main(int argc, char **argv)
160{
161    ::testing::InitGoogleTest(&argc, argv);
162
163    panda::compiler::PandaRuntimeTest::Initialize(argc, argv);
164    panda::compiler::options.SetCompilerUseSafepoint(false);
165    return RUN_ALL_TESTS();
166}
167