[cfe-commits] r115575 - in /cfe/trunk: lib/CodeGen/CGObjCMac.cpp test/CodeGenObjC/exceptions.m

John McCall rjmccall at apple.com
Mon Oct 4 16:42:51 PDT 2010


Author: rjmccall
Date: Mon Oct  4 18:42:51 2010
New Revision: 115575

URL: http://llvm.org/viewvc/llvm-project?rev=115575&view=rev
Log:
In the fragile ObjC ABI, save the caught exception to the side if there are
both @catches and a @finally, because the second call to @objc_exception_try_enter
will clobber the exception slot.  Fixes rdar://problem/8440970.


Modified:
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp
    cfe/trunk/test/CodeGenObjC/exceptions.m

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=115575&r1=115574&r2=115575&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Mon Oct  4 18:42:51 2010
@@ -2973,6 +2973,10 @@
   llvm::Value *CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
                                                      "_call_try_exit");
 
+  // A slot containing the exception to rethrow.  Only needed when we
+  // have both a @catch and a @finally.
+  llvm::Value *PropagatingExnVar = 0;
+
   // Push a normal cleanup to leave the try scope.
   CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalCleanup, &S,
                                                  SyncArgSlot,
@@ -3044,6 +3048,12 @@
     llvm::BasicBlock *CatchBlock = 0;
     llvm::BasicBlock *CatchHandler = 0;
     if (HasFinally) {
+      // Save the currently-propagating exception before
+      // objc_exception_try_enter clears the exception slot.
+      PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
+                                               "propagating_exception");
+      CGF.Builder.CreateStore(Caught, PropagatingExnVar);
+
       // Enter a new exception try block (in case a @catch block
       // throws an exception).
       CGF.Builder.CreateCall(ObjCTypes.getExceptionTryEnterFn(), ExceptionData)
@@ -3178,6 +3188,15 @@
       // the try's write hazard and here.
       //Hazards.emitWriteHazard();
 
+      // Extract the new exception and save it to the
+      // propagating-exception slot.
+      assert(PropagatingExnVar);
+      llvm::CallInst *NewCaught =
+        CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
+                               ExceptionData, "caught");
+      NewCaught->setDoesNotThrow();
+      CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
+
       // Don't pop the catch handler; the throw already did.
       CGF.Builder.CreateStore(CGF.Builder.getFalse(), CallTryExitVar);
       CGF.EmitBranchThroughCleanup(FinallyRethrow);
@@ -3198,13 +3217,21 @@
   CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
   CGF.EmitBlock(FinallyRethrow.getBlock(), true);
   if (CGF.HaveInsertPoint()) {
-    // Just look in the buffer for the exception to throw.
-    llvm::CallInst *Caught =
-      CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
-                             ExceptionData);
-    Caught->setDoesNotThrow();
+    // If we have a propagating-exception variable, check it.
+    llvm::Value *PropagatingExn;
+    if (PropagatingExnVar) {
+      PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
+
+    // Otherwise, just look in the buffer for the exception to throw.
+    } else {
+      llvm::CallInst *Caught =
+        CGF.Builder.CreateCall(ObjCTypes.getExceptionExtractFn(),
+                               ExceptionData);
+      Caught->setDoesNotThrow();
+      PropagatingExn = Caught;
+    }
 
-    CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), Caught)
+    CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(), PropagatingExn)
       ->setDoesNotThrow();
     CGF.Builder.CreateUnreachable();
   }

Modified: cfe/trunk/test/CodeGenObjC/exceptions.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/exceptions.m?rev=115575&r1=115574&r2=115575&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/exceptions.m (original)
+++ cfe/trunk/test/CodeGenObjC/exceptions.m Mon Oct  4 18:42:51 2010
@@ -133,3 +133,59 @@
   // CHECK-NEXT: ret void
   f3_helper(4, &x);
 }
+
+// rdar://problem/8440970
+void f4() {
+  extern void f4_help(int);
+
+  // CHECK: define void @f4()
+  // CHECK:      [[EXNDATA:%.*]] = alloca [[EXNDATA_T:%.*]], align
+  // CHECK:      call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
+  // CHECK:      call i32 @_setjmp
+  @try {
+  // CHECK:      call void @f4_help(i32 0)
+    f4_help(0);
+
+  // The finally cleanup has two threaded entrypoints after optimization:
+
+  // finally.no-call-exit:  Predecessor is when the catch throws.
+  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
+  // CHECK-NEXT: call void @f4_help(i32 2)
+  // CHECK-NEXT: br label
+  //   -> rethrow
+
+  // finally.call-exit:  Predecessors are the @try and @catch fallthroughs
+  // as well as the no-match case in the catch mechanism.  The i1 is whether
+  // to rethrow and should be true only in the last case.
+  // CHECK:      phi i1
+  // CHECK-NEXT: phi i8*
+  // CHECK-NEXT: call void @objc_exception_try_exit([[EXNDATA_T]]* [[EXNDATA]])
+  // CHECK-NEXT: call void @f4_help(i32 2)
+  // CHECK-NEXT: br i1
+  //   -> ret, rethrow
+
+  // ret:
+  // CHECK:      ret void
+
+  // Catch mechanism:
+  // CHECK:      call i8* @objc_exception_extract([[EXNDATA_T]]* [[EXNDATA]])
+  // CHECK-NEXT: call void @objc_exception_try_enter([[EXNDATA_T]]* [[EXNDATA]])
+  // CHECK:      call i32 @_setjmp
+  //   -> next, finally.no-call-exit
+  // CHECK:      call i32 @objc_exception_match
+  //   -> finally.call-exit, match
+  } @catch (NSArray *a) {
+  // match:
+  // CHECK:      call void @f4_help(i32 1)
+  // CHECK-NEXT: br label
+  //   -> finally.call-exit
+    f4_help(1);
+  } @finally {
+    f4_help(2);
+  }
+
+  // rethrow:
+  // CHECK:      phi i8*
+  // CHECK-NEXT: call void @objc_exception_throw(i8*
+  // CHECK-NEXT: unreachable
+}





More information about the cfe-commits mailing list