Czy można zobaczyć kod wygenerowany przez ARC w czasie kompilacji?

Przeczytałem Transitioning to Arc Release Notes w sekcji "Summary". Powiedzieli:

ARC działa poprzez dodawanie kodu w czasie kompilacji, aby zapewnić, że obiekty działają tak długo, jak to konieczne, ale już nie. Koncepcyjnie wynika to z tego samego konwencje zarządzania pamięcią jako ręczne zliczanie referencji (opisane w Advanced Memory Management Programming Guide) poprzez dodanie odpowiednie zarządzanie pamięcią wymaga od ciebie.

Aby kompilator Wygeneruj poprawny kod

Ciekawe jaki wynik ten ARC poprawił nasz kod.

Moje pytanie: Czy możemy zobaczyć zmianę? (w terminach alloc , retain , assign lub release .Nie poziom montażu !)

Powód: ponieważ myślę, że dobrze jest zobaczyć kod najlepszej praktyki w rozwoju starej tradycji bez trybu ARC.

Author: James, 2012-05-03

3 answers

ARC w clang nie działa przepisując kod z ObjC do ObjC, ale emitując dodatkowy bitcode zachowaj / zwolnij LLVM podczas code-gen. oznacza to, że nie jest możliwe, aby wiedzieć, jak kompilator "naprawić" go bez przechodzenia do poziomu LLVM IR/assembly.


Jeśli ARC emituje BITCODE LLVM, jak powiedziałeś. Czy jest to zrobione w celu, który zużywa mniej czasu w procesie kompilacji? (mniej skomplikowany kod obiektu, mniej pliku nagłówkowego?)

Jest zawsze lepiej, jeśli kompilator może zmniejszyć liczba przejść przez kod.


Możesz mi pokazać jakiś przykład lub narzędzie, które pokazuje kod na poziomie złożenia?

Aby uzyskać kod assembly, możesz albo

  1. Generuje assembly bezpośrednio z kompilatora. W wierszu poleceń Dodaj znacznik -S podczas wywoływania kompilatora. Rezultatem jest plik .S zawierający kod złożenia. W projekcie Xcode otwórz plik kodu źródłowego, a następnie przejdź do Product (na pasku menu) → Wygeneruj WyjściePlik Assembly .

  2. Wygenerować plik obiektowy, a następnie go zdemontować. Wbudowane polecenie {[5] } może wykonywać demontaż, a istnieją zaawansowane narzędzia, takie jak otx (bezpłatne) lub IDA (bezpłatne do oceny).

Wolę route 2, ponieważ generuje mniej śmieci, a narzędzie do demontażu można skonfigurować tak, aby wytwarzało więcej użytecznych informacji. W każdym razie, przy obu metodach musisz być w stanie odczytać montaż kod.

Weź ten kod jako przykład:

- (BOOL)application:(UIApplication*)application 
        didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
   self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   self.window.backgroundColor = [UIColor whiteColor];
   [self.window makeKeyAndVisible];
   return YES;
}

Po skompilowaniu zostanie wytworzony następujący zestaw (analizowany przy użyciu IDA):

