Search code examples
objective-ccpointersstructobjective-c-runtime

Why is isa field of Objective C object has 1 offset with its class pointer?


I'm trying to using the following code to understand NSObject's C struct layout. First I print its struct layout using NSData, then I print the class pointer directly using [NSObject class].

id obj = [NSObject new];
long nsSize = class_getInstanceSize([NSObject class]);
NSData *nsData = [NSData dataWithBytes:(__bridge const void *)obj length:nsSize];
NSLog(@"obj: %@", nsData);
NSLog(@"NSObject Class: %p", [NSObject class]);

And I got the result:

2015-10-15 08:11:53.913 ObjC_CMD[11406:1999149] obj: <f1e06573 ffff1d00>
2015-10-15 08:11:53.913 ObjC_CMD[11406:1999149] NSObject Class: 0x7fff7365e0f0

What's interesting is the end of class pointer is e0f0, while the NSData print result shows its isa as eof1 (it's in reverse order because of little endian). I read in book that the isa pointer is topmost in an object's struct layout, so why it has 1 offset?

By the way, I have also tried on other types of objects, there is always 1 offset between isa and class pointer. Shouldn't they be the same?

P.S. I just noticed that the class pointer begins with 0x7fff, but the isa in C struct seems to be 0xffff, this difference is also interesting. What's the exact relationship between isa field and class pointer obtained from [NSObject class]?


Solution

  • The 1 in the least significant bit means isa is not a pointer. In 64-bit land, the 64-bits of isa got repurposed into a bit-mask. On the most significant side of the isa bit-mask are other bit fields and the reference count.

    Part of the isa bit-mask (30 bits in the middle) identify the class object, which is the part you recognized.