• 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 #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