]> granicus.if.org Git - clang/commitdiff
Honor objc_precise_lifetime in GC mode by feeding the value
authorJohn McCall <rjmccall@apple.com>
Fri, 24 Jun 2011 23:21:27 +0000 (23:21 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 24 Jun 2011 23:21:27 +0000 (23:21 +0000)
in the variable to an inline asm which gets run when the variable
goes out of scope.

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

lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CodeGenFunction.h

index b6ad130a4039e1d7eaef885c6b302340562b3337..7e126d95e18a15634413391e52036e221030d1ac 100644 (file)
@@ -364,6 +364,20 @@ namespace {
     }
   };
 
+  struct ExtendGCLifetime : EHScopeStack::Cleanup {
+    const VarDecl &Var;
+    ExtendGCLifetime(const VarDecl *var) : Var(*var) {}
+
+    void Emit(CodeGenFunction &CGF, bool forEH) {
+      // Compute the address of the local variable, in case it's a
+      // byref or something.
+      DeclRefExpr DRE(const_cast<VarDecl*>(&Var), Var.getType(), VK_LValue,
+                      SourceLocation());
+      llvm::Value *value = CGF.EmitLoadOfScalar(CGF.EmitDeclRefLValue(&DRE));
+      CGF.EmitExtendGCLifetime(value);
+    }
+  };
+
   struct CallCleanupFunction : EHScopeStack::Cleanup {
     llvm::Constant *CleanupFn;
     const CGFunctionInfo &FnInfo;
@@ -1029,6 +1043,12 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
     }
   }
 
+  // In GC mode, honor objc_precise_lifetime.
+  if (getLangOptions().getGCMode() != LangOptions::NonGC &&
+      D.hasAttr<ObjCPreciseLifetimeAttr>()) {
+    EHStack.pushCleanup<ExtendGCLifetime>(NormalCleanup, &D);
+  }
+
   // Handle the cleanup attribute.
   if (const CleanupAttr *CA = D.getAttr<CleanupAttr>()) {
     const FunctionDecl *FD = CA->getFunctionDecl();
index 9107e9859e5f56b874c3ec2f246cbf2bb2acf681..62ee03c089f91fc657b9dd0c2d6a0dd017227e71 100644 (file)
@@ -2484,4 +2484,22 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
     DI->EmitRegionEnd(Builder);
   }
 }
+
+/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+/// make sure it survives garbage collection until this point.
+void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
+  // We just use an inline assembly.
+  const llvm::Type *paramTypes[] = { VoidPtrTy };
+  llvm::FunctionType *extenderType
+    = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false);
+  llvm::Value *extender
+    = llvm::InlineAsm::get(extenderType,
+                           /* assembly */ "",
+                           /* constraints */ "r",
+                           /* side effects */ true);
+
+  object = Builder.CreateBitCast(object, VoidPtrTy);
+  Builder.CreateCall(extender, object)->setDoesNotThrow();
+}
+
 CGObjCRuntime::~CGObjCRuntime() {}
index fea2e6111a38fcf67ae1667c127e7a01b60012fb..717f319fd35f36cf960f7e253844fa0aa8f966a4 100644 (file)
@@ -2146,6 +2146,10 @@ public:
   void EmitGCMemmoveCollectable(llvm::Value *DestPtr, llvm::Value *SrcPtr,
                                 QualType Ty);
 
+  /// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
+  /// make sure it survives garbage collection until this point.
+  void EmitExtendGCLifetime(llvm::Value *object);
+
   /// EmitComplexExpr - Emit the computation of the specified expression of
   /// complex type, returning the result.
   ComplexPairTy EmitComplexExpr(const Expr *E,