[cfe-commits] r135764 - in /cfe/trunk: docs/AutomaticReferenceCounting.html include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/AttributeList.h lib/CodeGen/CGObjC.cpp lib/Sema/AttributeList.cpp lib/Sema/SemaDeclAttr.cpp test/CodeGenObjC/arc.m
John McCall
rjmccall at apple.com
Fri Jul 22 01:53:00 PDT 2011
Author: rjmccall
Date: Fri Jul 22 03:53:00 2011
New Revision: 135764
URL: http://llvm.org/viewvc/llvm-project?rev=135764&view=rev
Log:
Document the existing objc_precise_lifetime attribute.
Introduce and document a new objc_returns_inner_pointer
attribute, and consume it by performing a retain+autorelease
on message receivers when they're not immediately loaded from
an object with precise lifetime.
Modified:
cfe/trunk/docs/AutomaticReferenceCounting.html
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/AttributeList.h
cfe/trunk/lib/CodeGen/CGObjC.cpp
cfe/trunk/lib/Sema/AttributeList.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/test/CodeGenObjC/arc.m
Modified: cfe/trunk/docs/AutomaticReferenceCounting.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/AutomaticReferenceCounting.html?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/docs/AutomaticReferenceCounting.html (original)
+++ cfe/trunk/docs/AutomaticReferenceCounting.html Fri Jul 22 03:53:00 2011
@@ -1315,6 +1315,39 @@
<p>The complete optimization rules are quite complicated, but it would
still be useful to document them here.</p>
+<div id="optimization.precise">
+<h1>Precise lifetime semantics</h1>
+
+<p>In general, ARC maintains an invariant that a retainable object
+pointer held in a <tt>__strong</tt> object will be retained for the
+full formal lifetime of the object. Objects subject to this invariant
+have <span class="term">precise lifetime semantics</span>.</p>
+
+<p>By default, local variables of automatic storage duration do not
+have precise lifetime semantics. Such objects are simply strong
+references which hold values of retainable object pointer type, and
+these values are still fully subject to the optimizations on values
+under local control.</p>
+
+<div class="rationale"><p>Rationale: applying these precise-lifetime
+semantics strictly would be prohibitive. Many useful optimizations
+that might theoretically decrease the lifetime of an object would be
+rendered impossible. Essentially, it promises too much.</p></div>
+
+<p>A local variable of retainable object owner type and automatic
+storage duration may be annotated with the <tt>objc_precise_lifetime</tt>
+attribute to indicate that it should be considered to be an object
+with precise lifetime semantics.</p>
+
+<div class="rationale"><p>Rationale: nonetheless, it is sometimes
+useful to be able to force an object to be released at a precise time,
+even if that object does not appear to be used. This is likely to be
+uncommon enough that the syntactic weight of explicitly requesting
+these semantics will not be burdensome, and may even make the code
+clearer.</p></div>
+
+</div> <!-- optimization.precise -->
+
</div>
<div id="misc">
@@ -1562,6 +1595,56 @@
</div> <!-- misc.exceptions -->
+<div id="misc.interior">
+<h1>Interior pointers</h1>
+
+<p>An Objective-C method returning a non-retainable pointer may be
+annotated with the <tt>objc_returns_inner_pointer</tt> attribute to
+indicate that it returns a handle to the internal data of an object,
+and that this reference will be invalidated if the object is
+destroyed. When such a message is sent to an object, the object's
+lifetime will be extended until at least the earliest of:</p>
+
+<ul>
+<li>the last use of the returned pointer, or any pointer derived from
+it, in the calling function or</li>
+<li>the autorelease pool is restored to a previous state.</li>
+</ul>
+
+<div class="rationale"><p>Rationale: not all memory and resources are
+managed with reference counts; it is common for objects to manage
+private resources in their own, private way. Typically these
+resources are completely encapsulated within the object, but some
+classes offer their users direct access for efficiency. If ARC is not
+aware of methods that return such <q>interior</q> pointers, its
+optimizations can cause the owning object to be reclaimed too soon.
+This attribute informs ARC that it must tread lightly.</p>
+
+<p>The extension rules are somewhat intentionally vague. The
+autorelease pool limit is there to permit a simple implementation to
+simply retain and autorelease the receiver. The other limit permits
+some amount of optimization. The phrase <q>derived from</q> is
+intended to encompass the results both of pointer transformations,
+such as casts and arithmetic, and of loading from such derived
+pointers; furthermore, it applies whether or not such derivations are
+applied directly in the calling code or by other utility code (for
+example, the C library routine <tt>strchr</tt>). However, the
+implementation never need account for uses after a return from the
+code which calls the method returning an interior pointer.</p></div>
+
+<p>As an exception, no extension is required if the receiver is loaded
+directly from a <tt>__strong</tt> object
+with <a href="#optimization.precise">precise lifetime semantics</a>.</p>
+
+<div class="rationale"><p>Rationale: implicit autoreleases carry the
+risk of significantly inflating memory use, so it's important to
+provide users a way of avoiding these autoreleases. Tying this to
+precise lifetime semantics is ideal, as for local variables this
+requires a very explicit annotation, which allows ARC to trust the
+user with good cheer.</p></div>
+
+</div> <!-- misc.interior -->
+
</div> <!-- misc -->
<div id="runtime">
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Fri Jul 22 03:53:00 2011
@@ -405,6 +405,11 @@
let Subjects = [Var];
}
+def ObjCReturnsInnerPointer : Attr {
+ let Spellings = ["objc_returns_inner_pointer"];
+ let Subjects = [ObjCMethod];
+}
+
def Overloadable : Attr {
let Spellings = ["overloadable"];
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jul 22 03:53:00 2011
@@ -1413,7 +1413,7 @@
"'overloadable' function %0 must have a prototype">;
def warn_ns_attribute_wrong_return_type : Warning<
"%0 attribute only applies to %select{functions|methods}1 that "
- "return %select{an Objective-C object|a pointer}2">;
+ "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">;
def warn_ns_attribute_wrong_parameter_type : Warning<
"%0 attribute only applies to %select{Objective-C object|pointer}1 "
"parameters">;
Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Fri Jul 22 03:53:00 2011
@@ -215,6 +215,7 @@
AT_objc_method_family,
AT_objc_ownership, // Clang-specific.
AT_objc_precise_lifetime, // Clang-specific.
+ AT_objc_returns_inner_pointer, // Clang-specific.
AT_opencl_image_access, // OpenCL-specific.
AT_opencl_kernel_function, // OpenCL-specific.
AT_overloadable, // Clang-specific.
Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Fri Jul 22 03:53:00 2011
@@ -80,6 +80,53 @@
CGF.ConvertType(E->getType())));
}
+/// Decide whether to extend the lifetime of the receiver of a
+/// returns-inner-pointer message.
+static bool
+shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
+ switch (message->getReceiverKind()) {
+
+ // For a normal instance message, we should extend unless the
+ // receiver is loaded from a variable with precise lifetime.
+ case ObjCMessageExpr::Instance: {
+ const Expr *receiver = message->getInstanceReceiver();
+ const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
+ if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
+ receiver = ice->getSubExpr()->IgnoreParens();
+
+ // Only __strong variables.
+ if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return true;
+
+ // All ivars and fields have precise lifetime.
+ if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver))
+ return false;
+
+ // Otherwise, check for variables.
+ const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr());
+ if (!declRef) return true;
+ const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl());
+ if (!var) return true;
+
+ // All variables have precise lifetime except local variables with
+ // automatic storage duration that aren't specially marked.
+ return (var->hasLocalStorage() &&
+ !var->hasAttr<ObjCPreciseLifetimeAttr>());
+ }
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ // It's never necessary for class objects.
+ return false;
+
+ case ObjCMessageExpr::SuperInstance:
+ // We generally assume that 'self' lives throughout a method call.
+ return false;
+ }
+
+ llvm_unreachable("invalid receiver kind");
+}
+
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
@@ -88,6 +135,8 @@
bool isDelegateInit = E->isDelegateInitCall();
+ const ObjCMethodDecl *method = E->getMethodDecl();
+
// We don't retain the receiver in delegate init calls, and this is
// safe because the receiver value is always loaded from 'self',
// which we zero out. We don't want to Block_copy block receivers,
@@ -95,8 +144,8 @@
bool retainSelf =
(!isDelegateInit &&
CGM.getLangOptions().ObjCAutoRefCount &&
- E->getMethodDecl() &&
- E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>());
+ method &&
+ method->hasAttr<NSConsumesSelfAttr>());
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
@@ -112,8 +161,7 @@
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver());
Receiver = ter.getPointer();
- if (!ter.getInt())
- Receiver = EmitARCRetainNonBlock(Receiver);
+ if (ter.getInt()) retainSelf = false;
} else
Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
@@ -126,9 +174,6 @@
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
@@ -136,9 +181,6 @@
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
case ObjCMessageExpr::SuperClass:
@@ -146,17 +188,25 @@
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
+
+ // In ARC, we sometimes want to "extend the lifetime"
+ // (i.e. retain+autorelease) of receivers of returns-inner-pointer
+ // messages.
+ if (getLangOptions().ObjCAutoRefCount && method &&
+ method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
+ shouldExtendReceiverForInnerPointerMessage(E))
+ Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
+
QualType ResultType =
- E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ method ? method->getResultType() : E->getType();
CallArgList Args;
- EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
+ EmitCallArgs(Args, method, E->arg_begin(), E->arg_end());
// For delegate init calls in ARC, do an unsafe store of null into
// self. This represents the call taking direct ownership of that
@@ -189,12 +239,12 @@
Receiver,
isClassMessage,
Args,
- E->getMethodDecl());
+ method);
} else {
result = Runtime.GenerateMessageSend(*this, Return, ResultType,
E->getSelector(),
Receiver, Args, OID,
- E->getMethodDecl());
+ method);
}
// For delegate init calls in ARC, implicitly store the result of
@@ -213,7 +263,7 @@
Builder.CreateStore(newSelf, selfAddr);
}
- return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
+ return AdjustRelatedResultType(*this, E, method, result);
}
namespace {
Modified: cfe/trunk/lib/Sema/AttributeList.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/AttributeList.cpp?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/AttributeList.cpp (original)
+++ cfe/trunk/lib/Sema/AttributeList.cpp Fri Jul 22 03:53:00 2011
@@ -163,6 +163,7 @@
.Case("vec_type_hint", IgnoredAttribute)
.Case("objc_exception", AT_objc_exception)
.Case("objc_method_family", AT_objc_method_family)
+ .Case("objc_returns_inner_pointer", AT_objc_returns_inner_pointer)
.Case("ext_vector_type", AT_ext_vector_type)
.Case("neon_vector_type", AT_neon_vector_type)
.Case("neon_polyvector_type", AT_neon_polyvector_type)
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri Jul 22 03:53:00 2011
@@ -2767,6 +2767,33 @@
};
}
+static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
+ const AttributeList &attr) {
+ SourceLocation loc = attr.getLoc();
+
+ ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D);
+
+ if (!isa<ObjCMethodDecl>(method)) {
+ S.Diag(method->getLocStart(), diag::err_attribute_wrong_decl_type)
+ << SourceRange(loc, loc) << attr.getName() << 13 /* methods */;
+ return;
+ }
+
+ // Check that the method returns a normal pointer.
+ QualType resultType = method->getResultType();
+ if (!resultType->isPointerType() || resultType->isObjCRetainableType()) {
+ S.Diag(method->getLocStart(), diag::warn_ns_attribute_wrong_return_type)
+ << SourceRange(loc)
+ << attr.getName() << /*method*/ 1 << /*non-retainable pointer*/ 2;
+
+ // Drop the attribute.
+ return;
+ }
+
+ method->addAttr(
+ ::new (S.Context) ObjCReturnsInnerPointerAttr(loc, S.Context));
+}
+
static void handleObjCOwnershipAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (hasDeclarator(D)) return;
@@ -2969,6 +2996,9 @@
case AttributeList::AT_objc_precise_lifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr); break;
+ case AttributeList::AT_objc_returns_inner_pointer:
+ handleObjCReturnsInnerPointerAttr(S, D, Attr); break;
+
// Checker-specific.
case AttributeList::AT_cf_consumed:
case AttributeList::AT_ns_consumed: handleNSConsumedAttr (S, D, Attr); break;
Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=135764&r1=135763&r2=135764&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Fri Jul 22 03:53:00 2011
@@ -1616,3 +1616,53 @@
// CHECK-NEXT: [[T5:%.*]] = load i8** [[T4]]
// CHECK-NEXT: ret i8* [[T5]]
+// rdar://problem/9821110
+ at interface Test58
+- (char*) interior __attribute__((objc_returns_inner_pointer));
+// Should we allow this on properties?
+ at end
+extern Test58 *test58_helper(void);
+
+// CHECK: define void @test58a()
+void test58a(void) {
+ // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
+ // CHECK-NEXT: store [[TEST58]]* [[T3]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
+ // CHECK-NEXT: [[T4:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST58]]* [[T3]] to i8*
+ // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
+ // CHECK-NEXT: store i8* [[T6]], i8**
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind, !clang.imprecise_release
+ // CHECK-NEXT: ret void
+ Test58 *ptr = test58_helper();
+ char *c = [(ptr) interior];
+}
+
+// CHECK: define void @test58b()
+void test58b(void) {
+ // CHECK: [[T0:%.*]] = call [[TEST58:%.*]]* @test58_helper()
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
+ // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST58]]*
+ // CHECK-NEXT: store [[TEST58]]* [[T3]]
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
+ // CHECK-NEXT: [[T1:%.*]] = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_
+ // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
+ // CHECK-NEXT: store i8* [[T3]], i8**
+ // CHECK-NEXT: [[T0:%.*]] = load [[TEST58]]**
+ // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST58]]* [[T0]] to i8*
+ // CHECK-NEXT: call void @objc_release(i8* [[T1]]) nounwind
+ // CHECK-NOT: clang.imprecise_release
+ // CHECK-NEXT: ret void
+ __attribute__((objc_precise_lifetime)) Test58 *ptr = test58_helper();
+ char *c = [ptr interior];
+}
More information about the cfe-commits
mailing list