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 <cstddef>
18
19 namespace panda::ecmascript::kungfu {
FrameStateBuilder(BytecodeCircuitBuilder * builder,Circuit * circuit,const MethodLiteral * literal)20 FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
21 Circuit *circuit, const MethodLiteral *literal)
22 : builder_(builder),
23 numVregs_(literal->GetNumberVRegs() + FIXED_ARGS),
24 accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc
25 circuit_(circuit),
26 gateAcc_(circuit),
27 bcEndStateInfos_(circuit->chunk()),
28 bbBeginStateInfos_(circuit->chunk()),
29 postOrderList_(circuit->chunk())
30 {
31 }
32
~FrameStateBuilder()33 FrameStateBuilder::~FrameStateBuilder()
34 {
35 liveOutResult_ = nullptr;
36 bcEndStateInfos_.clear();
37 bbBeginStateInfos_.clear();
38 builder_ = nullptr;
39 }
40
BuildFrameValues(FrameStateInfo * stateInfo)41 GateRef FrameStateBuilder::BuildFrameValues(FrameStateInfo *stateInfo)
42 {
43 size_t frameStateInputs = numVregs_;
44 std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
45 auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
46 JSTaggedValue::VALUE_OPTIMIZED_OUT,
47 GateType::TaggedValue());
48 for (size_t i = 0; i < numVregs_; i++) {
49 auto value = stateInfo->ValuesAt(i);
50 if (value == Circuit::NullGate()) {
51 value = optimizedGate;
52 }
53 inList[i] = value;
54 }
55 return circuit_->NewGate(circuit_->FrameValues(frameStateInputs), inList);
56 }
57
BuildFrameStateGate(size_t pcOffset,GateRef frameValues,FrameStateOutput output)58 GateRef FrameStateBuilder::BuildFrameStateGate(size_t pcOffset, GateRef frameValues, FrameStateOutput output)
59 {
60 GateRef frameArgs = builder_->GetFrameArgs();
61 GateRef preFrameState = builder_->GetPreFrameState();
62 UInt32PairAccessor accessor(static_cast<uint32_t>(pcOffset), output.GetValue());
63 return circuit_->NewGate(circuit_->FrameState(accessor.ToValue()),
64 {frameArgs, frameValues, preFrameState});
65 }
66
BindStateSplit(GateRef state,GateRef depend,GateRef frameState)67 void FrameStateBuilder::BindStateSplit(GateRef state, GateRef depend, GateRef frameState)
68 {
69 GateRef stateSplit = circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
70 auto uses = gateAcc_.Uses(depend);
71 for (auto useIt = uses.begin(); useIt != uses.end();) {
72 if (gateAcc_.IsDependIn(useIt) && *useIt != stateSplit) {
73 useIt = gateAcc_.ReplaceIn(useIt, stateSplit);
74 } else {
75 useIt++;
76 }
77 }
78 if (builder_->IsLogEnabled()) {
79 gateAcc_.ShortPrint(frameState);
80 }
81 }
82
BindStateSplit(GateRef gate,GateRef frameState)83 void FrameStateBuilder::BindStateSplit(GateRef gate, GateRef frameState)
84 {
85 auto state = gateAcc_.GetState(gate);
86 auto depend = gateAcc_.GetDep(gate);
87 if (gateAcc_.GetOpCode(state) == OpCode::IF_SUCCESS) {
88 state = gateAcc_.GetState(state);
89 }
90 GateRef stateSplit = circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
91 gateAcc_.ReplaceDependIn(gate, stateSplit);
92 if (builder_->IsLogEnabled()) {
93 gateAcc_.ShortPrint(frameState);
94 }
95 }
96
CreateEmptyStateInfo()97 FrameStateInfo *FrameStateBuilder::CreateEmptyStateInfo()
98 {
99 auto chunk = circuit_->chunk();
100 auto frameInfo = chunk->New<FrameStateInfo>(chunk, numVregs_);
101 for (size_t i = 0; i < numVregs_; i++) {
102 frameInfo->SetValuesAt(i, Circuit::NullGate());
103 }
104 return frameInfo;
105 }
106
BuildPostOrderList(size_t size)107 void FrameStateBuilder::BuildPostOrderList(size_t size)
108 {
109 postOrderList_.clear();
110 std::deque<size_t> pendingList;
111 std::vector<bool> visited(size, false);
112 // entry block (bbid=0) is a empty block, need skip
113 auto firstBlockId = 1;
114 pendingList.emplace_back(firstBlockId);
115
116 while (!pendingList.empty()) {
117 size_t curBlockId = pendingList.back();
118 visited[curBlockId] = true;
119
120 bool change = false;
121 auto &bb = builder_->GetBasicBlockById(curBlockId);
122 for (const auto &succBlock: bb.succs) {
123 if (!visited[succBlock->id]) {
124 pendingList.emplace_back(succBlock->id);
125 change = true;
126 break;
127 }
128 }
129 if (change) {
130 continue;
131 }
132 for (const auto &succBlock: bb.catchs) {
133 if (!visited[succBlock->id]) {
134 pendingList.emplace_back(succBlock->id);
135 change = true;
136 break;
137 }
138 }
139 if (!change) {
140 postOrderList_.emplace_back(curBlockId);
141 pendingList.pop_back();
142 }
143 }
144 }
145
MergeIntoPredBC(uint32_t predPc,size_t diff)146 bool FrameStateBuilder::MergeIntoPredBC(uint32_t predPc, size_t diff)
147 {
148 // liveout next
149 auto frameInfo = GetOrOCreateBCEndStateInfo(predPc);
150 FrameStateInfo *predFrameInfo = liveOutResult_;
151 bool changed = frameInfo->MergeLiveout(predFrameInfo);
152 if (!changed) {
153 return changed;
154 }
155 for (size_t i = 0; i < numVregs_; i++) {
156 auto predValue = predFrameInfo->ValuesAt(i);
157 auto value = frameInfo->ValuesAt(i);
158 // if value not null, merge pred
159 if (value == Circuit::NullGate() && predValue != Circuit::NullGate()) {
160 predValue = TryGetLoopExitValue(predValue, diff);
161 frameInfo->SetValuesAt(i, predValue);
162 changed = true;
163 }
164 }
165 return changed;
166 }
167
GetPreBBInput(BytecodeRegion * bb,BytecodeRegion * predBb,GateRef gate)168 GateRef FrameStateBuilder::GetPreBBInput(BytecodeRegion *bb, BytecodeRegion *predBb, GateRef gate)
169 {
170 if (gateAcc_.GetOpCode(gate) == OpCode::VALUE_SELECTOR) {
171 return GetPhiComponent(bb, predBb, gate);
172 }
173 return gate;
174 }
175
GetPhiComponent(BytecodeRegion * bb,BytecodeRegion * predBb,GateRef phi)176 GateRef FrameStateBuilder::GetPhiComponent(BytecodeRegion *bb, BytecodeRegion *predBb, GateRef phi)
177 {
178 ASSERT(gateAcc_.GetOpCode(phi) == OpCode::VALUE_SELECTOR);
179
180 if (bb->phiGate.find(phi) == bb->phiGate.end()) {
181 return Circuit::NullGate();
182 }
183
184 if (bb->numOfLoopBacks != 0) {
185 ASSERT(bb->loopbackBlocks.size() != 0);
186 auto forwardValue = gateAcc_.GetValueIn(phi, 0); // 0: fowward
187 auto loopBackValue = gateAcc_.GetValueIn(phi, 1); // 1: back
188 size_t backIndex = 0;
189 size_t forwardIndex = 0;
190 for (size_t i = 0; i < bb->numOfStatePreds; ++i) {
191 auto predId = std::get<0>(bb->expandedPreds.at(i));
192 if (bb->loopbackBlocks.count(predId)) {
193 if (predId == predBb->id) {
194 if (bb->numOfLoopBacks == 1) {
195 return loopBackValue;
196 }
197 return gateAcc_.GetValueIn(loopBackValue, backIndex);
198 }
199 backIndex++;
200 } else {
201 if (predId == predBb->id) {
202 auto mergeCount = bb->numOfStatePreds - bb->numOfLoopBacks;
203 if (mergeCount == 1) {
204 return forwardValue;
205 }
206 return gateAcc_.GetValueIn(forwardValue, forwardIndex);
207 }
208 forwardIndex++;
209 }
210 }
211 return Circuit::NullGate();
212 }
213
214 ASSERT(gateAcc_.GetNumValueIn(phi) == bb->numOfStatePreds);
215 // The phi input nodes need to be traversed in reverse order, because there is a bb with multiple def points
216 for (size_t i = bb->numOfStatePreds - 1; i >= 0; --i) {
217 auto predId = std::get<0>(bb->expandedPreds.at(i));
218 if (predId == predBb->id) {
219 return gateAcc_.GetValueIn(phi, i);
220 }
221 }
222 return Circuit::NullGate();
223 }
224
MergeIntoPredBB(BytecodeRegion * bb,BytecodeRegion * predBb)225 bool FrameStateBuilder::MergeIntoPredBB(BytecodeRegion *bb, BytecodeRegion *predBb)
226 {
227 bool changed = MergeIntoPredBC(predBb->end, LoopExitCount(predBb, bb));
228 if (!changed) {
229 return changed;
230 }
231 auto predLiveout = GetOrOCreateBCEndStateInfo(predBb->end);
232 // replace phi
233 if (bb->valueSelectorAccGate != Circuit::NullGate()) {
234 auto phi = bb->valueSelectorAccGate;
235 auto value = predLiveout->ValuesAt(accumulatorIndex_);
236 if (value == phi) {
237 auto target = GetPreBBInput(bb, predBb, phi);
238 if (target != Circuit::NullGate()) {
239 auto diff = LoopExitCount(predBb, bb);
240 target = TryGetLoopExitValue(target, diff);
241 predLiveout->SetValuesAt(accumulatorIndex_, target);
242 }
243 }
244 }
245 for (auto &it : bb->vregToValueGate) {
246 auto reg = it.first;
247 auto gate = it.second;
248 auto value = predLiveout->ValuesAt(reg);
249 if (value == gate) {
250 auto target = GetPreBBInput(bb, predBb, gate);
251 if (target == Circuit::NullGate()) {
252 continue;
253 }
254 auto diff = LoopExitCount(predBb, bb);
255 target = TryGetLoopExitValue(target, diff);
256 predLiveout->SetValuesAt(reg, target);
257 }
258 }
259 return changed;
260 }
261
ComputeLiveOut(size_t bbId)262 bool FrameStateBuilder::ComputeLiveOut(size_t bbId)
263 {
264 auto &bb = builder_->GetBasicBlockById(bbId);
265 bool changed = false;
266 ASSERT(!bb.isDead);
267 // iterator bc
268 auto &iterator = bb.GetBytecodeIterator();
269 iterator.GotoEnd();
270 ASSERT(bb.end == iterator.Index());
271 auto liveout = GetOrOCreateBCEndStateInfo(bb.end);
272 liveOutResult_->CopyFrom(liveout);
273 while (true) {
274 auto &bytecodeInfo = iterator.GetBytecodeInfo();
275 ComputeLiveOutBC(iterator.Index(), bytecodeInfo, bbId);
276 --iterator;
277 if (iterator.Done()) {
278 break;
279 }
280 auto prevPc = iterator.Index();
281 changed |= MergeIntoPredBC(prevPc, 0);
282 }
283
284 SaveBBBeginStateInfo(bbId);
285
286 bool defPhi = bb.valueSelectorAccGate != Circuit::NullGate() ||
287 bb.vregToValueGate.size() != 0;
288 // merge current into pred bb
289 for (auto bbPred : bb.preds) {
290 if (bbPred->isDead) {
291 continue;
292 }
293 if (defPhi) {
294 changed |= MergeIntoPredBB(&bb, bbPred);
295 } else {
296 changed |= MergeIntoPredBC(bbPred->end, LoopExitCount(bbPred, &bb));
297 }
298 }
299 if (!bb.trys.empty()) {
300 // clear GET_EXCEPTION gate if this is a catch block
301 UpdateAccumulator(Circuit::NullGate());
302 for (auto bbPred : bb.trys) {
303 if (bbPred->isDead) {
304 continue;
305 }
306 if (defPhi) {
307 changed |= MergeIntoPredBB(&bb, bbPred);
308 } else {
309 changed |= MergeIntoPredBC(bbPred->end, LoopExitCount(bbPred, &bb));
310 }
311 }
312 }
313
314 return changed;
315 }
316
ComputeLiveState()317 void FrameStateBuilder::ComputeLiveState()
318 {
319 // recompute liveout
320 bool changed = true;
321 while (changed) {
322 changed = false;
323 for (size_t i = 0; i < postOrderList_.size(); i++) {
324 changed |= ComputeLiveOut(postOrderList_[i]);
325 }
326 }
327 }
328
BuildFrameState()329 void FrameStateBuilder::BuildFrameState()
330 {
331 bcEndStateInfos_.resize(builder_->GetLastBcIndex() + 1, nullptr); // 1: +1 pcOffsets size
332 auto size = builder_->GetBasicBlockCount();
333 bbBeginStateInfos_.resize(size, nullptr);
334 liveOutResult_ = CreateEmptyStateInfo();
335 BuildPostOrderList(size);
336 ComputeLiveState();
337 BindBBStateSplit();
338 }
339
ComputeLiveOutBC(uint32_t index,const BytecodeInfo & bytecodeInfo,size_t bbId)340 void FrameStateBuilder::ComputeLiveOutBC(uint32_t index, const BytecodeInfo &bytecodeInfo, size_t bbId)
341 {
342 if (bytecodeInfo.IsMov()) {
343 auto gate = Circuit::NullGate();
344 // variable kill
345 if (bytecodeInfo.AccOut()) {
346 gate = ValuesAtAccumulator();
347 UpdateAccumulator(Circuit::NullGate());
348 } else if (bytecodeInfo.vregOut.size() != 0) {
349 auto out = bytecodeInfo.vregOut[0];
350 gate = ValuesAt(out);
351 UpdateVirtualRegister(out, Circuit::NullGate());
352 }
353 // variable use
354 // when alive gate is null, find def
355 if (bytecodeInfo.AccIn()) {
356 if (gate == Circuit::NullGate()) {
357 gate = builder_->ResolveDef(bbId, index, 0, true);
358 }
359 UpdateAccumulator(gate);
360 } else if (bytecodeInfo.inputs.size() != 0) {
361 auto vreg = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
362 if (gate == Circuit::NullGate()) {
363 gate = builder_->ResolveDef(bbId, index, vreg, false);
364 }
365 UpdateVirtualRegister(vreg, gate);
366 }
367 return;
368 }
369 if (!bytecodeInfo.IsGeneral() && !bytecodeInfo.IsReturn() && !bytecodeInfo.IsCondJump()) {
370 return;
371 }
372 GateRef gate = builder_->GetGateByBcIndex(index);
373 // variable kill
374 if (bytecodeInfo.AccOut()) {
375 UpdateAccumulator(Circuit::NullGate());
376 }
377 for (const auto &out: bytecodeInfo.vregOut) {
378 UpdateVirtualRegister(out, Circuit::NullGate());
379 }
380 if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
381 UpdateVirtualRegistersOfResume(gate);
382 }
383
384 // variable use
385 if (bytecodeInfo.AccIn()) {
386 auto id = bytecodeInfo.inputs.size();
387 GateRef def = gateAcc_.GetValueIn(gate, id);
388 UpdateAccumulator(def);
389 }
390 for (size_t i = 0; i < bytecodeInfo.inputs.size(); i++) {
391 auto in = bytecodeInfo.inputs[i];
392 if (std::holds_alternative<VirtualRegister>(in)) {
393 auto vreg = std::get<VirtualRegister>(in).GetId();
394 GateRef def = gateAcc_.GetValueIn(gate, i);
395 UpdateVirtualRegister(vreg, def);
396 }
397 }
398 if (IsAsyncResolveOrSusp(bytecodeInfo)) {
399 UpdateVirtualRegistersOfSuspend(gate);
400 }
401 }
402
IsAsyncResolveOrSusp(const BytecodeInfo & bytecodeInfo)403 bool FrameStateBuilder::IsAsyncResolveOrSusp(const BytecodeInfo &bytecodeInfo)
404 {
405 EcmaOpcode opcode = bytecodeInfo.GetOpcode();
406 return opcode == EcmaOpcode::SUSPENDGENERATOR_V8 || opcode == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8;
407 }
408
BuildStateSplitAfter(size_t index,BytecodeRegion & bb)409 void FrameStateBuilder::BuildStateSplitAfter(size_t index, BytecodeRegion& bb)
410 {
411 auto gate = builder_->GetGateByBcIndex(index);
412 ASSERT(gateAcc_.GetOpCode(gate) == OpCode::JS_BYTECODE);
413 auto nextIndex = GetNearestNextIndex(index, bb);
414 if (builder_->GetBytecodeInfo(nextIndex).IsCall()) {
415 return;
416 }
417 auto pcOffset = builder_->GetPcOffset(nextIndex);
418 auto stateInfo = GetFrameInfoAfter(nextIndex - 1); // 1: after prev bc
419 GateRef frameValues = BuildFrameValues(stateInfo);
420 GateRef frameStateAfter = BuildFrameStateGate(
421 pcOffset, frameValues, FrameStateOutput::Invalid());
422 BindStateSplit(gate, gate, frameStateAfter);
423 }
424
GetNearestNextIndex(size_t index,BytecodeRegion & bb) const425 size_t FrameStateBuilder::GetNearestNextIndex(size_t index, BytecodeRegion& bb) const
426 {
427 index++;
428 auto gate = builder_->GetGateByBcIndex(index);
429 while ((gate == Circuit::NullGate() || gateAcc_.IsConstant(gate)) && index < bb.end) {
430 index++;
431 gate = builder_->GetGateByBcIndex(index);
432 }
433 return index;
434 }
435
BuildStateSplitBefore(BytecodeRegion & bb,size_t index)436 void FrameStateBuilder::BuildStateSplitBefore(BytecodeRegion& bb, size_t index)
437 {
438 auto pcOffset = builder_->GetPcOffset(index);
439 auto stateInfo = GetFrameInfoBefore(bb, index);
440 GateRef frameValues = BuildFrameValues(stateInfo);
441 GateRef frameStateBefore = BuildFrameStateGate(
442 pcOffset, frameValues, FrameStateOutput::Invalid());
443 if (index == bb.start) {
444 BindStateSplit(bb.stateCurrent, bb.dependCurrent, frameStateBefore);
445 } else {
446 auto gate = builder_->GetGateByBcIndex(index);
447 BindStateSplit(gate, frameStateBefore);
448 }
449 }
450
ShouldInsertFrameStateBefore(BytecodeRegion & bb,size_t index)451 bool FrameStateBuilder::ShouldInsertFrameStateBefore(BytecodeRegion& bb, size_t index)
452 {
453 auto gate = builder_->GetGateByBcIndex(index);
454 if (index == bb.start) {
455 if (bb.numOfStatePreds > 1) { // 1: > 1 is merge
456 return true;
457 } else if (bb.numOfStatePreds == 1) { // 1: == 1 maybe loopexit
458 auto predBb = (bb.preds.size() > 0) ? bb.preds.at(0) : bb.trys.at(0);
459 if (LoopExitCount(predBb, &bb) > 0) {
460 return true;
461 }
462 }
463 if (gateAcc_.GetOpCode(bb.dependCurrent) == OpCode::GET_EXCEPTION) {
464 return true;
465 }
466 } else {
467 if (gate == Circuit::NullGate() || gateAcc_.GetStateCount(gate) != 1) {
468 return false;
469 }
470 auto state = gateAcc_.GetState(gate);
471 if (gateAcc_.GetOpCode(state) == OpCode::IF_SUCCESS) {
472 return true;
473 }
474 }
475 return false;
476 }
477
BuildFrameState(BytecodeRegion & bb,const BytecodeInfo & bytecodeInfo,size_t index)478 void FrameStateBuilder::BuildFrameState(BytecodeRegion& bb,
479 const BytecodeInfo &bytecodeInfo, size_t index)
480 {
481 // Not bind state split for Call
482 if (bytecodeInfo.IsCall()) {
483 BuildCallFrameState(index, bb);
484 }
485
486 bool needStateSplitBefore = ShouldInsertFrameStateBefore(bb, index);
487 auto gate = builder_->GetGateByBcIndex(index);
488 if (needStateSplitBefore && index != bb.start) {
489 auto depend = gateAcc_.GetDep(gate);
490 if (gateAcc_.GetOpCode(depend) == OpCode::STATE_SPLIT) {
491 needStateSplitBefore = false;
492 }
493 }
494 if (needStateSplitBefore) {
495 BuildStateSplitBefore(bb, index);
496 }
497
498 if (!bytecodeInfo.NoSideEffects() && !bytecodeInfo.IsThrow()) {
499 if (!gateAcc_.HasIfExceptionUse(gate)) {
500 BuildStateSplitAfter(index, bb);
501 }
502 }
503 }
504
BuildCallFrameState(size_t index,BytecodeRegion & bb)505 void FrameStateBuilder::BuildCallFrameState(size_t index, BytecodeRegion& bb)
506 {
507 auto pcOffset = builder_->GetPcOffset(index);
508 auto stateInfo = GetFrameInfoBefore(bb, index);
509 GateRef frameValues = BuildFrameValues(stateInfo);
510 GateRef frameState = BuildFrameStateGate(pcOffset, frameValues, FrameStateOutput::Invalid());
511 auto gate = builder_->GetGateByBcIndex(index);
512 gateAcc_.ReplaceFrameStateIn(gate, frameState);
513 }
514
BindBBStateSplit()515 void FrameStateBuilder::BindBBStateSplit()
516 {
517 auto& dfsList = builder_->GetDfsList();
518 for (auto &bbId: dfsList) {
519 auto &bb = builder_->GetBasicBlockById(bbId);
520 if (builder_->IsFirstBasicBlock(bb.id)) {
521 BuildStateSplitBefore(bb, bb.start);
522 }
523 if (builder_->IsEntryBlock(bb.id)) {
524 BuildStateSplitBefore(bb, bb.start);
525 }
526 ASSERT(!bb.isDead);
527 builder_->EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
528 auto &iterator = bb.GetBytecodeIterator();
529 auto index = iterator.Index();
530 BuildFrameState(bb, bytecodeInfo, index);
531 return true;
532 });
533 }
534 }
535
GetFrameInfoBefore(BytecodeRegion & bb,uint32_t bcId)536 FrameStateInfo *FrameStateBuilder::GetFrameInfoBefore(BytecodeRegion &bb, uint32_t bcId)
537 {
538 if (bcId == bb.start) {
539 return GetBBBeginStateInfo(bb.id);
540 } else {
541 return GetOrOCreateBCEndStateInfo(bcId - 1); // 1: prev pc
542 }
543 }
544
GetFrameInfoAfter(uint32_t bcId)545 FrameStateInfo *FrameStateBuilder::GetFrameInfoAfter(uint32_t bcId)
546 {
547 return GetOrOCreateBCEndStateInfo(bcId);
548 }
549
SaveBBBeginStateInfo(size_t bbId)550 void FrameStateBuilder::SaveBBBeginStateInfo(size_t bbId)
551 {
552 if (bbBeginStateInfos_[bbId] == nullptr) {
553 bbBeginStateInfos_[bbId] = CreateEmptyStateInfo();
554 }
555 bbBeginStateInfos_[bbId]->CopyFrom(liveOutResult_);
556 }
557
UpdateVirtualRegistersOfSuspend(GateRef gate)558 void FrameStateBuilder::UpdateVirtualRegistersOfSuspend(GateRef gate)
559 {
560 auto saveRegsGate = gateAcc_.GetDep(gate);
561 size_t numOfRegs = gateAcc_.GetNumValueIn(saveRegsGate);
562 for (size_t i = 0; i < numOfRegs; i++) {
563 GateRef def = gateAcc_.GetValueIn(saveRegsGate, i);
564 UpdateVirtualRegister(i, def);
565 }
566 }
567
UpdateVirtualRegistersOfResume(GateRef gate)568 void FrameStateBuilder::UpdateVirtualRegistersOfResume(GateRef gate)
569 {
570 auto uses = gateAcc_.Uses(gate);
571 for (auto it = uses.begin(); it != uses.end(); it++) {
572 if (gateAcc_.IsValueIn(it) && gateAcc_.GetOpCode(*it) == OpCode::RESTORE_REGISTER) {
573 auto vreg = static_cast<size_t>(gateAcc_.GetVirtualRegisterIndex(*it));
574 UpdateVirtualRegister(vreg, Circuit::NullGate());
575 }
576 }
577 }
578
LoopExitCount(BytecodeRegion * bb,BytecodeRegion * bbNext)579 size_t FrameStateBuilder::LoopExitCount(BytecodeRegion* bb, BytecodeRegion* bbNext)
580 {
581 size_t headDep = ((bbNext->numOfLoopBacks > 0) && (bbNext->loopbackBlocks.count(bb->id) == 0)) ? 1 : 0;
582 if (bbNext->loopDepth < headDep) {
583 // loop optimization disabled.
584 return 0;
585 }
586 size_t nextDep = bbNext->loopDepth - headDep;
587 ASSERT(bb->loopDepth >= nextDep);
588 return bb->loopDepth > nextDep;
589 }
590
TryGetLoopExitValue(GateRef value,size_t diff)591 GateRef FrameStateBuilder::TryGetLoopExitValue(GateRef value, size_t diff)
592 {
593 if ((gateAcc_.GetOpCode(value) != OpCode::LOOP_EXIT_VALUE) || (diff == 0)) {
594 return value;
595 }
596 for (size_t i = 0; i < diff; ++i) {
597 ASSERT(gateAcc_.GetOpCode(value) == OpCode::LOOP_EXIT_VALUE);
598 value = gateAcc_.GetValueIn(value);
599 }
600 return value;
601 }
602 }
603