From: John McCall Date: Fri, 24 Jun 2011 23:21:27 +0000 (+0000) Subject: Honor objc_precise_lifetime in GC mode by feeding the value X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0c24c808e4dce43e88abf2d5f98546b901bd4315;p=clang Honor objc_precise_lifetime in GC mode by feeding the value 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 --- diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index b6ad130a40..7e126d95e1 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -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(&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()) { + EHStack.pushCleanup(NormalCleanup, &D); + } + // Handle the cleanup attribute. if (const CleanupAttr *CA = D.getAttr()) { const FunctionDecl *FD = CA->getFunctionDecl(); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 9107e9859e..62ee03c089 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -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() {} diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index fea2e6111a..717f319fd3 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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,