[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Implementation of CFBridgingRelease() on GNUstep
From: |
David Chisnall |
Subject: |
Re: Implementation of CFBridgingRelease() on GNUstep |
Date: |
Thu, 1 Jun 2017 18:29:31 +0100 |
On 1 Jun 2017, at 17:49, Daniel Ferreira (theiostream) <address@hidden> wrote:
>
> CFBridgingRetain() and CFBridgingRelease() should to exactly what the
> __bridge_retained and __bridge_transfer compiler directives do, so an
> insight on how the libobjc2 ARC runtime handles this case will
> probably give us an answer.
>
> However, according to Mike Ash[1] in an article from 2011 on the dawn of ARC,
>
>> CFStringRef valueCF = CFPreferencesCopyAppValue(CFSTR("someKey"),
>> CFSTR("com.company.someapp"));
>> NSString *value = (__bridge NSString *)valueCF;
>> CFRelease(valueCF);
>> [self useValue: value];
>
> is functionally equivalent to:
>
>> NSString *value =
>> CFBridgingRelease(CFPreferencesCopyAppValue(CFSTR("someKey"),
>> CFSTR("com.company.someapp")));
>> [self useValue: value];
>
> So it seems to me logically that the behavior of CFBridgingRelease()
> should be that of reducing the reference count of the object but not
> deallocate it if it reaches zero, assuming ARC will immediately add
> one to the reference count when the CF type becomes an Objective-C
> object.
>
> As for CFBridgingRetain(), the same effect will be attained anyway if
> we CFRetain() when ARC releases everything on ObjC-land, but I wonder
> if it should do anything else.
>
> [1]:
> https://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html
You can see what any of these do by looking at the LLVM IR generated by clang:
$ cat arc.m
void* bridge(id x)
{
return (__bridge void*)x;
}
id bridge_back(void *x)
{
return (__bridge id)x;
}
void* bridge_retained(id x)
{
return (__bridge_retained void*)x;
}
id bridge_retained_back(void *x)
{
return (__bridge_transfer id)x;
}
$ clang -S -emit-llvm -fobjc-arc -o - arc.m -O2
define i8* @bridge(i8*) local_unnamed_addr #0 {
ret i8* %0
}
define i8* @bridge_back(i8*) local_unnamed_addr #0 {
%2 = tail call i8* @objc_retain(i8* %0) #2
%3 = tail call i8* @objc_autoreleaseReturnValue(i8* %0) #2
ret i8* %0
}
define i8* @bridge_retained(i8*) local_unnamed_addr #0 {
%2 = tail call i8* @objc_retain(i8* %0) #2
ret i8* %0
}
define i8* @bridge_retained_back(i8*) local_unnamed_addr #0 {
%2 = tail call i8* @objc_autoreleaseReturnValue(i8* %0) #2
ret i8* %0
}
As you can see, __bridge_retained becomes an objc_retain call, but __bridge is
a no-op, which exists solely for the compiler and static analysers to use to
understand that the programmer didn’t intend an ownership transfer.
In contrast, a __bridge_retained cast does transfer ownership. The recipient
of the void* is responsible for releasing the object. A __bridge_transfer in
the other direction does precisely this. As I understand it,
CFBridgingRelease() is equivalent to __bridge_transfer, and so wants to become
a call to objc_autorelease() (in this example, the transfer happens on the
return value and so the call becomes objc_autoreleaseReturnValue() -
CFBridgingRelease should probably call that directly if it’s a function,
because that will allow the caller to pop it off the autorelease stack if
required). The ownership of the reference is transferred to ARC, but the
reference remains valid.
It absolutely should *NOT* decrement the reference count but not deallocate the
object if it reaches zero!
David