More exception handling improvements... WIP.

Highlights include:

  Add a helper to generate __cxa_free_exception and _ZSt9terminatev.
  Add a region to handle EH object deallocation for ctor failures for throw.
  Add a terminate handler for __cxa_end_catch.
  A framework for adding cleanup actions for the exceptional edges only.

llvm-svn: 90305
This commit is contained in:
Mike Stump 2009-12-02 07:41:41 +00:00
parent b9878ee6b6
commit 33270211a0
3 changed files with 112 additions and 47 deletions

View File

@ -31,9 +31,21 @@ static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
}
static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) {
// void __cxa_free_exception(void *thrown_exception);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
Args, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
}
static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
// void __cxa_throw (void *thrown_exception, std::type_info *tinfo,
// void (*dest) (void *) );
// void __cxa_throw(void *thrown_exception, std::type_info *tinfo,
// void (*dest) (void *));
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(3, Int8PtrTy);
@ -46,7 +58,7 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
}
static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
// void __cxa_rethrow ();
// void __cxa_rethrow();
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@ -55,7 +67,7 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
}
static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
// void* __cxa_begin_catch ();
// void* __cxa_begin_catch();
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@ -67,7 +79,7 @@ static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
}
static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
// void __cxa_end_catch ();
// void __cxa_end_catch();
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
@ -92,6 +104,15 @@ static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
}
static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
// void __terminate();
const llvm::FunctionType *FTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
return CGF.CGM.CreateRuntimeFunction(FTy, "_ZSt9terminatev");
}
// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
// N is casted to the right type.
static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
@ -112,7 +133,19 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
CGF.EmitAggExpr(E, This, false);
} else if (CXXConstructorDecl *CopyCtor
= RD->getCopyConstructor(CGF.getContext(), 0)) {
// FIXME: region management
// All temporaries end before we call __cxa_throw
CodeGenFunction::CleanupScope TryScope(CGF);
{
// These actions are only on the exceptional edge.
CodeGenFunction::DelayedCleanupBlock Scope(CGF, true);
llvm::Constant *FreeExceptionFn = getFreeExceptionFn(CGF);
const llvm::Type *Int8PtrTy
= llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
llvm::Value *ExceptionPtr = CGF.Builder.CreateBitCast(N, Int8PtrTy);
CGF.Builder.CreateCall(FreeExceptionFn, ExceptionPtr);
}
llvm::Value *Src = CGF.EmitLValue(E).getAddress();
// Stolen from EmitClassAggrMemberwiseCopy
@ -129,9 +162,8 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
CopyCtor->getType()->getAs<FunctionType>()->getResultType();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, CallArgs, CopyCtor);
// FIXME: region management
} else
CGF.ErrorUnsupported(E, "uncopyable object");
llvm::llvm_unreachable("uncopyable object");
}
}
@ -154,7 +186,7 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
CGF.EmitAggregateCopy(This, E, ObjectType);
} else if (CXXConstructorDecl *CopyCtor
= RD->getCopyConstructor(CGF.getContext(), 0)) {
// FIXME: region management
// FIXME: region management, call terminate
llvm::Value *Src = E;
// Stolen from EmitClassAggrMemberwiseCopy
@ -241,16 +273,12 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::BasicBlock *PrevLandingPad = getInvokeDest();
llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
#if 0
llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
#endif
llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
#if 0
// Push an EH context entry, used for handling rethrows.
PushCleanupBlock(FinallyBlock);
#endif
// Emit the statements in the try {} block
setInvokeDest(TryHandler);
@ -306,6 +334,7 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
llvm::Value *Selector
= Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
SelectorArgs.end(), "selector");
llvm::BasicBlock *TerminateHandler = 0;
for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
const CXXCatchStmt *C = S.getHandler(i);
VarDecl *CatchParam = C->getExceptionDecl();
@ -375,13 +404,15 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
EmitBlock(MatchEnd);
// Unfortunately, we also have to generate another EH frame here
// in case this throws.
llvm::BasicBlock *MatchEndHandler =
createBasicBlock("match.end.handler");
llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
// Set up terminate handler
bool GenerateTerminate = false;
if (!TerminateHandler) {
TerminateHandler = createBasicBlock("terminate.handler");
GenerateTerminate = true;
}
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
Builder.CreateInvoke(getEndCatchFn(*this),
Cont, MatchEndHandler,
Cont, TerminateHandler,
Args.begin(), Args.begin());
EmitBlock(Cont);
@ -390,19 +421,31 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
if (Info.EndBlock)
EmitBlock(Info.EndBlock);
EmitBlock(MatchEndHandler);
Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
Args.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
Builder.CreateStore(Exc, RethrowPtr);
EmitBranchThroughCleanup(FinallyRethrow);
if (GenerateTerminate) {
GenerateTerminate = false;
EmitBlock(TerminateHandler);
Exc = Builder.CreateCall(llvm_eh_exception, "exc");
// We are required to emit this call to satisfy LLVM, even
// though we don't use the result.
Args.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
0));
Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
llvm::CallInst *TerminateCall =
Builder.CreateCall(getTerminateFn(*this));
TerminateCall->setDoesNotReturn();
Builder.CreateUnreachable();
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
}
if (Next)
EmitBlock(Next);
}
@ -413,7 +456,6 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
setInvokeDest(PrevLandingPad);
#if 0
EmitBlock(FinallyBlock);
if (Info.SwitchBlock)
@ -423,7 +465,6 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// Branch around the rethrow code.
EmitBranch(FinallyEnd);
#endif
EmitBlock(FinallyRethrow);
Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),

