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 explicit StubPassData(Stub *stub, LLVMModule *module, CompilerLog *log)
37 : PassData(nullptr, nullptr, nullptr, log, "stubs"), module_(module), stub_(stub) {}
38 ~StubPassData() = default;
39
GetCompilationConfig() const40 const CompilationConfig *GetCompilationConfig() const
41 {
42 return module_->GetCompilationConfig();
43 }
44
GetCircuit() const45 Circuit *GetCircuit() const
46 {
47 return stub_->GetEnvironment()->GetCircuit();
48 }
49
GetStubModule() const50 LLVMModule *GetStubModule() const
51 {
52 return module_;
53 }
54
GetStub() const55 Stub *GetStub() const
56 {
57 return stub_;
58 }
59
60 private:
61 LLVMModule *module_;
62 Stub *stub_;
63 };
64
65 class StubBuildCircuitPass {
66 public:
Run(StubPassData * data)67 bool Run(StubPassData *data)
68 {
69 auto stub = data->GetStub();
70 LOG_COMPILER(INFO) << "Stub Name: " << stub->GetMethodName();
71 stub->GenerateCircuit(data->GetCompilationConfig());
72 return true;
73 }
74 };
75
76 class StubLLVMIRGenPass {
77 public:
CreateCodeGen(LLVMModule * module,bool enableLog)78 void CreateCodeGen(LLVMModule *module, bool enableLog)
79 {
80 llvmImpl_ = std::make_unique<LLVMIRGeneratorImpl>(module, enableLog);
81 }
82
Run(StubPassData * data,size_t index)83 bool Run(StubPassData *data, size_t index)
84 {
85 bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputCIR();
86 auto stubModule = data->GetStubModule();
87 CreateCodeGen(stubModule, enableLog);
88 CodeGenerator codegen(llvmImpl_, "stubs");
89 codegen.RunForStub(data->GetCircuit(), data->GetConstScheduleResult(), index, data->GetCompilationConfig());
90 return true;
91 }
92 private:
93 std::unique_ptr<CodeGeneratorImpl> llvmImpl_ {nullptr};
94 };
95
RunPipeline(LLVMModule * module) const96 void StubCompiler::RunPipeline(LLVMModule *module) const
97 {
98 auto callSigns = module->GetCSigns();
99 CompilerLog *log = GetLog();
100 auto logList = GetLogList();
101 auto cconfig = module->GetCompilationConfig();
102 NativeAreaAllocator allocator;
103
104 bool enableMethodLog = !log->NoneMethod();
105 for (size_t i = 0; i < callSigns.size(); i++) {
106 Circuit circuit(&allocator, cconfig->Is64Bit());
107 Stub stub(callSigns[i], &circuit);
108 ASSERT(callSigns[i]->HasConstructor());
109 void* env = reinterpret_cast<void*>(stub.GetEnvironment());
110 StubBuilder* stubBuilder = static_cast<StubBuilder*>(callSigns[i]->GetConstructor()(env));
111 stub.SetStubBuilder(stubBuilder);
112
113 if (log->CertainMethod()) {
114 enableMethodLog = logList->IncludesMethod(stub.GetMethodName());
115 }
116 log->SetEnableMethodLog(enableMethodLog);
117
118 StubPassData data(&stub, module, log);
119 PassRunner<StubPassData> pipeline(&data);
120 pipeline.RunPass<StubBuildCircuitPass>();
121 pipeline.RunPass<VerifierPass>();
122 pipeline.RunPass<SchedulingPass>();
123 pipeline.RunPass<StubLLVMIRGenPass>(i);
124 delete stubBuilder;
125 }
126 }
127
InitializeCS() const128 void StubCompiler::InitializeCS() const
129 {
130 BytecodeStubCSigns::Initialize();
131 CommonStubCSigns::Initialize();
132 BuiltinsStubCSigns::Initialize();
133 RuntimeStubCSigns::Initialize();
134 }
135
BuildStubModuleAndSave() const136 bool StubCompiler::BuildStubModuleAndSave() const
137 {
138 InitializeCS();
139 size_t res = 0;
140 CompilerLog *log = GetLog();
141 const MethodLogList *logList = GetLogList();
142 StubFileGenerator generator(log, logList, triple_, enablePGOProfiler_);
143 if (!filePath_.empty()) {
144 LOG_COMPILER(INFO) << "compiling bytecode handler stubs";
145 LLVMModule bcStubModule("bc_stub", triple_, enablePGOProfiler_);
146 LLVMAssembler bcStubAssembler(bcStubModule.GetModule(), LOptions(optLevel_, false, relocMode_));
147 bcStubModule.SetUpForBytecodeHandlerStubs();
148 RunPipeline(&bcStubModule);
149 generator.AddModule(&bcStubModule, &bcStubAssembler);
150 res++;
151
152 LOG_COMPILER(INFO) << "compiling common stubs";
153 LLVMModule comStubModule("com_stub", triple_, enablePGOProfiler_);
154 LLVMAssembler comStubAssembler(comStubModule.GetModule(), LOptions(optLevel_, true, relocMode_));
155 comStubModule.SetUpForCommonStubs();
156 RunPipeline(&comStubModule);
157 generator.AddModule(&comStubModule, &comStubAssembler);
158 res++;
159
160 LOG_COMPILER(INFO) << "compiling builtins stubs";
161 LLVMModule builtinsStubModule("builtins_stub", triple_, enablePGOProfiler_);
162 LLVMAssembler builtinsStubAssembler(builtinsStubModule.GetModule(), LOptions(optLevel_, true, relocMode_));
163 builtinsStubModule.SetUpForBuiltinsStubs();
164 RunPipeline(&builtinsStubModule);
165 generator.AddModule(&builtinsStubModule, &builtinsStubAssembler);
166 res++;
167 generator.SaveStubFile(filePath_);
168 }
169 return (res > 0);
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 enablePGOProfiler = runtimeOptions.IsEnablePGOProfiler();
197 panda::ecmascript::kungfu::CompilerLog logOpt(logOption);
198 panda::ecmascript::kungfu::MethodLogList logList(methodsList);
199 panda::ecmascript::kungfu::StubCompiler compiler(
200 triple, stubFile, optLevel, relocMode, &logOpt, &logList, enablePGOProfiler);
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