aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen')
-rw-r--r--lib/CodeGen/CGBlocks.cpp27
-rw-r--r--lib/CodeGen/CGBlocks.h2
-rw-r--r--lib/CodeGen/CGCall.cpp25
-rw-r--r--lib/CodeGen/CGClass.cpp83
-rw-r--r--lib/CodeGen/CGDecl.cpp112
-rw-r--r--lib/CodeGen/CGDeclCXX.cpp62
-rw-r--r--lib/CodeGen/CGException.cpp1493
-rw-r--r--lib/CodeGen/CGException.h342
-rw-r--r--lib/CodeGen/CGExpr.cpp17
-rw-r--r--lib/CodeGen/CGExprAgg.cpp2
-rw-r--r--lib/CodeGen/CGObjC.cpp14
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp354
-rw-r--r--lib/CodeGen/CGObjCMac.cpp676
-rw-r--r--lib/CodeGen/CGObjCRuntime.h6
-rw-r--r--lib/CodeGen/CGStmt.cpp268
-rw-r--r--lib/CodeGen/CGTemporaries.cpp144
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp551
-rw-r--r--lib/CodeGen/CodeGenFunction.h580
18 files changed, 2964 insertions, 1794 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index e5871b27d4..0d05a62138 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -363,32 +363,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
} else {
if (BDRE->getCopyConstructorExpr()) {
E = BDRE->getCopyConstructorExpr();
- // Code to destruct copy-constructed descriptor element for
- // copied-in class object.
- // TODO: Refactor this into common code with mostly similar
- // CodeGenFunction::EmitLocalBlockVarDecl
- QualType DtorTy = E->getType();
- if (const RecordType *RT = DtorTy->getAs<RecordType>())
- if (CXXRecordDecl *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (!ClassDecl->hasTrivialDestructor()) {
- const CXXDestructorDecl *D = ClassDecl->getDestructor();
- assert(D && "BuildBlockLiteralTmp - destructor is nul");
- {
- // Normal destruction.
- DelayedCleanupBlock Scope(*this);
- EmitCXXDestructorCall(D, Dtor_Complete,
- /*ForVirtualBase=*/false, Addr);
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
- }
- if (Exceptions) {
- EHCleanupBlock Cleanup(*this);
- EmitCXXDestructorCall(D, Dtor_Complete,
- /*ForVirtualBase=*/false, Addr);
- }
- }
- }
+ PushDestructorCleanup(E->getType(), Addr);
}
else {
E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD),
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 9e3750e3e6..772a62c24f 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -99,7 +99,7 @@ public:
llvm::Value *BlockObjectAssign;
llvm::Value *BlockObjectDispose;
- const llvm::Type *PtrToInt8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
std::map<uint64_t, llvm::Constant *> AssignCache;
std::map<uint64_t, llvm::Constant *> DestroyCache;
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 528a038f91..0a17e56d72 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1075,6 +1075,24 @@ RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) {
return EmitAnyExprToTemp(E);
}
+/// Emits a call or invoke instruction to the given function, depending
+/// on the current state of the EH stack.
+llvm::CallSite
+CodeGenFunction::EmitCallOrInvoke(llvm::Value *Callee,
+ llvm::Value * const *ArgBegin,
+ llvm::Value * const *ArgEnd,
+ const llvm::Twine &Name) {
+ llvm::BasicBlock *InvokeDest = getInvokeDest();
+ if (!InvokeDest)
+ return Builder.CreateCall(Callee, ArgBegin, ArgEnd, Name);
+
+ llvm::BasicBlock *ContBB = createBasicBlock("invoke.cont");
+ llvm::InvokeInst *Invoke = Builder.CreateInvoke(Callee, ContBB, InvokeDest,
+ ArgBegin, ArgEnd, Name);
+ EmitBlock(ContBB);
+ return Invoke;
+}
+
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
llvm::Value *Callee,
ReturnValueSlot ReturnValue,
@@ -1206,15 +1224,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
}
- llvm::BasicBlock *InvokeDest = getInvokeDest();
unsigned CallingConv;
CodeGen::AttributeListType AttributeList;
CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv);
llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList.begin(),
AttributeList.end());
+ llvm::BasicBlock *InvokeDest = 0;
+ if (!(Attrs.getFnAttributes() & llvm::Attribute::NoUnwind))
+ InvokeDest = getInvokeDest();
+
llvm::CallSite CS;
- if (!InvokeDest || (Attrs.getFnAttributes() & llvm::Attribute::NoUnwind)) {
+ if (!InvokeDest) {
CS = Builder.CreateCall(Callee, Args.data(), Args.data()+Args.size());
} else {
llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 085cfd3168..a69a3f9566 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -340,7 +340,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) {
// FIXME: Is this OK for C++0x delegating constructors?
- CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup);
CXXDestructorDecl *DD = BaseClassDecl->getDestructor();
CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V);
@@ -354,7 +354,7 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
QualType T,
unsigned Index) {
if (Index == MemberInit->getNumArrayIndices()) {
- CodeGenFunction::CleanupScope Cleanups(CGF);
+ CodeGenFunction::RunCleanupsScope Cleanups(CGF);
llvm::Value *Dest = LHS.getAddress();
if (ArrayIndexVar) {
@@ -410,7 +410,7 @@ static void EmitAggMemberInitializer(CodeGenFunction &CGF,
llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
{
- CodeGenFunction::CleanupScope Cleanups(CGF);
+ CodeGenFunction::RunCleanupsScope Cleanups(CGF);
// Inside the loop body recurse to emit the inner loop or, eventually, the
// constructor call.
@@ -534,7 +534,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (!RD->hasTrivialDestructor()) {
// FIXME: Is this OK for C++0x delegating constructors?
- CodeGenFunction::EHCleanupBlock Cleanup(CGF);
+ CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup);
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
@@ -612,7 +612,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
if (IsTryBody)
TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
- unsigned CleanupStackSize = CleanupEntries.size();
+ EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin();
// Emit the constructor prologue, i.e. the base and member
// initializers.
@@ -628,7 +628,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// initializers, which includes (along the exceptional path) the
// destructors for those members and bases that were fully
// constructed.
- EmitCleanupBlocks(CleanupStackSize);
+ PopCleanupBlocks(CleanupDepth);
if (IsTryBody)
ExitCXXTryStmt(*cast<CXXTryStmt>(Body), TryInfo);
@@ -648,9 +648,6 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
B != E; ++B) {
CXXBaseOrMemberInitializer *Member = (*B);
- assert(LiveTemporaries.empty() &&
- "Should not have any live temporaries at initializer start!");
-
if (Member->isBaseInitializer())
EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
else
@@ -659,12 +656,8 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
InitializeVTablePointers(ClassDecl);
- for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I) {
- assert(LiveTemporaries.empty() &&
- "Should not have any live temporaries at initializer start!");
-
+ for (unsigned I = 0, E = MemberInitializers.size(); I != E; ++I)
EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
- }
}
/// EmitDestructorBody - Emits the body of the current destructor.
@@ -684,8 +677,28 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
if (isTryBody)
TryInfo = EnterCXXTryStmt(*cast<CXXTryStmt>(Body));
- llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
- PushCleanupBlock(DtorEpilogue);
+ // Emit the destructor epilogue now. If this is a complete
+ // destructor with a function-try-block, perform the base epilogue
+ // as well.
+ //
+ // FIXME: This isn't really right, because an exception in the
+ // non-EH epilogue should jump to the appropriate place in the
+ // EH epilogue.
+ {
+ CleanupBlock Cleanup(*this, NormalCleanup);
+
+ if (isTryBody && DtorType == Dtor_Complete)
+ EmitDtorEpilogue(Dtor, Dtor_Base);
+ EmitDtorEpilogue(Dtor, DtorType);
+
+ if (Exceptions) {
+ Cleanup.beginEHCleanup();
+
+ if (isTryBody && DtorType == Dtor_Complete)
+ EmitDtorEpilogue(Dtor, Dtor_Base);
+ EmitDtorEpilogue(Dtor, DtorType);
+ }
+ }
bool SkipBody = false; // should get jump-threaded
@@ -724,23 +737,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// nothing to do besides what's in the epilogue
}
- // Jump to the cleanup block.
- CleanupBlockInfo Info = PopCleanupBlock();
- assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
- EmitBlock(DtorEpilogue);
-
- // Emit the destructor epilogue now. If this is a complete
- // destructor with a function-try-block, perform the base epilogue
- // as well.
- if (isTryBody && DtorType == Dtor_Complete)
- EmitDtorEpilogue(Dtor, Dtor_Base);
- EmitDtorEpilogue(Dtor, DtorType);
-
- // Link up the cleanup information.
- if (Info.SwitchBlock)
- EmitBlock(Info.SwitchBlock);
- if (Info.EndBlock)
- EmitBlock(Info.EndBlock);
+ // We're done with the epilogue cleanup.
+ PopCleanupBlock();
// Exit the try if applicable.
if (isTryBody)
@@ -939,7 +937,7 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
// Keep track of the current number of live temporaries.
{
- CXXTemporariesCleanupScope Scope(*this);
+ RunCleanupsScope Scope(*this);
EmitCXXConstructorCall(D, Ctor_Complete, /*ForVirtualBase=*/false, Address,
ArgBeg, ArgEnd);
@@ -1114,6 +1112,23 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
}
+void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) {
+ CXXRecordDecl *ClassDecl = T->getAsCXXRecordDecl();
+ if (!ClassDecl) return;
+ if (ClassDecl->hasTrivialDestructor()) return;
+
+ const CXXDestructorDecl *D = ClassDecl->getDestructor();
+
+ CleanupBlock Scope(*this, NormalCleanup);
+
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr);
+
+ if (Exceptions) {
+ Scope.beginEHCleanup();
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false, Addr);
+ }
+}
+
llvm::Value *
CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This,
const CXXRecordDecl *ClassDecl,
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 5c3055f5b6..959a9ae483 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -391,7 +391,8 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
/// variable declaration with auto, register, or no storage class specifier.
/// These turn into simple stack objects, or GlobalValues depending on target.
-void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
+void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D,
+ SpecialInitFn *SpecialInit) {
QualType Ty = D.getType();
bool isByRef = D.hasAttr<BlocksAttr>();
bool needsDispose = false;
@@ -489,7 +490,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
{
// Push a cleanup block and restore the stack there.
- DelayedCleanupBlock scope(*this);
+ CleanupBlock scope(*this, NormalCleanup);
V = Builder.CreateLoad(Stack, "tmp");
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
@@ -597,7 +598,9 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
}
- if (Init) {
+ if (SpecialInit) {
+ SpecialInit(*this, D, DeclPtr);
+ } else if (Init) {
llvm::Value *Loc = DeclPtr;
if (isByRef)
Loc = Builder.CreateStructGEP(DeclPtr, getByRefValueLLVMField(&D),
@@ -663,7 +666,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EmitAggExpr(Init, Loc, isVolatile);
}
}
-
+
// Handle CXX destruction of variables.
QualType DtorTy(Ty);
while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
@@ -683,20 +686,18 @@ 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(Loc, BasePtr);
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
-
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
- }
+ CleanupBlock Scope(*this, NormalCleanup);
+
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(Loc, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+
if (Exceptions) {
- EHCleanupBlock Cleanup(*this);
+ Scope.beginEHCleanup();
+
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -705,30 +706,30 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
}
} else {
- {
- // Normal destruction.
- DelayedCleanupBlock Scope(*this);
-
- if (NRVO) {
- // If we exited via NRVO, we skip the destructor call.
- llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
- Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
- Scope.getCleanupExitBlock(),
- NoNRVO);
- EmitBlock(NoNRVO);
- }
-
- // We don't call the destructor along the normal edge if we're
- // applying the NRVO.
- EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
- Loc);
-
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
+ // Normal destruction.
+ CleanupBlock Scope(*this, NormalCleanup);
+
+ llvm::BasicBlock *SkipDtor = 0;
+ if (NRVO) {
+ // If we exited via NRVO, we skip the destructor call.
+ llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
+ SkipDtor = createBasicBlock("nrvo.skipdtor");
+ Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
+ SkipDtor,
+ NoNRVO);
+ EmitBlock(NoNRVO);
}
+ // We don't call the destructor along the normal edge if we're
+ // applying the NRVO.
+ EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
+ Loc);
+
+ if (NRVO) EmitBlock(SkipDtor);
+
+ // Along the exceptions path we always execute the dtor.
if (Exceptions) {
- EHCleanupBlock Cleanup(*this);
+ Scope.beginEHCleanup();
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
Loc);
}
@@ -752,17 +753,19 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
//
// To fix this we insert a bitcast here.
QualType ArgTy = Info.arg_begin()->type;
- {
- DelayedCleanupBlock scope(*this);
- CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
- ConvertType(ArgTy))),
- getContext().getPointerType(D.getType())));
- EmitCall(Info, F, ReturnValueSlot(), Args);
- }
+ CleanupBlock CleanupScope(*this, NormalCleanup);
+
+ // Normal cleanup.
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
+ ConvertType(ArgTy))),
+ getContext().getPointerType(D.getType())));
+ EmitCall(Info, F, ReturnValueSlot(), Args);
+
+ // EH cleanup.
if (Exceptions) {
- EHCleanupBlock Cleanup(*this);
+ CleanupScope.beginEHCleanup();
CallArgList Args;
Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
@@ -773,15 +776,16 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
- {
- DelayedCleanupBlock scope(*this);
- llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
- V = Builder.CreateLoad(V);
- BuildBlockRelease(V);
- }
+ CleanupBlock CleanupScope(*this, NormalCleanup);
+
+ 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);
+ CleanupScope.beginEHCleanup();
+
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
V = Builder.CreateLoad(V);
BuildBlockRelease(V);
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 803ee10721..d7d01847ea 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -347,8 +347,6 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
EmitBlock(InitCheckBlock);
// Variables used when coping with thread-safe statics and exceptions.
- llvm::BasicBlock *SavedLandingPad = 0;
- llvm::BasicBlock *LandingPad = 0;
if (ThreadsafeStatics) {
// Call __cxa_guard_acquire.
V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable);
@@ -358,10 +356,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
InitBlock, EndBlock);
+ // Call __cxa_guard_abort along the exceptional edge.
if (Exceptions) {
- SavedLandingPad = getInvokeDest();
- LandingPad = createBasicBlock("guard.lpad");
- setInvokeDest(LandingPad);
+ CleanupBlock Cleanup(*this, EHCleanup);
+ Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
}
EmitBlock(InitBlock);
@@ -376,7 +374,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
EmitDeclInit(*this, D, GV);
if (ThreadsafeStatics) {
- // Call __cxa_guard_release.
+ // Call __cxa_guard_release. This cannot throw.
Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
} else {
llvm::Value *One =
@@ -388,58 +386,6 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
if (!D.getType()->isReferenceType())
EmitDeclDestroy(*this, D, GV);
- if (ThreadsafeStatics && Exceptions) {
- // If an exception is thrown during initialization, call __cxa_guard_abort
- // along the exceptional edge.
- EmitBranch(EndBlock);
-
- // Construct the landing pad.
- EmitBlock(LandingPad);
-
- // Personality function and LLVM intrinsics.
- llvm::Constant *Personality =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
- (VMContext),
- true),
- "__gxx_personality_v0");
- Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
- llvm::Value *llvm_eh_exception =
- CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
- llvm::Value *llvm_eh_selector =
- CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
-
- // Exception object
- llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
- llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
-
- // Call the selector function.
- const llvm::PointerType *PtrToInt8Ty
- = llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
- llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
- llvm::Value* SelectorArgs[3] = { Exc, Personality, Null };
- Builder.CreateCall(llvm_eh_selector, SelectorArgs, SelectorArgs + 3,
- "selector");
- Builder.CreateStore(Exc, RethrowPtr);
-
- // Call __cxa_guard_abort along the exceptional edge.
- Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
-
- setInvokeDest(SavedLandingPad);
-
- // Rethrow the current exception.
- if (getInvokeDest()) {
- llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
- Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
- getInvokeDest(),
- Builder.CreateLoad(RethrowPtr));
- EmitBlock(Cont);
- } else
- Builder.CreateCall(getUnwindResumeOrRethrowFn(),
- Builder.CreateLoad(RethrowPtr));
-
- Builder.CreateUnreachable();
- }
-
EmitBlock(EndBlock);
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 182c2ea877..1645e66d55 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -14,11 +14,158 @@
#include "clang/AST/StmtCXX.h"
#include "llvm/Intrinsics.h"
+#include "llvm/Support/CallSite.h"
#include "CodeGenFunction.h"
+#include "CGException.h"
+
using namespace clang;
using namespace CodeGen;
+/// Push an entry of the given size onto this protected-scope stack.
+char *EHScopeStack::allocate(size_t Size) {
+ if (!StartOfBuffer) {
+ unsigned Capacity = 1024;
+ while (Capacity < Size) Capacity *= 2;
+ StartOfBuffer = new char[Capacity];
+ StartOfData = EndOfBuffer = StartOfBuffer + Capacity;
+ } else if (static_cast<size_t>(StartOfData - StartOfBuffer) < Size) {
+ unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer;
+ unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer);
+
+ unsigned NewCapacity = CurrentCapacity;
+ do {
+ NewCapacity *= 2;
+ } while (NewCapacity < UsedCapacity + Size);
+
+ char *NewStartOfBuffer = new char[NewCapacity];
+ char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity;
+ char *NewStartOfData = NewEndOfBuffer - UsedCapacity;
+ memcpy(NewStartOfData, StartOfData, UsedCapacity);
+ delete [] StartOfBuffer;
+ StartOfBuffer = NewStartOfBuffer;
+ EndOfBuffer = NewEndOfBuffer;
+ StartOfData = NewStartOfData;
+ }
+
+ assert(StartOfBuffer + Size <= StartOfData);
+ StartOfData -= Size;
+ return StartOfData;
+}
+
+EHScopeStack::stable_iterator
+EHScopeStack::getEnclosingEHCleanup(iterator it) const {
+ assert(it != end());
+ do {
+ if (isa<EHCleanupScope>(*it)) {
+ if (cast<EHCleanupScope>(*it).isEHCleanup())
+ return stabilize(it);
+ return cast<EHCleanupScope>(*it).getEnclosingEHCleanup();
+ }
+ ++it;
+ } while (it != end());
+ return stable_end();
+}
+
+
+void EHScopeStack::pushCleanup(llvm::BasicBlock *NormalEntry,
+ llvm::BasicBlock *NormalExit,
+ llvm::BasicBlock *EHEntry,
+ llvm::BasicBlock *EHExit) {
+ char *Buffer = allocate(EHCleanupScope::getSize());
+ new (Buffer) EHCleanupScope(BranchFixups.size(),
+ InnermostNormalCleanup,
+ InnermostEHCleanup,
+ NormalEntry, NormalExit, EHEntry, EHExit);
+ if (NormalEntry)
+ InnermostNormalCleanup = stable_begin();
+ if (EHEntry)
+ InnermostEHCleanup = stable_begin();
+}
+
+void EHScopeStack::popCleanup() {
+ assert(!empty() && "popping exception stack when not empty");
+
+ assert(isa<EHCleanupScope>(*begin()));
+ EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
+ InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
+ InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
+ StartOfData += EHCleanupScope::getSize();
+
+ // Check whether we can shrink the branch-fixups stack.
+ if (!BranchFixups.empty()) {
+ // If we no longer have any normal cleanups, all the fixups are
+ // complete.
+ if (!hasNormalCleanups())
+ BranchFixups.clear();
+
+ // Otherwise we can still trim out unnecessary nulls.
+ else
+ popNullFixups();
+ }
+}
+
+EHFilterScope *EHScopeStack::pushFilter(unsigned NumFilters) {
+ char *Buffer = allocate(EHFilterScope::getSizeForNumFilters(NumFilters));
+ CatchDepth++;
+ return new (Buffer) EHFilterScope(NumFilters);
+}
+
+void EHScopeStack::popFilter() {
+ assert(!empty() && "popping exception stack when not empty");
+
+ EHFilterScope &Filter = cast<EHFilterScope>(*begin());
+ StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters());
+
+ assert(CatchDepth > 0 && "mismatched filter push/pop");
+ CatchDepth--;
+}
+
+EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) {
+ char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers));
+ CatchDepth++;
+ return new (Buffer) EHCatchScope(NumHandlers);
+}
+
+void EHScopeStack::pushTerminate() {
+ char *Buffer = allocate(EHTerminateScope::getSize());
+ CatchDepth++;
+ new (Buffer) EHTerminateScope();
+}
+
+/// Remove any 'null' fixups on the stack. However, we can't pop more
+/// fixups than the fixup depth on the innermost normal cleanup, or
+/// else fixups that we try to add to that cleanup will end up in the
+/// wrong place. We *could* try to shrink fixup depths, but that's
+/// actually a lot of work for little benefit.
+void EHScopeStack::popNullFixups() {
+ // We expect this to only be called when there's still an innermost
+ // normal cleanup; otherwise there really shouldn't be any fixups.
+ assert(hasNormalCleanups());
+
+ EHScopeStack::iterator it = find(InnermostNormalCleanup);
+ unsigned MinSize = cast<EHCleanupScope>(*it).getFixupDepth();
+ assert(BranchFixups.size() >= MinSize && "fixup stack out of order");
+
+ while (BranchFixups.size() > MinSize &&
+ BranchFixups.back().Destination == 0)
+ BranchFixups.pop_back();
+}
+
+void EHScopeStack::resolveBranchFixups(llvm::BasicBlock *Dest) {
+ assert(Dest && "null block passed to resolveBranchFixups");
+
+ if (BranchFixups.empty()) return;
+ assert(hasNormalCleanups() &&
+ "branch fixups exist with no normal cleanups on stack");
+
+ for (unsigned I = 0, E = BranchFixups.size(); I != E; ++I)
+ if (BranchFixups[I].Destination == Dest)
+ BranchFixups[I].Destination = 0;
+
+ popNullFixups();
+}
+
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
@@ -66,8 +213,19 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
}
+static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) {
+ // void *__cxa_get_exception_ptr(void*);
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr");
+}
+
static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
- // void* __cxa_begin_catch();
+ // void *__cxa_begin_catch(void*);
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
std::vector<const llvm::Type*> Args(1, Int8PtrTy);
@@ -123,28 +281,87 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort");
}
-static llvm::Constant *getPersonalityFn(CodeGenModule &CGM) {
- const char *PersonalityFnName = "__gcc_personality_v0";
- LangOptions Opts = CGM.getLangOptions();
- if (Opts.CPlusPlus) {
- if (Opts.SjLjExceptions)
- PersonalityFnName = "__gxx_personality_sj0";
+static const char *getCPersonalityFn(CodeGenFunction &CGF) {
+ return "__gcc_personality_v0";
+}
+
+static const char *getObjCPersonalityFn(CodeGenFunction &CGF) {
+ if (CGF.CGM.getLangOptions().NeXTRuntime) {
+ if (CGF.CGM.getLangOptions().ObjCNonFragileABI)
+ return "__objc_personality_v0";
+ else
+ return getCPersonalityFn(CGF);
+ } else {
+ return "__gnu_objc_personality_v0";
+ }
+}
+
+static const char *getCXXPersonalityFn(CodeGenFunction &CGF) {
+ if (CGF.CGM.getLangOptions().SjLjExceptions)
+ return "__gxx_personality_sj0";
+ else
+ return "__gxx_personality_v0";
+}
+
+/// Determines the personality function to use when both C++
+/// and Objective-C exceptions are being caught.
+static const char *getObjCXXPersonalityFn(CodeGenFunction &CGF) {
+ // The ObjC personality defers to the C++ personality for non-ObjC
+ // handlers. Unlike the C++ case, we use the same personality
+ // function on targets using (backend-driven) SJLJ EH.
+ if (CGF.CGM.getLangOptions().NeXTRuntime) {
+ if (CGF.CGM.getLangOptions().ObjCNonFragileABI)
+ return "__objc_personality_v0";
+
+ // In the fragile ABI, just use C++ exception handling and hope
+ // they're not doing crazy exception mixing.
else
- PersonalityFnName = "__gxx_personality_v0";
- } else if (Opts.ObjC1) {
- if (Opts.NeXTRuntime) {
- if (Opts.ObjCNonFragileABI)
- PersonalityFnName = "__gcc_personality_v0";
- } else
- PersonalityFnName = "__gnu_objc_personality_v0";
+ return getCXXPersonalityFn(CGF);
}
+ // I'm pretty sure the GNU runtime doesn't support mixed EH.
+ // TODO: we don't necessarily need mixed EH here; remember what
+ // kind of exceptions we actually try to catch in this function.
+ CGF.CGM.ErrorUnsupported(CGF.CurCodeDecl,
+ "the GNU Objective C runtime does not support "
+ "catching C++ and Objective C exceptions in the "
+ "same function");
+ // Use the C++ personality just to avoid returning null.
+ return getCXXPersonalityFn(CGF);
+}
+
+static llvm::Constant *getPersonalityFn(CodeGenFunction &CGF) {
+ const char *Name;
+ const LangOptions &Opts = CGF.CGM.getLangOptions();
+ if (Opts.CPlusPlus && Opts.ObjC1)
+ Name = getObjCXXPersonalityFn(CGF);
+ else if (Opts.CPlusPlus)
+ Name = getCXXPersonalityFn(CGF);
+ else if (Opts.ObjC1)
+ Name = getObjCPersonalityFn(CGF);
+ else
+ Name = getCPersonalityFn(CGF);
+
llvm::Constant *Personality =
- CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty(
- CGM.getLLVMContext()),
- true),
- PersonalityFnName);
- return llvm::ConstantExpr::getBitCast(Personality, CGM.PtrToInt8Ty);
+ CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(
+ llvm::Type::getInt32Ty(
+ CGF.CGM.getLLVMContext()),
+ true),
+ Name);
+ return llvm::ConstantExpr::getBitCast(Personality, CGF.CGM.PtrToInt8Ty);
+}
+
+/// Returns the value to inject into a selector to indicate the
+/// presence of a catch-all.
+static llvm::Constant *getCatchAllValue(CodeGenFunction &CGF) {
+ // Possibly we should use @llvm.eh.catch.all.value here.
+ return llvm::ConstantPointerNull::get(CGF.CGM.PtrToInt8Ty);
+}
+
+/// Returns the value to inject into a selector to indicate the
+/// presence of a cleanup.