为什么这个内联汇编在libobjc中调用release,retain和autorelease?

时间:2014-05-07 19:44:00

标签: objective-c assembly inline-assembly libobjc

下面的代码段取自Apple的ObjC运行时(libobjc)源代码。我想知道这究竟意味着什么。 (不是google-able,抱歉)

// 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]");

更新

以下是对bypass_msgSend_release()的调用:

movl    -4(%ebp), %eax
movl    %eax, (%esp)
calll   "-[NSObject release]"

1 个答案:

答案 0 :(得分:4)

以下是文件中稍后retain的实际实现:

__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;
}

因此,如果它是标记指针,则不执行任何操作。很公平,这意味着它实际上并没有与堆上的任何东西相关,也没有保留计数。

否则在过去,他们只是向对象发送retain消息。现在,如果已经注意到它包含自定义retain(毫无疑问不是旧运行时将记录的内容,因此版本检查),它们会向对象发送retain消息,否则它们会使用旁路方法。

旁路似乎直接调用已知地址[NSObject retain]

所以我的猜测?这是速度优化。如果您可以确定没有自定义保留,并且实际上直接跳转到IMP,那么您可以节省动态调度的成本。鉴于编译器现在在ARC下自动抛出C调用(特别是不是Objective-C调用),这意味着你永远不会进入更昂贵的东西。