<html><body><p><font size="2">Dear all,</font><br><br><font size="2">Would you please review the following change?</font><br><font size="2">Bug: </font><a href="https://bugs.openjdk.java.net/browse/JDK-8205908"><font size="2">https://bugs.openjdk.java.net/browse/JDK-8205908</font></a><br><font size="2">Webrev: </font><a href="http://cr.openjdk.java.net/~mhorie/8205908/webrev.00/"><font size="2">http://cr.openjdk.java.net/~mhorie/8205908/webrev.00/</font></a><br><br><br><font size="2">[Current implementation]</font><br><font size="2">ParNewGeneration::copy_to_survivor_space tries to move live objects to a different location. There are two patterns on how to copy an object depending on whether there is space to allocate new_obj in to-space or not. If a thread cannot find space to allocate new_obj in to-space, the thread first executes the CAS with a dummy forwarding pointer "ClaimedForwardPtr", which is a sentinel to mark an object as claimed. After succeeding in the CAS, a thread can copy the new_obj in the old space. Here, suppose thread A succeeds in the CAS, while thread B fails in the CAS. When thread A finishes the copy, it replaces the dummy forwarding pointer with a real forwarding pointer. After thread B fails in the CAS, thread B returns the forwardee after waiting for the copy of the forwardee is completed. This is observable by checking the dummy forwarding pointer is replaced with a real forwarding pointer by thread A. In contrast, if a thread can find space to allocate new_obj in to-space, the thread first copies the new_obj and then executes the CAS with the new_obj. If a thread fails in the CAS, it deallocates the copied new_obj and returns the forwardee.</font><br><br><font size="2">Procedure of ParNewGeneration::copy_to_survivor_space : ([L****] represents the line number in src/hotspot/share/gc/cms/parNewGeneration.cpp) </font><br><font size="2">1. Try to each allocate space for new_obj in to-space [L.1110]</font><br><font size="2">2. If fail in the allocation in to-space [L1117] </font><br><font size="2"> 2.1. Execute the CAS with the dummy forwarding pointer [L1122] ——— (A)</font><br><font size="2"> 2.2. If fail in the CAS, return the forwardee via real_forwardee() [L1123]</font><br><font size="2"> 2.3. If succeed in the CAS [L1128] </font><br><font size="2"> 2.3.1. If promotion is allowed, copy new_obj in the old area [L1129]</font><br><font size="2"> 2.3.2. If promotion is not allowed, forward to obj itself [L1133]</font><br><font size="2"> 2.4. Set new_obj as forwardee [L1142]</font><br><font size="2">3. If succeed in the allocation in to-space [L1144] </font><br><font size="2"> 3.1. Copy new_obj [L1146]</font><br><font size="2"> 3.2. Execute the CAS with new_obj [L1148] ——— (B)</font><br><font size="2">4. Dereference the new_obj for logging. Each new_obj copied by each thread at step 3.1 is used instead of forwardee() [L1159]</font><br><font size="2">5. If succeed in either CAS (A) or CAS (B), return new_obj [L1163]</font><br><font size="2">6. If fail in CAS (B), get the forwardee via real_forwardee(). Unallocate new_obj in to-space [L1193]</font><br><font size="2">7. Return forwardee [L1203]</font><br><br><font size="2">For reference, real_forwardee() is as shown below:</font><br><font size="2">oop ParNewGeneration::real_forwardee(oop obj) {</font><br><font size="2"> oop forward_ptr = obj->forwardee();</font><br><font size="2"> if (forward_ptr != ClaimedForwardPtr) {</font><br><font size="2"> return forward_ptr;</font><br><font size="2"> } else {</font><br><font size="2"> // manually inlined for readability.</font><br><font size="2"> oop forward_ptr = obj->forwardee();</font><br><font size="2"> while (forward_ptr == ClaimedForwardPtr) {</font><br><font size="2"> waste_some_time();</font><br><font size="2"> forward_ptr = obj->forwardee();</font><br><font size="2"> }</font><br><font size="2"> return forward_ptr;</font><br><font size="2"> }</font><br><font size="2">}</font><br><br><font size="2">Regarding the CAS (A),</font><br><font size="2">There is no copy before the CAS.</font><br><font size="2">Dereferencing the forwardee must be allowed after obtaining the forwardee.</font><br><br><font size="2">Regarding the CAS (B),</font><br><font size="2">There is a copy before the CAS.</font><br><font size="2">Dereferencing the forwardee must be allowed after obtaining the forwardee.</font><br><br><br><font size="2">[Observation on the current implementation]</font><br><font size="2">No fence is necessary before and after the CAS (A).</font><br><font size="2">Release barrier is necessary before the CAS (B).</font><br><font size="2">The forwardee_acquire() must be used instead of forwardee() in real_forwardee().</font><br><br><br><font size="2">[Performance measurement]</font><br><font size="2">The critical-jOPS of SPECjbb2015 improved by 12% with this change.</font><br><br><br><font size="2">Best regards,</font><br><font size="2">--</font><br><font size="2">Michihiro,</font><br><font size="2">IBM Research - Tokyo</font><BR>
</body></html>