]> granicus.if.org Git - clang/commitdiff
Start implementing support for @synchonized with the darwin ObjC API.
authorChris Lattner <sabre@nondot.org>
Sat, 15 Nov 2008 21:26:17 +0000 (21:26 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 15 Nov 2008 21:26:17 +0000 (21:26 +0000)
Patch by Fariborz!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59377 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGObjC.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/CodeGen/CGObjCMac.cpp
lib/CodeGen/CGObjCRuntime.h
lib/CodeGen/CGStmt.cpp
lib/CodeGen/CodeGenFunction.h

index 3ffdb4d8667d689b1ae14e0980092d5a5f604d72..058278cfa4ea67040750921c4f23364719dcec78 100644 (file)
@@ -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() {}
index 4afbf3c2fb4ee943b25182696729714efcbd4c34..4726be2115159f5a3cb4ef300615d6a3354d970e 100644 (file)
@@ -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);
 }
index 70b9b49f7dda23071bd78e5487d197aea19c79ca..296b1af5518d6f7f23e421163b6b3103df90461a 100644 (file)
@@ -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));
index d690289f140b4b01fd50f6932d23e86ac6cecca3..435e1483e386f33ade59c87172c26460aa13b0a7 100644 (file)
@@ -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.  
index 767e275d2d224f9b59225f889c731f6efcee61a1..3f2cd803dab313f5f0521e3871ace8e18e314e13 100644 (file)
@@ -92,7 +92,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
     EmitObjCAtThrowStmt(cast<ObjCAtThrowStmt>(*S));
     break;
   case Stmt::ObjCAtSynchronizedStmtClass:
-    ErrorUnsupported(S, "@synchronized statement");
+    EmitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(*S));
     break;
   case Stmt::ObjCForCollectionStmtClass: 
     EmitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(*S));
index 50b35bd8cdbc971286cb40064f9cea7296b44e5d..5d99dba69a8cb1ab903fdec5904fcd1351b457f7 100644 (file)
@@ -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