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