[cfe-commits] r56763 - in /cfe/trunk/lib/CodeGen: CGObjCMac.cpp CodeGenFunction.h
Daniel Dunbar
daniel at zuster.org
Sat Sep 27 18:03:16 PDT 2008
Author: ddunbar
Date: Sat Sep 27 20:03:14 2008
New Revision: 56763
URL: http://llvm.org/viewvc/llvm-project?rev=56763&view=rev
Log:
Add support for implicit rethrows in @catch blocks.
Comment exception-handling code generation strategy.
Modified:
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=56763&r1=56762&r2=56763&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Sat Sep 27 20:03:14 2008
@@ -1383,6 +1383,75 @@
return ObjCTypes.EnumerationMutationFn;
}
+/*
+
+Objective-C setjmp-longjmp (sjlj) Exception Handling
+--
+
+The basic framework for a @try-catch-finally is as follows:
+{
+ objc_exception_data d;
+ id _rethrow = null;
+
+ objc_exception_try_enter(&d);
+ if (!setjmp(d.jmp_buf)) {
+ ... try body ...
+ } else {
+ // exception path
+ id _caught = objc_exception_extract(&d);
+
+ // enter new try scope for handlers
+ if (!setjmp(d.jmp_buf)) {
+ ... match exception and execute catch blocks ...
+
+ // fell off end, rethrow.
+ _rethrow = _caught;
+ } else {
+ // exception in catch block
+ _rethrow = objc_exception_extract(&d);
+ goto finally_no_exit;
+ }
+ }
+
+finally:
+ // match either the initial try_enter or the catch try_enter,
+ // depending on the path followed.
+ objc_exception_try_exit(&d);
+finally_no_exit:
+ ... finally block ....
+ if (_rethrow)
+ objc_exception_throw(_rethrow);
+}
+
+This framework differs slightly from the one gcc uses, in that gcc
+uses _rethrow to determine if objc_exception_try_exit should be
+called. This breaks in the face of throwing nil and introduces an
+unnecessary branch. Note that our framework still does not properly
+handle throwing nil, as a nil object will not be rethrown.
+
+FIXME: Determine if _rethrow should be integrated into the other
+architecture for selecting paths out of the finally block.
+
+We specialize this framework for a few particular circumstances:
+
+ - If there are no catch blocks, then we avoid emitting the second
+ exception handling context.
+
+ - If there is a catch-all catch block (i.e. @catch(...) or @catch(id
+ e)) we avoid emitting the code to rethrow an uncaught exception.
+
+ - FIXME: If there is no @finally block we can do a few more
+ simplifications.
+
+Rethrows and Jumps-Through-Finally
+--
+
+Support for implicit rethrows and jumping through the finally block is
+handled by storing the current exception-handling context in
+ObjCEHStack.
+
+*/
+
void CGObjCMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtTryStmt &S)
{
@@ -1413,6 +1482,10 @@
CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNonNull(SetJmpResult, "threw"),
TryHandler, TryBlock);
+ // Push an EH context entry for use by rethrow and
+ // jumps-through-finally.
+ CGF.ObjCEHStack.push_back(CodeGenFunction::ObjCEHEntry(FinallyBlock));
+
// Emit the @try block.
CGF.EmitBlock(TryBlock);
CGF.EmitStmt(S.getTryBody());
@@ -1426,6 +1499,7 @@
llvm::Value *Caught = CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn,
ExceptionData,
"caught");
+ CGF.ObjCEHStack.back().Exception = Caught;
if (const ObjCAtCatchStmt* CatchStmt = S.getCatchStmts()) {
// Enter a new exception try block (in case a @catch block throws
// an exception).
@@ -1497,14 +1571,12 @@
// Emit the @catch block.
CGF.EmitBlock(MatchedBlock);
- if (CatchParam) {
- CGF.EmitStmt(CatchParam);
-
- llvm::Value *Tmp =
- CGF.Builder.CreateBitCast(Caught, CGF.ConvertType(VD->getType()),
- "tmp");
- CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(VD));
- }
+ CGF.EmitStmt(CatchParam);
+
+ llvm::Value *Tmp =
+ CGF.Builder.CreateBitCast(Caught, CGF.ConvertType(VD->getType()),
+ "tmp");
+ CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(VD));
CGF.EmitStmt(CatchStmt->getCatchBody());
CGF.Builder.CreateBr(FinallyBlock);
@@ -1551,6 +1623,8 @@
CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, Rethrow);
CGF.Builder.CreateUnreachable();
+ CGF.ObjCEHStack.pop_back();
+
CGF.EmitBlock(FinallyEndBlock);
}
@@ -1564,7 +1638,9 @@
ExceptionAsObject =
CGF.Builder.CreateBitCast(Exception, ObjCTypes.ObjectPtrTy, "tmp");
} else {
- assert(0 && "FIXME: rethrows not supported!");
+ assert((!CGF.ObjCEHStack.empty() && CGF.ObjCEHStack.back().Exception) &&
+ "Unexpected rethrow outside @catch block.");
+ ExceptionAsObject = CGF.ObjCEHStack.back().Exception;
}
CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, ExceptionAsObject);
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=56763&r1=56762&r2=56763&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Sat Sep 27 20:03:14 2008
@@ -79,6 +79,22 @@
const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth;
+
+public:
+ // FIXME: The following should be private once EH code is moved out
+ // of NeXT runtime.
+
+ // ObjCEHStack - This keeps track of which object to rethrow from
+ // inside @catch blocks and which @finally block exits from an EH
+ // scope should be chained through.
+ struct ObjCEHEntry {
+ ObjCEHEntry(llvm::BasicBlock *fb)
+ : Exception(0), FinallyBlock(fb) {}
+
+ llvm::Value *Exception;
+ llvm::BasicBlock *FinallyBlock;
+ };
+ llvm::SmallVector<ObjCEHEntry, 8> ObjCEHStack;
private:
/// LabelIDs - Track arbitrary ids assigned to labels for use in
@@ -108,7 +124,7 @@
llvm::BasicBlock *ContinueBlock;
};
llvm::SmallVector<BreakContinue, 8> BreakContinueStack;
-
+
/// SwitchInsn - This is nearest current switch instruction. It is null if
/// if current context is not in a switch.
llvm::SwitchInst *SwitchInsn;
More information about the cfe-commits
mailing list