gnustep-dev
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]