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
��