2012-02-05 135 views
17

我稍微困惑,爲什麼鐺是出於以下兩個方法發射不同的代碼:爲什麼這些簡單的方法編譯方式不同?

@interface ClassA : NSObject 
@end 

@implementation ClassA 
+ (ClassA*)giveMeAnObject1 { 
    return [[ClassA alloc] init]; 
} 
+ (id)giveMeAnObject2 { 
    return [[ClassA alloc] init]; 
} 
@end 

如果我們在發出那麼我們看到這個ARMv7的,在O3,啓用ARC:

 .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject1]" 
"+[ClassA giveMeAnObject1]": 
     push {r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
     mov  r7, sp 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_0: 
     add  r1, pc 
LPC0_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC0_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC0_2+4)) 
LPC0_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r7, lr} 
     b.w  _objc_autorelease 

     .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject2]" 
"+[ClassA giveMeAnObject2]": 
     push {r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     mov  r7, sp 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
LPC2_0: 
     add  r1, pc 
LPC2_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
LPC2_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

只有區別是尾部呼叫objc_autoreleaseReturnValueobjc_autorelease。我希望雙方都能誠實地致電objc_autoreleaseReturnValue。事實上,第一種不使用objc_autoreleaseReturnValue的方法意味着它可能比第二種方法慢,因爲肯定會有一個自動釋放,然後由調用者保留,而不是ARC可以做的冗餘調用的更快旁路運行時間。這是發射

的LLVM給人某種原因爲什麼它是這樣的:

define internal %1* @"\01+[ClassA giveMeAnObject1]"(i8* nocapture %self, i8* nocapture %_cmd) { 
    %1 = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_", align 4 
    %2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 4 
    %3 = bitcast %struct._class_t* %1 to i8* 
    %4 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %3, i8* %2) 
    %5 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2", align 4 
    %6 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %4, i8* %5) 
    %7 = tail call i8* @objc_autorelease(i8* %6) nounwind 
    %8 = bitcast i8* %6 to %1* 
    ret %1* %8 
} 

define internal i8* @"\01+[ClassA giveMeAnObject2]"(i8* nocapture %self, i8* nocapture %_cmd) { 
    %1 = load %struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_", align 4 
    %2 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_", align 4 
    %3 = bitcast %struct._class_t* %1 to i8* 
    %4 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %3, i8* %2) 
    %5 = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_2", align 4 
    %6 = tail call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* %4, i8* %5) 
    %7 = tail call i8* @objc_autoreleaseReturnValue(i8* %6) nounwind 
    ret i8* %6 
} 

但我掙扎,看看它爲什麼決定以不同的方式編譯這兩個方法。任何人都可以點亮它嗎?

更新:

更加古怪的是這些方法:

+ (ClassA*)giveMeAnObject3 { 
    ClassA *a = [[ClassA alloc] init]; 
    return a; 
} 

+ (id)giveMeAnObject4 { 
    ClassA *a = [[ClassA alloc] init]; 
    return a; 
} 

這些編譯爲:

 .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject3]" 
"+[ClassA giveMeAnObject3]": 
     push {r4, r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     add  r7, sp, #4 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC2_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC2_1+4)) 
LPC2_0: 
     add  r1, pc 
LPC2_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC2_2+4)) 
LPC2_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     blx  _objc_retainAutoreleasedReturnValue 
     mov  r4, r0 
     mov  r0, r4 
     blx  _objc_release 
     mov  r0, r4 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

     .align 2 
     .code 16 
     .thumb_func  "+[ClassA giveMeAnObject4]" 
"+[ClassA giveMeAnObject4]": 
     push {r4, r7, lr} 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC3_0+4)) 
     add  r7, sp, #4 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC3_0+4)) 
     movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC3_1+4)) 
     movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC3_1+4)) 
LPC3_0: 
     add  r1, pc 
LPC3_1: 
     add  r0, pc 
     ldr  r1, [r1] 
     ldr  r0, [r0] 
     blx  _objc_msgSend 
     movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC3_2+4)) 
     movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_2-(LPC3_2+4)) 
LPC3_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     blx  _objc_retainAutoreleasedReturnValue 
     mov  r4, r0 
     mov  r0, r4 
     blx  _objc_release 
     mov  r0, r4 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

這一次,他們卻一致有幾件事情可能這裏進一步優化:

  1. 有一個多餘的mov r4, r0後跟mov r0, r4

  2. 有一個保留後跟一個發佈。

當然,無論這些方法的底位可以變成:

LPC3_2: 
     add  r1, pc 
     ldr  r1, [r1] 
     blx  _objc_msgSend 
     pop.w {r4, r7, lr} 
     b.w  _objc_autoreleaseReturnValue 

顯然,我們之後還省略彈出r4,因爲我們實際上並不破壞它了。然後該方法將變成與giveMeAnObject2完全相同,這正是我們所期望的。

爲什麼叮噹不聰明,這樣做?!

+0

奇數,是的。你有沒有嘗試不同的優化級別? -os?無論如何,提交一個bug(並在這裏發佈#)。 – bbum 2012-02-05 20:09:27

+0

我已經嘗試了不同的優化級別,但沒有真正額外的報告。儘管我仍然需要更多的努力。那麼我會提交一個錯誤,但我想確保它首先是一個錯誤。我可能會錯過簡單的東西,雖然這很奇怪。 – mattjgalloway 2012-02-05 20:23:20

+0

@bbum - 其實我撒謊了。 'O0'有點有趣。案例1和2變得一樣。雖然顯然沒有尾部調用優化或類似的東西。所以,恩,我想這是關於優化尾部呼叫的。 – mattjgalloway 2012-02-05 20:30:36

回答

5

這似乎是優化器中的一個錯誤,正在作爲rdar:// problem/10813093進行跟蹤。

+0

太棒了。感謝您爲我尋找這個!當然是一個奇怪的! – mattjgalloway 2012-02-07 17:27:38

相關問題