Add cleanups for exceptional edges. WIP.

llvm-svn: 90940
This commit is contained in:
Mike Stump 2009-12-09 03:35:49 +00:00
parent daa3d6bb50
commit aff69af918
5 changed files with 174 additions and 34 deletions

View File

@ -581,22 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) {
DelayedCleanupBlock Scope(*this);
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(DeclPtr, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
{
DelayedCleanupBlock Scope(*this);
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(DeclPtr, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(DeclPtr, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
{
DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
}
}
}
}
@ -608,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
DelayedCleanupBlock scope(*this);
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
// In some cases, the type of the function argument will be different from
@ -619,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
//
// To fix this we insert a bitcast here.
QualType ArgTy = Info.arg_begin()->type;
DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy));
{
DelayedCleanupBlock scope(*this);
CallArgList Args;
Args.push_back(std::make_pair(RValue::get(DeclPtr),
getContext().getPointerType(D.getType())));
CallArgList Args;
Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
ConvertType(ArgTy))),
getContext().getPointerType(D.getType())));
EmitCall(Info, F, Args);
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCall(Info, F, Args);
CallArgList Args;
Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
ConvertType(ArgTy))),
getContext().getPointerType(D.getType())));
EmitCall(Info, F, Args);
}
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
DelayedCleanupBlock scope(*this);
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
V = Builder.CreateLoad(V);
BuildBlockRelease(V);
{
DelayedCleanupBlock scope(*this);
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
V = Builder.CreateLoad(V);
BuildBlockRelease(V);
}
// FIXME: Turn this on and audit the codegen
if (0 && Exceptions) {
EHCleanupBlock Cleanup(*this);
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
V = Builder.CreateLoad(V);
BuildBlockRelease(V);
}
}
}

View File

@ -650,3 +650,55 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
EmitBlock(FinallyEnd);
}
CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
CGF.EmitBranch(Cont1);
CGF.setInvokeDest(PreviousInvokeDest);
CGF.EmitBlock(CleanupHandler);
llvm::Constant *Personality =
CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
(CGF.VMContext),
true),
"__gxx_personality_v0");
Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
llvm::Value *llvm_eh_exception =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
llvm::Value *llvm_eh_selector =
CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
const llvm::IntegerType *Int8Ty;
const llvm::PointerType *PtrToInt8Ty;
Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
// C string type. Used in lots of places.
PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
llvm::SmallVector<llvm::Value*, 8> Args;
Args.clear();
Args.push_back(Exc);
Args.push_back(Personality);
Args.push_back(Null);
CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
CGF.EmitBlock(CleanupEntryBB);
CGF.EmitBlock(Cont1);
if (CGF.getInvokeDest()) {
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
CGF.getInvokeDest(), Exc);
CGF.EmitBlock(Cont);
} else
CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
CGF.Builder.CreateUnreachable();
CGF.EmitBlock(Cont);
if (CGF.Exceptions)
CGF.setInvokeDest(CleanupHandler);
}

View File

@ -137,8 +137,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext());
DelayedCleanupBlock scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
{
DelayedCleanupBlock scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
Val.getAggregateAddr());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete,
Val.getAggregateAddr());
}
}
}
}

View File

@ -34,6 +34,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
ConditionalBranchLevel(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
Exceptions = getContext().getLangOptions().Exceptions;
}
ASTContext &CodeGenFunction::getContext() const {
@ -625,9 +626,10 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock,
llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly) {
CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
EHOnly));
PreviousInvokeDest, EHOnly));
}
void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@ -651,6 +653,8 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
bool EHOnly = CE.EHOnly;
setInvokeDest(CE.PreviousInvokeDest);
CleanupEntries.pop_back();
// Check if any branch fixups pointed to the scope we just popped. If so,

View File

@ -107,6 +107,7 @@ public:
const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth;
bool Exceptions;
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
@ -115,8 +116,12 @@ 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,
llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly = false);
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) {
PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false);
}
/// CleanupBlockInfo - A struct representing a popped cleanup block.
struct CleanupBlockInfo {
@ -139,9 +144,35 @@ public:
: CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {}
};
/// EHCleanupBlock - RAII object that will create a cleanup block for the
/// exceptional edge and set the insert point to that block. When destroyed,
/// it creates the cleanup edge and sets the insert point to the previous
/// block.
class EHCleanupBlock {
CodeGenFunction& CGF;
llvm::BasicBlock *Cont;
llvm::BasicBlock *CleanupHandler;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *PreviousInvokeDest;
public:
EHCleanupBlock(CodeGenFunction &cgf)
: CGF(cgf), Cont(CGF.createBasicBlock("cont")),
CleanupHandler(CGF.createBasicBlock("ehcleanup")),
CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")),
PreviousInvokeDest(CGF.getInvokeDest()) {
CGF.EmitBranch(Cont);
CGF.Builder.SetInsertPoint(CleanupEntryBB);
// FIXME: set up terminate handler here
// CGF.setInvokeDest(TerminateHandler);
}
~EHCleanupBlock();
};
/// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
/// branch fixups and return a block info struct with the switch block and end
/// block.
/// block. This will also reset the invoke handler to the previous value
/// from when the cleanup block was created.
CleanupBlockInfo PopCleanupBlock();
/// DelayedCleanupBlock - RAII object that will create a cleanup block and set
@ -152,13 +183,15 @@ public:
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
llvm::BasicBlock *CurInvokeDest;
bool EHOnly;
public:
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
EHOnly(ehonly) {
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
CurInvokeDest(CGF.getInvokeDest()),
EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
}
@ -169,7 +202,8 @@ public:
}
~DelayedCleanupBlock() {
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, EHOnly);
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest,
EHOnly);
// FIXME: This is silly, move this into the builder.
if (CurBB)
CGF.Builder.SetInsertPoint(CurBB);
@ -316,13 +350,20 @@ private:
/// inserted into the current function yet.
std::vector<llvm::BranchInst *> BranchFixups;
/// PreviousInvokeDest - The invoke handler from the start of the cleanup
/// region.
llvm::BasicBlock *PreviousInvokeDest;
/// EHOnly - Perform this only on the exceptional edge, not the main edge.
bool EHOnly;
explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock, bool ehonly)
: CleanupEntryBlock(CleanupEntryBlock),
llvm::BasicBlock *CleanupExitBlock,
llvm::BasicBlock *PreviousInvokeDest,
bool ehonly)
: CleanupEntryBlock(CleanupEntryBlock),
CleanupExitBlock(CleanupExitBlock),
PreviousInvokeDest(PreviousInvokeDest),
EHOnly(ehonly) {}
};