我有一个方法 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 获得了关于它的引用.但我不知道这是什么意思。任何人都可以详细说明吗?非常感谢。
id objc_autoreleaseReturnValue(id value);
Precondition: value is null or a pointer to a valid object.
If value is null, this call has no effect. Otherwise, it makes a best effort to hand off ownership of a retain count on the object to a call to objc_retainAutoreleasedReturnValue for the same object in an enclosing call frame. If this is not possible, the object is autoreleased as above.
Always returns value.
最佳答案
首先感谢@Darren,感谢您的链接。
我引用了 link 中的一些段落.
ARC has a trick that keeps returned objects out of autorelease pools if both the caller and callee are ARC.
But how does that work? One of the features of ARC is that old compiled-before-ARC code (MRC code) can call ARC code and vice-versa. But if ARC code doesn’t put a returned object in an autorelease pool that MRC code is expecting, then the object would just leak.
So ARC-ified clang code emits this function call when returning an object: objc_autoreleaseReturnValue(id).
If you look at objc_autoreleaseReturnValue's implementation, it calls callerAcceptsFastAutorelease(). Even if you don’t read x86_64 or ARM assembly, the code’s comment is straight-forward:
/*
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/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or