• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 <algorithm>
19 #include <cstddef>
20 
21 #include "ecmascript/base/number_helper.h"
22 #include "ecmascript/compiler/gate_accessor.h"
23 #include "ecmascript/deoptimizer/deoptimizer.h"
24 #include "ecmascript/interpreter/interpreter-inl.h"
25 #include "libpandafile/bytecode_instruction-inl.h"
26 
27 
28 namespace panda::ecmascript::kungfu {
BytecodeToCircuit()29 void BytecodeCircuitBuilder::BytecodeToCircuit()
30 {
31     ExceptionInfo exceptionInfo = {};
32 
33     // collect try catch block info
34     CollectTryCatchBlockInfo(exceptionInfo);
35     hasTryCatch_ = exceptionInfo.size() != 0;
36     BuildRegionInfo();
37     // Building the basic block diagram of bytecode
38     BuildRegions(exceptionInfo);
39 }
40 
BuildRegionInfo()41 void BytecodeCircuitBuilder::BuildRegionInfo()
42 {
43     uint32_t size = pcOffsets_.size();
44     ASSERT(size > 0);
45     uint32_t end = size - 1;  // 1: end
46     BytecodeIterator iterator(this, 0, end);
47 
48     infoData_.resize(size);
49     byteCodeToJSGates_.resize(size, std::vector<GateRef>(0));
50     regionsInfo_.InsertHead(0); // 0: start pc
51     iterator.GotoStart();
52     while (!iterator.Done()) {
53         auto index = iterator.Index();
54         auto &info = infoData_[index];
55         auto pc = pcOffsets_[index];
56         info.metaData_ = bytecodes_->GetBytecodeMetaData(pc);
57         ASSERT(!info.metaData_.IsInvalid());
58         BytecodeInfo::InitBytecodeInfo(this, info, pc);
59         CollectRegionInfo(index);
60         ++iterator;
61     }
62 }
63 
CollectRegionInfo(uint32_t bcIndex)64 void BytecodeCircuitBuilder::CollectRegionInfo(uint32_t bcIndex)
65 {
66     auto pc = pcOffsets_[bcIndex];
67     auto &info = infoData_[bcIndex];
68     int32_t offset = 0;
69     if (info.IsJump()) {
70         switch (info.GetOpcode()) {
71             case EcmaOpcode::JEQZ_IMM8:
72             case EcmaOpcode::JNEZ_IMM8:
73             case EcmaOpcode::JMP_IMM8:
74                 offset = static_cast<int8_t>(READ_INST_8_0());
75                 break;
76             case EcmaOpcode::JNEZ_IMM16:
77             case EcmaOpcode::JEQZ_IMM16:
78             case EcmaOpcode::JMP_IMM16:
79                 offset = static_cast<int16_t>(READ_INST_16_0());
80                 break;
81             case EcmaOpcode::JMP_IMM32:
82             case EcmaOpcode::JNEZ_IMM32:
83             case EcmaOpcode::JEQZ_IMM32:
84                 offset = static_cast<int32_t>(READ_INST_32_0());
85                 break;
86             default:
87                 LOG_ECMA(FATAL) << "this branch is unreachable";
88                 UNREACHABLE();
89                 break;
90         }
91         auto nextIndex = bcIndex + 1; // 1: next pc
92         auto targetIndex = FindBcIndexByPc(pc + offset);
93         auto it = candidateEmptyCatch_.find(targetIndex);
94         if (it != candidateEmptyCatch_.end()) {
95             it->second = true;
96         }
97         // condition branch current basic block end
98         if (info.IsCondJump()) {
99             regionsInfo_.InsertSplit(nextIndex);
100             regionsInfo_.InsertJump(targetIndex, bcIndex, false);
101         } else {
102             if (bcIndex != GetLastBcIndex()) {
103                 regionsInfo_.InsertHead(nextIndex);
104             }
105             regionsInfo_.InsertJump(targetIndex, bcIndex, true);
106         }
107     } else if (info.IsReturn() || info.IsThrow()) {
108         if (bcIndex != GetLastBcIndex()) {
109             auto nextIndex = bcIndex + 1; // 1: next pc
110             regionsInfo_.InsertHead(nextIndex);
111         }
112     }
113 }
114 
CollectTryCatchBlockInfo(ExceptionInfo & byteCodeException)115 void BytecodeCircuitBuilder::CollectTryCatchBlockInfo(ExceptionInfo &byteCodeException)
116 {
117     auto pf = file_->GetPandaFile();
118     panda_file::MethodDataAccessor mda(*pf, method_->GetMethodId());
119     panda_file::CodeDataAccessor cda(*pf, mda.GetCodeId().value());
120 
121     cda.EnumerateTryBlocks([this, &byteCodeException](
122         panda_file::CodeDataAccessor::TryBlock &tryBlock) {
123         auto tryStartOffset = tryBlock.GetStartPc();
124         auto tryEndOffset = tryBlock.GetStartPc() + tryBlock.GetLength();
125 
126         auto tryStartPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryStartOffset);
127         auto tryEndPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + tryEndOffset);
128         // skip try blocks with same pc in start and end label
129         if (tryStartPc == tryEndPc) {
130             return true;
131         }
132 
133         auto tryStartBcIndex = FindBcIndexByPc(tryStartPc);
134         regionsInfo_.InsertSplit(tryStartBcIndex);
135         if (tryEndPc <= GetLastPC()) {
136             auto tryEndBcIndex = FindBcIndexByPc(tryEndPc);
137             regionsInfo_.InsertSplit(tryEndBcIndex);
138         }
139         byteCodeException.emplace_back(ExceptionItem { tryStartPc, tryEndPc, {} });
140         tryBlock.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
141             auto pcOffset = catchBlock.GetHandlerPc();
142             auto catchBlockPc = const_cast<uint8_t *>(method_->GetBytecodeArray() + pcOffset);
143             auto catchBlockBcIndex = FindBcIndexByPc(catchBlockPc);
144             candidateEmptyCatch_.insert(std::pair<uint32_t, bool>(catchBlockBcIndex, false));
145             regionsInfo_.InsertHead(catchBlockBcIndex);
146             // try block associate catch block
147             byteCodeException.back().catches.emplace_back(catchBlockPc);
148             return true;
149         });
150         return true;
151     });
152 }
153 
IsAncestor(size_t nodeA,size_t nodeB)154 bool BytecodeCircuitBuilder::IsAncestor(size_t nodeA, size_t nodeB)
155 {
156     return timeIn_[bbIdToDfsTimestamp_[nodeA]] <= timeIn_[bbIdToDfsTimestamp_[nodeB]] &&
157         timeOut_[bbIdToDfsTimestamp_[nodeA]] >= timeOut_[bbIdToDfsTimestamp_[nodeB]];
158 }
159 
PerformDFS(const std::vector<size_t> & immDom,size_t listSize)160 void BytecodeCircuitBuilder::PerformDFS(const std::vector<size_t> &immDom, size_t listSize)
161 {
162     std::vector<std::vector<size_t>> sonList(listSize);
163     for (size_t idx = 1; idx < immDom.size(); idx++) {
164         sonList[immDom[idx]].push_back(idx);
165     }
166 
167     {
168         size_t timestamp = 0;
169         struct DFSState {
170             size_t cur;
171             std::vector<size_t> &succList;
172             size_t idx;
173         };
174         std::stack<DFSState> dfsStack;
175         size_t root = 0;
176         dfsStack.push({root, sonList[root], 0});
177         timeIn_[root] = timestamp++;
178         while (!dfsStack.empty()) {
179             auto &curState = dfsStack.top();
180             auto &cur = curState.cur;
181             auto &succList = curState.succList;
182             auto &idx = curState.idx;
183             if (idx == succList.size()) {
184                 timeOut_[cur] = timestamp++;
185                 dfsStack.pop();
186                 continue;
187             }
188             const auto &succ = succList[idx];
189             dfsStack.push({succ, sonList[succ], 0});
190             timeIn_[succ] = timestamp++;
191             idx++;
192         }
193     }
194 }
195 
196 
ReducibilityCheck()197 void BytecodeCircuitBuilder::ReducibilityCheck()
198 {
199     std::vector<size_t> basicBlockList;
200     std::vector<size_t> immDom;
201     std::unordered_map<size_t, size_t> bbDfsTimestampToIdx;
202     ComputeDominatorTree(basicBlockList, immDom, bbDfsTimestampToIdx);
203     timeIn_.resize(basicBlockList.size());
204     timeOut_.resize(basicBlockList.size());
205     PerformDFS(immDom, basicBlockList.size());
206 }
207 
ComputeImmediateDominators(const std::vector<size_t> & basicBlockList,std::unordered_map<size_t,size_t> & dfsFatherIdx,std::vector<size_t> & immDom,std::unordered_map<size_t,size_t> & bbDfsTimestampToIdx)208 void BytecodeCircuitBuilder::ComputeImmediateDominators(const std::vector<size_t> &basicBlockList,
209                                                         std::unordered_map<size_t, size_t> &dfsFatherIdx,
210                                                         std::vector<size_t> &immDom,
211                                                         std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
212 {
213     std::vector<size_t> semiDom(basicBlockList.size());
214     std::vector<std::vector<size_t> > semiDomTree(basicBlockList.size());
215     {
216         std::vector<size_t> parent(basicBlockList.size());
217         std::iota(parent.begin(), parent.end(), 0);
218         std::vector<size_t> minIdx(basicBlockList.size());
219         std::function<size_t(size_t)> unionFind = [&] (size_t idx) -> size_t {
220             if (parent[idx] == idx) return idx;
221             size_t unionFindSetRoot = unionFind(parent[idx]);
222             if (semiDom[minIdx[idx]] > semiDom[minIdx[parent[idx]]]) {
223                 minIdx[idx] = minIdx[parent[idx]];
224             }
225             return parent[idx] = unionFindSetRoot;
226         };
227         auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
228             size_t parentFatherIdx = unionFind(fatherIdx);
229             size_t parentSonIdx = unionFind(sonIdx);
230             parent[parentSonIdx] = parentFatherIdx;
231         };
232         auto calculateSemiDom = [&](size_t idx, const ChunkVector<BytecodeRegion *> &blocks) {
233             for (const auto &preBlock : blocks) {
234                 if (bbDfsTimestampToIdx[preBlock->id] < idx) {
235                     semiDom[idx] = std::min(semiDom[idx], bbDfsTimestampToIdx[preBlock->id]);
236                 } else {
237                     unionFind(bbDfsTimestampToIdx[preBlock->id]);
238                     semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[bbDfsTimestampToIdx[preBlock->id]]]);
239                 }
240             }
241         };
242         std::iota(semiDom.begin(), semiDom.end(), 0);
243         semiDom[0] = semiDom.size();
244         for (size_t idx = basicBlockList.size() - 1; idx >= 1; idx--) {
245             calculateSemiDom(idx, graph_[basicBlockList[idx]]->preds);
246             if (!graph_[basicBlockList[idx]]->trys.empty()) {
247                 calculateSemiDom(idx, graph_[basicBlockList[idx]]->trys);
248             }
249             for (const auto &succDomIdx : semiDomTree[idx]) {
250                 unionFind(succDomIdx);
251                 if (idx == semiDom[minIdx[succDomIdx]]) {
252                     immDom[succDomIdx] = idx;
253                 } else {
254                     immDom[succDomIdx] = minIdx[succDomIdx];
255                 }
256             }
257             minIdx[idx] = idx;
258             merge(dfsFatherIdx[basicBlockList[idx]], idx);
259             semiDomTree[semiDom[idx]].emplace_back(idx);
260         }
261         for (size_t idx = 1; idx < basicBlockList.size(); idx++) {
262             if (immDom[idx] != semiDom[idx]) {
263                 immDom[idx] = immDom[immDom[idx]];
264             }
265         }
266         semiDom[0] = 0;
267     }
268 }
269 
ComputeDominatorTree(std::vector<size_t> & basicBlockList,std::vector<size_t> & immDom,std::unordered_map<size_t,size_t> & bbDfsTimestampToIdx)270 void BytecodeCircuitBuilder::ComputeDominatorTree(std::vector<size_t> &basicBlockList, std::vector<size_t> &immDom,
271     std::unordered_map<size_t, size_t> &bbDfsTimestampToIdx)
272 {
273     std::unordered_map<size_t, size_t> dfsFatherIdx;
274     size_t timestamp = 0;
275     std::deque<size_t> pendingList;
276     std::vector<size_t> visited(graph_.size(), 0);
277     auto basicBlockId = graph_[0]->id;
278     visited[graph_[0]->id] = 1;
279     pendingList.emplace_back(basicBlockId);
280 
281     auto visitConnectedBlocks = [&](const ChunkVector<BytecodeRegion *> &succs, size_t curBlockId) {
282         for (const auto &succBlock : succs) {
283             if (visited[succBlock->id] == 0) {
284                 visited[succBlock->id] = 1;
285                 pendingList.emplace_back(succBlock->id);
286                 dfsFatherIdx[succBlock->id] = bbIdToDfsTimestamp_[curBlockId];
287             }
288         }
289     };
290 
291     while (!pendingList.empty()) {
292         size_t curBlockId = pendingList.back();
293         pendingList.pop_back();
294         basicBlockList.emplace_back(curBlockId);
295         bbIdToDfsTimestamp_[curBlockId] = timestamp++;
296         visitConnectedBlocks(graph_[curBlockId]->succs, curBlockId);
297         if (!graph_[curBlockId]->catches.empty()) {
298             visitConnectedBlocks(graph_[curBlockId]->catches, curBlockId);
299         }
300     }
301     for (size_t idx = 0; idx < basicBlockList.size(); idx++) {
302         bbDfsTimestampToIdx[basicBlockList[idx]] = idx;
303     }
304 
305     immDom.resize(basicBlockList.size());
306     ComputeImmediateDominators(basicBlockList, dfsFatherIdx, immDom, bbDfsTimestampToIdx);
307 }
308 
BuildEntryBlock()309 void BytecodeCircuitBuilder::BuildEntryBlock()
310 {
311     BytecodeRegion &entryBlock = RegionAt(0);
312     BytecodeRegion &nextBlock = RegionAt(1);
313     entryBlock.succs.emplace_back(&nextBlock);
314     nextBlock.preds.emplace_back(&entryBlock);
315     entryBlock.bytecodeIterator_.Reset(this, 0, BytecodeIterator::INVALID_INDEX);
316 }
317 
BuildBasicBlock()318 void BytecodeCircuitBuilder::BuildBasicBlock()
319 {
320     auto &items = regionsInfo_.GetBlockItems();
321     size_t blockId = 1;
322     for (const auto &item : items) {
323         auto &curBlock = GetBasicBlockById(blockId);
324         curBlock.id = blockId;
325         curBlock.start = item.GetStartBcIndex();
326         if (blockId != 1) {
327             auto &prevBlock = RegionAt(blockId - 1);
328             ASSERT(curBlock.start >= 1);
329             prevBlock.end = curBlock.start - 1;
330             prevBlock.bytecodeIterator_.Reset(this, prevBlock.start, prevBlock.end);
331             // fall through
332             if (!item.IsHeadBlock()) {
333                 curBlock.preds.emplace_back(&prevBlock);
334                 prevBlock.succs.emplace_back(&curBlock);
335             }
336         }
337         blockId++;
338     }
339     auto &lastBlock = RegionAt(blockId - 1); // 1: last block
340     lastBlock.end = GetLastBcIndex();
341     lastBlock.bytecodeIterator_.Reset(this, lastBlock.start, lastBlock.end);
342 }
343 
BuildRegions(const ExceptionInfo & byteCodeException)344 void BytecodeCircuitBuilder::BuildRegions(const ExceptionInfo &byteCodeException)
345 {
346     auto blockSize = regionsInfo_.GetBlockItems().size();
347 
348     // 1 : entry block. if the loop head is in the first bb block, the variables used in the head cannot correctly
349     // generate Phi nodes through the dominator-tree algorithm, resulting in an infinite loop. Therefore, an empty
350     // BB block is generated as an entry block
351     graph_.resize(blockSize + 1, nullptr);
352     for (size_t i = 0; i < graph_.size(); i++) {
353         graph_[i] = circuit_->chunk()->New<BytecodeRegion>(circuit_->chunk());
354     }
355 
356     // build entry block
357     BuildEntryBlock();
358 
359     // build basic block
360     BuildBasicBlock();
361 
362     auto &splitItems = regionsInfo_.GetSplitItems();
363     for (const auto &item : splitItems) {
364         auto curIndex = regionsInfo_.FindBBIndexByBcIndex(item.startBcIndex);
365         auto &curBlock = GetBasicBlockById(curIndex);
366         auto predIndex = regionsInfo_.FindBBIndexByBcIndex(item.predBcIndex);
367         auto &predBlock = GetBasicBlockById(predIndex);
368         curBlock.preds.emplace_back(&predBlock);
369         predBlock.succs.emplace_back(&curBlock);
370     }
371 
372     if (byteCodeException.size() != 0) {
373         BuildCatchBlocks(byteCodeException);
374     }
375     UpdateCFG();
376     if (HasTryCatch()) {
377         CollectTryPredsInfo();
378     }
379     RemoveUnreachableRegion();
380     if (NeedIrreducibleLoopCheck()) {
381         ReducibilityCheck();
382     }
383     if (IsLogEnabled() && !IsPreAnalysis()) {
384         PrintGraph(std::string("Update CFG [" + methodName_ + "]").c_str());
385     }
386     BuildCircuit();
387 }
388 
UpdateEmptyCatchBB()389 void BytecodeCircuitBuilder::UpdateEmptyCatchBB()
390 {
391     for (size_t i = 0; i < graph_.size(); i++) {
392         auto &bb = RegionAt(i);
393         auto it = candidateEmptyCatch_.find(bb.start);
394         if (it != candidateEmptyCatch_.end()) {
395             if (it->second) {
396                 bb.IsEmptyCatchBB = true;
397                 hasEmptyCatchBB_ = true;
398             }
399         }
400     }
401 }
402 
BuildCatchBlocks(const ExceptionInfo & byteCodeException)403 void BytecodeCircuitBuilder::BuildCatchBlocks(const ExceptionInfo &byteCodeException)
404 {
405     // try catch block associate
406     for (size_t i = 0; i < graph_.size(); i++) {
407         auto &bb = RegionAt(i);
408         auto startIndex = bb.start;
409         bool noThrow = true;
410         EnumerateBlock(bb, [&noThrow](const BytecodeInfo &bytecodeInfo) -> bool {
411             if (bytecodeInfo.IsGeneral()) {
412                 if (!bytecodeInfo.NoThrow()) {
413                     noThrow = false;
414                     return false;
415                 }
416             }
417             return true;
418         });
419         if (noThrow) {
420             continue;
421         }
422         const auto pc = pcOffsets_[startIndex];
423         for (auto it = byteCodeException.cbegin(); it != byteCodeException.cend(); it++) {
424             if (pc < it->startPc || pc >= it->endPc) {
425                 continue;
426             }
427             // try block interval
428             const auto &catches = it->catches; // catches start pc
429             for (size_t j = i + 1; j < graph_.size(); j++) {
430                 auto &catchBB = RegionAt(j);
431                 const auto catchStart = pcOffsets_[catchBB.start];
432                 if (std::find(catches.cbegin(), catches.cend(), catchStart) != catches.cend()) {
433                     bb.catches.insert(bb.catches.cbegin(), &catchBB);
434                 }
435             }
436         }
437 
438         // When there are multiple catch blocks in the current block, the set of catch blocks
439         // needs to be sorted to satisfy the order of execution of catch blocks.
440         bb.SortCatches();
441     }
442 }
443 
CollectTryPredsInfo()444 void BytecodeCircuitBuilder::CollectTryPredsInfo()
445 {
446     for (size_t i = 0; i < graph_.size(); i++) {
447         auto &bb = RegionAt(i);
448         if (bb.catches.empty()) {
449             continue;
450         } else if (bb.catches.size() > 1) { // 1: cache size
451             for (auto it = bb.catches.begin() + 1; it != bb.catches.end();) { // 1: invalid catch bb
452                 bb.EraseThisBlock((*it)->trys);
453                 it = bb.catches.erase(it);
454             }
455         }
456 
457         EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
458             if (bytecodeInfo.IsGeneral()) {
459                 // if block which can throw exception has serval catchs block,
460                 // only the innermost catch block is useful
461                 ASSERT(bb.catches.size() == 1); // 1: cache size
462                 if (!bytecodeInfo.NoThrow()) {
463                     bb.catches.at(0)->numOfStatePreds++;
464                 }
465             }
466             return true;
467         });
468     }
469 }
470 
RemoveUnusedPredsInfo(BytecodeRegion & bb)471 void BytecodeCircuitBuilder::RemoveUnusedPredsInfo(BytecodeRegion& bb)
472 {
473     EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
474         if (bytecodeInfo.IsGeneral()) {
475             ASSERT(bb.catches.size() == 1); // 1: cache size
476             if (!bytecodeInfo.NoThrow()) {
477                 bb.catches.at(0)->numOfStatePreds--;
478             }
479         }
480         return true;
481     });
482 }
483 
ClearUnreachableRegion(ChunkVector<BytecodeRegion * > & pendingList)484 void BytecodeCircuitBuilder::ClearUnreachableRegion(ChunkVector<BytecodeRegion*>& pendingList)
485 {
486     auto bb = pendingList.back();
487     pendingList.pop_back();
488     for (auto it = bb->preds.begin(); it != bb->preds.end(); it++) {
489         ASSERT((*it)->numOfStatePreds >= 0);
490         if ((*it)->numOfStatePreds != 0) {
491             bb->EraseThisBlock((*it)->succs);
492         }
493     }
494     for (auto it = bb->succs.begin(); it != bb->succs.end(); it++) {
495         auto bbNext = *it;
496         ASSERT(bbNext->numOfStatePreds >= 0);
497         if (bbNext->numOfStatePreds != 0) {
498             bb->EraseThisBlock(bbNext->preds);
499             bbNext->numOfStatePreds--;
500             if (bbNext->numOfStatePreds == 0) {
501                 pendingList.emplace_back(bbNext);
502             }
503         }
504     }
505     for (auto it = bb->trys.begin(); it != bb->trys.end(); it++) {
506         ASSERT((*it)->numOfStatePreds >= 0);
507         if ((*it)->numOfStatePreds != 0) {
508             bb->EraseThisBlock((*it)->catches);
509         }
510     }
511     for (auto it = bb->catches.begin(); it != bb->catches.end(); it++) {
512         auto bbNext = *it;
513         ASSERT(bbNext->numOfStatePreds >= 0);
514         if (bbNext->numOfStatePreds != 0) {
515             RemoveUnusedPredsInfo(*bb);
516             bb->EraseThisBlock(bbNext->trys);
517             if (bbNext->numOfStatePreds == 0) {
518                 pendingList.emplace_back(bbNext);
519             }
520         }
521     }
522     bb->preds.clear();
523     bb->succs.clear();
524     bb->trys.clear();
525     bb->catches.clear();
526     numOfLiveBB_--;
527 
528     RemoveIfInRpoList(bb);
529 }
530 
RemoveIfInRpoList(BytecodeRegion * bb)531 void BytecodeCircuitBuilder::RemoveIfInRpoList(BytecodeRegion *bb)
532 {
533     auto& rpoList = frameStateBuilder_.GetRpoList();
534     for (auto iter = rpoList.begin(); iter != rpoList.end(); iter++) {
535         if (*iter == bb->id) {
536             rpoList.erase(iter);
537             break;
538         }
539     }
540 }
541 
RemoveUnreachableRegion()542 void BytecodeCircuitBuilder::RemoveUnreachableRegion()
543 {
544     numOfLiveBB_ = graph_.size();
545     ChunkVector<BytecodeRegion*> pendingList(circuit_->chunk());
546     for (size_t i = 1; i < graph_.size(); i++) { // 1: skip entry bb
547         auto &bb = RegionAt(i);
548         ASSERT(bb.numOfStatePreds >= 0);
549         if (bb.numOfStatePreds == 0) {
550             pendingList.emplace_back(&bb);
551         }
552     }
553     while (!pendingList.empty()) {
554         ClearUnreachableRegion(pendingList);
555     }
556 }
557 
ComputeNumOfLoopBack()558 void BytecodeCircuitBuilder::ComputeNumOfLoopBack()
559 {
560     for (size_t i = 0; i < graph_.size(); i++) {
561         auto &bb = RegionAt(i);
562         if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
563             continue;
564         }
565         for (auto &succ: bb.succs) {
566             if (succ->IsLoopBack(bb)) {
567                 succ->numOfLoopBack++;
568             }
569         }
570         if (bb.catches.empty()) {
571             continue;
572         }
573 
574         EnumerateBlock(bb, [&bb](const BytecodeInfo &bytecodeInfo) -> bool {
575             if (bytecodeInfo.IsGeneral() && !bytecodeInfo.NoThrow() && bb.catches.at(0)->IsLoopBack(bb)) {
576                 // if block which can throw exception has serval catchs block,
577                 // only the innermost catch block is useful
578                 ASSERT(bb.catches.size() == 1); // 1: cache size
579                 bb.catches.at(0)->numOfLoopBack++;
580             }
581             return true;
582         });
583     }
584 }
585 // Update CFG's predecessor, successor and try catch associations
UpdateCFG()586 void BytecodeCircuitBuilder::UpdateCFG()
587 {
588     for (size_t i = 0; i < graph_.size(); i++) {
589         auto &bb = RegionAt(i);
590         bb.preds.clear();
591         bb.trys.clear();
592         ChunkVector<BytecodeRegion *> newSuccs(circuit_->chunk());
593         for (const auto &succ: bb.succs) {
594             newSuccs.emplace_back(succ);
595         }
596         bb.succs.clear();
597         bb.succs.insert(bb.succs.end(), newSuccs.begin(), newSuccs.end());
598     }
599     for (size_t i = 0; i < graph_.size(); i++) {
600         auto &bb = RegionAt(i);
601         for (auto &succ: bb.succs) {
602             succ->preds.emplace_back(&bb);
603             succ->numOfStatePreds++;
604         }
605         for (auto &catchBlock: bb.catches) {
606             catchBlock->trys.emplace_back(&bb);
607         }
608     }
609     UpdateEmptyCatchBB();
610 }
611 
612 // build circuit
BuildCircuitArgs()613 void BytecodeCircuitBuilder::BuildCircuitArgs()
614 {
615     argAcc_.NewCommonArg(CommonArgIdx::GLUE, MachineType::I64, GateType::NJSValue());
616     if (!method_->IsFastCall()) {
617         argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGC, MachineType::I64, GateType::NJSValue());
618         argAcc_.NewCommonArg(CommonArgIdx::ACTUAL_ARGV, MachineType::ARCH, GateType::NJSValue());
619         auto funcIdx = static_cast<size_t>(CommonArgIdx::FUNC);
620         const size_t actualNumArgs = argAcc_.GetActualNumArgs();
621         // new actual argument gates
622         for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
623             argAcc_.NewArg(argIdx);
624         }
625     } else {
626         auto funcIdx = static_cast<size_t>(FastCallArgIdx::FUNC);
627         size_t actualNumArgs = static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS) + method_->GetNumArgsWithCallField();
628         for (size_t argIdx = funcIdx; argIdx < actualNumArgs; argIdx++) {
629             argAcc_.NewArg(argIdx);
630         }
631     }
632     argAcc_.CollectArgs();
633     BuildFrameArgs();
634 }
635 
BuildFrameArgs()636 void BytecodeCircuitBuilder::BuildFrameArgs()
637 {
638     UInt32PairAccessor accessor(0, 0);
639     auto metaData = circuit_->FrameArgs(accessor.ToValue());
640     size_t numArgs = metaData->GetNumIns();
641     std::vector<GateRef> args(numArgs, Circuit::NullGate());
642     size_t idx = 0;
643     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::FUNC);
644     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::NEW_TARGET);
645     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::THIS_OBJECT);
646     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGC);
647     args[idx++] = argAcc_.GetCommonArgGate(CommonArgIdx::ACTUAL_ARGV);
648     GateRef sharedConstpool = Circuit::NullGate();
649     GateRef unSharedConstpool = Circuit::NullGate();
650     GetCurrentConstpool(argAcc_.GetCommonArgGate(CommonArgIdx::FUNC), sharedConstpool, unSharedConstpool);
651     args[idx++] = sharedConstpool;
652     args[idx++] = unSharedConstpool;
653     args[idx++] = GetPreFrameArgs();
654     GateRef frameArgs = circuit_->NewGate(metaData, args);
655     argAcc_.SetFrameArgs(frameArgs);
656 }
657 
BuildOSRArgs()658 void BytecodeCircuitBuilder::BuildOSRArgs()
659 {
660     // offset -1 : glue
661     (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_GLUE), MachineType::I64,
662                             {circuit_->GetArgRoot()}, GateType::NJSValue());
663     // offset -2 : argc
664     GateRef argc = method_->IsFastCall()
665                        ? circuit_->GetConstantGate(MachineType::I64, 0, GateType::NJSValue())
666                        : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGS), MachineType::I64,
667                                            {circuit_->GetArgRoot()}, GateType::TaggedValue());
668     // offset -3 : argv
669     GateRef argv = method_->IsFastCall()
670                        ? circuit_->GetConstantGate(MachineType::ARCH, 0, GateType::NJSValue())
671                        : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGV), MachineType::I64,
672                                            {circuit_->GetArgRoot()}, GateType::TaggedValue());
673     // offset -4 : func
674     (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_FUNCTION), MachineType::I64,
675                             {circuit_->GetArgRoot()}, GateType::TaggedValue());
676     // offset -5 : new_target
677     GateRef newTarget =
678         method_->IsFastCall()
679             ? circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType())
680             : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NEW_TARGET), MachineType::I64,
681                                 {circuit_->GetArgRoot()}, GateType::TaggedValue());
682     // offset -6 : this_object
683     (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_THIS_OBJECT), MachineType::I64,
684                             {circuit_->GetArgRoot()}, GateType::TaggedValue());
685     // offset -7 : numargs
686     (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NUM_ARGS), MachineType::I64,
687                             {circuit_->GetArgRoot()}, GateType::TaggedValue());
688     for (size_t argIdx = 1; argIdx <= method_->GetNumArgsWithCallField(); argIdx++) {
689         // common args
690         argAcc_.NewArg(method_->IsFastCall() ? static_cast<size_t>(FastCallArgIdx::NUM_OF_ARGS)
691                                              : static_cast<size_t>(CommonArgIdx::NUM_OF_ARGS) + argIdx);
692     }
693 
694     auto &args = argAcc_.args_;
695     if (args.size() == 0) {
696         GateAccessor(circuit_).GetArgsOuts(args);
697         std::reverse(args.begin(), args.end());
698         if (method_->IsFastCall() && args.size() >= static_cast<uint8_t>(FastCallArgIdx::NUM_OF_ARGS)) {
699             args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGC), argc);
700             args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::ACTUAL_ARGV), argv);
701             // 3: newtarget index
702             args.insert(args.begin() + static_cast<uint8_t>(CommonArgIdx::NEW_TARGET), newTarget);
703         }
704     }
705 
706     BuildFrameArgs();
707 }
708 
CreateGateInList(const BytecodeInfo & info,const GateMetaData * meta)709 std::vector<GateRef> BytecodeCircuitBuilder::CreateGateInList(
710     const BytecodeInfo &info, const GateMetaData *meta)
711 {
712     auto numValues = meta->GetNumIns();
713     const size_t length = meta->GetInValueStarts();
714     std::vector<GateRef> inList(numValues, Circuit::NullGate());
715     auto inputSize = info.inputs.size();
716     for (size_t i = 0; i < inputSize; i++) {
717         auto &input = info.inputs[i];
718         if (std::holds_alternative<ConstDataId>(input)) {
719             inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
720                                                            std::get<ConstDataId>(input).GetId(),
721                                                            GateType::NJSValue());
722         } else if (std::holds_alternative<Immediate>(input)) {
723             inList[i + length] = circuit_->GetConstantGate(MachineType::I64,
724                                                            std::get<Immediate>(input).GetValue(),
725                                                            GateType::NJSValue());
726         } else if (std::holds_alternative<ICSlotId>(input)) {
727             inList[i + length] = circuit_->GetConstantGate(MachineType::I16,
728                                                            std::get<ICSlotId>(input).GetId(),
729                                                            GateType::NJSValue());
730         } else {
731             ASSERT(std::holds_alternative<VirtualRegister>(input));
732             continue;
733         }
734     }
735     if (info.AccIn()) {
736         inputSize++;
737     }
738     if (meta->HasFrameState()) {
739         inList[inputSize + length] = GetFrameArgs();
740     }
741     return inList;
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         default:
804             LOG_ECMA(FATAL) << "this branch is unreachable";
805             UNREACHABLE();
806     }
807     return gate;
808 }
809 
MergeThrowGate(BytecodeRegion & bb,uint32_t bcIndex)810 void BytecodeCircuitBuilder::MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex)
811 {
812     auto state = frameStateBuilder_.GetCurrentState();
813     auto depend = frameStateBuilder_.GetCurrentDepend();
814     if (!bb.catches.empty()) {
815         auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
816         auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
817         auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
818         frameStateBuilder_.UpdateStateDepend(ifException, ifException);
819         ASSERT(bb.catches.size() == 1); // 1: one catch
820         auto bbNext = bb.catches.at(0);
821         frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
822         bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
823         state = ifSuccess;
824         depend = dependRelay;
825     }
826     auto constant = circuit_->GetConstantGate(MachineType::I64,
827                                               JSTaggedValue::VALUE_EXCEPTION,
828                                               GateType::TaggedValue());
829     circuit_->NewGate(circuit_->Return(),
830         { state, depend, constant, circuit_->GetReturnRoot() });
831 }
832 
MergeExceptionGete(BytecodeRegion & bb,const BytecodeInfo & bytecodeInfo,uint32_t bcIndex)833 void BytecodeCircuitBuilder::MergeExceptionGete(BytecodeRegion &bb,
834     const BytecodeInfo& bytecodeInfo, uint32_t bcIndex)
835 {
836     auto state = frameStateBuilder_.GetCurrentState();
837     auto depend = frameStateBuilder_.GetCurrentDepend();
838     auto ifSuccess = circuit_->NewGate(circuit_->IfSuccess(), {state});
839     auto dependRelay = circuit_->NewGate(circuit_->DependRelay(), {ifSuccess, depend});
840     ASSERT(bb.catches.size() == 1); // 1: one catch
841     auto bbNext = bb.catches.at(0);
842     auto ifException = circuit_->NewGate(circuit_->IfException(), {state, depend});
843     frameStateBuilder_.UpdateStateDepend(ifException, ifException);
844     frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
845     if (bytecodeInfo.GetOpcode() == EcmaOpcode::CREATEASYNCGENERATOROBJ_V8) {
846         bbNext->expandedPreds.push_back({bb.id, bcIndex + 1, true}); // 1: next pc
847     } else {
848         bbNext->expandedPreds.push_back({bb.id, bcIndex, true});
849     }
850     depend = dependRelay;
851     frameStateBuilder_.UpdateStateDepend(ifSuccess, depend);
852 }
853 
NewJSGate(BytecodeRegion & bb)854 void BytecodeCircuitBuilder::NewJSGate(BytecodeRegion &bb)
855 {
856     auto &iterator = bb.GetBytecodeIterator();
857     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
858     GateRef state = frameStateBuilder_.GetCurrentState();
859     GateRef depend = frameStateBuilder_.GetCurrentDepend();
860     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
861     GateRef gate = 0;
862     bool writable = !bytecodeInfo.NoSideEffects();
863     bool hasFrameState = bytecodeInfo.HasFrameState();
864     size_t pcOffset = GetPcOffset(iterator.Index());
865     auto methodOffset = method_->GetMethodId().GetOffset();
866     auto meta = circuit_->JSBytecode(
867         numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), writable, hasFrameState);
868     std::vector<GateRef> inList = CreateGateInList(bytecodeInfo, meta);
869     if (bytecodeInfo.IsDef()) {
870         gate = circuit_->NewGate(meta, MachineType::I64, inList.size(),
871                                  inList.data(), GateType::AnyType());
872     } else {
873         gate = circuit_->NewGate(meta, MachineType::NOVALUE, inList.size(),
874                                  inList.data(), GateType::Empty());
875     }
876     byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
877     jsGatesToByteCode_[gate] = iterator.Index();
878     gateAcc_.NewIn(gate, 0, state);
879     gateAcc_.NewIn(gate, 1, depend);
880     frameStateBuilder_.UpdateStateDepend(gate, gate);
881     frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
882     if (bytecodeInfo.IsThrow()) {
883         MergeThrowGate(bb, iterator.Index());
884         return;
885     }
886 
887     if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
888         MergeExceptionGete(bb, bytecodeInfo, iterator.Index());
889     } else if (!bb.catches.empty()) {
890         frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
891     }
892     if (bytecodeInfo.IsGeneratorRelative()) {
893         suspendAndResumeGates_.emplace_back(gate);
894     }
895 }
896 
NewJump(BytecodeRegion & bb)897 void BytecodeCircuitBuilder::NewJump(BytecodeRegion &bb)
898 {
899     auto &iterator = bb.GetBytecodeIterator();
900     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
901     GateRef state = frameStateBuilder_.GetCurrentState();
902     GateRef depend = frameStateBuilder_.GetCurrentDepend();
903     size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
904     if (bytecodeInfo.IsCondJump() && bb.succs.size() == 2) { // 2: two succ
905         size_t pcOffset = GetPcOffset(iterator.Index());
906         auto methodOffset = method_->GetMethodId().GetOffset();
907         auto meta = circuit_->JSBytecode(
908             numValueInputs, methodOffset, bytecodeInfo.GetOpcode(), pcOffset, iterator.Index(), false, false);
909         auto numValues = meta->GetNumIns();
910         GateRef gate = circuit_->NewGate(meta, std::vector<GateRef>(numValues, Circuit::NullGate()));
911         gateAcc_.NewIn(gate, 0, state);
912         gateAcc_.NewIn(gate, 1, depend);
913         frameStateBuilder_.UpdateStateDepend(gate, gate);
914         frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
915 
916         auto ifTrue = circuit_->NewGate(circuit_->IfTrue(), {gate});
917         auto trueRelay = circuit_->NewGate(circuit_->DependRelay(), {ifTrue, gate});
918         auto ifFalse = circuit_->NewGate(circuit_->IfFalse(), {gate});
919         auto falseRelay = circuit_->NewGate(circuit_->DependRelay(), {ifFalse, gate});
920         for (auto &bbNext: bb.succs) {
921             if (iterator.Index() + 1 == bbNext->start) {
922                 frameStateBuilder_.UpdateStateDepend(ifFalse, falseRelay);
923                 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
924                 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
925             } else {
926                 frameStateBuilder_.UpdateStateDepend(ifTrue, trueRelay);
927                 frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
928                 bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
929             }
930         }
931         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
932         jsGatesToByteCode_[gate] = iterator.Index();
933     } else {
934         ASSERT(bb.succs.size() == 1); // 1: only one succ if not condjump
935         auto &bbNext = bb.succs.at(0);
936         frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
937         bbNext->expandedPreds.push_back({bb.id, iterator.Index(), false});
938     }
939 
940     if (!bb.catches.empty()) {
941         frameStateBuilder_.GetOrOCreateMergedContext(bb.catches.at(0)->id);
942     }
943 }
944 
NewReturn(BytecodeRegion & bb)945 GateRef BytecodeCircuitBuilder::NewReturn(BytecodeRegion &bb)
946 {
947     ASSERT(bb.succs.empty());
948     auto &iterator = bb.GetBytecodeIterator();
949     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
950     GateRef state = frameStateBuilder_.GetCurrentState();
951     GateRef depend = frameStateBuilder_.GetCurrentDepend();
952     GateRef gate = Circuit::NullGate();
953     if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURN) {
954         // handle return.dyn bytecode
955         gate = circuit_->NewGate(circuit_->Return(),
956             { state, depend, Circuit::NullGate(), circuit_->GetReturnRoot() });
957         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
958         jsGatesToByteCode_[gate] = iterator.Index();
959     } else if (bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED) {
960         // handle returnundefined bytecode
961         auto constant = circuit_->GetConstantGate(MachineType::I64,
962                                                   JSTaggedValue::VALUE_UNDEFINED,
963                                                   GateType::TaggedValue());
964         gate = circuit_->NewGate(circuit_->Return(),
965             { state, depend, constant, circuit_->GetReturnRoot() });
966         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
967         jsGatesToByteCode_[gate] = iterator.Index();
968     }
969     return gate;
970 }
971 
NewByteCode(BytecodeRegion & bb)972 void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb)
973 {
974     auto &iterator = bb.GetBytecodeIterator();
975     const BytecodeInfo& bytecodeInfo = iterator.GetBytecodeInfo();
976     FrameLiveOut* liveout;
977     auto bcId = iterator.Index();
978     if (bcId != 0 && iterator.IsInRange(bcId - 1)) {
979         liveout = frameStateBuilder_.GetOrOCreateBCEndLiveOut(bcId - 1);
980     } else {
981         liveout = frameStateBuilder_.GetOrOCreateBBLiveOut(bb.id);
982     }
983     frameStateBuilder_.AdvanceToNextBc(bytecodeInfo, liveout, bcId);
984     GateRef gate = Circuit::NullGate();
985     if (bytecodeInfo.IsSetConstant()) {
986         // handle bytecode command to get constants
987         gate = NewConst(bytecodeInfo);
988         byteCodeToJSGates_[iterator.Index()].emplace_back(gate);
989         jsGatesToByteCode_[gate] = iterator.Index();
990     } else if (bytecodeInfo.IsGeneral()) {
991         // handle general ecma.* bytecodes
992         NewJSGate(bb);
993     } else if (bytecodeInfo.IsJump()) {
994         // handle conditional jump and unconditional jump bytecodes
995         NewJump(bb);
996     } else if (bytecodeInfo.IsReturn()) {
997         // handle return.dyn and returnundefined bytecodes
998         gate = NewReturn(bb);
999     } else if (bytecodeInfo.IsMov()) {
1000         frameStateBuilder_.UpdateMoveValues(bytecodeInfo);
1001     } else if (!bytecodeInfo.IsDiscarded()) {
1002         LOG_ECMA(FATAL) << "this branch is unreachable";
1003         UNREACHABLE();
1004     }
1005     if (gate != Circuit::NullGate()) {
1006         frameStateBuilder_.UpdateFrameValues(bytecodeInfo, iterator.Index(), gate);
1007     }
1008 }
1009 
BuildSubCircuit()1010 void BytecodeCircuitBuilder::BuildSubCircuit()
1011 {
1012     auto &entryBlock = RegionAt(0);
1013     frameStateBuilder_.InitEntryBB(entryBlock);
1014     auto& rpoList = frameStateBuilder_.GetRpoList();
1015     for (auto &bbId: rpoList) {
1016         auto &bb = RegionAt(bbId);
1017         frameStateBuilder_.AdvanceToNextBB(bb);
1018         if (IsEntryBlock(bb.id)) {
1019             if (NeedCheckSafePointAndStackOver()) {
1020                 GateRef state = frameStateBuilder_.GetCurrentState();
1021                 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1022                 auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
1023                 bb.dependCache = stackCheck;
1024                 frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
1025             }
1026             auto &bbNext = RegionAt(bb.id + 1);
1027             frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
1028             bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1029             continue;
1030         }
1031         if (!bb.trys.empty()) {
1032             GateRef state = frameStateBuilder_.GetCurrentState();
1033             GateRef depend = frameStateBuilder_.GetCurrentDepend();
1034             auto getException = circuit_->NewGate(circuit_->GetException(),
1035                 MachineType::I64, {state, depend}, GateType::AnyType());
1036             frameStateBuilder_.UpdateAccumulator(getException);
1037             frameStateBuilder_.UpdateStateDepend(state, getException);
1038         }
1039         EnumerateBlock(bb, [this, &bb]
1040             (const BytecodeInfo &bytecodeInfo) -> bool {
1041             NewByteCode(bb);
1042             if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1043                 return false;
1044             }
1045             return true;
1046         });
1047         bool needFallThrough = true;
1048         if (!bb.IsEmptryBlock()) {
1049             const BytecodeInfo& bytecodeInfo = GetBytecodeInfo(bb.end);
1050             needFallThrough = bytecodeInfo.needFallThrough();
1051         }
1052         // fallThrough or empty merge bb
1053         if (needFallThrough) {
1054             ASSERT(bb.succs.size() == 1); // 1: fall through
1055             auto &bbNext = RegionAt(bb.succs[0]->id);
1056             frameStateBuilder_.MergeIntoSuccessor(bb, bbNext);
1057             bbNext.expandedPreds.push_back({bb.id, bb.end, false});
1058         }
1059     }
1060 }
1061 
FindOsrLoopHeadBB()1062 bool BytecodeCircuitBuilder::FindOsrLoopHeadBB()
1063 {
1064     int32_t loopBackBcIndex {-1};
1065     for (size_t k = 0; k < pcOffsets_.size(); k++) {
1066         if (static_cast<int32_t>(pcOffsets_[k] - pcOffsets_[0]) == osrOffset_) {
1067             loopBackBcIndex = static_cast<int32_t>(k);
1068         }
1069     }
1070     if (loopBackBcIndex == -1) {
1071         LOG_COMPILER(ERROR) << "Unable to find the loop back of OSR.";
1072         return false;
1073     }
1074     auto &rpoList = frameStateBuilder_.GetRpoList();
1075     for (auto &bbId : rpoList) {
1076         auto &bb = RegionAt(bbId);
1077         if (bb.end == static_cast<uint32_t>(loopBackBcIndex)) {
1078             frameStateBuilder_.SetOsrLoopHeadBB(bb);
1079             return true;
1080         }
1081     }
1082     LOG_COMPILER(ERROR) << "Unable to find the loop head bb of OSR.";
1083     return false;
1084 }
1085 
GenDeoptAndReturnForOsrLoopExit(BytecodeRegion & osrLoopExitBB)1086 void BytecodeCircuitBuilder::GenDeoptAndReturnForOsrLoopExit(BytecodeRegion &osrLoopExitBB)
1087 {
1088     frameStateBuilder_.AdvanceToNextBB(osrLoopExitBB, true);
1089     GateRef state = frameStateBuilder_.GetCurrentState();
1090     GateRef depend = frameStateBuilder_.GetCurrentDepend();
1091     std::string comment = Deoptimizier::DisplayItems(DeoptType::OSRLOOPEXIT);
1092     GateRef type =
1093         circuit_->GetConstantGate(MachineType::I64, static_cast<int64_t>(DeoptType::OSRLOOPEXIT), GateType::NJSValue());
1094     GateRef condition = circuit_->GetConstantGate(MachineType::I1, 0, GateType::NJSValue());
1095     GateRef deopt = circuit_->NewGate(circuit_->DeoptCheck(), MachineType::I1,
1096                                       {state, depend, condition, gateAcc_.GetFrameState(depend), type},
1097                                       GateType::NJSValue(), comment.c_str());
1098     GateRef dependRelay = circuit_->NewGate(circuit_->DependRelay(), {deopt, depend});
1099     GateRef undef =
1100         circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::TaggedValue());
1101     circuit_->NewGate(circuit_->Return(), {state, dependRelay, undef, circuit_->GetReturnRoot()});
1102 }
1103 
CollectCacheBBforOSRLoop(BytecodeRegion * bb)1104 void BytecodeCircuitBuilder::CollectCacheBBforOSRLoop(BytecodeRegion *bb)
1105 {
1106     catchBBOfOSRLoop_.insert(bb);
1107     for (BytecodeRegion *succBB : bb->succs) {
1108         CollectCacheBBforOSRLoop(succBB);
1109     }
1110 }
1111 
HandleOsrLoopBody(BytecodeRegion & osrLoopBodyBB)1112 void BytecodeCircuitBuilder::HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB)
1113 {
1114     if (!osrLoopBodyBB.trys.empty()) {
1115         GateRef state = frameStateBuilder_.GetCurrentState();
1116         GateRef depend = frameStateBuilder_.GetCurrentDepend();
1117         auto getException =
1118             circuit_->NewGate(circuit_->GetException(), MachineType::I64, {state, depend}, GateType::AnyType());
1119         frameStateBuilder_.UpdateAccumulator(getException);
1120         frameStateBuilder_.UpdateStateDepend(state, getException);
1121     }
1122     // collect catch BB.
1123     if (!osrLoopBodyBB.catches.empty()) {
1124         for (BytecodeRegion *targetBB : osrLoopBodyBB.catches) {
1125             CollectCacheBBforOSRLoop(targetBB);
1126         }
1127     }
1128     EnumerateBlock(osrLoopBodyBB, [this, &osrLoopBodyBB](const BytecodeInfo &bytecodeInfo) -> bool {
1129         NewByteCode(osrLoopBodyBB);
1130         if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) {
1131             return false;
1132         }
1133         return true;
1134     });
1135     bool needFallThrough = true;
1136     if (!osrLoopBodyBB.IsEmptryBlock()) {
1137         const BytecodeInfo &bytecodeInfo = GetBytecodeInfo(osrLoopBodyBB.end);
1138         needFallThrough = bytecodeInfo.needFallThrough();
1139     }
1140     // fallThrough or empty merge osrLoopBodyBB
1141     if (needFallThrough) {
1142         ASSERT(osrLoopBodyBB.succs.size() == 1);  // 1: fall through
1143         auto &bbNext = RegionAt(osrLoopBodyBB.succs[0]->id);
1144         frameStateBuilder_.MergeIntoSuccessor(osrLoopBodyBB, bbNext);
1145         bbNext.expandedPreds.push_back({osrLoopBodyBB.id, osrLoopBodyBB.end, false});
1146     }
1147 }
1148 
BuildOsrCircuit()1149 void BytecodeCircuitBuilder::BuildOsrCircuit()
1150 {
1151     if (!FindOsrLoopHeadBB()) {
1152         LOG_COMPILER(FATAL) << "invalid osr offset";
1153     }
1154     circuit_->SetIsOsr();
1155     auto &entryBlock = RegionAt(0);
1156     frameStateBuilder_.InitEntryBB(entryBlock);
1157     std::set<size_t> osrLoopExitBBIds;
1158     auto &rpoList = frameStateBuilder_.GetRpoList();
1159     for (auto &bbId : rpoList) {
1160         auto &bb = RegionAt(bbId);
1161         if (frameStateBuilder_.IsOsrLoopExit(bb)) {
1162             // The loop exit BB is in front of the loop head BB. At this time,
1163             // the loop exit BB does not have the context object, and the processing of the loop exit BB is delayed.
1164             if (frameStateBuilder_.IsContextExists(bb.id)) {
1165                 GenDeoptAndReturnForOsrLoopExit(bb);
1166             } else {
1167                 osrLoopExitBBIds.insert(bbId);
1168             }
1169             continue;
1170         }
1171 
1172         // Processes only the BBs related to the loop specified by the OSR.
1173         if (!IsEntryBlock(bb.id) && frameStateBuilder_.OutOfOsrLoop(bb) && !IsCacheBBOfOSRLoop(bb)) {
1174             continue;
1175         }
1176 
1177         frameStateBuilder_.AdvanceToNextBB(bb);
1178         if (IsEntryBlock(bb.id)) {
1179             if (NeedCheckSafePointAndStackOver()) {
1180                 GateRef state = frameStateBuilder_.GetCurrentState();
1181                 GateRef depend = frameStateBuilder_.GetCurrentDepend();
1182                 auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend});
1183                 bb.dependCache = stackCheck;
1184                 frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck);
1185             }
1186             auto *bbNext = &RegionAt(bb.id + 1);
1187             while (!IsEntryBlock(bbNext->id) && frameStateBuilder_.OutOfOsrLoop(*bbNext)) {
1188                 bbNext = &RegionAt(bbNext->id + 1);
1189             }
1190             frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext);
1191             bbNext->expandedPreds.push_back({bb.id, bb.end, false});
1192             continue;
1193         }
1194 
1195         HandleOsrLoopBody(bb);
1196     }
1197     for (size_t bbId : osrLoopExitBBIds) {
1198         auto &bb = RegionAt(bbId);
1199         GenDeoptAndReturnForOsrLoopExit(bb);
1200     }
1201 }
1202 
BuildCircuit()1203 void BytecodeCircuitBuilder::BuildCircuit()
1204 {
1205     if (IsOSR()) {
1206         // create osr arg gates array
1207         BuildOSRArgs();
1208         frameStateBuilder_.DoBytecodeAnalysis();
1209         if (TerminateAnalysis()) {
1210             return;
1211         }
1212         // build states sub-circuit of osr block
1213         BuildOsrCircuit();
1214     } else {
1215         // create arg gates array
1216         BuildCircuitArgs();
1217         frameStateBuilder_.DoBytecodeAnalysis();
1218         if (TerminateAnalysis()) {
1219             return;
1220         }
1221         // build states sub-circuit of each block
1222         BuildSubCircuit();
1223     }
1224     if (IsLogEnabled()) {
1225         PrintGraph(std::string("Bytecode2Gate [" + methodName_ + "]").c_str());
1226         LOG_COMPILER(INFO) << "\033[34m" << "============= "
1227                            << "After bytecode2circuit lowering ["
1228                            << methodName_ << "]"
1229                            << " =============" << "\033[0m";
1230         circuit_->PrintAllGatesWithBytecode();
1231         LOG_COMPILER(INFO) << "\033[34m" << "=========================== End ===========================" << "\033[0m";
1232     }
1233 }
1234 
PrintGraph(const char * title)1235 void BytecodeCircuitBuilder::PrintGraph(const char* title)
1236 {
1237     LOG_COMPILER(INFO) << "======================== " << title << " ========================";
1238     for (size_t i = 0; i < graph_.size(); i++) {
1239         BytecodeRegion& bb = RegionAt(i);
1240         if (!IsEntryBlock(bb.id) && bb.numOfStatePreds == 0) {
1241             LOG_COMPILER(INFO) << "B" << bb.id << ":                               ;preds= invalid BB";
1242             LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1243                                << std::to_string(bb.end) << ")";
1244             continue;
1245         }
1246         std::string log("B" + std::to_string(bb.id) + ":                               ;preds= ");
1247         for (size_t k = 0; k < bb.preds.size(); ++k) {
1248             log += std::to_string(bb.preds[k]->id) + ", ";
1249         }
1250         LOG_COMPILER(INFO) << log;
1251         if (IsEntryBlock(bb.id)) {
1252             LOG_COMPILER(INFO) << "\tBytecodePC: Empty";
1253         } else {
1254             LOG_COMPILER(INFO) << "\tBytecodePC: [" << std::to_string(bb.start) << ", "
1255                 << std::to_string(bb.end) << ")";
1256         }
1257 
1258         std::string log1("\tSucces: ");
1259         for (size_t j = 0; j < bb.succs.size(); j++) {
1260             log1 += std::to_string(bb.succs[j]->id) + ", ";
1261         }
1262         LOG_COMPILER(INFO) << log1;
1263 
1264         for (size_t j = 0; j < bb.catches.size(); j++) {
1265             LOG_COMPILER(INFO) << "\tcatch [: " << std::to_string(bb.catches[j]->start) << ", "
1266                                << std::to_string(bb.catches[j]->end) << ")";
1267         }
1268 
1269         std::string log2("\tTrys: ");
1270         for (auto tryBlock: bb.trys) {
1271             log2 += std::to_string(tryBlock->id) + " , ";
1272         }
1273         LOG_COMPILER(INFO) << log2;
1274 
1275         PrintBytecodeInfo(bb);
1276         LOG_COMPILER(INFO) << "";
1277     }
1278 }
1279 
PrintBytecodeInfo(BytecodeRegion & bb)1280 void BytecodeCircuitBuilder::PrintBytecodeInfo(BytecodeRegion& bb)
1281 {
1282     if (IsEntryBlock(bb.id)) {
1283         LOG_COMPILER(INFO) << "\tBytecode[] = Empty";
1284         return;
1285     }
1286     LOG_COMPILER(INFO) << "\tBytecode[] = ";
1287     EnumerateBlock(bb, [&](const BytecodeInfo &bytecodeInfo) -> bool {
1288         auto &iterator = bb.GetBytecodeIterator();
1289         std::string log;
1290         log += std::string("\t\t< ") + std::to_string(iterator.Index()) + ": ";
1291         log += GetEcmaOpcodeStr(iterator.GetBytecodeInfo().GetOpcode()) + ", " + "In=[";
1292         if (bytecodeInfo.AccIn()) {
1293             log += "acc,";
1294         }
1295         for (const auto &in: bytecodeInfo.inputs) {
1296             if (std::holds_alternative<VirtualRegister>(in)) {
1297                 log += std::to_string(std::get<VirtualRegister>(in).GetId()) + ",";
1298             }
1299         }
1300         log += "], Out=[";
1301         if (bytecodeInfo.AccOut()) {
1302             log += "acc,";
1303         }
1304         for (const auto &out: bytecodeInfo.vregOut) {
1305             log += std::to_string(out) + ",";
1306         }
1307         log += "] >";
1308         LOG_COMPILER(INFO) << log;
1309 
1310         auto gate = GetGateByBcIndex(iterator.Index());
1311         if (gate != Circuit::NullGate()) {
1312             this->gateAcc_.ShortPrint(gate);
1313         }
1314         return true;
1315     });
1316 }
1317 }  // namespace panda::ecmascript::kungfu
1318