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 #include "ecmascript/compiler/pass_manager.h"
16
17 #include "ecmascript/compiler/bytecodes.h"
18 #include "ecmascript/compiler/compilation_driver.h"
19 #include "ecmascript/compiler/pass.h"
20 #include "ecmascript/ecma_handle_scope.h"
21 #include "ecmascript/jspandafile/js_pandafile_manager.h"
22 #include "ecmascript/jspandafile/method_literal.h"
23 #include "ecmascript/jspandafile/panda_file_translator.h"
24 #include "ecmascript/log.h"
25 #include "ecmascript/log_wrapper.h"
26 #include "ecmascript/pgo_profiler/pgo_profiler.h"
27 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
28 #include "ecmascript/pgo_profiler/pgo_utils.h"
29 #include "ecmascript/jit/jit.h"
30 #include "jsnapi_expo.h"
31
32 namespace panda::ecmascript::kungfu {
33 using PGOProfilerManager = pgo::PGOProfilerManager;
34
PassContext(const std::string & triple,CompilerLog * log,BytecodeInfoCollector * collector,IRModule * aotModule,PGOProfilerDecoder * decoder)35 PassContext::PassContext(const std::string &triple, CompilerLog *log, BytecodeInfoCollector* collector,
36 IRModule *aotModule, PGOProfilerDecoder *decoder)
37 : compilationEnv_(collector->GetCompilationEnv()),
38 bcInfoCollector_(collector),
39 bytecodes_(collector->GetByteCodes()),
40 cmpCfg_(triple, &compilationEnv_->GetJSOptions()),
41 log_(log),
42 jsPandaFile_(collector->GetJSPandaFile()),
43 aotModule_(aotModule),
44 decoder_(decoder)
45 {
46 }
47
48
Compile(JSHandle<ProfileTypeInfo> & profileTypeInfo,AOTFileGenerator & gen,int32_t osrOffset)49 bool JitPassManager::Compile(JSHandle<ProfileTypeInfo> &profileTypeInfo,
50 AOTFileGenerator &gen, int32_t osrOffset)
51 {
52 const JSPandaFile *jsPandaFile = compilationEnv_->GetJSPandaFile();
53 ASSERT(jsPandaFile != nullptr);
54 MethodLiteral *methodLiteral = compilationEnv_->GetMethodLiteral();
55 const uint8_t *pcStart = compilationEnv_->GetMethodPcStart();
56 const panda_file::File::Header *header = jsPandaFile->GetPandaFile()->GetHeader();
57 ApEntityId abcId = compilationEnv_->GetMethodAbcId();
58 std::string fileName(jsPandaFile->GetJSPandaFileDesc());
59
60 collector_ = new BytecodeInfoCollector(compilationEnv_, const_cast<JSPandaFile*>(jsPandaFile),
61 profilerDecoder_);
62
63 gen.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc());
64 lOptions_ = new LOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
65 cmpDriver_ = new JitCompilationDriver(profilerDecoder_,
66 collector_,
67 &gen,
68 fileName,
69 triple_,
70 lOptions_,
71 log_,
72 log_->OutputASM(),
73 maxMethodsInModule_);
74 return cmpDriver_->CompileMethod(jsPandaFile, methodLiteral, profileTypeInfo, pcStart, header, abcId,
75 [this, &fileName, &osrOffset] (
76 const CString &recordName,
77 const std::string &methodName,
78 MethodLiteral *methodLiteral,
79 JSHandle<ProfileTypeInfo> &profileTypeInfo,
80 uint32_t methodOffset,
81 const MethodPcInfo &methodPCInfo,
82 MethodInfo &methodInfo,
83 Module *m,
84 const uint8_t *pcStart,
85 const panda_file::File::Header *header,
86 ApEntityId abcId) -> bool {
87 if (compilationEnv_->GetJSOptions().GetTraceJIT()) {
88 LOG_COMPILER(INFO) << "JIT Compile Method Start: " << methodName << ", " << methodOffset << "\n";
89 }
90 ctx_ = new PassContext(triple_, log_, collector_, m->GetModule(), &profilerDecoder_);
91
92 auto jsPandaFile = ctx_->GetJSPandaFile();
93 auto cmpCfg = ctx_->GetCompilerConfig();
94 auto module = m->GetModule();
95 log_->SetMethodLog(fileName, methodName, logList_);
96
97 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
98 bool enableMethodLog = log_->GetEnableMethodLog();
99 if (enableMethodLog) {
100 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
101 << "] recordName [" << recordName << "] log:" << "\033[0m";
102 }
103 Chunk chunk(compilationEnv_->GetNativeAreaAllocator());
104 if (compilationEnv_->GetJSOptions().IsEnableJITPGO()) {
105 jitProfiler_ = compilationEnv_->GetPGOProfiler()->GetJITProfile();
106 static_cast<JitCompilationEnv*>(compilationEnv_)->SetProfileTypeInfo(profileTypeInfo);
107 jitProfiler_->SetCompilationEnv(compilationEnv_);
108 jitProfiler_->InitChunk(&chunk);
109 jitProfiler_->ProfileBytecode(compilationEnv_->GetJSThread(), profileTypeInfo, nullptr,
110 methodLiteral->GetMethodId(), abcId, pcStart,
111 methodLiteral->GetCodeSize(jsPandaFile, methodLiteral->GetMethodId()),
112 header);
113 } else {
114 jitProfiler_ = nullptr;
115 }
116
117 if (compilationEnv_->GetJSOptions().IsEnableJitFrame()) {
118 circuit_ = new Circuit(compilationEnv_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(),
119 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::FASTJIT_FUNCTION_FRAME);
120 } else {
121 circuit_ = new Circuit(compilationEnv_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(),
122 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
123 }
124
125 PGOProfilerDecoder defDecoder;
126 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : &defDecoder;
127
128 builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo,
129 circuit_, ctx_->GetByteCodes(), enableMethodLog && log_->OutputCIR(),
130 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false, jitProfiler_);
131 builder_->SetOsrOffset(osrOffset);
132 {
133 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
134 builder_->SetJitCompile();
135 builder_->BytecodeToCircuit();
136 if (builder_->HasIrreducibleLoop()) {
137 LOG_JIT(DEBUG) << "compile fail as has irreducible loop:" << methodName;
138 return false;
139 }
140 if (builder_->HasEmptyCatchBB() && compilationEnv_->GetJSOptions().IsEnableAPPJIT()) {
141 LOG_JIT(DEBUG) << "compile fail as has empty catch bb:" << methodName;
142 return false;
143 }
144 }
145
146 CallMethodFlagMap methodFlagMap;
147 data_ = new PassData(builder_, circuit_, ctx_, log_, fullName, &methodInfo, recordName,
148 methodLiteral, methodOffset, &methodFlagMap, CVector<AbcFileInfo> {},
149 compilationEnv_->GetNativeAreaAllocator(), decoder, passOptions_);
150 PassRunner<PassData> pipeline(data_);
151
152 pipeline.RunPass<RunFlowCyclesVerifierPass>();
153 pipeline.RunPass<RedundantPhiEliminationPass>();
154 if (builder_->EnableLoopOptimization()) {
155 pipeline.RunPass<LoopOptimizationPass>();
156 pipeline.RunPass<RedundantPhiEliminationPass>();
157 }
158 if (passOptions_->EnableTypeLowering()) {
159 pipeline.RunPass<PGOTypeInferPass>();
160 }
161 {
162 Jit::JitLockHolder lock(compilationEnv_, "TSInlineLoweringPass");
163 pipeline.RunPass<TSInlineLoweringPass>();
164 }
165
166 pipeline.RunPass<RedundantPhiEliminationPass>();
167 pipeline.RunPass<AsyncFunctionLoweringPass>();
168 pipeline.RunPass<TypeBytecodeLoweringPass>();
169 pipeline.RunPass<UselessGateEliminationPass>();
170 pipeline.RunPass<InductionVariableAnalysisPass>();
171 pipeline.RunPass<RedundantPhiEliminationPass>();
172 pipeline.RunPass<NTypeBytecodeLoweringPass>();
173 pipeline.RunPass<UselessGateEliminationPass>();
174 pipeline.RunPass<EarlyEliminationPass>();
175 pipeline.RunPass<NumberSpeculativePass>();
176 pipeline.RunPass<UselessGateEliminationPass>();
177 pipeline.RunPass<LaterEliminationPass>();
178 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) {
179 pipeline.RunPass<ValueNumberingPass>();
180 }
181 pipeline.RunPass<StateSplitLinearizerPass>();
182 pipeline.RunPass<EscapeAnalysisPass>();
183 pipeline.RunPass<StringOptimizationPass>();
184 pipeline.RunPass<NTypeHCRLoweringPass>();
185 pipeline.RunPass<TypeHCRLoweringPass>();
186 pipeline.RunPass<UselessGateEliminationPass>();
187 pipeline.RunPass<LaterEliminationPass>();
188 pipeline.RunPass<EarlyEliminationPass>();
189 pipeline.RunPass<LCRLoweringPass>();
190 pipeline.RunPass<UselessGateEliminationPass>();
191 pipeline.RunPass<ConstantFoldingPass>();
192 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) {
193 pipeline.RunPass<ValueNumberingPass>();
194 }
195 pipeline.RunPass<SlowPathLoweringPass>();
196 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) {
197 pipeline.RunPass<ValueNumberingPass>();
198 }
199 pipeline.RunPass<InstructionCombinePass>();
200 pipeline.RunPass<EarlyEliminationPass>();
201 pipeline.RunPass<UselessGateEliminationPass>();
202 if (!compilationEnv_->GetJSOptions().IsEnableJitFastCompile()) {
203 pipeline.RunPass<VerifierPass>();
204 }
205 pipeline.RunPass<GraphLinearizerPass>();
206 return true;
207 });
208 }
209
RunCg()210 bool JitPassManager::RunCg()
211 {
212 PassRunner<PassData> pipeline(data_);
213 pipeline.RunPass<CGIRGenPass>();
214 return cmpDriver_->RunCg();
215 }
216
~JitPassManager()217 JitPassManager::~JitPassManager()
218 {
219 if (data_ != nullptr) {
220 delete data_;
221 data_ = nullptr;
222 }
223 if (builder_ != nullptr) {
224 delete builder_;
225 builder_ = nullptr;
226 }
227 if (circuit_ != nullptr) {
228 delete circuit_;
229 circuit_ = nullptr;
230 }
231 if (ctx_ != nullptr) {
232 delete ctx_;
233 ctx_ = nullptr;
234 }
235 if (cmpDriver_ != nullptr) {
236 delete cmpDriver_;
237 cmpDriver_ = nullptr;
238 }
239 if (lOptions_ != nullptr) {
240 delete lOptions_;
241 lOptions_ = nullptr;
242 }
243 if (collector_ != nullptr) {
244 delete collector_;
245 collector_ = nullptr;
246 }
247 }
248
CompileValidFiles(AOTFileGenerator & generator,bool & ret,AotCompilerStats & compilerStats)249 void PassManager::CompileValidFiles(AOTFileGenerator &generator, bool &ret, AotCompilerStats &compilerStats)
250 {
251 for (uint32_t i = 0 ; i < fileInfos_.size(); ++i) {
252 JSPandaFile *jsPandaFile = fileInfos_[i].jsPandaFile_.get();
253 auto &collector = *bcInfoCollectors_[i];
254 const std::string &extendedFilePath = fileInfos_[i].extendedFilePath_;
255 LOG_COMPILER(INFO) << "AOT compile: " << extendedFilePath;
256 generator.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc());
257 if (!Compile(jsPandaFile, extendedFilePath, generator, compilerStats, collector)) {
258 ret = false;
259 continue;
260 }
261 }
262 }
263
Compile(JSPandaFile * jsPandaFile,const std::string & fileName,AOTFileGenerator & gen,AotCompilerStats & compilerStats,BytecodeInfoCollector & collector)264 bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, AOTFileGenerator &gen,
265 AotCompilerStats &compilerStats, BytecodeInfoCollector &collector)
266 {
267 [[maybe_unused]] EcmaHandleScope handleScope(compilationEnv_->GetJSThread());
268
269 // Checking released/debuggable pandafile uses method literals, which are initialized in BytecodeInfoCollector,
270 // should after it.
271 if (!IsReleasedPandaFile(jsPandaFile)) {
272 LOG_COMPILER(ERROR) << "The input panda file [" << fileName
273 << "] of AOT Compiler is debuggable version, do not use for performance test!";
274 }
275 LOptions lOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
276 CompilationDriver cmpDriver(profilerDecoder_,
277 &collector,
278 &gen,
279 fileName,
280 triple_,
281 &lOptions,
282 log_,
283 log_->OutputASM(),
284 maxMethodsInModule_);
285
286 cmpDriver.Run(*callMethodFlagMap_, [this, &fileName, &collector](const CString recordName,
287 const std::string &methodName,
288 MethodLiteral *methodLiteral,
289 uint32_t methodOffset,
290 const MethodPcInfo &methodPCInfo,
291 MethodInfo &methodInfo,
292 Module *m) {
293 PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_);
294 auto jsPandaFile = ctx.GetJSPandaFile();
295 auto cmpCfg = ctx.GetCompilerConfig();
296 auto module = m->GetModule();
297 log_->SetMethodLog(fileName, methodName, logList_);
298
299 std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
300 bool enableMethodLog = log_->GetEnableMethodLog();
301 if (enableMethodLog) {
302 LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
303 << "] recordName [" << recordName << "] log:" << "\033[0m";
304 }
305
306 Circuit circuit(compilationEnv_->GetNativeAreaAllocator(), ctx.GetAOTModule()->GetDebugInfo(),
307 fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
308
309 PGOProfilerDecoder defDecoder;
310 PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : &defDecoder;
311
312 BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, &circuit,
313 ctx.GetByteCodes(), enableMethodLog && log_->OutputCIR(),
314 passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false);
315 {
316 TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
317 builder.BytecodeToCircuit();
318 }
319
320 PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, recordName,
321 methodLiteral, methodOffset, callMethodFlagMap_, fileInfos_,
322 compilationEnv_->GetNativeAreaAllocator(), decoder, passOptions_,
323 optBCRange_);
324 PassRunner<PassData> pipeline(&data);
325 if (!pipeline.RunPass<PreCompileCheckPass>()) {
326 return;
327 }
328 pipeline.RunPass<RunFlowCyclesVerifierPass>();
329 pipeline.RunPass<RedundantPhiEliminationPass>();
330 if (builder.EnableLoopOptimization()) {
331 pipeline.RunPass<LoopOptimizationPass>();
332 pipeline.RunPass<RedundantPhiEliminationPass>();
333 }
334 pipeline.RunPass<PGOTypeInferPass>();
335 pipeline.RunPass<TSInlineLoweringPass>();
336 pipeline.RunPass<RedundantPhiEliminationPass>();
337 pipeline.RunPass<AsyncFunctionLoweringPass>();
338 pipeline.RunPass<TypeBytecodeLoweringPass>();
339 pipeline.RunPass<UselessGateEliminationPass>();
340 pipeline.RunPass<InductionVariableAnalysisPass>();
341 pipeline.RunPass<RedundantPhiEliminationPass>();
342 pipeline.RunPass<NTypeBytecodeLoweringPass>();
343 pipeline.RunPass<UselessGateEliminationPass>();
344 pipeline.RunPass<EarlyEliminationPass>();
345 pipeline.RunPass<NumberSpeculativePass>();
346 pipeline.RunPass<UselessGateEliminationPass>();
347 pipeline.RunPass<LaterEliminationPass>();
348 pipeline.RunPass<ValueNumberingPass>();
349 pipeline.RunPass<StateSplitLinearizerPass>();
350 pipeline.RunPass<EscapeAnalysisPass>();
351 pipeline.RunPass<StringOptimizationPass>();
352 pipeline.RunPass<NTypeHCRLoweringPass>();
353 pipeline.RunPass<TypeHCRLoweringPass>();
354 pipeline.RunPass<UselessGateEliminationPass>();
355 pipeline.RunPass<LaterEliminationPass>();
356 pipeline.RunPass<EarlyEliminationPass>();
357 pipeline.RunPass<LCRLoweringPass>();
358 pipeline.RunPass<UselessGateEliminationPass>();
359 pipeline.RunPass<ConstantFoldingPass>();
360 pipeline.RunPass<ValueNumberingPass>();
361 pipeline.RunPass<SlowPathLoweringPass>();
362 pipeline.RunPass<ValueNumberingPass>();
363 pipeline.RunPass<InstructionCombinePass>();
364 pipeline.RunPass<EarlyEliminationPass>();
365 pipeline.RunPass<UselessGateEliminationPass>();
366 if (passOptions_->EnableVerifierPass()) {
367 pipeline.RunPass<VerifierPass>();
368 }
369 pipeline.RunPass<GraphLinearizerPass>();
370 pipeline.RunPass<CGIRGenPass>();
371 });
372
373 compilerStats.SetCompilerMethodCount(cmpDriver.GetCompilerMethodCount());
374 LOG_COMPILER(INFO) << collector.GetBytecodeInfo().GetSkippedMethodSize()
375 << " methods have been skipped";
376 return true;
377 }
378
IsReleasedPandaFile(const JSPandaFile * jsPandaFile) const379 bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const
380 {
381 MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals();
382 if (methodLiteral == nullptr) {
383 LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc();
384 return false;
385 }
386
387 panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
388 ASSERT(methodId.IsValid());
389 DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
390 LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId);
391 return lvt.empty();
392 }
393 } // namespace panda::ecmascript::kungfu
394