From: Chris Lattner Date: Sat, 15 Nov 2008 21:26:17 +0000 (+0000) Subject: Start implementing support for @synchonized with the darwin ObjC API. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=10cac6f7115b59a466bb8d2d51cdddeb38aadc37;p=clang Start implementing support for @synchonized with the darwin ObjC API. Patch by Fariborz! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59377 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 3ffdb4d866..058278cfa4 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -533,4 +533,10 @@ void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) CGM.getObjCRuntime().EmitThrowStmt(*this, S); } +void CodeGenFunction::EmitObjCAtSynchronizedStmt( + const ObjCAtSynchronizedStmt &S) +{ + CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S); +} + CGObjCRuntime::~CGObjCRuntime() {} diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 4afbf3c2fb..4726be2115 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -128,6 +128,8 @@ public: const ObjCAtTryStmt &S); virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S); + virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S); }; } // end anonymous namespace @@ -961,6 +963,11 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, CGF.ErrorUnsupported(&S, "@throw statement"); } +void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S) { + CGF.ErrorUnsupported(&S, "@synchronized statement"); +} + CodeGen::CGObjCRuntime *CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM){ return new CGObjCGNU(CGM); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 70b9b49f7d..296b1af551 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -155,7 +155,13 @@ public: /// SetJmpFn - LLVM _setjmp function. llvm::Function *SetJmpFn; - + + /// SyncEnterFn - LLVM object_sync_enter function. + llvm::Function *SyncEnterFn; + + /// SyncExitFn - LLVM object_sync_exit function. + llvm::Function *SyncExitFn; + public: ObjCTypesHelper(CodeGen::CodeGenModule &cgm); ~ObjCTypesHelper(); @@ -430,6 +436,8 @@ public: const ObjCAtTryStmt &S); virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S); + virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S); }; } // end anonymous namespace @@ -1751,6 +1759,96 @@ void CodeGenFunction::EmitJumpThroughFinally(ObjCEHEntry *E, EmitBranch(ExecuteTryExit ? E->FinallyBlock : E->FinallyNoExit); } +/// EmitSynchronizedStmt - Code gen for @synchronized(expr) stmt; +/// Effectively generating code for: +/// objc_sync_enter(expr); +/// @try stmt @finally { objc_sync_exit(expr); } +void CGObjCMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S) { + // Create various blocks we refer to for handling @finally. + llvm::BasicBlock *FinallyBlock = CGF.createBasicBlock("finally"); + llvm::BasicBlock *FinallyNoExit = CGF.createBasicBlock("finally.noexit"); + llvm::BasicBlock *FinallyRethrow = CGF.createBasicBlock("finally.throw"); + llvm::BasicBlock *FinallyEnd = CGF.createBasicBlock("finally.end"); + llvm::Value *DestCode = + CGF.CreateTempAlloca(llvm::Type::Int32Ty, "finally.dst"); + + // Generate jump code. Done here so we can directly add things to + // the switch instruction. + llvm::BasicBlock *FinallyJump = CGF.createBasicBlock("finally.jump"); + llvm::SwitchInst *FinallySwitch = + llvm::SwitchInst::Create(new llvm::LoadInst(DestCode, "", FinallyJump), + FinallyEnd, 10, FinallyJump); + + // Push an EH context entry, used for handling rethrows and jumps + // through finally. + CodeGenFunction::ObjCEHEntry EHEntry(FinallyBlock, FinallyNoExit, + FinallySwitch, DestCode); + CGF.ObjCEHStack.push_back(&EHEntry); + + // Allocate memory for the exception data and rethrow pointer. + llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy, + "exceptiondata.ptr"); + llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy, + "_rethrow"); + // Call objc_sync_enter(sync.expr) + CGF.Builder.CreateCall(ObjCTypes.SyncEnterFn, + CGF.EmitScalarExpr(S.getSynchExpr())); + + // Enter a new try block and call setjmp. + CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData); + llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0, + "jmpbufarray"); + JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp"); + llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.SetJmpFn, + JmpBufPtr, "result"); + + llvm::BasicBlock *TryBlock = CGF.createBasicBlock("try"); + llvm::BasicBlock *TryHandler = CGF.createBasicBlock("try.handler"); + CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNotNull(SetJmpResult, "threw"), + TryHandler, TryBlock); + + // Emit the @try block. + CGF.EmitBlock(TryBlock); + CGF.EmitStmt(S.getSynchBody()); + CGF.EmitJumpThroughFinally(&EHEntry, FinallyEnd); + + // Emit the "exception in @try" block. + CGF.EmitBlock(TryHandler); + + // Retrieve the exception object. We may emit multiple blocks but + // nothing can cross this so the value is already in SSA form. + llvm::Value *Caught = CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn, + ExceptionData, + "caught"); + EHEntry.Exception = Caught; + CGF.Builder.CreateStore(Caught, RethrowPtr); + CGF.EmitJumpThroughFinally(&EHEntry, FinallyRethrow, false); + + // Pop the exception-handling stack entry. It is important to do + // this now, because the code in the @finally block is not in this + // context. + CGF.ObjCEHStack.pop_back(); + + // Emit the @finally block. + CGF.EmitBlock(FinallyBlock); + CGF.Builder.CreateCall(ObjCTypes.ExceptionTryExitFn, ExceptionData); + + CGF.EmitBlock(FinallyNoExit); + // objc_sync_exit(expr); As finally's sole statement. + CGF.Builder.CreateCall(ObjCTypes.SyncExitFn, + CGF.EmitScalarExpr(S.getSynchExpr())); + + CGF.EmitBlock(FinallyJump); + + CGF.EmitBlock(FinallyRethrow); + CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, + CGF.Builder.CreateLoad(RethrowPtr)); + CGF.Builder.CreateUnreachable(); + + CGF.EmitBlock(FinallyEnd); +} + /* *** Private Interface *** */ /// EmitImageInfo - Emit the image info marker used to encode some module @@ -2415,6 +2513,23 @@ ObjCTypesHelper::ObjCTypesHelper(CodeGen::CodeGenModule &cgm) Params, false), "objc_exception_match"); + + // synchronized APIs + // void objc_sync_enter (id) + Params.clear(); + Params.push_back(ObjectPtrTy); + SyncEnterFn = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + Params, + false), + "objc_sync_enter"); + // void objc_sync_exit (id) + SyncExitFn = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::VoidTy, + Params, + false), + "objc_sync_exit"); + Params.clear(); Params.push_back(llvm::PointerType::getUnqual(llvm::Type::Int32Ty)); diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index d690289f14..435e1483e3 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -38,6 +38,7 @@ namespace CodeGen { class ObjCAtTryStmt; class ObjCAtThrowStmt; + class ObjCAtSynchronizedStmt; class ObjCCategoryImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; @@ -142,6 +143,8 @@ public: const ObjCAtTryStmt &S) = 0; virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S) = 0; + virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S) = 0; }; /// Creates an instance of an Objective-C runtime class. diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 767e275d2d..3f2cd803da 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -92,7 +92,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { EmitObjCAtThrowStmt(cast(*S)); break; case Stmt::ObjCAtSynchronizedStmtClass: - ErrorUnsupported(S, "@synchronized statement"); + EmitObjCAtSynchronizedStmt(cast(*S)); break; case Stmt::ObjCForCollectionStmtClass: EmitObjCForCollectionStmt(cast(*S)); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 50b35bd8cd..5d99dba69a 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -401,6 +401,7 @@ public: void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); + void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); //===--------------------------------------------------------------------===// // LValue Expression Emission