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:
parent
b9878ee6b6
commit
33270211a0
|
@ -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),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue