[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