• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "ecmascript/compiler/bytecodes.h"
17 #include "ecmascript/compiler/compilation_driver.h"
18 #include "ecmascript/compiler/pass.h"
19 #include "ecmascript/ecma_handle_scope.h"
20 #include "ecmascript/jspandafile/js_pandafile_manager.h"
21 #include "ecmascript/jspandafile/panda_file_translator.h"
22 #include "ecmascript/log.h"
23 #include "ecmascript/log_wrapper.h"
24 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
25 #include "ecmascript/ts_types/ts_manager.h"
26 
27 namespace panda::ecmascript::kungfu {
28 using PGOProfilerManager = pgo::PGOProfilerManager;
Compile(JSHandle<JSFunction> & jsFunction,AOTFileGenerator & gen)29 bool JitPassManager::Compile(JSHandle<JSFunction> &jsFunction, AOTFileGenerator &gen)
30 {
31     [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
32     const JSPandaFile *jsPandaFile = Method::Cast(jsFunction->GetMethod().GetTaggedObject())->GetJSPandaFile();
33 
34     collector_ = new BytecodeInfoCollector(vm_, const_cast<JSPandaFile*>(jsPandaFile),
35         jsFunction, profilerDecoder_, passOptions_->EnableCollectLiteralInfo());
36     std::string fileName = jsPandaFile->GetFileName();
37     if (!IsReleasedPandaFile(jsPandaFile)) {
38         LOG_COMPILER(ERROR) << "The input panda file [" << fileName << "] is debuggable version.";
39     }
40 
41     gen.SetCurrentCompileFileName(jsPandaFile->GetNormalizedFileDesc());
42     lOptions_ = new LOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
43     cmpDriver_ = new JitCompilationDriver(profilerDecoder_,
44                                           collector_,
45                                           vm_->GetJSOptions().GetCompilerSelectMethods(),
46                                           vm_->GetJSOptions().GetCompilerSkipMethods(),
47                                           &gen,
48                                           fileName,
49                                           triple_,
50                                           lOptions_,
51                                           log_,
52                                           log_->OutputASM(),
53                                           maxMethodsInModule_);
54     cmpDriver_->CompileMethod(jsFunction, [this, &fileName] (const CString recordName,
55                                                              const std::string &methodName,
56                                                              MethodLiteral *methodLiteral,
57                                                              uint32_t methodOffset,
58                                                              const MethodPcInfo &methodPCInfo,
59                                                              MethodInfo &methodInfo,
60                                                              Module *m) {
61         if (vm_->GetJSOptions().GetTraceJIT()) {
62             LOG_COMPILER(INFO) << "JIT Compile Method Start: " << methodName << ", " << methodOffset << "\n";
63         }
64         ctx_ = new PassContext(triple_, log_, collector_, m->GetModule(), &profilerDecoder_);
65 
66         auto jsPandaFile = ctx_->GetJSPandaFile();
67         auto cmpCfg = ctx_->GetCompilerConfig();
68         auto tsManager = ctx_->GetTSManager();
69         auto module = m->GetModule();
70         // note: TSManager need to set current constantpool before all pass
71         tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
72         log_->SetMethodLog(fileName, methodName, logList_);
73 
74         std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
75         bool enableMethodLog = log_->GetEnableMethodLog();
76         if (enableMethodLog) {
77             LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
78                                << "] recordName [" << recordName << "] log:" << "\033[0m";
79         }
80         bool hasTypes = jsPandaFile->HasTSTypes(recordName);
81         if (UNLIKELY(!hasTypes)) {
82             LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
83         }
84 
85         circuit_ = new Circuit(vm_->GetNativeAreaAllocator(), ctx_->GetAOTModule()->GetDebugInfo(),
86             fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
87         PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr;
88 
89         builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo, tsManager,
90             circuit_, ctx_->GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
91             passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false,
92             passOptions_->EnableOptTrackField());
93         {
94             TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
95             builder_->BytecodeToCircuit();
96         }
97 
98         data_ = new PassData(builder_, circuit_, ctx_, log_, fullName, &methodInfo, hasTypes, recordName,
99             methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_);
100         PassRunner<PassData> pipeline(data_);
101         if (data_->GetMethodLiteral()->HasDebuggerStmt()) {
102             data_->AbortCompilation();
103             return;
104         }
105         pipeline.RunPass<RunFlowCyclesVerifierPass>();
106         pipeline.RunPass<RedundantPhiEliminationPass>();
107         if (builder_->EnableLoopOptimization()) {
108             pipeline.RunPass<LoopOptimizationPass>();
109             pipeline.RunPass<RedundantPhiEliminationPass>();
110         }
111         pipeline.RunPass<TypeInferPass>();
112         if (data_->IsTypeAbort()) {
113             data_->AbortCompilation();
114             return;
115         }
116         pipeline.RunPass<PGOTypeInferPass>();
117         pipeline.RunPass<TSClassAnalysisPass>();
118         pipeline.RunPass<TSInlineLoweringPass>();
119         pipeline.RunPass<RedundantPhiEliminationPass>();
120         pipeline.RunPass<AsyncFunctionLoweringPass>();
121         pipeline.RunPass<TypeBytecodeLoweringPass>();
122         pipeline.RunPass<RedundantPhiEliminationPass>();
123         pipeline.RunPass<NTypeBytecodeLoweringPass>();
124         if (data_->IsTypeAbort()) {
125             data_->AbortCompilation();
126             return;
127         }
128         pipeline.RunPass<EarlyEliminationPass>();
129         pipeline.RunPass<NumberSpeculativePass>();
130         pipeline.RunPass<LaterEliminationPass>();
131         pipeline.RunPass<ValueNumberingPass>();
132         pipeline.RunPass<StateSplitLinearizerPass>();
133         pipeline.RunPass<StringOptimizationPass>();
134         pipeline.RunPass<NTypeHCRLoweringPass>();
135         pipeline.RunPass<TypeHCRLoweringPass>();
136         pipeline.RunPass<LaterEliminationPass>();
137         pipeline.RunPass<EarlyEliminationPass>();
138         pipeline.RunPass<LCRLoweringPass>();
139         pipeline.RunPass<ConstantFoldingPass>();
140         pipeline.RunPass<ValueNumberingPass>();
141         pipeline.RunPass<SlowPathLoweringPass>();
142         pipeline.RunPass<ValueNumberingPass>();
143         pipeline.RunPass<InstructionCombinePass>();
144         pipeline.RunPass<EarlyEliminationPass>();
145         pipeline.RunPass<VerifierPass>();
146         pipeline.RunPass<GraphLinearizerPass>();
147     });
148     return true;
149 }
150 
RunCg()151 bool JitPassManager::RunCg()
152 {
153     PassRunner<PassData> pipeline(data_);
154     pipeline.RunPass<CGIRGenPass>();
155     return cmpDriver_->RunCg();
156 }
157 
~JitPassManager()158 JitPassManager::~JitPassManager()
159 {
160     if (collector_ != nullptr) {
161         delete collector_;
162         collector_ = nullptr;
163     }
164     if (lOptions_ != nullptr) {
165         delete lOptions_;
166         lOptions_ = nullptr;
167     }
168     if (cmpDriver_ != nullptr) {
169         delete cmpDriver_;
170         cmpDriver_ = nullptr;
171     }
172     if (ctx_ != nullptr) {
173         delete ctx_;
174         ctx_ = nullptr;
175     }
176     if (circuit_ != nullptr) {
177         delete circuit_;
178         circuit_ = nullptr;
179     }
180     if (builder_ != nullptr) {
181         delete builder_;
182         builder_ = nullptr;
183     }
184     if (data_ != nullptr) {
185         delete data_;
186         data_ = nullptr;
187     }
188 }
189 
Compile(JSPandaFile * jsPandaFile,const std::string & fileName,AOTFileGenerator & gen)190 bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, AOTFileGenerator &gen)
191 {
192     [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread());
193 
194     BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_,
195                                     maxAotMethodSize_, passOptions_->EnableCollectLiteralInfo());
196     // Checking released/debuggable pandafile uses method literals, which are initialized in BytecodeInfoCollector,
197     // should after it.
198     if (!IsReleasedPandaFile(jsPandaFile)) {
199         LOG_COMPILER(ERROR) << "The input panda file [" << fileName
200                             << "] of AOT Compiler is debuggable version, do not use for performance test!";
201     }
202 
203     LOptions lOptions(optLevel_, FPFlag::RESERVE_FP, relocMode_);
204     CompilationDriver cmpDriver(profilerDecoder_,
205                                 &collector,
206                                 vm_->GetJSOptions().GetCompilerSelectMethods(),
207                                 vm_->GetJSOptions().GetCompilerSkipMethods(),
208                                 &gen,
209                                 fileName,
210                                 triple_,
211                                 &lOptions,
212                                 log_,
213                                 log_->OutputASM(),
214                                 maxMethodsInModule_);
215 
216     cmpDriver.Run([this, &fileName, &collector](const CString recordName,
217                                                 const std::string &methodName,
218                                                 MethodLiteral *methodLiteral,
219                                                 uint32_t methodOffset,
220                                                 const MethodPcInfo &methodPCInfo,
221                                                 MethodInfo &methodInfo,
222                                                 Module *m) {
223         PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_);
224         auto jsPandaFile = ctx.GetJSPandaFile();
225         auto cmpCfg = ctx.GetCompilerConfig();
226         auto tsManager = ctx.GetTSManager();
227         auto module = m->GetModule();
228         // note: TSManager need to set current constantpool before all pass
229         tsManager->SetCurConstantPool(jsPandaFile, methodOffset);
230         log_->SetMethodLog(fileName, methodName, logList_);
231 
232         std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile);
233         bool enableMethodLog = log_->GetEnableMethodLog();
234         if (enableMethodLog) {
235             LOG_COMPILER(INFO) << "\033[34m" << "aot method [" << fullName
236                                << "] recordName [" << recordName << "] log:" << "\033[0m";
237         }
238         bool hasTypes = jsPandaFile->HasTSTypes(recordName);
239         if (UNLIKELY(!hasTypes)) {
240             LOG_COMPILER(INFO) << "record: " << recordName << " has no types";
241         }
242 
243         Circuit circuit(vm_->GetNativeAreaAllocator(), ctx.GetAOTModule()->GetDebugInfo(),
244                         fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME);
245 
246         PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr;
247 
248         BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, &circuit,
249                                        ctx.GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(),
250                                        passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false,
251                                        passOptions_->EnableOptTrackField());
252         {
253             TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_);
254             builder.BytecodeToCircuit();
255         }
256 
257         PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, hasTypes, recordName,
258                       methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_);
259         PassRunner<PassData> pipeline(&data);
260         if (data.GetMethodLiteral()->HasDebuggerStmt()) {
261             data.AbortCompilation();
262             return;
263         }
264         pipeline.RunPass<RunFlowCyclesVerifierPass>();
265         pipeline.RunPass<RedundantPhiEliminationPass>();
266         if (builder.EnableLoopOptimization()) {
267             pipeline.RunPass<LoopOptimizationPass>();
268             pipeline.RunPass<RedundantPhiEliminationPass>();
269         }
270         pipeline.RunPass<TypeInferPass>();
271         if (data.IsTypeAbort()) {
272             data.AbortCompilation();
273             return;
274         }
275         pipeline.RunPass<PGOTypeInferPass>();
276         pipeline.RunPass<TSClassAnalysisPass>();
277         pipeline.RunPass<TSInlineLoweringPass>();
278         pipeline.RunPass<RedundantPhiEliminationPass>();
279         pipeline.RunPass<AsyncFunctionLoweringPass>();
280         // skip async function, because some application run with errors.
281         if (methodInfo.IsTypeInferAbort()) {
282             data.AbortCompilation();
283             return;
284         }
285         pipeline.RunPass<TypeBytecodeLoweringPass>();
286         pipeline.RunPass<RedundantPhiEliminationPass>();
287         pipeline.RunPass<NTypeBytecodeLoweringPass>();
288         if (data.IsTypeAbort()) {
289             data.AbortCompilation();
290             return;
291         }
292         pipeline.RunPass<EarlyEliminationPass>();
293         pipeline.RunPass<NumberSpeculativePass>();
294         pipeline.RunPass<LaterEliminationPass>();
295         pipeline.RunPass<ValueNumberingPass>();
296         pipeline.RunPass<StateSplitLinearizerPass>();
297         pipeline.RunPass<StringOptimizationPass>();
298         pipeline.RunPass<NTypeHCRLoweringPass>();
299         pipeline.RunPass<TypeHCRLoweringPass>();
300         pipeline.RunPass<LaterEliminationPass>();
301         pipeline.RunPass<EarlyEliminationPass>();
302         pipeline.RunPass<LCRLoweringPass>();
303         pipeline.RunPass<ConstantFoldingPass>();
304         pipeline.RunPass<ValueNumberingPass>();
305         pipeline.RunPass<SlowPathLoweringPass>();
306         pipeline.RunPass<ValueNumberingPass>();
307         pipeline.RunPass<InstructionCombinePass>();
308         pipeline.RunPass<EarlyEliminationPass>();
309         pipeline.RunPass<VerifierPass>();
310         pipeline.RunPass<GraphLinearizerPass>();
311         pipeline.RunPass<CGIRGenPass>();
312     });
313 
314     LOG_COMPILER(INFO) << collector.GetBytecodeInfo().GetSkippedMethodSize()
315                        << " methods have been skipped";
316     return true;
317 }
318 
IsReleasedPandaFile(const JSPandaFile * jsPandaFile) const319 bool PassManager::IsReleasedPandaFile(const JSPandaFile *jsPandaFile) const
320 {
321     MethodLiteral* methodLiteral = jsPandaFile->GetMethodLiterals();
322     if (methodLiteral == nullptr) {
323         LOG_COMPILER(ERROR) << "There is no mehtod literal in " << jsPandaFile->GetJSPandaFileDesc();
324         return false;
325     }
326 
327     panda_file::File::EntityId methodId = methodLiteral->GetMethodId();
328     ASSERT(methodId.IsValid());
329     DebugInfoExtractor *debugInfoExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile);
330     LocalVariableTable lvt = debugInfoExtractor->GetLocalVariableTable(methodId);
331     return lvt.empty();
332 }
333 } // namespace panda::ecmascript::kungfu
334