8

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]"
mojuba
  • 11,842
  • 9
  • 51
  • 72
  • 1
    Those appear to be explicit invocations of retain, release, and autorelease, to circumvent the compiler's desire to object to the same. As to why they're present, I haven't a clue. – Hot Licks May 07 '14 at 19:58
  • Which file is this in? – jscs May 07 '14 at 20:05
  • http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm – Martin R May 07 '14 at 20:09
  • @JoshCaswell NSObject.mm - it's a hidden implementation of NSObject that's somehow partially re-implemented in CF. Also see my update with some asm code. – mojuba May 07 '14 at 20:11
  • 1
    I presume this is to bypass ARC, which would forbid the call. But I'm guessing at this point. Very interesting discovery. – Rob Napier May 07 '14 at 20:12
  • @JoshCaswell I presume you edited the title. I'd say not "Why" but "How exactly" is this inline code calling etc. :) – mojuba May 07 '14 at 20:15
  • 1
    Feel free to edit it again; I didn't mean to change your question, just make it clearer. Note that tags are not necessary in the title, and that the code itself is in the question, so that will be found in a search. I suggest that a strictly prose description is best for the title. – jscs May 07 '14 at 20:17
  • Hmmm... That is an interesting hack that presumably anyone could use to map a C/C++ call to an Objective-C method. Avoids the need for "glue" code (though I'm not sure that avoiding glue code justifies the hack). – Hot Licks May 07 '14 at 20:26
  • @HotLicks so maybe this is part of their "toll-free" bridging or something? Still `calll "string"` should mean something. I have never seen this before in asm code. – mojuba May 07 '14 at 20:28
  • 1
    @mojuba - The string is just the actual linker-visible name of the method. It's in quotes since it contains non-standard characters. – Hot Licks May 07 '14 at 20:34
  • @HotLicks so it's a "toll-free" direct call of a method. In this case they wanted to bypass a virtual call. – mojuba May 07 '14 at 20:51
  • @mojuba - Yep, it's significant to note that it's a non-virtual call. – Hot Licks May 07 '14 at 20:56

1 Answers1

4

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.

Tommy
  • 99,986
  • 12
  • 185
  • 204