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 #include "ecmascript/compiler/pass_manager.h"
16 #include "ecmascript/compiler/bytecodes.h"
17 #include "ecmascript/compiler/compilation_driver.h"
18 #include "ecmascript/compiler/pass.h"
19 #include "ecmascript/ecma_handle_scope.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/jspandafile/panda_file_translator.h"
22 #include "ecmascript/log.h"
23 #include "ecmascript/log_wrapper.h"
24 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
25 #include "ecmascript/ts_types/ts_manager.h"
26
27 namespace panda::ecmascript::kungfu {
28 using PGOProfilerManager = pgo::PGOProfilerManager;
Compile(JSHandle<JSFunction> & jsFunction,AOTFileGenerator & gen)29 bool JitPassManager::Compile(JSHandle<JSFunction> &jsFunction, AOTFileGenerator &gen)
30 {
31 [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
32 const JSPandaFile *jsPandaFile = Method::Cast(jsFunction->GetMethod().GetTaggedObject())->GetJSPandaFile();
33
34 collector_ = new BytecodeInfoCollector(vm_, const_cast<JSPandaFile*>(jsPandaFile),
35 jsFunction, profilerDecoder_, passOptions_->EnableCollectLiteralInfo());
36 std::string fileName = jsPandaFile->GetFileName();
37 if (!IsReleasedPandaFile(jsPandaFile)) {
38 LOG_COMPILER(ERROR) << "The input panda file [" << fileName << "] is debuggable version.";
39 }
40
41 gen.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc());
42 lOptions_ = new LOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
43 cmpDriver_ = new JitCompilationDriver(profilerDecoder_,
44 collector_,
45 vm_->GetJSOptions().GetCompilerSelectMethods(),
46 vm_->GetJSOptions().GetCompilerSkipMethods(),
47 &gen,
48 fileName,
49 triple_,
50 lOptions_,
51 log_,
52 log_->OutputASM(),
53 maxMethodsInModule_);
54 cmpDriver_->CompileMethod(jsFunction, [this, &fileName] (const CString recordName,
55 const std::string &methodName,
56 MethodLiteral *methodLiteral,
57 uint32_t methodOffset,
58 const MethodPcInfo &methodPCInfo,
59 MethodInfo &methodInfo,
60 Module *m) {
61 if (vm_->GetJSOptions().GetTraceJIT()) {
62 LOG_COMPILER(INFO) << "JIT Compile Method Start: " << methodName << ", " << methodOffset << "\n";
63 }
64 ctx_ = new PassContext(triple_, log_, collector_, m->GetModule(), &profilerDecoder_);
65
66 auto jsPandaFile = ctx_->GetJSPandaFile();
67 auto cmpCfg = ctx_->GetCompilerConfig();
68 auto tsManager = ctx_->GetTSManager();
69 auto module = m->GetModule();
70 // note: TSManager need to set current constantpool before all pass
71 tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
72 log_->SetMethodLog(fileName, methodName, logList_);
73
74 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
75 bool enableMethodLog = log_->GetEnableMethodLog();
76 if (enableMethodLog) {
77 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
78 << "] recordName [" << recordName << "] log:" << "\033[0m";
79 }
80 bool hasTypes = jsPandaFile->HasTSTypes(recordName);
81 if (UNLIKELY(!hasTypes)) {
82 LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
83 }
84
85 circuit_ = new Circuit(vm_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(),
86 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
87 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr;
88
89 builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo, tsManager,
90 circuit_, ctx_->GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
91 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false,
92 passOptions_->EnableOptTrackField());
93 {
94 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
95 builder_->BytecodeToCircuit();
96 }
97
98 data_ = new PassData(builder_, circuit_, ctx_, log_, fullName, &methodInfo, hasTypes, recordName,
99 methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_);
100 PassRunner<PassData> pipeline(data_);
101 if (data_->GetMethodLiteral()->HasDebuggerStmt()) {
102 data_->AbortCompilation();
103 return;
104 }
105 pipeline.RunPass<RunFlowCyclesVerifierPass>();
106 pipeline.RunPass<RedundantPhiEliminationPass>();
107 if (builder_->EnableLoopOptimization()) {
108 pipeline.RunPass<LoopOptimizationPass>();
109 pipeline.RunPass<RedundantPhiEliminationPass>();
110 }
111 pipeline.RunPass<TypeInferPass>();
112 if (data_->IsTypeAbort()) {
113 data_->AbortCompilation();
114 return;
115 }
116 pipeline.RunPass<PGOTypeInferPass>();
117 pipeline.RunPass<TSClassAnalysisPass>();
118 pipeline.RunPass<TSInlineLoweringPass>();
119 pipeline.RunPass<RedundantPhiEliminationPass>();
120 pipeline.RunPass<AsyncFunctionLoweringPass>();
121 pipeline.RunPass<TypeBytecodeLoweringPass>();
122 pipeline.RunPass<RedundantPhiEliminationPass>();
123 pipeline.RunPass<NTypeBytecodeLoweringPass>();
124 if (data_->IsTypeAbort()) {
125 data_->AbortCompilation();
126 return;
127 }
128 pipeline.RunPass<EarlyEliminationPass>();
129 pipeline.RunPass<NumberSpeculativePass>();
130 pipeline.RunPass<LaterEliminationPass>();
131 pipeline.RunPass<ValueNumberingPass>();
132 pipeline.RunPass<StateSplitLinearizerPass>();
133 pipeline.RunPass<StringOptimizationPass>();
134 pipeline.RunPass<NTypeHCRLoweringPass>();
135 pipeline.RunPass<TypeHCRLoweringPass>();
136 pipeline.RunPass<LaterEliminationPass>();
137 pipeline.RunPass<EarlyEliminationPass>();
138 pipeline.RunPass<LCRLoweringPass>();
139 pipeline.RunPass<ConstantFoldingPass>();
140 pipeline.RunPass<ValueNumberingPass>();
141 pipeline.RunPass<SlowPathLoweringPass>();
142 pipeline.RunPass<ValueNumberingPass>();
143 pipeline.RunPass<InstructionCombinePass>();
144 pipeline.RunPass<EarlyEliminationPass>();
145 pipeline.RunPass<VerifierPass>();
146 pipeline.RunPass<GraphLinearizerPass>();
147 });
148 return true;
149 }
150
RunCg()151 bool JitPassManager::RunCg()
152 {
153 PassRunner<PassData> pipeline(data_);
154 pipeline.RunPass<CGIRGenPass>();
155 return cmpDriver_->RunCg();
156 }
157
~JitPassManager()158 JitPassManager::~JitPassManager()
159 {
160 if (collector_ != nullptr) {
161 delete collector_;
162 collector_ = nullptr;
163 }
164 if (lOptions_ != nullptr) {
165 delete lOptions_;
166 lOptions_ = nullptr;
167 }
168 if (cmpDriver_ != nullptr) {
169 delete cmpDriver_;
170 cmpDriver_ = nullptr;
171 }
172 if (ctx_ != nullptr) {
173 delete ctx_;
174 ctx_ = nullptr;
175 }
176 if (circuit_ != nullptr) {
177 delete circuit_;
178 circuit_ = nullptr;
179 }
180 if (builder_ != nullptr) {
181 delete builder_;
182 builder_ = nullptr;
183 }
184 if (data_ != nullptr) {
185 delete data_;
186 data_ = nullptr;
187 }
188 }
189
Compile(JSPandaFile * jsPandaFile,const std::string & fileName,AOTFileGenerator & gen)190 bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, AOTFileGenerator &gen)
191 {
192 [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
193
194 BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_,
195 maxAotMethodSize_, passOptions_->EnableCollectLiteralInfo());
196 // Checking released/debuggable pandafile uses method literals, which are initialized in BytecodeInfoCollector,
197 // should after it.
198 if (!IsReleasedPandaFile(jsPandaFile)) {
199 LOG_COMPILER(ERROR) << "The input panda file [" << fileName
200 << "] of AOT Compiler is debuggable version, do not use for performance test!";
201 }
202
203 LOptions lOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
204 CompilationDriver cmpDriver(profilerDecoder_,
205 &collector,
206 vm_->GetJSOptions().GetCompilerSelectMethods(),
207 vm_->GetJSOptions().GetCompilerSkipMethods(),
208 &gen,
209 fileName,
210 triple_,
211 &lOptions,
212 log_,
213 log_->OutputASM(),
214 maxMethodsInModule_);
215
216 cmpDriver.Run([this, &fileName, &collector](const CString recordName,
217 const std::string &methodName,
218 MethodLiteral *methodLiteral,
219 uint32_t methodOffset,
220 const MethodPcInfo &methodPCInfo,
221 MethodInfo &methodInfo,
222 Module *m) {
223 PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_);
224 auto jsPandaFile = ctx.GetJSPandaFile();
225 auto cmpCfg = ctx.GetCompilerConfig();
226 auto tsManager = ctx.GetTSManager();
227 auto module = m->GetModule();
228 // note: TSManager need to set current constantpool before all pass
229 tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
230 log_->SetMethodLog(fileName, methodName, logList_);
231
232 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
233 bool enableMethodLog = log_->GetEnableMethodLog();
234 if (enableMethodLog) {
235 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
236 << "] recordName [" << recordName << "] log:" << "\033[0m";
237 }
238 bool hasTypes = jsPandaFile->HasTSTypes(recordName);
239 if (UNLIKELY(!hasTypes)) {
240 LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
241 }
242
243 Circuit circuit(vm_->GetNativeAreaAllocator(), ctx.GetAOTModule()->GetDebugInfo(),
244 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
245
246 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr;
247
248 BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, &circuit,
249 ctx.GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
250 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false,
251 passOptions_->EnableOptTrackField());
252 {
253 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
254 builder.BytecodeToCircuit();
255 }
256
257 PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, hasTypes, recordName,
258 methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_);
259 PassRunner<PassData> pipeline(&data);
260 if (data.GetMethodLiteral()->HasDebuggerStmt()) {
261 data.AbortCompilation();
262 return;
263 }
264 pipeline.RunPass<RunFlowCyclesVerifierPass>();
265 pipeline.RunPass<RedundantPhiEliminationPass>();
266 if (builder.EnableLoopOptimization()) {
267 pipeline.RunPass<LoopOptimizationPass>();
268 pipeline.RunPass<RedundantPhiEliminationPass>();
269 }
270 pipeline.RunPass<TypeInferPass>();
271 if (data.IsTypeAbort()) {
272 data.AbortCompilation();
273 return;
274 }
275 pipeline.RunPass<PGOTypeInferPass>();
276 pipeline.RunPass<TSClassAnalysisPass>();
277 pipeline.RunPass<TSInlineLoweringPass>();
278 pipeline.RunPass<RedundantPhiEliminationPass>();
279 pipeline.RunPass<AsyncFunctionLoweringPass>();
280 // skip async function, because some application run with errors.
281 if (methodInfo.IsTypeInferAbort()) {
282 data.AbortCompilation();
283 return;
284 }
285 pipeline.RunPass<TypeBytecodeLoweringPass>();
286 pipeline.RunPass<RedundantPhiEliminationPass>();
287 pipeline.RunPass<NTypeBytecodeLoweringPass>();
288 if (data.IsTypeAbort()) {
289 data.AbortCompilation();
290 return;
291 }
292 pipeline.RunPass<EarlyEliminationPass>();
293 pipeline.RunPass<NumberSpeculativePass>();
294 pipeline.RunPass<LaterEliminationPass>();
295 pipeline.RunPass<ValueNumberingPass>();
296 pipeline.RunPass<StateSplitLinearizerPass>();
297 pipeline.RunPass<StringOptimizationPass>();
298 pipeline.RunPass<NTypeHCRLoweringPass>();
299 pipeline.RunPass<TypeHCRLoweringPass>();
300 pipeline.RunPass<LaterEliminationPass>();
301 pipeline.RunPass<EarlyEliminationPass>();
302 pipeline.RunPass<LCRLoweringPass>();
303 pipeline.RunPass<ConstantFoldingPass>();
304 pipeline.RunPass<ValueNumberingPass>();
305 pipeline.RunPass<SlowPathLoweringPass>();
306 pipeline.RunPass<ValueNumberingPass>();
307 pipeline.RunPass<InstructionCombinePass>();
308 pipeline.RunPass<EarlyEliminationPass>();
309 pipeline.RunPass<VerifierPass>();
310 pipeline.RunPass<GraphLinearizerPass>();
311 pipeline.RunPass<CGIRGenPass>();
312 });
313
314 LOG_COMPILER(INFO) << collector.GetBytecodeInfo().GetSkippedMethodSize()
315 << " methods have been skipped";
316 return true;
317 }
318
IsReleasedPandaFile(const JSPandaFile * jsPandaFile) const319 bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const
320 {
321 MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals();
322 if (methodLiteral == nullptr) {
323 LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc();
324 return false;
325 }
326
327 panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
328 ASSERT(methodId.IsValid());
329 DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
330 LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId);
331 return lvt.empty();
332 }
333 } // namespace panda::ecmascript::kungfu
334