• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef COMPILER_TESTS_PANDA_RUNNER_H
17 #define COMPILER_TESTS_PANDA_RUNNER_H
18 
19 #include "unit_test.h"
20 #include "assembler/assembly-emitter.h"
21 #include "assembler/assembly-parser.h"
22 #include "include/runtime.h"
23 
24 namespace panda::test {
25 class PandaRunner {
26 public:
27     using Callback = int (*)(uintptr_t, uintptr_t);
28 
PandaRunner()29     PandaRunner()
30     {
31         auto exec_path = panda::os::file::File::GetExecutablePath();
32 
33         std::vector<std::string> boot_panda_files = {exec_path.Value() + "/../pandastdlib/arkstdlib.abc"};
34 
35         options_.SetBootPandaFiles(boot_panda_files);
36 
37         options_.SetShouldLoadBootPandaFiles(true);
38         options_.SetShouldInitializeIntrinsics(false);
39         options_.SetNoAsyncJit(true);
40     }
41 
Parse(std::string_view source)42     void Parse(std::string_view source)
43     {
44         pandasm::Parser parser;
45 
46         auto res = parser.Parse(source.data());
47         ASSERT_TRUE(res) << "Parse failed: " << res.Error().message << "\nLine " << res.Error().line_number << ": "
48                          << res.Error().whole_line;
49         file_ = pandasm::AsmEmitter::Emit(res.Value());
50     }
51 
52     ~PandaRunner() = default;
53 
SetHook(Callback hook)54     void SetHook(Callback hook)
55     {
56         callback_ = hook;
57     }
58 
Run(std::string_view source)59     void Run(std::string_view source)
60     {
61         return Run(source, std::vector<std::string> {});
62     }
63 
Run(std::string_view source,Callback hook)64     void Run(std::string_view source, Callback hook)
65     {
66         callback_ = hook;
67         return Run(source, ssize_t(0));
68     }
69 
Run(std::string_view source,ssize_t expected_result)70     void Run(std::string_view source, ssize_t expected_result)
71     {
72         expected_result_ = expected_result;
73         return Run(source, std::vector<std::string> {});
74     }
75 
Run(std::string_view source,const std::vector<std::string> & args)76     void Run(std::string_view source, const std::vector<std::string> &args)
77     {
78         auto finalizer = [](void *) {
79             callback_ = nullptr;
80             Runtime::Destroy();
81         };
82         std::unique_ptr<void, decltype(finalizer)> runtime_destroyer(&finalizer, finalizer);
83 
84         compiler::CompilerLogger::SetComponents(GetCompilerOptions().GetCompilerLog());
85 
86         Run(CreateRuntime(), source, args);
87     }
88 
Run(Runtime * runtime,std::string_view source,const std::vector<std::string> & args)89     void Run(Runtime *runtime, std::string_view source, const std::vector<std::string> &args)
90     {
91         pandasm::Parser parser;
92         auto res = parser.Parse(source.data());
93         ASSERT_TRUE(res) << "Parse failed: " << res.Error().message << "\nLine " << res.Error().line_number << ": "
94                          << res.Error().whole_line;
95         auto pf = pandasm::AsmEmitter::Emit(res.Value());
96         runtime->GetClassLinker()->AddPandaFile(std::move(pf));
97 
98         if (callback_) {
99             if (auto method = GetMethod("hook"); method != nullptr) {
100                 method->SetCompiledEntryPoint(reinterpret_cast<void *>(Hook));
101             }
102         }
103 
104         auto eres = runtime->Execute("_GLOBAL::main", args);
105         ASSERT_TRUE(eres) << static_cast<unsigned>(eres.Error());
106         if (expected_result_) {
107             ASSERT_EQ(eres.Value(), expected_result_.value());
108         }
109     }
110 
CreateRuntime()111     Runtime *CreateRuntime()
112     {
113         Runtime::Create(options_);
114         return Runtime::GetCurrent();
115     }
116 
GetRuntimeOptions()117     RuntimeOptions &GetRuntimeOptions()
118     {
119         return options_;
120     }
121 
GetCompilerOptions()122     compiler::CompilerOptions &GetCompilerOptions()
123     {
124         return compiler::options;
125     }
126 
GetMethod(std::string_view method_name)127     static Method *GetMethod(std::string_view method_name)
128     {
129         PandaString descriptor;
130         auto *thread = MTManagedThread::GetCurrent();
131         thread->ManagedCodeBegin();
132         auto cls = Runtime::GetCurrent()
133                        ->GetClassLinker()
134                        ->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY)
135                        ->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
136         thread->ManagedCodeEnd();
137         ASSERT(cls);
138         return cls->GetDirectMethod(utf::CStringAsMutf8(method_name.data()));
139     }
140 
141 private:
Hook()142     NO_OPTIMIZE static int Hook()
143     {
144         ASSERT(callback_);
145         if constexpr (RUNTIME_ARCH == Arch::AARCH64) {
146             uintptr_t fp;
147             uintptr_t lr;
148             ManagedThread::GetCurrent()->SetCurrentFrameIsCompiled(true);
149             asm("ldr %0, [fp, #0]" : "=r"(fp));
150             asm("ldr %0, [fp, #8]" : "=r"(lr));
151             ManagedThread::GetCurrent()->SetCurrentFrame(reinterpret_cast<Frame *>(fp));
152             return callback_(lr, fp);
153         } else if constexpr (RUNTIME_ARCH == Arch::AARCH32) {
154             uintptr_t fp;
155             uintptr_t lr;
156             ManagedThread::GetCurrent()->SetCurrentFrameIsCompiled(true);
157 #if (defined(__clang__) || defined(PANDA_TARGET_ARM64))
158             asm("ldr %0, [fp, #0]" : "=r"(fp));
159             asm("ldr %0, [fp, #4]" : "=r"(lr));
160 #else
161             // gcc compile header "push {r4, r11, lr}"
162             asm("ldr %0, [fp, #-4]" : "=r"(fp));
163             asm("ldr %0, [fp, #0]" : "=r"(lr));
164 #endif
165             ManagedThread::GetCurrent()->SetCurrentFrame(reinterpret_cast<Frame *>(fp));
166             return callback_(lr, fp);
167         } else if constexpr (RUNTIME_ARCH == Arch::X86_64) {
168             uintptr_t fp;
169             uintptr_t lr;
170             ManagedThread::GetCurrent()->SetCurrentFrameIsCompiled(true);
171             asm("movq (%%rbp), %0" : "=r"(fp));
172             asm("movq 8(%%rbp), %0" : "=r"(lr));
173             ManagedThread::GetCurrent()->SetCurrentFrame(reinterpret_cast<Frame *>(fp));
174             return callback_(lr, fp);
175         } else {
176             return -1;
177         }
178     }
179 
180 private:
181     RuntimeOptions options_;
182     static inline Callback callback_ {nullptr};
183     std::unique_ptr<const panda_file::File> file_ {nullptr};
184     std::optional<ssize_t> expected_result_;
185 };
186 }  // namespace panda::test
187 
188 #endif  // COMPILER_TESTS_PANDA_RUNNER_H
189