Hi Eliot, On 4 December 2017 at 23:44, Eliot Miranda <eliot.miranda@gmail.com> wrote:
Alas a forwarding object has two fields that need to be set in separate
words.
The class index in the header must be the forwarder class index, and the first word of the object body must point to the forwarder.
Good to better understand that. Just restating after condensing most of the thread, only the Main-thread would convert objects to forwarders.
Reverting obviously requires two writes too. So atomic (un)forwarding is not possible.
sorry, just double-checking since I realised I erred in my example below, which may have mislead your response. IIUC(now)... while "creating" a forwarder involves writing separately to object-header and object-body. wouldn't "reverting" only involve updating an object-pointer in a slot to the real-object's new location? And that would be a single word operation on both 32bit and 64bit platforms?
- Currently the marking phase removes all forwarders and I would like incremental marking to maintain the same invariant (forwarders are always white).
A concurrent-marking thread could essentially do the same. i. From shared memory load forward header Fh from object-slot Fheader <== object-slot ii. Follow forwarder to real-object, store into local temporary Rheader <== flattened/followed pointer
iii. Atomic compare-and-swap R back into object-slot, object-slot <== if Fheader then Rheader
whoops, corrected... i. From shared memory, concurrent marking-scan has loaded an object-pointer from object-slot. If it points to a forwarding object ... Opointer <== object-slot (as part of normal marking scan) if *Opointer isForwardingObject { Fpointer <== Opointer (redundant, just for clarity) ii. Follow that to real-object, store into local temporary Rpointer <== followed Fpointer forwarding chain to real object. iii. Atomic compare-and-swap Rpointer back into object-slot object-slot <== if still Fpointer then Rpointer When (iii.) fails * If I'm the Main-thread, I'm in the middle of handling a failed forwarder-check and can infer the GC-thread already did what I was going to do. I can be certain that... "object-slot == Rpointer" (since thats the only object-slot mutation GC-threads can do) so its fine to continue to my usual post-flattening retry * If I'm a GC-thread, either: * the Main-thread flattened the forwarder, or * the Main-thread changed which object the slot holds In either case, just re-read the slot A race scenario to consider is where the Main-thread converts an object to a forwarder simultaneous with a GC-thread flattening one of its slots. The object copy in its new location may miss that update. But in terms of the object graph that seems not a problem, since the copy without that update is still consistent. Infrequently just a little bit of work is lost. I'm contemplating other race scenarios around marking, but won't distract with them for now. cheers -ben