1/* 2 * Copyright (c) 2021-2024 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 "ecmascript/compiler/stub_compiler.h" 17 18#include "ecmascript/base/config.h" 19#include "ecmascript/base/string_helper.h" 20#include "ecmascript/compiler/codegen/llvm/llvm_codegen.h" 21#include "ecmascript/compiler/file_generators.h" 22#include "ecmascript/compiler/interpreter_stub-inl.h" 23#include "ecmascript/compiler/pass.h" 24#include "ecmascript/compiler/scheduler.h" 25#include "ecmascript/compiler/stub.h" 26#include "ecmascript/compiler/stub_builder-inl.h" 27#include "ecmascript/compiler/verifier.h" 28#include "ecmascript/js_runtime_options.h" 29#include "ecmascript/log.h" 30#include "ecmascript/napi/include/jsnapi.h" 31#include "ecmascript/compiler/baseline/baseline_stub_csigns.h" 32 33namespace panda::ecmascript::kungfu { 34class StubPassData : public PassData { 35public: 36 StubPassData(Stub *stub, LLVMModule *module, CompilerLog *log) 37 : PassData(nullptr, nullptr, nullptr, log, "stubs"), 38 cfg_(module->GetTripleStr()), 39 module_(module), 40 stub_(stub) {} 41 ~StubPassData() = default; 42 43 const CompilationConfig *GetCompilationConfig() const 44 { 45 return &cfg_; 46 } 47 48 Circuit *GetCircuit() const 49 { 50 return stub_->GetCircuit(); 51 } 52 53 LLVMModule *GetStubModule() const 54 { 55 return module_; 56 } 57 58 Stub *GetStub() const 59 { 60 return stub_; 61 } 62 63private: 64 CompilationConfig cfg_; 65 LLVMModule *module_; 66 Stub *stub_; 67}; 68 69class StubBuildCircuitPass { 70public: 71 bool Run(StubPassData *data) 72 { 73 auto stub = data->GetStub(); 74 LOG_COMPILER(INFO) << "Stub Name: " << stub->GetMethodName(); 75 stub->GenerateCircuit(data->GetCompilationConfig()); 76 return true; 77 } 78}; 79 80class StubLLVMIRGenPass { 81public: 82 void CreateCodeGen(LLVMModule *module, bool enableLog) 83 { 84 llvmImpl_ = std::make_unique<LLVMIRGeneratorImpl>(module, enableLog); 85 } 86 87 bool Run(StubPassData *data, size_t index) 88 { 89 bool enableLog = data->GetLog()->EnableMethodCIRLog() || data->GetLog()->OutputASM(); 90 auto stubModule = data->GetStubModule(); 91 CreateCodeGen(stubModule, enableLog); 92 CodeGenerator codegen(llvmImpl_, "stubs"); 93 codegen.RunForStub(data->GetCircuit(), data->GetConstScheduleResult(), index, data->GetCompilationConfig()); 94 return true; 95 } 96private: 97 std::unique_ptr<CodeGeneratorImpl> llvmImpl_ {nullptr}; 98}; 99 100void StubCompiler::RunPipeline(LLVMModule *module, NativeAreaAllocator *allocator) const 101{ 102 auto callSigns = module->GetCSigns(); 103 CompilerLog *log = GetLog(); 104 for (size_t i = 0; i < callSigns.size(); i++) { 105 auto &cs = callSigns[i]; 106 Circuit circuit(allocator, module->GetDebugInfo(), cs->GetName().c_str(), module->Is64Bit()); 107 Stub stub(cs, &circuit); 108 log->SetStubLog(stub.GetMethodName(), GetLogList()); 109 110 StubPassData data(&stub, module, log); 111 PassRunner<StubPassData> pipeline(&data); 112 pipeline.RunPass<StubBuildCircuitPass>(); 113 pipeline.RunPass<VerifierPass>(); 114 pipeline.RunPass<SchedulingPass>(); 115 pipeline.RunPass<StubLLVMIRGenPass>(i); 116 } 117} 118 119void StubCompiler::InitializeCS() const 120{ 121 BytecodeStubCSigns::Initialize(); 122 CommonStubCSigns::Initialize(); 123 BaselineStubCSigns::Initialize(); 124 BuiltinsStubCSigns::Initialize(); 125 RuntimeStubCSigns::Initialize(); 126} 127 128bool StubCompiler::BuildStubModuleAndSave() const 129{ 130 if (filePath_.empty()) { 131 return false; 132 } 133 134 InitializeCS(); 135 CompilerLog *log = GetLog(); 136 MethodLogList *logList = GetLogList(); 137 138 NativeAreaAllocator allocator; 139 StubFileGenerator generator(log, logList, triple_, concurrentCompile_); 140 141 LOG_COMPILER(INFO) << "=============== compiling bytecode handler stubs ==============="; 142 LOptions stubOp(optLevel_, FPFlag::ELIM_FP, relocMode_); 143 Module* stubM = generator.AddModule(&allocator, "bc_stub", triple_, stubOp, log->OutputASM(), StubFileKind::BC); 144 if (!stubM->IsLLVM()) { 145 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ==============="; 146 return false; 147 } 148 RunPipeline(static_cast<LLVMModule*>(stubM->GetModule()), &allocator); 149 150 LOG_COMPILER(INFO) << "=============== compiling common stubs ==============="; 151 LOptions comOp(optLevel_, FPFlag::RESERVE_FP, relocMode_); 152 Module* comM = generator.AddModule(&allocator, "com_stub", triple_, comOp, log->OutputASM(), StubFileKind::COM); 153 if (!comM->IsLLVM()) { 154 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ==============="; 155 return false; 156 } 157 RunPipeline(static_cast<LLVMModule*>(comM->GetModule()), &allocator); 158 159 LOG_COMPILER(INFO) << "=============== compiling builtins stubs ==============="; 160 LOptions builtinOp(optLevel_, FPFlag::RESERVE_FP, relocMode_); 161 Module* builtinM = generator.AddModule(&allocator, "builtin_stub", triple_, builtinOp, log->OutputASM(), 162 StubFileKind::BUILTIN); 163 if (!builtinM->IsLLVM()) { 164 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ==============="; 165 return false; 166 } 167 RunPipeline(static_cast<LLVMModule*>(builtinM->GetModule()), &allocator); 168 169 LOG_COMPILER(INFO) << "=============== compiling baseline stubs ==============="; 170 LOptions baselineOp(optLevel_, FPFlag::RESERVE_FP, relocMode_); 171 Module* baselineM = generator.AddModule(&allocator, "baseline_stub", triple_, baselineOp, log->OutputASM(), 172 StubFileKind::BASELINE); 173 if (!baselineM->IsLLVM()) { 174 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ==============="; 175 return false; 176 } 177 RunPipeline(static_cast<LLVMModule*>(baselineM->GetModule()), &allocator); 178 179 generator.SaveStubFile(filePath_); 180 return true; 181} 182 183std::string GetHelper() 184{ 185 std::string str; 186 str.append(STUB_HELP_HEAD_MSG); 187 str.append(HELP_OPTION_MSG); 188 return str; 189} 190} // namespace panda::ecmascript::kungfu 191 192int main(const int argc, const char **argv) 193{ 194 panda::ecmascript::JSRuntimeOptions runtimeOptions; 195 bool ret = runtimeOptions.ParseCommand(argc, argv); 196 if (!ret) { 197 std::cerr << panda::ecmascript::kungfu::GetHelper(); 198 return 1; 199 } 200 201 panda::ecmascript::Log::Initialize(runtimeOptions); 202 std::string triple = runtimeOptions.GetTargetTriple(); 203 std::string stubFile = runtimeOptions.GetStubFile(); 204 size_t optLevel = runtimeOptions.GetOptLevel(); 205 size_t relocMode = runtimeOptions.GetRelocMode(); 206 std::string logOption = runtimeOptions.GetCompilerLogOption(); 207 std::string methodsList = runtimeOptions.GetMethodsListForLog(); 208 bool concurrentCompile = runtimeOptions.IsConcurrentCompile(); 209 210 panda::ecmascript::kungfu::CompilerLog logOpt(logOption); 211 panda::ecmascript::kungfu::MethodLogList logList(methodsList); 212 panda::ecmascript::kungfu::StubCompiler compiler(triple, stubFile, optLevel, relocMode, &logOpt, &logList, 213 concurrentCompile); 214 215 bool res = compiler.BuildStubModuleAndSave(); 216 LOG_COMPILER(INFO) << "stub compiler run finish, result condition(T/F):" << std::boolalpha << res; 217 return res ? 0 : -1; 218} 219