• 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 "eh_func.h"
17 #include "cgfunc.h"
18 #include "cg.h"
19 #include "mir_builder.h"
20 #include "switch_lowerer.h"
21 
22 namespace maplebe {
23 using namespace maple;
24 
CollectEHInformation(std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)25 void EHFunc::CollectEHInformation(std::vector<std::pair<LabelIdx, CatchNode *>> &catchVec)
26 {
27     MIRFunction &mirFunc = cgFunc->GetFunction();
28     MIRModule *mirModule = mirFunc.GetModule();
29     CHECK_FATAL(mirModule != nullptr, "mirModule is nullptr in CGFunc::BuildEHFunc");
30     BlockNode *blkNode = mirFunc.GetBody();
31     CHECK_FATAL(blkNode != nullptr, "current function body is nullptr in CGFunc::BuildEHFunc");
32     EHTry *lastTry = nullptr; /* record last try */
33     /*
34      * curTry: record the current try wrapping the current statement,
35      *         reset to null when meet a endtry
36      */
37     EHTry *curTry = nullptr;
38     StmtNode *nextStmt = nullptr;
39 
40     /* collect all try-catch blocks */
41     for (StmtNode *stmt = blkNode->GetFirst(); stmt != nullptr; stmt = nextStmt) {
42         nextStmt = stmt->GetNext();
43         Opcode op = stmt->GetOpCode();
44         switch (op) {
45             case OP_try: {
46                 TryNode *tryNode = static_cast<TryNode *>(stmt);
47                 EHTry *ehTry = cgFunc->GetMemoryPool()->New<EHTry>(*(cgFunc->GetFuncScopeAllocator()), *tryNode);
48                 lastTry = ehTry;
49                 curTry = ehTry;
50                 AddTry(*ehTry);
51                 break;
52             }
53             case OP_endtry: {
54                 DEBUG_ASSERT(lastTry != nullptr, "lastTry is nullptr when current node is endtry");
55                 lastTry->SetEndtryNode(*stmt);
56                 lastTry = nullptr;
57                 curTry = nullptr;
58                 break;
59             }
60             case OP_catch: {
61                 CatchNode *catchNode = static_cast<CatchNode *>(stmt);
62                 DEBUG_ASSERT(stmt->GetPrev()->GetOpCode() == OP_label, "catch's previous node is not a label");
63                 LabelNode *labelStmt = static_cast<LabelNode *>(stmt->GetPrev());
64                 catchVec.emplace_back(std::pair<LabelIdx, CatchNode *>(labelStmt->GetLabelIdx(), catchNode));
65                 /* rename the type of <*void> to <*Throwable> */
66                 for (uint32 i = 0; i < catchNode->Size(); i++) {
67                     MIRType *ehType =
68                         GlobalTables::GetTypeTable().GetTypeFromTyIdx(catchNode->GetExceptionTyIdxVecElement(i));
69                     DEBUG_ASSERT(ehType->GetKind() == kTypePointer, "ehType must be kTypePointer.");
70                     MIRPtrType *ehPointedTy = static_cast<MIRPtrType *>(ehType);
71                     if (ehPointedTy->GetPointedTyIdx() == static_cast<TyIdx>(PTY_void)) {
72                         DEBUG_ASSERT(mirModule->GetThrowableTyIdx() != 0u, "throwable type id is 0");
73                         const MIRType *throwType =
74                             GlobalTables::GetTypeTable().GetTypeFromTyIdx(mirModule->GetThrowableTyIdx());
75                         MIRType *pointerType = cgFunc->GetBecommon().BeGetOrCreatePointerType(*throwType);
76                         catchNode->SetExceptionTyIdxVecElement(pointerType->GetTypeIndex(), i);
77                     }
78                 }
79                 break;
80             }
81             case OP_throw: {
82                 if (!cgFunc->GetCG()->GetCGOptions().GenerateExceptionHandlingCode() ||
83                     (cgFunc->GetCG()->IsExclusiveEH() && cgFunc->GetCG()->IsExclusiveFunc(mirFunc))) {
84                     /* remove the statment */
85                     BlockNode *bodyNode = mirFunc.GetBody();
86                     bodyNode->RemoveStmt(stmt);
87                     break;
88                 }
89                 UnaryStmtNode *throwNode = static_cast<UnaryStmtNode *>(stmt);
90                 EHThrow *ehReThrow = cgFunc->GetMemoryPool()->New<EHThrow>(*throwNode);
91                 ehReThrow->SetJavaTry(curTry);
92                 AddRethrow(*ehReThrow);
93                 break;
94             }
95             case OP_block:
96                 CHECK_FATAL(false, "should've lowered earlier");
97             default:
98                 break;
99         }
100     }
101 }
102 
DumpEHTry(const MIRModule & mirModule)103 void EHTry::DumpEHTry(const MIRModule &mirModule)
104 {
105     if (tryNode != nullptr) {
106         tryNode->Dump();
107     }
108 
109     if (endTryNode != nullptr) {
110         endTryNode->Dump();
111     }
112 
113     for (const auto *currCatch : catchVec) {
114         if (currCatch == nullptr) {
115             continue;
116         }
117         currCatch->Dump();
118     }
119 }
120 
ConvertThrowToRuntime(CGFunc & cgFunc,BaseNode & arg)121 void EHThrow::ConvertThrowToRuntime(CGFunc &cgFunc, BaseNode &arg)
122 {
123     MIRFunction &mirFunc = cgFunc.GetFunction();
124     MIRModule *mirModule = mirFunc.GetModule();
125     MIRFunction *calleeFunc =
126         mirModule->GetMIRBuilder()->GetOrCreateFunction("MCC_ThrowException", static_cast<TyIdx>(PTY_void));
127     cgFunc.GetBecommon().UpdateTypeTable(*calleeFunc->GetMIRFuncType());
128     calleeFunc->SetNoReturn();
129     MapleVector<BaseNode *> args(mirModule->GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());
130     args.emplace_back(&arg);
131     CallNode *callAssign = mirModule->GetMIRBuilder()->CreateStmtCall(calleeFunc->GetPuidx(), args);
132     mirFunc.GetBody()->ReplaceStmt1WithStmt2(rethrow, callAssign);
133 }
134 
ConvertThrowToRethrow(CGFunc & cgFunc)135 void EHThrow::ConvertThrowToRethrow(CGFunc &cgFunc)
136 {
137     MIRFunction &mirFunc = cgFunc.GetFunction();
138     MIRModule *mirModule = mirFunc.GetModule();
139     MIRBuilder *mirBuilder = mirModule->GetMIRBuilder();
140     MIRFunction *unFunc = mirBuilder->GetOrCreateFunction("MCC_RethrowException", static_cast<TyIdx>(PTY_void));
141     cgFunc.GetBecommon().UpdateTypeTable(*unFunc->GetMIRFuncType());
142     unFunc->SetNoReturn();
143     MapleVector<BaseNode *> args(mirBuilder->GetCurrentFuncCodeMpAllocator()->Adapter());
144     args.emplace_back(rethrow->Opnd(0));
145     CallNode *callNode = mirBuilder->CreateStmtCall(unFunc->GetPuidx(), args);
146     mirFunc.GetBody()->ReplaceStmt1WithStmt2(rethrow, callNode);
147 }
148 
Lower(CGFunc & cgFunc)149 void EHThrow::Lower(CGFunc &cgFunc)
150 {
151     BaseNode *opnd0 = rethrow->Opnd(0);
152     DEBUG_ASSERT(((opnd0->GetPrimType() == GetLoweredPtrType()) || (opnd0->GetPrimType() == PTY_ref)),
153                  "except a dread of a pointer to get its type");
154     MIRFunction &mirFunc = cgFunc.GetFunction();
155     MIRModule *mirModule = mirFunc.GetModule();
156     MIRBuilder *mirBuilder = mirModule->GetMIRBuilder();
157     DEBUG_ASSERT(mirBuilder != nullptr, "get mirBuilder failed in EHThrow::Lower");
158     MIRSymbol *mirSymbol = nullptr;
159     BaseNode *arg = nullptr;
160     MIRType *pstType = nullptr;
161     switch (opnd0->GetOpCode()) {
162         case OP_dread: {
163             DreadNode *drNode = static_cast<DreadNode *>(opnd0);
164             mirSymbol = mirFunc.GetLocalOrGlobalSymbol(drNode->GetStIdx());
165             DEBUG_ASSERT(mirSymbol != nullptr, "get symbol failed in EHThrow::Lower");
166             pstType = mirSymbol->GetType();
167             arg = drNode->CloneTree(mirModule->GetCurFuncCodeMPAllocator());
168             break;
169         }
170         case OP_iread: {
171             IreadNode *irNode = static_cast<IreadNode *>(opnd0);
172             MIRPtrType *pointerTy =
173                 static_cast<MIRPtrType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(irNode->GetTyIdx()));
174             if (irNode->GetFieldID() != 0) {
175                 MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerTy->GetPointedTyIdx());
176                 MIRStructType *structTy = nullptr;
177                 if (pointedTy->GetKind() != kTypeJArray) {
178                     structTy = static_cast<MIRStructType *>(pointedTy);
179                 } else {
180                     /* it's a Jarray type. using it's parent's field info: java.lang.Object */
181                     structTy = static_cast<MIRJarrayType *>(pointedTy)->GetParentType();
182                 }
183                 DEBUG_ASSERT(structTy != nullptr, "structTy is nullptr in EHThrow::Lower ");
184                 pstType = structTy->GetFieldType(irNode->GetFieldID());
185             } else {
186                 pstType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerTy->GetPointedTyIdx());
187             }
188             arg = irNode->CloneTree(mirModule->GetCurFuncCodeMPAllocator());
189             break;
190         }
191         case OP_regread: {
192             RegreadNode *rrNode = static_cast<RegreadNode *>(opnd0);
193             MIRPreg *pReg = mirFunc.GetPregTab()->PregFromPregIdx(rrNode->GetRegIdx());
194             DEBUG_ASSERT(pReg->GetPrimType() == GetLoweredPtrType(), "must be a pointer type");
195             pstType = pReg->GetMIRType();
196             arg = rrNode->CloneTree(mirModule->GetCurFuncCodeMPAllocator());
197             break;
198         }
199         case OP_retype: {
200             RetypeNode *retypeNode = static_cast<RetypeNode *>(opnd0);
201             pstType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(retypeNode->GetTyIdx());
202             arg = retypeNode->CloneTree(mirModule->GetCurFuncCodeMPAllocator());
203             break;
204         }
205         case OP_cvt: {
206             TypeCvtNode *cvtNode = static_cast<TypeCvtNode *>(opnd0);
207             PrimType prmType = cvtNode->GetPrimType();
208             // prmType supposed to be Pointer.
209             if ((prmType == PTY_ptr) || (prmType == PTY_ref) || (prmType == PTY_a32) || (prmType == PTY_a64)) {
210                 ConvertThrowToRethrow(cgFunc);
211             }
212             return;
213         }
214         default:
215             DEBUG_ASSERT(false, " NYI throw something");
216     }
217     CHECK_FATAL(pstType != nullptr, "pstType is null in EHThrow::Lower");
218     if (pstType->GetKind() != kTypePointer) {
219         LogInfo::MapleLogger() << "Error in function " << mirFunc.GetName() << "\n";
220         rethrow->Dump();
221         LogInfo::MapleLogger() << "pstType is supposed to be Pointer, but is not";
222         pstType->Dump(0);
223         CHECK_FATAL(false, "throw operand type kind must be kTypePointer");
224     }
225 
226     MIRType *stType =
227         GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast<MIRPtrType *>(pstType)->GetPointedTyIdx());
228     if (!IsUnderTry()) {
229         /*
230          * in this case the throw happens without a try...endtry wrapping it, need to generate lsda.
231          * insert 2 labels before and after throw
232          */
233         LabelNode *throwBeginLbl = mirBuilder->CreateStmtLabel(mirBuilder->CreateLabIdx(mirFunc));
234         LabelNode *throwEndLbl = mirBuilder->CreateStmtLabel(mirBuilder->CreateLabIdx(mirFunc));
235         BlockNode *bodyNode = mirFunc.GetBody();
236         bodyNode->InsertBefore(rethrow, throwBeginLbl);
237         bodyNode->InsertAfter(rethrow, throwEndLbl);
238         startLabel = throwBeginLbl;
239         endLabel = throwEndLbl;
240     }
241 
242     if (stType->GetKind() == kTypeClass) {
243         ConvertThrowToRuntime(cgFunc, *arg);
244     } else {
245         ConvertThrowToRethrow(cgFunc);
246     }
247 }
248 
EHFunc(CGFunc & func)249 EHFunc::EHFunc(CGFunc &func)
250     : cgFunc(&func),
251       tryVec(func.GetFuncScopeAllocator()->Adapter()),
252       ehTyTable(func.GetFuncScopeAllocator()->Adapter()),
253       ty2IndexTable(std::less<TyIdx>(), func.GetFuncScopeAllocator()->Adapter()),
254       rethrowVec(func.GetFuncScopeAllocator()->Adapter())
255 {
256 }
257 
BuildEHFunc()258 EHFunc *CGFunc::BuildEHFunc()
259 {
260     EHFunc *newEHFunc = GetMemoryPool()->New<EHFunc>(*this);
261     SetEHFunc(*newEHFunc);
262     std::vector<std::pair<LabelIdx, CatchNode *>> catchVec;
263     newEHFunc->CollectEHInformation(catchVec);
264     newEHFunc->MergeCatchToTry(catchVec);
265     newEHFunc->BuildEHTypeTable(catchVec);
266     newEHFunc->InsertEHSwitchTable();
267     newEHFunc->InsertCxaAfterEachCatch(catchVec);
268     newEHFunc->GenerateCleanupLabel();
269 
270     GetBecommon().BeGetOrCreatePointerType(*GlobalTables::GetTypeTable().GetVoid());
271     if (newEHFunc->NeedFullLSDA()) {
272         newEHFunc->CreateLSDA();
273     } else if (newEHFunc->HasThrow()) {
274         newEHFunc->LowerThrow();
275     }
276     if (GetCG()->GetCGOptions().GenerateExceptionHandlingCode()) {
277         newEHFunc->CreateTypeInfoSt();
278     }
279 
280     return newEHFunc;
281 }
282 
NeedFullLSDA() const283 bool EHFunc::NeedFullLSDA() const
284 {
285     if (cgFunc->GetFunction().IsJava()) {
286         return HasTry();
287     } else {
288         return false;
289     }
290 }
291 
NeedFastLSDA() const292 bool EHFunc::NeedFastLSDA() const
293 {
294     if (cgFunc->GetFunction().IsJava()) {
295         return !HasTry();
296     } else {
297         return false;
298     }
299 }
300 
HasTry() const301 bool EHFunc::HasTry() const
302 {
303     return !tryVec.empty();
304 }
305 
CreateTypeInfoSt()306 void EHFunc::CreateTypeInfoSt()
307 {
308     MIRFunction &mirFunc = cgFunc->GetFunction();
309     bool ctorDefined = false;
310     if (mirFunc.GetAttr(FUNCATTR_constructor) && !mirFunc.GetAttr(FUNCATTR_static) && (mirFunc.GetBody() != nullptr)) {
311         ctorDefined = true;
312     }
313 
314     if (!ctorDefined) {
315         return;
316     }
317 
318     const auto *classType = static_cast<const MIRClassType *>(mirFunc.GetClassType());
319     if (cgFunc->GetMirModule().IsCModule() && classType == nullptr) {
320         return;
321     }
322     DEBUG_ASSERT(classType != nullptr, "");
323     if (classType->GetMethods().empty() && (classType->GetFieldsSize() == 0)) {
324         return;
325     }
326 
327     if (classType->GetExceptionRootType() == nullptr) {
328         return; /* not a exception type */
329     }
330 }
331 
LowerThrow()332 void EHFunc::LowerThrow()
333 {
334     MIRFunction &mirFunc = cgFunc->GetFunction();
335     /* just lower without building LSDA */
336     for (EHThrow *rethrow : rethrowVec) {
337         BaseNode *opnd0 = rethrow->GetRethrow()->Opnd(0);
338         /* except a dread of a point to get its type */
339         switch (opnd0->GetOpCode()) {
340             case OP_retype: {
341                 RetypeNode *retypeNode = static_cast<RetypeNode *>(opnd0);
342                 DEBUG_ASSERT(GlobalTables::GetTypeTable().GetTypeFromTyIdx(retypeNode->GetTyIdx())->GetKind() ==
343                                  kTypePointer,
344                              "expecting a pointer type");
345                 rethrow->ConvertThrowToRuntime(
346                     *cgFunc, *retypeNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator()));
347                 break;
348             }
349             case OP_dread: {
350                 DreadNode *drNode = static_cast<DreadNode *>(opnd0);
351                 DEBUG_ASSERT(mirFunc.GetLocalOrGlobalSymbol(drNode->GetStIdx())->GetType()->GetKind() == kTypePointer,
352                              "expect pointer type");
353                 rethrow->ConvertThrowToRuntime(*cgFunc,
354                                                *drNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator()));
355                 break;
356             }
357             case OP_iread: {
358                 IreadNode *irNode = static_cast<IreadNode *>(opnd0);
359                 MIRPtrType *receiverPtrType = nullptr;
360                 if (irNode->GetFieldID() != 0) {
361                     MIRPtrType *pointerTy =
362                         static_cast<MIRPtrType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(irNode->GetTyIdx()));
363                     MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointerTy->GetPointedTyIdx());
364                     MIRStructType *structTy = nullptr;
365                     if (pointedTy->GetKind() != kTypeJArray) {
366                         structTy = static_cast<MIRStructType *>(pointedTy);
367                     } else {
368                         /* it's a Jarray type. using it's parent's field info: java.lang.Object */
369                         structTy = static_cast<MIRJarrayType *>(pointedTy)->GetParentType();
370                     }
371                     DEBUG_ASSERT(structTy != nullptr, "structTy is nullptr in EHFunc::LowerThrow");
372                     receiverPtrType = static_cast<MIRPtrType *>(structTy->GetFieldType(irNode->GetFieldID()));
373                 } else {
374                     receiverPtrType =
375                         static_cast<MIRPtrType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(irNode->GetTyIdx()));
376                     receiverPtrType = static_cast<MIRPtrType *>(
377                         GlobalTables::GetTypeTable().GetTypeFromTyIdx(receiverPtrType->GetPointedTyIdx()));
378                 }
379                 DEBUG_ASSERT(receiverPtrType->GetKind() == kTypePointer, "expecting a pointer type");
380                 rethrow->ConvertThrowToRuntime(*cgFunc,
381                                                *irNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator()));
382                 break;
383             }
384             case OP_regread: {
385                 RegreadNode *rrNode = static_cast<RegreadNode *>(opnd0);
386                 DEBUG_ASSERT(mirFunc.GetPregTab()->PregFromPregIdx(rrNode->GetRegIdx())->GetPrimType() ==
387                                  GetLoweredPtrType(),
388                              "expect GetLoweredPtrType()");
389                 DEBUG_ASSERT(mirFunc.GetPregTab()->PregFromPregIdx(rrNode->GetRegIdx())->GetMIRType()->GetKind() ==
390                                  kTypePointer,
391                              "expect pointer type");
392                 rethrow->ConvertThrowToRuntime(*cgFunc,
393                                                *rrNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator()));
394                 break;
395             }
396             case OP_constval: {
397                 ConstvalNode *constValNode = static_cast<ConstvalNode *>(opnd0);
398                 BaseNode *newNode = constValNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator());
399                 DEBUG_ASSERT(newNode != nullptr, "nullptr check");
400                 rethrow->ConvertThrowToRuntime(*cgFunc, *newNode);
401                 break;
402             }
403             case OP_cvt: {
404                 TypeCvtNode *cvtNode = static_cast<TypeCvtNode *>(opnd0);
405                 PrimType prmType = cvtNode->GetPrimType();
406                 // prmType supposed to be Pointer.
407                 if ((prmType == PTY_ptr) || (prmType == PTY_ref) || (prmType == PTY_a32) || (prmType == PTY_a64)) {
408                     BaseNode *newNode = cvtNode->CloneTree(mirFunc.GetModule()->GetCurFuncCodeMPAllocator());
409                     rethrow->ConvertThrowToRuntime(*cgFunc, *newNode);
410                 }
411                 break;
412             }
413             default:
414                 DEBUG_ASSERT(false, "unexpected or NYI");
415         }
416     }
417 }
418 
419 /*
420  * merge catch to try
421  */
MergeCatchToTry(const std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)422 void EHFunc::MergeCatchToTry(const std::vector<std::pair<LabelIdx, CatchNode *>> &catchVec)
423 {
424     size_t tryOffsetCount;
425     for (auto *ehTry : tryVec) {
426         tryOffsetCount = ehTry->GetTryNode()->GetOffsetsCount();
427         for (size_t i = 0; i < tryOffsetCount; i++) {
428             auto o = ehTry->GetTryNode()->GetOffset(i);
429             for (const auto &catchVecPair : catchVec) {
430                 LabelIdx lbIdx = catchVecPair.first;
431                 if (lbIdx == o) {
432                     ehTry->PushBackCatchVec(*catchVecPair.second);
433                     break;
434                 }
435             }
436         }
437         CHECK_FATAL(ehTry->GetCatchVecSize() == tryOffsetCount,
438                     "EHTry instance offset does not equal catch node amount.");
439     }
440 }
441 
442 /* catchvec is going to be released by the caller */
BuildEHTypeTable(const std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)443 void EHFunc::BuildEHTypeTable(const std::vector<std::pair<LabelIdx, CatchNode *>> &catchVec)
444 {
445     if (!catchVec.empty()) {
446         /* the first one assume to be <*void> */
447         TyIdx voidTyIdx(PTY_void);
448         ehTyTable.emplace_back(voidTyIdx);
449         ty2IndexTable[voidTyIdx] = 0;
450         /* create void pointer and update becommon's size table */
451         cgFunc->GetBecommon().UpdateTypeTable(*GlobalTables::GetTypeTable().GetVoidPtr());
452     }
453 
454     /* create the type table for this function, just iterate each catch */
455     CatchNode *jCatchNode = nullptr;
456     size_t catchNodeSize;
457     for (const auto &catchVecPair : catchVec) {
458         jCatchNode = catchVecPair.second;
459         catchNodeSize = jCatchNode->Size();
460         for (size_t i = 0; i < catchNodeSize; i++) {
461             MIRType *mirTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(jCatchNode->GetExceptionTyIdxVecElement(i));
462             DEBUG_ASSERT(mirTy->GetKind() == kTypePointer, "mirTy is not pointer type");
463             TyIdx ehTyIdx = static_cast<MIRPtrType *>(mirTy)->GetPointedTyIdx();
464             if (ty2IndexTable.find(ehTyIdx) != ty2IndexTable.end()) {
465                 continue;
466             }
467 
468             ty2IndexTable[ehTyIdx] = ehTyTable.size();
469             ehTyTable.emplace_back(ehTyIdx);
470             MIRClassType *catchType =
471                 static_cast<MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(ehTyIdx));
472             MIRClassType *rootType = catchType->GetExceptionRootType();
473             if (rootType == nullptr) {
474                 rootType = static_cast<MIRClassType *>(GlobalTables::GetTypeTable().GetOrCreateClassType(
475                     "Ljava_2Flang_2FThrowable_3B", *GlobalTables::GetGsymTable().GetModule()));
476                 catchType->SetParentTyIdx(rootType->GetTypeIndex());
477             }
478         }
479     }
480 }
481 
DumpEHFunc() const482 void EHFunc::DumpEHFunc() const
483 {
484     MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
485     for (uint32 i = 0; i < this->tryVec.size(); i++) {
486         LogInfo::MapleLogger() << "\n========== start " << i << " th eh:\n";
487         EHTry *ehTry = tryVec[i];
488         ehTry->DumpEHTry(mirModule);
489         LogInfo::MapleLogger() << "========== end " << i << " th eh =========\n";
490     }
491 
492     LogInfo::MapleLogger() << "\n========== start LSDA type table ========\n";
493     for (uint32 i = 0; i < this->ehTyTable.size(); i++) {
494         LogInfo::MapleLogger() << i << " vector to ";
495         GlobalTables::GetTypeTable().GetTypeFromTyIdx(ehTyTable[i])->Dump(0);
496         LogInfo::MapleLogger() << "\n";
497     }
498     LogInfo::MapleLogger() << "========== end LSDA type table ========\n";
499 
500     LogInfo::MapleLogger() << "\n========== start type-index map ========\n";
501     for (const auto &ty2indexTablePair : ty2IndexTable) {
502         GlobalTables::GetTypeTable().GetTypeFromTyIdx(ty2indexTablePair.first)->Dump(0);
503         LogInfo::MapleLogger() << " map to ";
504         LogInfo::MapleLogger() << ty2indexTablePair.second << "\n";
505     }
506     LogInfo::MapleLogger() << "========== end type-index map ========\n";
507 }
508 
509 /*
510  * cleanup_label is an LabelNode, and placed just before endLabel.
511  * cleanup_label is the first statement of cleanupbb.
512  * the layout of clean up code is:
513  * //return bb
514  *   ...
515  * //cleanup bb = lastbb->prev; cleanupbb->PrependBB(retbb)
516  *   cleanup_label:
517  *     ...
518  * //lastbb
519  *   endLabel:
520  *     .cfi_endproc
521  *   .Label.xx.end:
522  *     .size
523  */
GenerateCleanupLabel()524 void EHFunc::GenerateCleanupLabel()
525 {
526     MIRModule *mirModule = cgFunc->GetFunction().GetModule();
527     cgFunc->SetCleanupLabel(*mirModule->GetMIRBuilder()->CreateStmtLabel(CreateLabel(".LCLEANUP")));
528     BlockNode *blockNode = cgFunc->GetFunction().GetBody();
529     blockNode->InsertBefore(cgFunc->GetEndLabel(), cgFunc->GetCleanupLabel());
530 }
531 
InsertDefaultLabelAndAbortFunc(BlockNode & blkNode,SwitchNode & switchNode,const StmtNode & beforeEndLabel)532 void EHFunc::InsertDefaultLabelAndAbortFunc(BlockNode &blkNode, SwitchNode &switchNode, const StmtNode &beforeEndLabel)
533 {
534     MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
535     LabelIdx dfLabIdx = cgFunc->GetFunction().GetLabelTab()->CreateLabel();
536     cgFunc->GetFunction().GetLabelTab()->AddToStringLabelMap(dfLabIdx);
537     StmtNode *dfLabStmt = mirModule.GetMIRBuilder()->CreateStmtLabel(dfLabIdx);
538     blkNode.InsertAfter(&beforeEndLabel, dfLabStmt);
539     MIRFunction *calleeFunc = mirModule.GetMIRBuilder()->GetOrCreateFunction("abort", static_cast<TyIdx>(PTY_void));
540     cgFunc->GetBecommon().UpdateTypeTable(*calleeFunc->GetMIRFuncType());
541     MapleVector<BaseNode *> args(mirModule.GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());
542     CallNode *callExit = mirModule.GetMIRBuilder()->CreateStmtCall(calleeFunc->GetPuidx(), args);
543     blkNode.InsertAfter(dfLabStmt, callExit);
544     switchNode.SetDefaultLabel(dfLabIdx);
545 }
546 
FillSwitchTable(SwitchNode & switchNode,const EHTry & ehTry)547 void EHFunc::FillSwitchTable(SwitchNode &switchNode, const EHTry &ehTry)
548 {
549     CatchNode *catchNode = nullptr;
550     MIRType *exceptionType = nullptr;
551     MIRPtrType *ptType = nullptr;
552     size_t catchVecSize = ehTry.GetCatchVecSize();
553     /* update switch node's cases */
554     for (size_t i = 0; i < catchVecSize; i++) {
555         catchNode = ehTry.GetCatchNodeAt(i);
556         for (size_t j = 0; j < catchNode->Size(); j++) {
557             exceptionType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(catchNode->GetExceptionTyIdxVecElement(j));
558             ptType = static_cast<MIRPtrType *>(exceptionType);
559             MapleMap<TyIdx, uint32>::iterator ty2IdxIt = ty2IndexTable.find(ptType->GetPointedTyIdx());
560             DEBUG_ASSERT(ty2IdxIt != ty2IndexTable.end(), "find tyIdx failed!");
561             uint32 tableIdx = ty2IdxIt->second;
562             LabelNode *catchLabelNode = static_cast<LabelNode *>(catchNode->GetPrev());
563             CasePair p(tableIdx, catchLabelNode->GetLabelIdx());
564             bool inserted = false;
565             for (auto x : switchNode.GetSwitchTable()) {
566                 if (x == p) {
567                     inserted = true;
568                     break;
569                 }
570             }
571             if (!inserted) {
572                 switchNode.InsertCasePair(p);
573             }
574         }
575     }
576 }
577 
578 /* this is also the landing pad code. */
InsertEHSwitchTable()579 void EHFunc::InsertEHSwitchTable()
580 {
581     MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
582     BlockNode *blockNode = cgFunc->GetFunction().GetBody();
583     CHECK_FATAL(blockNode != nullptr, "get function body failed in EHThrow::InsertEHSwitchTable");
584     StmtNode *endLabelPrevNode = nullptr;
585     SwitchNode *switchNode = nullptr;
586     for (auto *ehTry : tryVec) {
587         endLabelPrevNode = cgFunc->GetEndLabel()->GetPrev();
588         /*
589          * get the next statement of the trynode. when no throw happend in try block, jump to the statement directly
590          * create a switch statement and insert after tryend;
591          */
592         switchNode = mirModule.CurFuncCodeMemPool()->New<SwitchNode>(mirModule);
593         /* create a new label as default, and if program excute here, error it */
594         InsertDefaultLabelAndAbortFunc(*blockNode, *switchNode, *endLabelPrevNode);
595         /* create s special symbol that use the second return of __builtin_eh_return() */
596         MIRSymbol *mirSymbol = mirModule.GetMIRBuilder()->CreateSymbol(TyIdx(PTY_i32), "__eh_index__", kStVar, kScAuto,
597                                                                        &cgFunc->GetFunction(), kScopeLocal);
598         switchNode->SetSwitchOpnd(mirModule.GetMIRBuilder()->CreateExprDread(*mirSymbol));
599         FillSwitchTable(*switchNode, *ehTry);
600         SwitchLowerer switchLower(mirModule, *switchNode, *cgFunc->GetFuncScopeAllocator());
601         blockNode->InsertBlockAfter(*switchLower.LowerSwitch(), endLabelPrevNode);
602         ehTry->SetFallthruGoto(endLabelPrevNode->GetNext());
603     }
604     if (!CGOptions::IsQuiet()) {
605         cgFunc->GetFunction().Dump();
606     }
607 }
608 
CreateLabel(const std::string & cstr)609 LabelIdx EHFunc::CreateLabel(const std::string &cstr)
610 {
611     MIRSymbol *mirSymbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(cgFunc->GetFunction().GetStIdx().Idx());
612     CHECK_FATAL(mirSymbol != nullptr, "get function symbol failed in EHFunc::CreateLabel");
613     std::string funcName = mirSymbol->GetName();
614     std::string labStr = funcName.append(cstr).append(std::to_string(labelIdx++));
615     return cgFunc->GetFunction().GetOrCreateLableIdxFromName(labStr);
616 }
617 
618 /* think about moving this to BELowerer where LowerThrownval is already written */
InsertCxaAfterEachCatch(const std::vector<std::pair<LabelIdx,CatchNode * >> & catchVec)619 void EHFunc::InsertCxaAfterEachCatch(const std::vector<std ::pair<LabelIdx, CatchNode *>> &catchVec)
620 {
621     MIRModule &mirModule = *cgFunc->GetFunction().GetModule();
622     BlockNode *funcBody = cgFunc->GetFunction().GetBody();
623     CatchNode *jCatchNode = nullptr;
624     TyIdx voidPTy = GlobalTables::GetTypeTable().GetVoidPtr()->GetTypeIndex();
625     for (const auto &catchVecPair : catchVec) {
626         jCatchNode = catchVecPair.second;
627         MIRFunction *calleeFunc = mirModule.GetMIRBuilder()->GetOrCreateFunction("MCC_JavaBeginCatch", voidPTy);
628         cgFunc->GetBecommon().UpdateTypeTable(*calleeFunc->GetMIRFuncType());
629         RegreadNode *retRegRead0 = mirModule.CurFuncCodeMemPool()->New<RegreadNode>();
630         retRegRead0->SetRegIdx(-kSregRetval0);
631         retRegRead0->SetPrimType(GetLoweredPtrType());
632         MapleVector<BaseNode *> args(mirModule.GetMIRBuilder()->GetCurrentFuncCodeMpAllocator()->Adapter());
633         args.emplace_back(retRegRead0);
634         CallNode *callAssign = mirModule.GetMIRBuilder()->CreateStmtCall(calleeFunc->GetPuidx(), args);
635         funcBody->InsertAfter(jCatchNode, callAssign);
636     }
637 }
638 
CreateLSDAHeader()639 void EHFunc::CreateLSDAHeader()
640 {
641     constexpr uint8 startEncoding = 0xff;
642     constexpr uint8 typeEncoding = 0x9b;
643     constexpr uint8 callSiteEncoding = 0x1;
644     MIRBuilder *mirBuilder = cgFunc->GetFunction().GetModule()->GetMIRBuilder();
645 
646     LSDAHeader *lsdaHeaders = cgFunc->GetMemoryPool()->New<LSDAHeader>();
647     LabelIdx lsdaHdLblIdx = CreateLabel("LSDAHD"); /* LSDA head */
648     LabelNode *lsdaHdLblNode = mirBuilder->CreateStmtLabel(lsdaHdLblIdx);
649     lsdaHeaders->SetLSDALabel(*lsdaHdLblNode);
650 
651     LabelIdx lsdaTTStartIdx = CreateLabel("LSDAALLS"); /* LSDA all start; */
652     LabelNode *lsdaTTLblNode = mirBuilder->CreateStmtLabel(lsdaTTStartIdx);
653     LabelIdx lsdaTTEndIdx = CreateLabel("LSDAALLE"); /* LSDA all end; */
654     LabelNode *lsdaCSTELblNode = mirBuilder->CreateStmtLabel(lsdaTTEndIdx);
655     lsdaHeaders->SetTTypeOffset(lsdaTTLblNode, lsdaCSTELblNode);
656 
657     lsdaHeaders->SetLPStartEncoding(startEncoding);
658     lsdaHeaders->SetTTypeEncoding(typeEncoding);
659     lsdaHeaders->SetCallSiteEncoding(callSiteEncoding);
660     lsdaHeader = lsdaHeaders;
661 }
662 
FillLSDACallSiteTable()663 void EHFunc::FillLSDACallSiteTable()
664 {
665     constexpr uint8 callSiteFirstAction = 0x1;
666     MIRBuilder *mirBuilder = cgFunc->GetFunction().GetModule()->GetMIRBuilder();
667     BlockNode *bodyNode = cgFunc->GetFunction().GetBody();
668 
669     lsdaCallSiteTable = cgFunc->GetMemoryPool()->New<LSDACallSiteTable>(*cgFunc->GetFuncScopeAllocator());
670     LabelIdx lsdaCSTStartIdx = CreateLabel("LSDACSTS"); /* LSDA callsite table start; */
671     LabelNode *lsdaCSTStartLabel = mirBuilder->CreateStmtLabel(lsdaCSTStartIdx);
672     LabelIdx lsdaCSTEndIdx = CreateLabel("LSDACSTE"); /* LSDA callsite table end; */
673     LabelNode *lsdaCSTEndLabel = mirBuilder->CreateStmtLabel(lsdaCSTEndIdx);
674     lsdaCallSiteTable->SetCSTable(lsdaCSTStartLabel, lsdaCSTEndLabel);
675 
676     /* create LDSACallSite for each EHTry instance */
677     for (auto *ehTry : tryVec) {
678         DEBUG_ASSERT(ehTry != nullptr, "null ptr check");
679         /* replace try with a label which is the callsite_start */
680         LabelIdx csStartLblIdx = CreateLabel("LSDACS");
681         LabelNode *csLblNode = mirBuilder->CreateStmtLabel(csStartLblIdx);
682         LabelIdx csEndLblIdx = CreateLabel("LSDACE");
683         LabelNode *ceLblNode = mirBuilder->CreateStmtLabel(csEndLblIdx);
684         TryNode *tryNode = ehTry->GetTryNode();
685         bodyNode->ReplaceStmt1WithStmt2(tryNode, csLblNode);
686         StmtNode *endTryNode = ehTry->GetEndtryNode();
687         bodyNode->ReplaceStmt1WithStmt2(endTryNode, ceLblNode);
688 
689         LabelNode *ladpadEndLabel = nullptr;
690         if (ehTry->GetFallthruGoto()) {
691             ladpadEndLabel = mirBuilder->CreateStmtLabel(CreateLabel("LSDALPE"));
692             bodyNode->InsertBefore(ehTry->GetFallthruGoto(), ladpadEndLabel);
693         } else {
694             ladpadEndLabel = ceLblNode;
695         }
696         /* When there is only one catch, the exception table is optimized. */
697         if (ehTry->GetCatchVecSize() == 1) {
698             ladpadEndLabel = static_cast<LabelNode *>(ehTry->GetCatchNodeAt(0)->GetPrev());
699         }
700 
701         LSDACallSite *lsdaCallSite = cgFunc->GetMemoryPool()->New<LSDACallSite>();
702         LabelPair csStart(cgFunc->GetStartLabel(), csLblNode);
703         LabelPair csLength(csLblNode, ceLblNode);
704         LabelPair csLandingPad(cgFunc->GetStartLabel(), ladpadEndLabel);
705         lsdaCallSite->Init(csStart, csLength, csLandingPad, callSiteFirstAction);
706         ehTry->SetLSDACallSite(*lsdaCallSite);
707         lsdaCallSiteTable->PushBack(*lsdaCallSite);
708     }
709 }
710 
CreateLSDA()711 void EHFunc::CreateLSDA()
712 {
713     constexpr uint8 callSiteCleanUpAction = 0x0;
714     /* create header */
715     CreateLSDAHeader();
716     /* create and fill callsite table */
717     FillLSDACallSiteTable();
718 
719     for (auto *rethrow : rethrowVec) {
720         DEBUG_ASSERT(rethrow != nullptr, "null ptr check");
721         /* replace throw (void * obj) with call __java_rethrow and unwind resume */
722         rethrow->Lower(*cgFunc);
723         if (rethrow->HasLSDA()) {
724             LSDACallSite *lsdaCallSite = cgFunc->GetMemoryPool()->New<LSDACallSite>();
725             LabelPair csStart(cgFunc->GetStartLabel(), rethrow->GetStartLabel());
726             LabelPair csLength(rethrow->GetStartLabel(), rethrow->GetEndLabel());
727             LabelPair csLandingPad(nullptr, nullptr);
728             lsdaCallSite->Init(csStart, csLength, csLandingPad, callSiteCleanUpAction);
729             lsdaCallSiteTable->PushBack(*lsdaCallSite);
730         }
731     }
732 
733     /* LSDAAction table */
734     CreateLSDAAction();
735 }
736 
CreateLSDAAction()737 void EHFunc::CreateLSDAAction()
738 {
739     constexpr uint8 actionTableNextEncoding = 0x7d;
740     /* iterate each try and its corresponding catch */
741     LSDAActionTable *actionTable = cgFunc->GetMemoryPool()->New<LSDAActionTable>(*cgFunc->GetFuncScopeAllocator());
742     lsdaActionTable = actionTable;
743 
744     for (auto *ehTry : tryVec) {
745         LSDAAction *lastAction = nullptr;
746         for (int32 j = static_cast<int32>(ehTry->GetCatchVecSize()) - 1; j >= 0; --j) {
747             CatchNode *catchNode = ehTry->GetCatchNodeAt(j);
748             DEBUG_ASSERT(catchNode != nullptr, "null ptr check");
749             for (uint32 idx = 0; idx < catchNode->Size(); ++idx) {
750                 MIRPtrType *ptType = static_cast<MIRPtrType *>(
751                     GlobalTables::GetTypeTable().GetTypeFromTyIdx(catchNode->GetExceptionTyIdxVecElement(idx)));
752                 uint32 tyIndex = ty2IndexTable[ptType->GetPointedTyIdx()]; /* get the index of ptType of ehTyTable; */
753                 DEBUG_ASSERT(tyIndex != 0, "exception type index not allow equal zero");
754                 LSDAAction *lsdaAction = cgFunc->GetMemoryPool()->New<LSDAAction>(
755                     tyIndex, lastAction == nullptr ? 0 : actionTableNextEncoding);
756                 lastAction = lsdaAction;
757                 actionTable->PushBack(*lsdaAction);
758             }
759         }
760 
761         /* record actionTable group offset, per LSDAAction object in actionTable occupy 2 bytes */
762         ehTry->SetCSAction((actionTable->Size() - 1) * 2 + 1);
763     }
764 }
765 
PhaseRun(maplebe::CGFunc & f)766 bool CgBuildEHFunc::PhaseRun(maplebe::CGFunc &f)
767 {
768     f.BuildEHFunc();
769     return false;
770 }
771 MAPLE_TRANSFORM_PHASE_REGISTER(CgBuildEHFunc, buildehfunc)
772 } /* namespace maplebe */
773