> On Mar 16, 2016, at 9:25 AM, Joe Groff <jgr...@apple.com> wrote:
> 
> This sounds awesome. Should we still consider using a non-pointer isa 
> representation on 64 bit platforms? 16 bytes per object header is still kinda 
> big. If we laid out the np-isa bits so that the "side allocation" bit were 
> the MSB, and the strong refcount immediately below it, we could pull the same 
> trick letting the strong refcount overflow into the side allocation bit. 
> Drawbacks would be that we'd need to go back to a global sidetable to 
> reference the overflow allocation, and that on Apple platforms, we'd need to 
> follow whatever non-pointer-isa layout the Objective-C runtime uses, and the 
> exact layout of the bits would have to remain runtime-private and thus not 
> inlineable. If we're running on the assumption that side allocations are 
> rarely needed, then paying for the lock in the rare case might be worth a 
> potentially substantial memory savings.

Packing everything into a single 64-bit field is tricky but might work.

I think OS X and Linux x86_64 is the worst case currently, with 3 low bits and 
17 high bits available. Here's what libobjc stores in its isa field on x86_64:

 1 bit   is nonpointer
 1 bit   has associated references
 1 bit   has destructor
44 bits  class pointer
 6 bits  magic for tools
 1 bit   is weakly referenced
 1 bit   is deallocating
 1 bit   has additional refcount in side allocation
 8 bits  refcount

Some of those bits can be combined or reduced:

is-nonpointer is unnecessary as long as at least one of the bits outside the 
class pointer is set. There may be binary compatibility problems here, though. 
(Do existing Swift apps check that bit directly?)

has-associated-references and is-weakly-referenced and has-additional-refcount 
could be folded into a single has-sidetable bit. 

magic is needed for tools like `leaks` to distinguish real objects from 
non-object allocations. If the isa field is not a simple pointer then there are 
otherwise too many false objects for `leaks` to be usable. 6 bits is pushing 
the bare minimum here, but we might be able to trim this by making the tools 
smarter and more invasive. (For example: if the has-sidetable bit is set then 
look for a side allocation pointing back to the object. If you don't find one 
then it's not a real object.)  Being able to run `leaks` and `heap` on an 
unprepared process is an important capability, and I don't think we can afford 
to cripple it.

refcount can always be trimmed. I don't know what the shape of the "objects 
whose refcount is ever greater than X" curve looks like.


Given the above, we can claw back enough bits for things like a small unowned 
refcount and is-pinned or is-nonstructurally-mutating bits. 

My biggest concern is future Swift concurrency support. I suspect we will want 
storage for a thread ID or a lock. Maybe those would be uncommon enough that 
they can live in a side allocation. Will we want a thread ID in every 
thread-local object in production code so we can assert that it has not 
incorrectly escaped, or can we leave things like that for debug builds only?


One scheme that I want to investigate for ObjC's use is to allocate a flat 
array of side allocations, and store an index into that array in the isa 
field's extra bits. Depending on architecture that allows between 256K and 64M 
objects with side allocations before falling back to a global table. If that 
works well enough then packing everything into a single pointer-size field 
becomes more plausible.


Joe, did you measure the cost of a mask operation at every Swift virtual call? 
I can't remember.


-- 
Greg Parker     gpar...@apple.com     Runtime Wrangler


_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Reply via email to