arkcompiler_ets_runtime/ecmascript/compiler/frame_states.cpp
openharmony_ci 9f9503bd6b
!8038 修复携程aot编译cppcrash问题
Merge pull request !8038 from zhao1d/zld
2024-07-07 07:44:29 +00:00

1333 lines
47 KiB
C++

/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/frame_states.h"
#include <cstddef>
#include "ecmascript/compiler/bytecode_circuit_builder.h"
namespace panda::ecmascript::kungfu {
FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
Circuit *circuit, const MethodLiteral *literal)
: bcBuilder_(builder),
pgoTypeRecorder_(builder->GetPGOTypeRecorder()),
numVregs_(literal->GetNumberVRegs() + FIXED_ARGS),
accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc
envIndex_(literal->GetNumberVRegs()),
circuit_(circuit),
acc_(circuit),
bcEndStateLiveouts_(circuit->chunk()),
bbBeginStateLiveouts_(circuit->chunk()),
bbFrameContext_(circuit->chunk()),
loops_(circuit->chunk()),
rpoList_(circuit->chunk()),
postOrderList_(circuit->chunk())
{
}
FrameStateBuilder::~FrameStateBuilder()
{
liveOutResult_ = nullptr;
bcEndStateLiveouts_.clear();
bbBeginStateLiveouts_.clear();
bbFrameContext_.clear();
bcBuilder_ = nullptr;
}
void FrameStateBuilder::BuildPostOrderList(size_t size)
{
postOrderList_.clear();
std::deque<size_t> pendingList;
std::vector<bool> visited(size, false);
// entry block (bbid=0) is a empty block, need skip
auto firstBlockId = 1;
pendingList.emplace_back(firstBlockId);
while (!pendingList.empty()) {
size_t curBlockId = pendingList.back();
visited[curBlockId] = true;
bool change = false;
auto &bb = bcBuilder_->GetBasicBlockById(curBlockId);
for (const auto &succBlock: bb.succs) {
if (!visited[succBlock->id]) {
pendingList.emplace_back(succBlock->id);
change = true;
break;
}
}
if (change) {
continue;
}
for (const auto &succBlock: bb.catches) {
if (!visited[succBlock->id]) {
pendingList.emplace_back(succBlock->id);
change = true;
break;
}
}
if (!change) {
postOrderList_.emplace_back(curBlockId);
pendingList.pop_back();
}
}
}
bool FrameStateBuilder::MergeIntoPredBC(uint32_t predPc)
{
// liveout next
auto liveout = GetOrOCreateBCEndLiveOut(predPc);
FrameLiveOut *predliveOut = liveOutResult_;
return liveout->MergeLiveout(predliveOut);
}
bool FrameStateBuilder::MergeFromSuccBB(size_t bbId)
{
// liveout next
auto liveout = GetOrOCreateBBLiveOut(bbId);
return liveOutResult_->MergeLiveout(liveout);
}
void FrameStateBuilder::MergeFromCatchBB(size_t bbId)
{
// liveout next
bool accumulatorIsLive = liveOutResult_->TestBit(accumulatorIndex_);
auto liveout = GetOrOCreateBBLiveOut(bbId);
liveOutResult_->MergeLiveout(liveout);
// accumulatorIndex_ is exeception object
if (!accumulatorIsLive) {
liveOutResult_->ClearBit(accumulatorIndex_);
}
}
bool FrameStateBuilder::ComputeLiveOut(size_t bbId)
{
auto &bb = bcBuilder_->GetBasicBlockById(bbId);
bool changed = false;
// iterator bc
auto &iterator = bb.GetBytecodeIterator();
iterator.GotoEnd();
ASSERT(bb.end == iterator.Index());
auto bbLiveout = GetOrOCreateBBLiveOut(bb.id);
auto liveout = GetOrOCreateBCEndLiveOut(bb.end);
liveOutResult_->CopyFrom(liveout);
// init frameContext
currentBBliveOut_ = bbLiveout;
while (true) {
auto &bytecodeInfo = iterator.GetBytecodeInfo();
if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
ASSERT(bb.catches.size() == 1); // 1: one catch
MergeFromCatchBB(bb.catches.at(0)->id);
}
ComputeLiveOutBC(bytecodeInfo);
--iterator;
if (iterator.Done()) {
break;
}
auto prevPc = iterator.Index();
changed |= MergeIntoPredBC(prevPc);
}
if (!bb.trys.empty()) {
// clear GET_EXCEPTION gate if this is a catch block
liveOutResult_->ClearBit(accumulatorIndex_);
}
bbLiveout->CopyFrom(liveOutResult_);
// merge current into pred bb
for (auto bbPred : bb.preds) {
changed |= MergeIntoPredBC(bbPred->end);
}
return changed;
}
void FrameStateBuilder::ComputeLiveState()
{
// recompute liveout
bool changed = true;
while (changed) {
changed = false;
for (size_t i = 0; i < postOrderList_.size(); i++) {
changed |= ComputeLiveOut(postOrderList_[i]);
}
}
}
void FrameStateBuilder::DoBytecodeAnalysis()
{
auto bcSize = bcBuilder_->GetLastBcIndex() + 1; // 1: +1 pcOffsets size
auto bbSize = bcBuilder_->GetBasicBlockCount();
bcEndStateLiveouts_.resize(bcSize, nullptr);
bbBeginStateLiveouts_.resize(bbSize, nullptr);
auto chunk = circuit_->chunk();
liveOutResult_ = chunk->New<FrameLiveOut>(chunk, numVregs_);
bbFrameContext_.resize(bbSize, nullptr);
BuildPostOrderList(bbSize);
ComputeLiveState();
if (bcBuilder_->IsLogEnabled()) {
DumpLiveState();
}
ComputeLoopInfo();
}
void FrameStateBuilder::ComputeLiveOutBC(const BytecodeInfo &bytecodeInfo)
{
if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
currentBBliveOut_->defRegisters_.Union(liveOutResult_->liveout_);
}
// variable kill
if (bytecodeInfo.AccOut()) {
liveOutResult_->ClearBit(accumulatorIndex_);
currentBBliveOut_->defRegisters_.SetBit(accumulatorIndex_);
}
for (const auto &out: bytecodeInfo.vregOut) {
liveOutResult_->ClearBit(out);
currentBBliveOut_->defRegisters_.SetBit(out);
}
// variable use
if (bytecodeInfo.AccIn()) {
liveOutResult_->SetBit(accumulatorIndex_);
}
for (size_t i = 0; i < bytecodeInfo.inputs.size(); i++) {
auto in = bytecodeInfo.inputs[i];
if (std::holds_alternative<VirtualRegister>(in)) {
auto vreg = std::get<VirtualRegister>(in).GetId();
liveOutResult_->SetBit(vreg);
}
}
}
FrameLiveOut *FrameStateBuilder::GetOrOCreateBCEndLiveOut(uint32_t bcIndex)
{
auto liveout = bcEndStateLiveouts_[bcIndex];
if (liveout == nullptr) {
auto chunk = circuit_->chunk();
liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
bcEndStateLiveouts_[bcIndex] = liveout;
}
return liveout;
}
FrameLiveOut *FrameStateBuilder::GetOrOCreateBBLiveOut(size_t bbIndex)
{
// As BB0 is empty, its bbBeginStateLiveouts is the same as BB1.
if (bbIndex == 0) {
if (bcBuilder_->IsOSR()) {
bbIndex = GetOsrLoopHeadBBId();
} else {
bbIndex = 1;
}
}
auto liveout = bbBeginStateLiveouts_[bbIndex];
if (liveout == nullptr) {
auto chunk = circuit_->chunk();
liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
bbBeginStateLiveouts_[bbIndex] = liveout;
}
return liveout;
}
FrameContext *FrameStateBuilder::GetOrOCreateMergedContext(uint32_t bbIndex)
{
auto context = bbFrameContext_[bbIndex];
if (context == nullptr) {
auto chunk = circuit_->chunk();
context = chunk->New<FrameContext>(chunk, numVregs_);
for (size_t i = 0; i < numVregs_; i++) {
context->SetValuesAt(i, Circuit::NullGate());
}
bbFrameContext_[bbIndex] = context;
}
return context;
}
void FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, GateRef gate)
{
auto pgoType = pgoTypeRecorder_->GetPGOType(acc_.TryGetPcOffset(gate));
acc_.TrySetPGOType(gate, pgoType);
auto valueCount = acc_.GetInValueCount(gate);
[[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
[[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
// RETURNUNDEFINED has value input, but not from acc
ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
auto valueStarts = acc_.GetInValueStarts(gate);
for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
auto inIdx = valueIdx + valueStarts;
if (!acc_.IsInGateNull(gate, inIdx)) {
continue;
}
if (valueIdx < bytecodeInfo.inputs.size()) {
auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
GateRef defVreg = liveContext_->ValuesAt(vregId);
acc_.NewIn(gate, inIdx, defVreg);
} else {
GateRef defAcc = liveContext_->ValuesAt(accumulatorIndex_);
acc_.NewIn(gate, inIdx, defAcc);
}
}
}
void FrameStateBuilder::AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
{
if (bytecodeInfo.IsGeneral()) {
BindStateSplitBefore(bytecodeInfo, liveout, bcId);
if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8 ||
bytecodeInfo.GetOpcode() == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8) {
auto hole = circuit_->GetConstantGate(MachineType::I64,
JSTaggedValue::VALUE_HOLE,
GateType::TaggedValue());
uint32_t numRegs = accumulatorIndex_;
std::vector<GateRef> vec(numRegs + 1, hole);
vec[0] = liveContext_->currentDepend_;
// accumulator is res
for (size_t i = 0; i < numRegs; i++) {
if (liveout->TestBit(i)) {
vec[i + 1] = liveContext_->ValuesAt(i); // 1: skip dep
} else {
vec[i + 1] = hole; // 1: skip dep
}
}
auto res = circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
liveContext_->currentDepend_ = res;
}
}
}
void FrameStateBuilder::UpdateStateDepend(GateRef state, GateRef depend)
{
liveContext_->currentState_ = state;
liveContext_->currentDepend_ = depend;
}
void FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo)
{
GateRef gate = Circuit::NullGate();
if (bytecodeInfo.AccIn()) {
gate = liveContext_->ValuesAt(accumulatorIndex_);
} else if (bytecodeInfo.inputs.size() != 0) {
auto vreg = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
gate = liveContext_->ValuesAt(vreg);
}
// variable kill
if (bytecodeInfo.AccOut()) {
liveContext_->SetValuesAt(accumulatorIndex_, gate);
} else if (bytecodeInfo.vregOut.size() != 0) {
auto vreg = bytecodeInfo.vregOut[0];
liveContext_->SetValuesAt(vreg, gate);
}
}
void FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo,
uint32_t bcId, GateRef gate)
{
ASSERT(!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov());
if (bytecodeInfo.IsSetConstant()) {
liveContext_->SetValuesAt(accumulatorIndex_, gate);
return;
}
// jump gate is null
if (gate != Circuit::NullGate()) {
FillBcInputs(bytecodeInfo, gate);
}
auto liveout = GetFrameLiveoutAfter(bcId);
// variable kill
if (bytecodeInfo.AccOut()) {
liveContext_->SetValuesAt(accumulatorIndex_, gate);
}
for (const auto &out: bytecodeInfo.vregOut) {
liveContext_->SetValuesAt(out, gate);
}
if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
// accumulator is generator object
for (size_t i = 0; i < accumulatorIndex_; i++) {
if (liveout->TestBit(i)) {
auto restore = circuit_->NewGate(circuit_->RestoreRegister(i),
MachineType::I64, { gate }, GateType::AnyType());
liveContext_->SetValuesAt(i, restore);
}
}
}
BindStateSplitAfter(bytecodeInfo, bcId, gate);
}
void FrameStateBuilder::SetOsrLoopHeadBB(const BytecodeRegion &osrLoopBodyBB)
{
auto *loopInfo = GetLoopInfoByLoopBody(osrLoopBodyBB);
if (loopInfo == nullptr) {
loopHeadOfOSR_ = nullptr;
} else {
loopHeadOfOSR_ = &(bcBuilder_->GetBasicBlockById(loopInfo->loopHeadId));
}
return;
}
bool FrameStateBuilder::IsOsrLoopExit(const BytecodeRegion &curBB)
{
if (loopHeadOfOSR_ == nullptr) {
return false;
}
auto *loopInfo = GetLoopInfoByLoopBody(*loopHeadOfOSR_);
if (!loopInfo || !loopInfo->loopExits) {
return false;
}
for (auto *exit : *loopInfo->loopExits) {
if (exit == &curBB) {
return true;
}
}
return false;
}
bool FrameStateBuilder::OutOfOsrLoop(const BytecodeRegion &curBB)
{
if (loopHeadOfOSR_ == nullptr) {
return false;
}
const LoopInfo &loopInfoOfOSR = GetLoopInfo(*loopHeadOfOSR_);
const LoopInfo *curLoop = GetLoopInfoByLoopBody(curBB);
while (curLoop != nullptr) {
if (curLoop == &loopInfoOfOSR) {
return false;
}
curLoop = curLoop->parentInfo;
}
return true;
}
size_t FrameStateBuilder::GetOsrLoopHeadBBId() const
{
if (loopHeadOfOSR_ == nullptr) {
return -1;
}
return loopHeadOfOSR_->id;
}
void FrameStateBuilder::InitEntryBB(const BytecodeRegion &bb)
{
auto frameContext = GetOrOCreateMergedContext(bb.id);
frameContext->currentState_ = circuit_->GetStateRoot();
frameContext->currentDepend_ = circuit_->GetDependRoot();
frameContext->needStateSplit_ = true;
// initialize argumnets
ASSERT(bcBuilder_->IsFirstBasicBlock(1)); // 1: is firstBlock
auto liveout = GetFrameLiveoutBefore(1); // 1: is firstBlock
GateRef frameArgs = bcBuilder_->GetFrameArgs();
if (liveout->TestBit(envIndex_)) {
GateRef jsFunc = acc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::FUNC));
auto env = acc_.GetInitialEnvGate(frameContext->currentDepend_, jsFunc);
frameContext->SetValuesAt(envIndex_, env);
frameContext->currentDepend_ = env;
}
auto holeGate = circuit_->GetConstantGate(MachineType::I64,
JSTaggedValue::VALUE_HOLE,
GateType::TaggedValue());
for (size_t i = 0; i < envIndex_; i++) {
if (liveout->TestBit(i)) {
if (bcBuilder_->ArgGateNotExisted(i)) {
frameContext->SetValuesAt(i, holeGate);
} else {
GateRef arg = bcBuilder_->GetArgGate(i);
frameContext->SetValuesAt(i, arg);
}
}
}
// init live interpreter registers
if (!bcBuilder_->IsOSR()) {
return;
}
auto *liveOut = GetFrameLiveoutBefore(GetOsrLoopHeadBBId());
for (size_t i = 0; i < envIndex_; i++) {
if (!liveOut->TestBit(i)) {
continue;
}
GateRef init = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(i), MachineType::I64,
{circuit_->GetArgRoot()}, GateType::TaggedValue());
frameContext->SetValuesAt(i, init);
}
if (liveOut->TestBit(envIndex_)) {
// -7: env
GateRef env = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ENV), MachineType::I64,
{circuit_->GetArgRoot()}, GateType::TaggedValue());
frameContext->SetValuesAt(envIndex_, env);
}
}
void FrameStateBuilder::NewMerge(const BytecodeRegion &bbNext)
{
auto frameContext = GetMergedBbContext(bbNext.id);
size_t numOfIns = bbNext.numOfStatePreds;
if (IsOsrLoopExit(bbNext)) {
// Only the precursor within the OSR loop is required.
numOfIns = 0;
for (const BytecodeRegion *bb : bbNext.preds) {
if (OutOfOsrLoop(*bb)) {
continue;
}
numOfIns++;
}
}
bool isLoopHead = !(bcBuilder_->IsOSR() && OutOfOsrLoop(bbNext)) && bbNext.loopNumber > 0;
const GateMetaData *metaData = isLoopHead ? circuit_->LoopBegin(numOfIns) : circuit_->Merge(numOfIns);
auto merge = circuit_->NewGate(metaData, std::vector<GateRef>(numOfIns, Circuit::NullGate()));
auto dependMerge =
circuit_->NewGate(circuit_->DependSelector(numOfIns), std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
acc_.NewIn(dependMerge, 0, merge); // 0: is state
// reset current state and depend
frameContext->currentState_ = merge;
frameContext->currentDepend_ = dependMerge;
if (isLoopHead) {
ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
auto& loopInfo = GetLoopInfo(bbNext);
headerGates[loopInfo.sortIndx] = merge;
ASSERT(numOfIns = loopInfo.numLoopBacks + 1); // 1: one entry
}
}
void FrameStateBuilder::MergeStateDepend(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
{
GateRef entryState = liveContext_->currentState_;
GateRef entryDepend = liveContext_->currentDepend_;
auto mergedContext = GetMergedBbContext(bbNext.id);
if (bbNext.numOfStatePreds == 1) { // 1: one entry edge
mergedContext->currentState_ = liveContext_->currentState_;
mergedContext->currentDepend_ = liveContext_->currentDepend_;
return;
}
auto index = mergedContext->currentIndex_;
// lazy first edge
if (index == 0) {
NewMerge(bbNext);
}
if (IsLoopBackEdge(bb, bbNext)) {
if (!(bcBuilder_->IsOSR() && IsOsrLoopExit(bbNext))) {
ASSERT(index != 0);
}
entryState = circuit_->NewGate(circuit_->LoopBack(), { entryState });
}
acc_.NewIn(mergedContext->currentState_, index, entryState);
acc_.NewIn(mergedContext->currentDepend_, index + 1, entryDepend); // 1: skip state
mergedContext->needStateSplit_ = true;
}
size_t FrameStateBuilder::GetNumOfStatePreds(const BytecodeRegion &bb)
{
size_t numOfIns = bb.numOfStatePreds;
if (bcBuilder_->IsOSR() && IsOsrLoopExit(bb)) {
numOfIns = 0;
for (const BytecodeRegion *b : bb.preds) {
if (OutOfOsrLoop(*b)) {
continue;
}
numOfIns++;
}
}
return numOfIns;
}
GateRef FrameStateBuilder::MergeValue(const BytecodeRegion &bb,
GateRef stateMerge, GateRef currentValue, GateRef nextValue, size_t index)
{
ASSERT(stateMerge != Circuit::NullGate());
ASSERT(currentValue != Circuit::NullGate());
if (nextValue != Circuit::NullGate() &&
(acc_.GetOpCode(nextValue) == OpCode::VALUE_SELECTOR && acc_.GetState(nextValue) == stateMerge)) {
ASSERT(currentValue != Circuit::NullGate());
acc_.NewIn(nextValue, index + 1, currentValue);
currentValue = nextValue;
} else if (currentValue != nextValue) {
size_t numOfIns = GetNumOfStatePreds(bb);
auto inList = std::vector<GateRef>(1 + numOfIns, Circuit::NullGate()); // 1: state
auto phi = circuit_->NewGate(circuit_->ValueSelector(numOfIns), MachineType::I64, inList.size(), inList.data(),
GateType::AnyType());
acc_.NewIn(phi, 0, stateMerge);
if (nextValue != Circuit::NullGate()) {
for (size_t i = 0; i < index; i++) {
acc_.NewIn(phi, i + 1, nextValue); // 1: skip state
}
acc_.NewIn(phi, index + 1, currentValue); // 1: skip state
} else {
ASSERT(index == 0);
acc_.NewIn(phi, 1, currentValue); // 1: skip state
}
currentValue = phi;
}
return currentValue;
}
void FrameStateBuilder::MergeAssignment(const BytecodeRegion &bbNext)
{
auto mergedContext = GetMergedBbContext(bbNext.id);
auto stateMerge = mergedContext->currentState_;
ASSERT(acc_.IsCFGMerge(stateMerge));
auto liveout = GetFrameLiveoutBefore(bbNext.id);
auto *loopAssignment = GetLoopAssignment(bbNext);
for (size_t i = 0; i < numVregs_; i++) {
if (liveout->TestBit(i)) {
auto current = liveContext_->ValuesAt(i);
auto next = mergedContext->ValuesAt(i);
GateRef value = Circuit::NullGate();
#ifndef NDEBUG
if (loopAssignment == nullptr) {
ASSERT(current != Circuit::NullGate() && next != Circuit::NullGate());
} else if (loopAssignment->TestBit(i)) {
// next is null or phi
ASSERT(next == Circuit::NullGate() ||
((acc_.GetOpCode(next) == OpCode::VALUE_SELECTOR) && acc_.GetState(next) == stateMerge));
} else {
ASSERT(next == Circuit::NullGate() || current == next);
}
#endif
if (loopAssignment != nullptr && !loopAssignment->TestBit(i)) {
value = current;
} else {
value = MergeValue(bbNext, stateMerge, current, next, mergedContext->currentIndex_);
}
mergedContext->SetValuesAt(i, value);
}
}
}
void FrameStateBuilder::CopyLiveoutValues(const BytecodeRegion &bbNext,
FrameContext* dest, FrameContext* src)
{
auto liveout = GetFrameLiveoutBefore(bbNext.id);
for (size_t i = 0; i < numVregs_; i++) {
if (liveout->TestBit(i)) {
auto value = src->ValuesAt(i);
dest->SetValuesAt(i, value);
} else {
dest->SetValuesAt(i, Circuit::NullGate());
}
}
}
FrameContext *FrameStateBuilder::GetCachedContext()
{
// lazy init cachedContext
if (cachedContext_ == nullptr) {
auto chunk = circuit_->chunk();
cachedContext_ = chunk->New<FrameContext>(chunk, numVregs_);
}
auto result = cachedContext_;
if (cachedContext_ == liveContext_) {
if (cachedContextBackup_ == nullptr) {
auto chunk = circuit_->chunk();
cachedContextBackup_ = chunk->New<FrameContext>(chunk, numVregs_);
}
result = cachedContextBackup_;
}
return result;
}
void FrameStateBuilder::SaveCurrentContext(const BytecodeRegion &bb)
{
auto newContext = GetCachedContext();
ASSERT(newContext != liveContext_);
newContext->CopyCurrentStatus(liveContext_);
CopyLiveoutValues(bb, newContext, liveContext_);
liveContext_ = newContext;
}
void FrameStateBuilder::NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAssignment)
{
auto state = liveContext_->currentState_;
auto depend = liveContext_->currentDepend_;
auto loopExit = circuit_->NewGate(circuit_->LoopExit(), { state });
auto loopExitDepend = circuit_->NewGate(circuit_->LoopExitDepend(),
{ loopExit, depend });
auto liveout = GetFrameLiveoutBefore(bbNext.id);
for (size_t i = 0; i < numVregs_; i++) {
if (liveout->TestBit(i)) {
auto current = liveContext_->ValuesAt(i);
if (loopAssignment->TestBit(i)) {
current = circuit_->NewGate(circuit_->LoopExitValue(), acc_.GetMachineType(current),
{loopExit, current}, acc_.GetGateType(current));
}
liveContext_->SetValuesAt(i, current);
} else {
ASSERT(liveContext_->ValuesAt(i) == Circuit::NullGate());
}
}
liveContext_->currentState_ = loopExit;
liveContext_->currentDepend_ = loopExitDepend;
if (!bcBuilder_->IsTypeLoweringEnabled()) {
return;
}
auto stateSplit = BuildStateSplit(liveContext_, liveout, bbNext.start);
liveContext_->currentDepend_ = stateSplit;
}
void FrameStateBuilder::TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
{
if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) {
return;
}
if (bcBuilder_->IsOSR() && bcBuilder_->IsCacheBBOfOSRLoop(bbNext)) {
return;
}
auto currentLoop = GetLoopInfoByLoopBody(bb);
if (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
// use bbNext as merged values
SaveCurrentContext(bbNext);
}
while (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
ASSERT(currentLoop->loopExits != nullptr);
#ifndef NDEBUG
bool found = false;
for (auto current : *currentLoop->loopExits) {
if (current->id == bbNext.id) {
found = true;
break;
}
}
ASSERT(found);
#endif
NewLoopExit(bbNext, currentLoop->loopAssignment);
currentLoop = currentLoop->parentInfo;
}
}
void FrameStateBuilder::AdvanceToNextBB(const BytecodeRegion &bb, bool isOsrLoopExit)
{
liveContext_ = GetMergedBbContext(bb.id);
ASSERT(liveContext_ != nullptr);
if (bb.loopNumber > 0) {
// use bb as merged values
SaveCurrentContext(bb);
} else if (!isOsrLoopExit) {
// all input merged
ASSERT(liveContext_->currentIndex_ == bb.numOfStatePreds);
}
if (liveContext_->needStateSplit_) {
liveContext_->needStateSplit_ = false;
if (!bcBuilder_->IsTypeLoweringEnabled()) {
return;
}
auto liveout = GetOrOCreateBBLiveOut(bb.id);
auto stateSplit = BuildStateSplit(liveContext_, liveout, bb.start);
liveContext_->currentDepend_ = stateSplit;
}
}
class SubContextScope {
public:
explicit SubContextScope(FrameStateBuilder* frameBuilder)
: frameBuilder_(frameBuilder)
{
originContext_ = frameBuilder->liveContext_;
}
~SubContextScope()
{
frameBuilder_->liveContext_ = originContext_;
}
private:
FrameContext* originContext_ {nullptr};
FrameStateBuilder* frameBuilder_ {nullptr};
};
void FrameStateBuilder::MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
{
[[maybe_unused]] SubContextScope scope(this);
TryInsertLoopExit(bb, bbNext);
auto mergedContext = GetOrOCreateMergedContext(bbNext.id);
MergeStateDepend(bb, bbNext);
if (mergedContext->currentIndex_ == 0) {
if (bbNext.loopNumber > 0) {
MergeAssignment(bbNext);
} else {
CopyLiveoutValues(bbNext, mergedContext, liveContext_);
}
} else {
MergeAssignment(bbNext);
}
mergedContext->currentIndex_++;
}
bool FrameStateBuilder::IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
{
if (bcBuilder_->IsOSR() && OutOfOsrLoop(bbNext)) {
return false;
} else if (bbNext.loopNumber > 0) {
auto& loopInfo = GetLoopInfo(bbNext);
return loopInfo.loopBodys->TestBit(bb.id);
}
return false;
}
FrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(const BytecodeRegion &bb)
{
ASSERT(bb.loopNumber > 0);
return loops_[bb.loopNumber - 1]; // -1: for index
}
FrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(BytecodeRegion &bb)
{
ASSERT(bb.loopNumber > 0);
return loops_[bb.loopNumber - 1]; // -1: for index
}
FrameStateBuilder::LoopInfo* FrameStateBuilder::GetLoopInfoByLoopBody(const BytecodeRegion &bb)
{
if (bb.loopIndex == 0) {
return nullptr;
}
auto& loopInfo = loops_[bb.loopIndex - 1];
ASSERT(loopInfo.loopBodys->TestBit(bb.id));
return &loopInfo;
}
BitSet *FrameStateBuilder::GetLoopAssignment(const BytecodeRegion &bb)
{
if (bb.loopNumber > 0) {
auto& loopInfo = GetLoopInfo(bb);
return loopInfo.loopAssignment;
}
return nullptr;
}
void FrameStateBuilder::AddEmptyBlock(BytecodeRegion* bb)
{
bbBeginStateLiveouts_.emplace_back(nullptr);
bbFrameContext_.emplace_back(nullptr);
auto liveout = GetOrOCreateBBLiveOut(bb->id);
liveout->CopyFrom(liveOutResult_);
GetOrOCreateMergedContext(bb->id);
bcBuilder_->AddBasicBlock(bb);
}
class BlockLoopAnalysis {
public:
explicit BlockLoopAnalysis(FrameStateBuilder *builder, Chunk* chunk)
: frameBuilder_(builder), bcBuilder_(builder->bcBuilder_),
pendingList_(chunk), loopbacks_(chunk),
dfsStack_(chunk), visitState_(chunk), chunk_(chunk) {}
void Run()
{
ComputeLoopBack();
TryClearDeadBlock();
frameBuilder_->numLoops_ = numLoops_;
if (numLoops_ > 0) {
ComputeLoopInfo();
if (bcBuilder_->IsLogEnabled()) {
for (size_t i = 0; i < numLoops_; i++) {
auto& loopInfo = frameBuilder_->loops_[i];
PrintLoop(loopInfo);
}
}
}
}
void CountLoopBackEdge(size_t fromId, size_t toId)
{
loopbacks_.push_back({fromId, toId});
auto &toBlock = bcBuilder_->GetBasicBlockById(toId);
if (toBlock.loopNumber == 0) {
toBlock.loopNumber = ++numLoops_;
}
}
void ComputeLoopBack()
{
auto size = bcBuilder_->GetBasicBlockCount();
visitState_.resize(size, MarkState::UNVISITED);
size_t entryId = 0; // entry id
VisitedInfo info = {0, false};
visitedInfo_.resize(size, info);
pendingList_.emplace_back(entryId);
while (!pendingList_.empty()) {
size_t bbId = pendingList_.back();
auto &bb = bcBuilder_->GetBasicBlockById(bbId);
bool allVisited = true;
visitState_[bbId] = MarkState::PENDING;
BytecodeRegion* catchBlock = bb.catches.empty() ? nullptr : bb.catches.at(0);
for (size_t i = visitedInfo_[bbId].needVisitIndex; i < bb.succs.size(); i++) {
BytecodeRegion* succBlock = bb.succs[i];
size_t succId = succBlock->id;
if (visitState_[succId] == MarkState::UNVISITED) {
pendingList_.emplace_back(succId);
visitState_[succId] = MarkState::ON_STACK;
allVisited = false;
visitedInfo_[bbId].needVisitIndex = i + 1;
break;
} else if (visitState_[succId] == MarkState::PENDING) {
// back edge
CountLoopBackEdge(bbId, succId);
}
}
if (catchBlock != nullptr && !visitedInfo_[bbId].isVisitedCatchBlock) {
size_t catchId = catchBlock->id;
if (visitState_[catchId] == MarkState::UNVISITED) {
pendingList_.emplace_back(catchId);
visitState_[catchId] = MarkState::ON_STACK;
allVisited = false;
visitedInfo_[bbId].isVisitedCatchBlock = true;
} else if (visitState_[catchId] == MarkState::PENDING) {
// back edge
CountLoopBackEdge(bbId, catchId);
}
}
if (allVisited) {
visitState_[bbId] = MarkState::VISITED;
pendingList_.pop_back();
frameBuilder_->rpoList_.push_front(bbId);
}
}
}
void TryClearDeadBlock()
{
if (frameBuilder_->rpoList_.size() == bcBuilder_->NumberOfLiveBlock()) {
return;
}
auto size = bcBuilder_->GetBasicBlockCount();
for (size_t i = 0; i < size; i++) {
auto &bb = bcBuilder_->GetBasicBlockById(i);
if (bb.numOfStatePreds != 0 && visitState_[i] == MarkState::UNVISITED) {
bb.numOfStatePreds = 0;
}
}
bcBuilder_->RemoveUnreachableRegion();
}
void CountLoopBody(FrameStateBuilder::LoopInfo& loopInfo, size_t bbId)
{
if (bbId != loopInfo.loopHeadId && !loopInfo.loopBodys->TestBit(bbId)) {
loopInfo.loopBodys->SetBit(bbId);
pendingList_.emplace_back(bbId);
auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(bbId);
ASSERT(liveout != nullptr);
loopInfo.loopAssignment->Union(liveout->defRegisters_);
}
}
void PropagateLoopBody(FrameStateBuilder::LoopInfo& loopInfo)
{
while (!pendingList_.empty()) {
auto cur = pendingList_.back();
auto &curBlock = bcBuilder_->GetBasicBlockById(cur);
pendingList_.pop_back();
for (auto pred : curBlock.preds) {
CountLoopBody(loopInfo, pred->id);
}
for (auto pred : curBlock.trys) {
CountLoopBody(loopInfo, pred->id);
}
}
}
void InitLoopInfo(FrameStateBuilder::LoopInfo& loopInfo, BytecodeRegion& loopHeader, size_t backId)
{
if (loopInfo.loopHeadId == 0) {
auto size = bcBuilder_->GetBasicBlockCount();
loopInfo.loopHeadId = loopHeader.id;
loopInfo.loopIndex = loopHeader.loopNumber;
loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
loopInfo.loopAssignment = chunk_->New<BitSet>(chunk_, frameBuilder_->numVregs_);
loopHeader.loopIndex = loopInfo.loopIndex;
loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(loopInfo.loopHeadId);
loopInfo.loopAssignment->Union(liveout->defRegisters_);
loopInfo.numLoopBacks = 1;
loopInfo.loopBodys->SetBit(backId);
} else {
if (!loopInfo.loopBodys->TestBit(backId)) {
loopInfo.loopBodys->SetBit(backId);
}
loopInfo.numLoopBacks++;
}
}
void ComputeLoopInfo()
{
frameBuilder_->loops_.resize(numLoops_, FrameStateBuilder::LoopInfo());
for (auto& info : loopbacks_) {
auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
InitLoopInfo(loopInfo, toBlock, info.fromId);
}
TryMergeLoopEntry();
ResizeLoopBody(); // tryMerge will insert region, need resize loop body.
for (auto& info : loopbacks_) {
auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
CountLoopBody(loopInfo, info.fromId);
PropagateLoopBody(loopInfo);
}
if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) {
return;
}
auto size = bcBuilder_->GetBasicBlockCount();
dfsStack_.resize(size, DFSState(0, 0));
ComputeLoopTree();
}
void InsertEmptyBytecodeRegion(FrameStateBuilder::LoopInfo& loopInfo,
BytecodeRegion& loopHeader, size_t numOfEntries)
{
auto size = bcBuilder_->GetBasicBlockCount();
auto block = chunk_->New<BytecodeRegion>(chunk_);
block->id = size;
block->numOfStatePreds = numOfEntries;
block->start = loopHeader.start;
ASSERT(loopHeader.start != 0);
block->end = BytecodeIterator::INVALID_INDEX;
block->bytecodeIterator_.Reset(bcBuilder_, block->start, block->end);
frameBuilder_->liveOutResult_->Reset();
for (auto it = loopHeader.preds.begin(); it != loopHeader.preds.end();) {
auto bbPred = *it;
// not loop back
if (!loopInfo.loopBodys->TestBit(bbPred->id)) {
it = loopHeader.preds.erase(it);
std::replace(bbPred->succs.begin(), bbPred->succs.end(), &loopHeader, block);
block->preds.emplace_back(bbPred);
} else {
it++;
}
}
frameBuilder_->MergeFromSuccBB(loopHeader.id);
block->succs.emplace_back(&loopHeader);
loopHeader.preds.insert(loopHeader.preds.begin(), block);
frameBuilder_->AddEmptyBlock(block);
ASSERT(loopHeader.trys.empty() && numOfEntries > 0);
loopHeader.numOfStatePreds -= (numOfEntries - 1); // 1: one entry
auto it = std::find(frameBuilder_->rpoList_.begin(), frameBuilder_->rpoList_.end(), loopHeader.id);
ASSERT(it != frameBuilder_->rpoList_.end());
frameBuilder_->rpoList_.insert(it, block->id);
visitState_.emplace_back(MarkState::UNVISITED1);
}
void TryMergeLoopEntry()
{
for (size_t i = 0; i < numLoops_; i++) {
auto& loopInfo = frameBuilder_->loops_[i];
auto& loopHeader = bcBuilder_->GetBasicBlockById(loopInfo.loopHeadId);
ASSERT(loopHeader.numOfStatePreds > loopInfo.numLoopBacks);
size_t numOfEntries = static_cast<size_t>(loopHeader.numOfStatePreds - loopInfo.numLoopBacks);
if (numOfEntries > 1 && loopHeader.trys.size() == 0) {
InsertEmptyBytecodeRegion(loopInfo, loopHeader, numOfEntries);
}
// clear loopback bits for visit body
loopInfo.loopBodys->Reset();
loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
}
}
void ResizeLoopBody()
{
for (auto& info : loopbacks_) {
auto size = bcBuilder_->GetBasicBlockCount();
auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
if (loopInfo.loopBodys->ShouldExpand(size)) {
auto tmp = loopInfo.loopBodys;
loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
loopInfo.loopBodys->CopyDataFrom(*tmp);
}
}
}
FrameStateBuilder::LoopInfo* EnterInnerLoop(FrameStateBuilder::LoopInfo* loopInfo, size_t bbId)
{
auto &bb = bcBuilder_->GetBasicBlockById(bbId);
if (bb.loopNumber > 0) {
auto &innerInfo = frameBuilder_->GetLoopInfo(bb);
ASSERT(innerInfo.parentInfo == nullptr);
innerInfo.parentInfo = loopInfo;
innerInfo.sortIndx = frameBuilder_->sortIndx_++;
loopInfo = &innerInfo;
} else if (loopInfo != nullptr) {
bb.loopIndex = loopInfo->loopIndex;
}
return loopInfo;
}
void ComputeLoopTree()
{
FrameStateBuilder::LoopInfo* loopInfo = nullptr;
auto currentDepth = Push(0, 0); // entry id
while (currentDepth > 0) {
auto &curState = dfsStack_[currentDepth - 1]; // -1: for current
auto const &bb = bcBuilder_->GetBasicBlockById(curState.bbId);
if (!bcBuilder_->IsOSR()) {
ASSERT(bb.catches.empty());
}
auto index = curState.index;
BytecodeRegion* bbNext = nullptr;
if (index >= bb.succs.size()) {
if (bb.loopNumber > 0) {
if (visitState_[curState.bbId] == MarkState::ON_STACK) {
ASSERT(loopInfo->loopHeadId == curState.bbId);
loopInfo = loopInfo->parentInfo;
visitState_[curState.bbId] = MarkState::VISITED1;
}
bbNext = PushLoopExist(bb, currentDepth);
}
} else {
bbNext = bb.succs[curState.index++]; // 1: goto next
}
if (bbNext != nullptr) {
if (loopInfo != nullptr && !loopInfo->loopBodys->TestBit(bbNext->id)) {
AddLoopExit(bbNext, loopInfo);
} else if (visitState_[bbNext->id] == MarkState::UNVISITED1) {
currentDepth = Push(bbNext->id, currentDepth);
loopInfo = EnterInnerLoop(loopInfo, bbNext->id);
}
} else {
if (bb.loopNumber == 0) {
visitState_[curState.bbId] = MarkState::VISITED1;
}
currentDepth--;
}
}
}
size_t Push(size_t bbId, size_t depth)
{
if (visitState_[bbId] == MarkState::UNVISITED1) {
dfsStack_[depth].bbId = bbId;
dfsStack_[depth].index = 0;
visitState_[bbId] = MarkState::ON_STACK;
return depth + 1;
}
return depth;
}
BytecodeRegion* PushLoopExist(const BytecodeRegion& bb, size_t depth)
{
ASSERT(depth > 0);
auto &curState = dfsStack_[depth - 1]; // -1: for current
auto loopExitIndex = curState.index - bb.succs.size();
auto& currentInfo = frameBuilder_->GetLoopInfo(bb);
BytecodeRegion* bbNext = nullptr;
if (currentInfo.loopExits != nullptr && loopExitIndex < currentInfo.loopExits->size()) {
bbNext = currentInfo.loopExits->at(loopExitIndex);
curState.index++; // 1: goto next
}
return bbNext;
}
void AddLoopExit(BytecodeRegion *bb, FrameStateBuilder::LoopInfo *loopInfo)
{
if (loopInfo->loopExits == nullptr) {
loopInfo->loopExits = chunk_->New<ChunkVector<BytecodeRegion*>>(chunk_);
}
loopInfo->loopExits->emplace_back(bb);
}
void PrintLoop(FrameStateBuilder::LoopInfo& loopInfo)
{
auto size = bcBuilder_->GetBasicBlockCount();
LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
LOG_COMPILER(INFO) << "LoopHead: " << loopInfo.loopHeadId;
if (loopInfo.parentInfo != nullptr) {
LOG_COMPILER(INFO) << "ParentLoopHead: " << loopInfo.parentInfo->loopHeadId;
}
std::string log = "Body: [";
for (size_t i = 0; i < size; i++) {
if (loopInfo.loopBodys->TestBit(i)) {
log += std::to_string(i) + ", ";
}
}
LOG_COMPILER(INFO) << log << "]";
std::string log1 = "Exit: [";
if (loopInfo.loopExits != nullptr) {
for (auto bb : *loopInfo.loopExits) {
log1 += std::to_string(bb->id) + ", ";
}
}
LOG_COMPILER(INFO) << log1 << "]";
std::string log2 = "LoopAssignment [";
bool firset = true;
for (size_t i = 0; i < frameBuilder_->numVregs_; i++) {
if (loopInfo.loopAssignment->TestBit(i)) {
if (!firset) {
log2 += ",";
}
firset = false;
log2 += std::to_string(i);
}
}
LOG_COMPILER(INFO) << log2 << "]";
LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
}
private:
struct EndToHead {
size_t fromId;
size_t toId;
};
struct DFSState {
DFSState(size_t bbId, size_t index)
: bbId(bbId), index(index) {}
size_t bbId;
size_t index;
};
struct VisitedInfo {
size_t needVisitIndex;
bool isVisitedCatchBlock = false;
};
enum class MarkState : uint8_t {
UNVISITED = 0,
ON_STACK,
PENDING,
VISITED,
VISITED1,
UNVISITED1 = VISITED
};
FrameStateBuilder* frameBuilder_ {nullptr};
BytecodeCircuitBuilder *bcBuilder_ {nullptr};
ChunkDeque<size_t> pendingList_;
ChunkVector<EndToHead> loopbacks_;
ChunkVector<DFSState> dfsStack_;
ChunkVector<MarkState> visitState_;
Chunk* chunk_ {nullptr};
size_t numLoops_ {0};
std::vector<VisitedInfo> visitedInfo_;
};
void FrameStateBuilder::ComputeLoopInfo()
{
BlockLoopAnalysis loopAnalysis(this, circuit_->chunk());
loopAnalysis.Run();
if (numLoops_ != 0) {
ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
headerGates.resize(numLoops_, Circuit::NullGate());
}
}
void FrameStateBuilder::DumpLiveState()
{
LOG_COMPILER(INFO) << "DumpLiveState";
for (size_t i = 0; i < bcEndStateLiveouts_.size(); i++) {
auto liveout = GetFrameLiveoutAfter(i);
if (liveout == nullptr) {
continue;
}
std::string log = "BC: " + std::to_string(i) + " {";
bool firset = true;
for (size_t j = 0; j < numVregs_; j++) {
if (liveout->TestBit(j)) {
if (!firset) {
log += ",";
}
firset = false;
log += std::to_string(j);
}
}
log += "}";
LOG_COMPILER(INFO) << log;
}
for (size_t i = 1; i < bbBeginStateLiveouts_.size(); i++) { // 1: skip entry
auto liveout = GetFrameLiveoutBefore(i);
if (liveout == nullptr) {
continue;
}
std::string log = "BB: " + std::to_string(i) + " {";
bool firset = true;
for (size_t j = 0; j < numVregs_; j++) {
if (liveout->TestBit(j)) {
if (!firset) {
log += ",";
}
firset = false;
log += std::to_string(j);
}
}
log += "}";
LOG_COMPILER(INFO) << log;
}
}
GateRef FrameStateBuilder::BuildFrameState(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
{
auto pcOffset = bcBuilder_->GetPcOffset(bcIndex);
GateRef gateValues = BuildFrameValues(frameContext, liveout);
GateRef frameArgs = bcBuilder_->GetFrameArgs();
GateRef preFrameState = bcBuilder_->GetPreFrameState();
UInt32PairAccessor accessor(static_cast<uint32_t>(pcOffset),
FrameStateOutput::Invalid().GetValue());
auto frameState = circuit_->NewGate(circuit_->FrameState(accessor.ToValue()),
{frameArgs, gateValues, preFrameState});
return frameState;
}
GateRef FrameStateBuilder::BuildStateSplit(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
{
auto frameState = BuildFrameState(frameContext, liveout, bcIndex);
auto state = frameContext->currentState_;
auto depend = frameContext->currentDepend_;
ASSERT(state != Circuit::NullGate());
ASSERT(depend != Circuit::NullGate());
return circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
}
void FrameStateBuilder::BindStateSplitBefore(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
{
if (!bcBuilder_->IsTypeLoweringEnabled()) {
return;
}
if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
frameStateCache_ = BuildFrameState(liveContext_, liveout, bcId);
}
ASSERT(!liveContext_->needStateSplit_);
}
void FrameStateBuilder::BindStateSplitAfter(const BytecodeInfo &bytecodeInfo,
uint32_t bcId, GateRef gate)
{
if (!bcBuilder_->IsTypeLoweringEnabled()) {
return;
}
if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
auto frameState = GetBcFrameStateCache();
acc_.ReplaceFrameStateIn(gate, frameState);
}
if (!bytecodeInfo.NoSideEffects() && !bytecodeInfo.IsThrow()) {
auto stateSplit = BuildStateSplit(liveContext_, GetOrOCreateBCEndLiveOut(bcId), bcId + 1); // 1: for after
liveContext_->currentDepend_ = stateSplit;
}
}
GateRef FrameStateBuilder::BuildFrameValues(FrameContext* frameContext, FrameLiveOut* liveout)
{
size_t frameStateInputs = numVregs_;
std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
JSTaggedValue::VALUE_OPTIMIZED_OUT,
GateType::TaggedValue());
for (size_t i = 0; i < numVregs_; i++) {
auto value = frameContext->ValuesAt(i);
if (value == Circuit::NullGate() || !liveout->TestBit(i)) {
value = optimizedGate;
}
inList[i] = value;
}
return circuit_->NewGate(circuit_->FrameValues(frameStateInputs), inList);
}
}