• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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