// iOS, Xcode 8.3.2 stock, ARM, release build
// BOOL
char -[MYObject boolProp](void * self, void * _cmd) {
r0 = sign_extend_32(self->_boolProp);
return r0;
}
void -[MYObject setBoolProp:](void * self, void * _cmd, char arg2) {
self->_boolProp = arg2;
return;
}
// DOUBLE - 32bit
double -[MYObject doubleProp](void * self, void * _cmd) {
r0 = self;
r4 = sp - 0x20;
asm { bfc r4, #0x0, #0x3 };
r0 = objc_copyStruct(r4 + 0x8, *0xc834 + r0, 0x8, 0x1, 0x0);
asm { ldrd r0, r1, [sp, #0x18 + var_10] };
return r0;
}
void -[MYObject setDoubleProp:](void * self, void * _cmd, double arg2) {
r0 = self;
r4 = sp - 0x20;
asm { bfc r4, #0x0, #0x3 };
sp = r4;
r1 = 0x2240;
asm { strd r2, r3, [sp, #0x18 + var_10] };
objc_copyStruct(r0 + *(r1 + 0xa5f4), sp + 0x8, 0x8, 0x1, 0x0);
return;
}
// DOUBLE - 64bit
double -[MYObject doubleProp](void * self, void * _cmd) {
r0 = self;
return r0;
}
void -[MYObject setDoubleProp:](void * self, void * _cmd, double arg2) {
*(self + sign_extend_64(0x100009004)) = d0;
return;
}
// See note at the bottom about C11 atomics!
// DOUBLE - 32bit, C11 Atomics
double -[MYObject c11AtomicDoubleProp](void * self, void * _cmd) {
r0 = self + *0xc89c;
asm { ldrexd r0, r1, [r0] };
asm { clrex };
asm { dmb };
return r0;
}
void -[MYObject setC11AtomicDoubleProp:](void * self, void * _cmd, double arg2) {
r0 = self;
asm { dmb };
do {
asm { ldrexd r1, r0, [sb] };
asm { strexd r0, r2, r3, [sb] };
} while (r0 != 0x0);
asm { dmb };
return;
}
// DOUBLE - 64bit, C11 atomics
double -[MYObject c11AtomicDoubleProp](void * self, void * _cmd) {
r0 = self;
asm { ldar x8, [x8] };
return r0;
}
void -[MYObject setC11AtomicDoubleProp:](void * self, void * _cmd, double arg2) {
asm { stlr x9, [x8] };
return;
}
// FLOAT
float -[MYObject floatProp](void * self, void * _cmd) {
r0 = self->_floatProp;
return r0;
}
void -[MYObject setFloatProp:](void * self, void * _cmd, float arg2) {
self->_floatProp = arg2;
return;
}
// STRONG OBJECT
void * -[MYObject strongObjProp](void * self, void * _cmd) {
r1 = _cmd;
r0 = self;
r3 = 0x1;
r2 = *0xc83c;
r0 = objc_getProperty(r0, r1, r2, r3);
return r0;
}
void -[MYObject setStrongObjProp:](void * self, void * _cmd, void * arg2) {
objc_setProperty_atomic();
return;
}
// WEAK OBJECT
void * -[MYObject weakObjProp](void * self, void * _cmd) {
r0 = self + *0xc840;
r0 = objc_loadWeakRetained(r0);
r0 = [r0 autorelease];
return r0;
}
void -[MYObject setWeakObjProp:](void * self, void * _cmd, void * arg2) {
r0 = self + *0xc840;
r1 = arg2;
objc_storeWeak(r0, r1);
return;
}
// UNSAFE OBJECT
void * -[MYObject unsafeObjProp](void * self, void * _cmd) {
r0 = self->_unsafeObjProp;
return r0;
}
void -[MYObject setUnsafeObjProp:](void * self, void * _cmd, void * arg2) {
self->_unsafeObjProp = arg2;
return;
}
// COPIED OBJECT
void * -[MYObject copiedObjectProp](void * self, void * _cmd) {
r0 = loc_a78c(self, _cmd); // NOTE: Jumps to the -strongObjectProp method impl. Clever!
return r0;
}
void -[MYObject setCopiedObjectProp:](void * self, void * _cmd, void * arg2) {
objc_setProperty_atomic_copy();
return;
}
// CGRECT
struct CGRect -[MYObject cgRectProp](void * self, void * _cmd) {
r0 = objc_copyStruct(self, _cmd + *0xc848, 0x10, 0x1, 0x0);
return r0;
}
void -[MYObject setCgRectProp:](void * self, void * _cmd, struct CGRect arg2) {
r0 = self;
sp = sp - 0x1c;
r9 = 0xc848;
asm { strd r2, r3, [sp, #0x14 + var_10] };
asm { strd r1, ip, [sp, #0x14 + var_8] };
objc_copyStruct(r0 + *r9, sp + 0x4, 0x10, 0x1, 0x0);
return;
}
Summary:
Note: Implementations of objc_copyStruct
, objc_setProperty_atomic
, and objc_getProperty
are available at https://opensource.apple.com/source/objc4/objc4-709/runtime/objc-accessors.mm.auto.html
- Types that fit in the arch size (
BOOL
,int
,unsafe_unretained id
, etc) are read/set directly with no synchronization. - Bigger types (e.g.
double
on 32bit) useobjc_copyStruct
which uses spinlocks. - Retain/weak/copy objects use
objc_setPropertyAtomic
andobjc_getProperty
which use spinlocks - C11 atomics replace
objc_copyStruct
with awhile
loop – similar to a spinlock
Compare the assembly for setting double on 64-bit using Obj-C-atomic and C11 atomic:
-[MYObject setC11AtomicDoubleProp:]: // C11 atomic
ldrsw x8, #0x100009060
add x8, x0, x8
fmov x9, d0
stlr x9, [x8]
ret
-[MYObject setDoubleProp:]: // ObjC atomic
ldrsw x8, #0x100009068
fmov x9, d0
str x9, [x0, x8]
ret
The obj-c atomic manages to combine the add
and stlr
instructions from C11 atomic into one str
instruction.