Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit d768e9d

Browse files
committed
Emit @finally blocks completely lazily instead of forcing their
existence by always threading an edge from the catchall. Not doing this was previously causing a crash in the very extreme case where neither the normal cleanup nor the EH catchall was actually reachable: we would delete the catchall entry block, which would cause us to delete the entry block of the finally cleanup as well because the cleanup logic would merge the blocks, which in turn triggered an assert because later blocks in the finally would still be using values from the entry. Laziness turns out to be the most elegant solution to the problem. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133601 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 4dba7b5 commit d768e9d

File tree

4 files changed

+94
-72
lines changed

4 files changed

+94
-72
lines changed

lib/CodeGen/CGException.cpp

+54-56
Original file line numberDiff line numberDiff line change
@@ -1298,28 +1298,29 @@ namespace {
12981298
/// Enters a finally block for an implementation using zero-cost
12991299
/// exceptions. This is mostly general, but hard-codes some
13001300
/// language/ABI-specific behavior in the catch-all sections.
1301-
CodeGenFunction::FinallyInfo
1302-
CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
1303-
llvm::Constant *BeginCatchFn,
1304-
llvm::Constant *EndCatchFn,
1305-
llvm::Constant *RethrowFn) {
1306-
assert((BeginCatchFn != 0) == (EndCatchFn != 0) &&
1301+
void CodeGenFunction::FinallyInfo::enter(CodeGenFunction &CGF,
1302+
const Stmt *body,
1303+
llvm::Constant *beginCatchFn,
1304+
llvm::Constant *endCatchFn,
1305+
llvm::Constant *rethrowFn) {
1306+
assert((beginCatchFn != 0) == (endCatchFn != 0) &&
13071307
"begin/end catch functions not paired");
1308-
assert(RethrowFn && "rethrow function is required");
1308+
assert(rethrowFn && "rethrow function is required");
1309+
1310+
BeginCatchFn = beginCatchFn;
13091311

13101312
// The rethrow function has one of the following two types:
13111313
// void (*)()
13121314
// void (*)(void*)
13131315
// In the latter case we need to pass it the exception object.
13141316
// But we can't use the exception slot because the @finally might
13151317
// have a landing pad (which would overwrite the exception slot).
1316-
const llvm::FunctionType *RethrowFnTy =
1318+
const llvm::FunctionType *rethrowFnTy =
13171319
cast<llvm::FunctionType>(
1318-
cast<llvm::PointerType>(RethrowFn->getType())
1319-
->getElementType());
1320-
llvm::Value *SavedExnVar = 0;
1321-
if (RethrowFnTy->getNumParams())
1322-
SavedExnVar = CreateTempAlloca(Builder.getInt8PtrTy(), "finally.exn");
1320+
cast<llvm::PointerType>(rethrowFn->getType())->getElementType());
1321+
SavedExnVar = 0;
1322+
if (rethrowFnTy->getNumParams())
1323+
SavedExnVar = CGF.CreateTempAlloca(CGF.Int8PtrTy, "finally.exn");
13231324

13241325
// A finally block is a statement which must be executed on any edge
13251326
// out of a given scope. Unlike a cleanup, the finally block may
@@ -1333,67 +1334,64 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
13331334
// The finally block itself is generated in the context of a cleanup
13341335
// which conditionally leaves the catch-all.
13351336

1336-
FinallyInfo Info;
1337-
13381337
// Jump destination for performing the finally block on an exception
13391338
// edge. We'll never actually reach this block, so unreachable is
13401339
// fine.
1341-
JumpDest RethrowDest = getJumpDestInCurrentScope(getUnreachableBlock());
1340+
RethrowDest = CGF.getJumpDestInCurrentScope(CGF.getUnreachableBlock());
13421341

13431342
// Whether the finally block is being executed for EH purposes.
1344-
llvm::AllocaInst *ForEHVar = CreateTempAlloca(Builder.getInt1Ty(),
1345-
"finally.for-eh");
1346-
InitTempAlloca(ForEHVar, llvm::ConstantInt::getFalse(getLLVMContext()));
1343+
ForEHVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "finally.for-eh");
1344+
CGF.Builder.CreateStore(CGF.Builder.getFalse(), ForEHVar);
13471345

13481346
// Enter a normal cleanup which will perform the @finally block.
1349-
EHStack.pushCleanup<PerformFinally>(NormalCleanup, Body,
1350-
ForEHVar, EndCatchFn,
1351-
RethrowFn, SavedExnVar);
1347+
CGF.EHStack.pushCleanup<PerformFinally>(NormalCleanup, body,
1348+
ForEHVar, endCatchFn,
1349+
rethrowFn, SavedExnVar);
13521350

13531351
// Enter a catch-all scope.
1354-
llvm::BasicBlock *CatchAllBB = createBasicBlock("finally.catchall");
1355-
CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
1356-
Builder.SetInsertPoint(CatchAllBB);
1357-
1358-
// If there's a begin-catch function, call it.
1359-
if (BeginCatchFn) {
1360-
Builder.CreateCall(BeginCatchFn, Builder.CreateLoad(getExceptionSlot()))
1361-
->setDoesNotThrow();
1362-
}
1352+
llvm::BasicBlock *catchBB = CGF.createBasicBlock("finally.catchall");
1353+
EHCatchScope *catchScope = CGF.EHStack.pushCatch(1);
1354+
catchScope->setCatchAllHandler(0, catchBB);
1355+
}
13631356

