• 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_ {};
170     bool IsEmptyCatchBB {false}; // For empty catch BB
BytecodeRegionBytecodeRegion171     BytecodeRegion(Chunk* chunk) : preds(chunk), succs(chunk),
172         trys(chunk), catches(chunk), loopBacks(chunk), expandedPreds(chunk)
173     {
174     }
175 
GetBytecodeIteratorBytecodeRegion176     BytecodeIterator &GetBytecodeIterator()
177     {
178         return bytecodeIterator_;
179     }
180 
181     bool operator <(const BytecodeRegion &target) const
182     {
183         return id < target.id;
184     }
185 
SortCatchesBytecodeRegion186     void SortCatches()
187     {
188         if (catches.size() > 1) {
189             std::sort(catches.begin(), catches.end(), [](BytecodeRegion *first, BytecodeRegion *second) {
190                 return first->start < second->start;
191             });
192         }
193     }
194 
EraseThisBlockBytecodeRegion195     void EraseThisBlock(ChunkVector<BytecodeRegion *> &blocks)
196     {
197         auto it = std::find(blocks.begin(), blocks.end(), this);
198         if (it != blocks.end()) {
199             blocks.erase(it);
200         }
201     }
202 
IsEmptryBlockBytecodeRegion203     bool IsEmptryBlock() const
204     {
205         return end == static_cast<uint32_t>(BytecodeIterator::INVALID_INDEX);
206     }
207 
IsLoopBackBytecodeRegion208     bool IsLoopBack(const BytecodeRegion &bb) const
209     {
210         return loopBacks.find(bb.id) != loopBacks.end();
211     }
212 };
213 
214 using BytecodeGraph = ChunkVector<BytecodeRegion*>;
215 
216 class BytecodeCircuitBuilder {
217 public:
218     BytecodeCircuitBuilder(const JSPandaFile *jsPandaFile,
219                            const MethodLiteral *methodLiteral,
220                            const MethodPcInfo &methodPCInfo,
221                            Circuit *circuit,
222                            Bytecodes *bytecodes,
223                            bool enableLog,
224                            bool enableTypeLowering,
225                            std::string name,
226                            const CString &recordName,
227                            PGOProfilerDecoder *decoder,
228                            bool isInline,
229                            JITProfiler* jitProfiler = nullptr)
circuit_(circuit)230         : circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile),
231           method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_),
232           pgoTypeRecorder_(*decoder, jsPandaFile, method_->GetMethodId().GetOffset()),
233           enableLog_(enableLog), enableTypeLowering_(enableTypeLowering),
234           pcOffsets_(methodPCInfo.pcOffsets),
235           frameStateBuilder_(this, circuit, methodLiteral),
236           methodName_(name), recordName_(recordName),
237           bytecodes_(bytecodes),
238           loopHeaderGates_(circuit->chunk()),
239           preFrameState_(circuit_->GetRoot()),
240           preFrameArgs_(circuit_->GetRoot()),
241           isInline_(isInline),
242           methodId_(method_->GetMethodId().GetOffset())
243     {
244         if (jitProfiler != nullptr) {
245             pgoTypeRecorder_.InitMap(jitProfiler);
246         }
247     }
248     ~BytecodeCircuitBuilder() = default;
249     NO_COPY_SEMANTIC(BytecodeCircuitBuilder);
250     NO_MOVE_SEMANTIC(BytecodeCircuitBuilder);
251     void PUBLIC_API BytecodeToCircuit();
252     void CollectRegionInfo(uint32_t bcIndex);
253 
GetCircuit()254     [[nodiscard]] Circuit* GetCircuit() const
255     {
256         return circuit_;
257     }
258 
GetGateByBcIndex(uint32_t bcIndex)259     GateRef GetGateByBcIndex(uint32_t bcIndex) const
260     {
261         ASSERT(bcIndex < byteCodeToJSGates_.size());
262         if (byteCodeToJSGates_[bcIndex].size() > 0) {
263             ASSERT(byteCodeToJSGates_[bcIndex].size() == 1);
264             return byteCodeToJSGates_[bcIndex].at(0);
265         }
266         return Circuit::NullGate();
267     }
268 
GetGatesByBcIndex(uint32_t bcIndex)269     const std::vector<GateRef>& GetGatesByBcIndex(uint32_t bcIndex) const
270     {
271         ASSERT(bcIndex < byteCodeToJSGates_.size());
272         return byteCodeToJSGates_[bcIndex];
273     }
274 
GetBcIndexByGate(GateRef gate)275     uint32_t GetBcIndexByGate(GateRef gate) const
276     {
277         return jsGatesToByteCode_.at(gate);
278     }
279 
IsBcIndexByGate(GateRef gate)280     bool IsBcIndexByGate(GateRef gate) const
281     {
282         if (jsGatesToByteCode_.find(gate) == jsGatesToByteCode_.end()) {
283             return false;
284         }
285         return true;
286     }
287 
SetOsrOffset(int32_t offset)288     void SetOsrOffset(int32_t offset)
289     {
290         osrOffset_ = offset;
291     }
292 
NeedCheckSafePointAndStackOver()293     bool NeedCheckSafePointAndStackOver() const
294     {
295         return !isInline_ && !method_->IsNoGC();
296     }
297 
UpdateBcIndexGate(GateRef gate,uint32_t bcIndex)298     void UpdateBcIndexGate(GateRef gate, uint32_t bcIndex)
299     {
300         ASSERT(gateAcc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
301         ASSERT(bcIndex < byteCodeToJSGates_.size());
302         byteCodeToJSGates_[bcIndex].emplace_back(gate);
303         jsGatesToByteCode_[gate] = bcIndex;
304     }
305 
GetMethod()306     [[nodiscard]] const MethodLiteral* GetMethod() const
307     {
308         return method_;
309     }
310 
GetJSPandaFile()311     [[nodiscard]] const JSPandaFile *GetJSPandaFile() const
312     {
313         return file_;
314     }
315 
GetMethodName()316     const std::string& GetMethodName() const
317     {
318         return methodName_;
319     }
320 
IsLogEnabled()321     bool IsLogEnabled() const
322     {
323         return enableLog_;
324     }
325 
IsTypeLoweringEnabled()326     bool IsTypeLoweringEnabled() const
327     {
328         return enableTypeLowering_;
329     }
330 
GetAsyncRelatedGates()331     [[nodiscard]] const std::vector<GateRef>& GetAsyncRelatedGates() const
332     {
333         return suspendAndResumeGates_;
334     }
335 
UpdateAsyncRelatedGate(GateRef gate)336     void UpdateAsyncRelatedGate(GateRef gate)
337     {
338         suspendAndResumeGates_.emplace_back(gate);
339     };
340 
341     template <class Callback>
EnumerateBlock(BytecodeRegion & bb,const Callback & cb)342     void EnumerateBlock(BytecodeRegion &bb, const Callback &cb)
343     {
344         auto &iterator = bb.GetBytecodeIterator();
345         iterator.GotoStart();
346         while (!iterator.Done()) {
347             auto &bytecodeInfo = iterator.GetBytecodeInfo();
348             bool ret = cb(bytecodeInfo);
349             if (!ret) {
350                 break;
351             }
352             ++iterator;
353         }
354     }
355 
GetBasicBlockById(size_t id)356     BytecodeRegion &GetBasicBlockById(size_t id)
357     {
358         ASSERT(id < graph_.size());
359         return RegionAt(id);
360     }
361 
AddBasicBlock(BytecodeRegion * region)362     void AddBasicBlock(BytecodeRegion* region)
363     {
364         graph_.emplace_back(region);
365     }
366 
GetBasicBlockCount()367     size_t GetBasicBlockCount() const
368     {
369         return graph_.size();
370     }
371 
GetPcOffset(const uint8_t * pc)372     size_t GetPcOffset(const uint8_t *pc) const
373     {
374         return static_cast<size_t>(pc - method_->GetBytecodeArray());
375     }
376 
GetPcOffset(uint32_t bcIndex)377     size_t GetPcOffset(uint32_t bcIndex) const
378     {
379         const uint8_t* pc = GetPCByIndex(bcIndex);
380         return GetPcOffset(pc);
381     }
382 
GetPcOffsetByGate(GateRef gate)383     size_t GetPcOffsetByGate(GateRef gate) const
384     {
385         return GetPcOffset(jsGatesToByteCode_.at(gate));
386     }
387 
GetElementsKindsForUser(GateRef gate)388     std::vector<ElementsKind> GetElementsKindsForUser(GateRef gate) const
389     {
390         return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate));
391     }
392 
GetTransitionElementsKindsForUser(GateRef gate)393     PUBLIC_API std::vector<ElementsKind> GetTransitionElementsKindsForUser(GateRef gate) const
394     {
395         return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate));
396     }
397 
GetElementsKindForCreater(GateRef gate)398     ElementsKind GetElementsKindForCreater(GateRef gate) const
399     {
400         return pgoTypeRecorder_.GetElementsKindForCreater(gateAcc_.TryGetPcOffset(gate));
401     }
402 
GetArrayElementsLength(GateRef gate)403     uint32_t GetArrayElementsLength(GateRef gate) const
404     {
405         return pgoTypeRecorder_.GetElementsLength(gateAcc_.TryGetPcOffset(gate));
406     }
407 
ShouldPGOTypeInfer(GateRef gate)408     bool ShouldPGOTypeInfer(GateRef gate) const
409     {
410         return jsGatesToByteCode_.find(gate) != jsGatesToByteCode_.end();
411     }
412 
GetNumberVRegs()413     size_t GetNumberVRegs() const
414     {
415         return static_cast<size_t>(method_->GetNumberVRegs());
416     }
417 
GetNumberVRegsWithEnv()418     size_t GetNumberVRegsWithEnv() const
419     {
420         return GetNumberVRegs() + 1; // 1: env variable
421     }
422 
GetEnvVregIdx()423     size_t GetEnvVregIdx() const
424     {
425         return GetNumberVRegs();
426     }
427 
GetBytecodes()428     Bytecodes *GetBytecodes() const
429     {
430         return bytecodes_;
431     }
432 
GetLastBcIndex()433     uint32_t GetLastBcIndex() const
434     {
435         ASSERT(pcOffsets_.size() > 0);
436         return static_cast<uint32_t>(pcOffsets_.size() - 1);
437     }
438 
GetPCByIndex(uint32_t index)439     const uint8_t *GetPCByIndex(uint32_t index) const
440     {
441         ASSERT(index <= GetLastBcIndex());
442         return pcOffsets_[index];
443     }
444 
GetFirstPC()445     const uint8_t *GetFirstPC() const
446     {
447         return GetPCByIndex(0);
448     }
449 
GetLastPC()450     const uint8_t *GetLastPC() const
451     {
452         return GetPCByIndex(GetLastBcIndex());
453     }
454 
FindBcIndexByPc(const uint8_t * pc)455     uint32_t FindBcIndexByPc(const uint8_t *pc) const
456     {
457         auto begin = pcOffsets_.begin();
458         auto end = pcOffsets_.end();
459         auto it = std::lower_bound(begin, end, pc);
460         ASSERT(it != end);
461         ASSERT(*it == pc);
462         return std::distance(begin, it);
463     }
464 
GetBytecodeInfo(uint32_t index)465     const BytecodeInfo &GetBytecodeInfo(uint32_t index) const
466     {
467         return infoData_[index];
468     }
469 
HasTryCatch()470     bool HasTryCatch() const
471     {
472         return hasTryCatch_;
473     }
474 
EnableLoopOptimization()475     bool EnableLoopOptimization() const
476     {
477         return (!HasTryCatch()) && frameStateBuilder_.HasLoop();
478     }
479 
480     void RemoveUnreachableRegion();
481 
GetFrameArgs()482     GateRef GetFrameArgs() const
483     {
484         return argAcc_.GetFrameArgs();
485     }
486 
GetPreFrameState()487     GateRef GetPreFrameState() const
488     {
489         return preFrameState_;
490     }
491 
SetPreFrameState(GateRef gate)492     void SetPreFrameState(GateRef gate)
493     {
494         preFrameState_ = gate;
495     }
496 
GetPreFrameArgs()497     GateRef GetPreFrameArgs() const
498     {
499         return preFrameArgs_;
500     }
501 
SetPreFrameArgs(GateRef gate)502     void SetPreFrameArgs(GateRef gate)
503     {
504         preFrameArgs_ = gate;
505     }
506 
IsEntryBlock(const size_t bbId)507     inline bool IsEntryBlock(const size_t bbId) const
508     {
509         return bbId == 0;
510     }
511 
IsFirstBasicBlock(const size_t bbId)512     inline bool IsFirstBasicBlock(const size_t bbId) const
513     {
514         return bbId == 1;
515     }
516 
GetPGOTypeRecorder()517     const PGOTypeRecorder *GetPGOTypeRecorder() const
518     {
519         return &pgoTypeRecorder_;
520     }
521 
GetArgGate(const size_t currentVreg)522     GateRef GetArgGate(const size_t currentVreg) const
523     {
524         return argAcc_.GetArgGate(currentVreg);
525     }
526 
ArgGateNotExisted(const size_t currentVreg)527     GateRef ArgGateNotExisted(const size_t currentVreg)
528     {
529         return argAcc_.ArgGateNotExisted(currentVreg);
530     }
531 
GetLoopHeaderGates()532     ChunkVector<GateRef>& GetLoopHeaderGates()
533     {
534         return loopHeaderGates_;
535     }
536 
NumberOfLiveBlock()537     size_t NumberOfLiveBlock() const
538     {
539         return numOfLiveBB_;
540     }
541 
GetCurrentConstpoolId()542     int32_t GetCurrentConstpoolId() const
543     {
544         panda_file::IndexAccessor indexAccessor(*file_->GetPandaFile(), panda_file::File::EntityId(methodId_));
545         return static_cast<int32_t>(indexAccessor.GetHeaderIndex());
546     }
547 
GetCurrentConstpool(GateRef jsFunc,GateRef & sharedConstPool,GateRef & unSharedConstPool)548     void GetCurrentConstpool(GateRef jsFunc, GateRef &sharedConstPool, GateRef &unSharedConstPool)
549     {
550         int32_t constpoolId = GetCurrentConstpoolId();
551         if (gateAcc_.GetOpCode(preFrameArgs_) == OpCode::CIRCUIT_ROOT) {
552             sharedConstPool = circuit_->NewGate(circuit_->GetSharedConstPool(constpoolId), MachineType::I64, {jsFunc},
553                                                 GateType::AnyType());
554             unSharedConstPool = circuit_->NewGate(circuit_->GetUnsharedConstPool(), MachineType::I64,
555                                                   {sharedConstPool}, GateType::AnyType());
556         }
557         GateRef frameArgs = preFrameArgs_;
558         GateRef preSharedConstPool = Circuit::NullGate();
559         GateRef preUnsharedConstPool = Circuit::NullGate();
560         int32_t preConstpoolId = 0;
561         while (gateAcc_.GetOpCode(frameArgs) != OpCode::CIRCUIT_ROOT) {
562             preSharedConstPool = gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::SHARED_CONST_POOL));
563             preUnsharedConstPool =
564                 gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::UNSHARED_CONST_POOL));
565             preConstpoolId = static_cast<int32_t>(gateAcc_.GetConstpoolId(preSharedConstPool));
566             if (preConstpoolId == constpoolId) {
567                 sharedConstPool = preSharedConstPool;
568                 unSharedConstPool = preUnsharedConstPool;
569                 break;
570             }
571             frameArgs = gateAcc_.GetFrameState(frameArgs);
572         }
573     }
574 
SetIrreducibleLoop()575     void SetIrreducibleLoop()
576     {
577         isIrreducible_ = true;
578     }
579 
HasIrreducibleLoop()580     bool HasIrreducibleLoop() const
581     {
582         return isIrreducible_;
583     }
584 
SetJitCompile()585     void SetJitCompile()
586     {
587         isJitCompile_ = true;
588     }
589 
IsJitCompile()590     bool IsJitCompile() const
591     {
592         return isJitCompile_;
593     }
594 
SetPreAnalysis()595     void SetPreAnalysis()
596     {
597         preAnalysis_ = true;
598     }
599 
IsPreAnalysis()600     bool IsPreAnalysis() const
601     {
602         return preAnalysis_;
603     }
604 
HasEmptyCatchBB()605     bool HasEmptyCatchBB() const
606     {
607         return hasEmptyCatchBB_;
608     }
609 
NeedIrreducibleLoopCheck()610     bool NeedIrreducibleLoopCheck() const
611     {
612         return IsPreAnalysis() || IsJitCompile();
613     }
614 
TerminateAnalysis()615     bool TerminateAnalysis() const
616     {
617         return IsPreAnalysis() || HasIrreducibleLoop();
618     }
619 
IsOSR()620     bool IsOSR() const
621     {
622         return osrOffset_ != MachineCode::INVALID_OSR_OFFSET;
623     }
624 
IsCacheBBOfOSRLoop(const BytecodeRegion & bb)625     bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const
626     {
627         return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end();
628     }
629 
630     enum class MarkState : uint8_t {
631         UNVISITED = 0,
632         ON_STACK,
633         PENDING,
634         VISITED,
635         VISITED1,
636         UNVISITED1 = VISITED
637     };
638 
639     struct VisitedInfo {
640         size_t needVisitIndex;
641         bool isVisitedCatchBlock = false;
642     };
643     bool IsAncestor(size_t nodeA, size_t nodeB);
644     void ComputeNumOfLoopBack();
645 
646 private:
647     void CollectTryCatchBlockInfo(ExceptionInfo &Exception);
648     void BuildCatchBlocks(const ExceptionInfo &Exception);
649     void BuildEntryBlock();
650     void BuildBasicBlock();
651     void BuildRegions(const ExceptionInfo &Exception);
652     // build circuit
653     void BuildCircuitArgs();
654     void BuildOSRArgs();
655     std::vector<GateRef> CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta);
656     GateRef NewConst(const BytecodeInfo &info);
657     void NewJSGate(BytecodeRegion &bb);
658     void NewJump(BytecodeRegion &bbd);
659     GateRef NewReturn(BytecodeRegion &bb);
660     void NewByteCode(BytecodeRegion &bb);
661     void MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex);
662     void MergeExceptionGete(BytecodeRegion &bb, const BytecodeInfo& bytecodeInfo, uint32_t bcIndex);
663     void BuildSubCircuit();
664     bool FindOsrLoopHeadBB();
665     void GenDeoptAndReturnForOsrLoopExit(BytecodeRegion& osrLoopExitBB);
666     void CollectCacheBBforOSRLoop(BytecodeRegion *bb);
667     void HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB);
668     void BuildOsrCircuit();
669 
670     void UpdateEmptyCatchBB();
671     void UpdateCFG();
672     void CollectTryPredsInfo();
673     void ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList);
674     void RemoveUnusedPredsInfo(BytecodeRegion& bb);
675     void BuildCircuit();
676     void PrintGraph();
677     void PrintBBInfo();
678     void PrintGraph(const char* title);
679     void PrintBytecodeInfo(BytecodeRegion& region);
680     void PrintDefsitesInfo(const std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo);
681     void BuildRegionInfo();
682     void BuildFrameArgs();
683     void RemoveIfInRpoList(BytecodeRegion *bb);
684     void PerformDFS(const std::vector<size_t> &immDom, size_t listSize);
685     void ReducibilityCheck();
686     void ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
687                                     std::unordered_map<size_t, size_t> &dfsFatherIdx, std::vector<size_t> &immDom,
688                                     std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
689     void ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
690         std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
691 
RegionAt(size_t i)692     BytecodeRegion &RegionAt(size_t i)
693     {
694         return *graph_[i];
695     }
696 
697     Circuit *circuit_;
698     std::vector<std::vector<GateRef>> byteCodeToJSGates_;
699     std::unordered_map<GateRef, size_t> jsGatesToByteCode_;
700     BytecodeGraph graph_;
701     const JSPandaFile *file_ {nullptr};
702     const MethodLiteral *method_ {nullptr};
703     GateAccessor gateAcc_;
704     ArgumentAccessor argAcc_;
705     PGOTypeRecorder pgoTypeRecorder_;
706     int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET};
707     bool enableLog_ {false};
708     bool enableTypeLowering_ {false};
709     std::vector<GateRef> suspendAndResumeGates_ {};
710     std::vector<const uint8_t*> pcOffsets_;
711     FrameStateBuilder frameStateBuilder_;
712     std::string methodName_;
713     const CString &recordName_;
714     Bytecodes *bytecodes_;
715     RegionsInfo regionsInfo_{};
716     std::vector<BytecodeInfo> infoData_ {};
717     bool hasTryCatch_ {false};
718     ChunkVector<GateRef> loopHeaderGates_;
719     GateRef preFrameState_ {Circuit::NullGate()};
720     GateRef preFrameArgs_ {Circuit::NullGate()};
721     size_t numOfLiveBB_ {0};
722     bool isInline_ {false};
723     uint32_t methodId_ {0};
724     bool preAnalysis_ {false};
725     std::set<const BytecodeRegion *> catchBBOfOSRLoop_{};
726     std::map<uint32_t, bool> candidateEmptyCatch_ {};
727     bool hasEmptyCatchBB_ {false};
728     bool isIrreducible_ {false};
729     bool isJitCompile_ {false};
730     CVector<size_t> timeIn_ {};
731     CVector<size_t> timeOut_ {};
732     std::unordered_map<size_t, size_t> bbIdToDfsTimestamp_ {};
733 };
734 }  // namespace panda::ecmascript::kungfu
735 #endif  // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
736