<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Swift heap object headers are fairly large—16 bytes on 64-bit, and 12 bytes on 32-bit. Into this space we pack:<div class=""><br class=""></div><div class="">- the 'isa' pointer for the object, pointing to its heap metadata/class object,</div><div class="">- the strong and unowned reference counts,</div><div class="">- 'pinned' and 'deallocating' flags.</div><div class=""><br class=""></div><div class="">We've also discussed taking a flag bit for 'not refcounted' objects, such as statically-allocated globals and/or stack promotions that need to be ABI compatible with heap objects, and potentially one for thread-local objects, to avoid barriers when refcounting objects we dynamically know are not referenced from multiple threads. We should consider whether we can reduce the header size. Two ideas come to mind:</div><div class=""><br class=""></div><div class=""><b class="">Dropping the unowned reference count</b></div><div class=""><b class=""><br class=""></b></div><div class="">If we adopt a sufficiently fast implementation for normal weak references, such as the activity count implementation suggested by Kevin and Mike, the unowned reference count might not be worth the expense. If we dropped it, that would be enough to bring the 32-bit object header down to 8 bytes. The tradeoff would be that unowned references become fatter, like weak references would, which might complicate our plans to eventually allow unowned to transparently become unowned(unsafe) in unchecked builds.</div><div class=""><br class=""></div><div class=""><b class="">Non-pointer isa for 64-bit platforms</b></div><div class=""><b class=""><br class=""></b></div><div class="">Neither x86-64 nor ARM64 populates the full 64 bits of address space—contemporary x86-64 uses only 48 bits (sign-extended, so effectively 47 bits for userspace), and Apple ARM64 platforms use fewer bits, the exact number dependent on OS version. If we were willing to drop the unowned refcount, and say that "64Ki-retains ought to be enough for anyone", overflowing the retain count into the "not refcounted" bit to leak overly-retained objects, we could use a layout similar to this to pack the remaining information into 8 bytes:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Courier New" class="">bits meaning</font></div><div class=""><font face="Courier New" class="">----- -------</font></div><div class=""><font face="Courier New" class="">63 not refcounted</font></div><div class=""><font face="Courier New" class="">47…62 strong refcount</font></div><div class=""><font face="Courier New" class="">03…46 metadata pointer</font></div><div class=""><font face="Courier New" class="">02 (reserved)</font></div><div class=""><font face="Courier New" class="">01 deallocating</font></div><div class=""><font face="Courier New" class="">00 pinned</font></div><div class=""><br class=""></div></div><div class="">There are of course some costs and complications. For classes, we look up vtable entries and resilient ivar offsets through the isa pointer, and masking the isa costs an extra instruction per object, though that can at least be shared for multiple method calls on the same object since we assume objects don't change class (at least not in ways that would change Swift method implementation or ivar layout). We do already pay this cost on Apple platforms for NSObject subclasses. More interestingly, Objective-C already uses non-pointer isa on ARM64, but not on x86-64. I'm not sure how flexible the ObjC implementation is here—Could Swift use non-pointer isas on platforms where ObjC doesn't? Could it ascribe different meanings to the bits from ObjC's?</div><div class=""><br class=""></div><div class="">-Joe</div></body></html>