1364-
// If we need to remember the exception pointer to rethrow later, do so.
1365-
if (SavedExnVar) {
1366-
llvm::Value *SavedExn = Builder.CreateLoad(getExceptionSlot());
1367-
Builder.CreateStore(SavedExn, SavedExnVar);
1368-
}
1357+
void CodeGenFunction::FinallyInfo::exit(CodeGenFunction &CGF) {
1358+
// Leave the finally catch-all.
1359+
EHCatchScope &catchScope = cast<EHCatchScope>(*CGF.EHStack.begin());
1360+
llvm::BasicBlock *catchBB = catchScope.getHandler(0).Block;
1361+
CGF.EHStack.popCatch();
13691362

1370-
// Tell the finally block that we're in EH.
1371-
Builder.CreateStore(llvm::ConstantInt::getTrue(getLLVMContext()), ForEHVar);
1363+
// If there are any references to the catch-all block, emit it.
1364+
if (catchBB->use_empty()) {
1365+
delete catchBB;
1366+
} else {
1367+
CGBuilderTy::InsertPoint savedIP = CGF.Builder.saveAndClearIP();
1368+
CGF.EmitBlock(catchBB);
13721369

1373-
// Thread a jump through the finally cleanup.
1374-
EmitBranchThroughCleanup(RethrowDest);
1370+
llvm::Value *exn = 0;
13751371

1376-
Builder.restoreIP(SavedIP);
1372+
// If there's a begin-catch function, call it.
1373+
if (BeginCatchFn) {
1374+
exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
1375+
CGF.Builder.CreateCall(BeginCatchFn, exn)->setDoesNotThrow();
1376+
}
13771377

1378-
EHCatchScope *CatchScope = EHStack.pushCatch(1);
1379-
CatchScope->setCatchAllHandler(0, CatchAllBB);
1378+
// If we need to remember the exception pointer to rethrow later, do so.
1379+
if (SavedExnVar) {
1380+
if (!exn) exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot());
1381+
CGF.Builder.CreateStore(exn, SavedExnVar);
1382+
}
13801383

1381-
return Info;
1382-
}
1384+
// Tell the cleanups in the finally block that we're do this for EH.
1385+
CGF.Builder.CreateStore(CGF.Builder.getTrue(), ForEHVar);
13831386

1384-
void CodeGenFunction::ExitFinallyBlock(FinallyInfo &Info) {
1385-
// Leave the finally catch-all.
1386-
EHCatchScope &Catch = cast<EHCatchScope>(*EHStack.begin());
1387-
llvm::BasicBlock *CatchAllBB = Catch.getHandler(0).Block;
1388-
EHStack.popCatch();
1387+
// Thread a jump through the finally cleanup.
1388+
CGF.EmitBranchThroughCleanup(RethrowDest);
13891389

1390-
// And leave the normal cleanup.
1391-
PopCleanupBlock();
1392-
1393-
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
1394-
EmitBlock(CatchAllBB, true);
1390+
CGF.Builder.restoreIP(savedIP);
1391+
}
13951392

