• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2025 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 "CFG.h"
17 #include "public/public.h"
18 #include "util/helpers.h"
19 
20 namespace ark::es2panda::compiler {
21 
BasicBlock(ArenaAllocator * allocator,size_t index)22 CFG::BasicBlock::BasicBlock(ArenaAllocator *allocator, size_t index) noexcept
23     : index_(index), nodes_(allocator->Adapter()), succs_(allocator->Adapter()), preds_(allocator->Adapter())
24 {
25 }
26 
AddNode(ir::AstNode * node)27 size_t CFG::BasicBlock::AddNode(ir::AstNode *node)
28 {
29     nodes_.push_back(node);
30     return nodes_.size() - 1;
31 }
32 
AddSuccessor(BasicBlock * successor)33 std::pair<size_t, size_t> CFG::BasicBlock::AddSuccessor(BasicBlock *successor)
34 {
35     succs_.push_back(successor);
36     ES2PANDA_ASSERT(successor != nullptr);
37     successor->preds_.push_back(this);
38     return std::make_pair(succs_.size() - 1, successor->preds_.size() - 1);
39 }
AddPredecessor(BasicBlock * predecessor)40 std::pair<size_t, size_t> CFG::BasicBlock::AddPredecessor(BasicBlock *predecessor)
41 {
42     preds_.push_back(predecessor);
43     predecessor->succs_.push_back(this);
44     return std::make_pair(preds_.size() - 1, predecessor->succs_.size() - 1);
45 }
46 
GetIndex() const47 size_t CFG::BasicBlock::GetIndex() const
48 {
49     return index_;
50 }
51 
GetFlags() const52 CFG::BasicBlockFlags CFG::BasicBlock::GetFlags() const
53 {
54     return flags_;
55 }
56 
GetSize() const57 size_t CFG::BasicBlock::GetSize() const
58 {
59     return nodes_.size();
60 }
61 
GetSuccessors() const62 const ArenaVector<CFG::BasicBlock *> &CFG::BasicBlock::GetSuccessors() const
63 {
64     return succs_;
65 }
GetPredecessors() const66 const ArenaVector<CFG::BasicBlock *> &CFG::BasicBlock::GetPredecessors() const
67 {
68     return preds_;
69 }
70 
GetNodes() const71 const ArenaVector<ir::AstNode *> &CFG::BasicBlock::GetNodes() const
72 {
73     return nodes_;
74 }
75 
GetLastNode() const76 ir::AstNode *CFG::BasicBlock::GetLastNode() const
77 {
78     if (nodes_.empty()) {
79         return nullptr;
80     }
81     return nodes_.back();
82 }
83 
CFG(ArenaAllocator * allocator)84 CFG::CFG(ArenaAllocator *allocator)
85     : allocator_(allocator),
86       blocks_(allocator_->Adapter()),
87       nodeBBMap_(allocator_->Adapter()),
88       functionNodeBBMap_(allocator_->Adapter()),
89       bbAnnotationMap_(allocator_->Adapter()),
90       switchCaseMap_(allocator_->Adapter()),
91       bbSuccLabelMap_(allocator_->Adapter()),
92       bbPredLabelMap_(allocator_->Adapter()),
93       loopStmtJumpTargetMap_(allocator_->Adapter()),
94       trueLabel_(true),
95       falseLabel_(false)
96 {
97 }
98 
RedirectEmptyBBEdges(CFG::BasicBlock * bb) const99 void CFG::RedirectEmptyBBEdges(CFG::BasicBlock *bb) const
100 {
101     for (auto pred : bb->preds_) {
102         for (auto &succ : pred->succs_) {
103             if (succ == bb) {
104                 succ = bb->succs_[0];
105                 break;
106             }
107         }
108     }
109 }
110 
MergeEmptyBlocks()111 void CFG::MergeEmptyBlocks()
112 {
113     std::list<CFG::BasicBlock *> merged;
114 
115     for (auto bb : blocks_) {
116         if (bb->nodes_.empty() && bb->succs_.empty() && bb->preds_.empty()) {
117             merged.push_back(bb);
118             continue;
119         }
120 
121         if (!(bb->nodes_.empty() && bb->succs_.size() == 1 && bbSuccLabelMap_.find(bb) == bbSuccLabelMap_.end())) {
122             continue;
123         }
124 
125         RedirectEmptyBBEdges(bb);
126         auto succ = bb->succs_[0];
127 
128         if (succ == bb) {
129             continue;
130         }
131 
132         if (bb->preds_.empty()) {
133             merged.push_back(bb);
134             continue;
135         }
136         // replace the previous predecessor with the first predecessor of the bb to be deleted if it exists
137         for (size_t index = 0; index < succ->preds_.size(); ++index) {
138             if (succ->preds_[index] == bb) {
139                 succ->preds_[index] = bb->preds_[0];
140                 SetBBPredEdgeLabel(succ, index, GetBBPredEdgeLabel(bb, 0));
141                 break;
142             }
143         }
144         // add the remaining predecessors to the successor node
145         for (size_t index = 1; index < bb->preds_.size(); ++index) {
146             bb->succs_[0]->preds_.push_back(bb->preds_[index]);
147             SetBBPredEdgeLabel(bb->succs_[0], bb->succs_[0]->preds_.size() - 1, GetBBPredEdgeLabel(bb, index));
148         }
149         merged.push_back(bb);
150     }
151 
152     // remove the merged blocks
153     for (auto bb : merged) {
154         blocks_.erase(bb);
155         bbAnnotationMap_.erase(bb);
156         bbPredLabelMap_.erase(bb);
157         bbSuccLabelMap_.erase(bb);
158     }
159 }
160 
GetBBPredEdgeLabel(const BasicBlock * bb,size_t index) const161 const ir::AstNode *CFG::GetBBPredEdgeLabel(const BasicBlock *bb, size_t index) const
162 {
163     const ir::AstNode *result = nullptr;
164     if (auto predIt = bbPredLabelMap_.find(bb); predIt != bbPredLabelMap_.end()) {
165         auto labelIt = predIt->second.find(index);
166         if (labelIt != predIt->second.end()) {
167             result = labelIt->second;
168         }
169     }
170     return result;
171 }
172 
173 /* pair<condition, label> */
GetBBPredCondition(const BasicBlock * bb,size_t index) const174 std::pair<ir::AstNode *, const ir::AstNode *> CFG::GetBBPredCondition(const BasicBlock *bb, size_t index) const
175 {
176     auto label = GetBBPredEdgeLabel(bb, index);
177     if (label == nullptr) {
178         return {nullptr, nullptr};
179     }
180 
181     auto predBB = bb->preds_[index];
182     return {predBB->nodes_[predBB->nodes_.size() - 1], label};
183 }
184 
GetBBSuccEdgeLabel(const BasicBlock * bb,size_t index) const185 const ir::AstNode *CFG::GetBBSuccEdgeLabel(const BasicBlock *bb, size_t index) const
186 {
187     const ir::AstNode *result = nullptr;
188     if (auto succIt = bbSuccLabelMap_.find(bb); succIt != bbSuccLabelMap_.end()) {
189         auto labelIt = succIt->second.find(index);
190         if (labelIt != succIt->second.end()) {
191             result = labelIt->second;
192         }
193     }
194     return result;
195 }
196 
Build(ir::ScriptFunction * scriptFunctionNode)197 CFG::BasicBlock *CFG::Build(ir::ScriptFunction *scriptFunctionNode)
198 {
199     if (!scriptFunctionNode->HasBody()) {
200         return nullptr;
201     }
202 
203     BasicBlock *entryBB = CreateNewBB({});
204     ES2PANDA_ASSERT(entryBB != nullptr);
205     entryBB->SetFlag(BasicBlockFlags::ENTRY);
206     functionNodeBBMap_[scriptFunctionNode] = entryBB;
207     if (scriptFunctionNode->Id() != nullptr) {
208         bbAnnotationMap_[entryBB] =
209             util::Helpers::EscapeHTMLString(allocator_, scriptFunctionNode->Id()->Name().Mutf8());
210     }
211     ES2PANDA_ASSERT(scriptFunctionNode->Body()->IsBlockStatement());
212     auto exitBB = Build(scriptFunctionNode->Body()->AsBlockStatement(), entryBB);
213     ES2PANDA_ASSERT(exitBB != nullptr);
214     exitBB->SetFlag(BasicBlockFlags::EXIT);
215     return entryBB;
216 }
217 
HasFlag(BasicBlockFlags flag) const218 bool CFG::BasicBlock::HasFlag(BasicBlockFlags flag) const
219 {
220     return (flags_ & flag) != 0;
221 }
222 
SetFlag(BasicBlockFlags flag)223 void CFG::BasicBlock::SetFlag(BasicBlockFlags flag)
224 {
225     flags_ |= flag;
226 }
227 
ClearFlag(BasicBlockFlags flag)228 void CFG::BasicBlock::ClearFlag(BasicBlockFlags flag)
229 {
230     flags_ &= ~flag;
231 }
232 
CreateNewBB(const std::vector<BasicBlock * > && preds,const std::vector<const ir::AstNode * > && labels)233 CFG::BasicBlock *CFG::CreateNewBB(const std::vector<BasicBlock *> &&preds,
234                                   const std::vector<const ir::AstNode *> &&labels)
235 {
236     auto bb = allocator_->New<BasicBlock>(allocator_, basicBlockIdx_++);
237     ES2PANDA_ASSERT(bb != nullptr);
238     if (inLoop_ > 0) {
239         bb->SetFlag(BasicBlockFlags::LOOP);
240     }
241     for (size_t pi = 0; pi < preds.size(); ++pi) {
242         if (preds[pi] == nullptr) {
243             continue;
244         }
245 
246         auto [predIndex, succIndex] = bb->AddPredecessor(preds[pi]);
247         if (labels.size() > pi && labels[pi] != nullptr) {
248             SetBBPredEdgeLabel(bb, predIndex, labels[pi]);
249             SetBBSuccEdgeLabel(preds[pi], succIndex, labels[pi]);
250             if (labels[pi] == &trueLabel_ || labels[pi] == &falseLabel_) {
251                 preds[pi]->SetFlag(BasicBlockFlags::CONDITION);
252             }
253         }
254     }
255 
256     blocks_.insert(bb);
257     return bb;
258 }
259 
SetBBPredEdgeLabel(const BasicBlock * bb,size_t index,const ir::AstNode * label)260 void CFG::SetBBPredEdgeLabel(const BasicBlock *bb, size_t index, const ir::AstNode *label)
261 {
262     if (label == nullptr) {
263         return;
264     }
265 
266     auto insertPred = bbPredLabelMap_.emplace(bb, allocator_->Adapter());
267     insertPred.first->second.emplace(index, label);
268 }
SetBBSuccEdgeLabel(const BasicBlock * bb,size_t index,const ir::AstNode * label)269 void CFG::SetBBSuccEdgeLabel(const BasicBlock *bb, size_t index, const ir::AstNode *label)
270 {
271     if (label == nullptr) {
272         return;
273     }
274 
275     auto insertSucc = bbSuccLabelMap_.emplace(bb, allocator_->Adapter());
276     insertSucc.first->second.emplace(index, label);
277 }
278 
BuildExpressions(ir::AstNode * node,CFG::BasicBlock * bb)279 CFG::BasicBlock *CFG::BuildExpressions(ir::AstNode *node, CFG::BasicBlock *bb)
280 {
281     switch (node->Type()) {
282         case ir::AstNodeType::ARRAY_EXPRESSION:
283             return Build(node->AsArrayExpression(), bb);
284         case ir::AstNodeType::ARROW_FUNCTION_EXPRESSION:
285             return Build(node->AsArrowFunctionExpression(), bb);
286         case ir::AstNodeType::ASSIGNMENT_EXPRESSION:
287             return Build(node->AsAssignmentExpression(), bb);
288         case ir::AstNodeType::BINARY_EXPRESSION:
289             return Build(node->AsBinaryExpression(), bb);
290         case ir::AstNodeType::BLOCK_EXPRESSION:  // The expression itself is excluded
291             return Build(node->AsBlockExpression(), bb);
292         case ir::AstNodeType::CALL_EXPRESSION:  // NOTE: Call edge is missing
293             return Build(node->AsCallExpression(), bb);
294         case ir::AstNodeType::CATCH_CLAUSE:
295             return Build(node->AsCatchClause(), bb);
296         case ir::AstNodeType::CHAIN_EXPRESSION:
297             return Build(node->AsChainExpression(), bb);
298         case ir::AstNodeType::CONDITIONAL_EXPRESSION:  // The expression itself is excluded
299             return Build(node->AsConditionalExpression(), bb);
300         case ir::AstNodeType::MEMBER_EXPRESSION:
301             return Build(node->AsMemberExpression(), bb);
302         case ir::AstNodeType::TYPEOF_EXPRESSION:
303             return Build(node->AsTypeofExpression(), bb);
304         case ir::AstNodeType::UNARY_EXPRESSION:
305             return Build(node->AsUnaryExpression(), bb);
306         case ir::AstNodeType::UPDATE_EXPRESSION:
307             return Build(node->AsUpdateExpression(), bb);
308         default:
309             return nullptr;
310     }
311 }
312 
BuildETSExpressions(ir::AstNode * node,CFG::BasicBlock * bb)313 CFG::BasicBlock *CFG::BuildETSExpressions(ir::AstNode *node, CFG::BasicBlock *bb)
314 {
315     switch (node->Type()) {
316         case ir::AstNodeType::ETS_NEW_CLASS_INSTANCE_EXPRESSION:  // NOTE: Call edge to the constructor is missing
317             return Build(node->AsETSNewClassInstanceExpression(), bb);
318         case ir::AstNodeType::ETS_TYPE_REFERENCE:
319             return bb;
320         case ir::AstNodeType::TS_AS_EXPRESSION:
321             return Build(node->AsTSAsExpression(), bb);
322         case ir::AstNodeType::TS_NON_NULL_EXPRESSION:
323             return Build(node->AsTSNonNullExpression(), bb);
324         default:
325             return nullptr;
326     }
327 }
328 
BuildStatements(ir::AstNode * node,CFG::BasicBlock * bb)329 CFG::BasicBlock *CFG::BuildStatements(ir::AstNode *node, CFG::BasicBlock *bb)
330 {
331     switch (node->Type()) {
332         case ir::AstNodeType::BLOCK_STATEMENT:
333             return Build(node->AsBlockStatement(), bb);
334         case ir::AstNodeType::BREAK_STATEMENT:
335             return Build(node->AsBreakStatement(), bb);
336         case ir::AstNodeType::CONTINUE_STATEMENT:
337             return Build(node->AsContinueStatement(), bb);
338         case ir::AstNodeType::EMPTY_STATEMENT:
339             return bb;
340         case ir::AstNodeType::EXPRESSION_STATEMENT:
341             return Build(node->AsExpressionStatement(), bb);
342         case ir::AstNodeType::FOR_OF_STATEMENT:
343             return Build(node->AsForOfStatement(), bb);
344         case ir::AstNodeType::FOR_UPDATE_STATEMENT:
345             return Build(node->AsForUpdateStatement(), bb);
346         case ir::AstNodeType::IF_STATEMENT:
347             return Build(node->AsIfStatement(), bb);
348         case ir::AstNodeType::LABELLED_STATEMENT:
349             return Build(node->AsLabelledStatement(), bb);
350         case ir::AstNodeType::RETURN_STATEMENT:
351             return Build(node->AsReturnStatement(), bb);
352         case ir::AstNodeType::SWITCH_STATEMENT:
353             return Build(node->AsSwitchStatement(), bb);
354         case ir::AstNodeType::THROW_STATEMENT:
355             return Build(node->AsThrowStatement(), bb);
356         case ir::AstNodeType::TRY_STATEMENT:
357             return Build(node->AsTryStatement(), bb);
358         case ir::AstNodeType::VARIABLE_DECLARATION:
359             return Build(node->AsVariableDeclaration(), bb);
360         case ir::AstNodeType::WHILE_STATEMENT:
361             return Build(node->AsWhileStatement(), bb);
362         case ir::AstNodeType::DO_WHILE_STATEMENT:
363             return Build(node->AsDoWhileStatement(), bb);
364         default:
365             return nullptr;
366     }
367 }
368 
Build(ir::AstNode * node,CFG::BasicBlock * bb)369 CFG::BasicBlock *CFG::Build(ir::AstNode *node, CFG::BasicBlock *bb)
370 {
371     if (node == nullptr) {
372         return bb;
373     }
374 
375     if (bb == nullptr) {
376         return nullptr;
377     }
378 
379     BasicBlock *stmtBB = BuildStatements(node, bb);
380     if (stmtBB != nullptr) {
381         return stmtBB;
382     }
383 
384     BasicBlock *exprBB = BuildExpressions(node, bb);
385     if (exprBB != nullptr) {
386         return exprBB;
387     }
388 
389     BasicBlock *etsExprBB = BuildETSExpressions(node, bb);
390     if (etsExprBB != nullptr) {
391         return etsExprBB;
392     }
393 
394     switch (node->Type()) {
395         case ir::AstNodeType::BIGINT_LITERAL:
396         case ir::AstNodeType::BOOLEAN_LITERAL:
397         case ir::AstNodeType::CHAR_LITERAL:
398         case ir::AstNodeType::IDENTIFIER:
399         case ir::AstNodeType::NULL_LITERAL:
400         case ir::AstNodeType::NUMBER_LITERAL:
401         case ir::AstNodeType::STRING_LITERAL:
402         case ir::AstNodeType::TEMPLATE_LITERAL:
403         case ir::AstNodeType::THIS_EXPRESSION:
404         case ir::AstNodeType::UNDEFINED_LITERAL:
405             AddNodeToBB(node, bb);
406             return bb;
407         default:
408             AddNodeToBB(node, bb);
409             return bb;
410     }
411 }
412 
Build(ir::CatchClause * catchClauseNode,BasicBlock * bb)413 CFG::BasicBlock *CFG::Build(ir::CatchClause *catchClauseNode, BasicBlock *bb)
414 {
415     // NOTE: Implement this
416     AddNodeToBB(catchClauseNode, bb);
417     return bb;
418 }
419 
Build(ir::ThrowStatement * throwStatementNode,BasicBlock * bb)420 CFG::BasicBlock *CFG::Build(ir::ThrowStatement *throwStatementNode, BasicBlock *bb)
421 {
422     // NOTE: Implement this
423     AddNodeToBB(throwStatementNode, bb);
424     return bb;
425 }
426 
Build(ir::TryStatement * tryStatementNode,BasicBlock * bb)427 CFG::BasicBlock *CFG::Build(ir::TryStatement *tryStatementNode, BasicBlock *bb)
428 {
429     // NOTE: Implement this
430     AddNodeToBB(tryStatementNode, bb);
431     return bb;
432 }
433 
Build(ir::ArrayExpression * arrayExpressionNode,BasicBlock * bb)434 CFG::BasicBlock *CFG::Build(ir::ArrayExpression *arrayExpressionNode, BasicBlock *bb)
435 {
436     for (auto element : arrayExpressionNode->Elements()) {
437         bb = Build(element, bb);
438     }
439     AddNodeToBB(arrayExpressionNode, bb);
440     return bb;
441 }
442 
Build(ir::ArrowFunctionExpression * arrowFunctionExpressionNode,BasicBlock * bb)443 CFG::BasicBlock *CFG::Build(ir::ArrowFunctionExpression *arrowFunctionExpressionNode, BasicBlock *bb)
444 {
445     AddNodeToBB(arrowFunctionExpressionNode, bb);
446     return bb;
447 }
448 
Build(ir::UnaryExpression * unaryExpressionNode,BasicBlock * bb)449 CFG::BasicBlock *CFG::Build(ir::UnaryExpression *unaryExpressionNode, BasicBlock *bb)
450 {
451     bb = Build(unaryExpressionNode->Argument(), bb);
452     AddNodeToBB(unaryExpressionNode, bb);
453     return bb;
454 }
455 
Build(ir::TSNonNullExpression * tsNonNullExpressionNode,BasicBlock * bb)456 CFG::BasicBlock *CFG::Build(ir::TSNonNullExpression *tsNonNullExpressionNode, BasicBlock *bb)
457 {
458     bb = Build(tsNonNullExpressionNode->Expr(), bb);
459     AddNodeToBB(tsNonNullExpressionNode, bb);
460     return bb;
461 }
462 
Build(ir::ChainExpression * chainExpressionNode,BasicBlock * bb)463 CFG::BasicBlock *CFG::Build(ir::ChainExpression *chainExpressionNode, BasicBlock *bb)
464 {
465     // NOTE: Implement this
466     AddNodeToBB(chainExpressionNode, bb);
467     return bb;
468 }
469 
Build(ir::ETSNewClassInstanceExpression * etsNewClassInstanceExpressionNode,BasicBlock * bb)470 CFG::BasicBlock *CFG::Build(ir::ETSNewClassInstanceExpression *etsNewClassInstanceExpressionNode, BasicBlock *bb)
471 {
472     for (auto argumentExpression : etsNewClassInstanceExpressionNode->GetArguments()) {
473         bb = Build(argumentExpression, bb);
474     }
475     AddNodeToBB(etsNewClassInstanceExpressionNode, bb);
476     return bb;
477 }
478 
Build(ir::ConditionalExpression * conditionalExpressionNode,BasicBlock * bb)479 CFG::BasicBlock *CFG::Build(ir::ConditionalExpression *conditionalExpressionNode, BasicBlock *bb)
480 {
481     auto conditionBB = Build(conditionalExpressionNode->Test(), bb);
482 
483     auto trueBB = CreateNewBB({conditionBB}, {&trueLabel_});
484     trueBB = Build(conditionalExpressionNode->Consequent(), trueBB);
485     auto falseBB = CreateNewBB({conditionBB}, {&falseLabel_});
486     falseBB = Build(conditionalExpressionNode->Alternate(), falseBB);
487     auto nextBB = CreateNewBB({trueBB, falseBB});
488     return nextBB;
489 }
490 
Build(ir::TypeofExpression * typeofExpressionNode,BasicBlock * bb)491 CFG::BasicBlock *CFG::Build(ir::TypeofExpression *typeofExpressionNode, BasicBlock *bb)
492 {
493     bb = Build(typeofExpressionNode->Argument(), bb);
494     AddNodeToBB(typeofExpressionNode, bb);
495     return bb;
496 }
497 
Build(ir::MemberExpression * memberExpressionNode,BasicBlock * bb)498 CFG::BasicBlock *CFG::Build(ir::MemberExpression *memberExpressionNode, BasicBlock *bb)
499 {
500     bb = Build(memberExpressionNode->Object(), bb);
501     bb = Build(memberExpressionNode->Property(), bb);
502     AddNodeToBB(memberExpressionNode, bb);
503 
504     return bb;
505 }
506 
Build(ir::WhileStatement * whileStatementNode,BasicBlock * bb)507 CFG::BasicBlock *CFG::Build(ir::WhileStatement *whileStatementNode, BasicBlock *bb)
508 {
509     ++inLoop_;
510     auto testBB = CreateNewBB({bb});
511     ES2PANDA_ASSERT(testBB != nullptr);
512     testBB->SetFlag(BasicBlockFlags::CONDITION);
513     --inLoop_;
514     auto falseBB = CreateNewBB({testBB}, {&falseLabel_});
515     ++inLoop_;
516     loopStmtJumpTargetMap_[whileStatementNode] = std::make_pair(testBB, falseBB);
517     bb = Build(whileStatementNode->Test(), testBB);
518     auto trueBB = CreateNewBB({bb}, {&trueLabel_});
519     trueBB = Build(whileStatementNode->Body(), trueBB);
520     ES2PANDA_ASSERT(trueBB != nullptr);
521     trueBB->AddSuccessor(testBB);
522     --inLoop_;
523     return falseBB;
524 }
525 
Build(ir::DoWhileStatement * doWhileStatementNode,BasicBlock * bb)526 CFG::BasicBlock *CFG::Build(ir::DoWhileStatement *doWhileStatementNode, BasicBlock *bb)
527 {
528     ++inLoop_;
529     auto bodyBB = CreateNewBB({bb});
530     auto testBB = CreateNewBB({});
531     ES2PANDA_ASSERT(testBB != nullptr);
532     testBB->SetFlag(BasicBlockFlags::CONDITION);
533     --inLoop_;
534     auto falseBB = CreateNewBB({testBB}, {&falseLabel_});
535     ++inLoop_;
536     loopStmtJumpTargetMap_[doWhileStatementNode] = std::make_pair(testBB, falseBB);
537     bb = Build(doWhileStatementNode->Body(), bodyBB);
538     ES2PANDA_ASSERT(bb != nullptr);
539     testBB = Build(doWhileStatementNode->Test(), testBB);
540     bb->AddSuccessor(testBB);
541     AddBBEdge(testBB, bodyBB, &trueLabel_);
542     --inLoop_;
543     return falseBB;
544 }
545 
Build(ir::SwitchStatement * switchStatementNode,BasicBlock * bb)546 CFG::BasicBlock *CFG::Build(ir::SwitchStatement *switchStatementNode, BasicBlock *bb)
547 {
548     bb = Build(switchStatementNode->Discriminant(), bb);
549     auto afterBB = CreateNewBB({});
550     loopStmtJumpTargetMap_[switchStatementNode] = std::make_pair(nullptr, afterBB);
551     BasicBlock *fallThrough = nullptr;
552     for (auto switchCase : switchStatementNode->Cases()) {
553         bb = CreateNewBB({bb});
554         bb = Build(switchCase->Test(), bb);
555         if (switchCase->Test() != nullptr) {
556             switchCaseMap_[switchCase->Test()] = switchStatementNode->Discriminant();
557         }
558 
559         auto caseBB = CreateNewBB({bb, fallThrough}, {switchCase->Test()});
560         for (auto consStatement : switchCase->Consequent()) {
561             caseBB = Build(consStatement, caseBB);
562         }
563         fallThrough = caseBB;
564     }
565 
566     if (fallThrough != nullptr) {
567         afterBB->AddPredecessor(fallThrough);
568     }
569 
570     return afterBB;
571 }
572 
Build(ir::CallExpression * callExpressionNode,BasicBlock * bb)573 CFG::BasicBlock *CFG::Build(ir::CallExpression *callExpressionNode, BasicBlock *bb)
574 {
575     bb = Build(callExpressionNode->Callee(), bb);
576     for (auto argument : callExpressionNode->Arguments()) {
577         bb = Build(argument, bb);
578     }
579     AddNodeToBB(callExpressionNode, bb);
580     return bb;
581 }
582 
Build(ir::LabelledStatement * labelledStatementNode,BasicBlock * bb)583 CFG::BasicBlock *CFG::Build(ir::LabelledStatement *labelledStatementNode, BasicBlock *bb)
584 {
585     bb = Build(labelledStatementNode->Body(), bb);
586     return bb;
587 }
588 
Build(ir::BreakStatement * breakStatementNode,BasicBlock * bb)589 CFG::BasicBlock *CFG::Build(ir::BreakStatement *breakStatementNode, BasicBlock *bb)
590 {
591     auto target = breakStatementNode->Target();
592     if (target == nullptr) {
593         return bb;
594     }
595 
596     if (target->IsLabelledStatement()) {
597         target = target->AsLabelledStatement()->Body();
598     }
599 
600     if (const auto targetIt = loopStmtJumpTargetMap_.find(target); targetIt != loopStmtJumpTargetMap_.end()) {
601         bb->AddSuccessor(targetIt->second.second);
602     }
603     return CreateNewBB({});
604 }
605 
Build(ir::ContinueStatement * continueStatementNode,BasicBlock * bb)606 CFG::BasicBlock *CFG::Build(ir::ContinueStatement *continueStatementNode, BasicBlock *bb)
607 {
608     auto target = continueStatementNode->Target();
609     if (target == nullptr) {
610         return bb;
611     }
612 
613     if (target->IsLabelledStatement()) {
614         target = target->AsLabelledStatement()->Body();
615     }
616     if (const auto targetIt = loopStmtJumpTargetMap_.find(target); targetIt != loopStmtJumpTargetMap_.end()) {
617         bb->AddSuccessor(targetIt->second.first);
618     }
619     return CreateNewBB({});
620 }
621 
Build(ir::UpdateExpression * updateExpressionNode,BasicBlock * bb)622 CFG::BasicBlock *CFG::Build(ir::UpdateExpression *updateExpressionNode, BasicBlock *bb)
623 {
624     if (updateExpressionNode->IsPrefix()) {
625         AddNodeToBB(updateExpressionNode, bb);
626         bb = Build(updateExpressionNode->Argument(), bb);
627     } else {
628         bb = Build(updateExpressionNode->Argument(), bb);
629         AddNodeToBB(updateExpressionNode, bb);
630     }
631     return bb;
632 }
633 
Build(ir::ForOfStatement * forOfStatementNode,BasicBlock * bb)634 CFG::BasicBlock *CFG::Build(ir::ForOfStatement *forOfStatementNode, BasicBlock *bb)
635 {
636     auto rightExprBB = Build(forOfStatementNode->Right(), bb);
637     auto nextBB = CreateNewBB({rightExprBB});
638     ++inLoop_;
639     auto loopBB = CreateNewBB({rightExprBB});
640     bb = Build(forOfStatementNode->Left(), loopBB);
641     loopStmtJumpTargetMap_[forOfStatementNode] = std::make_pair(bb, nextBB);
642     bb = Build(forOfStatementNode->Body(), bb);
643     --inLoop_;
644     ES2PANDA_ASSERT(bb != nullptr);
645     bb->AddSuccessor(loopBB);
646     bb->AddSuccessor(nextBB);
647     return nextBB;
648 }
649 
Build(ir::ForUpdateStatement * forUpdateStatementNode,BasicBlock * bb)650 CFG::BasicBlock *CFG::Build(ir::ForUpdateStatement *forUpdateStatementNode, BasicBlock *bb)
651 {
652     bb = Build(forUpdateStatementNode->Init(), bb);
653 
654     if (forUpdateStatementNode->Test() != nullptr) {
655         ++inLoop_;
656         auto testBB = CreateNewBB({bb});
657         --inLoop_;
658         auto falseBB = CreateNewBB({testBB}, {&falseLabel_});
659         ++inLoop_;
660         auto trueBB = CreateNewBB({testBB}, {&trueLabel_});
661         loopStmtJumpTargetMap_[forUpdateStatementNode] = std::make_pair(testBB, falseBB);
662         testBB = Build(forUpdateStatementNode->Test(), testBB);
663         auto bodyBB = Build(forUpdateStatementNode->Body(), trueBB);
664         bodyBB = Build(forUpdateStatementNode->Update(), bodyBB);
665         ES2PANDA_ASSERT(bodyBB != nullptr);
666         bodyBB->AddSuccessor(testBB);
667         --inLoop_;
668         return falseBB;
669     }
670 
671     auto nextBB = CreateNewBB({});
672     ++inLoop_;
673     auto bodyStartBB = CreateNewBB({bb});
674     loopStmtJumpTargetMap_[forUpdateStatementNode] = std::make_pair(bodyStartBB, nextBB);
675     auto bodyBB = Build(forUpdateStatementNode->Body(), bodyStartBB);
676     bodyBB = Build(forUpdateStatementNode->Update(), bodyBB);
677     ES2PANDA_ASSERT(bodyBB != nullptr);
678     bodyBB->AddSuccessor(bodyStartBB);
679     --inLoop_;
680     return nextBB;
681 }
682 
Build(ir::ReturnStatement * returnStatementNode,BasicBlock * bb)683 CFG::BasicBlock *CFG::Build(ir::ReturnStatement *returnStatementNode, BasicBlock *bb)
684 {
685     bb = Build(returnStatementNode->Argument(), bb);
686     AddNodeToBB(returnStatementNode, bb);
687     bb->SetFlag(BasicBlockFlags::EXIT);
688     return CreateNewBB({});
689 }
690 
Build(ir::TSAsExpression * asExpressionNode,BasicBlock * bb)691 CFG::BasicBlock *CFG::Build(ir::TSAsExpression *asExpressionNode, BasicBlock *bb)
692 {
693     bb = Build(asExpressionNode->Expr(), bb);
694     AddNodeToBB(asExpressionNode, bb);
695     return bb;
696 }
697 
Build(ir::AssignmentExpression * assignmentExpressionNode,BasicBlock * bb)698 CFG::BasicBlock *CFG::Build(ir::AssignmentExpression *assignmentExpressionNode, BasicBlock *bb)
699 {
700     bb = Build(assignmentExpressionNode->Right(), bb);
701     bb = Build(assignmentExpressionNode->Left(), bb);
702     AddNodeToBB(assignmentExpressionNode, bb);
703     return bb;
704 }
705 
Build(ir::ExpressionStatement * expressionStatementNode,BasicBlock * bb)706 CFG::BasicBlock *CFG::Build(ir::ExpressionStatement *expressionStatementNode, BasicBlock *bb)
707 {
708     return Build(expressionStatementNode->GetExpression(), bb);
709 }
710 
Build(ir::BinaryExpression * binaryExpressionNode,BasicBlock * bb)711 CFG::BasicBlock *CFG::Build(ir::BinaryExpression *binaryExpressionNode, BasicBlock *bb)
712 {
713     if (binaryExpressionNode->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_AND) {
714         auto leftBB = Build(binaryExpressionNode->Left(), bb);
715         auto leftTrueBB = CreateNewBB({leftBB}, {&trueLabel_});
716         leftTrueBB = Build(binaryExpressionNode->Right(), leftTrueBB);
717         bb = CreateNewBB({leftBB, leftTrueBB}, {&falseLabel_});
718     } else if (binaryExpressionNode->OperatorType() == lexer::TokenType::PUNCTUATOR_LOGICAL_OR) {
719         auto leftBB = Build(binaryExpressionNode->Left(), bb);
720         auto leftFalseBB = CreateNewBB({leftBB}, {&falseLabel_});
721         leftFalseBB = Build(binaryExpressionNode->Right(), leftFalseBB);
722         bb = CreateNewBB({leftFalseBB, leftBB}, {nullptr, &trueLabel_});
723     } else {  // NOTE: Implement the rest of it if any
724         bb = Build(binaryExpressionNode->Left(), bb);
725         bb = Build(binaryExpressionNode->Right(), bb);
726     }
727     AddNodeToBB(binaryExpressionNode, bb);
728     return bb;
729 }
730 
Build(ir::BlockStatement * blockStatementNode,BasicBlock * bb)731 CFG::BasicBlock *CFG::Build(ir::BlockStatement *blockStatementNode, BasicBlock *bb)
732 {
733     for (const auto statement : blockStatementNode->Statements()) {
734         bb = Build(statement, bb);
735     }
736     return bb;
737 }
738 
Build(ir::BlockExpression * blockExpressionNode,BasicBlock * bb)739 CFG::BasicBlock *CFG::Build(ir::BlockExpression *blockExpressionNode, BasicBlock *bb)
740 {
741     for (const auto statement : blockExpressionNode->Statements()) {
742         bb = Build(statement, bb);
743     }
744     return bb;
745 }
746 
Build(ir::IfStatement * ifStatementNode,BasicBlock * bb)747 CFG::BasicBlock *CFG::Build(ir::IfStatement *ifStatementNode, BasicBlock *bb)
748 {
749     auto conditionBB = Build(ifStatementNode->Test(), bb);
750     auto trueBB = CreateNewBB({conditionBB}, {&trueLabel_});
751     trueBB = Build(ifStatementNode->Consequent(), trueBB);
752 
753     BasicBlock *falseBB = conditionBB;
754     BasicBlock *newBB = nullptr;
755     if (ifStatementNode->Alternate() != nullptr) {
756         falseBB = CreateNewBB({conditionBB}, {&falseLabel_});
757         falseBB = Build(ifStatementNode->Alternate(), falseBB);
758         newBB = CreateNewBB({trueBB, falseBB});
759     } else {
760         newBB = CreateNewBB({trueBB, falseBB}, {nullptr, &falseLabel_});
761     }
762 
763     return newBB;
764 }
765 
DumpSuccessorEdges(std::ofstream & ofs,BasicBlock * const bb) const766 void CFG::DumpSuccessorEdges(std::ofstream &ofs, BasicBlock *const bb) const
767 {
768     for (size_t index = 0; index < bb->succs_.size(); ++index) {
769         ofs << "  BB" << bb->index_ << " -> BB" << bb->succs_[index]->index_ << " [color=\"blue\"";
770         if (auto labelsMapIt = bbSuccLabelMap_.find(bb); labelsMapIt != bbSuccLabelMap_.end()) {
771             if (auto indexMapIt = labelsMapIt->second.find(index); indexMapIt != labelsMapIt->second.end()) {
772                 ofs << " label=\""
773                     << util::Helpers::EscapeHTMLString(allocator_, indexMapIt->second->DumpEtsSrc()).View().Mutf8()
774                     << "\"";
775             }
776         }
777         ofs << "];\n";
778     }
779 }
780 
DumpPredecessorEdges(std::ofstream & ofs,BasicBlock * const bb) const781 void CFG::DumpPredecessorEdges(std::ofstream &ofs, BasicBlock *const bb) const
782 {
783     for (size_t index = 0; index < bb->preds_.size(); ++index) {
784         ofs << "  BB" << bb->index_ << " -> BB" << bb->preds_[index]->index_ << " [color=\"red\"";
785         if (auto labelsMapIt = bbPredLabelMap_.find(bb); labelsMapIt != bbPredLabelMap_.end()) {
786             if (auto indexMapIt = labelsMapIt->second.find(index); indexMapIt != labelsMapIt->second.end()) {
787                 ofs << " label=\""
788                     << util::Helpers::EscapeHTMLString(allocator_, indexMapIt->second->DumpEtsSrc()).View().Mutf8()
789                     << "\"";
790             }
791         }
792         ofs << "];\n";
793     }
794 }
795 
DumpDot(const char * filename) const796 bool CFG::DumpDot(const char *filename) const
797 {
798     std::ofstream out(filename);
799     if (!out) {
800         return false;
801     }
802 
803     out << "digraph CFG {\n"
804            "  node[shape = plaintext]\n";
805     for (const auto bb : blocks_) {
806         std::string color = "gray";
807         if (bb->HasFlag(BasicBlockFlags::CONDITION)) {
808             color = "green";
809         }
810         out << "  BB" << bb->index_ << R"([label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">)"
811             << "<TR><TD BGCOLOR=\"" << color << R"(" COLSPAN="3"><B>)" << bb->index_ << "</B>";
812 
813         if (const auto labelIt = bbAnnotationMap_.find(bb); labelIt != bbAnnotationMap_.end()) {
814             out << "(" << labelIt->second.View().Mutf8() << ")";
815         }
816 
817         out << "</TD></TR>";
818         for (size_t i = 0; i < bb->nodes_.size(); ++i) {
819             out << "<TR><TD PORT=\"f" << i << "\">" << i << "</TD><TD>" << ToString(bb->nodes_[i]->Type())
820                 << "</TD><TD>"
821                 << util::Helpers::EscapeHTMLString(allocator_, bb->nodes_[i]->DumpEtsSrc()).View().Mutf8()
822                 << "</TD></TR>";
823         }
824         out << "</TABLE>>];\n";
825 
826         DumpSuccessorEdges(out, bb);
827     }
828 
829     for (auto switchCase : switchCaseMap_) {
830         auto from = nodeBBMap_.find(switchCase.first);
831         auto to = nodeBBMap_.find(switchCase.second);
832         out << "  BB" << from->second.first->index_ << ":f" << from->second.second << " -> BB"
833             << to->second.first->index_ << ":f" << to->second.second << " [color=\"green\" label=\"case\"];\n";
834     }
835     out << "}\n";
836     return true;
837 }
838 
Build(ir::VariableDeclaration * variableDeclarationNode,BasicBlock * bb)839 CFG::BasicBlock *CFG::Build(ir::VariableDeclaration *variableDeclarationNode, BasicBlock *bb)
840 {
841     for (auto declarator : variableDeclarationNode->Declarators()) {
842         bb = Build(declarator->Init(), bb);
843         bb = Build(declarator->Id(), bb);
844     }
845     AddNodeToBB(variableDeclarationNode, bb);
846     return bb;
847 }
848 
AddNodeToBB(ir::AstNode * node,BasicBlock * bb)849 size_t CFG::AddNodeToBB(ir::AstNode *node, BasicBlock *bb)
850 {
851     if (bb == nullptr) {
852         bb = CreateNewBB({});
853     }
854     ES2PANDA_ASSERT(bb != nullptr);
855     size_t index = bb->AddNode(node);
856     nodeBBMap_[node] = std::make_pair(bb, index);
857     return index;
858 }
859 
VisitDepthFirst(const CFG::BBTraverser & traverser,const CFG::BasicBlock * bb,ArenaSet<const CFG::BasicBlock * > & visitedBlocks,ArenaVector<BasicBlock * > CFG::BasicBlock::* edges,bool allPath) const860 bool CFG::VisitDepthFirst(const CFG::BBTraverser &traverser, const CFG::BasicBlock *bb,
861                           ArenaSet<const CFG::BasicBlock *> &visitedBlocks,
862                           ArenaVector<BasicBlock *> CFG::BasicBlock::*edges, bool allPath) const
863 {
864     if (visitedBlocks.find(bb) != visitedBlocks.end()) {
865         return true;
866     }
867 
868     if (!traverser(bb)) {
869         return false;
870     }
871     visitedBlocks.insert(bb);
872 
873     for (const auto nextBB : bb->*edges) {
874         if (!VisitDepthFirst(traverser, nextBB, visitedBlocks, edges, allPath)) {
875             visitedBlocks.erase(bb);
876             return false;
877         }
878     }
879     visitedBlocks.erase(bb);
880     return true;
881 }
882 
IterateForwardDepthFirst(const BBTraverser & traverser,const BasicBlock * start,bool allPath) const883 void CFG::IterateForwardDepthFirst(const BBTraverser &traverser, const BasicBlock *start, bool allPath) const
884 {
885     ArenaSet<const BasicBlock *> visitedBlocks(allocator_->Adapter());
886     if (start != nullptr) {
887         VisitDepthFirst(traverser, start, visitedBlocks, &CFG::BasicBlock::succs_, allPath);
888     } else {
889         for (auto functions : functionNodeBBMap_) {
890             VisitDepthFirst(traverser, functions.second, visitedBlocks, &CFG::BasicBlock::succs_, allPath);
891         }
892     }
893 }
894 
GetForwardDepthFirstOrder(const BasicBlock * start,bool allPath) const895 ArenaList<const CFG::BasicBlock *> CFG::GetForwardDepthFirstOrder(const BasicBlock *start, bool allPath) const
896 {
897     ArenaList<const CFG::BasicBlock *> orderedList(allocator_->Adapter());
898     BBTraverser recorder = [&orderedList](const CFG::BasicBlock *bb) {
899         orderedList.push_back(bb);
900         return true;
901     };
902     IterateForwardDepthFirst(recorder, start, allPath);
903     return orderedList;
904 }
905 
IterateBackwardDepthFirst(const BBTraverser & traverser,const BasicBlock * start,bool allPath) const906 void CFG::IterateBackwardDepthFirst(const BBTraverser &traverser, const BasicBlock *start, bool allPath) const
907 {
908     ArenaSet<const BasicBlock *> visitedBlocks(allocator_->Adapter());
909     if (start != nullptr) {
910         VisitDepthFirst(traverser, start, visitedBlocks, &CFG::BasicBlock::preds_, allPath);
911     }
912 }
913 
GetBackwardDepthFirstOrder(const BasicBlock * start,bool allPath) const914 ArenaList<const CFG::BasicBlock *> CFG::GetBackwardDepthFirstOrder(const BasicBlock *start, bool allPath) const
915 {
916     ArenaList<const CFG::BasicBlock *> orderedList(allocator_->Adapter());
917     BBTraverser recorder = [&orderedList](const CFG::BasicBlock *bb) {
918         orderedList.push_back(bb);
919         return true;
920     };
921     IterateBackwardDepthFirst(recorder, start, allPath);
922     return orderedList;
923 }
924 
FindBasicBlock(ir::AstNode * node) const925 std::pair<CFG::BasicBlock *, size_t> CFG::FindBasicBlock(ir::AstNode *node) const
926 {
927     auto bbIt = nodeBBMap_.find(node);
928     if (bbIt == nodeBBMap_.end()) {
929         return {nullptr, 0};
930     }
931     return bbIt->second;
932 }
933 
Allocator() const934 ArenaAllocator *CFG::Allocator() const
935 {
936     return allocator_;
937 }
938 
FindEntryBasicBlock(ir::ScriptFunction * function) const939 CFG::BasicBlock *CFG::FindEntryBasicBlock(ir::ScriptFunction *function) const
940 {
941     auto bbIt = functionNodeBBMap_.find(function);
942     if (bbIt == functionNodeBBMap_.end()) {
943         return nullptr;
944     }
945 
946     return bbIt->second;
947 }
948 
IterateForwardTopologicalOrder(const BBTraverser & traverser,const BasicBlock * start,bool closeLoop) const949 void CFG::IterateForwardTopologicalOrder(const BBTraverser &traverser, const BasicBlock *start, bool closeLoop) const
950 {
951     ArenaList<const BasicBlock *> orderedList = GetForwardTopologicalOrder(start, closeLoop);
952     for (auto bb : orderedList) {
953         if (!traverser(bb)) {
954             break;
955         }
956     }
957 }
958 
GetForwardTopologicalOrder(const CFG::BasicBlock * start,bool closeLoop) const959 ArenaList<const CFG::BasicBlock *> CFG::GetForwardTopologicalOrder(const CFG::BasicBlock *start, bool closeLoop) const
960 {
961     ArenaSet<const BasicBlock *> visitedBlocks(allocator_->Adapter());
962     ArenaSet<const BasicBlock *> markedBlocks(allocator_->Adapter());
963     ArenaList<const BasicBlock *> orderedList(allocator_->Adapter());
964     VisitResult visitResult {orderedList, markedBlocks, visitedBlocks};
965 
966     if (start != nullptr) {
967         VisitTopOrder(visitResult, start, &CFG::BasicBlock::succs_, closeLoop);
968     } else {
969         for (auto functions : functionNodeBBMap_) {
970             VisitTopOrder(visitResult, functions.second, &CFG::BasicBlock::succs_, closeLoop);
971         }
972     }
973     return orderedList;
974 }
975 
IterateBackwardTopologicalOrder(const BBTraverser & traverser,const BasicBlock * start,bool closeLoop) const976 void CFG::IterateBackwardTopologicalOrder(const BBTraverser &traverser, const BasicBlock *start, bool closeLoop) const
977 {
978     ArenaList<const BasicBlock *> orderedList = GetBackwardTopologicalOrder(start, closeLoop);
979     for (auto bb : orderedList) {
980         if (!traverser(bb)) {
981             break;
982         }
983     }
984 }
985 
GetBackwardTopologicalOrder(const CFG::BasicBlock * start,bool closeLoop) const986 ArenaList<const CFG::BasicBlock *> CFG::GetBackwardTopologicalOrder(const CFG::BasicBlock *start, bool closeLoop) const
987 {
988     ArenaSet<const BasicBlock *> visitedBlocks(allocator_->Adapter());
989     ArenaSet<const BasicBlock *> markedBlocks(allocator_->Adapter());
990     ArenaList<const BasicBlock *> orderedList(allocator_->Adapter());
991     VisitResult visitResult {orderedList, markedBlocks, visitedBlocks};
992 
993     if (start != nullptr) {
994         VisitTopOrder(visitResult, start, &CFG::BasicBlock::preds_, closeLoop);
995     } else {
996         for (auto functions : functionNodeBBMap_) {
997             VisitTopOrder(visitResult, functions.second, &CFG::BasicBlock::preds_, closeLoop);
998         }
999     }
1000     return orderedList;
1001 }
1002 
VisitTopOrder(VisitResult & visitResult,const CFG::BasicBlock * bb,ArenaVector<BasicBlock * > CFG::BasicBlock::* edges,bool closeLoop) const1003 void CFG::VisitTopOrder(VisitResult &visitResult, const CFG::BasicBlock *bb,
1004                         ArenaVector<BasicBlock *> CFG::BasicBlock::*edges, bool closeLoop) const
1005 {
1006     if (visitResult.visitedBlocks.find(bb) != visitResult.visitedBlocks.end()) {
1007         return;
1008     }
1009 
1010     if (visitResult.markedBlocks.find(bb) != visitResult.markedBlocks.end()) {
1011         if (closeLoop) {
1012             visitResult.orderedList.push_front(bb);
1013         }
1014         return;
1015     }
1016 
1017     visitResult.markedBlocks.insert(bb);
1018 
1019     for (const auto nextBB : bb->*edges) {
1020         VisitTopOrder(visitResult, nextBB, edges, closeLoop);
1021     }
1022 
1023     visitResult.markedBlocks.erase(bb);
1024     visitResult.visitedBlocks.insert(bb);
1025     visitResult.orderedList.push_front(bb);
1026 }
1027 
GetFunctionEntries() const1028 const ArenaUnorderedMap<ir::ScriptFunction *, CFG::BasicBlock *> &CFG::GetFunctionEntries() const
1029 {
1030     return functionNodeBBMap_;
1031 }
1032 
GetAnnotation(const BasicBlock * bb) const1033 const util::UString *CFG::GetAnnotation(const BasicBlock *bb) const
1034 {
1035     if (const auto annotationlIt = bbAnnotationMap_.find(bb); annotationlIt != bbAnnotationMap_.end()) {
1036         return &annotationlIt->second;
1037     }
1038     return nullptr;
1039 }
1040 
GetSwitchCaseMap() const1041 const ArenaUnorderedMap<ir::AstNode *, ir::AstNode *> &CFG::GetSwitchCaseMap() const
1042 {
1043     return switchCaseMap_;
1044 }
1045 
GetBasicBlocks() const1046 const ArenaSet<CFG::BasicBlock *> &CFG::GetBasicBlocks() const
1047 {
1048     return blocks_;
1049 }
1050 
AddBBEdge(BasicBlock * from,BasicBlock * to,const ir::AstNode * label)1051 void CFG::AddBBEdge(BasicBlock *from, BasicBlock *to, const ir::AstNode *label)
1052 {
1053     auto [succEdgeIndex, prevEdgeIndex] = from->AddSuccessor(to);
1054     if (label != nullptr) {
1055         SetBBSuccEdgeLabel(from, succEdgeIndex, label);
1056         SetBBPredEdgeLabel(to, prevEdgeIndex, label);
1057     }
1058 }
1059 
1060 }  // namespace ark::es2panda::compiler
1061