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