The snippet below is taken from Apple's ObjC runtime (libobjc) source code. I wonder what this means exactly. (Not very google-able, sorry)
// HACK -- the use of these functions must be after the @implementation
id bypass_msgSend_retain(NSObject *obj) asm("-[NSObject retain]");
void bypass_msgSend_release(NSObject *obj) asm("-[NSObject release]");
id bypass_msgSend_autorelease(NSObject *obj) asm("-[NSObject autorelease]");
Update:
Here is what a call to bypass_msgSend_release() generates:
movl -4(%ebp), %eax
movl %eax, (%esp)
calll "-[NSObject release]"
Here's the actual implementation of retain
from later in the file:
__attribute__((aligned(16)))
id
objc_retain(id obj)
{
if (!obj || OBJC_IS_TAGGED_PTR(obj)) {
goto out_slow;
}
#if __OBJC2__
if (((class_t *)obj->isa)->hasCustomRR()) {
return [obj retain];
}
return bypass_msgSend_retain(obj);
#else
return [obj retain];
#endif
out_slow:
// clang really wants to reorder the "mov %rdi, %rax" early
// force better code gen with a data barrier
asm volatile("");
return obj;
}
So if it's a tagged pointer, do nothing. Fair enough, that means it doesn't actually relate to anything on the heap and there is no retain count.
Otherwise in the old days they'd just message retain
to the object. Now they message retain
to the object if it has been noted to contain a custom retain
(no doubt not something the old runtime would record, hence the version check) otherwise they use the bypass method.
The bypass appears to call directly into the known address of [NSObject retain]
.
So my guess? It's a speed optimisation. If you can tell that there's no custom retain and, in effect, jump straight to the IMP
then you save the cost of the dynamic dispatch. Given that the compiler now throws in the C calls automatically under ARC (notably not the Objective-C calls) that means you never go into the more expensive stuff.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With