2022-01-06 02:26:19 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021 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.
|
|
|
|
*/
|
|
|
|
|
2022-06-16 09:27:35 +00:00
|
|
|
#include "ecmascript/compiler/bytecode_circuit_builder.h"
|
|
|
|
|
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"
|
2022-07-21 17:37:55 +00:00
|
|
|
#include "ecmascript/ts_types/ts_manager.h"
|
2022-09-20 15:17:00 +00:00
|
|
|
#include "libpandafile/bytecode_instruction-inl.h"
|
2022-08-26 01:06:59 +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();
|
|
|
|
uint32_t end = size - 1; // 1: end
|
|
|
|
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
|
2022-11-02 01:32:55 +00:00
|
|
|
for (iterator.GotoStart(); !iterator.Done(); ++iterator) {
|
|
|
|
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);
|
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
|
2022-11-02 01:32:55 +00:00
|
|
|
byteCodeException.back().catchs.emplace_back(catchBlockPc);
|
2022-01-06 02:26:19 +00:00
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-04-23 09:21:01 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildEntryBlock()
|
|
|
|
{
|
|
|
|
BytecodeRegion &entryBlock = graph_[0];
|
|
|
|
BytecodeRegion &nextBlock = graph_[1];
|
|
|
|
entryBlock.succs.emplace_back(&nextBlock);
|
|
|
|
nextBlock.preds.emplace_back(&entryBlock);
|
|
|
|
entryBlock.bytecodeIterator_.Reset(this, INVALID_INDEX, INVALID_INDEX);
|
|
|
|
}
|
|
|
|
|
2022-11-02 07:10:09 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-11-02 07:10:09 +00:00
|
|
|
auto &items = regionsInfo_.GetBlockItems();
|
2022-11-02 01:32:55 +00:00
|
|
|
auto blockSize = items.size();
|
2023-04-23 09:21:01 +00:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
|
|
|
// build entry block
|
|
|
|
BuildEntryBlock();
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
// build basic block
|
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) {
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &prevBlock = graph_[blockId - 1];
|
|
|
|
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
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &lastBlock = graph_[blockId - 1]; // 1: last block
|
|
|
|
lastBlock.end = GetLastBcIndex();
|
|
|
|
lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
|
|
|
|
|
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
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
if (IsLogEnabled()) {
|
|
|
|
PrintGraph("Build Basic Block");
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-11-02 01:32:55 +00:00
|
|
|
ComputeDominatorTree();
|
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++) {
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &bb = graph_[i];
|
|
|
|
auto startIndex = bb.start;
|
|
|
|
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
|
|
|
|
const auto &catchs = it->catchs; // catchs start pc
|
2022-04-24 17:17:29 +00:00
|
|
|
for (size_t j = i + 1; j < graph_.size(); j++) {
|
2022-11-02 01:32:55 +00:00
|
|
|
auto &catchBB = graph_[j];
|
|
|
|
const auto catchStart = pcOffsets_[catchBB.start];
|
|
|
|
if (std::find(catchs.cbegin(), catchs.cend(), catchStart) != catchs.cend()) {
|
|
|
|
bb.catchs.insert(bb.catchs.cbegin(), &catchBB);
|
|
|
|
bb.succs.emplace_back(&catchBB);
|
|
|
|
catchBB.preds.emplace_back(&bb);
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::ComputeDominatorTree()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
|
|
|
// Construct graph backward order
|
2022-11-02 01:32:55 +00:00
|
|
|
std::unordered_map<size_t, size_t> bbIdToDfsTimestamp;
|
2022-08-01 09:13:57 +00:00
|
|
|
std::unordered_map<size_t, size_t> dfsFatherIdx;
|
|
|
|
std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
|
2022-10-15 04:09:38 +00:00
|
|
|
std::vector<size_t> basicBlockList;
|
2022-01-06 02:26:19 +00:00
|
|
|
size_t timestamp = 0;
|
|
|
|
std::deque<size_t> pendingList;
|
2022-04-24 17:17:29 +00:00
|
|
|
std::vector<size_t> visited(graph_.size(), 0);
|
|
|
|
auto basicBlockId = graph_[0].id;
|
2022-08-01 09:13:57 +00:00
|
|
|
visited[graph_[0].id] = 1;
|
2022-10-27 09:12:44 +00:00
|
|
|
pendingList.emplace_back(basicBlockId);
|
2022-01-06 02:26:19 +00:00
|
|
|
while (!pendingList.empty()) {
|
2022-08-01 09:13:57 +00:00
|
|
|
size_t curBlockId = pendingList.back();
|
2022-01-06 02:26:19 +00:00
|
|
|
pendingList.pop_back();
|
2022-10-27 09:12:44 +00:00
|
|
|
basicBlockList.emplace_back(curBlockId);
|
2022-10-15 04:09:38 +00:00
|
|
|
bbIdToDfsTimestamp[curBlockId] = timestamp++;
|
2022-08-01 09:13:57 +00:00
|
|
|
for (const auto &succBlock: graph_[curBlockId].succs) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (visited[succBlock->id] == 0) {
|
|
|
|
visited[succBlock->id] = 1;
|
2022-10-27 09:12:44 +00:00
|
|
|
pendingList.emplace_back(succBlock->id);
|
2022-10-15 04:09:38 +00:00
|
|
|
dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp[curBlockId];
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-08-26 01:06:59 +00:00
|
|
|
|
2022-10-15 04:09:38 +00:00
|
|
|
for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
|
|
|
|
bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
|
2022-08-01 09:13:57 +00:00
|
|
|
}
|
2022-10-15 04:09:38 +00:00
|
|
|
RemoveDeadRegions(bbIdToDfsTimestamp);
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2022-10-15 04:09:38 +00:00
|
|
|
std::vector<size_t> immDom(basicBlockList.size()); // immediate dominator with dfs order index
|
|
|
|
std::vector<size_t> semiDom(basicBlockList.size());
|
2022-08-01 09:13:57 +00:00
|
|
|
std::vector<size_t> realImmDom(graph_.size()); // immediate dominator with real index
|
2022-10-15 04:09:38 +00:00
|
|
|
std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
|
2022-08-01 09:13:57 +00:00
|
|
|
{
|
2022-10-15 04:09:38 +00:00
|
|
|
std::vector<size_t> parent(basicBlockList.size());
|
2022-08-01 09:13:57 +00:00
|
|
|
std::iota(parent.begin(), parent.end(), 0);
|
2022-10-15 04:09:38 +00:00
|
|
|
std::vector<size_t> minIdx(basicBlockList.size());
|
2022-08-01 09:13:57 +00:00
|
|
|
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]];
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-08-01 09:13:57 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
std::iota(semiDom.begin(), semiDom.end(), 0);
|
|
|
|
semiDom[0] = semiDom.size();
|
2022-10-15 04:09:38 +00:00
|
|
|
for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
|
|
|
|
for (const auto &preBlock : graph_[basicBlockList[idx]].preds) {
|
2022-08-01 09:13:57 +00:00
|
|
|
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]]]);
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-08-01 09:13:57 +00:00
|
|
|
for (const auto & succDomIdx : semiDomTree[idx]) {
|
|
|
|
unionFind(succDomIdx);
|
|
|
|
if (idx == semiDom[minIdx[succDomIdx]]) {
|
|
|
|
immDom[succDomIdx] = idx;
|
|
|
|
} else {
|
|
|
|
immDom[succDomIdx] = minIdx[succDomIdx];
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-08-01 09:13:57 +00:00
|
|
|
minIdx[idx] = idx;
|
2022-10-15 04:09:38 +00:00
|
|
|
merge(dfsFatherIdx[basicBlockList[idx]], idx);
|
2022-10-27 09:12:44 +00:00
|
|
|
semiDomTree[semiDom[idx]].emplace_back(idx);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-15 04:09:38 +00:00
|
|
|
for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
|
2022-08-01 09:13:57 +00:00
|
|
|
if (immDom[idx] != semiDom[idx]) {
|
|
|
|
immDom[idx] = immDom[immDom[idx]];
|
2022-04-14 08:14:34 +00:00
|
|
|
}
|
2022-10-15 04:09:38 +00:00
|
|
|
realImmDom[basicBlockList[idx]] = basicBlockList[immDom[idx]];
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-08-01 09:13:57 +00:00
|
|
|
semiDom[0] = 0;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-04-14 08:14:34 +00:00
|
|
|
if (IsLogEnabled()) {
|
2022-10-03 04:31:39 +00:00
|
|
|
PrintGraph("Computed Dom Trees");
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-04-14 08:14:34 +00:00
|
|
|
|
2022-08-01 09:13:57 +00:00
|
|
|
BuildImmediateDominator(realImmDom);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-09-29 06:18:49 +00:00
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &immDom)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-04-24 17:17:29 +00:00
|
|
|
graph_[0].iDominator = &graph_[0];
|
2022-01-18 04:02:20 +00:00
|
|
|
for (size_t i = 1; i < immDom.size(); i++) {
|
2022-04-24 17:17:29 +00:00
|
|
|
auto dominatedBlock = &graph_[i];
|
2022-01-06 02:26:19 +00:00
|
|
|
if (dominatedBlock->isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
auto immDomBlock = &graph_[immDom[i]];
|
2022-01-06 02:26:19 +00:00
|
|
|
dominatedBlock->iDominator = immDomBlock;
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &block : graph_) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (block.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (block.iDominator->id != block.id) {
|
|
|
|
block.iDominator->immDomBlocks.emplace_back(&block);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
ComputeDomFrontiers(immDom);
|
|
|
|
InsertPhi();
|
|
|
|
UpdateCFG();
|
|
|
|
BuildCircuit();
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::ComputeDomFrontiers(const std::vector<size_t> &immDom)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-01-22 11:09:02 +00:00
|
|
|
std::vector<std::set<BytecodeRegion *>> domFrontiers(immDom.size());
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb : graph_) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-01-22 11:09:02 +00:00
|
|
|
if (bb.preds.size() < 2) { // 2: pred num
|
2022-01-06 02:26:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < bb.preds.size(); i++) {
|
|
|
|
auto runner = bb.preds[i];
|
2022-01-18 04:02:20 +00:00
|
|
|
while (runner->id != immDom[bb.id]) {
|
2022-01-06 02:26:19 +00:00
|
|
|
domFrontiers[runner->id].insert(&bb);
|
2022-04-24 17:17:29 +00:00
|
|
|
runner = &graph_[immDom[runner->id]];
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < domFrontiers.size(); i++) {
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto iter = domFrontiers[i].cbegin(); iter != domFrontiers[i].cend(); iter++) {
|
|
|
|
graph_[i].domFrontiers.emplace_back(*iter);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
void BytecodeCircuitBuilder::RemoveDeadRegions(const std::unordered_map<size_t, size_t> &bbIdToDfsTimestamp)
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &block: graph_) {
|
2022-01-22 11:09:02 +00:00
|
|
|
std::vector<BytecodeRegion *> newPreds;
|
2022-01-19 01:11:02 +00:00
|
|
|
for (auto &bb : block.preds) {
|
2022-10-15 04:09:38 +00:00
|
|
|
if (bbIdToDfsTimestamp.count(bb->id)) {
|
2022-01-06 02:26:19 +00:00
|
|
|
newPreds.emplace_back(bb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
block.preds = newPreds;
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &block : graph_) {
|
2022-10-15 04:09:38 +00:00
|
|
|
block.isDead = !bbIdToDfsTimestamp.count(block.id);
|
2022-01-06 02:26:19 +00:00
|
|
|
if (block.isDead) {
|
|
|
|
block.succs.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::InsertPhi()
|
2022-01-06 02:26:19 +00:00
|
|
|
{
|
2022-11-02 01:32:55 +00:00
|
|
|
std::unordered_map<uint16_t, std::set<size_t>> defsitesInfo; // <vreg, bbs>
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb : graph_) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
EnumerateBlock(bb, [this, &defsitesInfo, &bb]
|
2022-10-27 03:56:58 +00:00
|
|
|
(const BytecodeInfo &bytecodeInfo) -> bool {
|
2022-09-29 06:18:49 +00:00
|
|
|
if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
|
2023-02-22 03:11:36 +00:00
|
|
|
auto numVRegs = GetNumberVRegsWithEnv();
|
2022-06-06 09:41:17 +00:00
|
|
|
for (size_t i = 0; i < numVRegs; i++) {
|
2022-10-27 03:56:58 +00:00
|
|
|
defsitesInfo[i].insert(bb.id);
|
2022-06-06 09:41:17 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-18 04:02:20 +00:00
|
|
|
for (const auto &vreg: bytecodeInfo.vregOut) {
|
2022-01-06 02:26:19 +00:00
|
|
|
defsitesInfo[vreg].insert(bb.id);
|
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
return true;
|
|
|
|
});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 02:35:25 +00:00
|
|
|
// handle phi generated from multiple control flow in the same source block
|
|
|
|
InsertExceptionPhi(defsitesInfo);
|
|
|
|
|
2022-01-19 01:11:02 +00:00
|
|
|
for (const auto&[variable, defsites] : defsitesInfo) {
|
2022-01-06 02:26:19 +00:00
|
|
|
std::queue<uint16_t> workList;
|
2022-01-18 04:02:20 +00:00
|
|
|
for (auto blockId: defsites) {
|
2022-01-06 02:26:19 +00:00
|
|
|
workList.push(blockId);
|
|
|
|
}
|
|
|
|
while (!workList.empty()) {
|
|
|
|
auto currentId = workList.front();
|
|
|
|
workList.pop();
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &block : graph_[currentId].domFrontiers) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (!block->phi.count(variable)) {
|
|
|
|
block->phi.insert(variable);
|
|
|
|
if (!defsitesInfo[variable].count(block->id)) {
|
|
|
|
workList.push(block->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-04-14 08:14:34 +00:00
|
|
|
|
|
|
|
if (IsLogEnabled()) {
|
2022-10-03 04:31:39 +00:00
|
|
|
PrintGraph("Inserted Phis");
|
2022-04-14 08:14:34 +00:00
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 01:32:55 +00:00
|
|
|
void BytecodeCircuitBuilder::InsertExceptionPhi(std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo)
|
2022-07-15 02:35:25 +00:00
|
|
|
{
|
|
|
|
// handle try catch defsite
|
|
|
|
for (auto &bb : graph_) {
|
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (bb.catchs.size() == 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::set<size_t> vregs;
|
2022-08-05 09:00:14 +00:00
|
|
|
EnumerateBlock(bb, [this, &vregs]
|
2022-10-27 03:56:58 +00:00
|
|
|
(const BytecodeInfo &bytecodeInfo) -> bool {
|
2022-09-29 06:18:49 +00:00
|
|
|
if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
|
2023-02-22 03:11:36 +00:00
|
|
|
auto numVRegs = GetNumberVRegsWithEnv();
|
2022-08-05 09:00:14 +00:00
|
|
|
for (size_t i = 0; i < numVRegs; i++) {
|
|
|
|
vregs.insert(i);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2022-07-15 02:35:25 +00:00
|
|
|
for (const auto &vreg: bytecodeInfo.vregOut) {
|
|
|
|
vregs.insert(vreg);
|
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
return true;
|
|
|
|
});
|
2022-07-15 02:35:25 +00:00
|
|
|
|
|
|
|
for (auto &vreg : vregs) {
|
|
|
|
defsitesInfo[vreg].insert(bb.catchs.at(0)->id);
|
|
|
|
bb.catchs.at(0)->phi.insert(vreg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb: graph_) {
|
2022-01-19 01:11:02 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bb.preds.clear();
|
|
|
|
bb.trys.clear();
|
2022-01-22 11:09:02 +00:00
|
|
|
std::vector<BytecodeRegion *> newSuccs;
|
2022-01-19 01:11:02 +00:00
|
|
|
for (const auto &succ: bb.succs) {
|
2022-04-24 17:17:29 +00:00
|
|
|
if (std::count(bb.catchs.cbegin(), bb.catchs.cend(), succ)) {
|
2022-01-19 01:11:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
2022-10-27 09:12:44 +00:00
|
|
|
newSuccs.emplace_back(succ);
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
|
|
|
bb.succs = newSuccs;
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb: graph_) {
|
2022-01-19 01:11:02 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (auto &succ: bb.succs) {
|
2022-10-27 09:12:44 +00:00
|
|
|
succ->preds.emplace_back(&bb);
|
2022-01-19 01:11:02 +00:00
|
|
|
}
|
|
|
|
for (auto &catchBlock: bb.catchs) {
|
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());
|
|
|
|
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();
|
2022-10-22 07:59:53 +00:00
|
|
|
if (HasTypes()) {
|
2022-07-05 07:24:00 +00:00
|
|
|
argAcc_.FillArgsGateType(&typeRecorder_);
|
|
|
|
}
|
2023-03-27 09:23:59 +00:00
|
|
|
|
|
|
|
BuildFrameArgs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildFrameArgs()
|
|
|
|
{
|
2023-05-18 03:24:10 +00:00
|
|
|
auto metaData = circuit_->FrameArgs();
|
|
|
|
size_t numArgs = static_cast<size_t>(FrameArgIdx::NUM_OF_ARGS) + metaData->GetInFrameStateCount();
|
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);
|
2023-05-18 03:24:10 +00:00
|
|
|
args[idx++] = circuit_->ReplaceableGate();
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-06-30 02:22:52 +00:00
|
|
|
bool BytecodeCircuitBuilder::ShouldBeDead(BytecodeRegion &curBlock)
|
|
|
|
{
|
|
|
|
auto isDead = false;
|
|
|
|
for (auto bbPred : curBlock.preds) {
|
|
|
|
if (!bbPred->isDead) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
isDead = true;
|
|
|
|
}
|
|
|
|
for (auto bbTry : curBlock.trys) {
|
|
|
|
if (!bbTry->isDead) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
isDead = true;
|
|
|
|
}
|
|
|
|
return isDead;
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
void BytecodeCircuitBuilder::CollectPredsInfo()
|
|
|
|
{
|
|
|
|
for (auto &bb: graph_) {
|
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bb.numOfStatePreds = 0;
|
|
|
|
}
|
|
|
|
// get number of expanded state predicates of each block
|
|
|
|
// one block-level try catch edge may correspond to multiple bytecode-level edges
|
|
|
|
for (auto &bb: graph_) {
|
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
if (ShouldBeDead(bb)) {
|
2022-07-22 09:12:45 +00:00
|
|
|
bb.UpdateTryCatchInfoForDeadBlock();
|
2022-06-30 02:22:52 +00:00
|
|
|
bb.isDead = true;
|
|
|
|
continue;
|
|
|
|
}
|
2022-07-22 09:12:45 +00:00
|
|
|
bool noThrow = true;
|
|
|
|
EnumerateBlock(bb, [&noThrow, &bb]
|
2022-10-27 03:56:58 +00:00
|
|
|
(const BytecodeInfo &bytecodeInfo) -> bool {
|
2022-02-17 03:48:40 +00:00
|
|
|
if (bytecodeInfo.IsGeneral()) {
|
2023-02-13 05:46:34 +00:00
|
|
|
if (!bb.catchs.empty() && !bytecodeInfo.NoThrow()) {
|
|
|
|
noThrow = false;
|
2022-04-24 17:17:29 +00:00
|
|
|
bb.catchs.at(0)->numOfStatePreds++;
|
|
|
|
}
|
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
if (bytecodeInfo.IsCondJump() && bb.succs.size() == 1) {
|
|
|
|
ASSERT(bb.succs[0]->id == bb.id + 1);
|
|
|
|
bb.succs[0]->numOfStatePreds++;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2022-07-22 09:12:45 +00:00
|
|
|
bb.UpdateRedundantTryCatchInfo(noThrow);
|
|
|
|
bb.UpdateTryCatchInfoIfNoThrow(noThrow);
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &succ: bb.succs) {
|
|
|
|
succ->numOfStatePreds++;
|
|
|
|
}
|
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
|
|
|
|
CollectLoopBack();
|
|
|
|
if (EnableLoopOptimization()) {
|
|
|
|
for (auto &head : loopHeads_) {
|
|
|
|
loopSize_ = 0;
|
|
|
|
ComputeLoopDepth(head.second);
|
|
|
|
head.first = loopSize_;
|
|
|
|
}
|
|
|
|
sort(loopHeads_.begin(), loopHeads_.end());
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb: graph_) {
|
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bb.phiAcc = (bb.numOfStatePreds > 1) || (!bb.trys.empty());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::NewMerge(GateRef &state, GateRef &depend, size_t numOfIns)
|
|
|
|
{
|
2022-11-29 09:25:20 +00:00
|
|
|
state = circuit_->NewGate(circuit_->Merge(numOfIns),
|
|
|
|
std::vector<GateRef>(numOfIns, Circuit::NullGate()));
|
|
|
|
depend = circuit_->NewGate(circuit_->DependSelector(numOfIns),
|
|
|
|
std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
|
2022-07-19 12:44:46 +00:00
|
|
|
gateAcc_.NewIn(depend, 0, state);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2023-04-03 08:33:32 +00:00
|
|
|
if (bb.numOfLoopBacks > 1) {
|
|
|
|
NewMerge(bb.loopBackStateMerge, bb.loopBackDependMerge, bb.numOfLoopBacks);
|
2022-10-09 09:40:04 +00:00
|
|
|
}
|
2023-04-03 08:33:32 +00:00
|
|
|
auto loopBack = circuit_->NewGate(circuit_->LoopBack(), { Circuit::NullGate() });
|
|
|
|
auto loopBegin = circuit_->NewGate(circuit_->LoopBegin(), { Circuit::NullGate(), loopBack });
|
2022-04-24 17:17:29 +00:00
|
|
|
// 2: the number of depend inputs and it is in accord with LOOP_BEGIN
|
2023-04-03 08:33:32 +00:00
|
|
|
auto loopDepend = circuit_->NewGate(circuit_->DependSelector(2),
|
|
|
|
{ loopBegin, Circuit::NullGate(), Circuit::NullGate() });
|
2023-04-18 02:56:21 +00:00
|
|
|
if (state == circuit_->GetStateRoot()) {
|
|
|
|
ASSERT(depend == circuit_->GetDependRoot());
|
|
|
|
gateAcc_.NewIn(loopBegin, 0, state);
|
|
|
|
gateAcc_.NewIn(loopDepend, 1, depend);
|
|
|
|
}
|
2023-04-03 08:33:32 +00:00
|
|
|
state = loopBegin;
|
|
|
|
depend = loopDepend;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
void BytecodeCircuitBuilder::NewLoopExit(GateRef &state, GateRef &depend)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2023-04-03 08:33:32 +00:00
|
|
|
auto loopExit = circuit_->NewGate(circuit_->LoopExit(),
|
2023-04-28 08:37:17 +00:00
|
|
|
{ state });
|
2023-04-03 08:33:32 +00:00
|
|
|
depend = circuit_->NewGate(circuit_->LoopExitDepend(),
|
2023-04-28 08:37:17 +00:00
|
|
|
{ loopExit, depend });
|
2023-04-03 08:33:32 +00:00
|
|
|
state = loopExit;
|
2023-04-28 08:37:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::TryInsertLoopExit(BytecodeRegion &bb, BytecodeRegion &bbNext,
|
|
|
|
GateRef &state, GateRef &depend)
|
|
|
|
{
|
|
|
|
size_t diff = LoopExitCount(bb.id, bbNext.id);
|
|
|
|
for (size_t i = 0; i < diff; ++i) {
|
|
|
|
NewLoopExit(state, depend);
|
|
|
|
}
|
2023-04-03 08:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildBlockCircuitHead(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
|
|
|
{
|
|
|
|
auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
|
|
|
|
if (mergeCount == 0) {
|
|
|
|
state = circuit_->GetStateRoot();
|
|
|
|
depend = circuit_->GetDependRoot();
|
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
if (mergeCount > 1) {
|
|
|
|
NewMerge(bb.stateMerge, bb.dependMerge, mergeCount);
|
|
|
|
state = bb.stateMerge;
|
|
|
|
depend = bb.dependMerge;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bb.numOfLoopBacks > 0) {
|
|
|
|
NewLoopBegin(bb, state, depend);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-03-27 09:23:59 +00:00
|
|
|
if (info.HasFrameState()) {
|
|
|
|
GateRef frameArgs = argAcc_.GetFrameArgs();
|
|
|
|
inList[inputSize + length] = frameArgs;
|
2022-11-28 01:26:23 +00:00
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
return inList;
|
|
|
|
}
|
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
void BytecodeCircuitBuilder::SetLoopBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
|
|
|
|
GateRef &state, GateRef &depend)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2023-04-03 08:33:32 +00:00
|
|
|
ASSERT(bbNext.numOfLoopBacks > 0);
|
|
|
|
ASSERT(gateAcc_.GetOpCode(bbNext.stateCurrent) == OpCode::LOOP_BEGIN);
|
|
|
|
ASSERT(gateAcc_.GetOpCode(bbNext.dependCurrent) == OpCode::DEPEND_SELECTOR);
|
|
|
|
// loop back
|
|
|
|
if (bbNext.loopbackBlocks.count(bb.id)) {
|
|
|
|
if (bbNext.loopBackStateMerge != Circuit::NullGate()) {
|
|
|
|
ASSERT(bbNext.loopBackDependMerge != Circuit::NullGate());
|
|
|
|
gateAcc_.NewIn(bbNext.loopBackStateMerge, bbNext.loopBackIndex, state);
|
|
|
|
gateAcc_.NewIn(bbNext.loopBackDependMerge, bbNext.loopBackIndex + 1, depend);
|
|
|
|
state = bbNext.loopBackStateMerge;
|
|
|
|
depend = bbNext.loopBackDependMerge;
|
|
|
|
}
|
|
|
|
if (bbNext.loopBackIndex == 0) {
|
|
|
|
auto loopBack = gateAcc_.GetState(bbNext.stateCurrent, 1); // 1: LoopBack
|
|
|
|
gateAcc_.NewIn(loopBack, 0, state);
|
|
|
|
gateAcc_.NewIn(bbNext.dependCurrent, 2, depend); // 2: loopback depend
|
|
|
|
}
|
|
|
|
bbNext.loopBackIndex++;
|
|
|
|
ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
|
2022-04-24 17:17:29 +00:00
|
|
|
} else {
|
2023-04-03 08:33:32 +00:00
|
|
|
if (bbNext.stateMerge != Circuit::NullGate()) {
|
|
|
|
ASSERT(bbNext.dependMerge != Circuit::NullGate());
|
|
|
|
gateAcc_.NewIn(bbNext.stateMerge, bbNext.forwardIndex, state);
|
|
|
|
gateAcc_.NewIn(bbNext.dependMerge, bbNext.forwardIndex + 1, depend);
|
|
|
|
state = bbNext.stateMerge;
|
|
|
|
depend = bbNext.dependMerge;
|
|
|
|
}
|
|
|
|
if (bbNext.forwardIndex == 0) {
|
|
|
|
gateAcc_.NewIn(bbNext.stateCurrent, 0, state);
|
|
|
|
gateAcc_.NewIn(bbNext.dependCurrent, 1, depend); // 1: first depend
|
|
|
|
}
|
|
|
|
bbNext.forwardIndex++;
|
|
|
|
ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
|
|
|
|
const GateRef &state, const GateRef &depend)
|
|
|
|
{
|
2023-04-28 08:37:17 +00:00
|
|
|
auto stateCur = state;
|
|
|
|
auto dependCur = depend;
|
|
|
|
|
|
|
|
if (EnableLoopOptimization()) {
|
|
|
|
TryInsertLoopExit(bb, bbNext, stateCur, dependCur);
|
|
|
|
}
|
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
// Init block head if not exists
|
|
|
|
if (bbNext.stateCurrent == Circuit::NullGate()) {
|
|
|
|
ASSERT(bbNext.dependCurrent == Circuit::NullGate());
|
|
|
|
BuildBlockCircuitHead(bbNext, bbNext.stateCurrent, bbNext.dependCurrent);
|
2023-04-28 08:37:17 +00:00
|
|
|
// no loop head, no merge bb
|
2023-04-03 08:33:32 +00:00
|
|
|
if (bbNext.stateCurrent == Circuit::NullGate()) {
|
|
|
|
ASSERT(bbNext.dependCurrent == Circuit::NullGate());
|
2023-04-28 08:37:17 +00:00
|
|
|
bbNext.stateCurrent = stateCur;
|
|
|
|
bbNext.dependCurrent = dependCur;
|
2023-04-03 08:33:32 +00:00
|
|
|
bbNext.statePredIndex++;
|
|
|
|
return;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
// loop bb
|
|
|
|
if (bbNext.numOfLoopBacks > 0) {
|
|
|
|
SetLoopBlockPred(bb, bbNext, stateCur, dependCur);
|
|
|
|
bbNext.statePredIndex++;
|
|
|
|
return;
|
|
|
|
}
|
2023-05-16 13:37:00 +00:00
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
// merge bb
|
|
|
|
if (bbNext.stateMerge != Circuit::NullGate()) {
|
|
|
|
ASSERT(bbNext.dependMerge != Circuit::NullGate());
|
|
|
|
gateAcc_.NewIn(bbNext.stateMerge, bbNext.statePredIndex, stateCur);
|
|
|
|
gateAcc_.NewIn(bbNext.dependMerge, bbNext.statePredIndex + 1, dependCur); // 1: skip state
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
bbNext.statePredIndex++;
|
|
|
|
ASSERT(bbNext.statePredIndex <= bbNext.numOfStatePreds);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-10-27 03:56:58 +00:00
|
|
|
void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
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();
|
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-03-27 09:23:59 +00:00
|
|
|
bool hasFrameState = bytecodeInfo.HasFrameState();
|
2023-03-02 12:09:04 +00:00
|
|
|
size_t pcOffset = GetPcOffset(iterator.Index());
|
2023-03-27 09:23:59 +00:00
|
|
|
auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, 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-01-13 01:18:36 +00:00
|
|
|
state = gate;
|
2023-02-13 05:46:34 +00:00
|
|
|
if (bytecodeInfo.IsThrow()) {
|
|
|
|
depend = gate;
|
|
|
|
|
|
|
|
if (!bb.catchs.empty()) {
|
|
|
|
auto &bbNext = bb.catchs.at(0);
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, gate, gate);
|
2023-02-13 05:46:34 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
|
|
|
|
} else {
|
|
|
|
auto constant = circuit_->GetConstantGate(MachineType::I64,
|
|
|
|
JSTaggedValue::VALUE_EXCEPTION,
|
|
|
|
GateType::TaggedValue());
|
|
|
|
circuit_->NewGate(circuit_->Return(),
|
|
|
|
{ state, depend, constant, circuit_->GetReturnRoot() });
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!bb.catchs.empty() && !bytecodeInfo.NoThrow()) {
|
2023-01-13 01:18:36 +00:00
|
|
|
auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
|
2023-02-13 05:46:34 +00:00
|
|
|
auto ifException = circuit_->NewGate(circuit_->IfException(), {gate, gate});
|
2023-01-13 01:18:36 +00:00
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
auto &bbNext = bb.catchs.at(0);
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, ifException, ifException);
|
2022-10-27 03:56:58 +00:00
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
|
2022-10-27 09:12:44 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index() + 1, true}); // 1: next pc
|
2022-09-29 06:18:49 +00:00
|
|
|
} else {
|
2022-10-27 03:56:58 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
|
2022-09-29 06:18:49 +00:00
|
|
|
}
|
2023-01-13 01:18:36 +00:00
|
|
|
state = ifSuccess;
|
2022-02-12 08:15:41 +00:00
|
|
|
}
|
2022-06-06 09:41:17 +00:00
|
|
|
if (bytecodeInfo.IsGeneratorRelative()) {
|
2023-03-20 09:31:17 +00:00
|
|
|
//exclude...
|
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8 ||
|
|
|
|
bytecodeInfo.GetOpcode() == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8 ||
|
|
|
|
bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8) {
|
2022-12-23 06:45:29 +00:00
|
|
|
auto hole = circuit_->GetConstantGate(MachineType::I64,
|
|
|
|
JSTaggedValue::VALUE_HOLE,
|
|
|
|
GateType::TaggedValue());
|
2023-02-22 03:11:36 +00:00
|
|
|
uint32_t numRegs = GetNumberVRegsWithEnv();
|
2022-12-23 06:45:29 +00:00
|
|
|
std::vector<GateRef> vec(numRegs + 1, hole);
|
|
|
|
vec[0] = depend;
|
|
|
|
GateRef saveRegs =
|
|
|
|
circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
|
|
|
|
gateAcc_.ReplaceDependIn(gate, saveRegs);
|
|
|
|
}
|
2022-06-06 09:41:17 +00:00
|
|
|
suspendAndResumeGates_.emplace_back(gate);
|
|
|
|
}
|
2023-01-13 01:18:36 +00:00
|
|
|
depend = gate;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 03:56:58 +00:00
|
|
|
void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
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();
|
2022-06-10 07:22:21 +00:00
|
|
|
size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
|
2022-02-17 03:48:40 +00:00
|
|
|
if (bytecodeInfo.IsCondJump()) {
|
2023-03-02 12:09:04 +00:00
|
|
|
size_t pcOffset = GetPcOffset(iterator.Index());
|
2023-03-27 09:23:59 +00:00
|
|
|
auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, 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);
|
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});
|
2022-06-30 02:22:52 +00:00
|
|
|
if (bb.succs.size() == 1) {
|
|
|
|
auto &bbNext = bb.succs[0];
|
|
|
|
ASSERT(bbNext->id == bb.id + 1);
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
|
|
|
|
SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
|
2022-10-27 03:56:58 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-11-15 12:32:23 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-06-30 02:22:52 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(bb.succs.size() == 2); // 2 : 2 num of successors
|
2022-08-04 07:37:10 +00:00
|
|
|
[[maybe_unused]] uint32_t bitSet = 0;
|
2022-06-30 02:22:52 +00:00
|
|
|
for (auto &bbNext: bb.succs) {
|
|
|
|
if (bbNext->id == bb.id + 1) {
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
|
2022-10-27 03:56:58 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-06-30 02:22:52 +00:00
|
|
|
bitSet |= 1;
|
|
|
|
} else {
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
|
2022-10-27 03:56:58 +00:00
|
|
|
bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
|
2022-06-30 02:22:52 +00:00
|
|
|
bitSet |= 2; // 2:verify
|
|
|
|
}
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-06-30 02:22:52 +00:00
|
|
|
ASSERT(bitSet == 3); // 3:Verify the number of successor blocks
|
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 {
|
|
|
|
ASSERT(bb.succs.size() == 1);
|
|
|
|
auto &bbNext = bb.succs.at(0);
|
2023-04-03 08:33:32 +00:00
|
|
|
SetBlockPred(bb, *bbNext, state, depend);
|
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
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2022-01-19 01:11:02 +00:00
|
|
|
|
2022-10-27 03:56:58 +00:00
|
|
|
void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
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();
|
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
|
2022-09-06 05:27:19 +00:00
|
|
|
// handle return.dyn bytecode
|
2022-11-29 09:25:20 +00:00
|
|
|
auto 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());
|
2022-11-29 09:25:20 +00:00
|
|
|
auto 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
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2022-10-27 03:56:58 +00:00
|
|
|
void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, GateRef &depend)
|
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();
|
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
|
|
|
|
GateRef 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
|
2022-10-27 03:56:58 +00:00
|
|
|
NewJSGate(bb, state, depend);
|
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
|
2022-10-27 03:56:58 +00:00
|
|
|
NewJump(bb, state, depend);
|
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
|
2022-10-27 03:56:58 +00:00
|
|
|
NewReturn(bb, state, depend);
|
2023-04-03 08:33:32 +00:00
|
|
|
} else if (!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov()) {
|
2022-12-01 07:29:41 +00:00
|
|
|
LOG_ECMA(FATAL) << "this branch is unreachable";
|
2022-04-24 17:17:29 +00:00
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildSubCircuit()
|
|
|
|
{
|
2023-04-03 08:33:32 +00:00
|
|
|
auto &entryBlock = graph_[0];
|
|
|
|
BuildBlockCircuitHead(entryBlock, entryBlock.stateCurrent, entryBlock.dependCurrent);
|
2023-04-28 08:37:17 +00:00
|
|
|
for (auto &bbId: dfsList_) {
|
2023-04-03 08:33:32 +00:00
|
|
|
auto &bb = graph_[bbId];
|
|
|
|
auto stateCur = bb.stateCurrent;
|
|
|
|
auto dependCur = bb.dependCurrent;
|
2022-01-19 01:11:02 +00:00
|
|
|
ASSERT(stateCur != Circuit::NullGate());
|
|
|
|
ASSERT(dependCur != Circuit::NullGate());
|
2023-04-23 09:21:01 +00:00
|
|
|
if (IsEntryBlock(bb.id)) {
|
2023-04-27 12:26:51 +00:00
|
|
|
stateCur = circuit_->NewGate(circuit_->UpdateHotness(), {stateCur, dependCur});
|
|
|
|
dependCur = stateCur;
|
2023-04-23 09:21:01 +00:00
|
|
|
auto &bbNext = graph_[bb.id + 1];
|
|
|
|
SetBlockPred(bb, bbNext, stateCur, dependCur);
|
|
|
|
bbNext.expandedPreds.push_back({bb.id, bb.end, false});
|
|
|
|
continue;
|
|
|
|
}
|
2022-02-10 02:03:48 +00:00
|
|
|
if (!bb.trys.empty()) {
|
2022-11-29 09:25:20 +00:00
|
|
|
dependCur = circuit_->NewGate(circuit_->GetException(),
|
2022-12-24 10:10:23 +00:00
|
|
|
MachineType::I64, {stateCur, dependCur}, GateType::AnyType());
|
2022-02-10 02:03:48 +00:00
|
|
|
}
|
2022-10-27 03:56:58 +00:00
|
|
|
EnumerateBlock(bb, [this, &stateCur, &dependCur, &bb]
|
|
|
|
(const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
NewByteCode(bb, stateCur, dependCur);
|
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-04-03 08:33:32 +00:00
|
|
|
const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
|
|
|
|
if (bytecodeInfo.needFallThrough()) {
|
|
|
|
auto &bbNext = graph_[bb.id + 1];
|
|
|
|
SetBlockPred(bb, bbNext, stateCur, dependCur);
|
|
|
|
bbNext.expandedPreds.push_back({bb.id, bb.end, false});
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
GateRef BytecodeCircuitBuilder::NewLoopBackPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
|
|
|
|
{
|
|
|
|
if (bb.numOfLoopBacks == 1) {
|
|
|
|
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
|
|
|
|
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
|
|
|
|
if (bb.loopbackBlocks.count(predId)) {
|
2023-04-28 08:37:17 +00:00
|
|
|
return NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateCurrent, 1), reg, acc);
|
2023-04-03 08:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
LOG_COMPILER(FATAL) << "this branch is unreachable";
|
|
|
|
}
|
|
|
|
auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
|
|
|
|
auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
|
|
|
|
MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
|
|
|
|
gateAcc_.NewIn(loopBackValue, 0, bb.loopBackStateMerge);
|
|
|
|
size_t loopBackIndex = 1; // 1: start index of value inputs
|
|
|
|
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
|
|
|
|
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
|
|
|
|
if (bb.loopbackBlocks.count(predId)) {
|
2023-04-28 08:37:17 +00:00
|
|
|
GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.loopBackStateMerge, loopBackIndex - 1),
|
|
|
|
reg, acc);
|
|
|
|
gateAcc_.NewIn(loopBackValue, loopBackIndex++, ans);
|
2023-04-03 08:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return loopBackValue;
|
|
|
|
}
|
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
size_t BytecodeCircuitBuilder::LoopExitCount(size_t from, size_t to)
|
|
|
|
{
|
|
|
|
if (!EnableLoopOptimization()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
const auto &bb = GetBasicBlockById(from);
|
|
|
|
const auto &bbNext = GetBasicBlockById(to);
|
|
|
|
size_t headDep = ((bbNext.numOfLoopBacks > 0) && (bbNext.loopbackBlocks.count(bb.id) == 0)) ? 1 : 0;
|
|
|
|
ASSERT(bbNext.loopDepth >= headDep);
|
|
|
|
size_t nextDep = bbNext.loopDepth - headDep;
|
|
|
|
ASSERT(bb.loopDepth >= nextDep);
|
|
|
|
return bb.loopDepth > nextDep;
|
|
|
|
}
|
|
|
|
|
|
|
|
GateRef BytecodeCircuitBuilder::NewValueFromPredBB(BytecodeRegion &bb, size_t idx,
|
|
|
|
GateRef exit, uint16_t reg, bool acc)
|
|
|
|
{
|
|
|
|
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(idx);
|
|
|
|
if (LoopExitCount(predId, bb.id) == 0) {
|
|
|
|
return ResolveDef(predId, predBcIdx, reg, acc);
|
|
|
|
}
|
|
|
|
while (gateAcc_.GetOpCode(exit) != OpCode::LOOP_EXIT) {
|
|
|
|
exit = gateAcc_.GetState(exit);
|
|
|
|
}
|
|
|
|
if (IsLoopExitValueExists(exit, reg, acc)) {
|
|
|
|
return GetLoopExitValue(exit, reg, acc);
|
|
|
|
}
|
|
|
|
GateRef res = ResolveDef(predId, predBcIdx, reg, acc);
|
|
|
|
return NewLoopExitValue(exit, reg, acc, res);
|
|
|
|
}
|
|
|
|
|
2023-04-03 08:33:32 +00:00
|
|
|
GateRef BytecodeCircuitBuilder::NewLoopForwardPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
|
|
|
|
{
|
|
|
|
auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
|
|
|
|
if (mergeCount == 1) {
|
|
|
|
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
|
|
|
|
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
|
|
|
|
if (!bb.loopbackBlocks.count(predId)) {
|
2023-04-28 08:37:17 +00:00
|
|
|
return NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateCurrent, 0), reg, acc);
|
2023-04-03 08:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
UNREACHABLE();
|
|
|
|
LOG_COMPILER(FATAL) << "this branch is unreachable";
|
|
|
|
}
|
|
|
|
auto inList = std::vector<GateRef>(1 + mergeCount, Circuit::NullGate());
|
|
|
|
auto forwardValue = circuit_->NewGate(
|
|
|
|
circuit_->ValueSelector(mergeCount), MachineType::I64,
|
|
|
|
inList.size(), inList.data(), GateType::AnyType());
|
|
|
|
gateAcc_.NewIn(forwardValue, 0, bb.stateMerge);
|
|
|
|
size_t forwardIndex = 1; // 1: start index of value inputs
|
|
|
|
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
|
|
|
|
auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
|
|
|
|
if (!bb.loopbackBlocks.count(predId)) {
|
2023-04-28 08:37:17 +00:00
|
|
|
GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateMerge, forwardIndex - 1), reg, acc);
|
|
|
|
gateAcc_.NewIn(forwardValue, forwardIndex++, ans);
|
2023-04-03 08:33:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return forwardValue;
|
|
|
|
}
|
|
|
|
|
2022-06-11 19:13:23 +00:00
|
|
|
void BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef ¤tPhi)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
|
|
|
if (bb.numOfLoopBacks == 0) {
|
2023-04-03 08:33:32 +00:00
|
|
|
if (bb.numOfStatePreds == 1) {
|
2023-04-28 08:37:17 +00:00
|
|
|
currentPhi = NewValueFromPredBB(bb, 0, bb.stateCurrent, reg, acc);
|
|
|
|
ASSERT(currentPhi != 0);
|
2023-04-03 08:33:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
ASSERT(bb.stateMerge != Circuit::NullGate());
|
2022-11-29 09:25:20 +00:00
|
|
|
auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate());
|
2022-06-11 19:13:23 +00:00
|
|
|
currentPhi =
|
2022-11-29 09:25:20 +00:00
|
|
|
circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), MachineType::I64,
|
|
|
|
inList.size(), inList.data(), GateType::AnyType());
|
2023-04-03 08:33:32 +00:00
|
|
|
gateAcc_.NewIn(currentPhi, 0, bb.stateMerge);
|
2022-04-24 17:17:29 +00:00
|
|
|
for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
|
2023-04-28 08:37:17 +00:00
|
|
|
GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetIn(bb.stateMerge, i), reg, acc);
|
|
|
|
gateAcc_.NewIn(currentPhi, i + 1, ans);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
2023-04-03 08:33:32 +00:00
|
|
|
ASSERT(gateAcc_.GetOpCode(bb.stateCurrent) == OpCode::LOOP_BEGIN);
|
2022-06-11 19:13:23 +00:00
|
|
|
// 2: the number of value inputs and it is in accord with LOOP_BEGIN
|
2022-11-29 09:25:20 +00:00
|
|
|
currentPhi = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I64,
|
2023-04-03 08:33:32 +00:00
|
|
|
{bb.stateCurrent, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
|
|
|
|
auto loopBackValue = NewLoopBackPhi(bb, reg, acc);
|
|
|
|
auto forwardValue = NewLoopForwardPhi(bb, reg, acc);
|
2022-07-19 12:44:46 +00:00
|
|
|
gateAcc_.NewIn(currentPhi, 1, forwardValue); // 1: index of forward value input
|
|
|
|
gateAcc_.NewIn(currentPhi, 2, loopBackValue); // 2: index of loop-back value input
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2023-04-19 08:04:57 +00:00
|
|
|
bb.phiGate.insert(currentPhi);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
bool BytecodeCircuitBuilder::IsLoopExitValueExists(GateRef loopExit, uint16_t reg, bool acc)
|
|
|
|
{
|
|
|
|
if (acc) {
|
|
|
|
return loopExitToAccGate_.count(loopExit) > 0;
|
|
|
|
} else {
|
|
|
|
return loopExitToVregGate_.count(std::make_pair(loopExit, reg)) > 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GateRef BytecodeCircuitBuilder::GetLoopExitValue(GateRef loopExit, uint16_t reg, bool acc)
|
|
|
|
{
|
|
|
|
if (acc) {
|
|
|
|
return loopExitToAccGate_.at(loopExit);
|
|
|
|
} else {
|
|
|
|
return loopExitToVregGate_.at(std::make_pair(loopExit, reg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GateRef BytecodeCircuitBuilder::CreateLoopExitValue(GateRef loopExit, uint16_t reg, bool acc, GateRef value)
|
|
|
|
{
|
|
|
|
GateRef newPhi = circuit_->NewGate(circuit_->LoopExitValue(), gateAcc_.GetMachineType(value),
|
|
|
|
{loopExit, value}, gateAcc_.GetGateType(value));
|
|
|
|
if (acc) {
|
|
|
|
return loopExitToAccGate_[loopExit] = newPhi;
|
|
|
|
} else {
|
|
|
|
auto key = std::make_pair(loopExit, reg);
|
|
|
|
return loopExitToVregGate_[key] = newPhi;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GateRef BytecodeCircuitBuilder::NewLoopExitValue(GateRef loopExit, uint16_t reg, bool acc, GateRef value)
|
|
|
|
{
|
|
|
|
ASSERT(gateAcc_.GetOpCode(loopExit) == OpCode::LOOP_EXIT);
|
|
|
|
ChunkVector<GateRef> exitList(circuit_->chunk());
|
|
|
|
while (gateAcc_.GetOpCode(loopExit) == OpCode::LOOP_EXIT) {
|
|
|
|
exitList.push_back(loopExit);
|
|
|
|
loopExit = gateAcc_.GetState(loopExit);
|
|
|
|
}
|
|
|
|
while (!exitList.empty()) {
|
|
|
|
GateRef exit = exitList.back();
|
|
|
|
value = CreateLoopExitValue(exit, reg, acc, value);
|
|
|
|
exitList.pop_back();
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2022-04-24 17:17:29 +00:00
|
|
|
// recursive variables renaming algorithm
|
2023-01-19 06:00:43 +00:00
|
|
|
GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId, const uint16_t reg, const bool acc)
|
2022-04-24 17:17:29 +00:00
|
|
|
{
|
2022-02-17 03:48:40 +00:00
|
|
|
auto tmpReg = reg;
|
2022-04-24 17:17:29 +00:00
|
|
|
// find def-site in bytecodes of basic block
|
|
|
|
auto ans = Circuit::NullGate();
|
|
|
|
auto &bb = graph_.at(bbId);
|
2022-07-05 07:24:00 +00:00
|
|
|
GateType type = GateType::AnyType();
|
2022-02-17 03:48:40 +00:00
|
|
|
auto tmpAcc = acc;
|
2022-11-02 07:10:09 +00:00
|
|
|
|
|
|
|
BytecodeIterator iterator(this, bb.start, bcId);
|
2022-10-27 03:56:58 +00:00
|
|
|
for (iterator.Goto(bcId); !iterator.Done(); --iterator) {
|
|
|
|
const BytecodeInfo& curInfo = iterator.GetBytecodeInfo();
|
2022-05-26 04:54:21 +00:00
|
|
|
// original bc use acc as input && current bc use acc as output
|
2022-10-27 03:56:58 +00:00
|
|
|
bool isTransByAcc = tmpAcc && curInfo.AccOut();
|
2022-05-26 04:54:21 +00:00
|
|
|
// 0 : the index in vreg-out list
|
|
|
|
bool isTransByVreg = (!tmpAcc && curInfo.IsOut(tmpReg, 0));
|
|
|
|
if (isTransByAcc || isTransByVreg) {
|
2022-02-17 03:48:40 +00:00
|
|
|
if (curInfo.IsMov()) {
|
2022-10-27 03:56:58 +00:00
|
|
|
tmpAcc = curInfo.AccIn();
|
2022-02-17 03:48:40 +00:00
|
|
|
if (!curInfo.inputs.empty()) {
|
|
|
|
ASSERT(!tmpAcc);
|
|
|
|
ASSERT(curInfo.inputs.size() == 1);
|
|
|
|
tmpReg = std::get<VirtualRegister>(curInfo.inputs.at(0)).GetId();
|
2022-07-05 07:24:00 +00:00
|
|
|
}
|
2022-10-22 07:59:53 +00:00
|
|
|
if (HasTypes()) {
|
2022-11-02 01:32:55 +00:00
|
|
|
type = typeRecorder_.UpdateType(iterator.Index(), type);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-02-17 03:48:40 +00:00
|
|
|
} else {
|
2023-04-28 08:37:17 +00:00
|
|
|
ans = byteCodeToJSGates_.at(iterator.Index()).at(0);
|
2022-11-29 09:25:20 +00:00
|
|
|
auto oldType = gateAcc_.GetGateType(ans);
|
|
|
|
if (HasTypes() && !type.IsAnyType() && oldType.IsAnyType()) {
|
2023-05-27 08:50:29 +00:00
|
|
|
typeRecorder_.GetOrUpdatePGOType(tsManager_, gateAcc_.TryGetPcOffset(ans), type);
|
2022-07-05 07:24:00 +00:00
|
|
|
gateAcc_.SetGateType(ans, type);
|
|
|
|
}
|
2022-02-17 03:48:40 +00:00
|
|
|
break;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-27 03:56:58 +00:00
|
|
|
if (curInfo.GetOpcode() != EcmaOpcode::RESUMEGENERATOR) {
|
2022-06-06 09:41:17 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// New RESTORE_REGISTER HIR, used to restore the register content when processing resume instruction.
|
|
|
|
// New SAVE_REGISTER HIR, used to save register content when processing suspend instruction.
|
2023-04-28 08:37:17 +00:00
|
|
|
auto resumeGate = byteCodeToJSGates_.at(iterator.Index()).at(0);
|
2023-01-19 06:00:43 +00:00
|
|
|
ans = GetExistingRestore(resumeGate, tmpReg);
|
|
|
|
if (ans != Circuit::NullGate()) {
|
2022-09-19 13:08:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2023-01-19 06:00:43 +00:00
|
|
|
GateRef resumeDependGate = gateAcc_.GetDep(resumeGate);
|
|
|
|
ans = circuit_->NewGate(circuit_->RestoreRegister(tmpReg), MachineType::I64,
|
|
|
|
{ resumeDependGate }, GateType::AnyType());
|
|
|
|
SetExistingRestore(resumeGate, tmpReg, ans);
|
|
|
|
gateAcc_.SetDep(resumeGate, ans);
|
|
|
|
auto saveRegGate = ResolveDef(bbId, iterator.Index() - 1, tmpReg, tmpAcc);
|
2023-03-20 09:31:17 +00:00
|
|
|
[[maybe_unused]] EcmaOpcode opcode = Bytecodes::GetOpcode(iterator.PeekPrevPc(2)); // 2: prev bc
|
|
|
|
ASSERT(opcode == EcmaOpcode::SUSPENDGENERATOR_V8 || opcode == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8);
|
2023-04-28 08:37:17 +00:00
|
|
|
GateRef suspendGate = byteCodeToJSGates_.at(iterator.Index() - 2).at(0); // 2: prev bc
|
2022-12-23 06:45:29 +00:00
|
|
|
GateRef saveRegs = gateAcc_.GetDep(suspendGate);
|
|
|
|
gateAcc_.ReplaceValueIn(saveRegs, saveRegGate, tmpReg);
|
2022-06-06 09:41:17 +00:00
|
|
|
break;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
// find GET_EXCEPTION gate if this is a catch block
|
2022-02-17 03:48:40 +00:00
|
|
|
if (ans == Circuit::NullGate() && tmpAcc) {
|
2022-04-24 17:17:29 +00:00
|
|
|
if (!bb.trys.empty()) {
|
2023-04-03 08:33:32 +00:00
|
|
|
GateRef getExceptionGate = Circuit::NullGate();
|
|
|
|
auto uses = gateAcc_.Uses(bb.dependCurrent);
|
|
|
|
for (auto it = uses.begin(); it != uses.end(); it++) {
|
|
|
|
if (gateAcc_.IsDependIn(it)) {
|
|
|
|
getExceptionGate = *it;
|
|
|
|
ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT(getExceptionGate != Circuit::NullGate());
|
2022-04-24 17:17:29 +00:00
|
|
|
ans = getExceptionGate;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// find def-site in value selectors of vregs
|
2022-02-17 03:48:40 +00:00
|
|
|
if (ans == Circuit::NullGate() && !tmpAcc && bb.phi.count(tmpReg)) {
|
2023-04-19 08:04:57 +00:00
|
|
|
if (!bb.vregToValueGate.count(tmpReg)) {
|
|
|
|
NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2023-04-19 08:04:57 +00:00
|
|
|
ans = bb.vregToValueGate.at(tmpReg);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
// find def-site in value selectors of acc
|
2022-02-17 03:48:40 +00:00
|
|
|
if (ans == Circuit::NullGate() && tmpAcc && bb.phiAcc) {
|
2022-04-24 17:17:29 +00:00
|
|
|
if (bb.valueSelectorAccGate == Circuit::NullGate()) {
|
2022-06-11 19:13:23 +00:00
|
|
|
NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
|
|
|
ans = bb.valueSelectorAccGate;
|
|
|
|
}
|
2022-06-16 09:27:35 +00:00
|
|
|
if (ans == Circuit::NullGate() && IsEntryBlock(bbId)) { // entry block
|
2022-04-24 17:17:29 +00:00
|
|
|
// find def-site in function args
|
2022-06-16 09:27:35 +00:00
|
|
|
ASSERT(!tmpAcc);
|
2023-02-22 03:11:36 +00:00
|
|
|
if (tmpReg == GetEnvVregIdx()) {
|
2023-03-27 09:23:59 +00:00
|
|
|
ans = gateAcc_.GetInitialEnvGate(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC));
|
2023-03-20 09:31:17 +00:00
|
|
|
} else if (argAcc_.ArgGateNotExisted(tmpReg)) {
|
|
|
|
// when GetArgGate fail, return hole
|
|
|
|
ans = circuit_->GetConstantGate(MachineType::I64,
|
|
|
|
JSTaggedValue::VALUE_HOLE,
|
|
|
|
GateType::TaggedValue());
|
2023-02-22 03:11:36 +00:00
|
|
|
} else {
|
|
|
|
ans = argAcc_.GetArgGate(tmpReg);
|
|
|
|
}
|
2022-05-26 04:54:21 +00:00
|
|
|
return ans;
|
2022-04-24 17:17:29 +00:00
|
|
|
}
|
2023-04-28 08:37:17 +00:00
|
|
|
if (EnableLoopOptimization()) {
|
|
|
|
// find def-site in value selectors of vregs
|
|
|
|
if (ans == Circuit::NullGate() && !tmpAcc) {
|
|
|
|
if (!bb.vregToValueGate.count(tmpReg)) {
|
|
|
|
bb.vregToValueGate[tmpReg] = Circuit::NullGate();
|
|
|
|
NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
|
|
|
|
} else if (bb.vregToValueGate.at(tmpReg) == Circuit::NullGate()) {
|
|
|
|
NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
|
|
|
|
}
|
|
|
|
ans = bb.vregToValueGate.at(tmpReg);
|
|
|
|
}
|
|
|
|
// find def-site in value selectors of acc
|
|
|
|
if (ans == Circuit::NullGate() && tmpAcc) {
|
|
|
|
if (bb.valueSelectorAccGate == Circuit::NullGate()) {
|
|
|
|
NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
|
|
|
|
}
|
|
|
|
ans = bb.valueSelectorAccGate;
|
|
|
|
}
|
|
|
|
}
|
2022-04-24 17:17:29 +00:00
|
|
|
if (ans == Circuit::NullGate()) {
|
|
|
|
// recursively find def-site in dominator block
|
2023-04-28 08:37:17 +00:00
|
|
|
GateRef res = ResolveDef(bb.iDominator->id, bb.iDominator->end, tmpReg, tmpAcc);
|
|
|
|
return res;
|
2022-04-24 17:17:29 +00:00
|
|
|
} else {
|
|
|
|
// def-site already found
|
|
|
|
return ans;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::BuildCircuit()
|
|
|
|
{
|
|
|
|
// create arg gates array
|
|
|
|
BuildCircuitArgs();
|
|
|
|
CollectPredsInfo();
|
|
|
|
// build states sub-circuit of each block
|
|
|
|
BuildSubCircuit();
|
2022-01-19 01:11:02 +00:00
|
|
|
// verification of soundness of CFG
|
2022-04-24 17:17:29 +00:00
|
|
|
for (auto &bb: graph_) {
|
2022-01-06 02:26:19 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
continue;
|
|
|
|
}
|
2022-01-19 01:11:02 +00:00
|
|
|
ASSERT(bb.statePredIndex == bb.numOfStatePreds);
|
2022-04-24 17:17:29 +00:00
|
|
|
ASSERT(bb.loopBackIndex == bb.numOfLoopBacks);
|
|
|
|
if (bb.numOfLoopBacks) {
|
|
|
|
ASSERT(bb.forwardIndex == bb.numOfStatePreds - bb.numOfLoopBacks);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
// resolve def-site of virtual regs and set all value inputs
|
|
|
|
EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
|
|
|
|
auto &iterator = bb.GetBytecodeIterator();
|
|
|
|
const auto bcIndex = iterator.Index();
|
|
|
|
const auto bbIndex = bb.id;
|
|
|
|
GateRef gate = GetGateByBcIndex(bcIndex);
|
|
|
|
if (gate == Circuit::NullGate()) {
|
|
|
|
return true;
|
2022-07-05 07:24:00 +00:00
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
if (gateAcc_.IsConstant(gate)) {
|
|
|
|
return true;
|
2022-01-14 09:48:52 +00:00
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
|
|
|
|
if (HasTypes()) {
|
|
|
|
auto type = typeRecorder_.GetType(bcIndex);
|
|
|
|
if (!type.IsAnyType()) {
|
|
|
|
gateAcc_.SetGateType(gate, type);
|
|
|
|
}
|
2023-05-15 08:48:14 +00:00
|
|
|
auto pgoType = typeRecorder_.GetOrUpdatePGOType(tsManager_, gateAcc_.TryGetPcOffset(gate), type);
|
2023-03-08 07:05:35 +00:00
|
|
|
gateAcc_.TrySetPGOType(gate, pgoType);
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
auto valueCount = gateAcc_.GetInValueCount(gate);
|
|
|
|
[[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
|
|
|
|
[[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
|
2023-04-25 03:58:36 +00:00
|
|
|
// RETURNUNDEFINED has value input, but not from acc
|
|
|
|
ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
|
2023-02-22 03:11:36 +00:00
|
|
|
ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
|
2022-11-10 09:58:04 +00:00
|
|
|
auto valueStarts = gateAcc_.GetInValueStarts(gate);
|
2022-11-02 07:10:09 +00:00
|
|
|
for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
|
2022-11-10 09:58:04 +00:00
|
|
|
auto inIdx = valueIdx + valueStarts;
|
2022-11-02 07:10:09 +00:00
|
|
|
if (!gateAcc_.IsInGateNull(gate, inIdx)) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-20 09:31:17 +00:00
|
|
|
if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8) {
|
|
|
|
GateRef depIn = gateAcc_.GetDep(gate);
|
|
|
|
size_t depCount = gateAcc_.GetNumValueIn(depIn);
|
|
|
|
GateRef defVreg = Circuit::NullGate();
|
|
|
|
for (size_t idx = 0; idx < depCount; idx++) {
|
|
|
|
defVreg = ResolveDef(bbIndex, bcIndex - 1, idx, false);
|
|
|
|
gateAcc_.ReplaceValueIn(depIn, defVreg, idx);
|
|
|
|
}
|
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
if (valueIdx < bytecodeInfo.inputs.size()) {
|
|
|
|
auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
|
2023-02-22 03:11:36 +00:00
|
|
|
GateRef defVreg = Circuit::NullGate();
|
|
|
|
if (IsFirstBCEnvIn(bbIndex, bcIndex, vregId)) {
|
2023-03-27 09:23:59 +00:00
|
|
|
defVreg = gateAcc_.GetInitialEnvGate(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC));
|
2023-02-22 03:11:36 +00:00
|
|
|
} else {
|
|
|
|
defVreg = ResolveDef(bbIndex, bcIndex - 1, vregId, false);
|
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
gateAcc_.NewIn(gate, inIdx, defVreg);
|
|
|
|
} else {
|
2023-01-19 06:00:43 +00:00
|
|
|
GateRef defAcc = ResolveDef(bbIndex, bcIndex - 1, 0, true);
|
2022-11-02 07:10:09 +00:00
|
|
|
gateAcc_.NewIn(gate, inIdx, defAcc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-11-02 07:10:09 +00:00
|
|
|
|
2022-11-14 03:40:41 +00:00
|
|
|
if (IsTypeLoweringEnabled()) {
|
2023-03-27 09:23:59 +00:00
|
|
|
GateRef frameArgs = argAcc_.GetFrameArgs();
|
|
|
|
frameStateBuilder_.BuildFrameState(frameArgs);
|
2022-10-09 07:13:51 +00:00
|
|
|
}
|
2022-04-14 08:14:34 +00:00
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
gateAcc_.EliminateRedundantPhi();
|
|
|
|
|
2022-04-14 08:14:34 +00:00
|
|
|
if (IsLogEnabled()) {
|
2022-10-03 04:31:39 +00:00
|
|
|
PrintGraph("Bytecode2Gate");
|
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-09-28 02:40:23 +00:00
|
|
|
GateRef BytecodeCircuitBuilder::GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const
|
2022-09-26 08:38:14 +00:00
|
|
|
{
|
2022-09-19 13:08:34 +00:00
|
|
|
auto pr = std::make_pair(resumeGate, tmpReg);
|
|
|
|
if (resumeRegToRestore_.count(pr)) {
|
|
|
|
return resumeRegToRestore_.at(pr);
|
|
|
|
}
|
|
|
|
return Circuit::NullGate();
|
|
|
|
}
|
|
|
|
|
2022-09-28 02:40:23 +00:00
|
|
|
void BytecodeCircuitBuilder::SetExistingRestore(GateRef resumeGate, uint16_t tmpReg, GateRef restoreGate)
|
2022-09-26 08:38:14 +00:00
|
|
|
{
|
2022-09-19 13:08:34 +00:00
|
|
|
auto pr = std::make_pair(resumeGate, tmpReg);
|
|
|
|
resumeRegToRestore_[pr] = restoreGate;
|
|
|
|
}
|
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
void BytecodeCircuitBuilder::CollectLoopBack()
|
|
|
|
{
|
|
|
|
auto size = GetBasicBlockCount();
|
|
|
|
ChunkVector<size_t> workList(circuit_->chunk());
|
|
|
|
ChunkVector<VisitState> visitState(circuit_->chunk());
|
|
|
|
visitState.resize(size, VisitState::UNVISITED);
|
|
|
|
size_t entryId = 0; // entry id
|
|
|
|
workList.emplace_back(entryId);
|
|
|
|
while (!workList.empty()) {
|
|
|
|
size_t bbId = workList.back();
|
|
|
|
auto &bb = GetBasicBlockById(bbId);
|
|
|
|
if (visitState[bbId] == VisitState::UNVISITED) {
|
|
|
|
dfsList_.emplace_back(bbId);
|
|
|
|
visitState[bbId] = VisitState::PENDING;
|
|
|
|
}
|
|
|
|
bool allVisited = true;
|
|
|
|
|
|
|
|
for (const auto &succBlock: bb.succs) {
|
|
|
|
size_t succId = succBlock->id;
|
|
|
|
if (visitState[succId] == VisitState::UNVISITED) {
|
|
|
|
// dfs
|
|
|
|
workList.emplace_back(succId);
|
|
|
|
allVisited = false;
|
|
|
|
break;
|
|
|
|
} else if (visitState[succId] == VisitState::PENDING) {
|
|
|
|
// back edge
|
|
|
|
CountLoopBackEdge(bbId, succId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &succBlock: bb.catchs) {
|
|
|
|
size_t succId = succBlock->id;
|
|
|
|
if (visitState[succId] == VisitState::UNVISITED) {
|
|
|
|
// dfs
|
|
|
|
workList.emplace_back(succId);
|
|
|
|
allVisited = false;
|
|
|
|
break;
|
|
|
|
} else if (visitState[succId] == VisitState::PENDING) {
|
|
|
|
// back edge
|
|
|
|
CountLoopBackEdge(bbId, succId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (allVisited) {
|
|
|
|
workList.pop_back();
|
|
|
|
visitState[bbId] = VisitState::VISITED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::CountLoopBackEdge(size_t fromId, size_t toId)
|
|
|
|
{
|
|
|
|
auto &toBlock = GetBasicBlockById(toId);
|
|
|
|
if (toBlock.numOfLoopBacks == 0) {
|
|
|
|
loopHeads_.emplace_back(std::make_pair(0, toId));
|
|
|
|
}
|
|
|
|
toBlock.loopbackBlocks.insert(fromId);
|
|
|
|
toBlock.numOfLoopBacks = toBlock.loopbackBlocks.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void BytecodeCircuitBuilder::ComputeLoopDepth(size_t loopHead)
|
|
|
|
{
|
|
|
|
ChunkSet<size_t> visited (circuit_->chunk());
|
|
|
|
ChunkQueue<size_t> workList (circuit_->chunk());
|
|
|
|
visited.insert(loopHead);
|
|
|
|
auto &headBB = GetBasicBlockById(loopHead);
|
|
|
|
headBB.loopDepth++;
|
|
|
|
for (auto loopBack : headBB.loopbackBlocks) {
|
|
|
|
workList.push(loopBack);
|
|
|
|
}
|
|
|
|
while (!workList.empty()) {
|
|
|
|
size_t cur = workList.front();
|
|
|
|
workList.pop();
|
|
|
|
if (visited.count(cur) > 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
visited.insert(cur);
|
|
|
|
auto &curBB = GetBasicBlockById(cur);
|
|
|
|
curBB.loopDepth++;
|
|
|
|
for (const auto& pred : curBB.preds) {
|
|
|
|
workList.push(pred->id);
|
|
|
|
}
|
|
|
|
for (const auto& pred : curBB.trys) {
|
|
|
|
workList.push(pred->id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loopSize_ = visited.size();
|
|
|
|
}
|
|
|
|
|
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++) {
|
2022-10-03 04:31:39 +00:00
|
|
|
BytecodeRegion& bb = graph_[i];
|
|
|
|
if (bb.isDead) {
|
|
|
|
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
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
for (size_t j = 0; j < bb.catchs.size(); j++) {
|
2022-11-02 01:32:55 +00:00
|
|
|
LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catchs[j]->start) << ", "
|
|
|
|
<< std::to_string(bb.catchs[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-10-03 04:31:39 +00:00
|
|
|
std::string log3 = "\tDom: ";
|
|
|
|
for (size_t j = 0; j < bb.immDomBlocks.size(); j++) {
|
|
|
|
log3 += "B" + std::to_string(bb.immDomBlocks[j]->id) + std::string(", ");
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << log3;
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
if (bb.iDominator) {
|
|
|
|
LOG_COMPILER(INFO) << "\tIDom B" << bb.iDominator->id;
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log4("\tDom Frontiers: ");
|
|
|
|
for (const auto &frontier: bb.domFrontiers) {
|
|
|
|
log4 += std::to_string(frontier->id) + " , ";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << log4;
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2022-10-03 04:31:39 +00:00
|
|
|
std::string log5("\tPhi: ");
|
|
|
|
for (auto variable: bb.phi) {
|
|
|
|
log5 += std::to_string(variable) + " , ";
|
2022-01-06 02:26:19 +00:00
|
|
|
}
|
2022-10-03 04:31:39 +00:00
|
|
|
LOG_COMPILER(INFO) << log5;
|
2022-01-06 02:26:19 +00:00
|
|
|
|
2023-04-28 08:37:17 +00:00
|
|
|
std::string log6("\tLoop Depth: ");
|
|
|
|
log6 += std::to_string(bb.loopDepth);
|
|
|
|
LOG_COMPILER(INFO) << log6;
|
|
|
|
|
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
|
|
|
{
|
2022-10-03 04:31:39 +00:00
|
|
|
if (bb.isDead) {
|
|
|
|
return;
|
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
|