• 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 
16 #ifndef ECMASCRIPT_COMPILER_PASS_H
17 #define ECMASCRIPT_COMPILER_PASS_H
18 
19 #include "ecmascript/compiler/async_function_lowering.h"
20 #include "ecmascript/compiler/bytecode_circuit_builder.h"
21 #include "ecmascript/compiler/common_stubs.h"
22 #include "ecmascript/compiler/compiler_log.h"
23 #include "ecmascript/compiler/early_elimination.h"
24 #include "ecmascript/compiler/graph_linearizer.h"
25 #include "ecmascript/compiler/later_elimination.h"
26 #include "ecmascript/compiler/lcr_lowering.h"
27 #include "ecmascript/compiler/llvm_codegen.h"
28 #include "ecmascript/compiler/loop_analysis.h"
29 #include "ecmascript/compiler/loop_peeling.h"
30 #include "ecmascript/compiler/ntype_hcr_lowering.h"
31 #include "ecmascript/compiler/ntype_mcr_lowering.h"
32 #include "ecmascript/compiler/number_speculative_runner.h"
33 #include "ecmascript/compiler/scheduler.h"
34 #include "ecmascript/compiler/slowpath_lowering.h"
35 #include "ecmascript/compiler/state_split_linearizer.h"
36 #include "ecmascript/compiler/ts_class_analysis.h"
37 #include "ecmascript/compiler/ts_inline_lowering.h"
38 #include "ecmascript/compiler/ts_hcr_lowering.h"
39 #include "ecmascript/compiler/type_inference/global_type_infer.h"
40 #include "ecmascript/compiler/type_inference/initialization_analysis.h"
41 #include "ecmascript/compiler/type_inference/pgo_type_infer.h"
42 #include "ecmascript/compiler/type_mcr_lowering.h"
43 #include "ecmascript/compiler/value_numbering.h"
44 #include "ecmascript/compiler/verifier.h"
45 
46 namespace panda::ecmascript::kungfu {
47 class PassContext;
48 
49 class PassData {
50 public:
51     PassData(BytecodeCircuitBuilder *builder, Circuit *circuit, PassContext *ctx, CompilerLog *log,
52              std::string methodName, MethodInfo *methodInfo = nullptr, bool hasTypes = false,
53              const CString &recordName = "", MethodLiteral *methodLiteral = nullptr,
54              uint32_t methodOffset = 0, NativeAreaAllocator *allocator = nullptr,
55              PGOProfilerDecoder *decoder = nullptr, PassOptions *passOptions = nullptr)
builder_(builder)56         : builder_(builder), circuit_(circuit), ctx_(ctx), log_(log), methodName_(methodName),
57           methodInfo_(methodInfo), hasTypes_(hasTypes), recordName_(recordName), methodLiteral_(methodLiteral),
58           methodOffset_(methodOffset), allocator_(allocator), decoder_(decoder), passOptions_(passOptions)
59     {
60     }
61 
62     virtual ~PassData() = default;
63 
GetConstScheduleResult()64     const ControlFlowGraph &GetConstScheduleResult() const
65     {
66         return cfg_;
67     }
68 
GetCfg()69     ControlFlowGraph &GetCfg()
70     {
71         return cfg_;
72     }
73 
GetCircuit()74     virtual Circuit* GetCircuit() const
75     {
76         return circuit_;
77     }
78 
GetBuilder()79     BytecodeCircuitBuilder* GetBuilder() const
80     {
81         return builder_;
82     }
83 
GetPassContext()84     PassContext* GetPassContext() const
85     {
86         return ctx_;
87     }
88 
GetCompilerConfig()89     CompilationConfig* GetCompilerConfig() const
90     {
91         return ctx_->GetCompilerConfig();
92     }
93 
GetTSManager()94     TSManager* GetTSManager() const
95     {
96         return ctx_->GetTSManager();
97     }
98 
GetJSPandaFile()99     const JSPandaFile *GetJSPandaFile() const
100     {
101         return ctx_->GetJSPandaFile();
102     }
103 
GetAotModule()104     LLVMModule* GetAotModule() const
105     {
106         return ctx_->GetAOTModule();
107     }
108 
GetLog()109     CompilerLog* GetLog() const
110     {
111         return log_;
112     }
113 
GetMethodName()114     const std::string& GetMethodName() const
115     {
116         return methodName_;
117     }
118 
GetMethodLiteral()119     const MethodLiteral* GetMethodLiteral() const
120     {
121         return methodLiteral_;
122     }
123 
GetMethodOffset()124     uint32_t GetMethodOffset() const
125     {
126         return methodOffset_;
127     }
128 
GetMethodInfo()129     MethodInfo* GetMethodInfo() const
130     {
131         return methodInfo_;
132     }
133 
GetMethodInfoIndex()134     size_t GetMethodInfoIndex() const
135     {
136         return methodInfo_->GetMethodInfoIndex();
137     }
138 
HasTypes()139     bool HasTypes() const
140     {
141         return hasTypes_;
142     }
143 
GetRecordName()144     const CString &GetRecordName() const
145     {
146         return recordName_;
147     }
148 
GetNativeAreaAllocator()149     NativeAreaAllocator* GetNativeAreaAllocator() const
150     {
151         return allocator_;
152     }
153 
GetPGOProfilerDecoder()154     PGOProfilerDecoder *GetPGOProfilerDecoder() const
155     {
156         return decoder_;
157     }
158 
GetPassOptions()159     PassOptions *GetPassOptions() const
160     {
161         return passOptions_;
162     }
163 
IsTypeAbort()164     bool IsTypeAbort() const
165     {
166         if (hasTypes_) {
167             // A ts method which has low type percent and not marked as a resolved method
168             // should be skipped from full compilation.
169             if (methodInfo_->IsTypeInferAbort() && !methodInfo_->IsResolvedMethod()) {
170                 return true;
171             }
172         } else {
173             // For js method, type infer pass will be skipped and it don't have a type percent.
174             // If we set an non zero type threshold, js method will be skipped from full compilation.
175             // The default Type threshold is -1.
176             if (ctx_->GetTSManager()->GetTypeThreshold() >= 0) {
177                 return true;
178             }
179         }
180         // when a method will be full compiled, we should confirm its TypeInferAbortBit to be false
181         // maybe it used to be true in the first round of compilation.
182         methodInfo_->SetTypeInferAbort(false);
183         log_->AddCompiledMethod(methodName_, recordName_);
184         return false;
185     }
186 
AbortCompilation()187     void AbortCompilation()
188     {
189         ctx_->GetBytecodeInfo().AddSkippedMethod(methodOffset_);
190         methodInfo_->SetIsCompiled(false);
191         log_->RemoveCompiledMethod(methodName_, recordName_);
192     }
193 
MarkAsTypeAbort()194     void MarkAsTypeAbort()
195     {
196         methodInfo_->SetTypeInferAbort(true);
197     }
198 
199 private:
200     BytecodeCircuitBuilder *builder_ {nullptr};
201     Circuit *circuit_ {nullptr};
202     ControlFlowGraph cfg_;
203     PassContext *ctx_ {nullptr};
204     CompilerLog *log_ {nullptr};
205     std::string methodName_;
206     MethodInfo *methodInfo_ {nullptr};
207     bool hasTypes_;
208     const CString &recordName_;
209     MethodLiteral *methodLiteral_ {nullptr};
210     uint32_t methodOffset_;
211     NativeAreaAllocator *allocator_ {nullptr};
212     PGOProfilerDecoder *decoder_ {nullptr};
213     PassOptions *passOptions_ {nullptr};
214 };
215 
216 template<typename T1>
217 class PassRunner {
218 public:
PassRunner(T1 * data)219     explicit PassRunner(T1* data) : data_(data) {}
220     virtual ~PassRunner() = default;
221     template<typename T2, typename... Args>
RunPass(Args...args)222     bool RunPass(Args... args)
223     {
224         T2 pass;
225         return pass.Run(data_, std::forward<Args>(args)...);
226     }
227 
228 private:
229     T1* data_;
230 };
231 
232 class TypeInferPass {
233 public:
Run(PassData * data)234     bool Run(PassData* data)
235     {
236         PassOptions *passOptions = data->GetPassOptions();
237         if (passOptions != nullptr && !passOptions->EnableTypeInfer()) {
238             return false;
239         }
240         TimeScope timescope("TypeInferPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
241         if (data->HasTypes()) {
242             bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType();
243             GlobalTypeInfer globalTypeInfer(data->GetPassContext(), data->GetMethodOffset(), data->GetRecordName(),
244                                             data->GetPGOProfilerDecoder(), passOptions->EnableOptTrackField(),
245                                             enableLog);
246             globalTypeInfer.ProcessTypeInference(data->GetBuilder(), data->GetCircuit());
247             if (data->GetMethodLiteral()->IsClassConstructor()) {
248                 InitializationAnalysis initAnalysis(data->GetCircuit(), data->GetTSManager(), data->GetRecordName(),
249                                                     data->GetMethodName(), enableLog);
250                 initAnalysis.Run();
251             }
252         }
253         return true;
254     }
255 };
256 
257 class PGOTypeInferPass {
258 public:
Run(PassData * data)259     bool Run(PassData* data)
260     {
261         TimeScope timescope("PGOTypeInferPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
262         bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType();
263         Chunk chunk(data->GetNativeAreaAllocator());
264         PGOTypeInfer pgoTypeInfer(data->GetCircuit(), data->GetTSManager(), data->GetBuilder(),
265                                   data->GetMethodName(), &chunk, enableLog);
266         pgoTypeInfer.Run();
267         return true;
268     }
269 };
270 
271 class TSClassAnalysisPass {
272 public:
Run(PassData * data)273     bool Run(PassData *data)
274     {
275         TimeScope timescope("TSClassAnalysisPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
276         TSClassAnalysis analyzer(data->GetPassContext()->GetTSManager());
277         analyzer.Run();
278         return true;
279     }
280 };
281 
282 class TSHCRLoweringPass {
283 public:
Run(PassData * data)284     bool Run(PassData* data)
285     {
286         PassOptions *passOptions = data->GetPassOptions();
287         if (!passOptions->EnableTypeLowering()) {
288             return false;
289         }
290         TimeScope timescope("TSHCRLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
291         bool enableLog = data->GetLog()->EnableMethodCIRLog();
292         bool enableTypeLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType();
293         TSHCRLowering lowering(data->GetCircuit(), data->GetPassContext(),
294             enableLog, enableTypeLog, data->GetMethodName());
295         bool success = lowering.RunTSHCRLowering();
296         if (!success) {
297             data->MarkAsTypeAbort();
298         }
299         return true;
300     }
301 };
302 
303 class NTypeHCRLoweringPass {
304 public:
Run(PassData * data)305     bool Run(PassData* data)
306     {
307         PassOptions *passOptions = data->GetPassOptions();
308         if (!passOptions->EnableTypeLowering()) {
309             return false;
310         }
311         TimeScope timescope("NTypeHCRLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
312         bool enableLog = data->GetLog()->EnableMethodCIRLog();
313         NTypeHCRLowering lowering(data->GetCircuit(), data->GetPassContext(),
314             data->GetTSManager(), data->GetRecordName(), enableLog, data->GetMethodName());
315         lowering.RunNTypeHCRLowering();
316         return true;
317     }
318 };
319 
320 class TypeMCRLoweringPass {
321 public:
Run(PassData * data)322     bool Run(PassData* data)
323     {
324         PassOptions *passOptions = data->GetPassOptions();
325         if (!passOptions->EnableTypeLowering()) {
326             return false;
327         }
328         TimeScope timescope("TypeMCRLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
329         bool enableLog = data->GetLog()->EnableMethodCIRLog();
330         TypeMCRLowering lowering(data->GetCircuit(), data->GetCompilerConfig(), data->GetTSManager(),
331                                  enableLog, data->GetMethodName());
332         lowering.RunTypeMCRLowering();
333         return true;
334     }
335 };
336 
337 class NTypeMCRLoweringPass {
338 public:
Run(PassData * data)339     bool Run(PassData* data)
340     {
341         PassOptions *passOptions = data->GetPassOptions();
342         if (!passOptions->EnableTypeLowering()) {
343             return false;
344         }
345         TimeScope timescope("NTypeMCRLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
346         bool enableLog = data->GetLog()->EnableMethodCIRLog();
347         NTypeMCRLowering lowering(data->GetCircuit(), data->GetPassContext(),
348                                   data->GetRecordName(), enableLog, data->GetMethodName());
349         lowering.RunNTypeMCRLowering();
350         return true;
351     }
352 };
353 
354 class LCRLoweringPass {
355 public:
Run(PassData * data)356     bool Run(PassData* data)
357     {
358         PassOptions *passOptions = data->GetPassOptions();
359         if (!passOptions->EnableTypeLowering()) {
360             return false;
361         }
362         TimeScope timescope("LCRLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
363         bool enableLog = data->GetLog()->EnableMethodCIRLog();
364         LCRLowering lowering(data->GetCircuit(), data->GetCompilerConfig(), enableLog, data->GetMethodName());
365         lowering.Run();
366         return true;
367     }
368 };
369 
370 class TSInlineLoweringPass {
371 public:
Run(PassData * data)372     bool Run(PassData* data)
373     {
374         PassOptions *passOptions = data->GetPassOptions();
375         if (!passOptions->EnableOptInlining() || !passOptions->EnableTypeLowering()) {
376             return false;
377         }
378         TimeScope timescope("TSInlineLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
379         bool enableLog = data->GetLog()->EnableMethodCIRLog();
380         TSInlineLowering inlining(data->GetCircuit(), data->GetPassContext(), enableLog, data->GetMethodName(),
381                                   data->GetNativeAreaAllocator(), passOptions, data->GetMethodOffset());
382         inlining.RunTSInlineLowering();
383         return true;
384     }
385 };
386 
387 class SlowPathLoweringPass {
388 public:
Run(PassData * data)389     bool Run(PassData* data)
390     {
391         TimeScope timescope("SlowPathLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
392         bool enableLog = data->GetLog()->EnableMethodCIRLog();
393         SlowPathLowering lowering(data->GetCircuit(), data->GetCompilerConfig(), data->GetTSManager(),
394                                   data->GetMethodLiteral(), enableLog, data->GetMethodName());
395         lowering.CallRuntimeLowering();
396         return true;
397     }
398 };
399 
400 class VerifierPass {
401 public:
Run(PassData * data)402     bool Run(PassData* data)
403     {
404         TimeScope timescope("VerifierPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
405         bool enableLog = data->GetLog()->EnableMethodCIRLog();
406         bool isQualified = Verifier::Run(data->GetCircuit(), data->GetMethodName(), enableLog);
407         if (!isQualified) {
408             LOG_FULL(FATAL) << "VerifierPass fail";
409             UNREACHABLE();
410         }
411         return isQualified;
412     }
413 };
414 
415 class NumberSpeculativePass {
416 public:
Run(PassData * data)417     bool Run(PassData* data)
418     {
419         PassOptions *passOptions = data->GetPassOptions();
420         if (!passOptions->EnableTypeLowering()) {
421             return false;
422         }
423         TimeScope timescope("NumberSpeculativePass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
424         Chunk chunk(data->GetNativeAreaAllocator());
425         bool enableLog = data->GetLog()->EnableMethodCIRLog();
426         NumberSpeculativeRunner(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run();
427         return true;
428     }
429 };
430 
431 class LoopOptimizationPass {
432 public:
Run(PassData * data)433     bool Run(PassData* data)
434     {
435         TimeScope timescope("LoopOptimizationPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
436         Chunk chunk(data->GetNativeAreaAllocator());
437         const auto& headList = data->GetBuilder()->GetLoopHeads();
438         LoopAnalysis loopAnalysis_(data->GetCircuit(), &chunk);
439         for (auto head : headList) {
440             auto bb = data->GetBuilder()->GetBasicBlockById(head.second);
441             auto loopInfo = new LoopInfo(&chunk, bb.stateCurrent);
442             loopAnalysis_.CollectLoopBody(loopInfo);
443             bool enableLog = data->GetLog()->EnableMethodCIRLog();
444             if (enableLog) {
445                 loopAnalysis_.PrintLoop(loopInfo);
446             }
447             if (data->GetPassOptions()->EnableOptLoopPeeling()) {
448                 LoopPeeling(data->GetBuilder(), data->GetCircuit(), enableLog,
449                             data->GetMethodName(), &chunk, loopInfo).Peel();
450             }
451         }
452         loopAnalysis_.LoopExitElimination();
453         return true;
454     }
455 };
456 
457 class EarlyEliminationPass {
458 public:
Run(PassData * data)459     bool Run(PassData* data)
460     {
461         PassOptions *passOptions = data->GetPassOptions();
462         if (!passOptions->EnableTypeLowering() || !passOptions->EnableEarlyElimination()) {
463             return false;
464         }
465         TimeScope timescope("EarlyEliminationPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
466         Chunk chunk(data->GetNativeAreaAllocator());
467         bool enableLog = data->GetLog()->EnableMethodCIRLog();
468         EarlyElimination(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run();
469         return true;
470     }
471 };
472 
473 class LaterEliminationPass {
474 public:
Run(PassData * data)475     bool Run(PassData* data)
476     {
477         PassOptions *passOptions = data->GetPassOptions();
478         if (!passOptions->EnableTypeLowering() || !passOptions->EnableLaterElimination()) {
479             return false;
480         }
481         TimeScope timescope("LaterEliminationPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
482         Chunk chunk(data->GetNativeAreaAllocator());
483         bool enableLog = data->GetLog()->EnableMethodCIRLog();
484         LaterElimination(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run();
485         return true;
486     }
487 };
488 
489 class ValueNumberingPass {
490 public:
Run(PassData * data)491     bool Run(PassData* data)
492     {
493         PassOptions *passOptions = data->GetPassOptions();
494         if (!passOptions->EnableTypeLowering() || !passOptions->EnableValueNumbering()) {
495             return false;
496         }
497         TimeScope timescope("ValueNumberingPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
498         Chunk chunk(data->GetNativeAreaAllocator());
499         bool enableLog = data->GetLog()->EnableMethodCIRLog();
500         ValueNumbering(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run();
501         return true;
502     }
503 };
504 
505 class SchedulingPass {
506 public:
Run(PassData * data)507     bool Run(PassData* data)
508     {
509         TimeScope timescope("SchedulingPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
510         bool enableLog = data->GetLog()->EnableMethodCIRLog();
511         Scheduler::Run(data->GetCircuit(), data->GetCfg(), data->GetMethodName(), enableLog);
512         return true;
513     }
514 };
515 
516 class StateSplitLinearizerPass {
517 public:
Run(PassData * data)518     bool Run(PassData* data)
519     {
520         PassOptions *passOptions = data->GetPassOptions();
521         if (!passOptions->EnableTypeLowering()) {
522             return false;
523         }
524         TimeScope timescope("StateSplitLinearizerPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
525         Chunk chunk(data->GetNativeAreaAllocator());
526         bool enableLog = data->GetLog()->EnableMethodCIRLog();
527         StateSplitLinearizer(data->GetCircuit(), data->GetCompilerConfig(),
528             enableLog, data->GetMethodName(), &chunk).Run();
529         return true;
530     }
531 };
532 
533 class GraphLinearizerPass {
534 public:
Run(PassData * data)535     bool Run(PassData* data)
536     {
537         TimeScope timescope("GraphLinearizerPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
538         Chunk chunk(data->GetNativeAreaAllocator());
539         bool enableLog = data->GetLog()->EnableMethodCIRLog();
540         GraphLinearizer(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run(data->GetCfg());
541         return true;
542     }
543 };
544 
545 class LLVMIRGenPass {
546 public:
CreateCodeGen(LLVMModule * module,bool enableLog)547     void CreateCodeGen(LLVMModule *module, bool enableLog)
548     {
549         llvmImpl_ = std::make_unique<LLVMIRGeneratorImpl>(module, enableLog);
550     }
551 
Run(PassData * data)552     bool Run(PassData *data)
553     {
554         auto module = data->GetAotModule();
555         TimeScope timescope("LLVMIRGenPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog());
556         bool enableLog = data->GetLog()->EnableMethodCIRLog() || data->GetLog()->OutputASM();
557         CreateCodeGen(module, enableLog);
558         CodeGenerator codegen(llvmImpl_, data->GetMethodName());
559         codegen.Run(data->GetCircuit(), data->GetConstScheduleResult(), data->GetCompilerConfig(),
560                     data->GetMethodLiteral(), data->GetJSPandaFile());
561         return true;
562     }
563 private:
564     std::unique_ptr<CodeGeneratorImpl> llvmImpl_ {nullptr};
565 };
566 
567 class AsyncFunctionLoweringPass {
568 public:
Run(PassData * data)569     bool Run(PassData* data)
570     {
571         TimeScope timescope("AsyncFunctionLoweringPass", data->GetMethodName(),
572                             data->GetMethodOffset(), data->GetLog());
573         bool enableLog = data->GetLog()->EnableMethodCIRLog() || data->GetLog()->OutputASM();
574         AsyncFunctionLowering lowering(data->GetBuilder(), data->GetCircuit(), data->GetCompilerConfig(),
575                                        enableLog, data->GetMethodName());
576         if (lowering.IsAsyncRelated()) {
577             lowering.ProcessAll();
578         }
579         return true;
580     }
581 };
582 } // namespace panda::ecmascript::kungfu
583 #endif
584