14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_COMPILER_FRAME_STATE_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_COMPILER_FRAME_STATE_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/base/bit_set.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/circuit.h"
214514f5e3Sopenharmony_ci#include "ecmascript/compiler/gate.h"
224514f5e3Sopenharmony_ci#include "ecmascript/compiler/gate_accessor.h"
234514f5e3Sopenharmony_ci#include "ecmascript/compiler/pgo_type/pgo_type_recorder.h"
244514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/method_literal.h"
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
274514f5e3Sopenharmony_ciclass BytecodeCircuitBuilder;
284514f5e3Sopenharmony_cistruct BytecodeRegion;
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_ciclass FrameLiveOut {
314514f5e3Sopenharmony_cipublic:
324514f5e3Sopenharmony_ci    explicit FrameLiveOut(Chunk* chunk, size_t numVregs)
334514f5e3Sopenharmony_ci        : liveout_(chunk, numVregs), defRegisters_(chunk, numVregs) {}
344514f5e3Sopenharmony_ci
354514f5e3Sopenharmony_ci    void SetBit(size_t index)
364514f5e3Sopenharmony_ci    {
374514f5e3Sopenharmony_ci        liveout_.SetBit(index);
384514f5e3Sopenharmony_ci    }
394514f5e3Sopenharmony_ci
404514f5e3Sopenharmony_ci    void ClearBit(size_t index)
414514f5e3Sopenharmony_ci    {
424514f5e3Sopenharmony_ci        liveout_.ClearBit(index);
434514f5e3Sopenharmony_ci    }
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_ci    bool TestBit(size_t index) const
464514f5e3Sopenharmony_ci    {
474514f5e3Sopenharmony_ci        return liveout_.TestBit(index);
484514f5e3Sopenharmony_ci    }
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    void CopyFrom(FrameLiveOut *other)
514514f5e3Sopenharmony_ci    {
524514f5e3Sopenharmony_ci        liveout_.CopyFrom(other->liveout_);
534514f5e3Sopenharmony_ci    }
544514f5e3Sopenharmony_ci
554514f5e3Sopenharmony_ci    bool MergeLiveout(FrameLiveOut *other)
564514f5e3Sopenharmony_ci    {
574514f5e3Sopenharmony_ci        return liveout_.UnionWithChanged(other->liveout_);
584514f5e3Sopenharmony_ci    }
594514f5e3Sopenharmony_ci
604514f5e3Sopenharmony_ci    void Reset()
614514f5e3Sopenharmony_ci    {
624514f5e3Sopenharmony_ci        return liveout_.Reset();
634514f5e3Sopenharmony_ci    }
644514f5e3Sopenharmony_ci
654514f5e3Sopenharmony_ciprivate:
664514f5e3Sopenharmony_ci    // [numVRegs_] [extra args] [numArgs_] [accumulator]
674514f5e3Sopenharmony_ci    BitSet liveout_;
684514f5e3Sopenharmony_ci    BitSet defRegisters_;
694514f5e3Sopenharmony_ci    friend class BlockLoopAnalysis;
704514f5e3Sopenharmony_ci    friend class FrameStateBuilder;
714514f5e3Sopenharmony_ci};
724514f5e3Sopenharmony_ci
734514f5e3Sopenharmony_ciclass FrameContext {
744514f5e3Sopenharmony_cipublic:
754514f5e3Sopenharmony_ci    explicit FrameContext(Chunk* chunk, size_t numVregs)
764514f5e3Sopenharmony_ci        : values_(numVregs, chunk) {}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_ci    GateRef ValuesAt(size_t index) const
794514f5e3Sopenharmony_ci    {
804514f5e3Sopenharmony_ci        ASSERT(index < values_.size());
814514f5e3Sopenharmony_ci        return values_[index];
824514f5e3Sopenharmony_ci    }
834514f5e3Sopenharmony_ci
844514f5e3Sopenharmony_ci    void SetValuesAt(size_t index, GateRef gate)
854514f5e3Sopenharmony_ci    {
864514f5e3Sopenharmony_ci        ASSERT(index < values_.size());
874514f5e3Sopenharmony_ci        values_[index] = gate;
884514f5e3Sopenharmony_ci    }
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ci    void CopyCurrentStatus(FrameContext *other)
914514f5e3Sopenharmony_ci    {
924514f5e3Sopenharmony_ci        currentState_ = other->currentState_;
934514f5e3Sopenharmony_ci        currentDepend_ = other->currentDepend_;
944514f5e3Sopenharmony_ci        needStateSplit_ = other->needStateSplit_;
954514f5e3Sopenharmony_ci    }
964514f5e3Sopenharmony_ciprivate:
974514f5e3Sopenharmony_ci    // [numVRegs_] [extra args] [numArgs_] [accumulator]
984514f5e3Sopenharmony_ci    ChunkVector<GateRef> values_;
994514f5e3Sopenharmony_ci    GateRef currentState_ {Circuit::NullGate()};
1004514f5e3Sopenharmony_ci    GateRef currentDepend_ {Circuit::NullGate()};
1014514f5e3Sopenharmony_ci    GateRef loopBackState_ {Circuit::NullGate()};
1024514f5e3Sopenharmony_ci    GateRef loopBackDepend_ {Circuit::NullGate()};
1034514f5e3Sopenharmony_ci    GateRef mergeState_ {Circuit::NullGate()};
1044514f5e3Sopenharmony_ci    GateRef mergeDepend_ {Circuit::NullGate()};
1054514f5e3Sopenharmony_ci    size_t currentIndex_ {0};
1064514f5e3Sopenharmony_ci    size_t loopBackIndex_ {0};
1074514f5e3Sopenharmony_ci    size_t mergeIndex_ {0};
1084514f5e3Sopenharmony_ci    bool needStateSplit_ {false};
1094514f5e3Sopenharmony_ci    friend class FrameStateBuilder;
1104514f5e3Sopenharmony_ci    friend class BlockLoopAnalysis;
1114514f5e3Sopenharmony_ci};
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_cistruct MergeStateDependInfo {
1144514f5e3Sopenharmony_ci    GateRef state;
1154514f5e3Sopenharmony_ci    GateRef depend;
1164514f5e3Sopenharmony_ci    size_t index;
1174514f5e3Sopenharmony_ci};
1184514f5e3Sopenharmony_ci
1194514f5e3Sopenharmony_ciclass FrameStateBuilder {
1204514f5e3Sopenharmony_cipublic:
1214514f5e3Sopenharmony_ci    FrameStateBuilder(BytecodeCircuitBuilder *builder,
1224514f5e3Sopenharmony_ci        Circuit *circuit, const MethodLiteral *literal);
1234514f5e3Sopenharmony_ci    ~FrameStateBuilder();
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_ci    void DoBytecodeAnalysis();
1264514f5e3Sopenharmony_ci    void AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId);
1274514f5e3Sopenharmony_ci    void UpdateFrameValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId,
1284514f5e3Sopenharmony_ci        GateRef gate);
1294514f5e3Sopenharmony_ci    void UpdateMoveValues(const BytecodeInfo &bytecodeInfo);
1304514f5e3Sopenharmony_ci    void UpdateStateDepend(GateRef state, GateRef depend);
1314514f5e3Sopenharmony_ci    FrameLiveOut *GetOrOCreateBCEndLiveOut(uint32_t bcIndex);
1324514f5e3Sopenharmony_ci    FrameLiveOut *GetOrOCreateBBLiveOut(size_t bbIndex);
1334514f5e3Sopenharmony_ci    GateRef GetCurrentState() const
1344514f5e3Sopenharmony_ci    {
1354514f5e3Sopenharmony_ci        return liveContext_->currentState_;
1364514f5e3Sopenharmony_ci    }
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_ci    GateRef GetCurrentDepend() const
1394514f5e3Sopenharmony_ci    {
1404514f5e3Sopenharmony_ci        return liveContext_->currentDepend_;
1414514f5e3Sopenharmony_ci    }
1424514f5e3Sopenharmony_ci    void MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
1434514f5e3Sopenharmony_ci    void AdvanceToNextBB(const BytecodeRegion &bb, bool isOsrLoopExit = false);
1444514f5e3Sopenharmony_ci    void InitEntryBB(const BytecodeRegion &bb);
1454514f5e3Sopenharmony_ci
1464514f5e3Sopenharmony_ci    ChunkDeque<size_t>& GetRpoList()
1474514f5e3Sopenharmony_ci    {
1484514f5e3Sopenharmony_ci        return rpoList_;
1494514f5e3Sopenharmony_ci    }
1504514f5e3Sopenharmony_ci
1514514f5e3Sopenharmony_ci    bool HasLoop() const
1524514f5e3Sopenharmony_ci    {
1534514f5e3Sopenharmony_ci        return numLoops_ > 0;
1544514f5e3Sopenharmony_ci    }
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_ci    void UpdateAccumulator(GateRef gate)
1574514f5e3Sopenharmony_ci    {
1584514f5e3Sopenharmony_ci        UpdateVirtualRegister(accumulatorIndex_, gate);
1594514f5e3Sopenharmony_ci    }
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ci    void SetOsrLoopHeadBB(const BytecodeRegion &loopHeadOfOSR);
1624514f5e3Sopenharmony_ci
1634514f5e3Sopenharmony_ci    bool IsOsrLoopExit(const BytecodeRegion &curBB);
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_ci    bool OutOfOsrLoop(const BytecodeRegion &curBB);
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    size_t GetOsrLoopHeadBBId() const;
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_ci    bool IsContextExists(uint32_t bbIndex) const
1704514f5e3Sopenharmony_ci    {
1714514f5e3Sopenharmony_ci        ASSERT(bbIndex < bbFrameContext_.size());
1724514f5e3Sopenharmony_ci        return bbFrameContext_[bbIndex] != nullptr;
1734514f5e3Sopenharmony_ci    }
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_ci    FrameContext *GetOrOCreateMergedContext(uint32_t bbIndex);
1764514f5e3Sopenharmony_ci
1774514f5e3Sopenharmony_ciprivate:
1784514f5e3Sopenharmony_ci    static constexpr size_t FIXED_ARGS = 2; // ac & env
1794514f5e3Sopenharmony_ci    struct LoopInfo {
1804514f5e3Sopenharmony_ci        size_t loopIndex {0};
1814514f5e3Sopenharmony_ci        size_t loopHeadId {0};
1824514f5e3Sopenharmony_ci        size_t numLoopBacks {0};
1834514f5e3Sopenharmony_ci        size_t sortIndx {0};
1844514f5e3Sopenharmony_ci        LoopInfo* parentInfo {nullptr};
1854514f5e3Sopenharmony_ci        BitSet* loopBodys {nullptr};
1864514f5e3Sopenharmony_ci        ChunkVector<BytecodeRegion*>* loopExits {nullptr};
1874514f5e3Sopenharmony_ci        BitSet* loopAssignment {nullptr};
1884514f5e3Sopenharmony_ci        FrameContext* mergedContext {nullptr};
1894514f5e3Sopenharmony_ci    };
1904514f5e3Sopenharmony_ci
1914514f5e3Sopenharmony_ci    void BuildPostOrderList(size_t size);
1924514f5e3Sopenharmony_ci    bool ComputeLiveOut(size_t bbId);
1934514f5e3Sopenharmony_ci    void ComputeLiveState();
1944514f5e3Sopenharmony_ci    void ComputeLiveOutBC(const BytecodeInfo &bytecodeInfo);
1954514f5e3Sopenharmony_ci    bool MergeIntoPredBC(uint32_t predPc);
1964514f5e3Sopenharmony_ci    bool MergeFromSuccBB(size_t bbId);
1974514f5e3Sopenharmony_ci    void MergeFromCatchBB(size_t bbId);
1984514f5e3Sopenharmony_ci
1994514f5e3Sopenharmony_ci    FrameLiveOut *GetFrameLiveoutAfter(uint32_t bcId)
2004514f5e3Sopenharmony_ci    {
2014514f5e3Sopenharmony_ci        return bcEndStateLiveouts_[bcId];
2024514f5e3Sopenharmony_ci    }
2034514f5e3Sopenharmony_ci
2044514f5e3Sopenharmony_ci    FrameLiveOut *GetFrameLiveoutBefore(size_t bbId)
2054514f5e3Sopenharmony_ci    {
2064514f5e3Sopenharmony_ci        return bbBeginStateLiveouts_[bbId];
2074514f5e3Sopenharmony_ci    }
2084514f5e3Sopenharmony_ci
2094514f5e3Sopenharmony_ci    GateRef ValuesAt(size_t index) const
2104514f5e3Sopenharmony_ci    {
2114514f5e3Sopenharmony_ci        return liveContext_->ValuesAt(index);
2124514f5e3Sopenharmony_ci    }
2134514f5e3Sopenharmony_ci
2144514f5e3Sopenharmony_ci    GateRef ValuesAtAccumulator() const
2154514f5e3Sopenharmony_ci    {
2164514f5e3Sopenharmony_ci        return ValuesAt(accumulatorIndex_);
2174514f5e3Sopenharmony_ci    }
2184514f5e3Sopenharmony_ci
2194514f5e3Sopenharmony_ci    void UpdateVirtualRegister(size_t index, GateRef gate)
2204514f5e3Sopenharmony_ci    {
2214514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(index, gate);
2224514f5e3Sopenharmony_ci    }
2234514f5e3Sopenharmony_ci
2244514f5e3Sopenharmony_ci    GateRef GetBcFrameStateCache()
2254514f5e3Sopenharmony_ci    {
2264514f5e3Sopenharmony_ci        ASSERT(frameStateCache_ != Circuit::NullGate());
2274514f5e3Sopenharmony_ci        auto cache = frameStateCache_;
2284514f5e3Sopenharmony_ci        frameStateCache_ = Circuit::NullGate();
2294514f5e3Sopenharmony_ci        return cache;
2304514f5e3Sopenharmony_ci    }
2314514f5e3Sopenharmony_ci
2324514f5e3Sopenharmony_ci    FrameContext *GetMergedBbContext(uint32_t bbIndex) const
2334514f5e3Sopenharmony_ci    {
2344514f5e3Sopenharmony_ci        ASSERT(bbIndex < bbFrameContext_.size());
2354514f5e3Sopenharmony_ci        return bbFrameContext_[bbIndex];
2364514f5e3Sopenharmony_ci    }
2374514f5e3Sopenharmony_ci
2384514f5e3Sopenharmony_ci    void FillBcInputs(const BytecodeInfo &bytecodeInfo, GateRef gate);
2394514f5e3Sopenharmony_ci    void DumpLiveState();
2404514f5e3Sopenharmony_ci    size_t GetNumOfStatePreds(const BytecodeRegion &bb);
2414514f5e3Sopenharmony_ci    GateRef MergeValue(const BytecodeRegion &bb,
2424514f5e3Sopenharmony_ci        GateRef currentValue, GateRef nextValue, bool isLoopBack, bool changedInLoop);
2434514f5e3Sopenharmony_ci    void NewMerge(const BytecodeRegion &bbNext);
2444514f5e3Sopenharmony_ci    void MergeStateDepend(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
2454514f5e3Sopenharmony_ci    void CopyLiveoutValues(const BytecodeRegion &bbNext, FrameContext* dest, FrameContext* src);
2464514f5e3Sopenharmony_ci    void SaveCurrentContext(const BytecodeRegion &bb);
2474514f5e3Sopenharmony_ci    MergeStateDependInfo GetCorrespondingState(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
2484514f5e3Sopenharmony_ci
2494514f5e3Sopenharmony_ci    void NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAssignment);
2504514f5e3Sopenharmony_ci    size_t ComputeLoopDepth(size_t loopHead);
2514514f5e3Sopenharmony_ci    void TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
2524514f5e3Sopenharmony_ci    void ComputeLoopInfo();
2534514f5e3Sopenharmony_ci    void ResizeLoopBody();
2544514f5e3Sopenharmony_ci    void MergeAssignment(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
2554514f5e3Sopenharmony_ci    BitSet *GetLoopAssignment(const BytecodeRegion &bb);
2564514f5e3Sopenharmony_ci    LoopInfo& GetLoopInfo(const BytecodeRegion &bb);
2574514f5e3Sopenharmony_ci    LoopInfo& GetLoopInfo(BytecodeRegion &bb);
2584514f5e3Sopenharmony_ci    LoopInfo* GetLoopInfoByLoopBody(const BytecodeRegion &bb);
2594514f5e3Sopenharmony_ci    bool IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext);
2604514f5e3Sopenharmony_ci    bool IsLoopHead(const BytecodeRegion &bb);
2614514f5e3Sopenharmony_ci    bool IfLoopNeedMerge(const BytecodeRegion &bb) const;
2624514f5e3Sopenharmony_ci    GateRef InitMerge(size_t numOfIns, bool isLoop);
2634514f5e3Sopenharmony_ci    bool IsGateNotEmpty(GateRef gate) const;
2644514f5e3Sopenharmony_ci
2654514f5e3Sopenharmony_ci    GateRef BuildFrameContext(FrameContext* frameContext);
2664514f5e3Sopenharmony_ci    void BindStateSplitBefore(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId);
2674514f5e3Sopenharmony_ci    void BindStateSplitAfter(const BytecodeInfo &bytecodeInfo, uint32_t bcId, GateRef gate);
2684514f5e3Sopenharmony_ci    GateRef BuildFrameValues(FrameContext* frameContext, FrameLiveOut* liveout);
2694514f5e3Sopenharmony_ci    GateRef BuildStateSplit(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex);
2704514f5e3Sopenharmony_ci    GateRef BuildFrameState(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex);
2714514f5e3Sopenharmony_ci    void AddEmptyBlock(BytecodeRegion* bb);
2724514f5e3Sopenharmony_ci    FrameContext *GetCachedContext();
2734514f5e3Sopenharmony_ci
2744514f5e3Sopenharmony_ci    BytecodeCircuitBuilder *bcBuilder_ {nullptr};
2754514f5e3Sopenharmony_ci    const PGOTypeRecorder *pgoTypeRecorder_ {nullptr};
2764514f5e3Sopenharmony_ci    FrameLiveOut *liveOutResult_ {nullptr};
2774514f5e3Sopenharmony_ci    FrameLiveOut *currentBBliveOut_ {nullptr};
2784514f5e3Sopenharmony_ci    FrameContext *liveContext_ {nullptr};
2794514f5e3Sopenharmony_ci    FrameContext *cachedContext_ {nullptr};
2804514f5e3Sopenharmony_ci    FrameContext *cachedContextBackup_ {nullptr};
2814514f5e3Sopenharmony_ci    size_t numVregs_ {0};
2824514f5e3Sopenharmony_ci    size_t accumulatorIndex_ {0};
2834514f5e3Sopenharmony_ci    size_t envIndex_ {0};
2844514f5e3Sopenharmony_ci    size_t numLoops_ {0};
2854514f5e3Sopenharmony_ci    size_t sortIndx_ {0};
2864514f5e3Sopenharmony_ci    GateRef frameStateCache_ {Circuit::NullGate()};
2874514f5e3Sopenharmony_ci    Circuit *circuit_ {nullptr};
2884514f5e3Sopenharmony_ci    GateAccessor acc_;
2894514f5e3Sopenharmony_ci    ChunkVector<FrameLiveOut *> bcEndStateLiveouts_;
2904514f5e3Sopenharmony_ci    ChunkVector<FrameLiveOut *> bbBeginStateLiveouts_;
2914514f5e3Sopenharmony_ci    ChunkVector<FrameContext *> bbFrameContext_;
2924514f5e3Sopenharmony_ci    ChunkVector<LoopInfo> loops_;
2934514f5e3Sopenharmony_ci    ChunkDeque<size_t> rpoList_;
2944514f5e3Sopenharmony_ci    ChunkVector<size_t> postOrderList_;
2954514f5e3Sopenharmony_ci    const BytecodeRegion *loopHeadOfOSR_ {nullptr};
2964514f5e3Sopenharmony_ci
2974514f5e3Sopenharmony_ci    friend class BlockLoopAnalysis;
2984514f5e3Sopenharmony_ci    friend class SubContextScope;
2994514f5e3Sopenharmony_ci};
3004514f5e3Sopenharmony_ci}  // panda::ecmascript::kungfu
3014514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_COMPILER_FRAME_STATE_H
302