View File

@ -606,8 +606,10 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
}
void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock) {
CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock));
llvm::BasicBlock *CleanupExitBlock,
bool EHOnly) {
CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
EHOnly));
}
void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@ -629,6 +631,8 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
std::vector<llvm::BranchInst *> BranchFixups;
std::swap(BranchFixups, CE.BranchFixups);
bool EHOnly = CE.EHOnly;
CleanupEntries.pop_back();
// Check if any branch fixups pointed to the scope we just popped. If so,
@ -663,8 +667,9 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
Builder.SetInsertPoint(SwitchBlock);
llvm::Value *DestCodePtr = CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
"cleanup.dst");
llvm::Value *DestCodePtr
= CreateTempAlloca(llvm::Type::getInt32Ty(VMContext),
"cleanup.dst");
llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
// Create a switch instruction to determine where to jump next.
@ -710,15 +715,16 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
new llvm::StoreInst(ID, DestCodePtr, BI);
} else {
// We need to jump through another cleanup block. Create a pad block
// with a branch instruction that jumps to the final destination and
// add it as a branch fixup to the current cleanup scope.
// with a branch instruction that jumps to the final destination and add
// it as a branch fixup to the current cleanup scope.
// Create the pad block.
llvm::BasicBlock *CleanupPad = createBasicBlock("cleanup.pad", CurFn);
// Create a unique case ID.
llvm::ConstantInt *ID = llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
SI->getNumSuccessors());
llvm::ConstantInt *ID
= llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
SI->getNumSuccessors());
// Store the jump destination before the branch instruction.
new llvm::StoreInst(ID, DestCodePtr, BI);
@ -744,12 +750,19 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
BlockScopes.erase(Blocks[i]);
}
return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock);
return CleanupBlockInfo(CleanupEntryBlock, SwitchBlock, EndBlock, EHOnly);
}
void CodeGenFunction::EmitCleanupBlock() {
CleanupBlockInfo Info = PopCleanupBlock();
if (Info.EHOnly) {
// FIXME: Add this to the exceptional edge
if (Info.CleanupBlock->getNumUses() == 0)
delete Info.CleanupBlock;
return;
}
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
if (CurBB && !CurBB->getTerminator() &&
Info.CleanupBlock->getNumUses() == 0) {

View File

@ -109,7 +109,8 @@ public:
/// PushCleanupBlock - Push a new cleanup entry on the stack and set the
/// passed in block as the cleanup block.
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock = 0);
llvm::BasicBlock *CleanupExitBlock = 0,
bool EHOnly = false);
/// CleanupBlockInfo - A struct representing a popped cleanup block.
struct CleanupBlockInfo {
@ -123,9 +124,13 @@ public:
/// EndBlock - the default destination for the switch instruction.
llvm::BasicBlock *EndBlock;
/// EHOnly - True iff this cleanup should only be performed on the
/// exceptional edge.
bool EHOnly;
CleanupBlockInfo(llvm::BasicBlock *cb, llvm::BasicBlock *sb,
llvm::BasicBlock *eb)
: CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb) {}
llvm::BasicBlock *eb, bool ehonly = false)
: CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {}
};
/// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
@ -141,11 +146,13 @@ public:
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
bool EHOnly;
public:
DelayedCleanupBlock(CodeGenFunction &cgf)
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) {
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
}
@ -156,7 +163,7 @@ public:
}
~DelayedCleanupBlock() {
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB);
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, EHOnly);
// FIXME: This is silly, move this into the builder.
if (CurBB)
CGF.Builder.SetInsertPoint(CurBB);
@ -303,10 +310,14 @@ private:
/// inserted into the current function yet.
std::vector<llvm::BranchInst *> BranchFixups;
/// EHOnly - Perform this only on the exceptional edge, not the main edge.
bool EHOnly;
explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock)
llvm::BasicBlock *CleanupExitBlock, bool ehonly)
: CleanupEntryBlock(CleanupEntryBlock),
CleanupExitBlock(CleanupExitBlock) {}
CleanupExitBlock(CleanupExitBlock),
EHOnly(ehonly) {}
};
/// CleanupEntries - Stack of cleanup entries.