• 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 - 1;  // 1: end
40     BytecodeIterator iterator(this, 0, end);
41 
42     infoData_.resize(size);
43     byteCodeToJSGate_.resize(size, Circuit::NullGate());
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         BytecodeInfo::InitBytecodeInfo(this, info, pc);
51         CollectRegionInfo(index);
52     }
53 }
54 
GetJumpOffset(uint32_t bcIndex) const55 int32_t BytecodeCircuitBuilder::GetJumpOffset(uint32_t bcIndex) const
56 {
57     auto pc = GetPCByIndex(bcIndex);
58     auto &info = GetBytecodeInfo(bcIndex);
59     int32_t offset = 0;
60     switch (info.GetOpcode()) {
61         case EcmaOpcode::JEQZ_IMM8:
62         case EcmaOpcode::JNEZ_IMM8:
63         case EcmaOpcode::JMP_IMM8:
64             offset = static_cast<int8_t>(READ_INST_8_0());
65             break;
66         case EcmaOpcode::JNEZ_IMM16:
67         case EcmaOpcode::JEQZ_IMM16:
68         case EcmaOpcode::JMP_IMM16:
69             offset = static_cast<int16_t>(READ_INST_16_0());
70             break;
71         case EcmaOpcode::JMP_IMM32:
72         case EcmaOpcode::JNEZ_IMM32:
73         case EcmaOpcode::JEQZ_IMM32:
74             offset = static_cast<int32_t>(READ_INST_32_0());
75             break;
76         case EcmaOpcode::RETURN:
77         case EcmaOpcode::RETURNUNDEFINED:
78         case EcmaOpcode::SUSPENDGENERATOR_V8:
79         case EcmaOpcode::DEPRECATED_SUSPENDGENERATOR_PREF_V8_V8:
80             offset = -(static_cast<int32_t>(pc - GetFirstPC()));
81             break;
82         default:
83             LOG_ECMA(FATAL) << "this branch is unreachable";
84             UNREACHABLE();
85             break;
86     }
87     return offset;
88 }
89 
CollectRegionInfo(uint32_t bcIndex)90 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
91 {
92     auto pc = pcOffsets_[bcIndex];
93     auto &info = infoData_[bcIndex];
94     int32_t offset = 0;
95     if (info.IsJump()) {
96         switch (info.GetOpcode()) {
97             case EcmaOpcode::JEQZ_IMM8:
98             case EcmaOpcode::JNEZ_IMM8:
99             case EcmaOpcode::JMP_IMM8:
100                 offset = static_cast<int8_t>(READ_INST_8_0());
101                 break;
102             case EcmaOpcode::JNEZ_IMM16:
103             case EcmaOpcode::JEQZ_IMM16:
104             case EcmaOpcode::JMP_IMM16:
105                 offset = static_cast<int16_t>(READ_INST_16_0());
106                 break;
107             case EcmaOpcode::JMP_IMM32:
108             case EcmaOpcode::JNEZ_IMM32:
109             case EcmaOpcode::JEQZ_IMM32:
110                 offset = static_cast<int32_t>(READ_INST_32_0());
111                 break;
112             default:
113                 UNREACHABLE();
114                 break;
115         }
116         auto nextIndex = bcIndex + 1; // 1: next pc
117         auto targetIndex = FindBcIndexByPc(pc + offset);
118         // condition branch current basic block end
119         if (info.IsCondJump()) {
120             regionsInfo_.InsertSplit(nextIndex);
121             regionsInfo_.InsertJump(targetIndex, bcIndex, false);
122         } else {
123             regionsInfo_.InsertHead(nextIndex);
124             regionsInfo_.InsertJump(targetIndex, bcIndex, true);
125         }
126     } else if (info.IsReturn() || info.IsThrow()) {
127         if (bcIndex != GetLastBcIndex()) {
128             auto nextIndex = bcIndex + 1; // 1: next pc
129             regionsInfo_.InsertHead(nextIndex);
130         }
131     }
132 }
133 
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)134 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
135 {
136     panda_file::MethodDataAccessor mda(*pf_, method_->GetMethodId());
137     panda_file::CodeDataAccessor cda(*pf_, mda.GetCodeId().value());
138 
139     cda.EnumerateTryBlocks([this, &byteCodeException](
140         panda_file::CodeDataAccessor::TryBlock &tryBlock) {
141         auto tryStartOffset = tryBlock.GetStartPc();
142         auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
143 
144         auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
145         auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
146         // skip try blocks with same pc in start and end label
147         if (tryStartPc == tryEndPc) {
148             return true;
149         }
150 
151         auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
152         regionsInfo_.InsertSplit(tryStartBcIndex);
153         if (tryEndPc <= GetLastPC()) {
154             auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
155             regionsInfo_.InsertSplit(tryEndBcIndex);
156         }
157         byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
158         tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
159             auto pcOffset = catchBlock.GetHandlerPc();
160             auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
161             auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
162             regionsInfo_.InsertHead(catchBlockBcIndex);
163             // try block associate catch block
164             byteCodeException.back().catchs.emplace_back(catchBlockPc);
165             return true;
166         });
167         return true;
168     });
169 }
170 
BuildRegions(const ExceptionInfo & byteCodeException)171 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
172 {
173     auto &items = regionsInfo_.GetBlockItems();
174     auto blockSize = items.size();
175     graph_.resize(blockSize);
176     // build basic block
177     size_t blockId = 0;
178     for (const auto &item : items) {
179         auto &curBlock = GetBasicBlockById(blockId);
180         curBlock.id = blockId;
181         curBlock.start = item.GetStartBcIndex();
182         if (blockId != 0) {
183             auto &prevBlock = graph_[blockId - 1];
184             prevBlock.end = curBlock.start - 1;
185             prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
186             // fall through
187             if (!item.IsHeadBlock()) {
188                 curBlock.preds.emplace_back(&prevBlock);
189                 prevBlock.succs.emplace_back(&curBlock);
190             }
191         }
192         blockId++;
193     }
194     auto &lastBlock = graph_[blockId - 1]; // 1: last block
195     lastBlock.end = GetLastBcIndex();
196     lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
197 
198     auto &splitItems = regionsInfo_.GetSplitItems();
199     for (const auto &item : splitItems) {
200         auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
201         auto &curBlock = GetBasicBlockById(curIndex);
202         auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
203         auto &predBlock = GetBasicBlockById(predIndex);
204         curBlock.preds.emplace_back(&predBlock);
205         predBlock.succs.emplace_back(&curBlock);
206     }
207 
208     if (byteCodeException.size() != 0) {
209         BuildCatchBlocks(byteCodeException);
210     }
211     if (IsLogEnabled()) {
212         PrintGraph("Build Basic Block");
213     }
214     ComputeDominatorTree();
215 }
216 
BuildCatchBlocks(const ExceptionInfo & byteCodeException)217 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
218 {
219     // try catch block associate
220     for (size_t i = 0; i < graph_.size(); i++) {
221         auto &bb = graph_[i];
222         auto startIndex = bb.start;
223         const auto pc = pcOffsets_[startIndex];
224         for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
225             if (pc < it->startPc || pc >= it->endPc) {
226                 continue;
227             }
228             // try block interval
229             const auto &catchs = it->catchs; // catchs start pc
230             for (size_t j = i + 1; j < graph_.size(); j++) {
231                 auto &catchBB = graph_[j];
232                 const auto catchStart = pcOffsets_[catchBB.start];
233                 if (std::find(catchs.cbegin(), catchs.cend(), catchStart) != catchs.cend()) {
234                     bb.catchs.insert(bb.catchs.cbegin(), &catchBB);
235                     bb.succs.emplace_back(&catchBB);
236                     catchBB.preds.emplace_back(&bb);
237                 }
238             }
239         }
240 
241         // When there are multiple catch blocks in the current block, the set of catch blocks
242         // needs to be sorted to satisfy the order of execution of catch blocks.
243         bb.SortCatches();
244     }
245 }
246 
ComputeDominatorTree()247 void BytecodeCircuitBuilder::ComputeDominatorTree()
248 {
249     // Construct graph backward order
250     std::unordered_map<size_t, size_t> bbIdToDfsTimestamp;
251     std::unordered_map<size_t, size_t> dfsFatherIdx;
252     std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
253     std::vector<size_t> basicBlockList;
254     size_t timestamp = 0;
255     std::deque<size_t> pendingList;
256     std::vector<size_t> visited(graph_.size(), 0);
257     auto basicBlockId = graph_[0].id;
258     visited[graph_[0].id] = 1;
259     pendingList.emplace_back(basicBlockId);
260     while (!pendingList.empty()) {
261         size_t curBlockId = pendingList.back();
262         pendingList.pop_back();
263         basicBlockList.emplace_back(curBlockId);
264         bbIdToDfsTimestamp[curBlockId] = timestamp++;
265         for (const auto &succBlock: graph_[curBlockId].succs) {
266             if (visited[succBlock->id] == 0) {
267                 visited[succBlock->id] = 1;
268                 pendingList.emplace_back(succBlock->id);
269                 dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp[curBlockId];
270             }
271         }
272     }
273 
274     for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
275         bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
276     }
277     RemoveDeadRegions(bbIdToDfsTimestamp);
278 
279     std::vector<size_t> immDom(basicBlockList.size()); // immediate dominator with dfs order index
280     std::vector<size_t> semiDom(basicBlockList.size());
281     std::vector<size_t> realImmDom(graph_.size()); // immediate dominator with real index
282     std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
283     {
284         std::vector<size_t> parent(basicBlockList.size());
285         std::iota(parent.begin(), parent.end(), 0);
286         std::vector<size_t> minIdx(basicBlockList.size());
287         std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
288             if (parent[idx] == idx) return idx;
289             size_t unionFindSetRoot = unionFind(parent[idx]);
290             if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
291                 minIdx[idx] = minIdx[parent[idx]];
292             }
293             return parent[idx] = unionFindSetRoot;
294         };
295         auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
296             size_t parentFatherIdx = unionFind(fatherIdx);
297             size_t parentSonIdx = unionFind(sonIdx);
298             parent[parentSonIdx] = parentFatherIdx;
299         };
300         std::iota(semiDom.begin(), semiDom.end(), 0);
301         semiDom[0] = semiDom.size();
302         for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
303             for (const auto &preBlock : graph_[basicBlockList[idx]].preds) {
304                 if (bbDfsTimestampToIdx[preBlock->id] < idx) {
305                     semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
306                 } else {
307                     unionFind(bbDfsTimestampToIdx[preBlock->id]);
308                     semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
309                 }
310             }
311             for (const auto & succDomIdx : semiDomTree[idx]) {
312                 unionFind(succDomIdx);
313                 if (idx == semiDom[minIdx[succDomIdx]]) {
314                     immDom[succDomIdx] = idx;
315                 } else {
316                     immDom[succDomIdx] = minIdx[succDomIdx];
317                 }
318             }
319             minIdx[idx] = idx;
320             merge(dfsFatherIdx[basicBlockList[idx]], idx);
321             semiDomTree[semiDom[idx]].emplace_back(idx);
322         }
323         for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
324             if (immDom[idx] != semiDom[idx]) {
325                 immDom[idx] = immDom[immDom[idx]];
326             }
327             realImmDom[basicBlockList[idx]] = basicBlockList[immDom[idx]];
328         }
329         semiDom[0] = 0;
330     }
331 
332     if (IsLogEnabled()) {
333         PrintGraph("Computed Dom Trees");
334     }
335 
336     BuildImmediateDominator(realImmDom);
337 }
338 
BuildImmediateDominator(const std::vector<size_t> & immDom)339 void BytecodeCircuitBuilder::BuildImmediateDominator(const std::vector<size_t> &immDom)
340 {
341     graph_[0].iDominator = &graph_[0];
342     for (size_t i = 1; i < immDom.size(); i++) {
343         auto dominatedBlock = &graph_[i];
344         if (dominatedBlock->isDead) {
345             continue;
346         }
347         auto immDomBlock = &graph_[immDom[i]];
348         dominatedBlock->iDominator = immDomBlock;
349     }
350 
351     for (auto &block : graph_) {
352         if (block.isDead) {
353             continue;
354         }
355         if (block.iDominator->id != block.id) {
356             block.iDominator->immDomBlocks.emplace_back(&block);
357         }
358     }
359 
360     ComputeDomFrontiers(immDom);
361     InsertPhi();
362     UpdateCFG();
363     BuildCircuit();
364 }
365 
ComputeDomFrontiers(const std::vector<size_t> & immDom)366 void BytecodeCircuitBuilder::ComputeDomFrontiers(const std::vector<size_t> &immDom)
367 {
368     std::vector<std::set<BytecodeRegion *>> domFrontiers(immDom.size());
369     for (auto &bb : graph_) {
370         if (bb.isDead) {
371             continue;
372         }
373         if (bb.preds.size() < 2) { // 2: pred num
374             continue;
375         }
376         for (size_t i = 0; i < bb.preds.size(); i++) {
377             auto runner = bb.preds[i];
378             while (runner->id != immDom[bb.id]) {
379                 domFrontiers[runner->id].insert(&bb);
380                 runner = &graph_[immDom[runner->id]];
381             }
382         }
383     }
384 
385     for (size_t i = 0; i < domFrontiers.size(); i++) {
386         for (auto iter = domFrontiers[i].cbegin(); iter != domFrontiers[i].cend(); iter++) {
387             graph_[i].domFrontiers.emplace_back(*iter);
388         }
389     }
390 }
391 
RemoveDeadRegions(const std::unordered_map<size_t,size_t> & bbIdToDfsTimestamp)392 void BytecodeCircuitBuilder::RemoveDeadRegions(const std::unordered_map<size_t, size_t> &bbIdToDfsTimestamp)
393 {
394     for (auto &block: graph_) {
395         std::vector<BytecodeRegion *> newPreds;
396         for (auto &bb : block.preds) {
397             if (bbIdToDfsTimestamp.count(bb->id)) {
398                 newPreds.emplace_back(bb);
399             }
400         }
401         block.preds = newPreds;
402     }
403 
404     for (auto &block : graph_) {
405         block.isDead = !bbIdToDfsTimestamp.count(block.id);
406         if (block.isDead) {
407             block.succs.clear();
408         }
409     }
410 }
411 
InsertPhi()412 void BytecodeCircuitBuilder::InsertPhi()
413 {
414     std::unordered_map<uint16_t, std::set<size_t>> defsitesInfo; // <vreg, bbs>
415     for (auto &bb : graph_) {
416         if (bb.isDead) {
417             continue;
418         }
419         EnumerateBlock(bb, [this, &defsitesInfo, &bb]
420             (const BytecodeInfo &bytecodeInfo) -> bool {
421             if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
422                 auto numVRegs = GetNumberVRegsWithEnv();
423                 for (size_t i = 0; i < numVRegs; i++) {
424                     defsitesInfo[i].insert(bb.id);
425                 }
426             }
427             for (const auto &vreg: bytecodeInfo.vregOut) {
428                 defsitesInfo[vreg].insert(bb.id);
429             }
430             return true;
431         });
432     }
433 
434     // handle phi generated from multiple control flow in the same source block
435     InsertExceptionPhi(defsitesInfo);
436 
437     for (const auto&[variable, defsites] : defsitesInfo) {
438         std::queue<uint16_t> workList;
439         for (auto blockId: defsites) {
440             workList.push(blockId);
441         }
442         while (!workList.empty()) {
443             auto currentId = workList.front();
444             workList.pop();
445             for (auto &block : graph_[currentId].domFrontiers) {
446                 if (!block->phi.count(variable)) {
447                     block->phi.insert(variable);
448                     if (!defsitesInfo[variable].count(block->id)) {
449                         workList.push(block->id);
450                     }
451                 }
452             }
453         }
454     }
455 
456     if (IsLogEnabled()) {
457         PrintGraph("Inserted Phis");
458     }
459 }
460 
InsertExceptionPhi(std::unordered_map<uint16_t,std::set<size_t>> & defsitesInfo)461 void BytecodeCircuitBuilder::InsertExceptionPhi(std::unordered_map<uint16_t, std::set<size_t>> &defsitesInfo)
462 {
463     // handle try catch defsite
464     for (auto &bb : graph_) {
465         if (bb.isDead) {
466             continue;
467         }
468         if (bb.catchs.size() == 0) {
469             continue;
470         }
471         std::set<size_t> vregs;
472         EnumerateBlock(bb, [this, &vregs]
473         (const BytecodeInfo &bytecodeInfo) -> bool {
474             if (bytecodeInfo.IsBc(EcmaOpcode::RESUMEGENERATOR)) {
475                 auto numVRegs = GetNumberVRegsWithEnv();
476                 for (size_t i = 0; i < numVRegs; i++) {
477                     vregs.insert(i);
478                 }
479                 return false;
480             }
481             for (const auto &vreg: bytecodeInfo.vregOut) {
482                 vregs.insert(vreg);
483             }
484             return true;
485         });
486 
487         for (auto &vreg : vregs) {
488             defsitesInfo[vreg].insert(bb.catchs.at(0)->id);
489             bb.catchs.at(0)->phi.insert(vreg);
490         }
491     }
492 }
493 
494 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()495 void BytecodeCircuitBuilder::UpdateCFG()
496 {
497     for (auto &bb: graph_) {
498         if (bb.isDead) {
499             continue;
500         }
501         bb.preds.clear();
502         bb.trys.clear();
503         std::vector<BytecodeRegion *> newSuccs;
504         for (const auto &succ: bb.succs) {
505             if (std::count(bb.catchs.cbegin(), bb.catchs.cend(), succ)) {
506                 continue;
507             }
508             newSuccs.emplace_back(succ);
509         }
510         bb.succs = newSuccs;
511     }
512     for (auto &bb: graph_) {
513         if (bb.isDead) {
514             continue;
515         }
516         for (auto &succ: bb.succs) {
517             succ->preds.emplace_back(&bb);
518         }
519         for (auto &catchBlock: bb.catchs) {
520             catchBlock->trys.emplace_back(&bb);
521         }
522     }
523 }
524 
525 // build circuit
BuildCircuitArgs()526 void BytecodeCircuitBuilder::BuildCircuitArgs()
527 {
528     argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
529     argAcc_.NewCommonArg(CommonArgIdx::LEXENV, MachineType::I64, GateType::TaggedValue());
530     argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
531     auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
532     const size_t actualNumArgs = argAcc_.GetActualNumArgs();
533     // new actual argument gates
534     for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
535         argAcc_.NewArg(argIdx);
536     }
537     argAcc_.CollectArgs();
538     if (HasTypes()) {
539         argAcc_.FillArgsGateType(&typeRecorder_);
540     }
541 }
542 
ShouldBeDead(BytecodeRegion & curBlock)543 bool BytecodeCircuitBuilder::ShouldBeDead(BytecodeRegion &curBlock)
544 {
545     auto isDead = false;
546     for (auto bbPred : curBlock.preds) {
547         if (!bbPred->isDead) {
548             return false;
549         }
550         isDead = true;
551     }
552     for (auto bbTry : curBlock.trys) {
553         if (!bbTry->isDead) {
554             return false;
555         }
556         isDead = true;
557     }
558     return isDead;
559 }
560 
CollectPredsInfo()561 void BytecodeCircuitBuilder::CollectPredsInfo()
562 {
563     for (auto &bb: graph_) {
564         if (bb.isDead) {
565             continue;
566         }
567         bb.numOfStatePreds = 0;
568     }
569     // get number of expanded state predicates of each block
570     // one block-level try catch edge may correspond to multiple bytecode-level edges
571     for (auto &bb: graph_) {
572         if (bb.isDead) {
573             continue;
574         }
575         if (ShouldBeDead(bb)) {
576             bb.UpdateTryCatchInfoForDeadBlock();
577             bb.isDead = true;
578             continue;
579         }
580         bool noThrow = true;
581         EnumerateBlock(bb, [&noThrow, &bb]
582         (const BytecodeInfo &bytecodeInfo) -> bool {
583             if (bytecodeInfo.IsGeneral()) {
584                 noThrow = false;
585                 if (!bb.catchs.empty()) {
586                     bb.catchs.at(0)->numOfStatePreds++;
587                 }
588             }
589             if (bytecodeInfo.IsCondJump() && bb.succs.size() == 1) {
590                 ASSERT(bb.succs[0]->id == bb.id + 1);
591                 bb.succs[0]->numOfStatePreds++;
592             }
593             return true;
594         });
595         bb.UpdateRedundantTryCatchInfo(noThrow);
596         bb.UpdateTryCatchInfoIfNoThrow(noThrow);
597         for (auto &succ: bb.succs) {
598             succ->numOfStatePreds++;
599         }
600     }
601     // collect loopback edges
602     std::vector<VisitState> visitState(graph_.size(), VisitState::UNVISITED);
603     std::function<void(size_t)> dfs = [&](size_t bbId) -> void {
604         visitState[bbId] = VisitState::PENDING;
605         std::vector<BytecodeRegion *> merge;
606         merge.insert(merge.end(), graph_[bbId].succs.begin(), graph_[bbId].succs.end());
607         merge.insert(merge.end(), graph_[bbId].catchs.begin(), graph_[bbId].catchs.end());
608         auto it = merge.crbegin();
609         while (it != merge.crend()) {
610             auto succBlock = *it;
611             it++;
612             if (visitState[succBlock->id] == VisitState::UNVISITED) {
613                 dfs(succBlock->id);
614             } else {
615                 if (visitState[succBlock->id] == VisitState::PENDING) {
616                     graph_[succBlock->id].loopbackBlocks.insert(bbId);
617                 }
618             }
619         }
620         visitState[bbId] = VisitState::VISITED;
621     };
622     dfs(graph_[0].id);
623     for (auto &bb: graph_) {
624         if (bb.isDead) {
625             continue;
626         }
627         bb.phiAcc = (bb.numOfStatePreds > 1) || (!bb.trys.empty());
628         bb.numOfLoopBacks = bb.loopbackBlocks.size();
629     }
630 }
631 
NewMerge(GateRef & state,GateRef & depend,size_t numOfIns)632 void BytecodeCircuitBuilder::NewMerge(GateRef &state, GateRef &depend, size_t numOfIns)
633 {
634     state = circuit_->NewGate(circuit_->Merge(numOfIns),
635                               std::vector<GateRef>(numOfIns, Circuit::NullGate()));
636     depend = circuit_->NewGate(circuit_->DependSelector(numOfIns),
637                                std::vector<GateRef>(numOfIns + 1, Circuit::NullGate()));
638     gateAcc_.NewIn(depend, 0, state);
639 }
640 
NewLoopBegin(BytecodeRegion & bb)641 void BytecodeCircuitBuilder::NewLoopBegin(BytecodeRegion &bb)
642 {
643     if (bb.id == 0 && bb.numOfStatePreds == 1) {
644         bb.mergeForwardEdges = circuit_->NewGate(circuit_->Merge(bb.numOfStatePreds),
645             std::vector<GateRef>(bb.numOfStatePreds,
646                                  circuit_->GetStateRoot()));
647         bb.depForward = circuit_->NewGate(circuit_->DependSelector(bb.numOfStatePreds),
648             std::vector<GateRef>(bb.numOfStatePreds + 1, Circuit::NullGate()));
649         gateAcc_.NewIn(bb.depForward, 0, bb.mergeForwardEdges);
650         gateAcc_.NewIn(bb.depForward, 1, circuit_->GetDependRoot());
651     } else {
652         NewMerge(bb.mergeForwardEdges, bb.depForward, bb.numOfStatePreds - bb.numOfLoopBacks);
653     }
654     NewMerge(bb.mergeLoopBackEdges, bb.depLoopBack, bb.numOfLoopBacks);
655     auto loopBack = circuit_->NewGate(circuit_->LoopBack(),
656         { bb.mergeLoopBackEdges });
657     bb.stateStart = circuit_->NewGate(circuit_->LoopBegin(),
658         { bb.mergeForwardEdges, loopBack });
659     // 2: the number of depend inputs and it is in accord with LOOP_BEGIN
660     bb.dependStart = circuit_->NewGate(circuit_->DependSelector(2),
661         { bb.stateStart, bb.depForward, bb.depLoopBack });
662 }
663 
BuildBlockCircuitHead()664 void BytecodeCircuitBuilder::BuildBlockCircuitHead()
665 {
666     for (auto &bb: graph_) {
667         if (bb.isDead) {
668             continue;
669         }
670         if (bb.numOfStatePreds == 0) {
671             bb.stateStart = circuit_->GetStateRoot();
672             bb.dependStart = circuit_->GetDependRoot();
673         } else if (bb.numOfLoopBacks > 0) {
674             NewLoopBegin(bb);
675         } else {
676             NewMerge(bb.stateStart, bb.dependStart, bb.numOfStatePreds);
677         }
678     }
679 }
680 
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)681 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
682     const BytecodeInfo &info, const GateMetaData *meta)
683 {
684     auto numValues = meta->GetNumIns();
685     const size_t length = meta->GetInValueStarts();
686     std::vector<GateRef> inList(numValues, Circuit::NullGate());
687     auto inputSize = info.inputs.size();
688     for (size_t i = 0; i < inputSize; i++) {
689         auto &input = info.inputs[i];
690         if (std::holds_alternative<ConstDataId>(input)) {
691             if (std::get<ConstDataId>(input).IsStringId()) {
692                 inList[i + length] = circuit_->GetConstantDataGate(std::get<ConstDataId>(input).CaculateBitField(),
693                                                                    GateType::StringType());
694             } else {
695                 inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
696                                                                std::get<ConstDataId>(input).GetId(),
697                                                                GateType::NJSValue());
698             }
699         } else if (std::holds_alternative<Immediate>(input)) {
700             inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
701                                                            std::get<Immediate>(input).GetValue(),
702                                                            GateType::NJSValue());
703         } else if (std::holds_alternative<ICSlotId>(input)) {
704             inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
705                                                            std::get<ICSlotId>(input).GetId(),
706                                                            GateType::NJSValue());
707         } else {
708             ASSERT(std::holds_alternative<VirtualRegister>(input));
709             continue;
710         }
711     }
712     if (info.AccIn()) {
713         inputSize++;
714     }
715     if (info.ThisObjectIn()) {
716         inList[inputSize + length] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
717     }
718     return inList;
719 }
720 
SetBlockPred(BytecodeRegion & bbNext,const GateRef & state,const GateRef & depend,bool isLoopBack)721 void BytecodeCircuitBuilder::SetBlockPred(BytecodeRegion &bbNext, const GateRef &state,
722                                           const GateRef &depend, bool isLoopBack)
723 {
724     if (bbNext.numOfLoopBacks == 0) {
725         gateAcc_.NewIn(bbNext.stateStart, bbNext.statePredIndex, state);
726         gateAcc_.NewIn(bbNext.dependStart, bbNext.statePredIndex + 1, depend);
727     } else {
728         if (isLoopBack) {
729             gateAcc_.NewIn(bbNext.mergeLoopBackEdges, bbNext.loopBackIndex, state);
730             gateAcc_.NewIn(bbNext.depLoopBack, bbNext.loopBackIndex + 1, depend);
731             bbNext.loopBackIndex++;
732             ASSERT(bbNext.loopBackIndex <= bbNext.numOfLoopBacks);
733         } else {
734             gateAcc_.NewIn(bbNext.mergeForwardEdges, bbNext.forwardIndex, state);
735             gateAcc_.NewIn(bbNext.depForward, bbNext.forwardIndex + 1, depend);
736             bbNext.forwardIndex++;
737             ASSERT(bbNext.forwardIndex <= bbNext.numOfStatePreds - bbNext.numOfLoopBacks);
738         }
739     }
740     bbNext.statePredIndex++;
741     ASSERT(bbNext.statePredIndex <= bbNext.numOfStatePreds);
742 }
743 
NewConst(const BytecodeInfo & info)744 GateRef BytecodeCircuitBuilder::NewConst(const BytecodeInfo &info)
745 {
746     auto opcode = info.GetOpcode();
747     GateRef gate = 0;
748     switch (opcode) {
749         case EcmaOpcode::LDNAN:
750             gate = circuit_->GetConstantGate(MachineType::I64,
751                                              base::NumberHelper::GetNaN(),
752                                              GateType::NumberType());
753             break;
754         case EcmaOpcode::LDINFINITY:
755             gate = circuit_->GetConstantGate(MachineType::I64,
756                                              base::NumberHelper::GetPositiveInfinity(),
757                                              GateType::NumberType());
758             break;
759         case EcmaOpcode::LDUNDEFINED:
760             gate = circuit_->GetConstantGate(MachineType::I64,
761                                              JSTaggedValue::VALUE_UNDEFINED,
762                                              GateType::UndefinedType());
763             break;
764         case EcmaOpcode::LDNULL:
765             gate = circuit_->GetConstantGate(MachineType::I64,
766                                              JSTaggedValue::VALUE_NULL,
767                                              GateType::NullType());
768             break;
769         case EcmaOpcode::LDTRUE:
770             gate = circuit_->GetConstantGate(MachineType::I64,
771                                              JSTaggedValue::VALUE_TRUE,
772                                              GateType::BooleanType());
773             break;
774         case EcmaOpcode::LDFALSE:
775             gate = circuit_->GetConstantGate(MachineType::I64,
776                                              JSTaggedValue::VALUE_FALSE,
777                                              GateType::BooleanType());
778             break;
779         case EcmaOpcode::LDHOLE:
780             gate = circuit_->GetConstantGate(MachineType::I64,
781                                              JSTaggedValue::VALUE_HOLE,
782                                              GateType::TaggedValue());
783             break;
784         case EcmaOpcode::LDAI_IMM32:
785             gate = circuit_->GetConstantGate(MachineType::I64,
786                                              std::get<Immediate>(info.inputs[0]).ToJSTaggedValueInt(),
787                                              GateType::IntType());
788             break;
789         case EcmaOpcode::FLDAI_IMM64:
790             gate = circuit_->GetConstantGate(MachineType::I64,
791                                              std::get<Immediate>(info.inputs.at(0)).ToJSTaggedValueDouble(),
792                                              GateType::DoubleType());
793             break;
794         case EcmaOpcode::LDFUNCTION:
795             gate = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
796             break;
797         case EcmaOpcode::LDNEWTARGET:
798             gate = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
799             break;
800         case EcmaOpcode::LDTHIS:
801             gate = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
802             break;
803         case EcmaOpcode::LDA_STR_ID16: {
804             auto input = std::get<ConstDataId>(info.inputs.at(0));
805             gate = circuit_->GetConstantDataGate(input.CaculateBitField(), GateType::StringType());
806             break;
807         }
808         default:
809             UNREACHABLE();
810     }
811     return gate;
812 }
813 
NewJSGate(BytecodeRegion & bb,GateRef & state,GateRef & depend)814 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb, GateRef &state, GateRef &depend)
815 {
816     auto &iterator = bb.GetBytecodeIterator();
817     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
818     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
819     GateRef gate = 0;
820     bool writable = !bytecodeInfo.NoSideEffects();
821     auto meta = circuit_->JSBytecode(numValueInputs,
822         bytecodeInfo.GetOpcode(), iterator.Index(), writable);
823     std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
824     if (bytecodeInfo.IsDef()) {
825         gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
826                                  inList.data(), GateType::AnyType());
827     } else {
828         gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
829                                  inList.data(), GateType::Empty());
830     }
831     if (bytecodeInfo.IsSuspend()) {
832         auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
833                                                     GetJumpOffset(iterator.Index()),
834                                                     GateType::NJSValue());
835         auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
836         gateAcc_.NewIn(gate, 0, updateHotness);
837         gateAcc_.NewIn(gate, 1, updateHotness);
838     } else {
839         gateAcc_.NewIn(gate, 0, state);
840         gateAcc_.NewIn(gate, 1, depend);
841     }
842     state = gate;
843     if (!bb.catchs.empty()) {
844         auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {gate});
845         auto ifException = circuit_->NewGate(circuit_->IfException(), {gate});
846 
847         auto &bbNext = bb.catchs.at(0);
848         auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
849         SetBlockPred(*bbNext, ifException, gate, isLoopBack);
850         if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
851             bbNext->expandedPreds.push_back({bb.id, iterator.Index() + 1, true}); // 1: next pc
852         } else {
853             bbNext->expandedPreds.push_back({bb.id, iterator.Index(), true});
854         }
855         state = ifSuccess;
856     }
857     byteCodeToJSGate_[iterator.Index()] = gate;
858     if (bytecodeInfo.IsGeneratorRelative()) {
859         if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8) {
860             auto hole = circuit_->GetConstantGate(MachineType::I64,
861                                                   JSTaggedValue::VALUE_HOLE,
862                                                   GateType::TaggedValue());
863             uint32_t numRegs = GetNumberVRegsWithEnv();
864             std::vector<GateRef> vec(numRegs + 1, hole);
865             vec[0] = depend;
866             GateRef saveRegs =
867                 circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
868             gateAcc_.ReplaceDependIn(gate, saveRegs);
869         }
870         suspendAndResumeGates_.emplace_back(gate);
871     }
872     depend = gate;
873     if (bytecodeInfo.IsThrow()) {
874         auto constant = circuit_->GetConstantGate(MachineType::I64,
875                                                   JSTaggedValue::VALUE_EXCEPTION,
876                                                   GateType::TaggedValue());
877         circuit_->NewGate(circuit_->Return(),
878             { state, depend, constant, circuit_->GetReturnRoot() });
879         return;
880     }
881     if (iterator.Index() == bb.end) {
882         auto &bbNext = graph_[bb.id + 1];
883         auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
884         SetBlockPred(bbNext, state, depend, isLoopBack);
885         bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
886     }
887 }
888 
NewJump(BytecodeRegion & bb,GateRef & state,GateRef & depend)889 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb, GateRef &state, GateRef &depend)
890 {
891     auto &iterator = bb.GetBytecodeIterator();
892     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
893     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
894     auto offset = GetJumpOffset(iterator.Index());
895     if (bytecodeInfo.IsCondJump()) {
896         ASSERT(!bytecodeInfo.Deopt());
897         auto meta = circuit_->JSBytecode(numValueInputs,
898             bytecodeInfo.GetOpcode(), iterator.Index(), false);
899         auto numValues = meta->GetNumIns();
900         GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
901         gateAcc_.NewIn(gate, 0, state);
902         gateAcc_.NewIn(gate, 1, depend);
903         auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
904         auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
905         if (offset < 0) {
906             // place update hotness Gate when offset is negative.
907             auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
908                                                         offset,
909                                                         GateType::NJSValue());
910             ifTrue = circuit_->NewGate(circuit_->UpdateHotness(), {ifTrue, trueRelay, offsetGate});
911             trueRelay = ifTrue;
912         }
913         auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
914         auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
915         if (bb.succs.size() == 1) {
916             auto &bbNext = bb.succs[0];
917             ASSERT(bbNext->id == bb.id + 1);
918             auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
919             SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
920             SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
921             bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
922             bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
923         } else {
924             ASSERT(bb.succs.size() == 2); // 2 : 2 num of successors
925             [[maybe_unused]] uint32_t bitSet = 0;
926             for (auto &bbNext: bb.succs) {
927                 if (bbNext->id == bb.id + 1) {
928                     auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
929                     SetBlockPred(*bbNext, ifFalse, falseRelay, isLoopBack);
930                     bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
931                     bitSet |= 1;
932                 } else {
933                     auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
934                     SetBlockPred(*bbNext, ifTrue, trueRelay, isLoopBack);
935                     bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
936                     bitSet |= 2; // 2:verify
937                 }
938             }
939             ASSERT(bitSet == 3); // 3:Verify the number of successor blocks
940         }
941         byteCodeToJSGate_[iterator.Index()] = gate;
942     } else {
943         ASSERT(bb.succs.size() == 1);
944         auto &bbNext = bb.succs.at(0);
945         auto isLoopBack = bbNext->loopbackBlocks.count(bb.id);
946         if (offset < 0) {
947             // place update hotness Gate when offset is negative.
948             auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
949                                                         offset,
950                                                         GateType::NJSValue());
951             auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
952             SetBlockPred(*bbNext, updateHotness, updateHotness, isLoopBack);
953         } else {
954             SetBlockPred(*bbNext, state, depend, isLoopBack);
955         }
956         bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
957     }
958 }
959 
NewReturn(BytecodeRegion & bb,GateRef & state,GateRef & depend)960 void BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb, GateRef &state, GateRef &depend)
961 {
962     ASSERT(bb.succs.empty());
963     auto &iterator = bb.GetBytecodeIterator();
964     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
965     auto offsetGate = circuit_->GetConstantGate(MachineType::I32,
966                                                 GetJumpOffset(iterator.Index()),
967                                                 GateType::NJSValue());
968     auto updateHotness = circuit_->NewGate(circuit_->UpdateHotness(), {state, depend, offsetGate});
969     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
970         // handle return.dyn bytecode
971         auto gate = circuit_->NewGate(circuit_->Return(),
972             { updateHotness, updateHotness, Circuit::NullGate(), circuit_->GetReturnRoot() });
973         byteCodeToJSGate_[iterator.Index()] = gate;
974     } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
975         // handle returnundefined bytecode
976         auto constant = circuit_->GetConstantGate(MachineType::I64,
977                                                   JSTaggedValue::VALUE_UNDEFINED,
978                                                   GateType::TaggedValue());
979         auto gate = circuit_->NewGate(circuit_->Return(),
980             { updateHotness, updateHotness, constant, circuit_->GetReturnRoot() });
981         byteCodeToJSGate_[iterator.Index()] = gate;
982     }
983 }
984 
NewByteCode(BytecodeRegion & bb,GateRef & state,GateRef & depend)985 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb, GateRef &state, GateRef &depend)
986 {
987     auto &iterator = bb.GetBytecodeIterator();
988     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
989     if (bytecodeInfo.IsSetConstant()) {
990         // handle bytecode command to get constants
991         GateRef gate = NewConst(bytecodeInfo);
992         byteCodeToJSGate_[iterator.Index()] = gate;
993         if (iterator.Index() == bb.end) {
994             auto &bbNext = graph_[bb.id + 1];
995             auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
996             SetBlockPred(bbNext, state, depend, isLoopBack);
997             bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
998         }
999     } else if (bytecodeInfo.IsGeneral()) {
1000         // handle general ecma.* bytecodes
1001         NewJSGate(bb, state, depend);
1002     } else if (bytecodeInfo.IsJump()) {
1003         // handle conditional jump and unconditional jump bytecodes
1004         NewJump(bb, state, depend);
1005     } else if (bytecodeInfo.IsReturn()) {
1006         // handle return.dyn and returnundefined bytecodes
1007         NewReturn(bb, state, depend);
1008     } else if (bytecodeInfo.IsMov()) {
1009         // handle mov.dyn lda.dyn sta.dyn bytecodes
1010         if (iterator.Index() == bb.end) {
1011             auto &bbNext = graph_[bb.id + 1];
1012             auto isLoopBack = bbNext.loopbackBlocks.count(bb.id);
1013             SetBlockPred(bbNext, state, depend, isLoopBack);
1014             bbNext.expandedPreds.push_back({bb.id, iterator.Index(), false});
1015         }
1016     } else if (bytecodeInfo.IsDiscarded()) {
1017         return;
1018     } else {
1019         UNREACHABLE();
1020     }
1021 }
1022 
BuildSubCircuit()1023 void BytecodeCircuitBuilder::BuildSubCircuit()
1024 {
1025     for (auto &bb: graph_) {
1026         if (bb.isDead) {
1027             continue;
1028         }
1029         auto stateCur = bb.stateStart;
1030         auto dependCur = bb.dependStart;
1031         ASSERT(stateCur != Circuit::NullGate());
1032         ASSERT(dependCur != Circuit::NullGate());
1033         if (!bb.trys.empty()) {
1034             dependCur = circuit_->NewGate(circuit_->GetException(),
1035                 MachineType::I64, {dependCur}, GateType::AnyType());
1036         }
1037         EnumerateBlock(bb, [this, &stateCur, &dependCur, &bb]
1038             (const BytecodeInfo &bytecodeInfo) -> bool {
1039             NewByteCode(bb, stateCur, dependCur);
1040             if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1041                 return false;
1042             }
1043             return true;
1044         });
1045     }
1046 }
1047 
NewPhi(BytecodeRegion & bb,uint16_t reg,bool acc,GateRef & currentPhi)1048 void BytecodeCircuitBuilder::NewPhi(BytecodeRegion &bb, uint16_t reg, bool acc, GateRef &currentPhi)
1049 {
1050     if (bb.numOfLoopBacks == 0) {
1051         auto inList = std::vector<GateRef>(1 + bb.numOfStatePreds, Circuit::NullGate());
1052         currentPhi =
1053             circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), MachineType::I64,
1054                               inList.size(), inList.data(), GateType::AnyType());
1055         gateAcc_.NewIn(currentPhi, 0, bb.stateStart);
1056         for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1057             auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1058             gateAcc_.NewIn(currentPhi, i + 1, ResolveDef(predId, predBcIdx, reg, acc));
1059         }
1060     } else {
1061         // 2: the number of value inputs and it is in accord with LOOP_BEGIN
1062         currentPhi = circuit_->NewGate(circuit_->ValueSelector(2), MachineType::I64,
1063                                       {bb.stateStart, Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType());
1064         auto inList = std::vector<GateRef>(1 + bb.numOfLoopBacks, Circuit::NullGate());
1065         auto loopBackValue = circuit_->NewGate(circuit_->ValueSelector(bb.numOfLoopBacks),
1066             MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
1067         gateAcc_.NewIn(loopBackValue, 0, bb.mergeLoopBackEdges);
1068         size_t loopBackIndex = 1;  // 1: start index of value inputs
1069         for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1070             auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1071             if (bb.loopbackBlocks.count(predId)) {
1072                 gateAcc_.NewIn(loopBackValue, loopBackIndex++, ResolveDef(predId, predBcIdx, reg, acc));
1073             }
1074         }
1075         inList = std::vector<GateRef>(1 + bb.numOfStatePreds - bb.numOfLoopBacks, Circuit::NullGate());
1076         auto forwardValue = circuit_->NewGate(
1077             circuit_->ValueSelector(bb.numOfStatePreds - bb.numOfLoopBacks), MachineType::I64,
1078             inList.size(), inList.data(), GateType::AnyType());
1079         gateAcc_.NewIn(forwardValue, 0, bb.mergeForwardEdges);
1080         size_t forwardIndex = 1;  // 1: start index of value inputs
1081         for (size_t i = 0; i < bb.numOfStatePreds; ++i) {
1082             auto &[predId, predBcIdx, isException] = bb.expandedPreds.at(i);
1083             if (!bb.loopbackBlocks.count(predId)) {
1084                 gateAcc_.NewIn(forwardValue, forwardIndex++, ResolveDef(predId, predBcIdx, reg, acc));
1085             }
1086         }
1087         gateAcc_.NewIn(currentPhi, 1, forwardValue);   // 1: index of forward value input
1088         gateAcc_.NewIn(currentPhi, 2, loopBackValue);  // 2: index of loop-back value input
1089     }
1090 }
1091 
1092 // recursive variables renaming algorithm
ResolveDef(const size_t bbId,int32_t bcId,const uint16_t reg,const bool acc)1093 GateRef BytecodeCircuitBuilder::ResolveDef(const size_t bbId, int32_t bcId, const uint16_t reg, const bool acc)
1094 {
1095     auto tmpReg = reg;
1096     // find def-site in bytecodes of basic block
1097     auto ans = Circuit::NullGate();
1098     auto &bb = graph_.at(bbId);
1099     GateType type = GateType::AnyType();
1100     auto tmpAcc = acc;
1101 
1102     BytecodeIterator iterator(this, bb.start, bcId);
1103     for (iterator.Goto(bcId); !iterator.Done(); --iterator) {
1104         const BytecodeInfo& curInfo = iterator.GetBytecodeInfo();
1105         // original bc use acc as input && current bc use acc as output
1106         bool isTransByAcc = tmpAcc && curInfo.AccOut();
1107         // 0 : the index in vreg-out list
1108         bool isTransByVreg = (!tmpAcc && curInfo.IsOut(tmpReg, 0));
1109         if (isTransByAcc || isTransByVreg) {
1110             if (curInfo.IsMov()) {
1111                 tmpAcc = curInfo.AccIn();
1112                 if (!curInfo.inputs.empty()) {
1113                     ASSERT(!tmpAcc);
1114                     ASSERT(curInfo.inputs.size() == 1);
1115                     tmpReg = std::get<VirtualRegister>(curInfo.inputs.at(0)).GetId();
1116                 }
1117                 if (HasTypes()) {
1118                     type = typeRecorder_.UpdateType(iterator.Index(), type);
1119                 }
1120             } else {
1121                 ans = byteCodeToJSGate_.at(iterator.Index());
1122                 auto oldType = gateAcc_.GetGateType(ans);
1123                 if (HasTypes() && !type.IsAnyType() && oldType.IsAnyType()) {
1124                     gateAcc_.SetGateType(ans, type);
1125                 }
1126                 break;
1127             }
1128         }
1129         if (curInfo.GetOpcode() != EcmaOpcode::RESUMEGENERATOR) {
1130             continue;
1131         }
1132         // New RESTORE_REGISTER HIR, used to restore the register content when processing resume instruction.
1133         // New SAVE_REGISTER HIR, used to save register content when processing suspend instruction.
1134         auto resumeGate = byteCodeToJSGate_.at(iterator.Index());
1135         ans = GetExistingRestore(resumeGate, tmpReg);
1136         if (ans != Circuit::NullGate()) {
1137             break;
1138         }
1139         GateRef resumeDependGate = gateAcc_.GetDep(resumeGate);
1140         ans = circuit_->NewGate(circuit_->RestoreRegister(tmpReg), MachineType::I64,
1141                                 { resumeDependGate }, GateType::AnyType());
1142         SetExistingRestore(resumeGate, tmpReg, ans);
1143         gateAcc_.SetDep(resumeGate, ans);
1144         auto saveRegGate = ResolveDef(bbId, iterator.Index() - 1, tmpReg, tmpAcc);
1145         ASSERT(Bytecodes::GetOpcode(iterator.PeekPrevPc(2)) == EcmaOpcode::SUSPENDGENERATOR_V8); // 2: prev bc
1146         GateRef suspendGate = byteCodeToJSGate_.at(iterator.Index() - 2); // 2: prev bc
1147         GateRef saveRegs = gateAcc_.GetDep(suspendGate);
1148         gateAcc_.ReplaceValueIn(saveRegs, saveRegGate, tmpReg);
1149         break;
1150     }
1151     // find GET_EXCEPTION gate if this is a catch block
1152     if (ans == Circuit::NullGate() && tmpAcc) {
1153         if (!bb.trys.empty()) {
1154             std::vector<GateRef> outList;
1155             gateAcc_.GetOuts(bb.dependStart, outList);
1156             ASSERT(outList.size() == 1);
1157             const auto &getExceptionGate = outList.at(0);
1158             ASSERT(gateAcc_.GetOpCode(getExceptionGate) == OpCode::GET_EXCEPTION);
1159             ans = getExceptionGate;
1160         }
1161     }
1162     // find def-site in value selectors of vregs
1163     if (ans == Circuit::NullGate() && !tmpAcc && bb.phi.count(tmpReg)) {
1164         if (!bb.vregToValSelectorGate.count(tmpReg)) {
1165             NewPhi(bb, tmpReg, tmpAcc, bb.vregToValSelectorGate[tmpReg]);
1166         }
1167         ans = bb.vregToValSelectorGate.at(tmpReg);
1168     }
1169     // find def-site in value selectors of acc
1170     if (ans == Circuit::NullGate() && tmpAcc && bb.phiAcc) {
1171         if (bb.valueSelectorAccGate == Circuit::NullGate()) {
1172             NewPhi(bb, tmpReg, tmpAcc, bb.valueSelectorAccGate);
1173         }
1174         ans = bb.valueSelectorAccGate;
1175     }
1176     if (ans == Circuit::NullGate() && IsEntryBlock(bbId)) { // entry block
1177         // find def-site in function args
1178         ASSERT(!tmpAcc);
1179         if (tmpReg == GetEnvVregIdx()) {
1180             ans = argAcc_.GetCommonArgGate(CommonArgIdx::LEXENV);
1181         } else {
1182             ans = argAcc_.GetArgGate(tmpReg);
1183         }
1184         return ans;
1185     }
1186     if (ans == Circuit::NullGate()) {
1187         // recursively find def-site in dominator block
1188         return ResolveDef(bb.iDominator->id, bb.iDominator->end, tmpReg, tmpAcc);
1189     } else {
1190         // def-site already found
1191         return ans;
1192     }
1193 }
1194 
BuildCircuit()1195 void BytecodeCircuitBuilder::BuildCircuit()
1196 {
1197     // create arg gates array
1198     BuildCircuitArgs();
1199     CollectPredsInfo();
1200     BuildBlockCircuitHead();
1201     // build states sub-circuit of each block
1202     BuildSubCircuit();
1203     // verification of soundness of CFG
1204     for (auto &bb: graph_) {
1205         if (bb.isDead) {
1206             continue;
1207         }
1208         ASSERT(bb.statePredIndex == bb.numOfStatePreds);
1209         ASSERT(bb.loopBackIndex == bb.numOfLoopBacks);
1210         if (bb.numOfLoopBacks) {
1211             ASSERT(bb.forwardIndex == bb.numOfStatePreds - bb.numOfLoopBacks);
1212         }
1213         // resolve def-site of virtual regs and set all value inputs
1214         EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1215             auto &iterator = bb.GetBytecodeIterator();
1216             const auto bcIndex = iterator.Index();
1217             const auto bbIndex = bb.id;
1218             GateRef gate = GetGateByBcIndex(bcIndex);
1219             if (gate == Circuit::NullGate()) {
1220                 return true;
1221             }
1222             if (gateAcc_.IsConstant(gate)) {
1223                 return true;
1224             }
1225 
1226             if (HasTypes()) {
1227                 auto type = typeRecorder_.GetType(bcIndex);
1228                 if (!type.IsAnyType()) {
1229                     gateAcc_.SetGateType(gate, type);
1230                 }
1231             }
1232             auto valueCount = gateAcc_.GetInValueCount(gate);
1233             [[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
1234             [[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
1235             ASSERT(numValueInputs == valueCount);
1236             ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
1237             auto valueStarts = gateAcc_.GetInValueStarts(gate);
1238             for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
1239                 auto inIdx = valueIdx + valueStarts;
1240                 if (!gateAcc_.IsInGateNull(gate, inIdx)) {
1241                     continue;
1242                 }
1243                 if (valueIdx < bytecodeInfo.inputs.size()) {
1244                     auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
1245                     GateRef defVreg = Circuit::NullGate();
1246                     if (IsFirstBCEnvIn(bbIndex, bcIndex, vregId)) {
1247                         defVreg = argAcc_.GetCommonArgGate(CommonArgIdx::LEXENV);
1248                     } else {
1249                         defVreg = ResolveDef(bbIndex, bcIndex - 1, vregId, false);
1250                     }
1251                     gateAcc_.NewIn(gate, inIdx, defVreg);
1252                 } else {
1253                     GateRef defAcc = ResolveDef(bbIndex, bcIndex - 1, 0, true);
1254                     gateAcc_.NewIn(gate, inIdx, defAcc);
1255                 }
1256             }
1257             return true;
1258         });
1259     }
1260 
1261     if (IsTypeLoweringEnabled()) {
1262         frameStateBuilder_.BuildFrameState();
1263     }
1264 
1265     if (IsLogEnabled()) {
1266         PrintGraph("Bytecode2Gate");
1267         LOG_COMPILER(INFO) << "\033[34m" << "============= "
1268                            << "After bytecode2circuit lowering ["
1269                            << methodName_ << "]"
1270                            << " =============" << "\033[0m";
1271         circuit_->PrintAllGatesWithBytecode();
1272         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
1273     }
1274 }
1275 
GetExistingRestore(GateRef resumeGate,uint16_t tmpReg) const1276 GateRef BytecodeCircuitBuilder::GetExistingRestore(GateRef resumeGate, uint16_t tmpReg) const
1277 {
1278     auto pr = std::make_pair(resumeGate, tmpReg);
1279     if (resumeRegToRestore_.count(pr)) {
1280         return resumeRegToRestore_.at(pr);
1281     }
1282     return Circuit::NullGate();
1283 }
1284 
SetExistingRestore(GateRef resumeGate,uint16_t tmpReg,GateRef restoreGate)1285 void BytecodeCircuitBuilder::SetExistingRestore(GateRef resumeGate, uint16_t tmpReg, GateRef restoreGate)
1286 {
1287     auto pr = std::make_pair(resumeGate, tmpReg);
1288     resumeRegToRestore_[pr] = restoreGate;
1289 }
1290 
PrintGraph(const char * title)1291 void BytecodeCircuitBuilder::PrintGraph(const char* title)
1292 {
1293     LOG_COMPILER(INFO) << "======================== " << title << " ========================";
1294     for (size_t i = 0; i < graph_.size(); i++) {
1295         BytecodeRegion& bb = graph_[i];
1296         if (bb.isDead) {
1297             LOG_COMPILER(INFO) << "B" << bb.id << ":                               ;preds= invalid BB";
1298             LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1299                                << std::to_string(bb.end) << ")";
1300             continue;
1301         }
1302         std::string log("B" + std::to_string(bb.id) + ":                               ;preds= ");
1303         for (size_t k = 0; k < bb.preds.size(); ++k) {
1304             log += std::to_string(bb.preds[k]->id) + ", ";
1305         }
1306         LOG_COMPILER(INFO) << log;
1307         LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1308                            << std::to_string(bb.end) << ")";
1309 
1310         std::string log1("\tSucces: ");
1311         for (size_t j = 0; j < bb.succs.size(); j++) {
1312             log1 += std::to_string(bb.succs[j]->id) + ", ";
1313         }
1314         LOG_COMPILER(INFO) << log1;
1315 
1316         for (size_t j = 0; j < bb.catchs.size(); j++) {
1317             LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catchs[j]->start) << ", "
1318                                << std::to_string(bb.catchs[j]->end) << ")";
1319         }
1320 
1321         std::string log2("\tTrys: ");
1322         for (auto tryBlock: bb.trys) {
1323             log2 += std::to_string(tryBlock->id) + " , ";
1324         }
1325         LOG_COMPILER(INFO) << log2;
1326 
1327         std::string log3 = "\tDom: ";
1328         for (size_t j = 0; j < bb.immDomBlocks.size(); j++) {
1329             log3 += "B" + std::to_string(bb.immDomBlocks[j]->id) + std::string(", ");
1330         }
1331         LOG_COMPILER(INFO) << log3;
1332 
1333         if (bb.iDominator) {
1334             LOG_COMPILER(INFO) << "\tIDom B" << bb.iDominator->id;
1335         }
1336 
1337         std::string log4("\tDom Frontiers: ");
1338         for (const auto &frontier: bb.domFrontiers) {
1339             log4 += std::to_string(frontier->id) + " , ";
1340         }
1341         LOG_COMPILER(INFO) << log4;
1342 
1343         std::string log5("\tPhi: ");
1344         for (auto variable: bb.phi) {
1345             log5 += std::to_string(variable) + " , ";
1346         }
1347         LOG_COMPILER(INFO) << log5;
1348 
1349         PrintBytecodeInfo(bb);
1350         LOG_COMPILER(INFO) << "";
1351     }
1352 }
1353 
PrintBytecodeInfo(BytecodeRegion & bb)1354 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
1355 {
1356     if (bb.isDead) {
1357         return;
1358     }
1359     LOG_COMPILER(INFO) << "\tBytecode[] = ";
1360     EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1361         auto &iterator = bb.GetBytecodeIterator();
1362         std::string log;
1363         log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
1364         log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
1365         if (bytecodeInfo.AccIn()) {
1366             log += "acc,";
1367         }
1368         for (const auto &in: bytecodeInfo.inputs) {
1369             if (std::holds_alternative<VirtualRegister>(in)) {
1370                 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
1371             }
1372         }
1373         log += "], Out=[";
1374         if (bytecodeInfo.AccOut()) {
1375             log += "acc,";
1376         }
1377         for (const auto &out: bytecodeInfo.vregOut) {
1378             log +=  std::to_string(out) + ",";
1379         }
1380         log += "] >";
1381         LOG_COMPILER(INFO) << log;
1382 
1383         auto gate = byteCodeToJSGate_[iterator.Index()];
1384         if (gate != Circuit::NullGate()) {
1385             this->gateAcc_.ShortPrint(gate);
1386         }
1387         return true;
1388     });
1389 }
1390 }  // namespace panda::ecmascript::kungfu
1391