我有一个方法 createATestObject 。顾名思义,它创建一个对象并返回它。代码很简单,在ARC下。

- (TestObj *)createATestObj
{
    return [[TestObj alloc] init] ;
}

我汇编文件并获得下面的汇编代码。
Lfunc_begin4:
    .cfi_startproc
@ BB#0:
    push    {r7, lr}
    mov r7, sp
    sub sp, #8
    @DEBUG_VALUE: -[ViewController createATestObj]:self <- undef
    @DEBUG_VALUE: -[ViewController createATestObj]:_cmd <- undef
    str r0, [sp, #4]
    str r1, [sp]
    movw    r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC4_0+4))
    movt    r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC4_0+4))
LPC4_0:
    add r0, pc
    ldr r0, [r0]
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_10-(LPC4_1+4))
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_10-(LPC4_1+4))
LPC4_1:
    add r1, pc
    ldr r1, [r1]
    blx _objc_msgSend
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC4_2+4))
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC4_2+4))
LPC4_2:
    add r1, pc
    ldr r1, [r1]
    blx _objc_msgSend
    add sp, #8
    pop.w   {r7, lr}
    b.w _objc_autoreleaseReturnValue
Ltmp13:
Lfunc_end4:
    .cfi_endproc

我注意到函数 _objc_autoreleaseReturnValue 并从 here 获取有关它的引用。但我不知道这是什么意思。任何人都可以详细说明吗?非常感谢。

最佳答案

首先感谢@Darren,感谢您的链接。

我在 link 中引用了一些段落。


/*
  Fast handling of returned autoreleased values.
  The caller and callee cooperate to keep the returned object
  out of the autorelease pool.

  Caller:
    ret = callee();
    objc_retainAutoreleasedReturnValue(ret);
    // use ret here

  Callee:
    // compute ret
    [ret retain];
    return objc_autoreleaseReturnValue(ret);

  objc_autoreleaseReturnValue() examines the caller's instructions following
  the return. If the caller's instructions immediately call
  objc_autoreleaseReturnValue, then the callee omits the -autorelease and saves
  the result in thread-local storage. If the caller does not look like it
  cooperates, then the callee calls -autorelease as usual.

  objc_autoreleaseReturnValue checks if the returned value is the same as the
  one in thread-local storage. If it is, the value is used directly. If not,
  the value is assumed to be truly autoreleased and is retained again.  In
  either case, the caller now has a retained reference to the value.

  Tagged pointer objects do participate in the fast autorelease scheme,
  because it saves message sends. They are not entered in the autorelease
  pool in the slow case.
*/

来自我的东西

让我们看看 objc_autoreleaseReturnValue 的源代码。
id
objc_autoreleaseReturnValue(id obj)
{
#if SUPPORT_RETURN_AUTORELEASE
    assert(tls_get_direct(AUTORELEASE_POOL_RECLAIM_KEY) == NULL);

    if (callerAcceptsFastAutorelease(__builtin_return_address(0))) {
        tls_set_direct(AUTORELEASE_POOL_RECLAIM_KEY, obj);
        return obj;
    }
#endif

    return objc_autorelease(obj);
}
__builtin_return_address(0) returns the return address of current function ,然后让我们看看 callerAcceptsFastAutorelease 对 arm 版本的实现:
static bool callerAcceptsFastAutorelease(const void *ra)
{
    // if the low bit is set, we're returning to thumb mode
    if ((uintptr_t)ra & 1) {
        // 3f 46          mov r7, r7
        // we mask off the low bit via subtraction
        if (*(uint16_t *)((uint8_t *)ra - 1) == 0x463f) {
            return true;
        }
    } else {
        // 07 70 a0 e1    mov r7, r7
        if (*(uint32_t *)ra == 0xe1a07007) {
            return true;
        }
    }
    return false;
}

在该方法中,它查找作为 mov r7, r7 标记的 objc_retainAutoreleaseReturnValue 指令,如果找到,则该方法返回 true ,因此被调用者将省略自动释放。

你可以看到调用者的汇编代码,在我的例子中是 testFun1
- (void)testFun1:(ViewController *)vc
{
    [vc createATestObj] ;
}

下面是汇编代码,你可以找到“mov r7, r7 @marker for objc_retainAutoreleaseReturnValue”这一行
    .cfi_startproc
@ BB#0:
    push    {r7, lr}
    mov r7, sp
    sub sp, #16
    add r3, sp, #4
    movw    r9, #0
    movt    r9, #0
    str r0, [sp, #12]
    str r1, [sp, #8]
    str.w   r9, [sp, #4]
    mov r0, r3
    mov r1, r2
    bl  _objc_storeStrong
    movw    r0, :lower16:(L_objc_msgSend$non_lazy_ptr-(LPC5_0+4))
    movt    r0, :upper16:(L_objc_msgSend$non_lazy_ptr-(LPC5_0+4))
LPC5_0:
    add r0, pc
    ldr r0, [r0]
    movw    r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_12-(LPC5_1+4))
    movt    r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_12-(LPC5_1+4))
LPC5_1:
    add r1, pc
Ltmp14:
    ldr r2, [sp, #4]
    ldr r1, [r1]
    str r0, [sp]                @ 4-byte Spill
    mov r0, r2
    ldr r2, [sp]                @ 4-byte Reload
    blx r2
    @ InlineAsm Start
    mov r7, r7      @ marker for objc_retainAutoreleaseReturnValue
    .code   16
    @ InlineAsm End
    bl  _objc_retainAutoreleasedReturnValue
    bl  _objc_release
    movs    r1, #0
    movt    r1, #0
    add r0, sp, #4
    bl  _objc_storeStrong
    add sp, #16
    pop {r7, pc}
Ltmp15:
Lfunc_end5:
    .cfi_endproc

更新:

我认为 apple's implementation 的评论有一些错误。

正确的注释应该是这样的:
/*
  Fast handling of returned autoreleased values.
  The caller and callee cooperate to keep the returned object
  out of the autorelease pool.

  Caller:
    ret = callee();
    objc_retainAutoreleasedReturnValue(ret);
    // use ret here

  Callee:
    // compute ret
    [ret retain];
    return objc_autoreleaseReturnValue(ret);

  objc_autoreleaseReturnValue() examines the caller's instructions following
  the return. If the caller's instructions immediately call
  objc_retainAutoreleasedReturnValue, then the callee omits the -autorelease and saves
  the result in thread-local storage. If the caller does not look like it
  cooperates, then the callee calls -autorelease as usual.

  objc_retainAutoreleasedReturnValue checks if the returned value is the same as the
  one in thread-local storage. If it is, the value is used directly. If not,
  the value is assumed to be truly autoreleased and is retained again.  In
  either case, the caller now has a retained reference to the value.

  Tagged pointer objects do participate in the fast autorelease scheme,
  because it saves message sends. They are not entered in the autorelease
  pool in the slow case.
*/

如果您有其他想法,请发表评论。谢谢!

关于ios - objc_autoreleaseReturnValue 是什么意思?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29249171/

10-10 21:47