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