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