• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "try_catch.h"
17 namespace maplebe {
CreateNewBB(StmtNode * first,StmtNode * last)18 BBT *TryCatchBlocksLower::CreateNewBB(StmtNode *first, StmtNode *last)
19 {
20     BBT *newBB = memPool.New<BBT>(first, last, &memPool);
21     bbList.emplace_back(newBB);
22     return newBB;
23 }
24 
FindTargetBBlock(LabelIdx idx,const std::vector<BBT * > & bbs)25 BBT *TryCatchBlocksLower::FindTargetBBlock(LabelIdx idx, const std::vector<BBT *> &bbs)
26 {
27     for (auto &target : bbs) {
28         if (target->GetLabelIdx() == idx) {
29             return target;
30         }
31     }
32     return nullptr;
33 }
34 
35 /* returns the first statement that is moved in into the try block. If none is moved in, nullptr is returned */
MoveCondGotoIntoTry(BBT & jtBB,BBT & condbrBB,const MapleVector<BBT * > & labeledBBsInTry)36 StmtNode *TryCatchBlocksLower::MoveCondGotoIntoTry(BBT &jtBB, BBT &condbrBB, const MapleVector<BBT *> &labeledBBsInTry)
37 {
38     StmtNode *firstStmtMovedIn = nullptr;
39     const MapleVector<BBT *> &bbs = labeledBBsInTry;
40     StmtNode *jtStmt = jtBB.GetKeyStmt();
41 #if DEBUG
42     StmtNode *js = jtBB.GetFirstStmt();
43     while (js->GetOpCode() != OP_try) {
44         js = js->GetNext();
45     }
46     CHECK_FATAL(js == jtStmt, "make sure js equal jtStmt");
47 #endif
48     StmtNode *ts = jtBB.GetFirstStmt()->GetPrev();
49     while ((ts != nullptr) && (ts->GetOpCode() == OP_comment)) {
50         ts = ts->GetPrev();
51     }
52 
53     if (ts != nullptr && ts->IsCondBr()) {
54         CHECK_FATAL(ts->GetNext() == jtBB.GetFirstStmt(), "make sure ts's next equal jtBB's firstStmt");
55         StmtNode *firstStmtNode = jtBB.GetFirstStmt();
56         /* [ jtbb_b..jtstmt ]; either jtbb_b is a comment or jtbb_b == jtstmt */
57         LabelIdx id = static_cast<CondGotoNode *>(ts)->GetOffset();
58         for (auto &lbb : bbs) {
59             if (lbb->GetLabelIdx() == id) {
60                 /*
61                  * this cond goto jumps into the try block; let the try block enclose it
62                  * first find the preceding comment statements if any
63                  */
64                 StmtNode *brS = ts;
65                 while ((ts->GetPrev() != nullptr) && (ts->GetPrev()->GetOpCode() == OP_comment)) {
66                     ts = ts->GetPrev();
67                 }
68                 StmtNode *secondStmtNode = ts; /* beginning statement of branch block */
69                 /* [ brbb_b..br_s ]; either brbb_b is a comment or brbb_b == br_s */
70                 firstStmtNode->SetPrev(secondStmtNode->GetPrev());
71                 if (secondStmtNode->GetPrev()) {
72                     secondStmtNode->GetPrev()->SetNext(firstStmtNode);
73                 }
74                 jtStmt->GetNext()->SetPrev(brS);
75                 brS->SetNext(jtStmt->GetNext());
76                 secondStmtNode->SetPrev(jtStmt);
77                 jtStmt->SetNext(secondStmtNode);
78                 condbrBB.SetLastStmt(*firstStmtNode->GetPrev());
79                 CHECK_FATAL(condbrBB.GetFallthruBranch() == &jtBB, "make sure condbrBB's fallthruBranch equal &jtBB");
80                 condbrBB.SetFallthruBranch(&jtBB);
81                 condbrBB.SetCondJumpBranch(nullptr);
82                 firstStmtMovedIn = secondStmtNode;
83                 break;
84             }
85         }
86     }
87     return firstStmtMovedIn;
88 }
89 
RecoverBasicBlock()90 void TryCatchBlocksLower::RecoverBasicBlock()
91 {
92     std::vector<BBT *> condbrBBs;
93     std::vector<BBT *> switchBBs;
94     std::vector<BBT *> labeledBBs;
95     using BBTPair = std::pair<BBT *, BBT *>;
96     std::vector<BBTPair> tryBBs;
97     std::vector<BBT *> catchBBs;
98 
99     CHECK_FATAL(body.GetFirst() != nullptr, "body should not be NULL");
100     bodyFirst = body.GetFirst();
101     StmtNode *next = bodyFirst;
102     /*
103      * comment block [ begin, end ], We treat comment statements as if they are parts
104      * of the immediately following non-comment statement
105      */
106     StmtNode *commentB = nullptr;
107     StmtNode *commentE = nullptr;
108 
109     BBT *curBB = nullptr;
110     BBT *lastBB = nullptr;
111     BBT *openTry = nullptr;
112 
113     /* recover basic blocks */
114     for (StmtNode *stmt = next; stmt != nullptr; stmt = next) {
115         next = stmt->GetNext();
116 
117         if (stmt->GetOpCode() == OP_comment) {
118             if (commentB == nullptr) {
119                 commentB = stmt;
120                 commentE = stmt;
121             } else {
122                 CHECK_FATAL(commentE != nullptr, "nullptr is not expected");
123                 CHECK_FATAL(commentE->GetNext() == stmt, "make sure commentE's next is stmt");
124                 commentE = stmt;
125             }
126             continue;
127         }
128 
129         CHECK_FATAL(stmt->GetOpCode() != OP_comment, "make sure stmt's opcde not equal OP_comment");
130         CHECK_FATAL(commentB == nullptr || (commentE != nullptr && commentE->GetNext() == stmt),
131                     "make sure commentB is nullptr or commentE's next is stmt");
132 
133         if (curBB != nullptr) {
134             if (stmt->GetOpCode() != OP_label && stmt->GetOpCode() != OP_try && stmt->GetOpCode() != OP_endtry) {
135                 curBB->Extend(commentB, stmt);
136             } else {
137                 /* java catch blockes always start with a label (i.e., OP_catch) */
138                 CHECK_FATAL(curBB->GetCondJumpBranch() == nullptr, "expect curBB's condJumpBranch is nullptr");
139                 CHECK_FATAL(curBB->GetFallthruBranch() == nullptr, "expect curBB's fallthruBranch is nullptr");
140                 /* a 'label' statement starts a new basic block */
141                 BBT *newBB = CreateNewBB(commentB, stmt);
142                 /*
143                  * if the immediately preceding statement (discounting comments) was throw, goto or return,
144                  * curBB is to be reset to nullptr, so the control  won't come here.
145                  */
146                 curBB->SetFallthruBranch(newBB);
147                 curBB = newBB;
148             }
149         } else {
150             /* start a new basic block with 'comment_b -- stmt' */
151             curBB = CreateNewBB(commentB, stmt);
152             if (lastBB != nullptr) {
153                 Opcode lastBBLastStmtOp = lastBB->GetLastStmt()->GetOpCode();
154                 if (lastBB->GetLastStmt()->IsCondBr() || lastBBLastStmtOp == OP_endtry) {
155                     lastBB->SetFallthruBranch(curBB);
156                 }
157                 /* else don't connect curBB to last_bb */
158             }
159         }
160         commentB = nullptr;
161         commentE = nullptr;
162 
163         switch (stmt->GetOpCode()) {
164             case OP_throw:
165             case OP_return:
166             case OP_goto:
167                 /* start a new bb at the next stmt */
168                 lastBB = curBB;
169                 curBB = nullptr;
170                 break;
171             case OP_label: {
172                 LabelNode *labelStmt = static_cast<LabelNode *>(stmt);
173                 labeledBBs.emplace_back(curBB);
174                 curBB->SetLabelIdx(static_cast<LabelIdx>(labelStmt->GetLabelIdx()));
175                 break;
176             }
177             case OP_brtrue:
178             case OP_brfalse:
179                 condbrBBs.emplace_back(curBB);
180                 lastBB = curBB;
181                 curBB = nullptr;
182                 break;
183             case OP_switch:
184                 switchBBs.emplace_back(curBB);
185                 lastBB = curBB;
186                 curBB = nullptr;
187                 break;
188             /*
189              * We deal try and endtry slightly differently.
190              * 1. try begins a basic block which includes the try statement and the subsequent statements up to one that
191              *    results in non-sequential control transfer such as unconditional/conditional branches.
192              * 2. endtry will create its own basic block which contains the endtry statement and nothing else.
193              */
194             case OP_try:
195             case OP_endtry: {
196                 /* because a label statement is inserted at the function entry */
197                 CHECK_FATAL(curBB != nullptr, "expect curBB is not nullptr");
198                 CHECK_FATAL(curBB->GetCondJumpBranch() == nullptr, "expect curBB's condJumpBranch is nullptr");
199                 CHECK_FATAL(curBB->GetFallthruBranch() == nullptr, "expect curBB's fallthruBranch is nullptr");
200                 CHECK_FATAL(curBB->GetLastStmt()->GetOpCode() == stmt->GetOpCode(),
201                             "the opcode of curBB's lastStmt should equal stmt's opcocde");
202                 if (stmt->GetOpCode() == OP_try) {
203                     CHECK_FATAL(openTry == nullptr, "trys are not expected to be nested");
204                     curBB->SetType(BBT::kBBTry, *stmt);
205                     openTry = curBB;
206                     prevBBOfTry[openTry] = lastBB;
207                 } else {
208                     tryBBs.emplace_back(BBTPair(openTry, curBB));
209                     openTry = nullptr;
210                     curBB->SetType(BBT::kBBEndTry, *stmt);
211                     lastBB = curBB;
212                     curBB = nullptr;
213                 }
214                 break;
215             }
216             case OP_catch: {
217 #if DEBUG
218                 StmtNode *ss = stmt->GetPrev();
219                 while ((ss != nullptr) && (ss->GetOpCode() == OP_comment)) {
220                     ss = ss->GetPrev();
221                 }
222                 CHECK_FATAL(ss != nullptr, "expect ss is not nullptr");
223                 CHECK_FATAL(ss->GetOpCode() == OP_label, "expect op equal OP_label");
224                 for (auto &tb : catchBBs) {
225                     CHECK_FATAL(tb != curBB, "tb should not equal curBB");
226                 }
227 #endif
228                 catchBBs.emplace_back(curBB);
229                 curBB->SetType(BBT::kBBCatch, *stmt);
230                 break;
231             }
232             case OP_block:
233                 CHECK_FATAL(0, "should not run here");
234             default:
235                 break;
236         }
237     }
238 
239     for (auto &cbBB : condbrBBs) {
240         CHECK_FATAL(cbBB->GetLastStmt()->IsCondBr(), "cbBB's lastStmt is not condBr");
241         CondGotoNode *cbBBLastStmt = static_cast<CondGotoNode *>(cbBB->GetLastStmt());
242         cbBB->SetCondJumpBranch(FindTargetBBlock(static_cast<LabelIdx>(cbBBLastStmt->GetOffset()), labeledBBs));
243     }
244 
245     for (auto &swBB : switchBBs) {
246         CHECK_FATAL(swBB->GetLastStmt()->GetOpCode() == OP_switch,
247                     "the opcode of sw's lastStmt should equal OP_switch");
248         SwitchNode *ss = static_cast<SwitchNode *>(swBB->GetLastStmt());
249 
250         swBB->AddSuccs(FindTargetBBlock(ss->GetDefaultLabel(), labeledBBs));
251         for (auto &cp : ss->GetSwitchTable()) {
252             swBB->AddSuccs(FindTargetBBlock(cp.second, labeledBBs));
253         }
254     }
255 
256     for (auto &bb : bbList) {
257         firstStmtToBBMap[bb->GetFirstStmt()] = bb;
258     }
259     CHECK_FATAL(openTry == nullptr, "trys are not expected to be nested");
260 }
261 
262 /* if catchBB is in try-endtry block and catch is own to current try-endtry, process it and return true */
CheckAndProcessCatchNodeInCurrTryBlock(BBT & origLowerBB,LabelIdx ebbLabel,uint32 index)263 bool TryCatchBlocksLower::CheckAndProcessCatchNodeInCurrTryBlock(BBT &origLowerBB, LabelIdx ebbLabel, uint32 index)
264 {
265     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
266     MapleVector<BBT *> &bbsToRelocate = tryEndTryBlock.GetBBsToRelocate();
267     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
268     StmtNode *tryStmt = tryEndTryBlock.GetTryStmtNode();
269     bool found = false;
270     for (size_t tempIndex = 0; tempIndex < static_cast<TryNode *>(tryStmt)->GetOffsetsCount(); ++tempIndex) {
271         auto id = static_cast<TryNode *>(tryStmt)->GetOffset(tempIndex);
272         /*
273          * if this labeled bb is a catch block,
274          * remove it from the list of blocks enclosed in this try-block'
275          */
276         if (ebbLabel == id) {
277             found = true;
278             enclosedBBs[index] = nullptr;
279             std::vector<BBT *> currBBThread;
280             BBT *lowerBB = &origLowerBB;
281             /* append it to the list of blocks placed after the end try block */
282             currBBThread.emplace_back(lowerBB);
283             while (lowerBB->GetFallthruBranch() != nullptr) {
284                 lowerBB = lowerBB->GetFallthruBranch();
285                 CHECK_FATAL(!lowerBB->IsTry(), "ebb must not be tryBB");
286                 if (lowerBB->IsEndTry()) {
287                     CHECK_FATAL(lowerBB == endTryBB, "lowerBB should equal endTryBB");
288                     break;
289                 }
290                 for (uint32 j = 0; j < enclosedBBs.size(); ++j) {
291                     if (enclosedBBs[j] == lowerBB) {
292                         enclosedBBs[j] = nullptr;
293                         break;
294                     }
295                 }
296                 currBBThread.emplace_back(lowerBB);
297             }
298 
299             if (!lowerBB->IsEndTry()) {
300                 for (auto &e : currBBThread) {
301                     bbsToRelocate.emplace_back(e);
302                 }
303             } else {
304                 /*
305                  * We have the following case.
306                  * bb_head -> bb_1 -> .. bb_n -> endtry_bb -> succ
307                  * For this particular case, we swap endtry bb and curr_bb_thread because the bblock that
308                  * contains the endtry statement does not contain any other statements!!
309                  */
310                 CHECK_FATAL(endTryBB->GetFirstStmt()->GetOpCode() == OP_comment ||
311                                 endTryBB->GetFirstStmt()->GetOpCode() == OP_endtry,
312                             "the opcode of endTryBB's firstStmt should be OP_comment or OP_endtry");
313                 CHECK_FATAL(endTryBB->GetLastStmt()->GetOpCode() == OP_endtry,
314                             "the opcode of endTryBB's lastStmt should be OP_endtry");
315 
316                 /* we move endtry_bb before thread_head */
317                 BBT *threadHead = currBBThread.front();
318                 CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev() != nullptr,
319                             "the prev node of threadHead's firstStmt should be not nullptr");
320                 CHECK_FATAL(threadHead->GetFirstStmt()->GetOpCode() == OP_comment ||
321                                 threadHead->GetFirstStmt()->GetOpCode() == OP_label,
322                             "the opcode of threadHead's firstStmt should be OP_comment or OP_label");
323                 CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev()->GetNext() == threadHead->GetFirstStmt(),
324                             "the next of the prev of threadHead's firstStmt should equal threadHead's firstStmt");
325                 threadHead->GetFirstStmt()->GetPrev()->SetNext(endTryBB->GetFirstStmt());
326                 endTryBB->GetFirstStmt()->SetPrev(threadHead->GetFirstStmt()->GetPrev());
327                 BBT *threadTail = currBBThread.back();
328                 threadTail->GetLastStmt()->SetNext(endTryBB->GetLastStmt()->GetNext());
329                 if (endTryBB->GetLastStmt()->GetNext() != nullptr) {
330                     endTryBB->GetLastStmt()->GetNext()->SetPrev(threadTail->GetLastStmt());
331                 }
332                 endTryBB->GetLastStmt()->SetNext(threadHead->GetFirstStmt());
333 
334                 CHECK_FATAL(endTryBB->GetCondJumpBranch() == nullptr, "endTryBB's condJumpBranch must be nullptr");
335                 if (threadTail->GetFallthruBranch() != nullptr) {
336                     threadTail->SetFallthruBranch(firstStmtToBBMap[threadTail->GetLastStmt()->GetNext()]);
337                 }
338                 endTryBB->SetFallthruBranch(nullptr);
339                 if (bodyEndWithEndTry) {
340                     body.SetLast(threadTail->GetLastStmt());
341                 }
342             }
343             break;
344         }
345     }
346     return found;
347 }
348 
349 /* collect catchbb->fallthru(0-n) into currBBThread, when encounter a new catch, return it, else return nullptr */
CollectCatchAndFallthruUntilNextCatchBB(BBT * & lowerBB,uint32 & nextEnclosedIdx,std::vector<BBT * > & currBBThread)350 BBT *TryCatchBlocksLower::CollectCatchAndFallthruUntilNextCatchBB(BBT *&lowerBB, uint32 &nextEnclosedIdx,
351                                                                   std::vector<BBT *> &currBBThread)
352 {
353     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
354     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
355 
356     BBT *nextBBThreadHead = nullptr;
357     while (lowerBB->GetFallthruBranch() != nullptr) {
358         lowerBB = lowerBB->GetFallthruBranch();
359         ++nextEnclosedIdx;
360         if (lowerBB->IsEndTry()) {
361             CHECK_FATAL(lowerBB == endTryBB, "lowerBB should equal endTryBB");
362             break;
363         }
364 
365         for (uint32 j = 0; j < enclosedBBs.size(); ++j) {
366             if (enclosedBBs[j] == lowerBB) {
367                 enclosedBBs[j] = nullptr;
368                 break;
369             }
370         }
371         if (lowerBB->IsCatch()) {
372             nextBBThreadHead = lowerBB;
373             break;
374         }
375         currBBThread.emplace_back(lowerBB);
376     }
377 
378     if (nextBBThreadHead == nullptr && lowerBB->GetFallthruBranch() == nullptr && lowerBB != endTryBB &&
379         nextEnclosedIdx < enclosedBBs.size() && enclosedBBs[nextEnclosedIdx]) {
380         /*
381          * Using a loop to find the next_bb_thread_head when it's a catch_BB or a normal_BB which
382          * is after a catch_BB. Other condition, push_back into the curr_bb_thread.
383          */
384         do {
385             lowerBB = enclosedBBs[nextEnclosedIdx];
386             enclosedBBs[nextEnclosedIdx++] = nullptr;
387             BBT *head = currBBThread.front();
388             if (head->IsCatch() || lowerBB->IsCatch()) {
389                 nextBBThreadHead = lowerBB;
390                 break;
391             }
392             currBBThread.emplace_back(lowerBB);
393         } while (nextEnclosedIdx < enclosedBBs.size());
394     }
395 
396     return nextBBThreadHead;
397 }
398 
ProcessThreadTail(BBT & threadTail,BBT * const & nextBBThreadHead,bool hasMoveEndTry)399 void TryCatchBlocksLower::ProcessThreadTail(BBT &threadTail, BBT *const &nextBBThreadHead, bool hasMoveEndTry)
400 {
401     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
402     StmtNode *newEndTry = endTryBB->GetKeyStmt()->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
403     newEndTry->SetPrev(threadTail.GetLastStmt());
404     newEndTry->SetNext(threadTail.GetLastStmt()->GetNext());
405     if (bodyEndWithEndTry && hasMoveEndTry) {
406         if (threadTail.GetLastStmt()->GetNext()) {
407             threadTail.GetLastStmt()->GetNext()->SetPrev(newEndTry);
408         }
409     } else {
410         CHECK_FATAL(threadTail.GetLastStmt()->GetNext() != nullptr,
411                     "the next of threadTail's lastStmt should not be nullptr");
412         threadTail.GetLastStmt()->GetNext()->SetPrev(newEndTry);
413     }
414     threadTail.GetLastStmt()->SetNext(newEndTry);
415 
416     threadTail.SetLastStmt(*newEndTry);
417     if (hasMoveEndTry && nextBBThreadHead == nullptr) {
418         body.SetLast(threadTail.GetLastStmt());
419     }
420 }
421 
422 /* Wrap this catch block with try-endtry block */
WrapCatchWithTryEndTryBlock(std::vector<BBT * > & currBBThread,BBT * & nextBBThreadHead,uint32 & nextEnclosedIdx,bool hasMoveEndTry)423 void TryCatchBlocksLower::WrapCatchWithTryEndTryBlock(std::vector<BBT *> &currBBThread, BBT *&nextBBThreadHead,
424                                                       uint32 &nextEnclosedIdx, bool hasMoveEndTry)
425 {
426     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
427     StmtNode *tryStmt = tryEndTryBlock.GetTryStmtNode();
428     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
429     for (auto &e : currBBThread) {
430         CHECK_FATAL(!e->IsTry(), "expect e is not try");
431     }
432     BBT *threadHead = currBBThread.front();
433     if (threadHead->IsCatch()) {
434         StmtNode *jcStmt = threadHead->GetKeyStmt();
435         CHECK_FATAL(jcStmt->GetNext() != nullptr, "jcStmt's next should not be nullptr");
436         TryNode *jtCopy = static_cast<TryNode *>(tryStmt)->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
437         jtCopy->SetNext(jcStmt->GetNext());
438         jtCopy->SetPrev(jcStmt);
439         jcStmt->GetNext()->SetPrev(jtCopy);
440         jcStmt->SetNext(jtCopy);
441 
442         BBT *threadTail = currBBThread.back();
443 
444         /* for this endtry stmt, we don't need to create a basic block */
445         ProcessThreadTail(*threadTail, static_cast<BBT *const &>(nextBBThreadHead), hasMoveEndTry);
446     } else {
447         /* For cases try->catch->normal_bb->normal_bb->endtry, Combine normal bb first. */
448         while (nextEnclosedIdx < enclosedBBs.size()) {
449             if (nextBBThreadHead != nullptr) {
450                 if (nextBBThreadHead->IsCatch()) {
451                     break;
452                 }
453             }
454             BBT *ebbSecond = enclosedBBs[nextEnclosedIdx];
455             enclosedBBs[nextEnclosedIdx++] = nullptr;
456             CHECK_FATAL(ebbSecond != endTryBB, "ebbSecond should not equal endTryBB");
457             if (ebbSecond->IsCatch()) {
458                 nextBBThreadHead = ebbSecond;
459                 break;
460             }
461             currBBThread.emplace_back(ebbSecond);
462         }
463         /* normal bb. */
464         StmtNode *stmt = threadHead->GetFirstStmt();
465 
466         TryNode *jtCopy = static_cast<TryNode *>(tryStmt)->CloneTree(mirModule.GetCurFuncCodeMPAllocator());
467         jtCopy->SetNext(stmt);
468         jtCopy->SetPrev(stmt->GetPrev());
469         stmt->GetPrev()->SetNext(jtCopy);
470         stmt->SetPrev(jtCopy);
471         threadHead->SetFirstStmt(*jtCopy);
472 
473         BBT *threadTail = currBBThread.back();
474 
475         /* for this endtry stmt, we don't need to create a basic block */
476         ProcessThreadTail(*threadTail, static_cast<BBT *const &>(nextBBThreadHead), hasMoveEndTry);
477     }
478 }
479 
480 /*
481  * We have the following case.
482  * bb_head -> bb_1 -> .. bb_n -> endtry_bb -> succ
483  * For this particular case, we swap EndTry bb and curr_bb_thread, because the bblock that contains the endtry
484  * statement does not contain any other statements!!
485  */
SwapEndTryBBAndCurrBBThread(const std::vector<BBT * > & currBBThread,bool & hasMoveEndTry,const BBT * nextBBThreadHead)486 void TryCatchBlocksLower::SwapEndTryBBAndCurrBBThread(const std::vector<BBT *> &currBBThread, bool &hasMoveEndTry,
487                                                       const BBT *nextBBThreadHead)
488 {
489     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
490     CHECK_FATAL(endTryBB->GetFirstStmt()->GetOpCode() == OP_comment ||
491                     endTryBB->GetFirstStmt()->GetOpCode() == OP_endtry,
492                 "the opcode of endTryBB's firstStmt should be OP_comment or OP_endtry");
493     CHECK_FATAL(endTryBB->GetLastStmt()->GetOpCode() == OP_endtry,
494                 "the opcode of endTryBB's lastStmt should be OP_endtry");
495 
496     /* we move endtry_bb before bb_head */
497     BBT *threadHead = currBBThread.front();
498     CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev() != nullptr,
499                 "the prev of threadHead's firstStmt should not nullptr");
500     CHECK_FATAL(threadHead->GetFirstStmt()->GetOpCode() == OP_comment ||
501                     threadHead->GetFirstStmt()->GetOpCode() == OP_label,
502                 "the opcode of threadHead's firstStmt should be OP_comment or OP_label");
503     CHECK_FATAL(threadHead->GetFirstStmt()->GetPrev()->GetNext() == threadHead->GetFirstStmt(),
504                 "the next of the prev of threadHead's firstStmt should equal threadHead's firstStmt");
505 
506     endTryBB->GetFirstStmt()->GetPrev()->SetNext(endTryBB->GetLastStmt()->GetNext());
507     if (endTryBB->GetLastStmt()->GetNext() != nullptr) {
508         endTryBB->GetLastStmt()->GetNext()->SetPrev(endTryBB->GetFirstStmt()->GetPrev());
509     }
510 
511     threadHead->GetFirstStmt()->GetPrev()->SetNext(endTryBB->GetFirstStmt());
512     endTryBB->GetFirstStmt()->SetPrev(threadHead->GetFirstStmt()->GetPrev());
513 
514     endTryBB->GetLastStmt()->SetNext(threadHead->GetFirstStmt());
515     threadHead->GetFirstStmt()->SetPrev(endTryBB->GetLastStmt());
516 
517     CHECK_FATAL(endTryBB->GetCondJumpBranch() == nullptr, "endTryBB's condJumpBranch must be nullptr");
518     endTryBB->SetFallthruBranch(nullptr);
519     if (bodyEndWithEndTry) {
520         hasMoveEndTry = true;
521         if (nextBBThreadHead == nullptr) {
522             body.SetLast(currBBThread.back()->GetLastStmt());
523         }
524     }
525 }
526 
ProcessEnclosedBBBetweenTryEndTry()527 void TryCatchBlocksLower::ProcessEnclosedBBBetweenTryEndTry()
528 {
529     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
530     MapleVector<BBT *> &labeledBBsInTry = tryEndTryBlock.GetLabeledBBsInTry();
531 
532     for (uint32 i = 0; i < enclosedBBs.size(); ++i) {
533         BBT *lowerBB = enclosedBBs[i];
534         uint32 nextEnclosedIdx = i + 1;
535         if (lowerBB == nullptr) {
536             continue; /* we may have removed the element */
537         }
538         if (!lowerBB->IsLabeled()) {
539             continue;
540         }
541         labeledBBsInTry.emplace_back(lowerBB);
542 
543         /*
544          * It seems the way a finally is associated with its try is to put the catch block inside
545          * the java-try-end-try block. So, keep the 'catch(void*)' in it.
546          */
547         LabelIdx ebbLabel = lowerBB->GetLabelIdx();
548         bool found = CheckAndProcessCatchNodeInCurrTryBlock(*lowerBB, ebbLabel, i);
549         /* fill cur_bb_thread until meet the next catch */
550         if (!found && lowerBB->IsCatch()) {
551             enclosedBBs[i] = nullptr;
552             std::vector<BBT *> currBBThread;
553             BBT *nextBBThreadHead = nullptr;
554             bool isFirstTime = true;
555             bool hasMoveEndTry = false;
556             do {
557                 if (nextBBThreadHead != nullptr) {
558                     isFirstTime = false;
559                 }
560                 nextBBThreadHead = nullptr;
561                 currBBThread.clear();
562                 currBBThread.emplace_back(lowerBB);
563                 nextBBThreadHead = CollectCatchAndFallthruUntilNextCatchBB(lowerBB, nextEnclosedIdx, currBBThread);
564                 WrapCatchWithTryEndTryBlock(currBBThread, nextBBThreadHead, nextEnclosedIdx, hasMoveEndTry);
565                 if (isFirstTime) {
566                     SwapEndTryBBAndCurrBBThread(currBBThread, hasMoveEndTry, nextBBThreadHead);
567                 }
568             } while (nextBBThreadHead != nullptr);
569         }
570     }
571 }
572 
ConnectRemainBB()573 void TryCatchBlocksLower::ConnectRemainBB()
574 {
575     MapleVector<BBT *> &enclosedBBs = tryEndTryBlock.GetEnclosedBBs();
576     BBT *startTryBB = tryEndTryBlock.GetStartTryBB();
577     BBT *endTryBB = tryEndTryBlock.GetEndTryBB();
578     size_t nEnclosedBBs = enclosedBBs.size();
579     size_t k = 0;
580     while ((k < nEnclosedBBs) && (enclosedBBs[k] == nullptr)) {
581         ++k;
582     }
583 
584     if (k < nEnclosedBBs) {
585         BBT *prevBB = enclosedBBs[k];
586 
587         startTryBB->GetLastStmt()->SetNext(prevBB->GetFirstStmt());
588         prevBB->GetFirstStmt()->SetPrev(startTryBB->GetLastStmt());
589 
590         for (++k; k < nEnclosedBBs; ++k) {
591             BBT *lowerBB = enclosedBBs[k];
592             if (lowerBB == nullptr) {
593                 continue;
594             }
595             prevBB->GetLastStmt()->SetNext(lowerBB->GetFirstStmt());
596             lowerBB->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
597             prevBB = lowerBB;
598         }
599 
600         prevBB->GetLastStmt()->SetNext(endTryBB->GetFirstStmt());
601         endTryBB->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
602     } else {
603         startTryBB->GetLastStmt()->SetNext(endTryBB->GetFirstStmt());
604         endTryBB->GetFirstStmt()->SetPrev(startTryBB->GetLastStmt());
605     }
606 }
607 
FindInsertAfterBB()608 BBT *TryCatchBlocksLower::FindInsertAfterBB()
609 {
610     BBT *insertAfter = tryEndTryBlock.GetEndTryBB();
611     CHECK_FATAL(tryEndTryBlock.GetEndTryBB()->GetLastStmt()->GetOpCode() == OP_endtry, "LowerBB type check");
612     BBT *iaOpenTry = nullptr;
613     while (insertAfter->GetFallthruBranch() != nullptr || iaOpenTry != nullptr) {
614         if (insertAfter->GetFallthruBranch() != nullptr) {
615             insertAfter = insertAfter->GetFallthruBranch();
616         } else {
617             CHECK_FATAL(iaOpenTry != nullptr, "iaOpenTry should not be nullptr");
618             insertAfter = firstStmtToBBMap[insertAfter->GetLastStmt()->GetNext()];
619             CHECK_FATAL(!insertAfter->IsTry(), "insertAfter should not be try");
620         }
621 
622         if (insertAfter->IsTry()) {
623             iaOpenTry = insertAfter;
624         } else if (insertAfter->IsEndTry()) {
625             iaOpenTry = nullptr;
626         }
627     }
628     return insertAfter;
629 }
630 
PlaceRelocatedBB(BBT & insertAfter)631 void TryCatchBlocksLower::PlaceRelocatedBB(BBT &insertAfter)
632 {
633     StmtNode *iaLast = insertAfter.GetLastStmt();
634     CHECK_FATAL(iaLast != nullptr, "iaLast should not nullptr");
635 
636     StmtNode *iaNext = iaLast->GetNext();
637     if (iaNext == nullptr) {
638         CHECK_FATAL(body.GetLast() == iaLast, "body's last should equal iaLast");
639     }
640     BBT *prevBB = &insertAfter;
641     MapleVector<BBT *> &bbsToRelocate = tryEndTryBlock.GetBBsToRelocate();
642     for (auto &rbb : bbsToRelocate) {
643         prevBB->GetLastStmt()->SetNext(rbb->GetFirstStmt());
644         rbb->GetFirstStmt()->SetPrev(prevBB->GetLastStmt());
645         prevBB = rbb;
646     }
647     prevBB->GetLastStmt()->SetNext(iaNext);
648     if (iaNext != nullptr) {
649         iaNext->SetPrev(prevBB->GetLastStmt());
650     } else {
651         /* !ia_next means we started with insert_after that was the last bblock Refer to the above CHECK_FATAL. */
652         body.SetLast(prevBB->GetLastStmt());
653         body.GetLast()->SetNext(nullptr);
654     }
655 }
656 
PalceCatchSeenSofar(BBT & insertAfter)657 void TryCatchBlocksLower::PalceCatchSeenSofar(BBT &insertAfter)
658 {
659     TryNode *tryNode = static_cast<TryNode *>(tryEndTryBlock.GetTryStmtNode());
660     DEBUG_ASSERT(tryNode != nullptr, "tryNode should not be nullptr");
661     MapleVector<BBT *> &bbsToRelocate = tryEndTryBlock.GetBBsToRelocate();
662 
663     for (size_t offsetIndex = 0; offsetIndex < tryNode->GetOffsetsCount(); ++offsetIndex) {
664         auto id = tryNode->GetOffset(offsetIndex);
665         bool myCatchBlock = false;
666         for (auto &jcb : bbsToRelocate) {
667             if (!jcb->IsLabeled()) {
668                 continue;
669             }
670             myCatchBlock = (id == jcb->GetLabelIdx());
671             if (myCatchBlock) {
672                 break;
673             }
674         }
675         /*
676          * If the catch block is the one enclosed in this try-endtry block,
677          * we just relocated it above, so we don't need to consider it again
678          */
679         if (myCatchBlock) {
680             continue;
681         }
682 
683         CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
684         for (auto &jcb : catchesSeenSoFar) {
685             CHECK_FATAL(jcb->IsLabeled(), "jcb should be labeled");
686             if (id == jcb->GetLabelIdx()) {
687                 /*
688                  * Remove jcb and all of the blocks that are reachable by following fallthruBranch.
689                  * If we hit a try block, cut there, append an unconditional jump to it to the preceding bblock,
690                  * and relocate them. We may need to insert a label in the try block
691                  */
692                 BBT *lastBB = jcb;
693                 while (lastBB->GetFallthruBranch() != nullptr && !lastBB->GetFallthruBranch()->IsTry()) {
694                     lastBB = lastBB->GetFallthruBranch();
695                 }
696 
697 #if DEBUG
698                 BBT::ValidateStmtList(bodyFirst);
699 #endif
700                 if (lastBB->GetFallthruBranch() != nullptr) {
701                     BBT *jtBB = lastBB->GetFallthruBranch();
702                     CHECK_FATAL(jtBB->IsTry(), "jtBB should be try");
703                     if (!jtBB->IsLabeled()) {
704                         LabelIdx jtLabIdx = mirModule.GetMIRBuilder()->CreateLabIdx(*mirModule.CurFunction());
705                         jtBB->SetLabelIdx(jtLabIdx);
706                         StmtNode *labelStmt = mirModule.GetMIRBuilder()->CreateStmtLabel(jtLabIdx);
707                         bool adjustBBFirstStmt = (jtBB->GetKeyStmt() == jtBB->GetFirstStmt());
708                         labelStmt->SetNext(jtBB->GetKeyStmt());
709                         labelStmt->SetPrev(jtBB->GetKeyStmt()->GetPrev());
710                         CHECK_FATAL(jtBB->GetKeyStmt()->GetPrev() != nullptr,
711                                     "the prev of jtBB's ketStmt shpould not be nullptr");
712                         jtBB->GetKeyStmt()->GetPrev()->SetNext(labelStmt);
713                         CHECK_FATAL(jtBB->GetKeyStmt()->GetNext() != nullptr,
714                                     "the next of jtBB's ketStmt shpould not be nullptr");
715                         jtBB->GetKeyStmt()->SetPrev(labelStmt);
716                         if (adjustBBFirstStmt) {
717                             firstStmtToBBMap.erase(jtBB->GetFirstStmt());
718                             jtBB->SetFirstStmt(*labelStmt);
719                             firstStmtToBBMap[jtBB->GetFirstStmt()] = jtBB;
720                         }
721                     }
722                     CHECK_FATAL(jtBB->IsLabeled(), "jtBB should be labeled");
723                     CHECK_FATAL(lastBB->GetLastStmt()->GetOpCode() != OP_goto,
724                                 "the opcode of lastBB's lastStmt should not be OP_goto");
725                     StmtNode *gotoStmt = mirModule.GetMIRBuilder()->CreateStmtGoto(OP_goto, jtBB->GetLabelIdx());
726 
727                     StmtNode *lastBBLastStmt = lastBB->GetLastStmt();
728                     gotoStmt->SetNext(lastBBLastStmt->GetNext());
729                     gotoStmt->SetPrev(lastBBLastStmt);
730                     if (lastBBLastStmt->GetNext()) {
731                         lastBBLastStmt->GetNext()->SetPrev(gotoStmt);
732                     }
733                     lastBBLastStmt->SetNext(gotoStmt);
734 
735                     lastBB->SetLastStmt(*gotoStmt);
736                     lastBB->SetFallthruBranch(nullptr);
737 
738 #if DEBUG
739                     CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
740                     BBT::ValidateStmtList(bodyFirst);
741 #endif
742                 }
743 
744                 /* we want to remove [jcb .. last_bb], inclusively. */
745                 if (jcb->GetFirstStmt() == body.GetFirst()) {
746                     body.SetFirst(lastBB->GetLastStmt()->GetNext());
747                     body.GetFirst()->SetPrev(nullptr);
748                     lastBB->GetLastStmt()->GetNext()->SetPrev(nullptr);
749                     bodyFirst = body.GetFirst();
750                 } else {
751                     CHECK_FATAL(jcb->GetFirstStmt()->GetPrev() != nullptr,
752                                 "the prev of jcb's firstStmt should not be nullptr");
753                     CHECK_FATAL(jcb->GetFirstStmt()->GetPrev()->GetNext() == jcb->GetFirstStmt(),
754                                 "the next of the prev of jcb's firstStmt should equal jcb's firstStmt");
755                     if (lastBB->GetLastStmt()->GetNext() != nullptr) {
756                         jcb->GetFirstStmt()->GetPrev()->SetNext(lastBB->GetLastStmt()->GetNext());
757                         lastBB->GetLastStmt()->GetNext()->SetPrev(jcb->GetFirstStmt()->GetPrev());
758                     } else {
759                         CHECK_FATAL(lastBB->GetLastStmt() == body.GetLast(),
760                                     "lastBB's lastStmt should equal body's last");
761                         body.SetLast(jcb->GetFirstStmt()->GetPrev());
762                         body.GetLast()->SetNext(nullptr);
763                         jcb->GetFirstStmt()->GetPrev()->SetNext(nullptr);
764                     }
765                 }
766                 jcb->GetFirstStmt()->SetPrev(nullptr);
767                 lastBB->GetLastStmt()->SetNext(nullptr);
768 
769 #if DEBUG
770                 CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
771                 BBT::ValidateStmtList(body.GetFirst(), jcb->GetFirstStmt());
772 #endif
773 
774                 /* append it (i.e., [jcb->firstStmt .. last_bb->lastStmt]) after insert_after */
775                 CHECK_FATAL(insertAfter.GetFallthruBranch() == nullptr,
776                             "insertAfter's fallthruBranch should be nullptr");
777                 if (insertAfter.GetLastStmt() == body.GetLast()) {
778                     CHECK_FATAL(insertAfter.GetLastStmt()->GetNext() == nullptr,
779                                 "the next of insertAfter's lastStmt should not be nullptr");
780                 }
781 
782                 jcb->GetFirstStmt()->SetPrev(insertAfter.GetLastStmt());
783                 lastBB->GetLastStmt()->SetNext(insertAfter.GetLastStmt()->GetNext());
784 
785                 CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
786 
787                 if (insertAfter.GetLastStmt()->GetNext() != nullptr) {
788                     insertAfter.GetLastStmt()->GetNext()->SetPrev(lastBB->GetLastStmt());
789                     CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
790                 } else {
791                     /*
792                      * note that we have a single BlockNode that contains  all the instructions of a method.
793                      * What that means is each instruction's next is not nullptr except for the very last instruction.
794                      * insert_after->lastStmt->next == nullptr, means insert_after->lastStmt is indeed the last
795                      * instruction, and we are moving instructions of 'last_bb' after it. Thus, we need to fix the
796                      * BlockNode's last field.
797                      */
798                     body.SetLast(lastBB->GetLastStmt());
799                     CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
800                 }
801                 insertAfter.GetLastStmt()->SetNext(jcb->GetFirstStmt());
802                 if (jcb->GetFirstStmt()->GetPrev() != nullptr) {
803                     CHECK_FATAL(jcb->GetFirstStmt()->GetPrev()->GetNext() == jcb->GetFirstStmt(),
804                                 "the next of the prev of jcb's firstStmt should equal jcb's firstStmt");
805                 }
806                 if (lastBB->GetLastStmt()->GetNext() != nullptr) {
807                     CHECK_FATAL(lastBB->GetLastStmt()->GetNext()->GetPrev() == lastBB->GetLastStmt(),
808                                 "thr prev of the next of lastBB's lastStmt should equal lastBB's lastStmt");
809                 }
810 
811                 CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
812             }
813         }
814     }
815 }
816 
TraverseBBList()817 void TryCatchBlocksLower::TraverseBBList()
818 {
819     tryEndTryBlock.Init();
820     for (auto &bb : bbList) {
821         if (bb->IsCatch() && tryEndTryBlock.GetStartTryBB() == nullptr) {
822             /* Add to the list of catch blocks seen so far. */
823             catchesSeenSoFar.emplace_back(bb);
824         }
825         bodyEndWithEndTry = false;
826 
827         if (tryEndTryBlock.GetStartTryBB() == nullptr) {
828             if (bb->IsTry()) {
829                 StmtNode *firstNonCommentStmt = bb->GetFirstStmt();
830                 while (firstNonCommentStmt != nullptr && firstNonCommentStmt->GetOpCode() == OP_comment) {
831                     firstNonCommentStmt = firstNonCommentStmt->GetNext();
832                 }
833                 CHECK_FATAL(bb->GetLastStmt()->GetOpCode() != OP_try || bb->GetLastStmt() == firstNonCommentStmt ||
834                                 !generateEHCode,
835                             "make sure the opcode of bb's lastStmt is not OP_try"
836                             "or the opcode of bb's lastStmt is OP_try but bb's lastStmt equals firstNonCommentStmt"
837                             "or not generate EHCode");
838                 /* prepare for processing a java try block */
839                 tryEndTryBlock.Reset(*bb);
840             }
841             continue;
842         }
843 
844         /* We should have not a try block enclosed in another java try block!! */
845         CHECK_FATAL(!bb->IsTry(), "bb should not be try");
846         if (!bb->IsEndTry()) {
847             tryEndTryBlock.PushToEnclosedBBs(*bb);
848         } else {
849             tryEndTryBlock.SetEndTryBB(bb);
850             if (tryEndTryBlock.GetEndTryBB()->GetLastStmt() == body.GetLast()) {
851                 bodyEndWithEndTry = true;
852             }
853 #if DEBUG
854             for (size_t i = 0; i < tryEndTryBlock.GetEnclosedBBsSize(); ++i) {
855                 CHECK_FATAL(tryEndTryBlock.GetEnclosedBBsElem(i), "there should not be nullptr in enclosedBBs");
856             }
857 #endif
858             ProcessEnclosedBBBetweenTryEndTry();
859             /* Now, connect the remaining ones again n_enclosed_bbs includes 'nullptr's (i.e., deleted entries) */
860             ConnectRemainBB();
861             BBT *insertAfter = FindInsertAfterBB();
862             PlaceRelocatedBB(*insertAfter);
863 
864 #if DEBUG
865             CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
866             BBT::ValidateStmtList(bodyFirst);
867 #endif
868             if (prevBBOfTry[tryEndTryBlock.GetStartTryBB()]) {
869                 StmtNode *firstStmtMovedIn =
870                     MoveCondGotoIntoTry(*tryEndTryBlock.GetStartTryBB(), *prevBBOfTry[tryEndTryBlock.GetStartTryBB()],
871                                         tryEndTryBlock.GetLabeledBBsInTry());
872                 if (firstStmtMovedIn == bodyFirst) {
873                     bodyFirst = tryEndTryBlock.GetStartTryBB()->GetFirstStmt();
874                     prevBBOfTry[tryEndTryBlock.GetStartTryBB()] = nullptr;
875                 }
876             }
877             /*
878              * Now, examine each offset attached to this try and move any catch block
879              * that is not in 'bbs_to_relocate' but in 'catches_seen_so_far'
880              */
881             PalceCatchSeenSofar(*insertAfter);
882 
883             /* close the try that is open */
884             tryEndTryBlock.SetStartTryBB(nullptr);
885         }
886 #if DEBUG
887         CHECK_FATAL(body.GetLast()->GetNext() == nullptr, "the next of body's last should be nullptr");
888         BBT::ValidateStmtList(bodyFirst);
889 #endif
890     }
891 
892     body.SetFirst(bodyFirst);
893 }
894 
CheckTryCatchPattern() const895 void TryCatchBlocksLower::CheckTryCatchPattern() const
896 {
897     StmtNode *openJt = nullptr;
898     for (StmtNode *stmt = body.GetFirst(); stmt; stmt = stmt->GetNext()) {
899         switch (stmt->GetOpCode()) {
900             case OP_try:
901                 openJt = stmt;
902                 break;
903             case OP_endtry:
904                 openJt = nullptr;
905                 break;
906             case OP_catch:
907                 if (openJt != nullptr) {
908                     CatchNode *jcn = static_cast<CatchNode *>(stmt);
909                     for (uint32 i = 0; i < jcn->Size(); ++i) {
910                         MIRType *type =
911                             GlobalTables::GetTypeTable().GetTypeFromTyIdx(jcn->GetExceptionTyIdxVecElement(i));
912                         MIRPtrType *ptr = static_cast<MIRPtrType *>(type);
913                         type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptr->GetPointedTyIdx());
914                         CHECK_FATAL(type->GetPrimType() == PTY_void, "type's primType should be PTY_void");
915                     }
916                 }
917                 break;
918             default:
919                 break;
920         }
921     }
922 }
923 } /* namespace maplebe */