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