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