]> granicus.if.org Git - clang/commitdiff
When initializing thread-safe statics, put the call to
authorDouglas Gregor <dgregor@apple.com>
Sun, 16 May 2010 01:24:12 +0000 (01:24 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 16 May 2010 01:24:12 +0000 (01:24 +0000)
__cxa_guard_abort along the exceptional edge into (in effect) a nested
"try" that rethrows after aborting. Fixes PR7144 and the remaining
Boost.ProgramOptions failures, along with the regressions that r103880
caused.

The crucial difference between this and r103880 is that we now follow
LLVM's little dance with the llvm.eh.exception and llvm.eh.selector
calls, then use _Unwind_Resume_or_Rethrow to rethrow.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103892 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenCXX/threadsafe-statics-exceptions.cpp [new file with mode: 0644]

index 036be9288525c696b32813408939989d2380e8e1..f94ddd988662ba7a1856d245931ef9dd2c960fcf 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "CodeGenFunction.h"
 #include "clang/CodeGen/CodeGenOptions.h"
+#include "llvm/Intrinsics.h"
+
 using namespace clang;
 using namespace CodeGen;
 
@@ -321,7 +323,10 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
 
   EmitBlock(InitCheckBlock);
 
-  if (ThreadsafeStatics) {
+  // 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);
                
@@ -330,14 +335,13 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
     Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"),
                          InitBlock, EndBlock);
   
-    EmitBlock(InitBlock);
-
     if (Exceptions) {
-      EHCleanupBlock Cleanup(*this);
-    
-      // Call __cxa_guard_abort.
-      Builder.CreateCall(getGuardAbortFn(*this), GuardVariable);
+      SavedLandingPad = getInvokeDest();
+      LandingPad = createBasicBlock("guard.lpad");
+      setInvokeDest(LandingPad);
     }
+    
+    EmitBlock(InitBlock);
   }
 
   if (D.getType()->isReferenceType()) {
@@ -353,7 +357,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
 
   if (ThreadsafeStatics) {
     // Call __cxa_guard_release.
-    Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);
+    Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable);    
   } else {
     llvm::Value *One = 
       llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1);
@@ -364,5 +368,57 @@ 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);
 }
index c1d05bf233b2dee1d3e5fdfd2cbdeda4978e23e3..9fa195235ff5df7313b230d8353d91a8fb29d772 100644 (file)
@@ -100,17 +100,17 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) {
   return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected");
 }
 
-static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
-  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() {
+  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
   std::vector<const llvm::Type*> Args(1, Int8PtrTy);
 
   const llvm::FunctionType *FTy =
-    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
+    llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args,
                             false);
 
-  if (CGF.CGM.getLangOptions().SjLjExceptions)
-    return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
-  return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
+  if (CGM.getLangOptions().SjLjExceptions)
+    return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
+  return CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
 }
 
 static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) {
@@ -397,7 +397,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) {
 
   if (Proto->getNumExceptions()) {
     EmitBlock(Unwind);
-    Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+    Builder.CreateCall(getUnwindResumeOrRethrowFn(),
                        Builder.CreateLoad(RethrowPtr));
     Builder.CreateUnreachable();
   }
@@ -631,12 +631,12 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S,
   // here.
   if (getInvokeDest()) {
     llvm::BasicBlock *Cont = createBasicBlock("invoke.cont");
-    Builder.CreateInvoke(getUnwindResumeOrRethrowFn(*this), Cont,
+    Builder.CreateInvoke(getUnwindResumeOrRethrowFn(), Cont,
                          getInvokeDest(),
                          Builder.CreateLoad(RethrowPtr));
     EmitBlock(Cont);
   } else
-    Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+    Builder.CreateCall(getUnwindResumeOrRethrowFn(),
                        Builder.CreateLoad(RethrowPtr));
 
   Builder.CreateUnreachable();
@@ -687,11 +687,11 @@ CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
   // Rethrow the exception.
   if (CGF.getInvokeDest()) {
     llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
-    CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
+    CGF.Builder.CreateInvoke(CGF.getUnwindResumeOrRethrowFn(), Cont,
                              CGF.getInvokeDest(), Exc);
     CGF.EmitBlock(Cont);
   } else
-    CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
+    CGF.Builder.CreateCall(CGF.getUnwindResumeOrRethrowFn(), Exc);
   CGF.Builder.CreateUnreachable();
 
   // Resume inserting where we started, but put the new cleanup
index 151c13c8088f95bdf30931bc9f8d396d0a5283b3..4f85878f0c01a9f0b6035a068ced1ef99a706cd1 100644 (file)
@@ -929,6 +929,7 @@ public:
   void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S);
   void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S);
 
+  llvm::Constant *getUnwindResumeOrRethrowFn();
   struct CXXTryStmtInfo {
     llvm::BasicBlock *SavedLandingPad;
     llvm::BasicBlock *HandlerBlock;
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
new file mode 100644 (file)
index 0000000..9347cc9
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -emit-llvm -o - -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s
+
+struct X {
+  X();
+  ~X();
+};
+
+struct Y { };
+
+// CHECK: define void @_Z1fv
+void f() {
+  // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
+  // CHECK: invoke void @_ZN1XC1Ev
+  // CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
+  // CHECK: call i32 @__cxa_atexit
+  // CHECK: br
+  static X x;
+  // CHECK: call i8* @llvm.eh.exception()
+  // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+  // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
+  // CHECK: call void @_Unwind_Resume_or_Rethrow
+  // CHECK: unreachable
+
+  // CHECK: call i8* @__cxa_allocate_exception
+  throw Y();
+}