• 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 #ifndef ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
17 #define ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
18 
19 #include <algorithm>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23 
24 #include "ecmascript/compiler/argument_accessor.h"
25 #include "ecmascript/compiler/bytecode_info_collector.h"
26 #include "ecmascript/compiler/bytecodes.h"
27 #include "ecmascript/compiler/circuit.h"
28 #include "ecmascript/compiler/ecma_opcode_des.h"
29 #include "ecmascript/compiler/frame_states.h"
30 #include "ecmascript/compiler/pgo_type/pgo_type_recorder.h"
31 #include "ecmascript/jit/jit_profiler.h"
32 #include "ecmascript/jspandafile/js_pandafile.h"
33 #include "ecmascript/jspandafile/method_literal.h"
34 #include "libpandafile/index_accessor.h"
35 
36 namespace panda::ecmascript::kungfu {
37 struct ExceptionItem {
38     uint8_t* startPc;
39     uint8_t* endPc;
40     std::vector<uint8_t*> catches;
41 
ExceptionItemExceptionItem42     ExceptionItem(uint8_t* startPc, uint8_t* endPc, std::vector<uint8_t*> catches)
43         : startPc(startPc), endPc(endPc), catches(catches) {}
44 };
45 
46 using ExceptionInfo = std::vector<ExceptionItem>;
47 
48 class RegionItem {
49 public:
50     static constexpr uint32_t INVALID_BC_INDEX = static_cast<uint32_t>(-1);
51     bool operator<(const RegionItem &rhs) const
52     {
53         return this->startBcIndex_ < rhs.startBcIndex_;
54     }
55 
56     bool operator>(const RegionItem &rhs) const
57     {
58         return this->startBcIndex_ > rhs.startBcIndex_;
59     }
60 
61     bool operator==(const RegionItem &rhs) const
62     {
63         return this->startBcIndex_ == rhs.startBcIndex_;
64     }
65 
RegionItem(uint32_t startBcIndex,bool isHeadBlock)66     RegionItem(uint32_t startBcIndex, bool isHeadBlock)
67         : startBcIndex_(startBcIndex), isHeadBlock_(isHeadBlock) {}
68 
GetStartBcIndex()69     uint32_t GetStartBcIndex() const
70     {
71         return startBcIndex_;
72     }
73 
IsHeadBlock()74     uint32_t IsHeadBlock() const
75     {
76         return isHeadBlock_;
77     }
78 private:
79     uint32_t startBcIndex_ { INVALID_BC_INDEX };
80     bool isHeadBlock_ { false };
81     friend class RegionsInfo;
82 };
83 
84 struct BytecodeSplitItem {
BytecodeSplitItemBytecodeSplitItem85     BytecodeSplitItem(uint32_t start, uint32_t pred)
86         : startBcIndex(start), predBcIndex(pred) {}
87     uint32_t startBcIndex { RegionItem::INVALID_BC_INDEX };
88     uint32_t predBcIndex { RegionItem::INVALID_BC_INDEX };
89 };
90 
91 class RegionsInfo {
92 public:
InsertJump(uint32_t bcIndex,uint32_t predBcIndex,bool isJumpImm)93     void InsertJump(uint32_t bcIndex, uint32_t predBcIndex, bool isJumpImm)
94     {
95         InsertBlockItem(bcIndex, false);
96         auto fallThrogth = bcIndex - 1; // 1: fall through
97         // isJumpImm will not generate fall through
98         if (isJumpImm || fallThrogth != predBcIndex) {
99             InsertSplitItem(bcIndex, predBcIndex);
100         }
101     }
102 
InsertHead(uint32_t bcIndex)103     void InsertHead(uint32_t bcIndex)
104     {
105         InsertBlockItem(bcIndex, true);
106     }
107 
InsertSplit(uint32_t bcIndex)108     void InsertSplit(uint32_t bcIndex)
109     {
110         InsertBlockItem(bcIndex, false);
111     }
112 
FindBBIndexByBcIndex(uint32_t bcIndex)113     size_t FindBBIndexByBcIndex(uint32_t bcIndex) const
114     {
115         auto findFunc = [] (uint32_t value, const RegionItem &item) {
116             return value < item.startBcIndex_;
117         };
118         const auto &it = std::upper_bound(blockItems_.begin(),
119             blockItems_.end(), bcIndex, findFunc);
120         if (it == blockItems_.end()) {
121             return blockItems_.size();
122         }
123         // blockItems_[0]'s value is 0, bcIndex must be: bcIndex > blockItems_.begin()
124         return std::distance(blockItems_.begin(), it);
125     }
126 
GetSplitItems()127     const std::vector<BytecodeSplitItem> &GetSplitItems() const
128     {
129         return splitItems_;
130     }
131 
GetBlockItems()132     const std::set<RegionItem> &GetBlockItems() const
133     {
134         return blockItems_;
135     }
136 private:
InsertBlockItem(uint32_t bcIndex,bool isHeadBlock)137     void InsertBlockItem(uint32_t bcIndex, bool isHeadBlock)
138     {
139         auto result = blockItems_.insert(RegionItem { bcIndex, isHeadBlock });
140         if (!result.second && isHeadBlock) {
141             blockItems_.erase(result.first);
142             blockItems_.insert(RegionItem { bcIndex, isHeadBlock });
143         }
144     }
145 
InsertSplitItem(uint32_t bcIndex,uint32_t predBcIndex)146     void InsertSplitItem(uint32_t bcIndex, uint32_t predBcIndex)
147     {
148         splitItems_.emplace_back(BytecodeSplitItem { bcIndex, predBcIndex });
149     }
150     std::set<RegionItem> blockItems_ {};
151     std::vector<BytecodeSplitItem> splitItems_ {};
152 };
153 
154 struct BytecodeRegion {
155     size_t id {0};
156     uint32_t start {0};
157     uint32_t end {0};
158     ChunkVector<BytecodeRegion *> preds; // List of predessesor blocks
159     ChunkVector<BytecodeRegion *> succs; // List of successors blocks
160     ChunkVector<BytecodeRegion *> trys; // List of trys blocks
161     ChunkVector<BytecodeRegion *> catches; // List of catches blocks
162     ChunkSet<size_t> loopBacks;
163     size_t numOfLoopBack {0};
164     size_t numOfStatePreds {0};
165     size_t loopNumber {0};
166     size_t loopIndex {0};
167     ChunkVector<std::tuple<size_t, size_t, bool>> expandedPreds;
168     GateRef dependCache {Circuit::NullGate()};
169     BytecodeIterator bytecodeIterator_ {};
BytecodeRegionBytecodeRegion170     BytecodeRegion(Chunk* chunk) : preds(chunk), succs(chunk),
171         trys(chunk), catches(chunk), loopBacks(chunk), expandedPreds(chunk)
172     {
173     }
174 
GetBytecodeIteratorBytecodeRegion175     BytecodeIterator &GetBytecodeIterator()
176     {
177         return bytecodeIterator_;
178     }
179 
180     bool operator <(const BytecodeRegion &target) const
181     {
182         return id < target.id;
183     }
184 
SortCatchesBytecodeRegion185     void SortCatches()
186     {
187         if (catches.size() > 1) {
188             std::sort(catches.begin(), catches.end(), [](BytecodeRegion *first, BytecodeRegion *second) {
189                 return first->start < second->start;
190             });
191         }
192     }
193 
EraseThisBlockBytecodeRegion194     void EraseThisBlock(ChunkVector<BytecodeRegion *> &blocks)
195     {
196         auto it = std::find(blocks.begin(), blocks.end(), this);
197         if (it != blocks.end()) {
198             blocks.erase(it);
199         }
200     }
201 
IsEmptryBlockBytecodeRegion202     bool IsEmptryBlock() const
203     {
204         return end == static_cast<uint32_t>(BytecodeIterator::INVALID_INDEX);
205     }
206 
IsLoopBackBytecodeRegion207     bool IsLoopBack(const BytecodeRegion &bb) const
208     {
209         return loopBacks.find(bb.id) != loopBacks.end();
210     }
211 };
212 
213 using BytecodeGraph = ChunkVector<BytecodeRegion*>;
214 
215 class BytecodeCircuitBuilder {
216 public:
217     BytecodeCircuitBuilder(const JSPandaFile *jsPandaFile,
218                            const MethodLiteral *methodLiteral,
219                            const MethodPcInfo &methodPCInfo,
220                            Circuit *circuit,
221                            Bytecodes *bytecodes,
222                            bool enableLog,
223                            bool enableTypeLowering,
224                            std::string name,
225                            const CString &recordName,
226                            PGOProfilerDecoder *decoder,
227                            bool isInline,
228                            JITProfiler* jitProfiler = nullptr)
circuit_(circuit)229         : circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile),
230           method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_),
231           pgoTypeRecorder_(*decoder, jsPandaFile, method_->GetMethodId().GetOffset()),
232           enableLog_(enableLog), enableTypeLowering_(enableTypeLowering),
233           pcOffsets_(methodPCInfo.pcOffsets),
234           frameStateBuilder_(this, circuit, methodLiteral),
235           methodName_(name), recordName_(recordName),
236           bytecodes_(bytecodes),
237           loopHeaderGates_(circuit->chunk()),
238           preFrameState_(circuit_->GetRoot()),
239           preFrameArgs_(circuit_->GetRoot()),
240           isInline_(isInline),
241           methodId_(method_->GetMethodId().GetOffset())
242     {
243         if (jitProfiler != nullptr) {
244             pgoTypeRecorder_.InitMap(jitProfiler);
245         }
246     }
247     ~BytecodeCircuitBuilder() = default;
248     NO_COPY_SEMANTIC(BytecodeCircuitBuilder);
249     NO_MOVE_SEMANTIC(BytecodeCircuitBuilder);
250     void PUBLIC_API BytecodeToCircuit();
251     void CollectRegionInfo(uint32_t bcIndex);
252 
GetCircuit()253     [[nodiscard]] Circuit* GetCircuit() const
254     {
255         return circuit_;
256     }
257 
GetGateByBcIndex(uint32_t bcIndex)258     GateRef GetGateByBcIndex(uint32_t bcIndex) const
259     {
260         ASSERT(bcIndex < byteCodeToJSGates_.size());
261         if (byteCodeToJSGates_[bcIndex].size() > 0) {
262             ASSERT(byteCodeToJSGates_[bcIndex].size() == 1);
263             return byteCodeToJSGates_[bcIndex].at(0);
264         }
265         return Circuit::NullGate();
266     }
267 
GetGatesByBcIndex(uint32_t bcIndex)268     const std::vector<GateRef>& GetGatesByBcIndex(uint32_t bcIndex) const
269     {
270         ASSERT(bcIndex < byteCodeToJSGates_.size());
271         return byteCodeToJSGates_[bcIndex];
272     }
273 
GetBcIndexByGate(GateRef gate)274     uint32_t GetBcIndexByGate(GateRef gate) const
275     {
276         return jsGatesToByteCode_.at(gate);
277     }
278 
IsBcIndexByGate(GateRef gate)279     bool IsBcIndexByGate(GateRef gate) const
280     {
281         if (jsGatesToByteCode_.find(gate) == jsGatesToByteCode_.end()) {
282             return false;
283         }
284         return true;
285     }
286 
SetOsrOffset(int32_t offset)287     void SetOsrOffset(int32_t offset)
288     {
289         osrOffset_ = offset;
290     }
291 
NeedCheckSafePointAndStackOver()292     bool NeedCheckSafePointAndStackOver() const
293     {
294         return !isInline_ && !method_->IsNoGC();
295     }
296 
UpdateBcIndexGate(GateRef gate,uint32_t bcIndex)297     void UpdateBcIndexGate(GateRef gate, uint32_t bcIndex)
298     {
299         ASSERT(gateAcc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
300         ASSERT(bcIndex < byteCodeToJSGates_.size());
301         byteCodeToJSGates_[bcIndex].emplace_back(gate);
302         jsGatesToByteCode_[gate] = bcIndex;
303     }
304 
GetMethod()305     [[nodiscard]] const MethodLiteral* GetMethod() const
306     {
307         return method_;
308     }
309 
GetJSPandaFile()310     [[nodiscard]] const JSPandaFile *GetJSPandaFile() const
311     {
312         return file_;
313     }
314 
GetMethodName()315     const std::string& GetMethodName() const
316     {
317         return methodName_;
318     }
319 
IsLogEnabled()320     bool IsLogEnabled() const
321     {
322         return enableLog_;
323     }
324 
IsTypeLoweringEnabled()325     bool IsTypeLoweringEnabled() const
326     {
327         return enableTypeLowering_;
328     }
329 
GetAsyncRelatedGates()330     [[nodiscard]] const std::vector<GateRef>& GetAsyncRelatedGates() const
331     {
332         return suspendAndResumeGates_;
333     }
334 
UpdateAsyncRelatedGate(GateRef gate)335     void UpdateAsyncRelatedGate(GateRef gate)
336     {
337         suspendAndResumeGates_.emplace_back(gate);
338     };
339 
340     template <class Callback>
EnumerateBlock(BytecodeRegion & bb,const Callback & cb)341     void EnumerateBlock(BytecodeRegion &bb, const Callback &cb)
342     {
343         auto &iterator = bb.GetBytecodeIterator();
344         iterator.GotoStart();
345         while (!iterator.Done()) {
346             auto &bytecodeInfo = iterator.GetBytecodeInfo();
347             bool ret = cb(bytecodeInfo);
348             if (!ret) {
349                 break;
350             }
351             ++iterator;
352         }
353     }
354 
GetBasicBlockById(size_t id)355     BytecodeRegion &GetBasicBlockById(size_t id)
356     {
357         ASSERT(id < graph_.size());
358         return RegionAt(id);
359     }
360 
AddBasicBlock(BytecodeRegion * region)361     void AddBasicBlock(BytecodeRegion* region)
362     {
363         graph_.emplace_back(region);
364     }
365 
GetBasicBlockCount()366     size_t GetBasicBlockCount() const
367     {
368         return graph_.size();
369     }
370 
GetPcOffset(const uint8_t * pc)371     size_t GetPcOffset(const uint8_t *pc) const
372     {
373         return static_cast<size_t>(pc - method_->GetBytecodeArray());
374     }
375 
GetPcOffset(uint32_t bcIndex)376     size_t GetPcOffset(uint32_t bcIndex) const
377     {
378         const uint8_t* pc = GetPCByIndex(bcIndex);
379         return GetPcOffset(pc);
380     }
381 
GetPcOffsetByGate(GateRef gate)382     size_t GetPcOffsetByGate(GateRef gate) const
383     {
384         return GetPcOffset(jsGatesToByteCode_.at(gate));
385     }
386 
GetElementsKindsForUser(GateRef gate)387     std::vector<ElementsKind> GetElementsKindsForUser(GateRef gate) const
388     {
389         return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate));
390     }
391 
GetTransitionElementsKindsForUser(GateRef gate)392     PUBLIC_API std::vector<ElementsKind> GetTransitionElementsKindsForUser(GateRef gate) const
393     {
394         return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate));
395     }
396 
GetElementsKindForCreater(GateRef gate)397     ElementsKind GetElementsKindForCreater(GateRef gate) const
398     {
399         return pgoTypeRecorder_.GetElementsKindForCreater(gateAcc_.TryGetPcOffset(gate));
400     }
401 
GetArrayElementsLength(GateRef gate)402     uint32_t GetArrayElementsLength(GateRef gate) const
403     {
404         return pgoTypeRecorder_.GetElementsLength(gateAcc_.TryGetPcOffset(gate));
405     }
406 
GetRegionSpaceFlag(GateRef gate)407     RegionSpaceFlag GetRegionSpaceFlag(GateRef gate) const
408     {
409         return pgoTypeRecorder_.GetRegionSpaceFlag(gateAcc_.TryGetPcOffset(gate));
410     }
411 
ShouldPGOTypeInfer(GateRef gate)412     bool ShouldPGOTypeInfer(GateRef gate) const
413     {
414         return jsGatesToByteCode_.find(gate) != jsGatesToByteCode_.end();
415     }
416 
GetNumberVRegs()417     size_t GetNumberVRegs() const
418     {
419         return static_cast<size_t>(method_->GetNumberVRegs());
420     }
421 
GetNumberVRegsWithEnv()422     size_t GetNumberVRegsWithEnv() const
423     {
424         return GetNumberVRegs() + 1; // 1: env variable
425     }
426 
GetEnvVregIdx()427     size_t GetEnvVregIdx() const
428     {
429         return GetNumberVRegs();
430     }
431 
GetBytecodes()432     Bytecodes *GetBytecodes() const
433     {
434         return bytecodes_;
435     }
436 
GetLastBcIndex()437     uint32_t GetLastBcIndex() const
438     {
439         ASSERT(pcOffsets_.size() > 0);
440         return static_cast<uint32_t>(pcOffsets_.size() - 1);
441     }
442 
GetPCByIndex(uint32_t index)443     const uint8_t *GetPCByIndex(uint32_t index) const
444     {
445         ASSERT(index <= GetLastBcIndex());
446         return pcOffsets_[index];
447     }
448 
GetFirstPC()449     const uint8_t *GetFirstPC() const
450     {
451         return GetPCByIndex(0);
452     }
453 
GetLastPC()454     const uint8_t *GetLastPC() const
455     {
456         return GetPCByIndex(GetLastBcIndex());
457     }
458 
FindBcIndexByPc(const uint8_t * pc)459     uint32_t FindBcIndexByPc(const uint8_t *pc) const
460     {
461         auto begin = pcOffsets_.begin();
462         auto end = pcOffsets_.end();
463         auto it = std::lower_bound(begin, end, pc);
464         ASSERT(it != end);
465         ASSERT(*it == pc);
466         return std::distance(begin, it);
467     }
468 
GetBytecodeInfo(uint32_t index)469     const BytecodeInfo &GetBytecodeInfo(uint32_t index) const
470     {
471         return infoData_[index];
472     }
473 
HasTryCatch()474     bool HasTryCatch() const
475     {
476         return hasTryCatch_;
477     }
478 
EnableLoopOptimization()479     bool EnableLoopOptimization() const
480     {
481         return (!HasTryCatch()) && frameStateBuilder_.HasLoop();
482     }
483 
484     void RemoveUnreachableRegion();
485 
486     void RemoveInsufficientProfileRegion();
487 
488     void RemoveIsolatedRegion();
489 
GetFrameArgs()490     GateRef GetFrameArgs() const
491     {
492         return argAcc_.GetFrameArgs();
493     }
494 
GetPreFrameState()495     GateRef GetPreFrameState() const
496     {
497         return preFrameState_;
498     }
499 
SetPreFrameState(GateRef gate)500     void SetPreFrameState(GateRef gate)
501     {
502         preFrameState_ = gate;
503     }
504 
GetPreFrameArgs()505     GateRef GetPreFrameArgs() const
506     {
507         return preFrameArgs_;
508     }
509 
SetPreFrameArgs(GateRef gate)510     void SetPreFrameArgs(GateRef gate)
511     {
512         preFrameArgs_ = gate;
513     }
514 
IsEntryBlock(const size_t bbId)515     inline bool IsEntryBlock(const size_t bbId) const
516     {
517         return bbId == 0;
518     }
519 
IsFirstBasicBlock(const size_t bbId)520     inline bool IsFirstBasicBlock(const size_t bbId) const
521     {
522         return bbId == 1;
523     }
524 
GetPGOTypeRecorder()525     const PGOTypeRecorder *GetPGOTypeRecorder() const
526     {
527         return &pgoTypeRecorder_;
528     }
529 
GetArgGate(const size_t currentVreg)530     GateRef GetArgGate(const size_t currentVreg) const
531     {
532         return argAcc_.GetArgGate(currentVreg);
533     }
534 
ArgGateNotExisted(const size_t currentVreg)535     GateRef ArgGateNotExisted(const size_t currentVreg)
536     {
537         return argAcc_.ArgGateNotExisted(currentVreg);
538     }
539 
GetLoopHeaderGates()540     ChunkVector<GateRef>& GetLoopHeaderGates()
541     {
542         return loopHeaderGates_;
543     }
544 
NumberOfLiveBlock()545     size_t NumberOfLiveBlock() const
546     {
547         return numOfLiveBB_;
548     }
549 
GetCurrentConstpoolId()550     int32_t GetCurrentConstpoolId() const
551     {
552         panda_file::IndexAccessor indexAccessor(*file_->GetPandaFile(), panda_file::File::EntityId(methodId_));
553         return static_cast<int32_t>(indexAccessor.GetHeaderIndex());
554     }
555 
GetCurrentConstpool(GateRef jsFunc,GateRef & sharedConstPool,GateRef & unSharedConstPool)556     void GetCurrentConstpool(GateRef jsFunc, GateRef &sharedConstPool, GateRef &unSharedConstPool)
557     {
558         int32_t constpoolId = GetCurrentConstpoolId();
559         if (gateAcc_.GetOpCode(preFrameArgs_) == OpCode::CIRCUIT_ROOT) {
560             sharedConstPool = circuit_->NewGate(circuit_->GetSharedConstPool(constpoolId), MachineType::I64, {jsFunc},
561                                                 GateType::AnyType());
562             unSharedConstPool = circuit_->NewGate(circuit_->GetUnsharedConstPool(), MachineType::I64,
563                                                   {sharedConstPool}, GateType::AnyType());
564         }
565         GateRef frameArgs = preFrameArgs_;
566         GateRef preSharedConstPool = Circuit::NullGate();
567         GateRef preUnsharedConstPool = Circuit::NullGate();
568         int32_t preConstpoolId = 0;
569         while (gateAcc_.GetOpCode(frameArgs) != OpCode::CIRCUIT_ROOT) {
570             preSharedConstPool = gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::SHARED_CONST_POOL));
571             preUnsharedConstPool =
572                 gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::UNSHARED_CONST_POOL));
573             preConstpoolId = static_cast<int32_t>(gateAcc_.GetConstpoolId(preSharedConstPool));
574             if (preConstpoolId == constpoolId) {
575                 sharedConstPool = preSharedConstPool;
576                 unSharedConstPool = preUnsharedConstPool;
577                 break;
578             }
579             frameArgs = gateAcc_.GetFrameState(frameArgs);
580         }
581     }
582 
SetIrreducibleLoop()583     void SetIrreducibleLoop()
584     {
585         isIrreducible_ = true;
586     }
587 
HasIrreducibleLoop()588     bool HasIrreducibleLoop() const
589     {
590         return isIrreducible_;
591     }
592 
SetJitCompile()593     void SetJitCompile()
594     {
595         isJitCompile_ = true;
596     }
597 
IsJitCompile()598     bool IsJitCompile() const
599     {
600         return isJitCompile_;
601     }
602 
SetPreAnalysis()603     void SetPreAnalysis()
604     {
605         preAnalysis_ = true;
606     }
607 
IsPreAnalysis()608     bool IsPreAnalysis() const
609     {
610         return preAnalysis_;
611     }
612 
NeedIrreducibleLoopCheck()613     bool NeedIrreducibleLoopCheck() const
614     {
615         return IsPreAnalysis() || IsJitCompile();
616     }
617 
TerminateAnalysis()618     bool TerminateAnalysis() const
619     {
620         return IsPreAnalysis() || HasIrreducibleLoop();
621     }
622 
IsOSR()623     bool IsOSR() const
624     {
625         return osrOffset_ != MachineCode::INVALID_OSR_OFFSET;
626     }
627 
IsCacheBBOfOSRLoop(const BytecodeRegion & bb)628     bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const
629     {
630         return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end();
631     }
632 
633     void ComputeNumOfLoopBack();
634 
635     enum class MarkState : uint8_t {
636         UNVISITED = 0,
637         ON_STACK,
638         PENDING,
639         VISITED,
640         VISITED1,
641         UNVISITED1 = VISITED
642     };
643 
644     struct VisitedInfo {
645         size_t needVisitIndex;
646         bool isVisitedCatchBlock = false;
647     };
648     bool IsAncestor(size_t nodeA, size_t nodeB);
649 
650 private:
651     void CollectTryCatchBlockInfo(ExceptionInfo &Exception);
652     void BuildCatchBlocks(const ExceptionInfo &Exception);
653     void BuildEntryBlock();
654     void BuildBasicBlock();
655     void BuildRegions(const ExceptionInfo &Exception);
656     // build circuit
657     void BuildCircuitArgs();
658     void BuildOSRArgs();
659     std::vector<GateRef> CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta);
660     GateRef NewDeopt(BytecodeRegion &bb);
661     GateRef NewConst(const BytecodeInfo &info);
662     void NewJSGate(BytecodeRegion &bb);
663     void NewJump(BytecodeRegion &bbd);
664     GateRef NewReturn(BytecodeRegion &bb);
665     void NewByteCode(BytecodeRegion &bb);
666     void MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex);
667     void MergeExceptionGete(BytecodeRegion &bb, const BytecodeInfo& bytecodeInfo, uint32_t bcIndex);
668     void BuildSubCircuit();
669     bool FindOsrLoopHeadBB();
670     void GenDeoptAndReturnForOsrLoopExit(BytecodeRegion& osrLoopExitBB);
671     void CollectCacheBBforOSRLoop(BytecodeRegion *bb);
672     void HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB);
673     void BuildOsrCircuit();
674 
675     void UpdateCFG();
676     void CollectTryPredsInfo();
677     void ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList, bool skipInsufficientProfile = false);
678     void RemoveUnusedPredsInfo(BytecodeRegion& bb, bool skipInsufficientProfile);
679     void BuildCircuit();
680     void PrintGraph();
681     void PrintBBInfo();
682     void PrintGraph(const char* title);
683     void PrintBytecodeInfo(BytecodeRegion& region);
684     void PrintDefsitesInfo(const std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo);
685     void BuildRegionInfo();
686     void BuildFrameArgs();
687     void RemoveIfInRpoList(BytecodeRegion *bb);
688     void PerformDFS(const std::vector<size_t> &immDom, size_t listSize);
689     void ReducibilityCheck();
690     void ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
691                                     std::unordered_map<size_t, size_t> &dfsFatherIdx, std::vector<size_t> &immDom,
692                                     std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
693     void ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
694         std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
695 
RegionAt(size_t i)696     BytecodeRegion &RegionAt(size_t i)
697     {
698         return *graph_[i];
699     }
700 
701     Circuit *circuit_;
702     std::vector<std::vector<GateRef>> byteCodeToJSGates_;
703     std::unordered_map<GateRef, size_t> jsGatesToByteCode_;
704     BytecodeGraph graph_;
705     const JSPandaFile *file_ {nullptr};
706     const MethodLiteral *method_ {nullptr};
707     GateAccessor gateAcc_;
708     ArgumentAccessor argAcc_;
709     PGOTypeRecorder pgoTypeRecorder_;
710     int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET};
711     bool enableLog_ {false};
712     bool enableTypeLowering_ {false};
713     std::vector<GateRef> suspendAndResumeGates_ {};
714     std::vector<const uint8_t*> pcOffsets_;
715     FrameStateBuilder frameStateBuilder_;
716     std::string methodName_;
717     const CString &recordName_;
718     Bytecodes *bytecodes_;
719     RegionsInfo regionsInfo_{};
720     std::vector<BytecodeInfo> infoData_ {};
721     bool hasTryCatch_ {false};
722     ChunkVector<GateRef> loopHeaderGates_;
723     GateRef preFrameState_ {Circuit::NullGate()};
724     GateRef preFrameArgs_ {Circuit::NullGate()};
725     size_t numOfLiveBB_ {0};
726     bool isInline_ {false};
727     uint32_t methodId_ {0};
728     bool preAnalysis_ {false};
729     std::set<const BytecodeRegion *> catchBBOfOSRLoop_{};
730     bool isIrreducible_ {false};
731     bool isJitCompile_ {false};
732     CVector<size_t> timeIn_ {};
733     CVector<size_t> timeOut_ {};
734     std::unordered_map<size_t, size_t> bbIdToDfsTimestamp_ {};
735 };
736 }  // namespace panda::ecmascript::kungfu
737 #endif  // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
738