RFR: Eliminate extra forwarding pointer per object

Aleksey Shipilev shade at redhat.com
Wed May 8 09:34:25 UTC 2019


On 5/7/19 9:49 PM, Roman Kennke wrote:
>> *) Maybe we should fork introducing new tmp to CAS? That would make the patch easier to backport, I
>> think.
> 
> Not sure. The change would make the register allocators free one more register but then not use it.
> I left it out of this iteration for now.

Yeah, the extra cleanness in the final patch might not worth the effort of doing the CAS change
beforehand. Maybe we should break some overly long lines in AArch64 CAS code (compare sh_aarch64.ad
and sh_x86_64.ad), while we are at it.


>> I actually think that we can keep ShenandoahBrooksPointer and put all that util code there. It would
>> still be doing its job: abstracting away the forwarding data handling.
> 
> I reinstated the ShenandoahForwarding utility class. However, it is hard to abstract the protocol
> because the two parts strictly belong together. However, this seems all the more reason to abstract
> it properly. The only thing that happens in between the two blocks is actually allocating and
> copying the object. So we could call into, say, ShenandoahForwarding::evacuate() which would do the
> prefix and suffix, and call back to say copy = ShHeap::allocate_and_copy(obj); or such for the
> payload. What do you think?

I don't understand off-hand why the protocol is different. For example, why do you need to drag
old_mark in SH:evacuate_object? You can still have try_update_forwardee to check that "old" mark is
not forwarded yet, and use that?

Pseudocode for try_update_forwardee:

// returns "true" on success
bool try_update_forwardee(p, copy_val):
  markOop old = p->mark_raw();
  if (old->is_marked()):
    return false;
  markOop new_mark = markOopDesc::encode_pointer_as_mark(copy_val);
  markOop prev_mark = p->cas_set_mark_raw(new_mark, old_mark);
  return prev_mark == old_mark;

...then:

if (try_update_forwardee(p, copy_val)):
  shenandoah_assert_correct(NULL, copy_val);
  return copy_val;
} else {
  return ShenandoahForwarding::get_forwardee(p);
}


>> *) In ShenandoahMarkCompact, do these need to be public?
>>
>>    76 public:
>>    77   void preserve_mark(oop obj);
>>    78   void restore_marks();
>>    79   void adjust_marks();
> 
> I forgot to mention ShenandoahMarkCompact. This completely overhauls how ShMarkCompact stores
> forwarding information. It's changed to basically work like other GCs and stores the forwarding in
> the mark-word. However, the mark word must sometimes be preserved. Therefore we store it to the
> side. The 3 methods above handle that. They are public because they are called from closures.
> Alternatively, we could make the closures friends of ShMarkCompact. ?

Yes, befriending closures would look cleaner, I think.

> Updated patch:
> http://cr.openjdk.java.net/~rkennke/eliminate-fwdptr/webrev.01/

Other nits:

 *) The dance like that needs some rationale/pseudo-code?

 326   Label done;
 327   __ movptr(tmp, Address(dst, oopDesc::mark_offset_in_bytes()));
 328   __ notptr(tmp);
 329   __ testb(tmp, markOopDesc::marked_value);
 330   __ jccb(Assembler::notZero, done);
 331   __ orptr(tmp, markOopDesc::marked_value);
 332   __ notptr(tmp);
 333   __ mov(dst, tmp);
 334   __ bind(done);

 *) In here, you can call get_forwardee_raw_unchecked to have only one shenandoah_assert_correct assert:

  45 inline oop ShenandoahForwarding::get_forwardee(oop obj) {
  46   shenandoah_assert_correct(NULL, obj);
  47   return oop(get_forwardee_raw(obj));
  48 }

-Aleksey



More information about the shenandoah-dev mailing list