Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp
38921 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "gc_implementation/g1/dirtyCardQueue.hpp"26#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"27#include "gc_implementation/g1/heapRegionRemSet.hpp"28#include "runtime/atomic.hpp"29#include "runtime/mutexLocker.hpp"30#include "runtime/safepoint.hpp"31#include "runtime/thread.inline.hpp"32#include "utilities/workgroup.hpp"3334bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,35bool consume,36uint worker_i) {37bool res = true;38if (_buf != NULL) {39res = apply_closure_to_buffer(cl, _buf, _index, _sz,40consume,41worker_i);42if (res && consume) _index = _sz;43}44return res;45}4647bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,48void** buf,49size_t index, size_t sz,50bool consume,51uint worker_i) {52if (cl == NULL) return true;53for (size_t i = index; i < sz; i += oopSize) {54int ind = byte_index_to_index((int)i);55jbyte* card_ptr = (jbyte*)buf[ind];56if (card_ptr != NULL) {57// Set the entry to null, so we don't do it again (via the test58// above) if we reconsider this buffer.59if (consume) buf[ind] = NULL;60if (!cl->do_card_ptr(card_ptr, worker_i)) return false;61}62}63return true;64}6566#ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away67#pragma warning( disable:4355 ) // 'this' : used in base member initializer list68#endif // _MSC_VER6970DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :71PtrQueueSet(notify_when_complete),72_mut_process_closure(NULL),73_shared_dirty_card_queue(this, true /*perm*/),74_free_ids(NULL),75_processed_buffers_mut(0), _processed_buffers_rs_thread(0)76{77_all_active = true;78}7980// Determines how many mutator threads can process the buffers in parallel.81uint DirtyCardQueueSet::num_par_ids() {82return (uint)os::initial_active_processor_count();83}8485void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl, Monitor* cbl_mon, Mutex* fl_lock,86int process_completed_threshold,87int max_completed_queue,88Mutex* lock, PtrQueueSet* fl_owner) {89_mut_process_closure = cl;90PtrQueueSet::initialize(cbl_mon, fl_lock, process_completed_threshold,91max_completed_queue, fl_owner);92set_buffer_size(G1UpdateBufferSize);93_shared_dirty_card_queue.set_lock(lock);94_free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);95}9697void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {98t->dirty_card_queue().handle_zero_index();99}100101void DirtyCardQueueSet::iterate_closure_all_threads(CardTableEntryClosure* cl,102bool consume,103uint worker_i) {104assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");105for(JavaThread* t = Threads::first(); t; t = t->next()) {106bool b = t->dirty_card_queue().apply_closure(cl, consume);107guarantee(b, "Should not be interrupted.");108}109bool b = shared_dirty_card_queue()->apply_closure(cl,110consume,111worker_i);112guarantee(b, "Should not be interrupted.");113}114115bool DirtyCardQueueSet::mut_process_buffer(void** buf) {116117// Used to determine if we had already claimed a par_id118// before entering this method.119bool already_claimed = false;120121// We grab the current JavaThread.122JavaThread* thread = JavaThread::current();123124// We get the the number of any par_id that this thread125// might have already claimed.126uint worker_i = thread->get_claimed_par_id();127128// If worker_i is not UINT_MAX then the thread has already claimed129// a par_id. We make note of it using the already_claimed value130if (worker_i != UINT_MAX) {131already_claimed = true;132} else {133134// Otherwise we need to claim a par id135worker_i = _free_ids->claim_par_id();136137// And store the par_id value in the thread138thread->set_claimed_par_id(worker_i);139}140141bool b = false;142if (worker_i != UINT_MAX) {143b = DirtyCardQueue::apply_closure_to_buffer(_mut_process_closure, buf, 0,144_sz, true, worker_i);145if (b) Atomic::inc(&_processed_buffers_mut);146147// If we had not claimed an id before entering the method148// then we must release the id.149if (!already_claimed) {150151// we release the id152_free_ids->release_par_id(worker_i);153154// and set the claimed_id in the thread to UINT_MAX155thread->set_claimed_par_id(UINT_MAX);156}157}158return b;159}160161162BufferNode*163DirtyCardQueueSet::get_completed_buffer(int stop_at) {164BufferNode* nd = NULL;165MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);166167if ((int)_n_completed_buffers <= stop_at) {168_process_completed = false;169return NULL;170}171172if (_completed_buffers_head != NULL) {173nd = _completed_buffers_head;174_completed_buffers_head = nd->next();175if (_completed_buffers_head == NULL)176_completed_buffers_tail = NULL;177_n_completed_buffers--;178assert(_n_completed_buffers >= 0, "Invariant");179}180debug_only(assert_completed_buffer_list_len_correct_locked());181return nd;182}183184bool DirtyCardQueueSet::185apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,186uint worker_i,187BufferNode* nd) {188if (nd != NULL) {189void **buf = BufferNode::make_buffer_from_node(nd);190size_t index = nd->index();191bool b =192DirtyCardQueue::apply_closure_to_buffer(cl, buf,193index, _sz,194true, worker_i);195if (b) {196deallocate_buffer(buf);197return true; // In normal case, go on to next buffer.198} else {199enqueue_complete_buffer(buf, index);200return false;201}202} else {203return false;204}205}206207bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl,208uint worker_i,209int stop_at,210bool during_pause) {211assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");212BufferNode* nd = get_completed_buffer(stop_at);213bool res = apply_closure_to_completed_buffer_helper(cl, worker_i, nd);214if (res) Atomic::inc(&_processed_buffers_rs_thread);215return res;216}217218void DirtyCardQueueSet::apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {219BufferNode* nd = _completed_buffers_head;220while (nd != NULL) {221bool b =222DirtyCardQueue::apply_closure_to_buffer(cl,223BufferNode::make_buffer_from_node(nd),2240, _sz, false);225guarantee(b, "Should not stop early.");226nd = nd->next();227}228}229230void DirtyCardQueueSet::par_apply_closure_to_all_completed_buffers(CardTableEntryClosure* cl) {231BufferNode* nd = _cur_par_buffer_node;232while (nd != NULL) {233BufferNode* next = (BufferNode*)nd->next();234BufferNode* actual = (BufferNode*)Atomic::cmpxchg_ptr((void*)next, (volatile void*)&_cur_par_buffer_node, (void*)nd);235if (actual == nd) {236bool b =237DirtyCardQueue::apply_closure_to_buffer(cl,238BufferNode::make_buffer_from_node(actual),2390, _sz, false);240guarantee(b, "Should not stop early.");241nd = next;242} else {243nd = actual;244}245}246}247248// Deallocates any completed log buffers249void DirtyCardQueueSet::clear() {250BufferNode* buffers_to_delete = NULL;251{252MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);253while (_completed_buffers_head != NULL) {254BufferNode* nd = _completed_buffers_head;255_completed_buffers_head = nd->next();256nd->set_next(buffers_to_delete);257buffers_to_delete = nd;258}259_n_completed_buffers = 0;260_completed_buffers_tail = NULL;261debug_only(assert_completed_buffer_list_len_correct_locked());262}263while (buffers_to_delete != NULL) {264BufferNode* nd = buffers_to_delete;265buffers_to_delete = nd->next();266deallocate_buffer(BufferNode::make_buffer_from_node(nd));267}268269}270271void DirtyCardQueueSet::abandon_logs() {272assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");273clear();274// Since abandon is done only at safepoints, we can safely manipulate275// these queues.276for (JavaThread* t = Threads::first(); t; t = t->next()) {277t->dirty_card_queue().reset();278}279shared_dirty_card_queue()->reset();280}281282283void DirtyCardQueueSet::concatenate_logs() {284// Iterate over all the threads, if we find a partial log add it to285// the global list of logs. Temporarily turn off the limit on the number286// of outstanding buffers.287int save_max_completed_queue = _max_completed_queue;288_max_completed_queue = max_jint;289assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");290for (JavaThread* t = Threads::first(); t; t = t->next()) {291DirtyCardQueue& dcq = t->dirty_card_queue();292if (dcq.size() != 0) {293void **buf = t->dirty_card_queue().get_buf();294// We must NULL out the unused entries, then enqueue.295for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) {296buf[PtrQueue::byte_index_to_index((int)i)] = NULL;297}298enqueue_complete_buffer(dcq.get_buf(), dcq.get_index());299dcq.reinitialize();300}301}302if (_shared_dirty_card_queue.size() != 0) {303enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(),304_shared_dirty_card_queue.get_index());305_shared_dirty_card_queue.reinitialize();306}307// Restore the completed buffer queue limit.308_max_completed_queue = save_max_completed_queue;309}310311312