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