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