• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/compiler/bytecode_circuit_builder.h"
16 #include "ecmascript/compiler/frame_states.h"
17 #include "ecmascript/ts_types/ts_manager.h"
18 #include <cstddef>
19 
20 namespace panda::ecmascript::kungfu {
FrameStateBuilder(BytecodeCircuitBuilder * builder,Circuit * circuit,const MethodLiteral * literal)21 FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
22     Circuit *circuit, const MethodLiteral *literal)
23     : bcBuilder_(builder),
24       tsManager_(builder->GetTSManager()),
25       typeRecorder_(builder->GetTypeRecorder()),
26       pgoTypeRecorder_(builder->GetPGOTypeRecorder()),
27       numVregs_(literal->GetNumberVRegs() + FIXED_ARGS),
28       accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc
29       envIndex_(literal->GetNumberVRegs()),
30       circuit_(circuit),
31       acc_(circuit),
32       bcEndStateLiveouts_(circuit->chunk()),
33       bbBeginStateLiveouts_(circuit->chunk()),
34       bbFrameContext_(circuit->chunk()),
35       loops_(circuit->chunk()),
36       rpoList_(circuit->chunk()),
37       postOrderList_(circuit->chunk())
38 {
39 }
40 
~FrameStateBuilder()41 FrameStateBuilder::~FrameStateBuilder()
42 {
43     liveOutResult_ = nullptr;
44     bcEndStateLiveouts_.clear();
45     bbBeginStateLiveouts_.clear();
46     bbFrameContext_.clear();
47     bcBuilder_ = nullptr;
48 }
49 
BuildPostOrderList(size_t size)50 void FrameStateBuilder::BuildPostOrderList(size_t size)
51 {
52     postOrderList_.clear();
53     std::deque<size_t> pendingList;
54     std::vector<bool> visited(size, false);
55     // entry block (bbid=0) is a empty block, need skip
56     auto firstBlockId = 1;
57     pendingList.emplace_back(firstBlockId);
58 
59     while (!pendingList.empty()) {
60         size_t curBlockId = pendingList.back();
61         visited[curBlockId] = true;
62 
63         bool change = false;
64         auto &bb = bcBuilder_->GetBasicBlockById(curBlockId);
65         for (const auto &succBlock: bb.succs) {
66             if (!visited[succBlock->id]) {
67                 pendingList.emplace_back(succBlock->id);
68                 change = true;
69                 break;
70             }
71         }
72         if (change) {
73             continue;
74         }
75         for (const auto &succBlock: bb.catches) {
76             if (!visited[succBlock->id]) {
77                 pendingList.emplace_back(succBlock->id);
78                 change = true;
79                 break;
80             }
81         }
82         if (!change) {
83             postOrderList_.emplace_back(curBlockId);
84             pendingList.pop_back();
85         }
86     }
87 }
88 
MergeIntoPredBC(uint32_t predPc)89 bool FrameStateBuilder::MergeIntoPredBC(uint32_t predPc)
90 {
91     // liveout next
92     auto liveout = GetOrOCreateBCEndLiveOut(predPc);
93     FrameLiveOut *predliveOut = liveOutResult_;
94     return liveout->MergeLiveout(predliveOut);
95 }
96 
MergeFromSuccBB(size_t bbId)97 bool FrameStateBuilder::MergeFromSuccBB(size_t bbId)
98 {
99     // liveout next
100     auto liveout = GetOrOCreateBBLiveOut(bbId);
101     return liveOutResult_->MergeLiveout(liveout);
102 }
103 
MergeFromCatchBB(size_t bbId)104 void FrameStateBuilder::MergeFromCatchBB(size_t bbId)
105 {
106     // liveout next
107     bool accumulatorIsLive = liveOutResult_->TestBit(accumulatorIndex_);
108     auto liveout = GetOrOCreateBBLiveOut(bbId);
109     liveOutResult_->MergeLiveout(liveout);
110     // accumulatorIndex_ is exeception object
111     if (!accumulatorIsLive) {
112         liveOutResult_->ClearBit(accumulatorIndex_);
113     }
114 }
115 
ComputeLiveOut(size_t bbId)116 bool FrameStateBuilder::ComputeLiveOut(size_t bbId)
117 {
118     auto &bb = bcBuilder_->GetBasicBlockById(bbId);
119     bool changed = false;
120     // iterator bc
121     auto &iterator = bb.GetBytecodeIterator();
122     iterator.GotoEnd();
123     ASSERT(bb.end == iterator.Index());
124     auto bbLiveout = GetOrOCreateBBLiveOut(bb.id);
125     auto liveout = GetOrOCreateBCEndLiveOut(bb.end);
126     liveOutResult_->CopyFrom(liveout);
127     // init frameContext
128     currentBBliveOut_ = bbLiveout;
129     while (true) {
130         auto &bytecodeInfo = iterator.GetBytecodeInfo();
131         if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
132             ASSERT(bb.catches.size() == 1); // 1: one catch
133             MergeFromCatchBB(bb.catches.at(0)->id);
134         }
135         ComputeLiveOutBC(bytecodeInfo);
136         --iterator;
137         if (iterator.Done()) {
138             break;
139         }
140         auto prevPc = iterator.Index();
141         changed |= MergeIntoPredBC(prevPc);
142     }
143     if (!bb.trys.empty()) {
144         // clear GET_EXCEPTION gate if this is a catch block
145         liveOutResult_->ClearBit(accumulatorIndex_);
146     }
147     bbLiveout->CopyFrom(liveOutResult_);
148     // merge current into pred bb
149     for (auto bbPred : bb.preds) {
150         changed |= MergeIntoPredBC(bbPred->end);
151     }
152 
153     return changed;
154 }
155 
ComputeLiveState()156 void FrameStateBuilder::ComputeLiveState()
157 {
158     // recompute liveout
159     bool changed = true;
160     while (changed) {
161         changed = false;
162         for (size_t i = 0; i < postOrderList_.size(); i++) {
163             changed |= ComputeLiveOut(postOrderList_[i]);
164         }
165     }
166 }
167 
DoBytecodeAnalysis()168 void FrameStateBuilder::DoBytecodeAnalysis()
169 {
170     auto bcSize = bcBuilder_->GetLastBcIndex() + 1; // 1: +1 pcOffsets size
171     auto bbSize = bcBuilder_->GetBasicBlockCount();
172     bcEndStateLiveouts_.resize(bcSize, nullptr);
173     bbBeginStateLiveouts_.resize(bbSize, nullptr);
174     auto chunk = circuit_->chunk();
175     liveOutResult_ = chunk->New<FrameLiveOut>(chunk, numVregs_);
176     bbFrameContext_.resize(bbSize, nullptr);
177     BuildPostOrderList(bbSize);
178     ComputeLiveState();
179     if (bcBuilder_->IsLogEnabled()) {
180         DumpLiveState();
181     }
182     ComputeLoopInfo();
183 }
184 
ComputeLiveOutBC(const BytecodeInfo & bytecodeInfo)185 void FrameStateBuilder::ComputeLiveOutBC(const BytecodeInfo &bytecodeInfo)
186 {
187     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
188         currentBBliveOut_->defRegisters_.Union(liveOutResult_->liveout_);
189     }
190     // variable kill
191     if (bytecodeInfo.AccOut()) {
192         liveOutResult_->ClearBit(accumulatorIndex_);
193         currentBBliveOut_->defRegisters_.SetBit(accumulatorIndex_);
194     }
195     for (const auto &out: bytecodeInfo.vregOut) {
196         liveOutResult_->ClearBit(out);
197         currentBBliveOut_->defRegisters_.SetBit(out);
198     }
199 
200     // variable use
201     if (bytecodeInfo.AccIn()) {
202         liveOutResult_->SetBit(accumulatorIndex_);
203     }
204     for (size_t i = 0; i < bytecodeInfo.inputs.size(); i++) {
205         auto in = bytecodeInfo.inputs[i];
206         if (std::holds_alternative<VirtualRegister>(in)) {
207             auto vreg = std::get<VirtualRegister>(in).GetId();
208             liveOutResult_->SetBit(vreg);
209         }
210     }
211 }
212 
GetOrOCreateBCEndLiveOut(uint32_t bcIndex)213 FrameLiveOut *FrameStateBuilder::GetOrOCreateBCEndLiveOut(uint32_t bcIndex)
214 {
215     auto liveout = bcEndStateLiveouts_[bcIndex];
216     if (liveout == nullptr) {
217         auto chunk = circuit_->chunk();
218         liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
219         bcEndStateLiveouts_[bcIndex] = liveout;
220     }
221     return liveout;
222 }
223 
GetOrOCreateBBLiveOut(size_t bbIndex)224 FrameLiveOut *FrameStateBuilder::GetOrOCreateBBLiveOut(size_t bbIndex)
225 {
226     // As BB0 is empty, its bbBeginStateLiveouts is the same as BB1.
227     if (bbIndex == 0) {
228         bbIndex = 1;
229     }
230     auto liveout = bbBeginStateLiveouts_[bbIndex];
231     if (liveout == nullptr) {
232         auto chunk = circuit_->chunk();
233         liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
234         bbBeginStateLiveouts_[bbIndex] = liveout;
235     }
236     return liveout;
237 }
238 
GetOrOCreateMergedContext(uint32_t bbIndex)239 FrameContext *FrameStateBuilder::GetOrOCreateMergedContext(uint32_t bbIndex)
240 {
241     auto context = bbFrameContext_[bbIndex];
242     if (context == nullptr) {
243         auto chunk = circuit_->chunk();
244         context = chunk->New<FrameContext>(chunk, numVregs_);
245         for (size_t i = 0; i < numVregs_; i++) {
246             context->SetValuesAt(i, Circuit::NullGate());
247         }
248         bbFrameContext_[bbIndex] = context;
249     }
250     return context;
251 }
252 
FillBcInputs(const BytecodeInfo & bytecodeInfo,uint32_t bcIndex,GateRef gate)253 void FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, uint32_t bcIndex, GateRef gate)
254 {
255     auto type = typeRecorder_->GetType(bcIndex);
256     acc_.SetGateType(gate, type);
257     EcmaOpcode opcode = bytecodeInfo.GetOpcode();
258     auto pgoType = pgoTypeRecorder_->GetPGOType(acc_.TryGetPcOffset(gate));
259     acc_.TrySetPGOType(gate, pgoType);
260 
261     auto valueCount = acc_.GetInValueCount(gate);
262     [[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
263     [[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
264     // RETURNUNDEFINED has value input, but not from acc
265     ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
266     ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
267     auto valueStarts = acc_.GetInValueStarts(gate);
268     for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
269         auto inIdx = valueIdx + valueStarts;
270         if (!acc_.IsInGateNull(gate, inIdx)) {
271             continue;
272         }
273         if (valueIdx < bytecodeInfo.inputs.size()) {
274             auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
275             GateRef defVreg = liveContext_->ValuesAt(vregId);
276             acc_.NewIn(gate, inIdx, defVreg);
277         } else {
278             GateRef defAcc = liveContext_->ValuesAt(accumulatorIndex_);
279             if (Bytecodes::IsCallOp(opcode)) {
280                 auto oldGt = acc_.GetGateType(defAcc).GetGTRef();
281                 GateType callTargetType = typeRecorder_->GetCallTargetType(bcIndex);
282                 if (!tsManager_->MethodOffsetIsVaild(oldGt) && !callTargetType.IsAnyType()) {
283                     acc_.SetGateType(defAcc, callTargetType);
284                 }
285             }
286             acc_.NewIn(gate, inIdx, defAcc);
287         }
288     }
289 }
290 
AdvanceToNextBc(const BytecodeInfo & bytecodeInfo,FrameLiveOut * liveout,uint32_t bcId)291 void FrameStateBuilder::AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
292 {
293     if (bytecodeInfo.IsGeneral()) {
294         BindStateSplitBefore(bytecodeInfo, liveout, bcId);
295         if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8 ||
296             bytecodeInfo.GetOpcode() == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8) {
297             auto hole = circuit_->GetConstantGate(MachineType::I64,
298                                                   JSTaggedValue::VALUE_HOLE,
299                                                   GateType::TaggedValue());
300             uint32_t numRegs = accumulatorIndex_;
301             std::vector<GateRef> vec(numRegs + 1, hole);
302             vec[0] = liveContext_->currentDepend_;
303             // accumulator is res
304             for (size_t i = 0; i < numRegs; i++) {
305                 if (liveout->TestBit(i)) {
306                     vec[i + 1] = liveContext_->ValuesAt(i);  // 1: skip dep
307                 } else {
308                     vec[i + 1] = hole; // 1: skip dep
309                 }
310             }
311             auto res = circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
312             liveContext_->currentDepend_ = res;
313         }
314     }
315 }
316 
UpdateStateDepend(GateRef state,GateRef depend)317 void FrameStateBuilder::UpdateStateDepend(GateRef state, GateRef depend)
318 {
319     liveContext_->currentState_ = state;
320     liveContext_->currentDepend_ = depend;
321 }
322 
UpdateMoveValues(const BytecodeInfo & bytecodeInfo,uint32_t bcId)323 void FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId)
324 {
325     GateRef gate = Circuit::NullGate();
326     if (bytecodeInfo.AccIn()) {
327         gate = liveContext_->ValuesAt(accumulatorIndex_);
328     } else if (bytecodeInfo.inputs.size() != 0) {
329         auto vreg = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
330         gate = liveContext_->ValuesAt(vreg);
331     }
332     // variable kill
333     if (bytecodeInfo.AccOut()) {
334         liveContext_->SetValuesAt(accumulatorIndex_, gate);
335     } else if (bytecodeInfo.vregOut.size() != 0) {
336         auto vreg = bytecodeInfo.vregOut[0];
337         liveContext_->SetValuesAt(vreg, gate);
338     }
339     if (bcBuilder_->HasTypes()) {
340         GateType type = acc_.GetGateType(gate);
341         if (type.IsAnyType()) {
342             type = typeRecorder_->UpdateType(bcId, type);
343             acc_.SetGateType(gate, type);
344         }
345     }
346 }
347 
UpdateFrameValues(const BytecodeInfo & bytecodeInfo,uint32_t bcId,GateRef gate)348 void FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo,
349     uint32_t bcId, GateRef gate)
350 {
351     ASSERT(!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov());
352     if (bytecodeInfo.IsSetConstant()) {
353         liveContext_->SetValuesAt(accumulatorIndex_, gate);
354         return;
355     }
356     // jump gate is null
357     if (gate != Circuit::NullGate()) {
358         FillBcInputs(bytecodeInfo, bcId, gate);
359     }
360     auto liveout = GetFrameLiveoutAfter(bcId);
361     // variable kill
362     if (bytecodeInfo.AccOut()) {
363         liveContext_->SetValuesAt(accumulatorIndex_, gate);
364     }
365     for (const auto &out: bytecodeInfo.vregOut) {
366         liveContext_->SetValuesAt(out, gate);
367     }
368     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
369         // accumulator is generator object
370         for (size_t i = 0; i < accumulatorIndex_; i++) {
371             if (liveout->TestBit(i)) {
372                 auto restore = circuit_->NewGate(circuit_->RestoreRegister(i),
373                     MachineType::I64, { gate }, GateType::AnyType());
374                 liveContext_->SetValuesAt(i, restore);
375             }
376         }
377     }
378     BindStateSplitAfter(bytecodeInfo, bcId, gate);
379 }
380 
InitEntryBB(const BytecodeRegion & bb)381 void FrameStateBuilder::InitEntryBB(const BytecodeRegion &bb)
382 {
383     auto frameContext = GetOrOCreateMergedContext(bb.id);
384     frameContext->currentState_ = circuit_->GetStateRoot();
385     frameContext->currentDepend_ = circuit_->GetDependRoot();
386     frameContext->needStateSplit_ = true;
387     // initialize argumnets
388     ASSERT(bcBuilder_->IsFirstBasicBlock(1)); // 1: is firstBlock
389     auto liveout = GetFrameLiveoutBefore(1); // 1: is firstBlock
390     GateRef frameArgs = bcBuilder_->GetFrameArgs();
391     if (liveout->TestBit(envIndex_)) {
392         GateRef jsFunc = acc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::FUNC));
393         auto env = acc_.GetInitialEnvGate(jsFunc);
394         frameContext->SetValuesAt(envIndex_, env);
395     }
396     auto holeGate = circuit_->GetConstantGate(MachineType::I64,
397                                               JSTaggedValue::VALUE_HOLE,
398                                               GateType::TaggedValue());
399     for (size_t i = 0; i < envIndex_; i++) {
400         if (liveout->TestBit(i)) {
401             if (bcBuilder_->ArgGateNotExisted(i)) {
402                 frameContext->SetValuesAt(i, holeGate);
403             } else {
404                 GateRef arg = bcBuilder_->GetArgGate(i);
405                 frameContext->SetValuesAt(i, arg);
406             }
407         }
408     }
409 }
410 
NewMerge(const BytecodeRegion & bbNext)411 void FrameStateBuilder::NewMerge(const BytecodeRegion &bbNext)
412 {
413     auto frameContext = GetMergedBbContext(bbNext.id);
414     size_t numOfIns = bbNext.numOfStatePreds;
415     const GateMetaData* metaData = bbNext.loopNumber > 0 ?
416         circuit_->LoopBegin(numOfIns) : circuit_->Merge(numOfIns);
417     auto merge = circuit_->NewGate(metaData,
418         std::vector<GateRef>(numOfIns, Circuit::NullGate()));
419     auto dependMerge = circuit_->NewGate(circuit_->DependSelector(numOfIns),
420         std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
421     acc_.NewIn(dependMerge, 0, merge); // 0: is state
422     // reset current state and depend
423     frameContext->currentState_ = merge;
424     frameContext->currentDepend_ = dependMerge;
425     if (bbNext.loopNumber > 0) {
426         ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
427         auto& loopInfo = GetLoopInfo(bbNext);
428         headerGates[loopInfo.sortIndx] = merge;
429         ASSERT(numOfIns = loopInfo.numLoopBacks + 1); // 1: one entry
430     }
431 }
432 
MergeStateDepend(const BytecodeRegion & bb,const BytecodeRegion & bbNext)433 void FrameStateBuilder::MergeStateDepend(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
434 {
435     GateRef entryState = liveContext_->currentState_;
436     GateRef entryDepend = liveContext_->currentDepend_;
437     auto mergedContext = GetMergedBbContext(bbNext.id);
438     if (bbNext.numOfStatePreds == 1) { // 1: one entry edge
439         mergedContext->currentState_ = liveContext_->currentState_;
440         mergedContext->currentDepend_ = liveContext_->currentDepend_;
441         return;
442     }
443     auto index = mergedContext->currentIndex_;
444     // lazy first edge
445     if (index == 0) {
446         NewMerge(bbNext);
447     }
448     if (IsLoopBackEdge(bb, bbNext)) {
449         ASSERT(index != 0);
450         entryState = circuit_->NewGate(circuit_->LoopBack(), { entryState });
451     }
452     acc_.NewIn(mergedContext->currentState_, index, entryState);
453     acc_.NewIn(mergedContext->currentDepend_, index + 1, entryDepend); // 1: skip state
454     mergedContext->needStateSplit_ = true;
455 }
456 
MergeValue(const BytecodeRegion & bb,GateRef stateMerge,GateRef currentValue,GateRef nextValue,size_t index)457 GateRef FrameStateBuilder::MergeValue(const BytecodeRegion &bb,
458     GateRef stateMerge, GateRef currentValue, GateRef nextValue, size_t index)
459 {
460     ASSERT(stateMerge != Circuit::NullGate());
461     ASSERT(currentValue != Circuit::NullGate());
462     if (nextValue != Circuit::NullGate() &&
463         (acc_.GetOpCode(nextValue) == OpCode::VALUE_SELECTOR && acc_.GetState(nextValue) == stateMerge)) {
464         ASSERT(currentValue != Circuit::NullGate());
465         acc_.NewIn(nextValue, index + 1, currentValue);
466         currentValue = nextValue;
467     } else if (currentValue != nextValue) {
468         auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate()); // 1: state
469         auto phi = circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds),
470             MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
471         acc_.NewIn(phi, 0, stateMerge);
472         if (nextValue != Circuit::NullGate()) {
473             for (size_t i = 0; i < index; i++) {
474                 acc_.NewIn(phi, i + 1, nextValue); // 1: skip state
475             }
476             acc_.NewIn(phi, index + 1, currentValue); // 1: skip state
477         } else {
478             ASSERT(index == 0);
479             acc_.NewIn(phi, 1, currentValue); // 1: skip state
480         }
481         currentValue = phi;
482     }
483     return currentValue;
484 }
485 
MergeAssignment(const BytecodeRegion & bbNext)486 void FrameStateBuilder::MergeAssignment(const BytecodeRegion &bbNext)
487 {
488     auto mergedContext = GetMergedBbContext(bbNext.id);
489     auto stateMerge = mergedContext->currentState_;
490     ASSERT(acc_.IsCFGMerge(stateMerge));
491     auto liveout = GetFrameLiveoutBefore(bbNext.id);
492     auto *loopAssignment = GetLoopAssignment(bbNext);
493     for (size_t i = 0; i < numVregs_; i++) {
494         if (liveout->TestBit(i)) {
495             auto current = liveContext_->ValuesAt(i);
496             auto next = mergedContext->ValuesAt(i);
497             GateRef value = Circuit::NullGate();
498 #ifndef NDEBUG
499             if (loopAssignment == nullptr) {
500                 ASSERT(current != Circuit::NullGate() && next != Circuit::NullGate());
501             } else if (loopAssignment->TestBit(i)) {
502                 // next is null or phi
503                 ASSERT(next == Circuit::NullGate() ||
504                     ((acc_.GetOpCode(next) == OpCode::VALUE_SELECTOR) && acc_.GetState(next) == stateMerge));
505             } else {
506                 ASSERT(next == Circuit::NullGate() || current == next);
507             }
508 #endif
509             if (loopAssignment != nullptr && !loopAssignment->TestBit(i)) {
510                 value = current;
511             } else {
512                 value = MergeValue(bbNext, stateMerge, current, next, mergedContext->currentIndex_);
513             }
514             mergedContext->SetValuesAt(i, value);
515         }
516     }
517 }
518 
CopyLiveoutValues(const BytecodeRegion & bbNext,FrameContext * dest,FrameContext * src)519 void FrameStateBuilder::CopyLiveoutValues(const BytecodeRegion &bbNext,
520     FrameContext* dest, FrameContext* src)
521 {
522     auto liveout = GetFrameLiveoutBefore(bbNext.id);
523     for (size_t i = 0; i < numVregs_; i++) {
524         if (liveout->TestBit(i)) {
525             auto value = src->ValuesAt(i);
526             dest->SetValuesAt(i, value);
527         } else {
528             dest->SetValuesAt(i, Circuit::NullGate());
529         }
530     }
531 }
532 
GetCachedContext()533 FrameContext *FrameStateBuilder::GetCachedContext()
534 {
535     // lazy init cachedContext
536     if (cachedContext_ == nullptr) {
537         auto chunk = circuit_->chunk();
538         cachedContext_ = chunk->New<FrameContext>(chunk, numVregs_);
539     }
540     auto result = cachedContext_;
541     if (cachedContext_ == liveContext_) {
542         if (cachedContextBackup_ == nullptr) {
543             auto chunk = circuit_->chunk();
544             cachedContextBackup_ = chunk->New<FrameContext>(chunk, numVregs_);
545         }
546         result = cachedContextBackup_;
547     }
548     return result;
549 }
550 
SaveCurrentContext(const BytecodeRegion & bb)551 void FrameStateBuilder::SaveCurrentContext(const BytecodeRegion &bb)
552 {
553     auto newContext = GetCachedContext();
554     ASSERT(newContext != liveContext_);
555     newContext->CopyCurrentStatus(liveContext_);
556     CopyLiveoutValues(bb, newContext, liveContext_);
557     liveContext_ = newContext;
558 }
559 
NewLoopExit(const BytecodeRegion & bbNext,BitSet * loopAssignment)560 void FrameStateBuilder::NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAssignment)
561 {
562     auto state = liveContext_->currentState_;
563     auto depend = liveContext_->currentDepend_;
564     auto loopExit = circuit_->NewGate(circuit_->LoopExit(), { state });
565     auto loopExitDepend = circuit_->NewGate(circuit_->LoopExitDepend(),
566         { loopExit, depend });
567     auto liveout = GetFrameLiveoutBefore(bbNext.id);
568     for (size_t i = 0; i < numVregs_; i++) {
569         if (liveout->TestBit(i)) {
570             auto current = liveContext_->ValuesAt(i);
571             if (loopAssignment->TestBit(i)) {
572                 current = circuit_->NewGate(circuit_->LoopExitValue(), acc_.GetMachineType(current),
573                     {loopExit, current}, acc_.GetGateType(current));
574             }
575             liveContext_->SetValuesAt(i, current);
576         } else {
577             ASSERT(liveContext_->ValuesAt(i) == Circuit::NullGate());
578         }
579     }
580     liveContext_->currentState_ = loopExit;
581     liveContext_->currentDepend_ = loopExitDepend;
582     if (!bcBuilder_->IsTypeLoweringEnabled()) {
583         return;
584     }
585     auto stateSplit = BuildStateSplit(liveContext_, liveout, bbNext.start);
586     liveContext_->currentDepend_ = stateSplit;
587 }
588 
TryInsertLoopExit(const BytecodeRegion & bb,const BytecodeRegion & bbNext)589 void FrameStateBuilder::TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
590 {
591     if (!bcBuilder_->EnableLoopOptimization()) {
592         return;
593     }
594     auto currentLoop = GetLoopInfoByLoopBody(bb);
595     if (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
596         // use bbNext as merged values
597         SaveCurrentContext(bbNext);
598     }
599     while (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
600         ASSERT(currentLoop->loopExits != nullptr);
601 #ifndef NDEBUG
602         bool found = false;
603         for (auto current : *currentLoop->loopExits) {
604             if (current->id == bbNext.id) {
605                 found = true;
606                 break;
607             }
608         }
609         ASSERT(found);
610 #endif
611         NewLoopExit(bbNext, currentLoop->loopAssignment);
612         currentLoop = currentLoop->parentInfo;
613     }
614 }
615 
AdvanceToNextBB(const BytecodeRegion & bb)616 void FrameStateBuilder::AdvanceToNextBB(const BytecodeRegion &bb)
617 {
618     liveContext_ = GetMergedBbContext(bb.id);
619     ASSERT(liveContext_ != nullptr);
620     if (bb.loopNumber > 0) {
621         // use bb as merged values
622         SaveCurrentContext(bb);
623     } else {
624         // all input merged
625         ASSERT(liveContext_->currentIndex_ == bb.numOfStatePreds);
626     }
627     if (liveContext_->needStateSplit_) {
628         liveContext_->needStateSplit_ = false;
629         if (!bcBuilder_->IsTypeLoweringEnabled()) {
630             return;
631         }
632         auto liveout = GetOrOCreateBBLiveOut(bb.id);
633         auto stateSplit = BuildStateSplit(liveContext_, liveout, bb.start);
634         liveContext_->currentDepend_ = stateSplit;
635     }
636 }
637 
638 class SubContextScope {
639 public:
SubContextScope(FrameStateBuilder * frameBuilder)640     explicit SubContextScope(FrameStateBuilder* frameBuilder)
641         : frameBuilder_(frameBuilder)
642     {
643         originContext_ = frameBuilder->liveContext_;
644     }
645 
~SubContextScope()646     ~SubContextScope()
647     {
648         frameBuilder_->liveContext_ = originContext_;
649     }
650 private:
651     FrameContext* originContext_ {nullptr};
652     FrameStateBuilder* frameBuilder_ {nullptr};
653 };
654 
MergeIntoSuccessor(const BytecodeRegion & bb,const BytecodeRegion & bbNext)655 void FrameStateBuilder::MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
656 {
657     [[maybe_unused]] SubContextScope scope(this);
658     TryInsertLoopExit(bb, bbNext);
659     auto mergedContext = GetOrOCreateMergedContext(bbNext.id);
660     MergeStateDepend(bb, bbNext);
661     if (mergedContext->currentIndex_ == 0) {
662         if (bbNext.loopNumber > 0) {
663             MergeAssignment(bbNext);
664         } else {
665             CopyLiveoutValues(bbNext, mergedContext, liveContext_);
666         }
667     } else {
668         MergeAssignment(bbNext);
669     }
670     mergedContext->currentIndex_++;
671 }
672 
IsLoopBackEdge(const BytecodeRegion & bb,const BytecodeRegion & bbNext)673 bool FrameStateBuilder::IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
674 {
675     if (bbNext.loopNumber > 0) {
676         auto& loopInfo = GetLoopInfo(bbNext);
677         return loopInfo.loopBodys->TestBit(bb.id);
678     }
679     return false;
680 }
681 
GetLoopInfo(const BytecodeRegion & bb)682 FrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(const BytecodeRegion &bb)
683 {
684     ASSERT(bb.loopNumber > 0);
685     return loops_[bb.loopNumber - 1]; // -1: for index
686 }
687 
GetLoopInfo(BytecodeRegion & bb)688 FrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(BytecodeRegion &bb)
689 {
690     ASSERT(bb.loopNumber > 0);
691     return loops_[bb.loopNumber - 1]; // -1: for index
692 }
693 
GetLoopInfoByLoopBody(const BytecodeRegion & bb)694 FrameStateBuilder::LoopInfo* FrameStateBuilder::GetLoopInfoByLoopBody(const BytecodeRegion &bb)
695 {
696     if (bb.loopIndex == 0) {
697         return nullptr;
698     }
699     auto& loopInfo = loops_[bb.loopIndex - 1];
700     ASSERT(loopInfo.loopBodys->TestBit(bb.id));
701     return &loopInfo;
702 }
703 
GetLoopAssignment(const BytecodeRegion & bb)704 BitSet *FrameStateBuilder::GetLoopAssignment(const BytecodeRegion &bb)
705 {
706     if (bb.loopNumber > 0) {
707         auto& loopInfo = GetLoopInfo(bb);
708         return loopInfo.loopAssignment;
709     }
710     return nullptr;
711 }
712 
AddEmptyBlock(BytecodeRegion * bb)713 void FrameStateBuilder::AddEmptyBlock(BytecodeRegion* bb)
714 {
715     bbBeginStateLiveouts_.emplace_back(nullptr);
716     bbFrameContext_.emplace_back(nullptr);
717     auto liveout = GetOrOCreateBBLiveOut(bb->id);
718     liveout->CopyFrom(liveOutResult_);
719     GetOrOCreateMergedContext(bb->id);
720     bcBuilder_->AddBasicBlock(bb);
721 }
722 
723 class BlockLoopAnalysis {
724 public:
BlockLoopAnalysis(FrameStateBuilder * builder,Chunk * chunk)725     explicit BlockLoopAnalysis(FrameStateBuilder *builder, Chunk* chunk)
726         : frameBuilder_(builder), bcBuilder_(builder->bcBuilder_),
727         pendingList_(chunk), loopbacks_(chunk),
728         dfsStack_(chunk), visitState_(chunk), chunk_(chunk) {}
729 
Run()730     void Run()
731     {
732         ComputeLoopBack();
733         TryClearDeadBlock();
734         frameBuilder_->numLoops_ = numLoops_;
735         if (numLoops_ > 0) {
736             ComputeLoopInfo();
737             if (bcBuilder_->IsLogEnabled()) {
738                 for (size_t i = 0; i < numLoops_; i++) {
739                     auto& loopInfo = frameBuilder_->loops_[i];
740                     PrintLoop(loopInfo);
741                 }
742             }
743         }
744     }
745 
CountLoopBackEdge(size_t fromId,size_t toId)746     void CountLoopBackEdge(size_t fromId, size_t toId)
747     {
748         loopbacks_.push_back({fromId, toId});
749         auto &toBlock = bcBuilder_->GetBasicBlockById(toId);
750         if (toBlock.loopNumber == 0) {
751             toBlock.loopNumber = ++numLoops_;
752         }
753     }
754 
ComputeLoopBack()755     void ComputeLoopBack()
756     {
757         auto size = bcBuilder_->GetBasicBlockCount();
758         visitState_.resize(size, MarkState::UNVISITED);
759         size_t entryId = 0; // entry id
760         pendingList_.emplace_back(entryId);
761         while (!pendingList_.empty()) {
762             size_t bbId = pendingList_.back();
763             auto &bb = bcBuilder_->GetBasicBlockById(bbId);
764             bool allVisited = true;
765             visitState_[bbId] = MarkState::PENDING;
766             auto it = bb.succs.begin();
767             BytecodeRegion* catchBlock = bb.catches.empty() ? nullptr : bb.catches.at(0);
768             while (it != bb.succs.end() || (catchBlock != nullptr)) {
769                 BytecodeRegion* succBlock = nullptr;
770                 if (it != bb.succs.end()) {
771                     succBlock = *it;
772                     it++;
773                 } else if (catchBlock != nullptr) {
774                     succBlock = catchBlock;
775                     catchBlock = nullptr;
776                 }
777                 size_t succId = succBlock->id;
778                 if (visitState_[succId] == MarkState::UNVISITED) {
779                     pendingList_.emplace_back(succId);
780                     visitState_[succId] = MarkState::ON_STACK;
781                     allVisited = false;
782                     break;
783                 } else if (visitState_[succId] == MarkState::PENDING) {
784                     // back edge
785                     CountLoopBackEdge(bbId, succId);
786                 }
787             }
788             if (allVisited) {
789                 visitState_[bbId] = MarkState::VISITED;
790                 pendingList_.pop_back();
791                 frameBuilder_->rpoList_.push_front(bbId);
792             }
793         }
794     }
795 
TryClearDeadBlock()796     void TryClearDeadBlock()
797     {
798         if (frameBuilder_->rpoList_.size() == bcBuilder_->NumberOfLiveBlock()) {
799             return;
800         }
801         auto size = bcBuilder_->GetBasicBlockCount();
802         for (size_t i = 0; i < size; i++) {
803             auto &bb = bcBuilder_->GetBasicBlockById(i);
804             if (bb.numOfStatePreds != 0 && visitState_[i] == MarkState::UNVISITED) {
805                 bb.numOfStatePreds = 0;
806             }
807         }
808         bcBuilder_->RemoveUnreachableRegion();
809     }
810 
CountLoopBody(FrameStateBuilder::LoopInfo & loopInfo,size_t bbId)811     void CountLoopBody(FrameStateBuilder::LoopInfo& loopInfo, size_t bbId)
812     {
813         if (bbId != loopInfo.loopHeadId && !loopInfo.loopBodys->TestBit(bbId)) {
814             loopInfo.loopBodys->SetBit(bbId);
815             pendingList_.emplace_back(bbId);
816             auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(bbId);
817             ASSERT(liveout != nullptr);
818             loopInfo.loopAssignment->Union(liveout->defRegisters_);
819         }
820     }
821 
PropagateLoopBody(FrameStateBuilder::LoopInfo & loopInfo)822     void PropagateLoopBody(FrameStateBuilder::LoopInfo& loopInfo)
823     {
824         while (!pendingList_.empty()) {
825             auto cur = pendingList_.back();
826             auto &curBlock = bcBuilder_->GetBasicBlockById(cur);
827             pendingList_.pop_back();
828             for (auto pred : curBlock.preds) {
829                 CountLoopBody(loopInfo, pred->id);
830             }
831             for (auto pred : curBlock.trys) {
832                 CountLoopBody(loopInfo, pred->id);
833             }
834         }
835     }
836 
InitLoopInfo(FrameStateBuilder::LoopInfo & loopInfo,BytecodeRegion & loopHeader,size_t backId)837     void InitLoopInfo(FrameStateBuilder::LoopInfo& loopInfo, BytecodeRegion& loopHeader, size_t backId)
838     {
839         if (loopInfo.loopHeadId == 0) {
840             auto size = bcBuilder_->GetBasicBlockCount();
841             loopInfo.loopHeadId = loopHeader.id;
842             loopInfo.loopIndex = loopHeader.loopNumber;
843             loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
844             loopInfo.loopAssignment = chunk_->New<BitSet>(chunk_, frameBuilder_->numVregs_);
845             loopHeader.loopIndex = loopInfo.loopIndex;
846             loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
847             auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(loopInfo.loopHeadId);
848             loopInfo.loopAssignment->Union(liveout->defRegisters_);
849             loopInfo.numLoopBacks = 1;
850             loopInfo.loopBodys->SetBit(backId);
851         } else {
852             if (!loopInfo.loopBodys->TestBit(backId)) {
853                 loopInfo.loopBodys->SetBit(backId);
854             }
855             loopInfo.numLoopBacks++;
856         }
857     }
858 
ComputeLoopInfo()859     void ComputeLoopInfo()
860     {
861         frameBuilder_->loops_.resize(numLoops_, FrameStateBuilder::LoopInfo());
862         for (auto& info : loopbacks_) {
863             auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
864             auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
865             InitLoopInfo(loopInfo, toBlock, info.fromId);
866         }
867         TryMergeLoopEntry();
868         ResizeLoopBody(); // tryMerge will insert region, need resize loop body.
869         for (auto& info : loopbacks_) {
870             auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
871             auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
872             CountLoopBody(loopInfo, info.fromId);
873             PropagateLoopBody(loopInfo);
874         }
875         if (!bcBuilder_->EnableLoopOptimization()) {
876             return;
877         }
878         auto size = bcBuilder_->GetBasicBlockCount();
879         dfsStack_.resize(size, DFSState(0, 0));
880         ComputeLoopTree();
881     }
882 
InsertEmptyBytecodeRegion(FrameStateBuilder::LoopInfo & loopInfo,BytecodeRegion & loopHeader,size_t numOfEntries)883     void InsertEmptyBytecodeRegion(FrameStateBuilder::LoopInfo& loopInfo,
884         BytecodeRegion& loopHeader, size_t numOfEntries)
885     {
886         auto size = bcBuilder_->GetBasicBlockCount();
887         auto block = chunk_->New<BytecodeRegion>(chunk_);
888         block->id = size;
889         block->numOfStatePreds = numOfEntries;
890         block->start = loopHeader.start;
891         ASSERT(loopHeader.start != 0);
892         block->end = BytecodeIterator::INVALID_INDEX;
893         block->bytecodeIterator_.Reset(bcBuilder_, block->start, block->end);
894 
895         frameBuilder_->liveOutResult_->Reset();
896         for (auto it = loopHeader.preds.begin(); it != loopHeader.preds.end();) {
897             auto bbPred = *it;
898             // not loop back
899             if (!loopInfo.loopBodys->TestBit(bbPred->id)) {
900                 it = loopHeader.preds.erase(it);
901                 std::replace(bbPred->succs.begin(), bbPred->succs.end(), &loopHeader, block);
902                 block->preds.emplace_back(bbPred);
903             } else {
904                 it++;
905             }
906         }
907         frameBuilder_->MergeFromSuccBB(loopHeader.id);
908         block->succs.emplace_back(&loopHeader);
909         loopHeader.preds.insert(loopHeader.preds.begin(), block);
910         frameBuilder_->AddEmptyBlock(block);
911 
912         ASSERT(loopHeader.trys.empty());
913         loopHeader.numOfStatePreds -= (numOfEntries - 1); // 1: one entry
914         auto it = std::find(frameBuilder_->rpoList_.begin(), frameBuilder_->rpoList_.end(), loopHeader.id);
915         ASSERT(it != frameBuilder_->rpoList_.end());
916         frameBuilder_->rpoList_.insert(it, block->id);
917         visitState_.emplace_back(MarkState::UNVISITED1);
918     }
919 
TryMergeLoopEntry()920     void TryMergeLoopEntry()
921     {
922         for (size_t i = 0; i < numLoops_; i++) {
923             auto& loopInfo = frameBuilder_->loops_[i];
924             auto& loopHeader = bcBuilder_->GetBasicBlockById(loopInfo.loopHeadId);
925             size_t numOfEntries = static_cast<size_t>(loopHeader.numOfStatePreds - loopInfo.numLoopBacks);
926             if (numOfEntries > 1 && loopHeader.trys.size() == 0) {
927                 InsertEmptyBytecodeRegion(loopInfo, loopHeader, numOfEntries);
928             }
929             // clear loopback bits for visit body
930             loopInfo.loopBodys->Reset();
931             loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
932         }
933     }
934 
ResizeLoopBody()935     void ResizeLoopBody()
936     {
937         for (auto& info : loopbacks_) {
938             auto size = bcBuilder_->GetBasicBlockCount();
939             auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
940             auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
941             if (loopInfo.loopBodys->ShouldExpand(size)) {
942                 auto tmp = loopInfo.loopBodys;
943                 loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
944                 loopInfo.loopBodys->CopyDataFrom(*tmp);
945             }
946         }
947     }
948 
EnterInnerLoop(FrameStateBuilder::LoopInfo * loopInfo,size_t bbId)949     FrameStateBuilder::LoopInfo* EnterInnerLoop(FrameStateBuilder::LoopInfo* loopInfo, size_t bbId)
950     {
951         auto &bb = bcBuilder_->GetBasicBlockById(bbId);
952         if (bb.loopNumber > 0) {
953             auto &innerInfo = frameBuilder_->GetLoopInfo(bb);
954             ASSERT(innerInfo.parentInfo == nullptr);
955             innerInfo.parentInfo = loopInfo;
956             innerInfo.sortIndx = frameBuilder_->sortIndx_++;
957             loopInfo = &innerInfo;
958         } else if (loopInfo != nullptr) {
959             bb.loopIndex = loopInfo->loopIndex;
960         }
961         return loopInfo;
962     }
963 
ComputeLoopTree()964     void ComputeLoopTree()
965     {
966         FrameStateBuilder::LoopInfo* loopInfo = nullptr;
967         auto currentDepth = Push(0, 0); // entry id
968         while (currentDepth > 0) {
969             auto &curState = dfsStack_[currentDepth - 1]; // -1: for current
970             auto const &bb = bcBuilder_->GetBasicBlockById(curState.bbId);
971             ASSERT(bb.catches.empty());
972             auto index = curState.index;
973             BytecodeRegion* bbNext = nullptr;
974             if (index >= bb.succs.size()) {
975                 if (bb.loopNumber > 0) {
976                     if (visitState_[curState.bbId] == MarkState::ON_STACK) {
977                         ASSERT(loopInfo->loopHeadId == curState.bbId);
978                         loopInfo = loopInfo->parentInfo;
979                         visitState_[curState.bbId] = MarkState::VISITED1;
980                     }
981                     bbNext = PushLoopExist(bb, currentDepth);
982                 }
983             } else {
984                 bbNext = bb.succs[curState.index++]; // 1: goto next
985             }
986             if (bbNext != nullptr) {
987                 if (loopInfo != nullptr && !loopInfo->loopBodys->TestBit(bbNext->id)) {
988                     AddLoopExit(bbNext, loopInfo);
989                 } else if (visitState_[bbNext->id] == MarkState::UNVISITED1) {
990                     currentDepth = Push(bbNext->id, currentDepth);
991                     loopInfo = EnterInnerLoop(loopInfo, bbNext->id);
992                 }
993             } else {
994                 if (bb.loopNumber == 0) {
995                     visitState_[curState.bbId] = MarkState::VISITED1;
996                 }
997                 currentDepth--;
998             }
999         }
1000     }
1001 
Push(size_t bbId,size_t depth)1002     size_t Push(size_t bbId, size_t depth)
1003     {
1004         if (visitState_[bbId] == MarkState::UNVISITED1) {
1005             dfsStack_[depth].bbId = bbId;
1006             dfsStack_[depth].index = 0;
1007             visitState_[bbId] = MarkState::ON_STACK;
1008             return depth + 1;
1009         }
1010         return depth;
1011     }
1012 
PushLoopExist(const BytecodeRegion & bb,size_t depth)1013     BytecodeRegion* PushLoopExist(const BytecodeRegion& bb, size_t depth)
1014     {
1015         auto &curState = dfsStack_[depth - 1]; // -1: for current
1016         auto loopExitIndex = curState.index - bb.succs.size();
1017         auto& currentInfo = frameBuilder_->GetLoopInfo(bb);
1018         BytecodeRegion* bbNext = nullptr;
1019         if (currentInfo.loopExits != nullptr && loopExitIndex < currentInfo.loopExits->size()) {
1020             bbNext = currentInfo.loopExits->at(loopExitIndex);
1021             curState.index++; // 1: goto next
1022         }
1023         return bbNext;
1024     }
1025 
AddLoopExit(BytecodeRegion * bb,FrameStateBuilder::LoopInfo * loopInfo)1026     void AddLoopExit(BytecodeRegion *bb, FrameStateBuilder::LoopInfo *loopInfo)
1027     {
1028         if (loopInfo->loopExits == nullptr) {
1029             loopInfo->loopExits = chunk_->New<ChunkVector<BytecodeRegion*>>(chunk_);
1030         }
1031         loopInfo->loopExits->emplace_back(bb);
1032     }
1033 
PrintLoop(FrameStateBuilder::LoopInfo & loopInfo)1034     void PrintLoop(FrameStateBuilder::LoopInfo& loopInfo)
1035     {
1036         auto size = bcBuilder_->GetBasicBlockCount();
1037         LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
1038         LOG_COMPILER(INFO) << "LoopHead: " << loopInfo.loopHeadId;
1039         if (loopInfo.parentInfo != nullptr) {
1040             LOG_COMPILER(INFO) << "ParentLoopHead: " << loopInfo.parentInfo->loopHeadId;
1041         }
1042         std::string log = "Body: [";
1043         for (size_t i = 0; i < size; i++) {
1044             if (loopInfo.loopBodys->TestBit(i)) {
1045                 log += std::to_string(i) + ", ";
1046             }
1047         }
1048         LOG_COMPILER(INFO) << log << "]";
1049         std::string log1 = "Exit: [";
1050         if (loopInfo.loopExits != nullptr) {
1051             for (auto bb : *loopInfo.loopExits) {
1052                 log1 += std::to_string(bb->id) + ", ";
1053             }
1054         }
1055         LOG_COMPILER(INFO) << log1 << "]";
1056         std::string log2 = "LoopAssignment [";
1057         bool firset = true;
1058         for (size_t i = 0; i < frameBuilder_->numVregs_; i++) {
1059             if (loopInfo.loopAssignment->TestBit(i)) {
1060                 if (!firset) {
1061                     log2 += ",";
1062                 }
1063                 firset = false;
1064                 log2 += std::to_string(i);
1065             }
1066         }
1067         LOG_COMPILER(INFO) << log2 << "]";
1068         LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
1069     }
1070 
1071 private:
1072     struct EndToHead {
1073         size_t fromId;
1074         size_t toId;
1075     };
1076     struct DFSState {
DFSStatepanda::ecmascript::kungfu::BlockLoopAnalysis::DFSState1077         DFSState(size_t bbId, size_t index)
1078             : bbId(bbId), index(index) {}
1079 
1080         size_t bbId;
1081         size_t index;
1082     };
1083     enum class MarkState : uint8_t {
1084         UNVISITED = 0,
1085         ON_STACK,
1086         PENDING,
1087         VISITED,
1088         VISITED1,
1089         UNVISITED1 = VISITED
1090     };
1091     FrameStateBuilder* frameBuilder_ {nullptr};
1092     BytecodeCircuitBuilder *bcBuilder_ {nullptr};
1093     ChunkDeque<size_t> pendingList_;
1094     ChunkVector<EndToHead> loopbacks_;
1095     ChunkVector<DFSState> dfsStack_;
1096     ChunkVector<MarkState> visitState_;
1097     Chunk* chunk_ {nullptr};
1098     size_t numLoops_ {0};
1099 };
1100 
ComputeLoopInfo()1101 void FrameStateBuilder::ComputeLoopInfo()
1102 {
1103     BlockLoopAnalysis loopAnalysis(this, circuit_->chunk());
1104     loopAnalysis.Run();
1105     if (numLoops_ != 0) {
1106         ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
1107         headerGates.resize(numLoops_, Circuit::NullGate());
1108     }
1109 }
1110 
DumpLiveState()1111 void FrameStateBuilder::DumpLiveState()
1112 {
1113     LOG_COMPILER(INFO) << "DumpLiveState";
1114     for (size_t i = 0; i < bcEndStateLiveouts_.size(); i++) {
1115         auto liveout = GetFrameLiveoutAfter(i);
1116         if (liveout == nullptr) {
1117             continue;
1118         }
1119         std::string log = "BC: " + std::to_string(i) + " {";
1120         bool firset = true;
1121         for (size_t j = 0; j < numVregs_; j++) {
1122             if (liveout->TestBit(j)) {
1123                 if (!firset) {
1124                     log += ",";
1125                 }
1126                 firset = false;
1127                 log += std::to_string(j);
1128             }
1129         }
1130         log += "}";
1131         LOG_COMPILER(INFO) << log;
1132     }
1133     for (size_t i = 1; i < bbBeginStateLiveouts_.size(); i++) { // 1: skip entry
1134         auto liveout = GetFrameLiveoutBefore(i);
1135         if (liveout == nullptr) {
1136             continue;
1137         }
1138         std::string log = "BB: " + std::to_string(i) + " {";
1139         bool firset = true;
1140         for (size_t j = 0; j < numVregs_; j++) {
1141             if (liveout->TestBit(j)) {
1142                 if (!firset) {
1143                     log += ",";
1144                 }
1145                 firset = false;
1146                 log += std::to_string(j);
1147             }
1148         }
1149         log += "}";
1150         LOG_COMPILER(INFO) << log;
1151     }
1152 }
1153 
BuildFrameState(FrameContext * frameContext,FrameLiveOut * liveout,size_t bcIndex)1154 GateRef FrameStateBuilder::BuildFrameState(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
1155 {
1156     auto pcOffset = bcBuilder_->GetPcOffset(bcIndex);
1157     GateRef gateValues = BuildFrameValues(frameContext, liveout);
1158 
1159     GateRef frameArgs = bcBuilder_->GetFrameArgs();
1160     GateRef preFrameState = bcBuilder_->GetPreFrameState();
1161     UInt32PairAccessor accessor(static_cast<uint32_t>(pcOffset),
1162         FrameStateOutput::Invalid().GetValue());
1163     auto frameState = circuit_->NewGate(circuit_->FrameState(accessor.ToValue()),
1164         {frameArgs, gateValues, preFrameState});
1165     return frameState;
1166 }
1167 
BuildStateSplit(FrameContext * frameContext,FrameLiveOut * liveout,size_t bcIndex)1168 GateRef FrameStateBuilder::BuildStateSplit(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
1169 {
1170     auto frameState = BuildFrameState(frameContext, liveout, bcIndex);
1171     auto state = frameContext->currentState_;
1172     auto depend = frameContext->currentDepend_;
1173     ASSERT(state != Circuit::NullGate());
1174     ASSERT(depend != Circuit::NullGate());
1175     return circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
1176 }
1177 
BindStateSplitBefore(const BytecodeInfo & bytecodeInfo,FrameLiveOut * liveout,uint32_t bcId)1178 void FrameStateBuilder::BindStateSplitBefore(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
1179 {
1180     if (!bcBuilder_->IsTypeLoweringEnabled()) {
1181         return;
1182     }
1183     if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
1184         frameStateCache_ = BuildFrameState(liveContext_, liveout, bcId);
1185     }
1186     ASSERT(!liveContext_->needStateSplit_);
1187 }
1188 
BindStateSplitAfter(const BytecodeInfo & bytecodeInfo,uint32_t bcId,GateRef gate)1189 void FrameStateBuilder::BindStateSplitAfter(const BytecodeInfo &bytecodeInfo,
1190     uint32_t bcId, GateRef gate)
1191 {
1192     if (!bcBuilder_->IsTypeLoweringEnabled()) {
1193         return;
1194     }
1195     if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
1196         auto frameState = GetBcFrameStateCache();
1197         acc_.ReplaceFrameStateIn(gate, frameState);
1198     }
1199     if (!bytecodeInfo.NoSideEffects() && !bytecodeInfo.IsThrow()) {
1200         auto stateSplit = BuildStateSplit(liveContext_, GetOrOCreateBCEndLiveOut(bcId), bcId + 1); // 1: for after
1201         liveContext_->currentDepend_ = stateSplit;
1202     }
1203 }
1204 
BuildFrameValues(FrameContext * frameContext,FrameLiveOut * liveout)1205 GateRef FrameStateBuilder::BuildFrameValues(FrameContext* frameContext, FrameLiveOut* liveout)
1206 {
1207     size_t frameStateInputs = numVregs_;
1208     std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
1209     auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
1210                                                    JSTaggedValue::VALUE_OPTIMIZED_OUT,
1211                                                    GateType::TaggedValue());
1212     for (size_t i = 0; i < numVregs_; i++) {
1213         auto value = frameContext->ValuesAt(i);
1214         if (value == Circuit::NullGate() || !liveout->TestBit(i)) {
1215             value = optimizedGate;
1216         }
1217         inList[i] = value;
1218     }
1219     return circuit_->NewGate(circuit_->FrameValues(frameStateInputs), inList);
1220 }
1221 }
1222