15

I have read the Transitioning to ARC Release Notes in "Summary" Section. They told :

ARC works by adding code at compile time to ensure that objects live as long as necessary, but no longer. Conceptually, it follows the same memory management conventions as manual reference counting (described in Advanced Memory Management Programming Guide) by adding the appropriate memory management calls for you.

In order for the compiler to generate correct code

I wonder what result that ARC corrected our code.

My question : Can we see the change? (In the term of alloc , retain , assign or release .Not assembly level !)

Reason : Because I think It's good to see the best-practice code in the old tradition development without ARC mode.

James
  • 24,676
  • 13
  • 84
  • 130
Sakares
  • 606
  • 12
  • 31
  • 1
    For the study case, I mean "old tradition development" is about how could we alloc,retain,assign or release them correctly. I also wouldn't like to hard code in assembly detail :-) . – Sakares May 03 '12 at 10:59
  • You can just read the documentation linked from the article you cite, ARC just does the same thing described in this article. Read the "Memory Management Policy" section to start, most of the ARC rules for daily programming are derived from there. https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html – Dietrich Epp May 03 '12 at 11:29
  • possible duplicate of [Seeing where ARC is inserting retain and releases](http://stackoverflow.com/questions/8812098/seeing-where-arc-is-inserting-retain-and-releases) – jscs May 03 '12 at 18:17

3 Answers3

27

ARC in clang doesn't work by rewriting code from ObjC to ObjC, but emitting the extra retain/release LLVM bitcode during code-gen. That means, it is not possible to know how the compiler "fix" it without going to LLVM IR / assembly level.


If ARC emit the LLVM bitcode as you said. Is it made for the purpose that use less time in compile process? (less complex ObjC code, less header file?)

It is always better if the compiler can reduce the number of passes through the code.


Can you show me some example or utility that show the code in assembly level?

To get the assembly code, you could either

  1. Generate assembly directly from the compiler. In the command line, add the -S flag when invoking the compiler. The result is a .S file containing the assembly code. In an Xcode project, open the source code file, then go to Product (on menu bar) → Generate OutputAssembly File.

  2. Generate the object file, and then disassemble it. The built-in command otool -tvV <file> can perform disassembly, and there are advanced tools like otx (free) or IDA (free for evaluation).

I prefer route 2 because it generates less garbage and the disassembly tool can be configured to produce more useful information. Anyway, with either method you need to be able to read assembly code.

Take this code as example:

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

After compiling the following assembly will be produced (analyzed using 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}

Without going into detail, you can see there are many _objc_release and _objc_retainAutoreleasedReturnValue. These are what ARC inserts during code-gen. Decompiling it by hand, we'll get:

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;

which is just the same as what @c roald's link describes.

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • It seem to be like you said. How do you think about emitting LLVM bitcode in assembly level ,fast compile? – Sakares May 03 '12 at 15:57
  • @Jojas: Sorry I don't understand what you mean by ", fast compile?". – kennytm May 03 '12 at 17:44
  • I would like to ask your opinion ,if ARC emit the LLVM bitcode as you said. Is it made for the purpose that use less time in compile process? (less complex ObjC code , less header file ?) – Sakares May 03 '12 at 18:01
  • At least before the bounty end, I have consider your answer that furthermore well explained knowledge ,Can you show me some example or utility that show the code in assembly level? I think it could be deserve for your reward. – Sakares May 12 '12 at 19:05
  • crystal-clear explained answer. Althought It's not exactly answer that I'm looking for but I really realized your answer is the only way to see ARC mechanism well. Of course, This is your reward ! Thank you for quality answer ! – Sakares May 13 '12 at 11:15
  • @kennytm did you follow all this instructions manually to figure out which values are in which registers? – pash3r Apr 09 '20 at 12:39
3

Mike Ash has a very illuminating discussion of ARC implementation here: http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

He discusses it at the level of inserting C function calls (objc_retain(), objc_release(), objc_retainAutoreleaseReturnValue(), and a few others, if that would be helpful for you. Written that way, the compiler can use tail-call optimizations to eliminate unnecessary steps.

The short answer, therefore, is that ARC doesn't use the same [retain]/[release] methods we would have used in older versions of Objecive C, so therefore seeing the ARC-preprocessed code wouldn't necessarily instruct you in how to do it yourself.

ARC is not unusual in being implemented as a preprocessing step in the compiler -- I believe many features of Objective C are implemented this way.

c roald
  • 1,984
  • 1
  • 20
  • 30
0

No you cannot go into such details without going into the assembly level details of LLVM.

Abhishek Singh
  • 6,068
  • 1
  • 23
  • 25