-[SomeAppDelegate application:didFinishLaunchingWithOptions:]:
    push       {r4-r7,lr}
    add        r7, sp, #0xC
    str.w      r8, [sp,-#0x4]!
    sub        sp, sp, #0x18
    movw       r1, #(0x343c - 0x2574)       ; @selector(alloc)
    mov        r8, r0
    movt.w     r1, #0
    mov        r0, (0x3464 - 0x2576)        ; _OBJC_CLASS_$_UIWindow
    add        r1, pc
    add        r0, pc
    ldr        r1, [r1]
    ldr        r0, [r0]
    blx        _objc_msgSend
    mov        r1, (0x3440 - 0x258e)        ; @selector(mainScreen)
    mov        r6, r0
    movw       r0, #(0x3468 - 0x2594)       ; _OBJC_CLASS_$_UIScreen
    add        r1, pc
    movt.w     r0, #0
    add        r0, pc
    ldr        r1, [r1]
    ldr        r0, [r0]
    blx        _objc_msgSend
    mov        r7, r7
    blx        _objc_retainAutoreleasedReturnValue
    mov        r5, r0
    cbz        r5, L25ba
    movw       r0, #(0x3444 - 0x25b2)       ; @selector(bounds)
    mov        r1, r5
    movt.w     r0, #0
    add        r0, pc
    ldr        r2, [r0]
    add        r0, sp, #0x8
    blx        _objc_msgSend_stret
    b          L25c4

L25ba:
    add        r0, sp, #0x8
    vmov.i32   q8, #0x80
    vstmia     r0, {d16-d17}

L25c4:
    mov        r1, (0x3448 - 0x25d2)        ; @selector(initWithFrame:)
    ldr        r0, [sp,#0x10]
    add        r1, pc
    ldr        r2, [sp,#0x8]
    ldr        r3, [sp,#0xc]
    ldr        r4, [sp,#0x14]
    stmea.w    sp, {r0,r4}
    mov        r0, r6
    ldr        r1, [r1]
    blx        _objc_msgSend
    mov        r4, r0
    mov        r0, (0x344c - 0x25F2)        ; @selector(setWindow:)
    mov        r2, r4
    add        r0, pc
    ldr        r1, [r0]
    mov        r0, r8
    blx        _objc_msgSend
    mov        r0, r4
    blx        _objc_release
    mov        r0, r5
    blx        _objc_release
    mov        r0, (0x3450 - 0x2610)        ; @selector(window)
    add        r0, pc
    ldr        r5, [r0]
    mov        r0, r8
    mov        r1, r5
    blx        _objc_msgSend
    mov        r7, r7
    blx        _objc_retainAutoreleasedReturnValue
    mov        r1, (0x3454 - 0x2630)        ; @selector(whiteColor)
    mov        r6, r0
    movw       r0, #(0x346C - 0x2636)       ; _OBJC_CLASS_$_UIColor
    add        r1, pc
    movt.w     r0, #0
    add        r0, pc
    ldr        r1, [r1]
    ldr        r0, [r0]
    blx        _objc_msgSend
    mov        r7, r7
    blx        _objc_retainAutoreleasedReturnValue
    mov        r4, r0
    mov        r0, (0x3458 - 0x2652)        ; @selector(setBackgroundColor:)
    mov        r2, r4
    add        r0, pc
    ldr        r1, [r0]
    mov        r0, r6
    blx        _objc_msgSend
    mov        r0, r4
    blx        _objc_release
    mov        r0, r6
    blx        _objc_release
    mov        r0, r8
    mov        r1, r5
    blx        _objc_msgSend
    mov        r7, r7
    blx        _objc_retainAutoreleasedReturnValue
    mov        r4, r0
    mov        r0, (0x345C - 0x2680)        ; @selector(makeKeyAndVisible)
    add        r0, pc
    ldr        r1, [r0]
    mov        r0, r4
    blx        _objc_msgSend
    mov        r0, r4
    blx        _objc_release
    movs       r0, #1
    add        sp, sp, #0x18
    ldr.w      r8, [sp], #4
    pop        {r4-r7,pc}

Bez wchodzenia w szczegóły, widać, że jest ich wiele _objc_release i _objc_retainAutoreleasedReturnValue. oto co Arc wstawia podczas kodu-gen. Dekompilując go ręcznie, otrzymamy:

UIScreen* r5 = objc_retainAutoreleasedReturnValue([UIScreen mainScreen]);
CGRect sp8 = r5 != nil ? [r5 bounds] : CGRectZero;
UIWindow* r4 = [[UIWindow alloc] initWithFrame:sp8];
[self setWindow:r4];
objc_release(r4);
objc_release(r5);

UIWindow* r6a = objc_retainAutoreleasedReturnValue([self window])
UIColor* r4a = objc_retainAutoreleasedReturnValue([UIColor whiteColor])
[r6a setBackgroundColor:r4a];
objc_release(r4a);
objc_release(r6a);

UIWindow* r4b = objc_retainAutoreleasedReturnValue([self window])
[r4b makeKeyAndVisible];
objc_release(r4b);

return 1;

Który jest dokładnie taki sam jak to, co opisuje link @c roald.

 25
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:00:29

Mike Ash ma bardzo pouczającą dyskusję na temat implementacji ARC tutaj: http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

Omawia to na poziomie wstawiania wywołań funkcji C (objc_retain (), objc_release (), objc_retainAutoreleaseReturnValue () i kilku innych, jeśli byłoby to dla ciebie pomocne. Napisany w ten sposób kompilator może używać optymalizacji wywołania ogonowego w celu wyeliminowania niepotrzebnych kroków.

Krótka odpowiedź, w związku z tym ARC nie używa tych samych metod [zachowaj]/[wydaj], których używalibyśmy w starszych wersjach Objecive C, więc zobaczenie wstępnie przetworzonego kodu Arc niekoniecznie instruowałoby Cię, jak to zrobić samemu.

ARC nie jest niczym niezwykłym w implementacji jako etap wstępnego przetwarzania w kompilatorze -- wierzę, że wiele funkcji Objective C jest zaimplementowanych w ten sposób.

 2
Author: c roald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-12 14:14:43

Nie Nie można wchodzić w takie szczegóły bez wchodzenia w szczegóły poziomu montażu LLVM.

 0
Author: Abhishek Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-12 16:53:57