From 8ecbaf25c1373be6fb5a9d332b08b6be16d9fd4e Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Tue, 24 Feb 2009 07:47:38 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65378 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCMac.cpp | 139 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 134 insertions(+), 5 deletions(-) diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 021fe15483..a9cb833c73 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -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 @@ public: // 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 @@ public: } 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 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul 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 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, return; } +void +CGObjCNonFragileABIMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const Stmt &S) { + // We don't handle anything interesting yet. + if (const ObjCAtTryStmt *TS = dyn_cast(&S)) + if (TS->getCatchStmts()) + return CGF.ErrorUnsupported(&S, "try (with catch) statement"); + + bool isTry = isa(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(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(S).getTryBody() + : cast(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(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 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(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) { -- 2.40.0