JDK-7121623 : G1: always be able to reliably calculate the length of a forwarded chunked array
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: hs23
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-12-14
  • Updated: 2013-09-18
  • Resolved: 2012-03-29
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8 Other
7u4Fixed 8Fixed hs23Fixed
Related Reports
Relates :  
For the implementation of another CR (6484965: G1: piggy-back liveness accounting phase on marking) we need to be able to calculate the size of an object whose to-space image we mark during a GC. This is currently quite tricky given that if the object is already forwarded by another worker we cannot guarantee that the to-space image of said object is consistent (the other worker might still be in the process of copying the object, so when we try to read its to-image header we might get back junk).

One idea round this is to read the size from the object's from-image. This works most of the time apart from the case of chunked object arrays. For those we use the from-image length field to store the sarting index of the next chunk to process (and restore the real length when after we claim the last chunk). But, when we read such an array, we cannot be sure whether the length is the actual length or the next index.

The solution propose here to deal with the case of chunk object arrays is to always encode the index so that it is always negative before we store it in the from-image length field. We can easily do this with the following: -(index + 1) (+1 so that 0 is also encoded as a negative value). This way we can distinguish whether the length is really a valid length (>=0) or an encoded index (<0). In the latter case, and by being careful to only store the encoded index after we finish copying the object, we can simply read the correct length from the to-image of the object.
It turns out that the idea of using a negative value to encode the next index (in the length field of the from-image) does not work as it introduces a subtle race (see the Evaluation section for the details).

The alternative we'll try is to use the length field of the to-image (instead of the from-image) to keep track of the next index. This way, the from-image will always be consistent and we'll always be able to read the correct size from it.

EVALUATION http://hg.openjdk.java.net/lambda/lambda/hotspot/rev/02838862dec8

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/02838862dec8

PUBLIC COMMENTS Given that the proposed solution (described in the Description field) had a race (described in the Evaluation) field I ended up implementing an alternative which is to encode the next in index as before (i.e., the actual value of the next index) but store it in the to-space object, not the from-space object. This way, we can always reliably read the size of an object that is forwarded during a GC by reading it from the from-space.

EVALUATION http://hg.openjdk.java.net/hsx/hotspot-gc/hotspot/rev/02838862dec8

EVALUATION It turns out that the original proposal (use a negative length to encode the next index) has a subtle race. Below are the details from an e-mail I sent out. Let's assume two threads, A and B, are racing to forward the same object array X. Consider the following interleaving: Thread A: is X forwarded? no Thread B: is X forwarded? no size = X.size(); X' = allocate size try to forward X to X'? yes copy X to X' chunk X, X.length is negative Thread A: size = X.size(); -> BOOM, as size() just read a negative length Interesting this race exists today but it's benign due to either careful design or sheer luck. When A reads size = X.size() it will actually get a smaller size than the actual size of X and will allocate a chunk smaller than X (!!!). However, given that X is already forwarded it won't need to copy it and will undo the allocation. So, no harm done.

PUBLIC COMMENTS I should add: I'd like to fix and push this separately as it's self-contained and I'd like to get it tested separately.

EVALUATION See Description.