1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/bytecode_circuit_builder.h"
17
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/compiler/gate_accessor.h"
20 #include "ecmascript/ts_types/ts_manager.h"
21 #include "libpandafile/bytecode_instruction-inl.h"
22
23 namespace panda::ecmascript::kungfu {
BytecodeToCircuit()24 void BytecodeCircuitBuilder::BytecodeToCircuit()
25 {
26 ExceptionInfo exceptionInfo = {};
27
28 // collect try catch block info
29 CollectTryCatchBlockInfo(exceptionInfo);
30 hasTryCatch_ = exceptionInfo.size() != 0;
31 BuildRegionInfo();
32 // Building the basic block diagram of bytecode
33 BuildRegions(exceptionInfo);
34 }
35
BuildRegionInfo()36 void BytecodeCircuitBuilder::BuildRegionInfo()
37 {
38 uint32_t size = pcOffsets_.size();
39 uint32_t end = size - 2; // 1: end
40 BytecodeIterator iterator(this, 0, end);
41
42 infoData_.resize(size);
43 byteCodeToJSGates_.resize(size, std::vector<GateRef>(0));
44 regionsInfo_.InsertHead(0); // 0: start pc
45 for (iterator.GotoStart(); !iterator.Done(); ++iterator) {
46 auto index = iterator.Index();
47 auto &info = infoData_[index];
48 auto pc = pcOffsets_[index];
49 info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
50 ASSERT(!info.metaData_.IsInvalid());
51 BytecodeInfo::InitBytecodeInfo(this, info, pc);
52 CollectRegionInfo(index);
53 }
54 }
55
CollectRegionInfo(uint32_t bcIndex)56 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
57 {
58 auto pc = pcOffsets_[bcIndex];
59 auto &info = infoData_[bcIndex];
60 int32_t offset = 0;
61 if (info.IsJump()) {
62 switch (info.GetOpcode()) {
63 case EcmaOpcode::JEQZ_IMM8:
64 case EcmaOpcode::JNEZ_IMM8:
65 case EcmaOpcode::JMP_IMM8:
66 offset = static_cast<int8_t>(READ_INST_8_0());
67 break;
68 case EcmaOpcode::JNEZ_IMM16:
69 case EcmaOpcode::JEQZ_IMM16:
70 case EcmaOpcode::JMP_IMM16:
71 offset = static_cast<int16_t>(READ_INST_16_0());
72 break;
73 case EcmaOpcode::JMP_IMM32:
74 case EcmaOpcode::JNEZ_IMM32:
75 case EcmaOpcode::JEQZ_IMM32:
76 offset = static_cast<int32_t>(READ_INST_32_0());
77 break;
78 default:
79 LOG_ECMA(FATAL) << "this branch is unreachable";
80 UNREACHABLE();
81 break;
82 }
83 auto nextIndex = bcIndex + 1; // 1: next pc
84 auto targetIndex = FindBcIndexByPc(pc + offset);
85 // condition branch current basic block end
86 if (info.IsCondJump()) {
87 regionsInfo_.InsertSplit(nextIndex);
88 regionsInfo_.InsertJump(targetIndex, bcIndex, false);
89 } else {
90 if (bcIndex != GetLastBcIndex()) {
91 regionsInfo_.InsertHead(nextIndex);
92 }
93 regionsInfo_.InsertJump(targetIndex, bcIndex, true);
94 }
95 } else if (info.IsReturn() || info.IsThrow()) {
96 if (bcIndex != GetLastBcIndex()) {
97 auto nextIndex = bcIndex + 1; // 1: next pc
98 regionsInfo_.InsertHead(nextIndex);
99 }
100 }
101 }
102
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)103 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
104 {
105 auto pf = file_->GetPandaFile();
106 panda_file::MethodDataAccessor mda(*pf, method_->GetMethodId());
107 panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
108
109 cda.EnumerateTryBlocks([this, &byteCodeException](
110 panda_file::CodeDataAccessor::TryBlock &tryBlock) {
111 auto tryStartOffset = tryBlock.GetStartPc();
112 auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
113
114 auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
115 auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
116 // skip try blocks with same pc in start and end label
117 if (tryStartPc == tryEndPc) {
118 return true;
119 }
120
121 auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
122 regionsInfo_.InsertSplit(tryStartBcIndex);
123 if (tryEndPc <= GetLastPC()) {
124 auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
125 regionsInfo_.InsertSplit(tryEndBcIndex);
126 }
127 byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
128 tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
129 auto pcOffset = catchBlock.GetHandlerPc();
130 auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
131 auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
132 regionsInfo_.InsertHead(catchBlockBcIndex);
133 // try block associate catch block
134 byteCodeException.back().catchs.emplace_back(catchBlockPc);
135 return true;
136 });
137 return true;
138 });
139 }
140
BuildEntryBlock()141 void BytecodeCircuitBuilder::BuildEntryBlock()
142 {
143 BytecodeRegion &entryBlock = graph_[0];
144 BytecodeRegion &nextBlock = graph_[1];
145 entryBlock.succs.emplace_back(&nextBlock);
146 nextBlock.preds.emplace_back(&entryBlock);
147 entryBlock.bytecodeIterator_.Reset(this, INVALID_INDEX, INVALID_INDEX);
148 }
149
BuildRegions(const ExceptionInfo & byteCodeException)150 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
151 {
152 auto &items = regionsInfo_.GetBlockItems();
153 auto blockSize = items.size();
154
155 // 1 : entry block. if the loop head is in the first bb block, the variables used in the head cannot correctly
156 // generate Phi nodes through the dominator-tree algorithm, resulting in an infinite loop. Therefore, an empty
157 // BB block is generated as an entry block
158 graph_.resize(blockSize + 1);
159
160 // build entry block
161 BuildEntryBlock();
162
163 // build basic block
164 size_t blockId = 1;
165 for (const auto &item : items) {
166 auto &curBlock = GetBasicBlockById(blockId);
167 curBlock.id = blockId;
168 curBlock.start = item.GetStartBcIndex();
169 if (blockId != 1) {
170 auto &prevBlock = graph_[blockId - 1];
171 prevBlock.end = curBlock.start - 1;
172 prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
173 // fall through
174 if (!item.IsHeadBlock()) {
175 curBlock.preds.emplace_back(&prevBlock);
176 prevBlock.succs.emplace_back(&curBlock);
177 }
178 }
179 blockId++;
180 }
181 auto &lastBlock = graph_[blockId - 1]; // 1: last block
182 lastBlock.end = GetLastBcIndex();
183 lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
184
185 auto &splitItems = regionsInfo_.GetSplitItems();
186 for (const auto &item : splitItems) {
187 auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
188 auto &curBlock = GetBasicBlockById(curIndex);
189 auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
190 auto &predBlock = GetBasicBlockById(predIndex);
191 curBlock.preds.emplace_back(&predBlock);
192 predBlock.succs.emplace_back(&curBlock);
193 }
194
195 if (byteCodeException.size() != 0) {
196 BuildCatchBlocks(byteCodeException);
197 }
198 if (IsLogEnabled()) {
199 PrintGraph("Build Basic Block");
200 }
201 ComputeDominatorTree();
202 }
203
BuildCatchBlocks(const ExceptionInfo & byteCodeException)204 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
205 {
206 // try catch block associate
207 for (size_t i = 0; i < graph_.size(); i++) {
208 auto &bb = graph_[i];
209 auto startIndex = bb.start;
210 const auto pc = pcOffsets_[startIndex];
211 for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
212 if (pc < it->startPc || pc >= it->endPc) {
213 continue;
214 }
215 // try block interval
216 const auto &catchs = it->catchs; // catchs start pc
217 for (size_t j = i + 1; j < graph_.size(); j++) {
218 auto &catchBB = graph_[j];
219 const auto catchStart = pcOffsets_[catchBB.start];
220 if (std::find(catchs.cbegin(), catchs.cend(), catchStart) != catchs.cend()) {
221 bb.catchs.insert(bb.catchs.cbegin(), &catchBB);
222 bb.succs.emplace_back(&catchBB);
223 catchBB.preds.emplace_back(&bb);
224 }
225 }
226 }
227
228 // When there are multiple catch blocks in the current block, the set of catch blocks
229 // needs to be sorted to satisfy the order of execution of catch blocks.
230 bb.SortCatches();
231 }
232 }
233
ComputeDominatorTree()234 void BytecodeCircuitBuilder::ComputeDominatorTree()
235 {
236 // Construct graph backward order
237 std::unordered_map<size_t, size_t> bbIdToDfsTimestamp;
238 std::unordered_map<size_t, size_t> dfsFatherIdx;
239 std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
240 std::vector<size_t> basicBlockList;
241 size_t timestamp = 0;
242 std::deque<size_t> pendingList;
243 std::vector<size_t> visited(graph_.size(), 0);
244 auto basicBlockId = graph_[0].id;
245 visited[graph_[0].id] = 1;
246 pendingList.emplace_back(basicBlockId);
247 while (!pendingList.empty()) {
248 size_t curBlockId = pendingList.back();
249 pendingList.pop_back();
250 basicBlockList.emplace_back(curBlockId);
251 bbIdToDfsTimestamp[curBlockId] = timestamp++;
252 for (const auto &succBlock: graph_[curBlockId].succs) {
253 if (visited[succBlock->id] == 0) {
254 visited[succBlock->id] = 1;
255 pendingList.emplace_back(succBlock->id);
256 dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp[curBlockId];
257 }
258 }
259 }
260
261 for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
262 bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
263 }
264 RemoveDeadRegions(bbIdToDfsTimestamp);
265
266 std::vector<size_t> immDom(basicBlockList.size()); // immediate dominator with dfs order index
267 std::vector<size_t> semiDom(basicBlockList.size());
268 std::vector<size_t> realImmDom(graph_.size()); // immediate dominator with real index
269 std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
270 {
271 std::vector<size_t> parent(basicBlockList.size());
272 std::iota(parent.begin(), parent.end(), 0);
273 std::vector<size_t> minIdx(basicBlockList.size());
274 std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
275 if (parent[idx] == idx) return idx;
276 size_t unionFindSetRoot = unionFind(parent[idx]);
277 if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
278 minIdx[idx] = minIdx[parent[idx]];
279 }
280 return parent[idx] = unionFindSetRoot;
281 };
282 auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
283 size_t parentFatherIdx = unionFind(fatherIdx);
284 size_t parentSonIdx = unionFind(sonIdx);
285 parent[parentSonIdx] = parentFatherIdx;
286 };
287 std::iota(semiDom.begin(), semiDom.end(), 0);
288 semiDom[0] = semiDom.size();
289 for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
290 for (const auto &preBlock : graph_[basicBlockList[idx]].preds) {
291 if (bbDfsTimestampToIdx[preBlock->id] < idx) {
292 semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
293 } else {
294 unionFind(bbDfsTimestampToIdx[preBlock->id]);
295 semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
296 }
297 }
298 for (const auto & succDomIdx : semiDomTree[idx]) {
299 unionFind(succDomIdx);
300 if (idx == semiDom[minIdx[succDomIdx]]) {
301 immDom[succDomIdx] = idx;
302 } else {
303 immDom[succDomIdx] = minIdx[succDomIdx];
304 }
305 }
306 minIdx[idx] = idx;
307 merge(dfsFatherIdx[basicBlockList[idx]], idx);
308 semiDomTree[semiDom[idx]].emplace_back(idx);
309 }
310 for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
311 if (immDom[idx] != semiDom[idx]) {
312 immDom[idx] = immDom[immDom[idx]];
313 }
314 realImmDom[basicBlockList[idx]] = basicBlockList[immDom[idx]];
315 }
316 semiDom[0] = 0;
317 }
318
319 if (IsLogEnabled()) {
320 PrintGraph("Computed Dom Trees");
321 }
322
323 BuildImmediateDominator(realImmDom);
324 }
325
BuildImmediateDominator(const std::vector<size_t> & immDom)326 void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &immDom)
327 {
328 graph_[0].iDominator = &graph_[0];
329 for (size_t i = 1; i < immDom.size(); i++) {
330 auto dominatedBlock = &graph_[i];
331 if (dominatedBlock->isDead) {
332 continue;
333 }
334 auto immDomBlock = &graph_[immDom[i]];
335 dominatedBlock->iDominator = immDomBlock;
336 }
337
338 for (auto &block : graph_) {
339 if (block.isDead) {
340 continue;
341 }
342 if (block.iDominator->id != block.id) {
343 block.iDominator->immDomBlocks.emplace_back(&block);
344 }
345 }
346
347 ComputeDomFrontiers(immDom);
348 InsertPhi();
349 UpdateCFG();
350 BuildCircuit();
351 }
352
ComputeDomFrontiers(const std::vector<size_t> & immDom)353 void BytecodeCircuitBuilder::ComputeDomFrontiers(const std::vector<size_t> &immDom)
354 {
355 std::vector<std::set<BytecodeRegion *>> domFrontiers(immDom.size());
356 for (auto &bb : graph_) {
357 if (bb.isDead) {
358 continue;
359 }
360 if (bb.preds.size() < 2) { // 2: pred num
361 continue;
362 }
363 for (size_t i = 0; i < bb.preds.size(); i++) {
364 auto runner = bb.preds[i];
365 while (runner->id != immDom[bb.id]) {
366 domFrontiers[runner->id].insert(&bb);
367 runner = &graph_[immDom[runner->id]];
368 }
369 }
370 }
371
372 for (size_t i = 0; i < domFrontiers.size(); i++) {
373 for (auto iter = domFrontiers[i].cbegin(); iter != domFrontiers[i].cend(); iter++) {
374 graph_[i].domFrontiers.emplace_back(*iter);
375 }
376 }
377 }
378
RemoveDeadRegions(const std::unordered_map<size_t,size_t> & bbIdToDfsTimestamp)379 void BytecodeCircuitBuilder::RemoveDeadRegions(const std::unordered_map<size_t, size_t> &bbIdToDfsTimestamp)
380 {
381 for (auto &block: graph_) {
382 std::vector<BytecodeRegion *> newPreds;
383 for (auto &bb : block.preds) {
384 if (bbIdToDfsTimestamp.count(bb->id)) {
385 newPreds.emplace_back(bb);
386 }
387 }
388 block.preds = newPreds;
389 }
390
391 for (auto &block : graph_) {
392 block.isDead = !bbIdToDfsTimestamp.count(block.id);
393 if (block.isDead) {
394 block.succs.clear();
395 }
396 }
397 }
398
InsertPhi()399 void BytecodeCircuitBuilder::InsertPhi()
400 {
401 std::unordered_map<uint16_t, std::set<size_t>> defsitesInfo; // <vreg, bbs>
402 for (auto &bb : graph_) {
403 if (bb.isDead) {
404 continue;
405 }
406 EnumerateBlock(bb, [this, &defsitesInfo, &bb]
407 (const BytecodeInfo &bytecodeInfo) -> bool {
408 if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
409 auto numVRegs = GetNumberVRegsWithEnv();
410 for (size_t i = 0; i < numVRegs; i++) {
411 defsitesInfo[i].insert(bb.id);
412 }
413 }
414 for (const auto &vreg: bytecodeInfo.vregOut) {
415 defsitesInfo[vreg].insert(bb.id);
416 }
417 return true;
418 });
419 }
420
421 // handle phi generated from multiple control flow in the same source block
422 InsertExceptionPhi(defsitesInfo);
423
424 for (const auto&[variable, defsites] : defsitesInfo) {
425 std::queue<uint16_t> workList;
426 for (auto blockId: defsites) {
427 workList.push(blockId);
428 }
429 while (!workList.empty()) {
430 auto currentId = workList.front();
431 workList.pop();
432 for (auto &block : graph_[currentId].domFrontiers) {
433 if (!block->phi.count(variable)) {
434 block->phi.insert(variable);
435 if (!defsitesInfo[variable].count(block->id)) {
436 workList.push(block->id);
437 }
438 }
439 }
440 }
441 }
442
443 if (IsLogEnabled()) {
444 PrintGraph("Inserted Phis");
445 }
446 }
447
InsertExceptionPhi(std::unordered_map<uint16_t,std::set<size_t>> & defsitesInfo)448 void BytecodeCircuitBuilder::InsertExceptionPhi(std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo)
449 {
450 // handle try catch defsite
451 for (auto &bb : graph_) {
452 if (bb.isDead) {
453 continue;
454 }
455 if (bb.catchs.size() == 0) {
456 continue;
457 }
458 std::set<size_t> vregs;
459 EnumerateBlock(bb, [this, &vregs]
460 (const BytecodeInfo &bytecodeInfo) -> bool {
461 if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
462 auto numVRegs = GetNumberVRegsWithEnv();
463 for (size_t i = 0; i < numVRegs; i++) {
464 vregs.insert(i);
465 }
466 return false;
467 }
468 for (const auto &vreg: bytecodeInfo.vregOut) {
469 vregs.insert(vreg);
470 }
471 return true;
472 });
473
474 for (auto &vreg : vregs) {
475 defsitesInfo[vreg].insert(bb.catchs.at(0)->id);
476 bb.catchs.at(0)->phi.insert(vreg);
477 }
478 }
479 }
480
481 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()482 void BytecodeCircuitBuilder::UpdateCFG()
483 {
484 for (auto &bb: graph_) {
485 if (bb.isDead) {
486 continue;
487 }
488 bb.preds.clear();
489 bb.trys.clear();
490 std::vector<BytecodeRegion *> newSuccs;
491 for (const auto &succ: bb.succs) {
492 if (std::count(bb.catchs.cbegin(), bb.catchs.cend(), succ)) {
493 continue;
494 }
495 newSuccs.emplace_back(succ);
496 }
497 bb.succs = newSuccs;
498 }
499 for (auto &bb: graph_) {
500 if (bb.isDead) {
501 continue;
502 }
503 for (auto &succ: bb.succs) {
504 succ->preds.emplace_back(&bb);
505 }
506 for (auto &catchBlock: bb.catchs) {
507 catchBlock->trys.emplace_back(&bb);
508 }
509 }
510 }
511
512 // build circuit
BuildCircuitArgs()513 void BytecodeCircuitBuilder::BuildCircuitArgs()
514 {
515 argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
516 if (!method_->IsFastCall()) {
517 argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
518 auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
519 const size_t actualNumArgs = argAcc_.GetActualNumArgs();
520 // new actual argument gates
521 for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
522 argAcc_.NewArg(argIdx);
523 }
524 } else {
525 auto funcIdx = static_cast<size_t>(FastCallArgIdx::FUNC);
526 size_t actualNumArgs = static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS) + method_->GetNumArgsWithCallField();
527 for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
528 argAcc_.NewArg(argIdx);
529 }
530 }
531 argAcc_.CollectArgs();
532 if (HasTypes()) {
533 argAcc_.FillArgsGateType(&typeRecorder_);
534 }
535
536 BuildFrameArgs();
537 }
538
BuildFrameArgs()539 void BytecodeCircuitBuilder::BuildFrameArgs()
540 {
541 auto metaData = circuit_->FrameArgs();
542 size_t numArgs = static_cast<size_t>(FrameArgIdx::NUM_OF_ARGS);
543 std::vector<GateRef> args(numArgs, Circuit::NullGate());
544 size_t idx = 0;
545 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
546 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
547 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
548 args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
549 GateRef frameArgs = circuit_->NewGate(metaData, args);
550 argAcc_.SetFrameArgs(frameArgs);
551 }
552
ShouldBeDead(BytecodeRegion & curBlock)553 bool BytecodeCircuitBuilder::ShouldBeDead(BytecodeRegion &curBlock)
554 {
555 if (curBlock.iDominator->isDead) {
556 return true;
557 }
558 auto isDead = false;
559 for (auto bbPred : curBlock.preds) {
560 if (!bbPred->isDead) {
561 return false;
562 }
563 isDead = true;
564 }
565 for (auto bbTry : curBlock.trys) {
566 if (!bbTry->isDead) {
567 return false;
568 }
569 isDead = true;
570 }
571 return isDead;
572 }
573
CollectPredsInfo()574 void BytecodeCircuitBuilder::CollectPredsInfo()
575 {
576 for (auto &bb: graph_) {
577 if (bb.isDead) {
578 continue;
579 }
580 bb.numOfStatePreds = 0;
581 }
582 // get number of expanded state predicates of each block
583 // one block-level try catch edge may correspond to multiple bytecode-level edges
584 for (auto &bb: graph_) {
585 if (bb.isDead) {
586 continue;
587 }
588 if (ShouldBeDead(bb)) {
589 bb.UpdateTryCatchInfoForDeadBlock();
590 bb.isDead = true;
591 continue;
592 }
593 bool noThrow = true;
594 EnumerateBlock(bb, [&noThrow, &bb]
595 (const BytecodeInfo &bytecodeInfo) -> bool {
596 if (bytecodeInfo.IsGeneral()) {
597 if (!bb.catchs.empty() && !bytecodeInfo.NoThrow()) {
598 noThrow = false;
599 bb.catchs.at(0)->numOfStatePreds++;
600 }
601 }
602 if (bytecodeInfo.IsCondJump() && bb.succs.size() == 1) {
603 ASSERT(bb.succs[0]->id == bb.id + 1);
604 bb.succs[0]->numOfStatePreds++;
605 }
606 return true;
607 });
608 bb.UpdateRedundantTryCatchInfo(noThrow);
609 bb.UpdateTryCatchInfoIfNoThrow(noThrow);
610 for (auto &succ: bb.succs) {
611 succ->numOfStatePreds++;
612 }
613 }
614
615 CollectLoopBack();
616 if (EnableLoopOptimization()) {
617 for (auto &head : loopHeads_) {
618 loopSize_ = 0;
619 ComputeLoopDepth(head.second);
620 head.first = loopSize_;
621 }
622 sort(loopHeads_.begin(), loopHeads_.end());
623 }
624
625 for (auto &bb: graph_) {
626 if (bb.isDead) {
627 continue;
628 }
629 bb.phiAcc = (bb.numOfStatePreds > 1) || (!bb.trys.empty());
630 }
631 }
632
NewMerge(GateRef & state,GateRef & depend,size_t numOfIns)633 void BytecodeCircuitBuilder::NewMerge(GateRef &state, GateRef &depend, size_t numOfIns)
634 {
635 state = circuit_->NewGate(circuit_->Merge(numOfIns),
636 std::vector<GateRef>(numOfIns, Circuit::NullGate()));
637 depend = circuit_->NewGate(circuit_->DependSelector(numOfIns),
638 std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
639 gateAcc_.NewIn(depend, 0, state);
640 }
641
NewLoopBegin(BytecodeRegion & bb,GateRef & state,GateRef & depend)642 void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb, GateRef &state, GateRef &depend)
643 {
644 if (bb.numOfLoopBacks > 1) {
645 NewMerge(bb.loopBackStateMerge, bb.loopBackDependMerge, bb.numOfLoopBacks);
646 }
647 auto loopBack = circuit_->NewGate(circuit_->LoopBack(), { Circuit::NullGate() });
648 auto loopBegin = circuit_->NewGate(circuit_->LoopBegin(), { Circuit::NullGate(), loopBack });
649 // 2: the number of depend inputs and it is in accord with LOOP_BEGIN
650 auto loopDepend = circuit_->NewGate(circuit_->DependSelector(2),
651 { loopBegin, Circuit::NullGate(), Circuit::NullGate() });
652 if (state == circuit_->GetStateRoot()) {
653 ASSERT(depend == circuit_->GetDependRoot());
654 gateAcc_.NewIn(loopBegin, 0, state);
655 gateAcc_.NewIn(loopDepend, 1, depend);
656 }
657 state = loopBegin;
658 depend = loopDepend;
659 }
660
NewLoopExit(GateRef & state,GateRef & depend)661 void BytecodeCircuitBuilder::NewLoopExit(GateRef &state, GateRef &depend)
662 {
663 auto loopExit = circuit_->NewGate(circuit_->LoopExit(),
664 { state });
665 depend = circuit_->NewGate(circuit_->LoopExitDepend(),
666 { loopExit, depend });
667 state = loopExit;
668 }
669
TryInsertLoopExit(BytecodeRegion & bb,BytecodeRegion & bbNext,GateRef & state,GateRef & depend)670 void BytecodeCircuitBuilder::TryInsertLoopExit(BytecodeRegion &bb, BytecodeRegion &bbNext,
671 GateRef &state, GateRef &depend)
672 {
673 size_t diff = LoopExitCount(bb.id, bbNext.id);
674 for (size_t i = 0; i < diff; ++i) {
675 NewLoopExit(state, depend);
676 }
677 }
678
BuildBlockCircuitHead(BytecodeRegion & bb,GateRef & state,GateRef & depend)679 void BytecodeCircuitBuilder::BuildBlockCircuitHead(BytecodeRegion &bb, GateRef &state, GateRef &depend)
680 {
681 auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
682 if (mergeCount == 0) {
683 state = circuit_->GetStateRoot();
684 depend = circuit_->GetDependRoot();
685 }
686
687 if (mergeCount > 1) {
688 NewMerge(bb.stateMerge, bb.dependMerge, mergeCount);
689 state = bb.stateMerge;
690 depend = bb.dependMerge;
691 }
692
693 if (bb.numOfLoopBacks > 0) {
694 NewLoopBegin(bb, state, depend);
695 }
696 }
697
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)698 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
699 const BytecodeInfo &info, const GateMetaData *meta)
700 {
701 auto numValues = meta->GetNumIns();
702 const size_t length = meta->GetInValueStarts();
703 std::vector<GateRef> inList(numValues, Circuit::NullGate());
704 auto inputSize = info.inputs.size();
705 for (size_t i = 0; i < inputSize; i++) {
706 auto &input = info.inputs[i];
707 if (std::holds_alternative<ConstDataId>(input)) {
708 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
709 std::get<ConstDataId>(input).GetId(),
710 GateType::NJSValue());
711 } else if (std::holds_alternative<Immediate>(input)) {
712 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
713 std::get<Immediate>(input).GetValue(),
714 GateType::NJSValue());
715 } else if (std::holds_alternative<ICSlotId>(input)) {
716 inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
717 std::get<ICSlotId>(input).GetId(),
718 GateType::NJSValue());
719 } else {
720 ASSERT(std::holds_alternative<VirtualRegister>(input));
721 continue;
722 }
723 }
724 if (info.AccIn()) {
725 inputSize++;
726 }
727 if (meta->HasFrameState()) {
728 inList[inputSize + length] = GetFrameArgs();
729 }
730 return inList;
731 }
732
SetLoopBlockPred(BytecodeRegion & bb,BytecodeRegion & bbNext,GateRef & state,GateRef & depend)733 void BytecodeCircuitBuilder::SetLoopBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
734 GateRef &state, GateRef &depend)
735 {
736 ASSERT(bbNext.numOfLoopBacks > 0);
737 ASSERT(gateAcc_.GetOpCode(bbNext.stateCurrent) == OpCode::LOOP_BEGIN);
738 ASSERT(gateAcc_.GetOpCode(bbNext.dependCurrent) == OpCode::DEPEND_SELECTOR);
739 // loop back
740 if (bbNext.loopbackBlocks.count(bb.id)) {
741 if (bbNext.loopBackStateMerge != Circuit::NullGate()) {
742 ASSERT(bbNext.loopBackDependMerge != Circuit::NullGate());
743 gateAcc_.NewIn(bbNext.loopBackStateMerge, bbNext.loopBackIndex, state);
744 gateAcc_.NewIn(bbNext.loopBackDependMerge, bbNext.loopBackIndex + 1, depend);
745 state = bbNext.loopBackStateMerge;
746 depend = bbNext.loopBackDependMerge;
747 }
748 if (bbNext.loopBackIndex == 0) {
749 auto loopBack = gateAcc_.GetState(bbNext.stateCurrent, 1); // 1: LoopBack
750 gateAcc_.NewIn(loopBack, 0, state);
751 gateAcc_.NewIn(bbNext.dependCurrent, 2, depend); // 2: loopback depend
752 }
753 bbNext.loopBackIndex++;
754 ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
755 } else {
756 if (bbNext.stateMerge != Circuit::NullGate()) {
757 ASSERT(bbNext.dependMerge != Circuit::NullGate());
758 gateAcc_.NewIn(bbNext.stateMerge, bbNext.forwardIndex, state);
759 gateAcc_.NewIn(bbNext.dependMerge, bbNext.forwardIndex + 1, depend);
760 state = bbNext.stateMerge;
761 depend = bbNext.dependMerge;
762 }
763 if (bbNext.forwardIndex == 0) {
764 gateAcc_.NewIn(bbNext.stateCurrent, 0, state);
765 gateAcc_.NewIn(bbNext.dependCurrent, 1, depend); // 1: first depend
766 }
767 bbNext.forwardIndex++;
768 ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
769 }
770 }
771
SetBlockPred(BytecodeRegion & bb,BytecodeRegion & bbNext,const GateRef & state,const GateRef & depend)772 void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bb, BytecodeRegion &bbNext,
773 const GateRef &state, const GateRef &depend)
774 {
775 auto stateCur = state;
776 auto dependCur = depend;
777
778 if (EnableLoopOptimization()) {
779 TryInsertLoopExit(bb, bbNext, stateCur, dependCur);
780 }
781
782 // Init block head if not exists
783 if (bbNext.stateCurrent == Circuit::NullGate()) {
784 ASSERT(bbNext.dependCurrent == Circuit::NullGate());
785 BuildBlockCircuitHead(bbNext, bbNext.stateCurrent, bbNext.dependCurrent);
786 // no loop head, no merge bb
787 if (bbNext.stateCurrent == Circuit::NullGate()) {
788 ASSERT(bbNext.dependCurrent == Circuit::NullGate());
789 bbNext.stateCurrent = stateCur;
790 bbNext.dependCurrent = dependCur;
791 bbNext.statePredIndex++;
792 return;
793 }
794 }
795
796 // loop bb
797 if (bbNext.numOfLoopBacks > 0) {
798 SetLoopBlockPred(bb, bbNext, stateCur, dependCur);
799 bbNext.statePredIndex++;
800 return;
801 }
802
803 // merge bb
804 if (bbNext.stateMerge != Circuit::NullGate()) {
805 ASSERT(bbNext.dependMerge != Circuit::NullGate());
806 gateAcc_.NewIn(bbNext.stateMerge, bbNext.statePredIndex, stateCur);
807 gateAcc_.NewIn(bbNext.dependMerge, bbNext.statePredIndex + 1, dependCur); // 1: skip state
808 }
809 bbNext.statePredIndex++;
810 ASSERT(bbNext.statePredIndex <= bbNext.numOfStatePreds);
811 }
812
NewConst(const BytecodeInfo & info)813 GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
814 {
815 auto opcode = info.GetOpcode();
816 GateRef gate = 0;
817 switch (opcode) {
818 case EcmaOpcode::LDNAN:
819 gate = circuit_->GetConstantGate(MachineType::I64,
820 base::NumberHelper::GetNaN(),
821 GateType::NumberType());
822 break;
823 case EcmaOpcode::LDINFINITY:
824 gate = circuit_->GetConstantGate(MachineType::I64,
825 base::NumberHelper::GetPositiveInfinity(),
826 GateType::NumberType());
827 break;
828 case EcmaOpcode::LDUNDEFINED:
829 gate = circuit_->GetConstantGate(MachineType::I64,
830 JSTaggedValue::VALUE_UNDEFINED,
831 GateType::UndefinedType());
832 break;
833 case EcmaOpcode::LDNULL:
834 gate = circuit_->GetConstantGate(MachineType::I64,
835 JSTaggedValue::VALUE_NULL,
836 GateType::NullType());
837 break;
838 case EcmaOpcode::LDTRUE:
839 gate = circuit_->GetConstantGate(MachineType::I64,
840 JSTaggedValue::VALUE_TRUE,
841 GateType::BooleanType());
842 break;
843 case EcmaOpcode::LDFALSE:
844 gate = circuit_->GetConstantGate(MachineType::I64,
845 JSTaggedValue::VALUE_FALSE,
846 GateType::BooleanType());
847 break;
848 case EcmaOpcode::LDHOLE:
849 gate = circuit_->GetConstantGate(MachineType::I64,
850 JSTaggedValue::VALUE_HOLE,
851 GateType::TaggedValue());
852 break;
853 case EcmaOpcode::LDAI_IMM32:
854 gate = circuit_->GetConstantGate(MachineType::I64,
855 std::get<Immediate>(info.inputs[0]).ToJSTaggedValueInt(),
856 GateType::IntType());
857 break;
858 case EcmaOpcode::FLDAI_IMM64:
859 gate = circuit_->GetConstantGate(MachineType::I64,
860 std::get<Immediate>(info.inputs.at(0)).ToJSTaggedValueDouble(),
861 GateType::DoubleType());
862 break;
863 case EcmaOpcode::LDFUNCTION:
864 gate = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
865 break;
866 case EcmaOpcode::LDNEWTARGET:
867 gate = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
868 break;
869 case EcmaOpcode::LDTHIS:
870 gate = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
871 break;
872 default:
873 LOG_ECMA(FATAL) << "this branch is unreachable";
874 UNREACHABLE();
875 }
876 return gate;
877 }
878
NewJSGate(BytecodeRegion & bb,GateRef & state,GateRef & depend)879 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateRef &depend)
880 {
881 auto &iterator = bb.GetBytecodeIterator();
882 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
883 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
884 GateRef gate = 0;
885 bool writable = !bytecodeInfo.NoSideEffects();
886 bool hasFrameState = bytecodeInfo.HasFrameArgs();
887 size_t pcOffset = GetPcOffset(iterator.Index());
888 auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, writable, hasFrameState);
889 std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
890 if (bytecodeInfo.IsDef()) {
891 gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
892 inList.data(), GateType::AnyType());
893 } else {
894 gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
895 inList.data(), GateType::Empty());
896 }
897 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
898 jsGatesToByteCode_[gate] = iterator.Index();
899 gateAcc_.NewIn(gate, 0, state);
900 gateAcc_.NewIn(gate, 1, depend);
901 state = gate;
902 if (bytecodeInfo.IsThrow()) {
903 depend = gate;
904
905 if (!bb.catchs.empty()) {
906 auto &bbNext = bb.catchs.at(0);
907 SetBlockPred(bb, *bbNext, gate, gate);
908 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
909 } else {
910 auto constant = circuit_->GetConstantGate(MachineType::I64,
911 JSTaggedValue::VALUE_EXCEPTION,
912 GateType::TaggedValue());
913 circuit_->NewGate(circuit_->Return(),
914 { state, depend, constant, circuit_->GetReturnRoot() });
915 }
916 return;
917 }
918 if (!bb.catchs.empty() && !bytecodeInfo.NoThrow()) {
919 auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
920 auto ifException = circuit_->NewGate(circuit_->IfException(), {gate, gate});
921
922 auto &bbNext = bb.catchs.at(0);
923 SetBlockPred(bb, *bbNext, ifException, ifException);
924 if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
925 bbNext->expandedPreds.push_back({bb.id, iterator.Index() + 1, true}); // 1: next pc
926 } else {
927 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
928 }
929 state = ifSuccess;
930 }
931 if (bytecodeInfo.IsGeneratorRelative()) {
932 //exclude...
933 if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8 ||
934 bytecodeInfo.GetOpcode() == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8 ||
935 bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8) {
936 auto hole = circuit_->GetConstantGate(MachineType::I64,
937 JSTaggedValue::VALUE_HOLE,
938 GateType::TaggedValue());
939 uint32_t numRegs = GetNumberVRegsWithEnv();
940 std::vector<GateRef> vec(numRegs + 1, hole);
941 vec[0] = depend;
942 GateRef saveRegs =
943 circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
944 gateAcc_.ReplaceDependIn(gate, saveRegs);
945 }
946 suspendAndResumeGates_.emplace_back(gate);
947 }
948 depend = gate;
949 }
950
NewJump(BytecodeRegion & bb,GateRef & state,GateRef & depend)951 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend)
952 {
953 auto &iterator = bb.GetBytecodeIterator();
954 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
955 size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
956 if (bytecodeInfo.IsCondJump()) {
957 size_t pcOffset = GetPcOffset(iterator.Index());
958 auto meta = circuit_->JSBytecode(numValueInputs, bytecodeInfo.GetOpcode(), pcOffset, false, false);
959 auto numValues = meta->GetNumIns();
960 GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
961 gateAcc_.NewIn(gate, 0, state);
962 gateAcc_.NewIn(gate, 1, depend);
963 auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
964 auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
965 auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
966 auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
967 if (bb.succs.size() == 1) {
968 auto &bbNext = bb.succs[0];
969 ASSERT(bbNext->id == bb.id + 1);
970 SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
971 SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
972 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
973 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
974 } else {
975 ASSERT(bb.succs.size() == 2); // 2 : 2 num of successors
976 [[maybe_unused]] uint32_t bitSet = 0;
977 for (auto &bbNext: bb.succs) {
978 if (bbNext->id == bb.id + 1) {
979 SetBlockPred(bb, *bbNext, ifFalse, falseRelay);
980 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
981 bitSet |= 1;
982 } else {
983 SetBlockPred(bb, *bbNext, ifTrue, trueRelay);
984 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
985 bitSet |= 2; // 2:verify
986 }
987 }
988 ASSERT(bitSet == 3); // 3:Verify the number of successor blocks
989 }
990 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
991 jsGatesToByteCode_[gate] = iterator.Index();
992 } else {
993 ASSERT(bb.succs.size() == 1);
994 auto &bbNext = bb.succs.at(0);
995 SetBlockPred(bb, *bbNext, state, depend);
996 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
997 }
998 }
999
NewReturn(BytecodeRegion & bb,GateRef & state,GateRef & depend)1000 void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateRef &depend)
1001 {
1002 ASSERT(bb.succs.empty());
1003 auto &iterator = bb.GetBytecodeIterator();
1004 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
1005 if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
1006 // handle return.dyn bytecode
1007 auto gate = circuit_->NewGate(circuit_->Return(),
1008 { state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
1009 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
1010 jsGatesToByteCode_[gate] = iterator.Index();
1011 } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
1012 // handle returnundefined bytecode
1013 auto constant = circuit_->GetConstantGate(MachineType::I64,
1014 JSTaggedValue::VALUE_UNDEFINED,
1015 GateType::TaggedValue());
1016 auto gate = circuit_->NewGate(circuit_->Return(),
1017 { state, depend, constant, circuit_->GetReturnRoot() });
1018 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
1019 jsGatesToByteCode_[gate] = iterator.Index();
1020 }
1021 }
1022
NewByteCode(BytecodeRegion & bb,GateRef & state,GateRef & depend)1023 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, GateRef &depend)
1024 {
1025 auto &iterator = bb.GetBytecodeIterator();
1026 const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
1027 if (bytecodeInfo.IsSetConstant()) {
1028 // handle bytecode command to get constants
1029 GateRef gate = NewConst(bytecodeInfo);
1030 byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
1031 jsGatesToByteCode_[gate] = iterator.Index();
1032 } else if (bytecodeInfo.IsGeneral()) {
1033 // handle general ecma.* bytecodes
1034 NewJSGate(bb, state, depend);
1035 } else if (bytecodeInfo.IsJump()) {
1036 // handle conditional jump and unconditional jump bytecodes
1037 NewJump(bb, state, depend);
1038 } else if (bytecodeInfo.IsReturn()) {
1039 // handle return.dyn and returnundefined bytecodes
1040 NewReturn(bb, state, depend);
1041 } else if (!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov()) {
1042 LOG_ECMA(FATAL) << "this branch is unreachable";
1043 UNREACHABLE();
1044 }
1045 }
1046
BuildSubCircuit()1047 void BytecodeCircuitBuilder::BuildSubCircuit()
1048 {
1049 auto &entryBlock = graph_[0];
1050 BuildBlockCircuitHead(entryBlock, entryBlock.stateCurrent, entryBlock.dependCurrent);
1051 for (auto &bbId: dfsList_) {
1052 auto &bb = graph_[bbId];
1053 auto stateCur = bb.stateCurrent;
1054 auto dependCur = bb.dependCurrent;
1055 ASSERT(stateCur != Circuit::NullGate());
1056 ASSERT(dependCur != Circuit::NullGate());
1057 if (IsEntryBlock(bb.id)) {
1058 if (NeedCheckSafePointAndStackOver()) {
1059 stateCur = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {stateCur, dependCur});
1060 dependCur = stateCur;
1061 }
1062 auto &bbNext = graph_[bb.id + 1];
1063 SetBlockPred(bb, bbNext, stateCur, dependCur);
1064 bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1065 continue;
1066 }
1067 if (!bb.trys.empty()) {
1068 dependCur = circuit_->NewGate(circuit_->GetException(),
1069 MachineType::I64, {stateCur, dependCur}, GateType::AnyType());
1070 bb.dependCurrent = dependCur;
1071 }
1072 EnumerateBlock(bb, [this, &stateCur, &dependCur, &bb]
1073 (const BytecodeInfo &bytecodeInfo) -> bool {
1074 NewByteCode(bb, stateCur, dependCur);
1075 if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1076 return false;
1077 }
1078 return true;
1079 });
1080 const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
1081 if (bytecodeInfo.needFallThrough()) {
1082 auto &bbNext = graph_[bb.id + 1];
1083 SetBlockPred(bb, bbNext, stateCur, dependCur);
1084 bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1085 }
1086 }
1087 }
1088
NewLoopBackPhi(BytecodeRegion & bb,uint16_t reg,bool acc)1089 GateRef BytecodeCircuitBuilder::NewLoopBackPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
1090 {
1091 if (bb.numOfLoopBacks == 1) {
1092 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1093 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1094 if (bb.loopbackBlocks.count(predId)) {
1095 return NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateCurrent, 1), reg, acc);
1096 }
1097 }
1098 UNREACHABLE();
1099 LOG_COMPILER(FATAL) << "this branch is unreachable";
1100 }
1101 auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
1102 auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
1103 MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
1104 gateAcc_.NewIn(loopBackValue, 0, bb.loopBackStateMerge);
1105 size_t loopBackIndex = 1; // 1: start index of value inputs
1106 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1107 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1108 if (bb.loopbackBlocks.count(predId)) {
1109 GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.loopBackStateMerge, loopBackIndex - 1),
1110 reg, acc);
1111 gateAcc_.NewIn(loopBackValue, loopBackIndex++, ans);
1112 }
1113 }
1114 return loopBackValue;
1115 }
1116
LoopExitCount(size_t from,size_t to)1117 size_t BytecodeCircuitBuilder::LoopExitCount(size_t from, size_t to)
1118 {
1119 if (!EnableLoopOptimization()) {
1120 return 0;
1121 }
1122 const auto &bb = GetBasicBlockById(from);
1123 const auto &bbNext = GetBasicBlockById(to);
1124 size_t headDep = ((bbNext.numOfLoopBacks > 0) && (bbNext.loopbackBlocks.count(bb.id) == 0)) ? 1 : 0;
1125 ASSERT(bbNext.loopDepth >= headDep);
1126 size_t nextDep = bbNext.loopDepth - headDep;
1127 ASSERT(bb.loopDepth >= nextDep);
1128 return bb.loopDepth > nextDep;
1129 }
1130
NewValueFromPredBB(BytecodeRegion & bb,size_t idx,GateRef exit,uint16_t reg,bool acc)1131 GateRef BytecodeCircuitBuilder::NewValueFromPredBB(BytecodeRegion &bb, size_t idx,
1132 GateRef exit, uint16_t reg, bool acc)
1133 {
1134 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(idx);
1135 if (LoopExitCount(predId, bb.id) == 0) {
1136 return ResolveDef(predId, predBcIdx, reg, acc);
1137 }
1138 while (gateAcc_.GetOpCode(exit) != OpCode::LOOP_EXIT) {
1139 exit = gateAcc_.GetState(exit);
1140 }
1141 if (IsLoopExitValueExists(exit, reg, acc)) {
1142 return GetLoopExitValue(exit, reg, acc);
1143 }
1144 GateRef res = ResolveDef(predId, predBcIdx, reg, acc);
1145 return NewLoopExitValue(exit, reg, acc, res);
1146 }
1147
NewLoopForwardPhi(BytecodeRegion & bb,uint16_t reg,bool acc)1148 GateRef BytecodeCircuitBuilder::NewLoopForwardPhi(BytecodeRegion &bb, uint16_t reg, bool acc)
1149 {
1150 auto mergeCount = bb.numOfStatePreds - bb.numOfLoopBacks;
1151 if (mergeCount == 1) {
1152 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1153 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1154 if (!bb.loopbackBlocks.count(predId)) {
1155 return NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateCurrent, 0), reg, acc);
1156 }
1157 }
1158 UNREACHABLE();
1159 LOG_COMPILER(FATAL) << "this branch is unreachable";
1160 }
1161 auto inList = std::vector<GateRef>(1 + mergeCount, Circuit::NullGate());
1162 auto forwardValue = circuit_->NewGate(
1163 circuit_->ValueSelector(mergeCount), MachineType::I64,
1164 inList.size(), inList.data(), GateType::AnyType());
1165 gateAcc_.NewIn(forwardValue, 0, bb.stateMerge);
1166 size_t forwardIndex = 1; // 1: start index of value inputs
1167 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1168 auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1169 if (!bb.loopbackBlocks.count(predId)) {
1170 GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetState(bb.stateMerge, forwardIndex - 1), reg, acc);
1171 gateAcc_.NewIn(forwardValue, forwardIndex++, ans);
1172 }
1173 }
1174 return forwardValue;
1175 }
1176
NewPhi(BytecodeRegion & bb,uint16_t reg,bool acc,GateRef & currentPhi)1177 void BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef ¤tPhi)
1178 {
1179 if (bb.numOfLoopBacks == 0) {
1180 if (bb.numOfStatePreds == 1) {
1181 currentPhi = NewValueFromPredBB(bb, 0, bb.stateCurrent, reg, acc);
1182 ASSERT(currentPhi != 0);
1183 return;
1184 }
1185 ASSERT(bb.stateMerge != Circuit::NullGate());
1186 auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate());
1187 currentPhi =
1188 circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), MachineType::I64,
1189 inList.size(), inList.data(), GateType::AnyType());
1190 gateAcc_.NewIn(currentPhi, 0, bb.stateMerge);
1191 for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1192 GateRef ans = NewValueFromPredBB(bb, i, gateAcc_.GetIn(bb.stateMerge, i), reg, acc);
1193 gateAcc_.NewIn(currentPhi, i + 1, ans);
1194 }
1195 } else {
1196 ASSERT(gateAcc_.GetOpCode(bb.stateCurrent) == OpCode::LOOP_BEGIN);
1197 // 2: the number of value inputs and it is in accord with LOOP_BEGIN
1198 currentPhi = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I64,
1199 {bb.stateCurrent, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
1200 auto loopBackValue = NewLoopBackPhi(bb, reg, acc);
1201 auto forwardValue = NewLoopForwardPhi(bb, reg, acc);
1202 gateAcc_.NewIn(currentPhi, 1, forwardValue); // 1: index of forward value input
1203 gateAcc_.NewIn(currentPhi, 2, loopBackValue); // 2: index of loop-back value input
1204 }
1205 bb.phiGate.insert(currentPhi);
1206 }
1207
IsLoopExitValueExists(GateRef loopExit,uint16_t reg,bool acc)1208 bool BytecodeCircuitBuilder::IsLoopExitValueExists(GateRef loopExit, uint16_t reg, bool acc)
1209 {
1210 if (acc) {
1211 return loopExitToAccGate_.count(loopExit) > 0;
1212 } else {
1213 return loopExitToVregGate_.count(std::make_pair(loopExit, reg)) > 0;
1214 }
1215 }
1216
GetLoopExitValue(GateRef loopExit,uint16_t reg,bool acc)1217 GateRef BytecodeCircuitBuilder::GetLoopExitValue(GateRef loopExit, uint16_t reg, bool acc)
1218 {
1219 if (acc) {
1220 return loopExitToAccGate_.at(loopExit);
1221 } else {
1222 return loopExitToVregGate_.at(std::make_pair(loopExit, reg));
1223 }
1224 }
1225
CreateLoopExitValue(GateRef loopExit,uint16_t reg,bool acc,GateRef value)1226 GateRef BytecodeCircuitBuilder::CreateLoopExitValue(GateRef loopExit, uint16_t reg, bool acc, GateRef value)
1227 {
1228 GateRef newPhi = circuit_->NewGate(circuit_->LoopExitValue(), gateAcc_.GetMachineType(value),
1229 {loopExit, value}, gateAcc_.GetGateType(value));
1230 if (acc) {
1231 return loopExitToAccGate_[loopExit] = newPhi;
1232 } else {
1233 auto key = std::make_pair(loopExit, reg);
1234 return loopExitToVregGate_[key] = newPhi;
1235 }
1236 }
1237
NewLoopExitValue(GateRef loopExit,uint16_t reg,bool acc,GateRef value)1238 GateRef BytecodeCircuitBuilder::NewLoopExitValue(GateRef loopExit, uint16_t reg, bool acc, GateRef value)
1239 {
1240 ASSERT(gateAcc_.GetOpCode(loopExit) == OpCode::LOOP_EXIT);
1241 ChunkVector<GateRef> exitList(circuit_->chunk());
1242 while (gateAcc_.GetOpCode(loopExit) == OpCode::LOOP_EXIT) {
1243 exitList.push_back(loopExit);
1244 loopExit = gateAcc_.GetState(loopExit);
1245 }
1246 while (!exitList.empty()) {
1247 GateRef exit = exitList.back();
1248 value = CreateLoopExitValue(exit, reg, acc, value);
1249 exitList.pop_back();
1250 }
1251 return value;
1252 }
1253
ResolveDef(const BytecodeRegion & bb,int32_t bcId,const uint16_t reg,const bool acc)1254 GateRef BytecodeCircuitBuilder::ResolveDef(const BytecodeRegion &bb, int32_t bcId, const uint16_t reg, const bool acc)
1255 {
1256 // Ensure that bcId is not negative
1257 if (bcId == 0) {
1258 return ResolveDef(bb.id, bcId, reg, acc, false);
1259 }
1260 return ResolveDef(bb.id, bcId - 1, reg, acc);
1261 }
1262
1263 // recursive variables renaming algorithm
ResolveDef(const size_t bbId,int32_t bcId,const uint16_t reg,const bool acc,bool needIter)1264 GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId,
1265 const uint16_t reg, const bool acc, bool needIter)
1266 {
1267 auto tmpReg = reg;
1268 // find def-site in bytecodes of basic block
1269 auto ans = Circuit::NullGate();
1270 auto &bb = graph_.at(bbId);
1271 GateType type = GateType::AnyType();
1272 auto tmpAcc = acc;
1273
1274 if (needIter) {
1275 BytecodeIterator iterator(this, bb.start, bcId);
1276 for (iterator.Goto(bcId); !iterator.Done(); --iterator) {
1277 const BytecodeInfo& curInfo = iterator.GetBytecodeInfo();
1278 // original bc use acc as input && current bc use acc as output
1279 bool isTransByAcc = tmpAcc && curInfo.AccOut();
1280 // 0 : the index in vreg-out list
1281 bool isTransByVreg = (!tmpAcc && curInfo.IsOut(tmpReg, 0));
1282 if (isTransByAcc || isTransByVreg) {
1283 if (curInfo.IsMov()) {
1284 tmpAcc = curInfo.AccIn();
1285 if (!curInfo.inputs.empty()) {
1286 ASSERT(!tmpAcc);
1287 ASSERT(curInfo.inputs.size() == 1);
1288 tmpReg = std::get<VirtualRegister>(curInfo.inputs.at(0)).GetId();
1289 }
1290 if (HasTypes()) {
1291 type = typeRecorder_.UpdateType(iterator.Index(), type);
1292 }
1293 } else {
1294 ans = byteCodeToJSGates_.at(iterator.Index()).at(0);
1295 auto oldType = gateAcc_.GetGateType(ans);
1296 if (!type.IsAnyType() && oldType.IsAnyType()) {
1297 typeRecorder_.GetOrUpdatePGOType(tsManager_, gateAcc_.TryGetPcOffset(ans), type);
1298 gateAcc_.SetGateType(ans, type);
1299 }
1300 break;
1301 }
1302 }
1303 if (curInfo.GetOpcode() != EcmaOpcode::RESUMEGENERATOR) {
1304 continue;
1305 }
1306 // New RESTORE_REGISTER HIR, used to restore the register content when processing resume instruction.
1307 // New SAVE_REGISTER HIR, used to save register content when processing suspend instruction.
1308 auto resumeGate = byteCodeToJSGates_.at(iterator.Index()).at(0);
1309 ans = GetExistingRestore(resumeGate, tmpReg);
1310 if (ans != Circuit::NullGate()) {
1311 break;
1312 }
1313 ans = circuit_->NewGate(circuit_->RestoreRegister(tmpReg), MachineType::I64,
1314 { resumeGate }, GateType::AnyType());
1315 SetExistingRestore(resumeGate, tmpReg, ans);
1316 auto saveRegGate = ResolveDef(bbId, iterator.Index() - 1, tmpReg, tmpAcc);
1317 [[maybe_unused]] EcmaOpcode opcode = Bytecodes::GetOpcode(iterator.PeekPrevPc(2)); // 2: prev bc
1318 ASSERT(opcode == EcmaOpcode::SUSPENDGENERATOR_V8 || opcode == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8);
1319 GateRef suspendGate = byteCodeToJSGates_.at(iterator.Index() - 2).at(0); // 2: prev bc
1320 GateRef saveRegs = gateAcc_.GetDep(suspendGate);
1321 gateAcc_.ReplaceValueIn(saveRegs, saveRegGate, tmpReg);
1322 break;
1323 }
1324 }
1325 // find GET_EXCEPTION gate if this is a catch block
1326 if (ans == Circuit::NullGate() && tmpAcc) {
1327 if (!bb.trys.empty()) {
1328 GateRef getExceptionGate = bb.dependCurrent;
1329 ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
1330 ASSERT(getExceptionGate != Circuit::NullGate());
1331 ans = getExceptionGate;
1332 }
1333 }
1334 // find def-site in value selectors of vregs
1335 if (ans == Circuit::NullGate() && !tmpAcc && bb.phi.count(tmpReg)) {
1336 if (!bb.vregToValueGate.count(tmpReg)) {
1337 NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
1338 }
1339 ans = bb.vregToValueGate.at(tmpReg);
1340 }
1341 // find def-site in value selectors of acc
1342 if (ans == Circuit::NullGate() && tmpAcc && bb.phiAcc) {
1343 if (bb.valueSelectorAccGate == Circuit::NullGate()) {
1344 NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
1345 }
1346 ans = bb.valueSelectorAccGate;
1347 }
1348 if (ans == Circuit::NullGate() && IsEntryBlock(bbId)) { // entry block
1349 // find def-site in function args
1350 ASSERT(!tmpAcc);
1351 if (tmpReg == GetEnvVregIdx()) {
1352 ans = gateAcc_.GetInitialEnvGate(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC));
1353 } else if (argAcc_.ArgGateNotExisted(tmpReg)) {
1354 // when GetArgGate fail, return hole
1355 ans = circuit_->GetConstantGate(MachineType::I64,
1356 JSTaggedValue::VALUE_HOLE,
1357 GateType::TaggedValue());
1358 } else {
1359 ans = argAcc_.GetArgGate(tmpReg);
1360 }
1361 return ans;
1362 }
1363 if (EnableLoopOptimization()) {
1364 // find def-site in value selectors of vregs
1365 if (ans == Circuit::NullGate() && !tmpAcc) {
1366 if (!bb.vregToValueGate.count(tmpReg)) {
1367 bb.vregToValueGate[tmpReg] = Circuit::NullGate();
1368 NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
1369 } else if (bb.vregToValueGate.at(tmpReg) == Circuit::NullGate()) {
1370 NewPhi(bb, tmpReg, tmpAcc, bb.vregToValueGate[tmpReg]);
1371 }
1372 ans = bb.vregToValueGate.at(tmpReg);
1373 }
1374 // find def-site in value selectors of acc
1375 if (ans == Circuit::NullGate() && tmpAcc) {
1376 if (bb.valueSelectorAccGate == Circuit::NullGate()) {
1377 NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
1378 }
1379 ans = bb.valueSelectorAccGate;
1380 }
1381 }
1382 if (ans == Circuit::NullGate()) {
1383 // recursively find def-site in dominator block
1384 GateRef res = ResolveDef(bb.iDominator->id, bb.iDominator->end, tmpReg, tmpAcc);
1385 return res;
1386 } else {
1387 // def-site already found
1388 return ans;
1389 }
1390 }
1391
BuildCircuit()1392 void BytecodeCircuitBuilder::BuildCircuit()
1393 {
1394 // create arg gates array
1395 BuildCircuitArgs();
1396 CollectPredsInfo();
1397 // build states sub-circuit of each block
1398 BuildSubCircuit();
1399 // verification of soundness of CFG
1400 for (auto &bb: graph_) {
1401 if (bb.isDead) {
1402 continue;
1403 }
1404 ASSERT(bb.statePredIndex == bb.numOfStatePreds);
1405 ASSERT(bb.loopBackIndex == bb.numOfLoopBacks);
1406 if (bb.numOfLoopBacks) {
1407 ASSERT(bb.forwardIndex == bb.numOfStatePreds - bb.numOfLoopBacks);
1408 }
1409 // resolve def-site of virtual regs and set all value inputs
1410 EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1411 auto &iterator = bb.GetBytecodeIterator();
1412 const auto bcIndex = iterator.Index();
1413 const auto bbIndex = bb.id;
1414 GateRef gate = GetGateByBcIndex(bcIndex);
1415 if (gate == Circuit::NullGate()) {
1416 return true;
1417 }
1418 if (gateAcc_.IsConstant(gate)) {
1419 return true;
1420 }
1421
1422 auto type = typeRecorder_.GetType(bcIndex);
1423 gateAcc_.SetGateType(gate, type);
1424 auto pgoType = typeRecorder_.GetOrUpdatePGOType(tsManager_, gateAcc_.TryGetPcOffset(gate), type);
1425 gateAcc_.TrySetPGOType(gate, pgoType);
1426
1427 auto valueCount = gateAcc_.GetInValueCount(gate);
1428 [[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
1429 [[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
1430 // RETURNUNDEFINED has value input, but not from acc
1431 ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
1432 ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
1433 auto valueStarts = gateAcc_.GetInValueStarts(gate);
1434 for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
1435 auto inIdx = valueIdx + valueStarts;
1436 if (!gateAcc_.IsInGateNull(gate, inIdx)) {
1437 continue;
1438 }
1439 if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEOBJECTWITHEXCLUDEDKEYS_IMM8_V8_V8) {
1440 GateRef depIn = gateAcc_.GetDep(gate);
1441 size_t depCount = gateAcc_.GetNumValueIn(depIn);
1442 GateRef defVreg = Circuit::NullGate();
1443 for (size_t idx = 0; idx < depCount; idx++) {
1444 defVreg = ResolveDef(bb, bcIndex, idx, false);
1445 gateAcc_.ReplaceValueIn(depIn, defVreg, idx);
1446 }
1447 }
1448 if (valueIdx < bytecodeInfo.inputs.size()) {
1449 auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
1450 GateRef defVreg = Circuit::NullGate();
1451 if (IsFirstBCEnvIn(bbIndex, bcIndex, vregId)) {
1452 defVreg = gateAcc_.GetInitialEnvGate(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC));
1453 } else {
1454 defVreg = ResolveDef(bb, bcIndex, vregId, false);
1455 }
1456 gateAcc_.NewIn(gate, inIdx, defVreg);
1457 } else {
1458 GateRef defAcc = ResolveDef(bb, bcIndex, 0, true);
1459 if (!Bytecodes::IsCallOp(bytecodeInfo.GetOpcode())) {
1460 gateAcc_.NewIn(gate, inIdx, defAcc);
1461 continue;
1462 }
1463 auto oldGt = gateAcc_.GetGateType(defAcc).GetGTRef();
1464 GateType callTargetType = typeRecorder_.GetCallTargetType(bcIndex);
1465 if (!tsManager_->MethodOffsetIsVaild(oldGt) && !callTargetType.IsAnyType()) {
1466 gateAcc_.SetGateType(defAcc, callTargetType);
1467 }
1468 gateAcc_.NewIn(gate, inIdx, defAcc);
1469 }
1470 }
1471 return true;
1472 });
1473 }
1474
1475 if (IsTypeLoweringEnabled()) {
1476 frameStateBuilder_.BuildFrameState();
1477 }
1478
1479 gateAcc_.EliminateRedundantPhi();
1480
1481 if (IsLogEnabled()) {
1482 PrintGraph("Bytecode2Gate");
1483 LOG_COMPILER(INFO) << "\033[34m" << "============= "
1484 << "After bytecode2circuit lowering ["
1485 << methodName_ << "]"
1486 << " =============" << "\033[0m";
1487 circuit_->PrintAllGatesWithBytecode();
1488 LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
1489 }
1490 }
1491
GetExistingRestore(GateRef resumeGate,uint16_t tmpReg) const1492 GateRef BytecodeCircuitBuilder::GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const
1493 {
1494 auto pr = std::make_pair(resumeGate, tmpReg);
1495 if (resumeRegToRestore_.count(pr)) {
1496 return resumeRegToRestore_.at(pr);
1497 }
1498 return Circuit::NullGate();
1499 }
1500
SetExistingRestore(GateRef resumeGate,uint16_t tmpReg,GateRef restoreGate)1501 void BytecodeCircuitBuilder::SetExistingRestore(GateRef resumeGate, uint16_t tmpReg, GateRef restoreGate)
1502 {
1503 auto pr = std::make_pair(resumeGate, tmpReg);
1504 resumeRegToRestore_[pr] = restoreGate;
1505 }
1506
CollectLoopBack()1507 void BytecodeCircuitBuilder::CollectLoopBack()
1508 {
1509 auto size = GetBasicBlockCount();
1510 ChunkVector<size_t> workList(circuit_->chunk());
1511 ChunkVector<VisitState> visitState(circuit_->chunk());
1512 visitState.resize(size, VisitState::UNVISITED);
1513 size_t entryId = 0; // entry id
1514 workList.emplace_back(entryId);
1515 while (!workList.empty()) {
1516 size_t bbId = workList.back();
1517 auto &bb = GetBasicBlockById(bbId);
1518 if (visitState[bbId] == VisitState::UNVISITED) {
1519 dfsList_.emplace_back(bbId);
1520 visitState[bbId] = VisitState::PENDING;
1521 }
1522 bool allVisited = true;
1523
1524 for (const auto &succBlock: bb.succs) {
1525 size_t succId = succBlock->id;
1526 if (visitState[succId] == VisitState::UNVISITED) {
1527 // dfs
1528 workList.emplace_back(succId);
1529 allVisited = false;
1530 break;
1531 } else if (visitState[succId] == VisitState::PENDING) {
1532 // back edge
1533 CountLoopBackEdge(bbId, succId);
1534 }
1535 }
1536
1537 for (const auto &succBlock: bb.catchs) {
1538 size_t succId = succBlock->id;
1539 if (visitState[succId] == VisitState::UNVISITED) {
1540 // dfs
1541 workList.emplace_back(succId);
1542 allVisited = false;
1543 break;
1544 } else if (visitState[succId] == VisitState::PENDING) {
1545 // back edge
1546 CountLoopBackEdge(bbId, succId);
1547 }
1548 }
1549 if (allVisited) {
1550 workList.pop_back();
1551 visitState[bbId] = VisitState::VISITED;
1552 }
1553 }
1554 }
1555
CountLoopBackEdge(size_t fromId,size_t toId)1556 void BytecodeCircuitBuilder::CountLoopBackEdge(size_t fromId, size_t toId)
1557 {
1558 auto &toBlock = GetBasicBlockById(toId);
1559 if (toBlock.numOfLoopBacks == 0) {
1560 loopHeads_.emplace_back(std::make_pair(0, toId));
1561 }
1562 toBlock.loopbackBlocks.insert(fromId);
1563 toBlock.numOfLoopBacks = toBlock.loopbackBlocks.size();
1564 }
1565
ComputeLoopDepth(size_t loopHead)1566 void BytecodeCircuitBuilder::ComputeLoopDepth(size_t loopHead)
1567 {
1568 ChunkSet<size_t> visited (circuit_->chunk());
1569 ChunkQueue<size_t> workList (circuit_->chunk());
1570 visited.insert(loopHead);
1571 auto &headBB = GetBasicBlockById(loopHead);
1572 headBB.loopDepth++;
1573 for (auto loopBack : headBB.loopbackBlocks) {
1574 workList.push(loopBack);
1575 }
1576 while (!workList.empty()) {
1577 size_t cur = workList.front();
1578 workList.pop();
1579 if (visited.count(cur) > 0) {
1580 continue;
1581 }
1582 visited.insert(cur);
1583 auto &curBB = GetBasicBlockById(cur);
1584 curBB.loopDepth++;
1585 for (const auto& pred : curBB.preds) {
1586 workList.push(pred->id);
1587 }
1588 for (const auto& pred : curBB.trys) {
1589 workList.push(pred->id);
1590 }
1591 }
1592 loopSize_ = visited.size();
1593 }
1594
PrintGraph(const char * title)1595 void BytecodeCircuitBuilder::PrintGraph(const char* title)
1596 {
1597 LOG_COMPILER(INFO) << "======================== " << title << " ========================";
1598 for (size_t i = 0; i < graph_.size(); i++) {
1599 BytecodeRegion& bb = graph_[i];
1600 if (bb.isDead) {
1601 LOG_COMPILER(INFO) << "B" << bb.id << ": ;preds= invalid BB";
1602 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1603 << std::to_string(bb.end) << ")";
1604 continue;
1605 }
1606 std::string log("B" + std::to_string(bb.id) + ": ;preds= ");
1607 for (size_t k = 0; k < bb.preds.size(); ++k) {
1608 log += std::to_string(bb.preds[k]->id) + ", ";
1609 }
1610 LOG_COMPILER(INFO) << log;
1611 if (IsEntryBlock(bb.id)) {
1612 LOG_COMPILER(INFO) << "\tBytecodePC: Empty";
1613 } else {
1614 LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1615 << std::to_string(bb.end) << ")";
1616 }
1617
1618 std::string log1("\tSucces: ");
1619 for (size_t j = 0; j < bb.succs.size(); j++) {
1620 log1 += std::to_string(bb.succs[j]->id) + ", ";
1621 }
1622 LOG_COMPILER(INFO) << log1;
1623
1624 for (size_t j = 0; j < bb.catchs.size(); j++) {
1625 LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catchs[j]->start) << ", "
1626 << std::to_string(bb.catchs[j]->end) << ")";
1627 }
1628
1629 std::string log2("\tTrys: ");
1630 for (auto tryBlock: bb.trys) {
1631 log2 += std::to_string(tryBlock->id) + " , ";
1632 }
1633 LOG_COMPILER(INFO) << log2;
1634
1635 std::string log3 = "\tDom: ";
1636 for (size_t j = 0; j < bb.immDomBlocks.size(); j++) {
1637 log3 += "B" + std::to_string(bb.immDomBlocks[j]->id) + std::string(", ");
1638 }
1639 LOG_COMPILER(INFO) << log3;
1640
1641 if (bb.iDominator) {
1642 LOG_COMPILER(INFO) << "\tIDom B" << bb.iDominator->id;
1643 }
1644
1645 std::string log4("\tDom Frontiers: ");
1646 for (const auto &frontier: bb.domFrontiers) {
1647 log4 += std::to_string(frontier->id) + " , ";
1648 }
1649 LOG_COMPILER(INFO) << log4;
1650
1651 std::string log5("\tPhi: ");
1652 for (auto variable: bb.phi) {
1653 log5 += std::to_string(variable) + " , ";
1654 }
1655 LOG_COMPILER(INFO) << log5;
1656
1657 std::string log6("\tLoop Depth: ");
1658 log6 += std::to_string(bb.loopDepth);
1659 LOG_COMPILER(INFO) << log6;
1660
1661 PrintBytecodeInfo(bb);
1662 LOG_COMPILER(INFO) << "";
1663 }
1664 }
1665
PrintBytecodeInfo(BytecodeRegion & bb)1666 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
1667 {
1668 if (bb.isDead) {
1669 return;
1670 }
1671 if (IsEntryBlock(bb.id)) {
1672 LOG_COMPILER(INFO) << "\tBytecode[] = Empty";
1673 return;
1674 }
1675 LOG_COMPILER(INFO) << "\tBytecode[] = ";
1676 EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1677 auto &iterator = bb.GetBytecodeIterator();
1678 std::string log;
1679 log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
1680 log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
1681 if (bytecodeInfo.AccIn()) {
1682 log += "acc,";
1683 }
1684 for (const auto &in: bytecodeInfo.inputs) {
1685 if (std::holds_alternative<VirtualRegister>(in)) {
1686 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
1687 }
1688 }
1689 log += "], Out=[";
1690 if (bytecodeInfo.AccOut()) {
1691 log += "acc,";
1692 }
1693 for (const auto &out: bytecodeInfo.vregOut) {
1694 log += std::to_string(out) + ",";
1695 }
1696 log += "] >";
1697 LOG_COMPILER(INFO) << log;
1698
1699 auto gate = GetGateByBcIndex(iterator.Index());
1700 if (gate != Circuit::NullGate()) {
1701 this->gateAcc_.ShortPrint(gate);
1702 }
1703 return true;
1704 });
1705 }
1706 } // namespace panda::ecmascript::kungfu
1707