1396-
Builder.restoreIP(SavedIP);
1393+
// Finally, leave the @finally cleanup.
1394+
CGF.PopCleanupBlock();
13971395
}
13981396

13991397
llvm::BasicBlock *CodeGenFunction::getTerminateLandingPad() {

lib/CodeGen/CGObjCRuntime.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,8 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
175175

176176
CodeGenFunction::FinallyInfo FinallyInfo;
177177
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
178-
FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(),
179-
beginCatchFn,
180-
endCatchFn,
181-
exceptionRethrowFn);
178+
FinallyInfo.enter(CGF, Finally->getFinallyBody(),
179+
beginCatchFn, endCatchFn, exceptionRethrowFn);
182180

183181
llvm::SmallVector<CatchHandler, 8> Handlers;
184182

@@ -266,9 +264,9 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
266264
// Go back to the try-statement fallthrough.
267265
CGF.Builder.restoreIP(SavedIP);
268266

269-
// Pop out of the normal cleanup on the finally.
267+
// Pop out of the finally.
270268
if (S.getFinallyStmt())
271-
CGF.ExitFinallyBlock(FinallyInfo);
269+
FinallyInfo.exit(CGF);
272270

273271
if (Cont.isValid())
274272
CGF.EmitBlock(Cont.getBlock());

lib/CodeGen/CodeGenFunction.h

+21-9
Original file line numberDiff line numberDiff line change
@@ -635,16 +635,28 @@ class CodeGenFunction : public CodeGenTypeCache {
635635
/// rethrows.
636636
llvm::SmallVector<llvm::Value*, 8> ObjCEHValueStack;
637637

638-
// A struct holding information about a finally block's IR
639-
// generation. For now, doesn't actually hold anything.
640-
struct FinallyInfo {
641-
};
638+
/// A class controlling the emission of a finally block.
639+
class FinallyInfo {
640+
/// Where the catchall's edge through the cleanup should go.
641+
JumpDest RethrowDest;
642+
643+
/// A function to call to enter the catch.
644+
llvm::Constant *BeginCatchFn;
645+
646+
/// An i1 variable indicating whether or not the @finally is
647+
/// running for an exception.
648+
llvm::AllocaInst *ForEHVar;
642649

643-
FinallyInfo EnterFinallyBlock(const Stmt *Stmt,
644-
llvm::Constant *BeginCatchFn,
645-
llvm::Constant *EndCatchFn,
646-
llvm::Constant *RethrowFn);
647-
void ExitFinallyBlock(FinallyInfo &FinallyInfo);
650+
/// An i8* variable into which the exception pointer to rethrow
651+
/// has been saved.
652+
llvm::AllocaInst *SavedExnVar;
653+
654+
public:
655+
void enter(CodeGenFunction &CGF, const Stmt *Finally,
656+
llvm::Constant *beginCatchFn, llvm::Constant *endCatchFn,
657+
llvm::Constant *rethrowFn);
658+
void exit(CodeGenFunction &CGF);
659+
};
648660

649661
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
650662
/// current full-expression. Safe against the possibility that

test/CodeGenObjC/exceptions-nonfragile.m

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -O2 -o - %s | FileCheck %s
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-nonfragile-abi -fexceptions -fobjc-exceptions -o - %s | FileCheck %s
22

33
// rdar://problem/8535238
44
// CHECK: declare void @objc_exception_rethrow()
@@ -15,3 +15,17 @@ void protos() {
1515
void throwing() {
1616
@throw(@"error!");
1717
}
18+
19+
// rdar://problem/9431547
20+
void die(void) __attribute__((nothrow, noreturn));
21+
void test2(void) {
22+
@try {
23+
die();
24+
} @finally {
25+
extern void test2_helper(void);
26+
test2_helper();
27+
}
28+
29+
// CHECK: define void @test2()
30+
// CHECK-NOT: call void @test2_helper()
31+
}

0 commit comments

Comments
 (0)