1 /*
2 * Copyright (c) 2021 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/common_stubs.h"
21 #include "ecmascript/compiler/file_generators.h"
22 #include "ecmascript/compiler/interpreter_stub-inl.h"
23 #include "ecmascript/compiler/llvm_codegen.h"
24 #include "ecmascript/compiler/pass.h"
25 #include "ecmascript/compiler/scheduler.h"
26 #include "ecmascript/compiler/stub.h"
27 #include "ecmascript/compiler/stub_builder-inl.h"
28 #include "ecmascript/compiler/verifier.h"
29 #include "ecmascript/js_runtime_options.h"
30 #include "ecmascript/log.h"
31 #include "ecmascript/napi/include/jsnapi.h"
32
33 namespace panda::ecmascript::kungfu {
34 class StubPassData : public PassData {
35 public:
StubPassData(Stub * stub,LLVMModule * module,CompilerLog * log)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
GetCompilationConfig() const43 const CompilationConfig *GetCompilationConfig() const
44 {
45 return &cfg_;
46 }
47
GetCircuit() const48 Circuit *GetCircuit() const
49 {
50 return stub_->GetCircuit();
51 }
52
GetStubModule() const53 LLVMModule *GetStubModule() const
54 {
55 return module_;
56 }
57
GetStub() const58 Stub *GetStub() const
59 {
60 return stub_;
61 }
62
63 private:
64 CompilationConfig cfg_;
65 LLVMModule *module_;
66 Stub *stub_;
67 };
68
69 class StubBuildCircuitPass {
70 public:
Run(StubPassData * data)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
80 class StubLLVMIRGenPass {
81 public:
CreateCodeGen(LLVMModule * module,bool enableLog)82 void CreateCodeGen(LLVMModule *module, bool enableLog)
83 {
84 llvmImpl_ = std::make_unique<LLVMIRGeneratorImpl>(module, enableLog);
85 }
86
Run(StubPassData * data,size_t index)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 }
96 private:
97 std::unique_ptr<CodeGeneratorImpl> llvmImpl_ {nullptr};
98 };
99
RunPipeline(LLVMModule * module,NativeAreaAllocator * allocator) const100 void 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
InitializeCS() const119 void StubCompiler::InitializeCS() const
120 {
121 BytecodeStubCSigns::Initialize();
122 CommonStubCSigns::Initialize();
123 BuiltinsStubCSigns::Initialize();
124 RuntimeStubCSigns::Initialize();
125 }
126
BuildStubModuleAndSave() const127 bool StubCompiler::BuildStubModuleAndSave() const
128 {
129 if (filePath_.empty()) {
130 return false;
131 }
132
133 InitializeCS();
134 CompilerLog *log = GetLog();
135 MethodLogList *logList = GetLogList();
136
137 NativeAreaAllocator allocator;
138 StubFileGenerator generator(log, logList, triple_);
139
140 LOG_COMPILER(INFO) << "=============== compiling bytecode handler stubs ===============";
141 LOptions stubOp(optLevel_, FPFlag::ELIM_FP, relocMode_);
142 Module* stubM = generator.AddModule(&allocator, "bc_stub", triple_, stubOp, log->OutputASM(), StubFileKind::BC);
143 if (!stubM->IsLLVM()) {
144 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ===============";
145 return false;
146 }
147 RunPipeline(static_cast<LLVMModule*>(stubM->GetModule()), &allocator);
148
149 LOG_COMPILER(INFO) << "=============== compiling common stubs ===============";
150 LOptions comOp(optLevel_, FPFlag::RESERVE_FP, relocMode_);
151 Module* comM = generator.AddModule(&allocator, "com_stub", triple_, comOp, log->OutputASM(), StubFileKind::COM);
152 if (!comM->IsLLVM()) {
153 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ===============";
154 return false;
155 }
156 RunPipeline(static_cast<LLVMModule*>(comM->GetModule()), &allocator);
157
158 LOG_COMPILER(INFO) << "=============== compiling builtins stubs ===============";
159 LOptions builtinOp(optLevel_, FPFlag::RESERVE_FP, relocMode_);
160 Module* builtinM = generator.AddModule(&allocator, "builtin_stub", triple_, builtinOp, log->OutputASM(),
161 StubFileKind::BUILTIN);
162 if (!builtinM->IsLLVM()) {
163 LOG_COMPILER(FATAL) << " Stub compiler is not supported for litecg ===============";
164 return false;
165 }
166 RunPipeline(static_cast<LLVMModule*>(builtinM->GetModule()), &allocator);
167
168 generator.SaveStubFile(filePath_);
169 return true;
170 }
171
GetHelper()172 std::string GetHelper()
173 {
174 std::string str;
175 str.append(STUB_HELP_HEAD_MSG);
176 str.append(HELP_OPTION_MSG);
177 return str;
178 }
179 } // namespace panda::ecmascript::kungfu
180
main(const int argc,const char ** argv)181 int main(const int argc, const char **argv)
182 {
183 panda::ecmascript::JSRuntimeOptions runtimeOptions;
184 bool ret = runtimeOptions.ParseCommand(argc, argv);
185 if (!ret) {
186 std::cerr << panda::ecmascript::kungfu::GetHelper();
187 return 1;
188 }
189
190 panda::ecmascript::Log::Initialize(runtimeOptions);
191 std::string triple = runtimeOptions.GetTargetTriple();
192 std::string stubFile = runtimeOptions.GetStubFile();
193 size_t optLevel = runtimeOptions.GetOptLevel();
194 size_t relocMode = runtimeOptions.GetRelocMode();
195 std::string logOption = runtimeOptions.GetCompilerLogOption();
196 std::string methodsList = runtimeOptions.GetMethodsListForLog();
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
202 bool res = compiler.BuildStubModuleAndSave();
203 LOG_COMPILER(INFO) << "stub compiler run finish, result condition(T/F):" << std::boolalpha << res;
204 return res ? 0 : -1;
205 }
206