Here's the disassembly for objc_msgSend on ARMv6, iOS4.2.1 (sorry no ARMv7 devices on my desk at the moment). I'll try to annotate it:
0x32d98f0cTests if r0 (the receiver) is nil, and if so, sets r1 selector to 0x0 and returns. I guess there's no nil handler on ARM. Simple function return values are in registers r0-r3, so I guess r1 is set to 0 in case the caller is expecting a long long.: teq r0, #0 ; 0x0 0x32d98f10 : moveq r1, #0 ; 0x0 0x32d98f14 : bxeq lr
If receiver is non-nil:
0x32d98f18^ this loads the class pointer ( isa ) into r4: push {r3, r4, r5, r6} 0x32d98f1c : ldr r4, [r0]
This looks similar to the bit twiddling x86 cache lookup in the class; it's somewhat harder to read than the x86 due to ARM's bit packing shortcuts[1]:
0x32d98f20Check if the method is NULL, and if so, jump to the cache miss at the end:: ldr r5, [r4, #8] 0x32d98f24 : ldr r6, [r5] 0x32d98f28 : add r3, r5, #8 ; 0x8 0x32d98f2c : and r5, r6, r1, lsr #2 0x32d98f30 : ldr r4, [r3, r5, lsl #2]
0x32d98f34This would appear to be the part checking if this is the cache entry we're looking for:: teq r4, #0 ; 0x0 0x32d98f38 : add r5, r5, #1 ; 0x1 0x32d98f3c : beq 0x32d98f60
0x32d98f40If it isn't, loop:: ldr r12, [r4] 0x32d98f44 : teq r1, r12 0x32d98f48 : and r5, r5, r6
0x32d98f4cIf it is, restore the registers and do an indirect jump into the method we found (I'm not sure what the teq r4,r4 is for):: bne 0x32d98f30
0x32d98f50Tail call into the slow version with full lookup (after restoring the clobbered registers and the stack pointer):: ldr r12, [r4, #8] 0x32d98f54 : teq r4, r4 0x32d98f58 : pop {r3, r4, r5, r6} 0x32d98f5c : bx r12
0x32d98f60: pop {r3, r4, r5, r6} 0x32d98f64 : b 0x32d98f68