src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp

Thu, 07 Apr 2011 09:53:20 -0700

author
johnc
date
Thu, 07 Apr 2011 09:53:20 -0700
changeset 2781
e1162778c1c8
parent 2314
f95d63e2154a
child 3119
4f41766176cf
permissions
-rw-r--r--

7009266: G1: assert(obj->is_oop_or_null(true )) failed: Error
Summary: A referent object that is only weakly reachable at the start of concurrent marking but is re-attached to the strongly reachable object graph during marking may not be marked as live. This can cause the reference object to be processed prematurely and leave dangling pointers to the referent object. Implement a read barrier for the java.lang.ref.Reference::referent field by intrinsifying the Reference.get() method, and intercepting accesses though JNI, reflection, and Unsafe, so that when a non-null referent object is read it is also logged in an SATB buffer.
Reviewed-by: kvn, iveresov, never, tonyp, dholmes

ysr@777 1 /*
trims@1907 2 * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
ysr@777 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ysr@777 4 *
ysr@777 5 * This code is free software; you can redistribute it and/or modify it
ysr@777 6 * under the terms of the GNU General Public License version 2 only, as
ysr@777 7 * published by the Free Software Foundation.
ysr@777 8 *
ysr@777 9 * This code is distributed in the hope that it will be useful, but WITHOUT
ysr@777 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ysr@777 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ysr@777 12 * version 2 for more details (a copy is included in the LICENSE file that
ysr@777 13 * accompanied this code).
ysr@777 14 *
ysr@777 15 * You should have received a copy of the GNU General Public License version
ysr@777 16 * 2 along with this work; if not, write to the Free Software Foundation,
ysr@777 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ysr@777 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
ysr@777 22 *
ysr@777 23 */
ysr@777 24
stefank@2314 25 #include "precompiled.hpp"
stefank@2314 26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
stefank@2314 27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
stefank@2314 28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
stefank@2314 29 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
stefank@2314 30 #include "memory/resourceArea.hpp"
stefank@2314 31 #include "runtime/handles.inline.hpp"
stefank@2314 32 #include "runtime/mutexLocker.hpp"
ysr@777 33
ysr@777 34 ConcurrentG1RefineThread::
iveresov@1230 35 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
iveresov@1230 36 int worker_id_offset, int worker_id) :
ysr@777 37 ConcurrentGCThread(),
iveresov@1230 38 _worker_id_offset(worker_id_offset),
iveresov@1229 39 _worker_id(worker_id),
iveresov@1229 40 _active(false),
iveresov@1229 41 _next(next),
iveresov@1546 42 _monitor(NULL),
ysr@777 43 _cg1r(cg1r),
iveresov@1546 44 _vtime_accum(0.0)
ysr@777 45 {
iveresov@1546 46
iveresov@1546 47 // Each thread has its own monitor. The i-th thread is responsible for signalling
iveresov@1546 48 // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
iveresov@1546 49 // thread. Monitors are also used to wake up the threads during termination.
iveresov@1546 50 // The 0th worker in notified by mutator threads and has a special monitor.
iveresov@1546 51 // The last worker is used for young gen rset size sampling.
iveresov@1546 52 if (worker_id > 0) {
iveresov@1546 53 _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
iveresov@1546 54 } else {
iveresov@1546 55 _monitor = DirtyCardQ_CBL_mon;
iveresov@1546 56 }
iveresov@1546 57 initialize();
ysr@777 58 create_and_start();
ysr@777 59 }
ysr@777 60
iveresov@1546 61 void ConcurrentG1RefineThread::initialize() {
iveresov@1546 62 if (_worker_id < cg1r()->worker_thread_num()) {
iveresov@1546 63 // Current thread activation threshold
iveresov@1546 64 _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
iveresov@1546 65 cg1r()->yellow_zone());
iveresov@1546 66 // A thread deactivates once the number of buffer reached a deactivation threshold
iveresov@1546 67 _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
iveresov@1546 68 } else {
iveresov@1546 69 set_active(true);
iveresov@1546 70 }
iveresov@1546 71 }
iveresov@1546 72
ysr@777 73 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
ysr@777 74 G1CollectedHeap* g1h = G1CollectedHeap::heap();
ysr@777 75 G1CollectorPolicy* g1p = g1h->g1_policy();
ysr@777 76 if (g1p->adaptive_young_list_length()) {
ysr@777 77 int regions_visited = 0;
johnc@1829 78 g1h->young_list()->rs_length_sampling_init();
johnc@1829 79 while (g1h->young_list()->rs_length_sampling_more()) {
johnc@1829 80 g1h->young_list()->rs_length_sampling_next();
ysr@777 81 ++regions_visited;
ysr@777 82
ysr@777 83 // we try to yield every time we visit 10 regions
ysr@777 84 if (regions_visited == 10) {
ysr@777 85 if (_sts.should_yield()) {
ysr@777 86 _sts.yield("G1 refine");
ysr@777 87 // we just abandon the iteration
ysr@777 88 break;
ysr@777 89 }
ysr@777 90 regions_visited = 0;
ysr@777 91 }
ysr@777 92 }
ysr@777 93
ysr@777 94 g1p->check_prediction_validity();
ysr@777 95 }
ysr@777 96 }
ysr@777 97
iveresov@1546 98 void ConcurrentG1RefineThread::run_young_rs_sampling() {
iveresov@1546 99 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 100 _vtime_start = os::elapsedVTime();
iveresov@1546 101 while(!_should_terminate) {
iveresov@1546 102 _sts.join();
iveresov@1546 103 sample_young_list_rs_lengths();
iveresov@1546 104 _sts.leave();
iveresov@1546 105
iveresov@1546 106 if (os::supports_vtime()) {
iveresov@1546 107 _vtime_accum = (os::elapsedVTime() - _vtime_start);
iveresov@1546 108 } else {
iveresov@1546 109 _vtime_accum = 0.0;
iveresov@1546 110 }
iveresov@1546 111
iveresov@1546 112 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
iveresov@1546 113 if (_should_terminate) {
iveresov@1546 114 break;
iveresov@1546 115 }
tonyp@1717 116 _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
iveresov@1546 117 }
iveresov@1546 118 }
iveresov@1546 119
iveresov@1546 120 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
iveresov@1546 121 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 122 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
iveresov@1546 123 while (!_should_terminate && !is_active()) {
iveresov@1546 124 _monitor->wait(Mutex::_no_safepoint_check_flag);
iveresov@1546 125 }
iveresov@1546 126 }
iveresov@1546 127
iveresov@1546 128 bool ConcurrentG1RefineThread::is_active() {
iveresov@1546 129 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 130 return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
iveresov@1546 131 }
iveresov@1546 132
iveresov@1546 133 void ConcurrentG1RefineThread::activate() {
iveresov@1546 134 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
iveresov@1546 135 if (_worker_id > 0) {
tonyp@1717 136 if (G1TraceConcRefinement) {
iveresov@1546 137 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 138 gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
iveresov@1546 139 _worker_id, _threshold, (int)dcqs.completed_buffers_num());
iveresov@1546 140 }
iveresov@1546 141 set_active(true);
iveresov@1546 142 } else {
iveresov@1546 143 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 144 dcqs.set_process_completed(true);
iveresov@1546 145 }
iveresov@1546 146 _monitor->notify();
iveresov@1546 147 }
iveresov@1546 148
iveresov@1546 149 void ConcurrentG1RefineThread::deactivate() {
iveresov@1546 150 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
iveresov@1546 151 if (_worker_id > 0) {
tonyp@1717 152 if (G1TraceConcRefinement) {
iveresov@1546 153 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 154 gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
iveresov@1546 155 _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
iveresov@1546 156 }
iveresov@1546 157 set_active(false);
iveresov@1546 158 } else {
iveresov@1546 159 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 160 dcqs.set_process_completed(false);
iveresov@1546 161 }
iveresov@1546 162 }
iveresov@1546 163
ysr@777 164 void ConcurrentG1RefineThread::run() {
ysr@777 165 initialize_in_thread();
ysr@777 166 wait_for_universe_init();
ysr@777 167
iveresov@1546 168 if (_worker_id >= cg1r()->worker_thread_num()) {
iveresov@1546 169 run_young_rs_sampling();
iveresov@1546 170 terminate();
johnc@1829 171 return;
iveresov@1546 172 }
iveresov@1546 173
iveresov@1546 174 _vtime_start = os::elapsedVTime();
ysr@777 175 while (!_should_terminate) {
iveresov@1229 176 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
iveresov@1546 177
iveresov@1546 178 // Wait for work
iveresov@1546 179 wait_for_completed_buffers();
iveresov@1546 180
iveresov@1546 181 if (_should_terminate) {
iveresov@1546 182 break;
iveresov@1229 183 }
iveresov@1229 184
iveresov@1546 185 _sts.join();
iveresov@1229 186
iveresov@1546 187 do {
iveresov@1546 188 int curr_buffer_num = (int)dcqs.completed_buffers_num();
iveresov@1546 189 // If the number of the buffers falls down into the yellow zone,
iveresov@1546 190 // that means that the transition period after the evacuation pause has ended.
iveresov@1546 191 if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
iveresov@1546 192 dcqs.set_completed_queue_padding(0);
iveresov@1546 193 }
iveresov@1229 194
iveresov@1546 195 if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
iveresov@1229 196 // If the number of the buffer has fallen below our threshold
iveresov@1229 197 // we should deactivate. The predecessor will reactivate this
iveresov@1229 198 // thread should the number of the buffers cross the threshold again.
iveresov@1229 199 deactivate();
iveresov@1229 200 break;
iveresov@1229 201 }
iveresov@1229 202
iveresov@1229 203 // Check if we need to activate the next thread.
iveresov@1546 204 if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
iveresov@1229 205 _next->activate();
iveresov@1229 206 }
iveresov@1546 207 } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
iveresov@1229 208
iveresov@1546 209 // We can exit the loop above while being active if there was a yield request.
iveresov@1546 210 if (is_active()) {
iveresov@1546 211 deactivate();
iveresov@1229 212 }
iveresov@1546 213
ysr@777 214 _sts.leave();
iveresov@1229 215
ysr@777 216 if (os::supports_vtime()) {
ysr@777 217 _vtime_accum = (os::elapsedVTime() - _vtime_start);
ysr@777 218 } else {
ysr@777 219 _vtime_accum = 0.0;
ysr@777 220 }
ysr@777 221 }
ysr@777 222 assert(_should_terminate, "just checking");
ysr@777 223 terminate();
ysr@777 224 }
ysr@777 225
ysr@777 226
ysr@777 227 void ConcurrentG1RefineThread::yield() {
tonyp@1717 228 if (G1TraceConcRefinement) {
tonyp@1717 229 gclog_or_tty->print_cr("G1-Refine-yield");
tonyp@1717 230 }
ysr@777 231 _sts.yield("G1 refine");
tonyp@1717 232 if (G1TraceConcRefinement) {
tonyp@1717 233 gclog_or_tty->print_cr("G1-Refine-yield-end");
tonyp@1717 234 }
ysr@777 235 }
ysr@777 236
ysr@777 237 void ConcurrentG1RefineThread::stop() {
ysr@777 238 // it is ok to take late safepoints here, if needed
ysr@777 239 {
ysr@777 240 MutexLockerEx mu(Terminator_lock);
ysr@777 241 _should_terminate = true;
ysr@777 242 }
ysr@777 243
ysr@777 244 {
iveresov@1546 245 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
iveresov@1546 246 _monitor->notify();
ysr@777 247 }
ysr@777 248
ysr@777 249 {
ysr@777 250 MutexLockerEx mu(Terminator_lock);
ysr@777 251 while (!_has_terminated) {
ysr@777 252 Terminator_lock->wait();
ysr@777 253 }
ysr@777 254 }
tonyp@1717 255 if (G1TraceConcRefinement) {
tonyp@1717 256 gclog_or_tty->print_cr("G1-Refine-stop");
tonyp@1717 257 }
ysr@777 258 }
ysr@777 259
tonyp@1454 260 void ConcurrentG1RefineThread::print() const {
tonyp@1454 261 print_on(tty);
ysr@777 262 }
tonyp@1454 263
tonyp@1454 264 void ConcurrentG1RefineThread::print_on(outputStream* st) const {
tonyp@1454 265 st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
tonyp@1454 266 Thread::print_on(st);
tonyp@1454 267 st->cr();
tonyp@1454 268 }

mercurial