1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_COMPILER_FRAME_STATE_H 17 #define ECMASCRIPT_COMPILER_FRAME_STATE_H 18 19 #include "ecmascript/compiler/argument_accessor.h" 20 #include "ecmascript/compiler/base/bit_set.h" 21 #include "ecmascript/compiler/circuit.h" 22 #include "ecmascript/compiler/gate.h" 23 #include "ecmascript/compiler/gate_accessor.h" 24 #include "ecmascript/compiler/pgo_type/pgo_type_recorder.h" 25 #include "ecmascript/jspandafile/method_literal.h" 26 27 namespace panda::ecmascript::kungfu { 28 class BytecodeCircuitBuilder; 29 struct BytecodeRegion; 30 31 class FrameLiveOut { 32 public: FrameLiveOut(Chunk * chunk,size_t numVregs)33 explicit FrameLiveOut(Chunk* chunk, size_t numVregs) 34 : liveout_(chunk, numVregs), defRegisters_(chunk, numVregs) {} 35 SetBit(size_t index)36 void SetBit(size_t index) 37 { 38 liveout_.SetBit(index); 39 } 40 ClearBit(size_t index)41 void ClearBit(size_t index) 42 { 43 liveout_.ClearBit(index); 44 } 45 TestBit(size_t index)46 bool TestBit(size_t index) const 47 { 48 return liveout_.TestBit(index); 49 } 50 CopyFrom(FrameLiveOut * other)51 void CopyFrom(FrameLiveOut *other) 52 { 53 liveout_.CopyFrom(other->liveout_); 54 } 55 MergeLiveout(FrameLiveOut * other)56 bool MergeLiveout(FrameLiveOut *other) 57 { 58 return liveout_.UnionWithChanged(other->liveout_); 59 } 60 Reset()61 void Reset() 62 { 63 return liveout_.Reset(); 64 } 65 66 private: 67 // [numVRegs_] [extra args] [numArgs_] [accumulator] 68 BitSet liveout_; 69 BitSet defRegisters_; 70 friend class BlockLoopAnalysis; 71 friend class FrameStateBuilder; 72 }; 73 74 class FrameContext { 75 public: FrameContext(Chunk * chunk,size_t numVregs)76 explicit FrameContext(Chunk* chunk, size_t numVregs) 77 : values_(numVregs, chunk) {} 78 ValuesAt(size_t index)79 GateRef ValuesAt(size_t index) const 80 { 81 ASSERT(index < values_.size()); 82 return values_[index]; 83 } 84 SetValuesAt(size_t index,GateRef gate)85 void SetValuesAt(size_t index, GateRef gate) 86 { 87 ASSERT(index < values_.size()); 88 values_[index] = gate; 89 } 90 CopyCurrentStatus(FrameContext * other)91 void CopyCurrentStatus(FrameContext *other) 92 { 93 currentState_ = other->currentState_; 94 currentDepend_ = other->currentDepend_; 95 needStateSplit_ = other->needStateSplit_; 96 } 97 private: 98 // [numVRegs_] [extra args] [numArgs_] [accumulator] 99 ChunkVector<GateRef> values_; 100 GateRef currentState_ {Circuit::NullGate()}; 101 GateRef currentDepend_ {Circuit::NullGate()}; 102 size_t currentIndex_ {0}; 103 bool needStateSplit_ {false}; 104 friend class FrameStateBuilder; 105 friend class BlockLoopAnalysis; 106 }; 107 108 class FrameStateBuilder { 109 public: 110 FrameStateBuilder(BytecodeCircuitBuilder *builder, 111 Circuit *circuit, const MethodLiteral *literal); 112 ~FrameStateBuilder(); 113 114 void DoBytecodeAnalysis(); 115 void AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId); 116 void UpdateFrameValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId, 117 GateRef gate); 118 void UpdateMoveValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId); 119 void UpdateStateDepend(GateRef state, GateRef depend); 120 FrameLiveOut *GetOrOCreateBCEndLiveOut(uint32_t bcIndex); 121 FrameLiveOut *GetOrOCreateBBLiveOut(size_t bbIndex); GetCurrentState()122 GateRef GetCurrentState() const 123 { 124 return liveContext_->currentState_; 125 } 126 GetCurrentDepend()127 GateRef GetCurrentDepend() const 128 { 129 return liveContext_->currentDepend_; 130 } 131 void MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext); 132 void AdvanceToNextBB(const BytecodeRegion &bb); 133 void InitEntryBB(const BytecodeRegion &bb); 134 GetRpoList()135 const ChunkDeque<size_t>& GetRpoList() const 136 { 137 return rpoList_; 138 } 139 HasLoop()140 bool HasLoop() const 141 { 142 return numLoops_ > 0; 143 } UpdateAccumulator(GateRef gate)144 void UpdateAccumulator(GateRef gate) 145 { 146 UpdateVirtualRegister(accumulatorIndex_, gate); 147 } 148 149 private: 150 static constexpr size_t FIXED_ARGS = 2; // ac & env 151 struct LoopInfo { 152 size_t loopIndex {0}; 153 size_t loopHeadId {0}; 154 size_t numLoopBacks {0}; 155 size_t sortIndx {0}; 156 LoopInfo* parentInfo {nullptr}; 157 BitSet* loopBodys {nullptr}; 158 ChunkVector<BytecodeRegion*>* loopExits {nullptr}; 159 BitSet* loopAssignment {nullptr}; 160 FrameContext* mergedContext {nullptr}; 161 }; 162 163 void BuildPostOrderList(size_t size); 164 bool ComputeLiveOut(size_t bbId); 165 void ComputeLiveState(); 166 void ComputeLiveOutBC(const BytecodeInfo &bytecodeInfo); 167 bool MergeIntoPredBC(uint32_t predPc); 168 bool MergeFromSuccBB(size_t bbId); 169 void MergeFromCatchBB(size_t bbId); 170 GetFrameLiveoutAfter(uint32_t bcId)171 FrameLiveOut *GetFrameLiveoutAfter(uint32_t bcId) 172 { 173 return bcEndStateLiveouts_[bcId]; 174 } 175 GetFrameLiveoutBefore(size_t bbId)176 FrameLiveOut *GetFrameLiveoutBefore(size_t bbId) 177 { 178 return bbBeginStateLiveouts_[bbId]; 179 } 180 ValuesAt(size_t index)181 GateRef ValuesAt(size_t index) const 182 { 183 return liveContext_->ValuesAt(index); 184 } 185 ValuesAtAccumulator()186 GateRef ValuesAtAccumulator() const 187 { 188 return ValuesAt(accumulatorIndex_); 189 } 190 UpdateVirtualRegister(size_t index,GateRef gate)191 void UpdateVirtualRegister(size_t index, GateRef gate) 192 { 193 liveContext_->SetValuesAt(index, gate); 194 } 195 GetBcFrameStateCache()196 GateRef GetBcFrameStateCache() 197 { 198 ASSERT(frameStateCache_ != Circuit::NullGate()); 199 auto cache = frameStateCache_; 200 frameStateCache_ = Circuit::NullGate(); 201 return cache; 202 } 203 GetMergedBbContext(uint32_t bbIndex)204 FrameContext *GetMergedBbContext(uint32_t bbIndex) const 205 { 206 ASSERT(bbIndex < bbFrameContext_.size()); 207 return bbFrameContext_[bbIndex]; 208 } 209 210 FrameContext *GetOrOCreateMergedContext(uint32_t bbIndex); 211 void FillBcInputs(const BytecodeInfo &bytecodeInfo, uint32_t bcIndex, GateRef gate); 212 void DumpLiveState(); 213 GateRef MergeValue(const BytecodeRegion &bb, 214 GateRef stateMerge, GateRef currentValue, GateRef nextValue, size_t index); 215 void NewMerge(const BytecodeRegion &bbNext); 216 void MergeStateDepend(const BytecodeRegion &bb, const BytecodeRegion &bbNext); 217 void CopyLiveoutValues(const BytecodeRegion &bbNext, FrameContext* dest, FrameContext* src); 218 void SaveCurrentContext(const BytecodeRegion &bb); 219 220 void NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAssignment); 221 size_t ComputeLoopDepth(size_t loopHead); 222 void TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext); 223 void ComputeLoopInfo(); 224 void ResizeLoopBody(); 225 void MergeAssignment(const BytecodeRegion &bbNext); 226 BitSet *GetLoopAssignment(const BytecodeRegion &bb); 227 LoopInfo& GetLoopInfo(const BytecodeRegion &bb); 228 LoopInfo& GetLoopInfo(BytecodeRegion &bb); 229 LoopInfo* GetLoopInfoByLoopBody(const BytecodeRegion &bb); 230 bool IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext); 231 232 GateRef BuildFrameContext(FrameContext* frameContext); 233 void BindStateSplitBefore(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId); 234 void BindStateSplitAfter(const BytecodeInfo &bytecodeInfo, uint32_t bcId, GateRef gate); 235 GateRef BuildFrameValues(FrameContext* frameContext, FrameLiveOut* liveout); 236 GateRef BuildStateSplit(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex); 237 GateRef BuildFrameState(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex); 238 void AddEmptyBlock(BytecodeRegion* bb); 239 FrameContext *GetCachedContext(); 240 241 BytecodeCircuitBuilder *bcBuilder_ {nullptr}; 242 TSManager *tsManager_ {nullptr}; 243 const TypeRecorder *typeRecorder_ {nullptr}; 244 const PGOTypeRecorder *pgoTypeRecorder_ {nullptr}; 245 FrameLiveOut *liveOutResult_ {nullptr}; 246 FrameLiveOut *currentBBliveOut_ {nullptr}; 247 FrameContext *liveContext_ {nullptr}; 248 FrameContext *cachedContext_ {nullptr}; 249 FrameContext *cachedContextBackup_ {nullptr}; 250 size_t numVregs_ {0}; 251 size_t accumulatorIndex_ {0}; 252 size_t envIndex_ {0}; 253 size_t numLoops_ {0}; 254 size_t sortIndx_ {0}; 255 GateRef frameStateCache_ {Circuit::NullGate()}; 256 Circuit *circuit_ {nullptr}; 257 GateAccessor acc_; 258 ChunkVector<FrameLiveOut *> bcEndStateLiveouts_; 259 ChunkVector<FrameLiveOut *> bbBeginStateLiveouts_; 260 ChunkVector<FrameContext *> bbFrameContext_; 261 ChunkVector<LoopInfo> loops_; 262 ChunkDeque<size_t> rpoList_; 263 ChunkVector<size_t> postOrderList_; 264 265 friend class BlockLoopAnalysis; 266 friend class SubContextScope; 267 }; 268 } // panda::ecmascript::kungfu 269 #endif // ECMASCRIPT_COMPILER_FRAME_STATE_H 270