• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentPhi)
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