Mac OS X
CSC Menu
Fringe Player


Hamster Emporium archive

archive   |   [objc explain]: So you crashed in objc_msgSend(): iPhone 5s Edition   >>

(link) [objc explain]: Non-pointer isa   (2013-09-24 1:27 AM)

On iOS for arm64, the isa field of Objective-C objects is no longer a pointer.

Say what?

On iOS for arm64, the isa field of Objective-C objects is no longer a pointer.

If it's not a pointer anymore, what is it?

Some of the bits still encode the pointer to the object's class. But neither OS X nor iOS actually uses all 64 bits of virtual address space. The Objective-C runtime may use these extra bits to store per-object data like its retain count or whether it has been weakly referenced.

Why change it?

Performance. Re-purposing these otherwise unused bits increases speed and decreases memory size. On iOS 7 the focus is on optimizing retain/release and alloc/dealloc.

What does this mean for my code?

Don't read obj->isa directly. The compiler will complain if you do. Trust the Compiler. The Compiler is your friend. Use [obj class] or object_getClass(obj) instead.

Don't write obj->isa directly. Use object_setClass() instead.

If you override +allocWithZone:, you may initialize your object's isa field to a "raw" isa pointer. If you do, no extra data will be stored in that isa field and you may suffer the slow path through code like retain/release. To enable these optimizations, instead set the isa field to zero (if it is not already) and then call object_setClass().

If you override retain/release to implement a custom inline retain count, consider removing that code in favor of the runtime's implementation.

The 64-bit iOS simulator currently does not use non-pointer isa. Test your code on a real arm64 device.

What does this mean for debugging?

The debugger knows how to decode the class from the isa field. You should not need to examine it directly in most cases.

You can run your code with environment variable OBJC_DISABLE_NONPOINTER_ISA=YES to disable non-pointer isa for all classes. If your code works with this set and fails without it, you may be incorrectly accessing an isa field directly somewhere.

If you are writing a debugger-like tool, the Objective-C runtime exports some variables to help decode isa fields. objc_debug_isa_class_mask describes which bits are the class pointer: (isa & class_mask) == class pointer. objc_debug_isa_magic_mask and objc_debug_isa_magic_value describe some bits that help distinguish valid isa fields from other invalid values: (isa & magic_mask) == magic_value for isa fields that are not raw class pointers. These variables may change in the future so do not use them in application code.

No seriously, what do each of the bits mean?

For entertainment purposes only. These values will change in future OS versions. I think they already have changed, actually.

1bitindexed0 is raw isa, 1 is non-pointer isa.
1bithas_assocObject has or once had an associated reference. Object with no associated references can deallocate faster.
1bithas_cxx_dtorObject has a C++ or ARC destructor. Objects with no destructor can deallocate faster.
30bitsshiftclsClass pointer's non-zero bits.
9bitsmagicEquals 0xd2. Used by the debugger to distinguish real objects from uninitialized junk.
1bitweakly_referencedObject is or once was pointed to by an ARC weak variable. Objects not weakly referenced can deallocate faster.
1bitdeallocatingObject is currently deallocating.
1bithas_sidetable_rcObject's retain count is too large to store inline.
19bitsextra_rcObject's retain count above 1. (For example, if extra_rc is 5 then the object's real retain count is 6.)

seal! Greg Parker
Sealie Software