2022-01-06 02:26:19 +00:00
|
|
|
/*
|
2024-07-11 13:21:48 +00:00
|
|
|
* Copyright (c) 2021-2024 Huawei Device Co., Ltd.
|
2022-01-06 02:26:19 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-06-16 09:27:35 +00:00
|
|
|
#include "ecmascript/compiler/bytecode_circuit_builder.h"
|
|
|
|
|
2024-08-31 06:53:09 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cstddef>
|
|
|
|
|
2022-04-24 07:14:09 +00:00
|
|
|
#include "ecmascript/base/number_helper.h"
|
2022-06-10 07:22:21 +00:00
|
|
|
#include "ecmascript/compiler/gate_accessor.h"
|
2024-03-19 06:57:29 +00:00
|
|
|
#include "ecmascript/deoptimizer/deoptimizer.h"
|
2024-07-11 13:21:48 +00:00
|
|
|
#include "ecmascript/interpreter/interpreter-inl.h"
|
2022-09-20 15:17:00 +00:00
|
|
|
#include "libpandafile/bytecode_instruction-inl.h"
|
2022-08-26 01:06:59 +00:00
|
|
|
|
2024-08-31 06:53:09 +00:00
|
|
|
|
2022-01-19 01:11:02 +00:00
|
|
|
namespace panda::ecmascript::kungfu {
|
2022-03-07 02:58:13 +00:00
|
|
|
void BytecodeCircuitBuilder::BytecodeToCircuit()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-11-02 01:32:55 +00:00
|
|
|
ExceptionInfo exceptionInfo = {};
|
2022-01-06 02:26:19 +00:00
|
|
|
|
|
|
|
// collect try catch block info
|
2022-08-02 08:38:18 +00:00
|
|
|
CollectTryCatchBlockInfo(exceptionInfo);
|
2022-11-28 01:26:23 +00:00
|
|
|
hasTryCatch_ = exceptionInfo.size() != 0;
|
2022-11-02 07:10:09 +00:00
|
|
|
BuildRegionInfo();
|
2022-01-06 02:26:19 +00:00
|
|
|
// Building the basic block diagram of bytecode
|
2022-11-02 07:10:09 +00:00
|
|
|
BuildRegions(exceptionInfo);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 07:10:09 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildRegionInfo()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-11-02 01:32:55 +00:00
|
|
|
uint32_t size = pcOffsets_.size();
|
2024-05-04 10:22:49 +00:00
|
|
|
ASSERT(size > 0);
|
2023-09-07 02:16:14 +00:00
|
|
|
uint32_t end = size - 1; // 1: end
|
2022-11-02 01:32:55 +00:00
|
|
|
BytecodeIterator iterator(this, 0, end);
|
|
|
|
|
|
|
|
infoData_.resize(size);
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_.resize(size, std::vector<GateRef>(0));
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertHead(0); // 0: start pc
|
2023-11-06 01:19:36 +00:00
|
|
|
iterator.GotoStart();
|
|
|
|
while (!iterator.Done()) {
|
2022-11-02 01:32:55 +00:00
|
|
|
auto index = iterator.Index();
|
|
|
|
auto &info = infoData_[index];
|
|
|
|
auto pc = pcOffsets_[index];
|
|
|
|
info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
|
2023-04-03 08:33:32 +00:00
|
|
|
ASSERT(!info.metaData_.IsInvalid());
|
2022-11-02 01:32:55 +00:00
|
|
|
BytecodeInfo::InitBytecodeInfo(this, info, pc);
|
2022-11-02 07:10:09 +00:00
|
|
|
CollectRegionInfo(index);
|
2023-11-06 01:19:36 +00:00
|
|
|
++iterator;
|
2022-11-02 01:32:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-02 07:10:09 +00:00
|
|
|
void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
|
2022-11-02 01:32:55 +00:00
|
|
|
{
|
|
|
|
auto pc = pcOffsets_[bcIndex];
|
|
|
|
auto &info = infoData_[bcIndex];
|
2022-11-25 07:22:42 +00:00
|
|
|
int32_t offset = 0;
|
2022-11-02 01:32:55 +00:00
|
|
|
if (info.IsJump()) {
|
|
|
|
switch (info.GetOpcode()) {
|
|
|
|
case EcmaOpcode::JEQZ_IMM8:
|
|
|
|
case EcmaOpcode::JNEZ_IMM8:
|
|
|
|
case EcmaOpcode::JMP_IMM8:
|
|
|
|
offset = static_cast<int8_t>(READ_INST_8_0());
|
|
|
|
break;
|
|
|
|
case EcmaOpcode::JNEZ_IMM16:
|
|
|
|
case EcmaOpcode::JEQZ_IMM16:
|
|
|
|
case EcmaOpcode::JMP_IMM16:
|
|
|
|
offset = static_cast<int16_t>(READ_INST_16_0());
|
|
|
|
break;
|
|
|
|
case EcmaOpcode::JMP_IMM32:
|
|
|
|
case EcmaOpcode::JNEZ_IMM32:
|
|
|
|
case EcmaOpcode::JEQZ_IMM32:
|
|
|
|
offset = static_cast<int32_t>(READ_INST_32_0());
|
|
|
|
break;
|
|
|
|
default:
|
2022-12-01 07:29:41 +00:00
|
|
|
LOG_ECMA(FATAL) << "this branch is unreachable";
|
2022-11-02 01:32:55 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
auto nextIndex = bcIndex + 1; // 1: next pc
|
|
|
|
auto targetIndex = FindBcIndexByPc(pc + offset);
|
|
|
|
// condition branch current basic block end
|
|
|
|
if (info.IsCondJump()) {
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertSplit(nextIndex);
|
|
|
|
regionsInfo_.InsertJump(targetIndex, bcIndex, false);
|
2022-11-02 01:32:55 +00:00
|
|
|
} else {
|
2023-04-18 02:56:21 +00:00
|
|
|
if (bcIndex != GetLastBcIndex()) {
|
|
|
|
regionsInfo_.InsertHead(nextIndex);
|
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertJump(targetIndex, bcIndex, true);
|
2022-08-16 15:48:09 +00:00
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
} else if (info.IsReturn() || info.IsThrow()) {
|
|
|
|
if (bcIndex != GetLastBcIndex()) {
|
|
|
|
auto nextIndex = bcIndex + 1; // 1: next pc
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertHead(nextIndex);
|
2022-04-01 06:33:39 +00:00
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-12-03 14:03:40 +00:00
|
|
|
auto pf = file_->GetPandaFile();
|
|
|
|
panda_file::MethodDataAccessor mda(*pf, method_->GetMethodId());
|
|
|
|
panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
|
2022-08-02 08:38:18 +00:00
|
|
|
|
|
|
|
cda.EnumerateTryBlocks([this, &byteCodeException](
|
2022-11-02 01:32:55 +00:00
|
|
|
panda_file::CodeDataAccessor::TryBlock &tryBlock) {
|
|
|
|
auto tryStartOffset = tryBlock.GetStartPc();
|
|
|
|
auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
|
|
|
|
|
2022-03-07 02:58:13 +00:00
|
|
|
auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
|
|
|
|
auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
|
2022-08-23 02:33:21 +00:00
|
|
|
// skip try blocks with same pc in start and end label
|
|
|
|
if (tryStartPc == tryEndPc) {
|
|
|
|
return true;
|
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
|
|
|
|
auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertSplit(tryStartBcIndex);
|
2022-11-02 01:32:55 +00:00
|
|
|
if (tryEndPc <= GetLastPC()) {
|
|
|
|
auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertSplit(tryEndBcIndex);
|
2022-11-02 01:32:55 +00:00
|
|
|
}
|
|
|
|
byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
|
|
|
|
tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
|
|
|
|
auto pcOffset = catchBlock.GetHandlerPc();
|
2022-03-07 02:58:13 +00:00
|
|
|
auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
|
2022-11-02 01:32:55 +00:00
|
|
|
auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
|
2022-11-02 07:10:09 +00:00
|
|
|
regionsInfo_.InsertHead(catchBlockBcIndex);
|
2022-01-06 02:26:19 +00:00
|
|
|
// try block associate catch block
|
2023-11-06 01:19:36 +00:00
|
|
|
byteCodeException.back().catches.emplace_back(catchBlockPc);
|
2022-01-06 02:26:19 +00:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-31 06:53:09 +00:00
|
|
|
bool BytecodeCircuitBuilder::IsAncestor(size_t nodeA, size_t nodeB)
|
|
|
|
{
|
|
|
|
return timeIn_[bbIdToDfsTimestamp_[nodeA]] <= timeIn_[bbIdToDfsTimestamp_[nodeB]] &&
|
|
|
|
timeOut_[bbIdToDfsTimestamp_[nodeA]] >= timeOut_[bbIdToDfsTimestamp_[nodeB]];
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::PerformDFS(const std::vector<size_t> &immDom, size_t listSize)
|
|
|
|
{
|
|
|
|
std::vector<std::vector<size_t>> sonList(listSize);
|
|
|
|
for (size_t idx = 1; idx < immDom.size(); idx++) {
|
|
|
|
sonList[immDom[idx]].push_back(idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
size_t timestamp = 0;
|
|
|
|
struct DFSState {
|
|
|
|
size_t cur;
|
|
|
|
std::vector<size_t> &succList;
|
|
|
|
size_t idx;
|
|
|
|
};
|
|
|
|
std::stack<DFSState> dfsStack;
|
|
|
|
size_t root = 0;
|
|
|
|
dfsStack.push({root, sonList[root], 0});
|
|
|
|
timeIn_[root] = timestamp++;
|
|
|
|
while (!dfsStack.empty()) {
|
|
|
|
auto &curState = dfsStack.top();
|
|
|
|
auto &cur = curState.cur;
|
|
|
|
auto &succList = curState.succList;
|
|
|
|
auto &idx = curState.idx;
|
|
|
|
if (idx == succList.size()) {
|
|
|
|
timeOut_[cur] = timestamp++;
|
|
|
|
dfsStack.pop();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const auto &succ = succList[idx];
|
|
|
|
dfsStack.push({succ, sonList[succ], 0});
|
|
|
|
timeIn_[succ] = timestamp++;
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::ReducibilityCheck()
|
|
|
|
{
|
|
|
|
std::vector<size_t> basicBlockList;
|
|
|
|
std::vector<size_t> immDom;
|
|
|
|
std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
|
|
|
|
ComputeDominatorTree(basicBlockList, immDom, bbDfsTimestampToIdx);
|
|
|
|
timeIn_.resize(basicBlockList.size());
|
|
|
|
timeOut_.resize(basicBlockList.size());
|
|
|
|
PerformDFS(immDom, basicBlockList.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
|
|
|
|
std::unordered_map<size_t, size_t> &dfsFatherIdx,
|
|
|
|
std::vector<size_t> &immDom,
|
|
|
|
std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
|
|
|
|
{
|
|
|
|
std::vector<size_t> semiDom(basicBlockList.size());
|
|
|
|
std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
|
|
|
|
{
|
|
|
|
std::vector<size_t> parent(basicBlockList.size());
|
|
|
|
std::iota(parent.begin(), parent.end(), 0);
|
|
|
|
std::vector<size_t> minIdx(basicBlockList.size());
|
|
|
|
std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
|
|
|
|
if (parent[idx] == idx) return idx;
|
|
|
|
size_t unionFindSetRoot = unionFind(parent[idx]);
|
|
|
|
if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
|
|
|
|
minIdx[idx] = minIdx[parent[idx]];
|
|
|
|
}
|
|
|
|
return parent[idx] = unionFindSetRoot;
|
|
|
|
};
|
|
|
|
auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
|
|
|
|
size_t parentFatherIdx = unionFind(fatherIdx);
|
|
|
|
size_t parentSonIdx = unionFind(sonIdx);
|
|
|
|
parent[parentSonIdx] = parentFatherIdx;
|
|
|
|
};
|
|
|
|
auto calculateSemiDom = [&](size_t idx, const ChunkVector<BytecodeRegion *> &blocks) {
|
|
|
|
for (const auto &preBlock : blocks) {
|
|
|
|
if (bbDfsTimestampToIdx[preBlock->id] < idx) {
|
|
|
|
semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
|
|
|
|
} else {
|
|
|
|
unionFind(bbDfsTimestampToIdx[preBlock->id]);
|
|
|
|
semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
std::iota(semiDom.begin(), semiDom.end(), 0);
|
|
|
|
semiDom[0] = semiDom.size();
|
|
|
|
for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
|
|
|
|
calculateSemiDom(idx, graph_[basicBlockList[idx]]->preds);
|
|
|
|
if (!graph_[basicBlockList[idx]]->trys.empty()) {
|
|
|
|
calculateSemiDom(idx, graph_[basicBlockList[idx]]->trys);
|
|
|
|
}
|
|
|
|
for (const auto &succDomIdx : semiDomTree[idx]) {
|
|
|
|
unionFind(succDomIdx);
|
|
|
|
if (idx == semiDom[minIdx[succDomIdx]]) {
|
|
|
|
immDom[succDomIdx] = idx;
|
|
|
|
} else {
|
|
|
|
immDom[succDomIdx] = minIdx[succDomIdx];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
minIdx[idx] = idx;
|
|
|
|
merge(dfsFatherIdx[basicBlockList[idx]], idx);
|
|
|
|
semiDomTree[semiDom[idx]].emplace_back(idx);
|
|
|
|
}
|
|
|
|
for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
|
|
|
|
if (immDom[idx] != semiDom[idx]) {
|
|
|
|
immDom[idx] = immDom[immDom[idx]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
semiDom[0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
|
|
|
|
std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
|
|
|
|
{
|
|
|
|
std::unordered_map<size_t, size_t> dfsFatherIdx;
|
|
|
|
size_t timestamp = 0;
|
|
|
|
std::deque<size_t> pendingList;
|
|
|
|
std::vector<size_t> visited(graph_.size(), 0);
|
|
|
|
auto basicBlockId = graph_[0]->id;
|
|
|
|
visited[graph_[0]->id] = 1;
|
|
|
|
pendingList.emplace_back(basicBlockId);
|
|
|
|
|
|
|
|
auto visitConnectedBlocks = [&](const ChunkVector<BytecodeRegion *> &succs, size_t curBlockId) {
|
|
|
|
for (const auto &succBlock : succs) {
|
|
|
|
if (visited[succBlock->id] == 0) {
|
|
|
|
visited[succBlock->id] = 1;
|
|
|
|
pendingList.emplace_back(succBlock->id);
|
|
|
|
dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp_[curBlockId];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
while (!pendingList.empty()) {
|
|
|
|
size_t curBlockId = pendingList.back();
|
|
|
|
pendingList.pop_back();
|
|
|
|
basicBlockList.emplace_back(curBlockId);
|
|
|
|
bbIdToDfsTimestamp_[curBlockId] = timestamp++;
|
|
|
|
visitConnectedBlocks(graph_[curBlockId]->succs, curBlockId);
|
|
|
|
if (!graph_[curBlockId]->catches.empty()) {
|
|
|
|
visitConnectedBlocks(graph_[curBlockId]->catches, curBlockId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
|
|
|
|
bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
immDom.resize(basicBlockList.size());
|
|
|
|
ComputeImmediateDominators(basicBlockList, dfsFatherIdx, immDom, bbDfsTimestampToIdx);
|
|
|
|
}
|
|
|
|
|
2023-04-23 09:21:01 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildEntryBlock()
|
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
BytecodeRegion &entryBlock = RegionAt(0);
|
|
|
|
BytecodeRegion &nextBlock = RegionAt(1);
|
2023-04-23 09:21:01 +00:00
|
|
|
entryBlock.succs.emplace_back(&nextBlock);
|
|
|
|
nextBlock.preds.emplace_back(&entryBlock);
|
2023-11-06 01:19:36 +00:00
|
|
|
entryBlock.bytecodeIterator_.Reset(this, 0, BytecodeIterator::INVALID_INDEX);
|
2023-04-23 09:21:01 +00:00
|
|
|
}
|
|
|
|
|
2024-08-31 06:53:09 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildBasicBlock()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-11-02 07:10:09 +00:00
|
|
|
auto &items = regionsInfo_.GetBlockItems();
|
2023-04-23 09:21:01 +00:00
|
|
|
size_t blockId = 1;
|
2022-11-02 01:32:55 +00:00
|
|
|
for (const auto &item : items) {
|
|
|
|
auto &curBlock = GetBasicBlockById(blockId);
|
|
|
|
curBlock.id = blockId;
|
|
|
|
curBlock.start = item.GetStartBcIndex();
|
2023-04-23 09:21:01 +00:00
|
|
|
if (blockId != 1) {
|
2023-11-06 01:19:36 +00:00
|
|
|
auto &prevBlock = RegionAt(blockId - 1);
|
2024-05-04 10:22:49 +00:00
|
|
|
ASSERT(curBlock.start >= 1);
|
2022-11-02 01:32:55 +00:00
|
|
|
prevBlock.end = curBlock.start - 1;
|
|
|
|
prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
|
|
|
|
// fall through
|
|
|
|
if (!item.IsHeadBlock()) {
|
|
|
|
curBlock.preds.emplace_back(&prevBlock);
|
|
|
|
prevBlock.succs.emplace_back(&curBlock);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
blockId++;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
auto &lastBlock = RegionAt(blockId - 1); // 1: last block
|
2022-11-02 01:32:55 +00:00
|
|
|
lastBlock.end = GetLastBcIndex();
|
|
|
|
lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
|
2024-08-31 06:53:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
|
|
|
|
{
|
|
|
|
auto blockSize = regionsInfo_.GetBlockItems().size();
|
|
|
|
|
|
|
|
// 1 : entry block. if the loop head is in the first bb block, the variables used in the head cannot correctly
|
|
|
|
// generate Phi nodes through the dominator-tree algorithm, resulting in an infinite loop. Therefore, an empty
|
|
|
|
// BB block is generated as an entry block
|
|
|
|
graph_.resize(blockSize + 1, nullptr);
|
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
|
|
|
graph_[i] = circuit_->chunk()->New<BytecodeRegion>(circuit_->chunk());
|
|
|
|
}
|
|
|
|
|
|
|
|
// build entry block
|
|
|
|
BuildEntryBlock();
|
|
|
|
|
|
|
|
// build basic block
|
|
|
|
BuildBasicBlock();
|
2022-11-02 01:32:55 +00:00
|
|
|
|
2022-11-02 07:10:09 +00:00
|
|
|
auto &splitItems = regionsInfo_.GetSplitItems();
|
2022-11-02 01:32:55 +00:00
|
|
|
for (const auto &item : splitItems) {
|
2022-11-02 07:10:09 +00:00
|
|
|
auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &curBlock = GetBasicBlockById(curIndex);
|
2022-11-02 07:10:09 +00:00
|
|
|
auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &predBlock = GetBasicBlockById(predIndex);
|
|
|
|
curBlock.preds.emplace_back(&predBlock);
|
|
|
|
predBlock.succs.emplace_back(&curBlock);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
if (byteCodeException.size() != 0) {
|
|
|
|
BuildCatchBlocks(byteCodeException);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
UpdateCFG();
|
|
|
|
if (HasTryCatch()) {
|
|
|
|
CollectTryPredsInfo();
|
|
|
|
}
|
|
|
|
RemoveUnreachableRegion();
|
2024-08-31 06:53:09 +00:00
|
|
|
if (NeedIrreducibleLoopCheck()) {
|
|
|
|
ReducibilityCheck();
|
|
|
|
}
|
|
|
|
if (IsLogEnabled() && !IsPreAnalysis()) {
|
2024-05-07 12:48:37 +00:00
|
|
|
PrintGraph(std::string("Update CFG [" + methodName_ + "]").c_str());
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
BuildCircuit();
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
|
|
|
// try catch block associate
|
2022-04-24 17:17:29 +00:00
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
2023-11-06 01:19:36 +00:00
|
|
|
auto &bb = RegionAt(i);
|
2022-11-02 01:32:55 +00:00
|
|
|
auto startIndex = bb.start;
|
2024-08-28 01:32:07 +00:00
|
|
|
bool noThrow = true;
|
|
|
|
EnumerateBlock(bb, [&noThrow](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
if (bytecodeInfo.IsGeneral()) {
|
|
|
|
if (!bytecodeInfo.NoThrow()) {
|
|
|
|
noThrow = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
if (noThrow) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
const auto pc = pcOffsets_[startIndex];
|
|
|
|
for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
|
|
|
|
if (pc < it->startPc || pc >= it->endPc) {
|
2022-01-18 04:02:20 +00:00
|
|
|
continue;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
// try block interval
|
2023-11-06 01:19:36 +00:00
|
|
|
const auto &catches = it->catches; // catches start pc
|
2022-04-24 17:17:29 +00:00
|
|
|
for (size_t j = i + 1; j < graph_.size(); j++) {
|
2023-11-06 01:19:36 +00:00
|
|
|
auto &catchBB = RegionAt(j);
|
2022-11-02 01:32:55 +00:00
|
|
|
const auto catchStart = pcOffsets_[catchBB.start];
|
2023-11-06 01:19:36 +00:00
|
|
|
if (std::find(catches.cbegin(), catches.cend(), catchStart) != catches.cend()) {
|
|
|
|
bb.catches.insert(bb.catches.cbegin(), &catchBB);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-21 02:14:57 +00:00
|
|
|
|
|
|
|
// When there are multiple catch blocks in the current block, the set of catch blocks
|
|
|
|
// needs to be sorted to satisfy the order of execution of catch blocks.
|
2022-07-15 02:35:25 +00:00
|
|
|
bb.SortCatches();
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::CollectTryPredsInfo()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
|
|
|
auto &bb = RegionAt(i);
|
|
|
|
if (bb.catches.empty()) {
|
|
|
|
continue;
|
|
|
|
} else if (bb.catches.size() > 1) { // 1: cache size
|
|
|
|
for (auto it = bb.catches.begin() + 1; it != bb.catches.end();) { // 1: invalid catch bb
|
|
|
|
bb.EraseThisBlock((*it)->trys);
|
|
|
|
it = bb.catches.erase(it);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
if (bytecodeInfo.IsGeneral()) {
|
|
|
|
// if block which can throw exception has serval catchs block,
|
|
|
|
// only the innermost catch block is useful
|
|
|
|
ASSERT(bb.catches.size() == 1); // 1: cache size
|
|
|
|
if (!bytecodeInfo.NoThrow()) {
|
|
|
|
bb.catches.at(0)->numOfStatePreds++;
|
2022-08-01 09:13:57 +00:00
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
return true;
|
|
|
|
});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::RemoveUnusedPredsInfo(BytecodeRegion& bb)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
if (bytecodeInfo.IsGeneral()) {
|
|
|
|
ASSERT(bb.catches.size() == 1); // 1: cache size
|
|
|
|
if (!bytecodeInfo.NoThrow()) {
|
|
|
|
bb.catches.at(0)->numOfStatePreds--;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
return true;
|
|
|
|
});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
auto bb = pendingList.back();
|
|
|
|
pendingList.pop_back();
|
|
|
|
for (auto it = bb->preds.begin(); it != bb->preds.end(); it++) {
|
2024-08-28 01:32:07 +00:00
|
|
|
ASSERT((*it)->numOfStatePreds >= 0);
|
2023-11-06 01:19:36 +00:00
|
|
|
if ((*it)->numOfStatePreds != 0) {
|
|
|
|
bb->EraseThisBlock((*it)->succs);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
for (auto it = bb->succs.begin(); it != bb->succs.end(); it++) {
|
|
|
|
auto bbNext = *it;
|
2024-08-28 01:32:07 +00:00
|
|
|
ASSERT(bbNext->numOfStatePreds >= 0);
|
2023-11-06 01:19:36 +00:00
|
|
|
if (bbNext->numOfStatePreds != 0) {
|
|
|
|
bb->EraseThisBlock(bbNext->preds);
|
|
|
|
bbNext->numOfStatePreds--;
|
|
|
|
if (bbNext->numOfStatePreds == 0) {
|
|
|
|
pendingList.emplace_back(bbNext);
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
for (auto it = bb->trys.begin(); it != bb->trys.end(); it++) {
|
2024-08-28 01:32:07 +00:00
|
|
|
ASSERT((*it)->numOfStatePreds >= 0);
|
2023-11-06 01:19:36 +00:00
|
|
|
if ((*it)->numOfStatePreds != 0) {
|
|
|
|
bb->EraseThisBlock((*it)->catches);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
for (auto it = bb->catches.begin(); it != bb->catches.end(); it++) {
|
|
|
|
auto bbNext = *it;
|
2024-08-28 01:32:07 +00:00
|
|
|
ASSERT(bbNext->numOfStatePreds >= 0);
|
2023-11-06 01:19:36 +00:00
|
|
|
if (bbNext->numOfStatePreds != 0) {
|
|
|
|
RemoveUnusedPredsInfo(*bb);
|
|
|
|
bb->EraseThisBlock(bbNext->trys);
|
|
|
|
if (bbNext->numOfStatePreds == 0) {
|
|
|
|
pendingList.emplace_back(bbNext);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
bb->preds.clear();
|
|
|
|
bb->succs.clear();
|
|
|
|
bb->trys.clear();
|
|
|
|
bb->catches.clear();
|
|
|
|
numOfLiveBB_--;
|
2024-04-18 12:43:30 +00:00
|
|
|
|
|
|
|
RemoveIfInRpoList(bb);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::RemoveIfInRpoList(BytecodeRegion *bb)
|
|
|
|
{
|
|
|
|
auto& rpoList = frameStateBuilder_.GetRpoList();
|
|
|
|
for (auto iter = rpoList.begin(); iter != rpoList.end(); iter++) {
|
|
|
|
if (*iter == bb->id) {
|
|
|
|
rpoList.erase(iter);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::RemoveUnreachableRegion()
|
2022-07-15 02:35:25 +00:00
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
numOfLiveBB_ = graph_.size();
|
|
|
|
ChunkVector<BytecodeRegion*> pendingList(circuit_->chunk());
|
|
|
|
for (size_t i = 1; i < graph_.size(); i++) { // 1: skip entry bb
|
|
|
|
auto &bb = RegionAt(i);
|
2024-08-28 01:32:07 +00:00
|
|
|
ASSERT(bb.numOfStatePreds >= 0);
|
|
|
|
if (bb.numOfStatePreds == 0) {
|
2023-11-06 01:19:36 +00:00
|
|
|
pendingList.emplace_back(&bb);
|
2022-07-15 02:35:25 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
while (!pendingList.empty()) {
|
|
|
|
ClearUnreachableRegion(pendingList);
|
|
|
|
}
|
2022-07-15 02:35:25 +00:00
|
|
|
}
|
|
|
|
|
2024-08-29 12:02:20 +00:00
|
|
|
void BytecodeCircuitBuilder::ComputeNumOfLoopBack()
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
|
|
|
auto &bb = RegionAt(i);
|
|
|
|
if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (auto &succ: bb.succs) {
|
|
|
|
if (succ->IsLoopBack(bb)) {
|
|
|
|
succ->numOfLoopBack++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bb.catches.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
if (bytecodeInfo.IsGeneral() && !bytecodeInfo.NoThrow() && bb.catches.at(0)->IsLoopBack(bb)) {
|
|
|
|
// if block which can throw exception has serval catchs block,
|
|
|
|
// only the innermost catch block is useful
|
|
|
|
ASSERT(bb.catches.size() == 1); // 1: cache size
|
|
|
|
bb.catches.at(0)->numOfLoopBack++;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2022-01-19 01:11:02 +00:00
|
|
|
// Update CFG's predecessor, successor and try catch associations
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::UpdateCFG()
|
2022-01-19 01:11:02 +00:00
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
|
|
|
auto &bb = RegionAt(i);
|
2022-01-19 01:11:02 +00:00
|
|
|
bb.preds.clear();
|
|
|
|
bb.trys.clear();
|
2023-11-06 01:19:36 +00:00
|
|
|
ChunkVector<BytecodeRegion *> newSuccs(circuit_->chunk());
|
2022-01-19 01:11:02 +00:00
|
|
|
for (const auto &succ: bb.succs) {
|
2022-10-27 09:12:44 +00:00
|
|
|
newSuccs.emplace_back(succ);
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
bb.succs.clear();
|
|
|
|
bb.succs.insert(bb.succs.end(), newSuccs.begin(), newSuccs.end());
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
|
|
|
auto &bb = RegionAt(i);
|
2022-01-19 01:11:02 +00:00
|
|
|
for (auto &succ: bb.succs) {
|
2022-10-27 09:12:44 +00:00
|
|
|
succ->preds.emplace_back(&bb);
|
2023-11-06 01:19:36 +00:00
|
|
|
succ->numOfStatePreds++;
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
for (auto &catchBlock: bb.catches) {
|
2022-10-27 09:12:44 +00:00
|
|
|
catchBlock->trys.emplace_back(&bb);
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
// build circuit
|
|
|
|
void BytecodeCircuitBuilder::BuildCircuitArgs()
|
|
|
|
{
|
2022-06-16 09:27:35 +00:00
|
|
|
argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
|
2023-05-18 11:13:51 +00:00
|
|
|
if (!method_->IsFastCall()) {
|
|
|
|
argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
|
2024-03-29 09:05:46 +00:00
|
|
|
argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGV, MachineType::ARCH, GateType::NJSValue());
|
2023-05-18 11:13:51 +00:00
|
|
|
auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
|
|
|
|
const size_t actualNumArgs = argAcc_.GetActualNumArgs();
|
|
|
|
// new actual argument gates
|
|
|
|
for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
|
|
|
|
argAcc_.NewArg(argIdx);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auto funcIdx = static_cast<size_t>(FastCallArgIdx::FUNC);
|
|
|
|
size_t actualNumArgs = static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS) + method_->GetNumArgsWithCallField();
|
|
|
|
for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
|
|
|
|
argAcc_.NewArg(argIdx);
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2022-07-19 12:44:46 +00:00
|
|
|
argAcc_.CollectArgs();
|
2023-03-27 09:23:59 +00:00
|
|
|
BuildFrameArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildFrameArgs()
|
|
|
|
{
|
2023-09-14 09:06:56 +00:00
|
|
|
UInt32PairAccessor accessor(0, 0);
|
|
|
|
auto metaData = circuit_->FrameArgs(accessor.ToValue());
|
|
|
|
size_t numArgs = metaData->GetNumIns();
|
2023-03-27 09:23:59 +00:00
|
|
|
std::vector<GateRef> args(numArgs, Circuit::NullGate());
|
|
|
|
size_t idx = 0;
|
|
|
|
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
|
|
|
|
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
|
|
|
|
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
|
|
|
|
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
|
2024-03-29 09:05:46 +00:00
|
|
|
args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGV);
|
2024-05-29 07:18:46 +00:00
|
|
|
GateRef sharedConstpool = Circuit::NullGate();
|
|
|
|
GateRef unSharedConstpool = Circuit::NullGate();
|
|
|
|
GetCurrentConstpool(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC), sharedConstpool, unSharedConstpool);
|
|
|
|
args[idx++] = sharedConstpool;
|
|
|
|
args[idx++] = unSharedConstpool;
|
2023-09-14 09:06:56 +00:00
|
|
|
args[idx++] = GetPreFrameArgs();
|
2023-05-18 03:24:10 +00:00
|
|
|
GateRef frameArgs = circuit_->NewGate(metaData, args);
|
2023-03-27 09:23:59 +00:00
|
|
|
argAcc_.SetFrameArgs(frameArgs);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 06:57:29 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildOSRArgs()
|
|
|
|
{
|
|
|
|
// offset -1 : glue
|
|
|
|
(void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_GLUE), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::NJSValue());
|
|
|
|
// offset -2 : argc
|
|
|
|
GateRef argc = method_->IsFastCall()
|
|
|
|
? circuit_->GetConstantGate(MachineType::I64, 0, GateType::NJSValue())
|
|
|
|
: circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGS), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
2024-03-29 09:05:46 +00:00
|
|
|
// offset -3 : argv
|
|
|
|
GateRef argv = method_->IsFastCall()
|
|
|
|
? circuit_->GetConstantGate(MachineType::ARCH, 0, GateType::NJSValue())
|
|
|
|
: circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGV), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
|
|
|
// offset -4 : func
|
2024-03-19 06:57:29 +00:00
|
|
|
(void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_FUNCTION), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
2024-03-29 09:05:46 +00:00
|
|
|
// offset -5 : new_target
|
2024-03-19 06:57:29 +00:00
|
|
|
GateRef newTarget =
|
|
|
|
method_->IsFastCall()
|
|
|
|
? circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType())
|
|
|
|
: circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NEW_TARGET), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
2024-03-29 09:05:46 +00:00
|
|
|
// offset -6 : this_object
|
2024-03-19 06:57:29 +00:00
|
|
|
(void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_THIS_OBJECT), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
2024-03-29 09:05:46 +00:00
|
|
|
// offset -7 : numargs
|
2024-03-19 06:57:29 +00:00
|
|
|
(void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NUM_ARGS), MachineType::I64,
|
|
|
|
{circuit_->GetArgRoot()}, GateType::TaggedValue());
|
|
|
|
for (size_t argIdx = 1; argIdx <= method_->GetNumArgsWithCallField(); argIdx++) {
|
|
|
|
// common args
|
|
|
|
argAcc_.NewArg(method_->IsFastCall() ? static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS)
|
|
|
|
: static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS) + argIdx);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto &args = argAcc_.args_;
|
|
|
|
if (args.size() == 0) {
|
|
|
|
GateAccessor(circuit_).GetArgsOuts(args);
|
|
|
|
std::reverse(args.begin(), args.end());
|
|
|
|
if (method_->IsFastCall() && args.size() >= static_cast<uint8_t>(FastCallArgIdx::NUM_OF_ARGS)) {
|
|
|
|
args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGC), argc);
|
2024-03-29 09:05:46 +00:00
|
|
|
args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGV), argv);
|
2024-03-19 06:57:29 +00:00
|
|
|
// 3: newtarget index
|
|
|
|
args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::NEW_TARGET), newTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BuildFrameArgs();
|
|
|
|
}
|
|
|
|
|
2022-11-29 09:25:20 +00:00
|
|
|
std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
|
|
|
|
const BytecodeInfo &info, const GateMetaData *meta)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2022-11-29 09:25:20 +00:00
|
|
|
auto numValues = meta->GetNumIns();
|
|
|
|
const size_t length = meta->GetInValueStarts();
|
2022-11-10 09:58:04 +00:00
|
|
|
std::vector<GateRef> inList(numValues, Circuit::NullGate());
|
2022-11-28 01:26:23 +00:00
|
|
|
auto inputSize = info.inputs.size();
|
|
|
|
for (size_t i = 0; i < inputSize; i++) {
|
2022-10-27 03:56:58 +00:00
|
|
|
auto &input = info.inputs[i];
|
2022-10-17 11:41:53 +00:00
|
|
|
if (std::holds_alternative<ConstDataId>(input)) {
|
2023-06-06 09:13:57 +00:00
|
|
|
inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
|
|
|
|
std::get<ConstDataId>(input).GetId(),
|
|
|
|
GateType::NJSValue());
|
2022-04-24 17:17:29 +00:00
|
|
|
} else if (std::holds_alternative<Immediate>(input)) {
|
2022-11-09 02:05:55 +00:00
|
|
|
inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
std::get<Immediate>(input).GetValue(),
|
|
|
|
GateType::NJSValue());
|
2022-10-24 11:32:00 +00:00
|
|
|
} else if (std::holds_alternative<ICSlotId>(input)) {
|
2022-11-09 02:05:55 +00:00
|
|
|
inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
|
2022-11-23 08:58:08 +00:00
|
|
|
std::get<ICSlotId>(input).GetId(),
|
|
|
|
GateType::NJSValue());
|
2022-04-24 17:17:29 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(std::holds_alternative<VirtualRegister>(input));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2022-11-28 01:26:23 +00:00
|
|
|
if (info.AccIn()) {
|
|
|
|
inputSize++;
|
|
|
|
}
|
2023-06-09 02:13:24 +00:00
|
|
|
if (meta->HasFrameState()) {
|
|
|
|
inList[inputSize + length] = GetFrameArgs();
|
2022-11-28 01:26:23 +00:00
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
return inList;
|
|
|
|
}
|
|
|
|
|
|
|
|
GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
{
|
2022-10-27 03:56:58 +00:00
|
|
|
auto opcode = info.GetOpcode();
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
GateRef gate = 0;
|
|
|
|
switch (opcode) {
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDNAN:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
base::NumberHelper::GetNaN(),
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::NumberType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDINFINITY:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
base::NumberHelper::GetPositiveInfinity(),
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::NumberType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDUNDEFINED:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_UNDEFINED,
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::UndefinedType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDNULL:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_NULL,
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::NullType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDTRUE:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_TRUE,
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::BooleanType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDFALSE:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_FALSE,
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::BooleanType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDHOLE:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_HOLE,
|
|
|
|
GateType::TaggedValue());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDAI_IMM32:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
std::get<Immediate>(info.inputs[0]).ToJSTaggedValueInt(),
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::IntType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::FLDAI_IMM64:
|
2022-11-09 02:05:55 +00:00
|
|
|
gate = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
std::get<Immediate>(info.inputs.at(0)).ToJSTaggedValueDouble(),
|
2022-11-29 09:25:20 +00:00
|
|
|
GateType::DoubleType());
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
break;
|
2022-09-08 01:37:53 +00:00
|
|
|
case EcmaOpcode::LDFUNCTION:
|
2022-06-16 09:27:35 +00:00
|
|
|
gate = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
|
2022-04-06 07:17:04 +00:00
|
|
|
break;
|
2022-09-09 07:35:02 +00:00
|
|
|
case EcmaOpcode::LDNEWTARGET:
|
|
|
|
gate = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
|
|
|
|
break;
|
|
|
|
case EcmaOpcode::LDTHIS:
|
2022-10-15 04:09:38 +00:00
|
|
|
gate = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
|
2022-09-09 07:35:02 +00:00
|
|
|
break;
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
default:
|
2022-12-01 07:29:41 +00:00
|
|
|
LOG_ECMA(FATAL) << "this branch is unreachable";
|
2022-04-11 02:41:49 +00:00
|
|
|
UNREACHABLE();
|
Add information such as instruction immediate, method_id, string_id, etc.
The lowering slow path requires not only the vreg information of the
instruction, but also other information such as string id, method id, etc.
For each bytecode instruction, collect the various information stored in
the instruction, and use the information as the input of the gate, and
in the lowering stage, take out the required information from the gate.
issue:https://gitee.com/openharmony/ark_js_runtime/issues/I4WQR5
Signed-off-by: wanyanglan <wanyanglan1@huawei.com>
Change-Id: I42ef36554b0b88ce3e1cd0f593e8ce9e924b83e0
2022-03-04 07:52:07 +00:00
|
|
|
}
|
|
|
|
return gate;
|
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex)
|
|
|
|
{
|
|
|
|
auto state = frameStateBuilder_.GetCurrentState();
|
|
|
|
auto depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
if (!bb.catches.empty()) {
|
|
|
|
auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
|
2024-03-11 07:35:55 +00:00
|
|
|
auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
|
2023-11-06 01:19:36 +00:00
|
|
|
auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
|
|
|
|
frameStateBuilder_.UpdateStateDepend(ifException, ifException);
|
|
|
|
ASSERT(bb.catches.size() == 1); // 1: one catch
|
|
|
|
auto bbNext = bb.catches.at(0);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
|
|
|
|
state = ifSuccess;
|
2024-03-11 07:35:55 +00:00
|
|
|
depend = dependRelay;
|
2023-11-06 01:19:36 +00:00
|
|
|
}
|
|
|
|
auto constant = circuit_->GetConstantGate(MachineType::I64,
|
|
|
|
JSTaggedValue::VALUE_EXCEPTION,
|
|
|
|
GateType::TaggedValue());
|
|
|
|
circuit_->NewGate(circuit_->Return(),
|
|
|
|
{ state, depend, constant, circuit_->GetReturnRoot() });
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::MergeExceptionGete(BytecodeRegion &bb,
|
|
|
|
const BytecodeInfo& bytecodeInfo, uint32_t bcIndex)
|
|
|
|
{
|
|
|
|
auto state = frameStateBuilder_.GetCurrentState();
|
|
|
|
auto depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
|
2024-03-11 07:35:55 +00:00
|
|
|
auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
|
2023-11-06 01:19:36 +00:00
|
|
|
ASSERT(bb.catches.size() == 1); // 1: one catch
|
|
|
|
auto bbNext = bb.catches.at(0);
|
|
|
|
auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
|
|
|
|
frameStateBuilder_.UpdateStateDepend(ifException, ifException);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, bcIndex + 1, true}); // 1: next pc
|
|
|
|
} else {
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
|
|
|
|
}
|
2024-03-11 07:35:55 +00:00
|
|
|
depend = dependRelay;
|
2023-11-06 01:19:36 +00:00
|
|
|
frameStateBuilder_.UpdateStateDepend(ifSuccess, depend);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb)
|
2022-01-18 04:02:20 +00:00
|
|
|
{
|
2022-10-27 03:56:58 +00:00
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
|
|
|
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
2022-11-02 07:10:09 +00:00
|
|
|
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
|
2022-04-24 17:17:29 +00:00
|
|
|
GateRef gate = 0;
|
2023-01-06 10:04:16 +00:00
|
|
|
bool writable = !bytecodeInfo.NoSideEffects();
|
2023-09-14 09:06:56 +00:00
|
|
|
bool hasFrameState = bytecodeInfo.HasFrameState();
|
2023-03-02 12:09:04 +00:00
|
|
|
size_t pcOffset = GetPcOffset(iterator.Index());
|
2023-12-22 05:41:23 +00:00
|
|
|
auto methodOffset = method_->GetMethodId().GetOffset();
|
|
|
|
auto meta = circuit_->JSBytecode(
|
|
|
|
numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), writable, hasFrameState);
|
2022-11-29 09:25:20 +00:00
|
|
|
std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
|
2022-10-07 23:56:43 +00:00
|
|
|
if (bytecodeInfo.IsDef()) {
|
2022-11-29 09:25:20 +00:00
|
|
|
gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
|
|
|
|
inList.data(), GateType::AnyType());
|
2022-04-24 17:17:29 +00:00
|
|
|
} else {
|
2022-11-29 09:25:20 +00:00
|
|
|
gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
|
|
|
|
inList.data(), GateType::Empty());
|
2022-04-14 08:14:34 +00:00
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
|
|
|
|
jsGatesToByteCode_[gate] = iterator.Index();
|
2023-04-27 12:26:51 +00:00
|
|
|
gateAcc_.NewIn(gate, 0, state);
|
|
|
|
gateAcc_.NewIn(gate, 1, depend);
|
2023-11-06 01:19:36 +00:00
|
|
|
frameStateBuilder_.UpdateStateDepend(gate, gate);
|
|
|
|
frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
|
2023-02-13 05:46:34 +00:00
|
|
|
if (bytecodeInfo.IsThrow()) {
|
2023-11-06 01:19:36 +00:00
|
|
|
MergeThrowGate(bb, iterator.Index());
|
2023-02-13 05:46:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-01-13 01:18:36 +00:00
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
|
|
|
|
MergeExceptionGete(bb, bytecodeInfo, iterator.Index());
|
2024-04-18 12:43:30 +00:00
|
|
|
} else if (!bb.catches.empty()) {
|
|
|
|
frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
|
2022-02-12 08:15:41 +00:00
|
|
|
}
|
2022-06-06 09:41:17 +00:00
|
|
|
if (bytecodeInfo.IsGeneratorRelative()) {
|
|
|
|
suspendAndResumeGates_.emplace_back(gate);
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2022-10-27 03:56:58 +00:00
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
|
|
|
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
2022-06-10 07:22:21 +00:00
|
|
|
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
|
2024-09-05 09:00:33 +00:00
|
|
|
if (bytecodeInfo.IsCondJump() && bb.succs.size() == 2) { // 2: two succ
|
2023-03-02 12:09:04 +00:00
|
|
|
size_t pcOffset = GetPcOffset(iterator.Index());
|
2023-12-22 05:41:23 +00:00
|
|
|
auto methodOffset = method_->GetMethodId().GetOffset();
|
|
|
|
auto meta = circuit_->JSBytecode(
|
|
|
|
numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), false, false);
|
2022-11-29 09:25:20 +00:00
|
|
|
auto numValues = meta->GetNumIns();
|
|
|
|
GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
|
2022-07-19 12:44:46 +00:00
|
|
|
gateAcc_.NewIn(gate, 0, state);
|
|
|
|
gateAcc_.NewIn(gate, 1, depend);
|
2023-11-06 01:19:36 +00:00
|
|
|
frameStateBuilder_.UpdateStateDepend(gate, gate);
|
|
|
|
frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
|
|
|
|
|
2022-11-29 09:25:20 +00:00
|
|
|
auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
|
|
|
|
auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
|
|
|
|
auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
|
|
|
|
auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
|
2023-11-06 01:19:36 +00:00
|
|
|
for (auto &bbNext: bb.succs) {
|
2023-11-22 01:15:28 +00:00
|
|
|
if (iterator.Index() + 1 == bbNext->start) {
|
2023-11-06 01:19:36 +00:00
|
|
|
frameStateBuilder_.UpdateStateDepend(ifFalse, falseRelay);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
|
|
|
} else {
|
|
|
|
frameStateBuilder_.UpdateStateDepend(ifTrue, trueRelay);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
|
|
|
|
jsGatesToByteCode_[gate] = iterator.Index();
|
2022-04-24 17:17:29 +00:00
|
|
|
} else {
|
2024-08-29 12:02:20 +00:00
|
|
|
ASSERT(bb.succs.size() == 1); // 1: only one succ if not condjump
|
2022-04-24 17:17:29 +00:00
|
|
|
auto &bbNext = bb.succs.at(0);
|
2023-11-06 01:19:36 +00:00
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
2022-10-27 03:56:58 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2024-04-18 12:43:30 +00:00
|
|
|
|
|
|
|
if (!bb.catches.empty()) {
|
|
|
|
frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2022-01-19 01:11:02 +00:00
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
|
|
|
ASSERT(bb.succs.empty());
|
2022-10-27 03:56:58 +00:00
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
|
|
|
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
GateRef gate = Circuit::NullGate();
|
2022-10-27 03:56:58 +00:00
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
|
2022-09-06 05:27:19 +00:00
|
|
|
// handle return.dyn bytecode
|
2023-11-06 01:19:36 +00:00
|
|
|
gate = circuit_->NewGate(circuit_->Return(),
|
2023-04-27 12:26:51 +00:00
|
|
|
{ state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
|
|
|
|
jsGatesToByteCode_[gate] = iterator.Index();
|
2022-10-27 03:56:58 +00:00
|
|
|
} else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
|
2022-04-24 17:17:29 +00:00
|
|
|
// handle returnundefined bytecode
|
2022-11-09 02:05:55 +00:00
|
|
|
auto constant = circuit_->GetConstantGate(MachineType::I64,
|
2022-11-23 08:58:08 +00:00
|
|
|
JSTaggedValue::VALUE_UNDEFINED,
|
|
|
|
GateType::TaggedValue());
|
2023-11-06 01:19:36 +00:00
|
|
|
gate = circuit_->NewGate(circuit_->Return(),
|
2023-04-27 12:26:51 +00:00
|
|
|
{ state, depend, constant, circuit_->GetReturnRoot() });
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
|
|
|
|
jsGatesToByteCode_[gate] = iterator.Index();
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
return gate;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2022-10-27 03:56:58 +00:00
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
|
|
|
const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
|
2023-11-01 09:18:44 +00:00
|
|
|
FrameLiveOut* liveout;
|
|
|
|
auto bcId = iterator.Index();
|
2024-08-04 09:15:12 +00:00
|
|
|
if (bcId != 0 && iterator.IsInRange(bcId - 1)) {
|
2023-11-01 09:18:44 +00:00
|
|
|
liveout = frameStateBuilder_.GetOrOCreateBCEndLiveOut(bcId - 1);
|
|
|
|
} else {
|
|
|
|
liveout = frameStateBuilder_.GetOrOCreateBBLiveOut(bb.id);
|
|
|
|
}
|
|
|
|
frameStateBuilder_.AdvanceToNextBc(bytecodeInfo, liveout, bcId);
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef gate = Circuit::NullGate();
|
2022-02-17 03:48:40 +00:00
|
|
|
if (bytecodeInfo.IsSetConstant()) {
|
2022-04-24 17:17:29 +00:00
|
|
|
// handle bytecode command to get constants
|
2023-11-06 01:19:36 +00:00
|
|
|
gate = NewConst(bytecodeInfo);
|
2023-04-28 08:37:17 +00:00
|
|
|
byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
|
|
|
|
jsGatesToByteCode_[gate] = iterator.Index();
|
2022-02-17 03:48:40 +00:00
|
|
|
} else if (bytecodeInfo.IsGeneral()) {
|
2022-04-24 17:17:29 +00:00
|
|
|
// handle general ecma.* bytecodes
|
2023-11-06 01:19:36 +00:00
|
|
|
NewJSGate(bb);
|
2022-02-17 03:48:40 +00:00
|
|
|
} else if (bytecodeInfo.IsJump()) {
|
2022-04-24 17:17:29 +00:00
|
|
|
// handle conditional jump and unconditional jump bytecodes
|
2023-11-06 01:19:36 +00:00
|
|
|
NewJump(bb);
|
2022-02-17 03:48:40 +00:00
|
|
|
} else if (bytecodeInfo.IsReturn()) {
|
2022-09-06 05:27:19 +00:00
|
|
|
// handle return.dyn and returnundefined bytecodes
|
2023-11-06 01:19:36 +00:00
|
|
|
gate = NewReturn(bb);
|
|
|
|
} else if (bytecodeInfo.IsMov()) {
|
2024-04-08 06:55:33 +00:00
|
|
|
frameStateBuilder_.UpdateMoveValues(bytecodeInfo);
|
2023-11-06 01:19:36 +00:00
|
|
|
} else if (!bytecodeInfo.IsDiscarded()) {
|
2022-12-01 07:29:41 +00:00
|
|
|
LOG_ECMA(FATAL) << "this branch is unreachable";
|
2022-04-24 17:17:29 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
2023-11-06 01:19:36 +00:00
|
|
|
if (gate != Circuit::NullGate()) {
|
|
|
|
frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildSubCircuit()
|
|
|
|
{
|
2023-11-06 01:19:36 +00:00
|
|
|
auto &entryBlock = RegionAt(0);
|
|
|
|
frameStateBuilder_.InitEntryBB(entryBlock);
|
|
|
|
auto& rpoList = frameStateBuilder_.GetRpoList();
|
|
|
|
for (auto &bbId: rpoList) {
|
|
|
|
auto &bb = RegionAt(bbId);
|
|
|
|
frameStateBuilder_.AdvanceToNextBB(bb);
|
2023-04-23 09:21:01 +00:00
|
|
|
if (IsEntryBlock(bb.id)) {
|
2023-08-07 08:24:38 +00:00
|
|
|
if (NeedCheckSafePointAndStackOver()) {
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
|
|
|
|
bb.dependCache = stackCheck;
|
|
|
|
frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
|
|
|
|
}
|
|
|
|
auto &bbNext = RegionAt(bb.id + 1);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
|
2023-04-23 09:21:01 +00:00
|
|
|
bbNext.expandedPreds.push_back({bb.id, bb.end, false});
|
|
|
|
continue;
|
|
|
|
}
|
2022-02-10 02:03:48 +00:00
|
|
|
if (!bb.trys.empty()) {
|
2023-11-06 01:19:36 +00:00
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
auto getException = circuit_->NewGate(circuit_->GetException(),
|
|
|
|
MachineType::I64, {state, depend}, GateType::AnyType());
|
|
|
|
frameStateBuilder_.UpdateAccumulator(getException);
|
2024-08-29 12:02:20 +00:00
|
|
|
frameStateBuilder_.UpdateStateDepend(state, getException);
|
2023-11-06 01:19:36 +00:00
|
|
|
}
|
|
|
|
EnumerateBlock(bb, [this, &bb]
|
2022-10-27 03:56:58 +00:00
|
|
|
(const BytecodeInfo &bytecodeInfo) -> bool {
|
2023-11-06 01:19:36 +00:00
|
|
|
NewByteCode(bb);
|
2022-02-17 03:48:40 +00:00
|
|
|
if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
|
2022-06-30 02:22:52 +00:00
|
|
|
return false;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
return true;
|
|
|
|
});
|
2023-11-06 01:19:36 +00:00
|
|
|
bool needFallThrough = true;
|
|
|
|
if (!bb.IsEmptryBlock()) {
|
|
|
|
const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
|
|
|
|
needFallThrough = bytecodeInfo.needFallThrough();
|
|
|
|
}
|
|
|
|
// fallThrough or empty merge bb
|
|
|
|
if (needFallThrough) {
|
|
|
|
ASSERT(bb.succs.size() == 1); // 1: fall through
|
|
|
|
auto &bbNext = RegionAt(bb.succs[0]->id);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
|
2023-04-03 08:33:32 +00:00
|
|
|
bbNext.expandedPreds.push_back({bb.id, bb.end, false});
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-19 06:57:29 +00:00
|
|
|
bool BytecodeCircuitBuilder::FindOsrLoopHeadBB()
|
|
|
|
{
|
|
|
|
int32_t loopBackBcIndex {-1};
|
|
|
|
for (size_t k = 0; k < pcOffsets_.size(); k++) {
|
|
|
|
if (static_cast<int32_t>(pcOffsets_[k] - pcOffsets_[0]) == osrOffset_) {
|
2024-05-31 07:07:53 +00:00
|
|
|
loopBackBcIndex = static_cast<int32_t>(k);
|
2024-03-19 06:57:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (loopBackBcIndex == -1) {
|
|
|
|
LOG_COMPILER(ERROR) << "Unable to find the loop back of OSR.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto &rpoList = frameStateBuilder_.GetRpoList();
|
|
|
|
for (auto &bbId : rpoList) {
|
|
|
|
auto &bb = RegionAt(bbId);
|
|
|
|
if (bb.end == static_cast<uint32_t>(loopBackBcIndex)) {
|
|
|
|
frameStateBuilder_.SetOsrLoopHeadBB(bb);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LOG_COMPILER(ERROR) << "Unable to find the loop head bb of OSR.";
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::GenDeoptAndReturnForOsrLoopExit(BytecodeRegion &osrLoopExitBB)
|
|
|
|
{
|
|
|
|
frameStateBuilder_.AdvanceToNextBB(osrLoopExitBB, true);
|
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
std::string comment = Deoptimizier::DisplayItems(DeoptType::OSRLOOPEXIT);
|
|
|
|
GateRef type =
|
|
|
|
circuit_->GetConstantGate(MachineType::I64, static_cast<int64_t>(DeoptType::OSRLOOPEXIT), GateType::NJSValue());
|
|
|
|
GateRef condition = circuit_->GetConstantGate(MachineType::I1, 0, GateType::NJSValue());
|
|
|
|
GateRef deopt = circuit_->NewGate(circuit_->DeoptCheck(), MachineType::I1,
|
|
|
|
{state, depend, condition, gateAcc_.GetFrameState(depend), type},
|
|
|
|
GateType::NJSValue(), comment.c_str());
|
|
|
|
GateRef dependRelay = circuit_->NewGate(circuit_->DependRelay(), {deopt, depend});
|
|
|
|
GateRef undef =
|
|
|
|
circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::TaggedValue());
|
|
|
|
circuit_->NewGate(circuit_->Return(), {state, dependRelay, undef, circuit_->GetReturnRoot()});
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::CollectCacheBBforOSRLoop(BytecodeRegion *bb)
|
|
|
|
{
|
|
|
|
catchBBOfOSRLoop_.insert(bb);
|
|
|
|
for (BytecodeRegion *succBB : bb->succs) {
|
|
|
|
CollectCacheBBforOSRLoop(succBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB)
|
|
|
|
{
|
|
|
|
if (!osrLoopBodyBB.trys.empty()) {
|
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
auto getException =
|
|
|
|
circuit_->NewGate(circuit_->GetException(), MachineType::I64, {state, depend}, GateType::AnyType());
|
|
|
|
frameStateBuilder_.UpdateAccumulator(getException);
|
|
|
|
frameStateBuilder_.UpdateStateDepend(state, getException);
|
|
|
|
}
|
|
|
|
// collect catch BB.
|
|
|
|
if (!osrLoopBodyBB.catches.empty()) {
|
|
|
|
for (BytecodeRegion *targetBB : osrLoopBodyBB.catches) {
|
|
|
|
CollectCacheBBforOSRLoop(targetBB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EnumerateBlock(osrLoopBodyBB, [this, &osrLoopBodyBB](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
NewByteCode(osrLoopBodyBB);
|
|
|
|
if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
bool needFallThrough = true;
|
|
|
|
if (!osrLoopBodyBB.IsEmptryBlock()) {
|
|
|
|
const BytecodeInfo &bytecodeInfo = GetBytecodeInfo(osrLoopBodyBB.end);
|
|
|
|
needFallThrough = bytecodeInfo.needFallThrough();
|
|
|
|
}
|
|
|
|
// fallThrough or empty merge osrLoopBodyBB
|
|
|
|
if (needFallThrough) {
|
|
|
|
ASSERT(osrLoopBodyBB.succs.size() == 1); // 1: fall through
|
|
|
|
auto &bbNext = RegionAt(osrLoopBodyBB.succs[0]->id);
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(osrLoopBodyBB, bbNext);
|
|
|
|
bbNext.expandedPreds.push_back({osrLoopBodyBB.id, osrLoopBodyBB.end, false});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildOsrCircuit()
|
|
|
|
{
|
|
|
|
if (!FindOsrLoopHeadBB()) {
|
|
|
|
LOG_COMPILER(FATAL) << "invalid osr offset";
|
|
|
|
}
|
|
|
|
circuit_->SetIsOsr();
|
|
|
|
auto &entryBlock = RegionAt(0);
|
|
|
|
frameStateBuilder_.InitEntryBB(entryBlock);
|
|
|
|
std::set<size_t> osrLoopExitBBIds;
|
|
|
|
auto &rpoList = frameStateBuilder_.GetRpoList();
|
|
|
|
for (auto &bbId : rpoList) {
|
|
|
|
auto &bb = RegionAt(bbId);
|
|
|
|
if (frameStateBuilder_.IsOsrLoopExit(bb)) {
|
|
|
|
// The loop exit BB is in front of the loop head BB. At this time,
|
|
|
|
// the loop exit BB does not have the context object, and the processing of the loop exit BB is delayed.
|
|
|
|
if (frameStateBuilder_.IsContextExists(bb.id)) {
|
|
|
|
GenDeoptAndReturnForOsrLoopExit(bb);
|
|
|
|
} else {
|
|
|
|
osrLoopExitBBIds.insert(bbId);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Processes only the BBs related to the loop specified by the OSR.
|
|
|
|
if (!IsEntryBlock(bb.id) && frameStateBuilder_.OutOfOsrLoop(bb) && !IsCacheBBOfOSRLoop(bb)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
frameStateBuilder_.AdvanceToNextBB(bb);
|
|
|
|
if (IsEntryBlock(bb.id)) {
|
|
|
|
if (NeedCheckSafePointAndStackOver()) {
|
|
|
|
GateRef state = frameStateBuilder_.GetCurrentState();
|
|
|
|
GateRef depend = frameStateBuilder_.GetCurrentDepend();
|
|
|
|
auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
|
|
|
|
bb.dependCache = stackCheck;
|
|
|
|
frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
|
|
|
|
}
|
|
|
|
auto *bbNext = &RegionAt(bb.id + 1);
|
|
|
|
while (!IsEntryBlock(bbNext->id) && frameStateBuilder_.OutOfOsrLoop(*bbNext)) {
|
|
|
|
bbNext = &RegionAt(bbNext->id + 1);
|
|
|
|
}
|
|
|
|
frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
|
|
|
|
bbNext->expandedPreds.push_back({bb.id, bb.end, false});
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
HandleOsrLoopBody(bb);
|
|
|
|
}
|
|
|
|
for (size_t bbId : osrLoopExitBBIds) {
|
|
|
|
auto &bb = RegionAt(bbId);
|
|
|
|
GenDeoptAndReturnForOsrLoopExit(bb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildCircuit()
|
|
|
|
{
|
2024-03-19 06:57:29 +00:00
|
|
|
if (IsOSR()) {
|
|
|
|
// create osr arg gates array
|
|
|
|
BuildOSRArgs();
|
|
|
|
frameStateBuilder_.DoBytecodeAnalysis();
|
2024-08-31 06:53:09 +00:00
|
|
|
if (TerminateAnalysis()) {
|
|
|
|
return;
|
|
|
|
}
|
2024-03-19 06:57:29 +00:00
|
|
|
// build states sub-circuit of osr block
|
|
|
|
BuildOsrCircuit();
|
|
|
|
} else {
|
|
|
|
// create arg gates array
|
|
|
|
BuildCircuitArgs();
|
|
|
|
frameStateBuilder_.DoBytecodeAnalysis();
|
2024-08-31 06:53:09 +00:00
|
|
|
if (TerminateAnalysis()) {
|
|
|
|
return;
|
|
|
|
}
|
2024-03-19 06:57:29 +00:00
|
|
|
// build states sub-circuit of each block
|
|
|
|
BuildSubCircuit();
|
|
|
|
}
|
2022-04-14 08:14:34 +00:00
|
|
|
if (IsLogEnabled()) {
|
2024-05-07 12:48:37 +00:00
|
|
|
PrintGraph(std::string("Bytecode2Gate [" + methodName_ + "]").c_str());
|
2022-10-09 07:53:21 +00:00
|
|
|
LOG_COMPILER(INFO) << "\033[34m" << "============= "
|
|
|
|
<< "After bytecode2circuit lowering ["
|
|
|
|
<< methodName_ << "]"
|
|
|
|
<< " =============" << "\033[0m";
|
2022-11-09 02:05:55 +00:00
|
|
|
circuit_->PrintAllGatesWithBytecode();
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
|
2022-04-14 08:14:34 +00:00
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
void BytecodeCircuitBuilder::PrintGraph(const char* title)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << "======================== " << title << " ========================";
|
2022-04-24 17:17:29 +00:00
|
|
|
for (size_t i = 0; i < graph_.size(); i++) {
|
2023-11-06 01:19:36 +00:00
|
|
|
BytecodeRegion& bb = RegionAt(i);
|
|
|
|
if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << "B" << bb.id << ": ;preds= invalid BB";
|
2022-11-02 01:32:55 +00:00
|
|
|
LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
|
|
|
|
<< std::to_string(bb.end) << ")";
|
2022-01-06 02:26:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log("B" + std::to_string(bb.id) + ": ;preds= ");
|
|
|
|
for (size_t k = 0; k < bb.preds.size(); ++k) {
|
|
|
|
log += std::to_string(bb.preds[k]->id) + ", ";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-07-06 06:12:54 +00:00
|
|
|
LOG_COMPILER(INFO) << log;
|
2023-04-23 09:21:01 +00:00
|
|
|
if (IsEntryBlock(bb.id)) {
|
|
|
|
LOG_COMPILER(INFO) << "\tBytecodePC: Empty";
|
|
|
|
} else {
|
|
|
|
LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
|
|
|
|
<< std::to_string(bb.end) << ")";
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log1("\tSucces: ");
|
|
|
|
for (size_t j = 0; j < bb.succs.size(); j++) {
|
|
|
|
log1 += std::to_string(bb.succs[j]->id) + ", ";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << log1;
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2023-11-06 01:19:36 +00:00
|
|
|
for (size_t j = 0; j < bb.catches.size(); j++) {
|
|
|
|
LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catches[j]->start) << ", "
|
|
|
|
<< std::to_string(bb.catches[j]->end) << ")";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log2("\tTrys: ");
|
|
|
|
for (auto tryBlock: bb.trys) {
|
|
|
|
log2 += std::to_string(tryBlock->id) + " , ";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << log2;
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
PrintBytecodeInfo(bb);
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << "";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2023-04-23 09:21:01 +00:00
|
|
|
if (IsEntryBlock(bb.id)) {
|
|
|
|
LOG_COMPILER(INFO) << "\tBytecode[] = Empty";
|
|
|
|
return;
|
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << "\tBytecode[] = ";
|
2022-10-27 03:56:58 +00:00
|
|
|
EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
|
2022-10-27 09:12:44 +00:00
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log;
|
2022-10-27 09:12:44 +00:00
|
|
|
log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
|
2022-11-02 01:32:55 +00:00
|
|
|
log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
|
2022-10-27 03:56:58 +00:00
|
|
|
if (bytecodeInfo.AccIn()) {
|
2022-10-03 04:31:39 +00:00
|
|
|
log += "acc,";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
for (const auto &in: bytecodeInfo.inputs) {
|
|
|
|
if (std::holds_alternative<VirtualRegister>(in)) {
|
|
|
|
log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
log += "], Out=[";
|
2022-10-27 03:56:58 +00:00
|
|
|
if (bytecodeInfo.AccOut()) {
|
2022-10-03 04:31:39 +00:00
|
|
|
log += "acc,";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
for (const auto &out: bytecodeInfo.vregOut) {
|
2022-11-29 03:14:12 +00:00
|
|
|
log += std::to_string(out) + ",";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
log += "] >";
|
|
|
|
LOG_COMPILER(INFO) << log;
|
2022-07-15 02:35:25 +00:00
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
auto gate = GetGateByBcIndex(iterator.Index());
|
2022-11-02 01:32:55 +00:00
|
|
|
if (gate != Circuit::NullGate()) {
|
|
|
|
this->gateAcc_.ShortPrint(gate);
|
2022-07-15 02:35:25 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
return true;
|
|
|
|
});
|
2022-07-15 02:35:25 +00:00
|
|
|
}
|
2022-04-22 03:03:38 +00:00
|
|
|
} // namespace panda::ecmascript::kungfu
|