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
36namespace panda::ecmascript::kungfu {
37struct ExceptionItem {
38    uint8_t* startPc;
39    uint8_t* endPc;
40    std::vector<uint8_t*> catches;
41
42    ExceptionItem(uint8_t* startPc, uint8_t* endPc, std::vector<uint8_t*> catches)
43        : startPc(startPc), endPc(endPc), catches(catches) {}
44};
45
46using ExceptionInfo = std::vector<ExceptionItem>;
47
48class RegionItem {
49public:
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
66    RegionItem(uint32_t startBcIndex, bool isHeadBlock)
67        : startBcIndex_(startBcIndex), isHeadBlock_(isHeadBlock) {}
68
69    uint32_t GetStartBcIndex() const
70    {
71        return startBcIndex_;
72    }
73
74    uint32_t IsHeadBlock() const
75    {
76        return isHeadBlock_;
77    }
78private:
79    uint32_t startBcIndex_ { INVALID_BC_INDEX };
80    bool isHeadBlock_ { false };
81    friend class RegionsInfo;
82};
83
84struct BytecodeSplitItem {
85    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
91class RegionsInfo {
92public:
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
103    void InsertHead(uint32_t bcIndex)
104    {
105        InsertBlockItem(bcIndex, true);
106    }
107
108    void InsertSplit(uint32_t bcIndex)
109    {
110        InsertBlockItem(bcIndex, false);
111    }
112
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
127    const std::vector<BytecodeSplitItem> &GetSplitItems() const
128    {
129        return splitItems_;
130    }
131
132    const std::set<RegionItem> &GetBlockItems() const
133    {
134        return blockItems_;
135    }
136private:
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
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
154struct 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    BytecodeRegion(Chunk* chunk) : preds(chunk), succs(chunk),
171        trys(chunk), catches(chunk), loopBacks(chunk), expandedPreds(chunk)
172    {
173    }
174
175    BytecodeIterator &GetBytecodeIterator()
176    {
177        return bytecodeIterator_;
178    }
179
180    bool operator <(const BytecodeRegion &target) const
181    {
182        return id < target.id;
183    }
184
185    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
194    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
202    bool IsEmptryBlock() const
203    {
204        return end == static_cast<uint32_t>(BytecodeIterator::INVALID_INDEX);
205    }
206
207    bool IsLoopBack(const BytecodeRegion &bb) const
208    {
209        return loopBacks.find(bb.id) != loopBacks.end();
210    }
211};
212
213using BytecodeGraph = ChunkVector<BytecodeRegion*>;
214
215class BytecodeCircuitBuilder {
216public:
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)
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
253    [[nodiscard]] Circuit* GetCircuit() const
254    {
255        return circuit_;
256    }
257
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
268    const std::vector<GateRef>& GetGatesByBcIndex(uint32_t bcIndex) const
269    {
270        ASSERT(bcIndex < byteCodeToJSGates_.size());
271        return byteCodeToJSGates_[bcIndex];
272    }
273
274    uint32_t GetBcIndexByGate(GateRef gate) const
275    {
276        return jsGatesToByteCode_.at(gate);
277    }
278
279    bool IsBcIndexByGate(GateRef gate) const
280    {
281        if (jsGatesToByteCode_.find(gate) == jsGatesToByteCode_.end()) {
282            return false;
283        }
284        return true;
285    }
286
287    void SetOsrOffset(int32_t offset)
288    {
289        osrOffset_ = offset;
290    }
291
292    bool NeedCheckSafePointAndStackOver() const
293    {
294        return !isInline_ && !method_->IsNoGC();
295    }
296
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
305    [[nodiscard]] const MethodLiteral* GetMethod() const
306    {
307        return method_;
308    }
309
310    [[nodiscard]] const JSPandaFile *GetJSPandaFile() const
311    {
312        return file_;
313    }
314
315    const std::string& GetMethodName() const
316    {
317        return methodName_;
318    }
319
320    bool IsLogEnabled() const
321    {
322        return enableLog_;
323    }
324
325    bool IsTypeLoweringEnabled() const
326    {
327        return enableTypeLowering_;
328    }
329
330    [[nodiscard]] const std::vector<GateRef>& GetAsyncRelatedGates() const
331    {
332        return suspendAndResumeGates_;
333    }
334
335    void UpdateAsyncRelatedGate(GateRef gate)
336    {
337        suspendAndResumeGates_.emplace_back(gate);
338    };
339
340    template <class Callback>
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
355    BytecodeRegion &GetBasicBlockById(size_t id)
356    {
357        ASSERT(id < graph_.size());
358        return RegionAt(id);
359    }
360
361    void AddBasicBlock(BytecodeRegion* region)
362    {
363        graph_.emplace_back(region);
364    }
365
366    size_t GetBasicBlockCount() const
367    {
368        return graph_.size();
369    }
370
371    size_t GetPcOffset(const uint8_t *pc) const
372    {
373        return static_cast<size_t>(pc - method_->GetBytecodeArray());
374    }
375
376    size_t GetPcOffset(uint32_t bcIndex) const
377    {
378        const uint8_t* pc = GetPCByIndex(bcIndex);
379        return GetPcOffset(pc);
380    }
381
382    size_t GetPcOffsetByGate(GateRef gate) const
383    {
384        return GetPcOffset(jsGatesToByteCode_.at(gate));
385    }
386
387    std::vector<ElementsKind> GetElementsKindsForUser(GateRef gate) const
388    {
389        return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate));
390    }
391
392    PUBLIC_API std::vector<ElementsKind> GetTransitionElementsKindsForUser(GateRef gate) const
393    {
394        return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate));
395    }
396
397    ElementsKind GetElementsKindForCreater(GateRef gate) const
398    {
399        return pgoTypeRecorder_.GetElementsKindForCreater(gateAcc_.TryGetPcOffset(gate));
400    }
401
402    uint32_t GetArrayElementsLength(GateRef gate) const
403    {
404        return pgoTypeRecorder_.GetElementsLength(gateAcc_.TryGetPcOffset(gate));
405    }
406
407    RegionSpaceFlag GetRegionSpaceFlag(GateRef gate) const
408    {
409        return pgoTypeRecorder_.GetRegionSpaceFlag(gateAcc_.TryGetPcOffset(gate));
410    }
411
412    bool ShouldPGOTypeInfer(GateRef gate) const
413    {
414        return jsGatesToByteCode_.find(gate) != jsGatesToByteCode_.end();
415    }
416
417    size_t GetNumberVRegs() const
418    {
419        return static_cast<size_t>(method_->GetNumberVRegs());
420    }
421
422    size_t GetNumberVRegsWithEnv() const
423    {
424        return GetNumberVRegs() + 1; // 1: env variable
425    }
426
427    size_t GetEnvVregIdx() const
428    {
429        return GetNumberVRegs();
430    }
431
432    Bytecodes *GetBytecodes() const
433    {
434        return bytecodes_;
435    }
436
437    uint32_t GetLastBcIndex() const
438    {
439        ASSERT(pcOffsets_.size() > 0);
440        return static_cast<uint32_t>(pcOffsets_.size() - 1);
441    }
442
443    const uint8_t *GetPCByIndex(uint32_t index) const
444    {
445        ASSERT(index <= GetLastBcIndex());
446        return pcOffsets_[index];
447    }
448
449    const uint8_t *GetFirstPC() const
450    {
451        return GetPCByIndex(0);
452    }
453
454    const uint8_t *GetLastPC() const
455    {
456        return GetPCByIndex(GetLastBcIndex());
457    }
458
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
469    const BytecodeInfo &GetBytecodeInfo(uint32_t index) const
470    {
471        return infoData_[index];
472    }
473
474    bool HasTryCatch() const
475    {
476        return hasTryCatch_;
477    }
478
479    bool EnableLoopOptimization() const
480    {
481        return (!HasTryCatch()) && frameStateBuilder_.HasLoop();
482    }
483
484    void RemoveUnreachableRegion();
485
486    GateRef GetFrameArgs() const
487    {
488        return argAcc_.GetFrameArgs();
489    }
490
491    GateRef GetPreFrameState() const
492    {
493        return preFrameState_;
494    }
495
496    void SetPreFrameState(GateRef gate)
497    {
498        preFrameState_ = gate;
499    }
500
501    GateRef GetPreFrameArgs() const
502    {
503        return preFrameArgs_;
504    }
505
506    void SetPreFrameArgs(GateRef gate)
507    {
508        preFrameArgs_ = gate;
509    }
510
511    inline bool IsEntryBlock(const size_t bbId) const
512    {
513        return bbId == 0;
514    }
515
516    inline bool IsFirstBasicBlock(const size_t bbId) const
517    {
518        return bbId == 1;
519    }
520
521    const PGOTypeRecorder *GetPGOTypeRecorder() const
522    {
523        return &pgoTypeRecorder_;
524    }
525
526    GateRef GetArgGate(const size_t currentVreg) const
527    {
528        return argAcc_.GetArgGate(currentVreg);
529    }
530
531    GateRef ArgGateNotExisted(const size_t currentVreg)
532    {
533        return argAcc_.ArgGateNotExisted(currentVreg);
534    }
535
536    ChunkVector<GateRef>& GetLoopHeaderGates()
537    {
538        return loopHeaderGates_;
539    }
540
541    size_t NumberOfLiveBlock() const
542    {
543        return numOfLiveBB_;
544    }
545
546    int32_t GetCurrentConstpoolId() const
547    {
548        panda_file::IndexAccessor indexAccessor(*file_->GetPandaFile(), panda_file::File::EntityId(methodId_));
549        return static_cast<int32_t>(indexAccessor.GetHeaderIndex());
550    }
551
552    void GetCurrentConstpool(GateRef jsFunc, GateRef &sharedConstPool, GateRef &unSharedConstPool)
553    {
554        int32_t constpoolId = GetCurrentConstpoolId();
555        if (gateAcc_.GetOpCode(preFrameArgs_) == OpCode::CIRCUIT_ROOT) {
556            sharedConstPool = circuit_->NewGate(circuit_->GetSharedConstPool(constpoolId), MachineType::I64, {jsFunc},
557                                                GateType::AnyType());
558            unSharedConstPool = circuit_->NewGate(circuit_->GetUnsharedConstPool(), MachineType::I64,
559                                                  {sharedConstPool}, GateType::AnyType());
560        }
561        GateRef frameArgs = preFrameArgs_;
562        GateRef preSharedConstPool = Circuit::NullGate();
563        GateRef preUnsharedConstPool = Circuit::NullGate();
564        int32_t preConstpoolId = 0;
565        while (gateAcc_.GetOpCode(frameArgs) != OpCode::CIRCUIT_ROOT) {
566            preSharedConstPool = gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::SHARED_CONST_POOL));
567            preUnsharedConstPool =
568                gateAcc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::UNSHARED_CONST_POOL));
569            preConstpoolId = static_cast<int32_t>(gateAcc_.GetConstpoolId(preSharedConstPool));
570            if (preConstpoolId == constpoolId) {
571                sharedConstPool = preSharedConstPool;
572                unSharedConstPool = preUnsharedConstPool;
573                break;
574            }
575            frameArgs = gateAcc_.GetFrameState(frameArgs);
576        }
577    }
578
579    void SetIrreducibleLoop()
580    {
581        isIrreducible_ = true;
582    }
583
584    bool HasIrreducibleLoop() const
585    {
586        return isIrreducible_;
587    }
588
589    void SetJitCompile()
590    {
591        isJitCompile_ = true;
592    }
593
594    bool IsJitCompile() const
595    {
596        return isJitCompile_;
597    }
598
599    void SetPreAnalysis()
600    {
601        preAnalysis_ = true;
602    }
603
604    bool IsPreAnalysis() const
605    {
606        return preAnalysis_;
607    }
608
609    bool NeedIrreducibleLoopCheck() const
610    {
611        return IsPreAnalysis() || IsJitCompile();
612    }
613
614    bool TerminateAnalysis() const
615    {
616        return IsPreAnalysis() || HasIrreducibleLoop();
617    }
618
619    bool IsOSR() const
620    {
621        return osrOffset_ != MachineCode::INVALID_OSR_OFFSET;
622    }
623
624    bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const
625    {
626        return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end();
627    }
628
629    void ComputeNumOfLoopBack();
630
631    enum class MarkState : uint8_t {
632        UNVISITED = 0,
633        ON_STACK,
634        PENDING,
635        VISITED,
636        VISITED1,
637        UNVISITED1 = VISITED
638    };
639
640    struct VisitedInfo {
641        size_t needVisitIndex;
642        bool isVisitedCatchBlock = false;
643    };
644    bool IsAncestor(size_t nodeA, size_t nodeB);
645
646private:
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 UpdateCFG();
671    void CollectTryPredsInfo();
672    void ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList);
673    void RemoveUnusedPredsInfo(BytecodeRegion& bb);
674    void BuildCircuit();
675    void PrintGraph();
676    void PrintBBInfo();
677    void PrintGraph(const char* title);
678    void PrintBytecodeInfo(BytecodeRegion& region);
679    void PrintDefsitesInfo(const std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo);
680    void BuildRegionInfo();
681    void BuildFrameArgs();
682    void RemoveIfInRpoList(BytecodeRegion *bb);
683    void PerformDFS(const std::vector<size_t> &immDom, size_t listSize);
684    void ReducibilityCheck();
685    void ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
686                                    std::unordered_map<size_t, size_t> &dfsFatherIdx, std::vector<size_t> &immDom,
687                                    std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
688    void ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
689        std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx);
690
691    BytecodeRegion &RegionAt(size_t i)
692    {
693        return *graph_[i];
694    }
695
696    Circuit *circuit_;
697    std::vector<std::vector<GateRef>> byteCodeToJSGates_;
698    std::unordered_map<GateRef, size_t> jsGatesToByteCode_;
699    BytecodeGraph graph_;
700    const JSPandaFile *file_ {nullptr};
701    const MethodLiteral *method_ {nullptr};
702    GateAccessor gateAcc_;
703    ArgumentAccessor argAcc_;
704    PGOTypeRecorder pgoTypeRecorder_;
705    int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET};
706    bool enableLog_ {false};
707    bool enableTypeLowering_ {false};
708    std::vector<GateRef> suspendAndResumeGates_ {};
709    std::vector<const uint8_t*> pcOffsets_;
710    FrameStateBuilder frameStateBuilder_;
711    std::string methodName_;
712    const CString &recordName_;
713    Bytecodes *bytecodes_;
714    RegionsInfo regionsInfo_{};
715    std::vector<BytecodeInfo> infoData_ {};
716    bool hasTryCatch_ {false};
717    ChunkVector<GateRef> loopHeaderGates_;
718    GateRef preFrameState_ {Circuit::NullGate()};
719    GateRef preFrameArgs_ {Circuit::NullGate()};
720    size_t numOfLiveBB_ {0};
721    bool isInline_ {false};
722    uint32_t methodId_ {0};
723    bool preAnalysis_ {false};
724    std::set<const BytecodeRegion *> catchBBOfOSRLoop_{};
725    bool isIrreducible_ {false};
726    bool isJitCompile_ {false};
727    CVector<size_t> timeIn_ {};
728    CVector<size_t> timeOut_ {};
729    std::unordered_map<size_t, size_t> bbIdToDfsTimestamp_ {};
730};
731}  // namespace panda::ecmascript::kungfu
732#endif  // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H
733