RFR(M): 7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error

John Cuthbertson john.cuthbertson at oracle.com
Fri Mar 11 17:34:50 PST 2011


Hi Everyone,

I'm looking for a few of volunteers to review the changes that fix this 
assertion failure. The latest changes can be found at: 
http://cr.openjdk.java.net/~johnc/7009266/webrev.3/ and include changes 
based upon earlier internal reviews. The earlier changes are also on 
cr.openjdk.java.net for reference.

Background:
The G1 garbage collector includes a concurrent marking algorithm that 
makes use of snapshot-at-the-beginning or SATB. With this algorithm the 
GC will mark all objects that are reachable at the start of marking; 
objects that are allocated since the start of marking are implicitly 
considered live. In order to populate the "snapshot" of the object graph 
that existed at the start of marking, G1 employs a write barrier. When 
an object is stored into another object's field the write-barrier 
records the previous value of that field as it was part of the 
"snapshot" and concurrent marking will trace the sub-graph that is 
reachable from this previous value.

Unfortunately, in the presence of Reference objects, SATB might not be 
sufficient to mark a referent object as live. Consider that, at the 
start of marking, we have a weakly reachable object i.e. an object where 
the only pointer to that object. If the referent is obtained from the 
Reference object and stored to another object's field (making the 
referent now strongly reachable and hence live) the G1 write barrier 
will record the field's previous value but not the value of the referent.

If the referent object is strongly reachable from some other object that 
will be traced by concurrent marking, _or_ there is a subsequent 
assignment to the field where we have written the referent (in which 
case we record the previous value - the referent - in an SATB buffer) 
then the referent will be marked live. Otherwise the referent will not 
be marked.

That is the issue that was causing the failure in this CR. There was a 
Logger object that was only reachable through a WeakReference at the 
start of concurrent marking. During marking the Logger object is 
obtained from the WeakReference and stored into a field of a live 
object. The G1 write barrier recorded the previous value in the field 
(as it is part of the snapshot at the start of marking). Since there was 
no other assignment to the live object's field and there was no other 
strong reference to the Logger object, the Logger object was not marked. 
At the end of concurrent marking the Logger object was considered dead 
and the link between the WeakReference and the Logger was severed by 
clearing the referent field during reference processing.

To solve this (entirely in Hotspot and causing a performance overhead 
for G1 only) it was decided that the best approach was to intrinsify the 
Reference.get() method in the JIT compilers and add new interpreter 
entry points so that the value in the referent field will be recorded in 
an SATB buffer by the G1 pre-barrier code.

The changes for Zero and the C++ interpreters are place holder routines 
but should be straight forward to implement.

None of the individual changes is large - they are just well distributed 
around the JVM. :)

Testing: white box test; eyeballing the generated compiled and 
interpreter code; the failing Kitchensink big-app on x86 (32/64 bit), 
sparc (32/64 bit), Xint, Xcomp (client and server), with and without G1; 
the GC test suite with and without G1; and jprt.

Thanks and regards,

JohnC


More information about the hotspot-gc-dev mailing list