[cfe-commits] r65378 - /cfe/trunk/lib/CodeGen/CGObjCMac.cpp
Daniel Dunbar
daniel at zuster.org
Mon Feb 23 23:47:38 PST 2009
Author: ddunbar
Date: Tue Feb 24 01:47:38 2009
New Revision: 65378
URL: http://llvm.org/viewvc/llvm-project?rev=65378&view=rev
Log:
Some initial Obj-C zero cost EH support.
- Only handles cases with @try with no @catch blocks, and there are a
number of problems with the implementation. Nevertheless, this is
good enough to handled @synchronized correctly, and some other
basic uses.
Modified:
cfe/trunk/lib/CodeGen/CGObjCMac.cpp
Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=65378&r1=65377&r2=65378&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Feb 24 01:47:38 2009
@@ -20,6 +20,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Target/TargetData.h"
@@ -291,7 +292,13 @@
// SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t*
const llvm::Type *SuperMessageRefPtrTy;
-
+
+ /// EHPersonalityPtr - LLVM value for an i8* to the Objective-C
+ /// exception personality function.
+ llvm::Value *EHPersonalityPtr;
+
+ llvm::Function *UnwindResumeOrRethrowFn;
+
ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm);
~ObjCNonFragileABITypesHelper(){}
};
@@ -731,9 +738,7 @@
}
virtual void EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
- const Stmt &S) {
- CGF.ErrorUnsupported(&S, "try or synchronized statement");
- }
+ const Stmt &S);
virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S);
virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
@@ -3340,7 +3345,22 @@
Params,
true),
"objc_msgSendSuper2_stret_fixup");
-
+
+ Params.clear();
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::Int32Ty,
+ Params,
+ true),
+ "__objc_personality_v0");
+ EHPersonalityPtr = llvm::ConstantExpr::getBitCast(Personality, Int8PtrTy);
+
+ Params.clear();
+ Params.push_back(Int8PtrTy);
+ UnwindResumeOrRethrowFn =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy,
+ Params,
+ false),
+ "_Unwind_Resume_or_Rethrow");
}
llvm::Function *CGObjCNonFragileABIMac::ModuleInitFunction() {
@@ -4692,6 +4712,115 @@
return;
}
+void
+CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
+ const Stmt &S) {
+ // We don't handle anything interesting yet.
+ if (const ObjCAtTryStmt *TS = dyn_cast<ObjCAtTryStmt>(&S))
+ if (TS->getCatchStmts())
+ return CGF.ErrorUnsupported(&S, "try (with catch) statement");
+
+ bool isTry = isa<ObjCAtTryStmt>(S);
+ llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try");
+ llvm::BasicBlock *PrevLandingPad = CGF.getInvokeDest();
+ llvm::BasicBlock *LandingPad = CGF.createBasicBlock("try.pad");
+ llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally");
+ llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end");
+
+ // For @synchronized, call objc_sync_enter(sync.expr). The
+ // evaluation of the expression must occur before we enter the
+ // @synchronized. We can safely avoid a temp here because jumps into
+ // @synchronized are illegal & this will dominate uses.
+ llvm::Value *SyncArg = 0;
+ if (!isTry) {
+ SyncArg =
+ CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
+ SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
+ CGF.Builder.CreateCall(ObjCTypes.SyncEnterFn, SyncArg);
+ }
+
+ // Push an EH context entry, used for handling rethrows and jumps
+ // through finally.
+ CGF.PushCleanupBlock(FinallyBlock);
+
+ CGF.setInvokeDest(LandingPad);
+
+ CGF.EmitBlock(TryBlock);
+ CGF.EmitStmt(isTry ? cast<ObjCAtTryStmt>(S).getTryBody()
+ : cast<ObjCAtSynchronizedStmt>(S).getSynchBody());
+ CGF.EmitBranchThroughCleanup(FinallyEnd);
+
+ // Pop the cleanup entry, the @finally is outside this cleanup
+ // scope.
+ CodeGenFunction::CleanupBlockInfo Info = CGF.PopCleanupBlock();
+ CGF.setInvokeDest(PrevLandingPad);
+
+ CGF.EmitBlock(FinallyBlock);
+
+ if (isTry) {
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
+ CGF.EmitStmt(FinallyStmt->getFinallyBody());
+ } else {
+ // Emit 'objc_sync_exit(expr)' as finally's sole statement for
+ // @synchronized.
+ CGF.Builder.CreateCall(ObjCTypes.SyncExitFn, SyncArg);
+ }
+
+ if (Info.SwitchBlock)
+ CGF.EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ CGF.EmitBlock(Info.EndBlock);
+
+ // Branch around the landing pad if necessary.
+ CGF.EmitBranch(FinallyEnd);
+
+ // Emit the landing pad.
+
+ // Clear insertion point to avoid chaining.
+ CGF.Builder.ClearInsertionPoint();
+ CGF.EmitBlock(LandingPad);
+
+ llvm::Value *llvm_eh_exception =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector_i64 =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector_i64);
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+
+ llvm::SmallVector<llvm::Value*, 8> Args;
+ Args.push_back(Exc);
+ Args.push_back(ObjCTypes.EHPersonalityPtr);
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::Int32Ty, 0));
+
+ llvm::Value *Selector =
+ CGF.Builder.CreateCall(llvm_eh_selector_i64, Args.begin(), Args.end());
+
+ // The only valid result for the limited case we are considering is
+ // the cleanup.
+ (void) Selector;
+
+ // Re-emit cleanup code for exceptional case.
+ if (isTry) {
+ // FIXME: This is horrible, in many ways: (a) it is broken because
+ // we are messing with some global data structures (like where
+ // labels point at), (b) it is exponential in the size of code
+ // generated, (c) seriously, its just gross.
+ if (const ObjCAtFinallyStmt* FinallyStmt =
+ cast<ObjCAtTryStmt>(S).getFinallyStmt())
+ CGF.EmitStmt(FinallyStmt->getFinallyBody());
+ } else {
+ // Emit 'objc_sync_exit(expr)' as finally's sole statement for
+ // @synchronized.
+ CGF.Builder.CreateCall(ObjCTypes.SyncExitFn, SyncArg);
+ }
+
+ CGF.EnsureInsertPoint();
+ CGF.Builder.CreateCall(ObjCTypes.UnwindResumeOrRethrowFn, Exc);
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(FinallyEnd);
+}
+
/// EmitThrowStmt - Generate code for a throw statement.
void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
const ObjCAtThrowStmt &S) {
More information about the cfe-commits
mailing list