b63b9a2edb
Reviewed-by: iignatyev, zgu
250 lines
7.5 KiB
C++
250 lines
7.5 KiB
C++
/*
|
|
* Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*
|
|
*/
|
|
|
|
#include "precompiled.hpp"
|
|
|
|
#include "gc/shared/stringdedup/stringDedup.hpp"
|
|
#include "gc/shared/stringdedup/stringDedupThread.hpp"
|
|
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
|
|
#include "gc/shenandoah/shenandoahStrDedupQueue.inline.hpp"
|
|
#include "gc/shenandoah/shenandoahStringDedup.inline.hpp"
|
|
#include "logging/log.hpp"
|
|
#include "runtime/mutex.hpp"
|
|
#include "runtime/mutexLocker.hpp"
|
|
|
|
ShenandoahStrDedupQueue::ShenandoahStrDedupQueue() :
|
|
_consumer_queue(NULL),
|
|
_num_producer_queue(ShenandoahHeap::heap()->max_workers()),
|
|
_published_queues(NULL),
|
|
_free_list(NULL),
|
|
_num_free_buffer(0),
|
|
_max_free_buffer(ShenandoahHeap::heap()->max_workers() * 2),
|
|
_cancel(false),
|
|
_total_buffers(0) {
|
|
_producer_queues = NEW_C_HEAP_ARRAY(ShenandoahQueueBuffer*, _num_producer_queue, mtGC);
|
|
for (size_t index = 0; index < _num_producer_queue; index ++) {
|
|
_producer_queues[index] = NULL;
|
|
}
|
|
}
|
|
|
|
ShenandoahStrDedupQueue::~ShenandoahStrDedupQueue() {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
for (size_t index = 0; index < num_queues(); index ++) {
|
|
release_buffers(queue_at(index));
|
|
}
|
|
|
|
release_buffers(_free_list);
|
|
FREE_C_HEAP_ARRAY(ShenandoahQueueBuffer*, _producer_queues);
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::wait_impl() {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
while (_consumer_queue == NULL && !_cancel) {
|
|
ml.wait();
|
|
assert(_consumer_queue == NULL, "Why wait?");
|
|
_consumer_queue = _published_queues;
|
|
_published_queues = NULL;
|
|
}
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::cancel_wait_impl() {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
_cancel = true;
|
|
ml.notify();
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::unlink_or_oops_do_impl(StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) {
|
|
ShenandoahQueueBuffer* q = queue_at(queue);
|
|
while (q != NULL) {
|
|
q->unlink_or_oops_do(cl);
|
|
q = q->next();
|
|
}
|
|
}
|
|
|
|
ShenandoahQueueBuffer* ShenandoahStrDedupQueue::queue_at(size_t queue_id) const {
|
|
assert(queue_id <= num_queues(), "Invalid queue id");
|
|
if (queue_id < _num_producer_queue) {
|
|
return _producer_queues[queue_id];
|
|
} else if (queue_id == _num_producer_queue) {
|
|
return _consumer_queue;
|
|
} else {
|
|
assert(queue_id == _num_producer_queue + 1, "Must be");
|
|
return _published_queues;
|
|
}
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::set_producer_buffer(ShenandoahQueueBuffer* buf, size_t queue_id) {
|
|
assert(queue_id < _num_producer_queue, "Not a producer queue id");
|
|
_producer_queues[queue_id] = buf;
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::push_impl(uint worker_id, oop string_oop) {
|
|
assert(worker_id < _num_producer_queue, "Invalid queue id. Can only push to producer queue");
|
|
assert(ShenandoahStringDedup::is_candidate(string_oop), "Not a candidate");
|
|
|
|
ShenandoahQueueBuffer* buf = queue_at((size_t)worker_id);
|
|
|
|
if (buf == NULL) {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
buf = new_buffer();
|
|
set_producer_buffer(buf, worker_id);
|
|
} else if (buf->is_full()) {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
buf->set_next(_published_queues);
|
|
_published_queues = buf;
|
|
buf = new_buffer();
|
|
set_producer_buffer(buf, worker_id);
|
|
ml.notify();
|
|
}
|
|
|
|
assert(!buf->is_full(), "Sanity");
|
|
buf->push(string_oop);
|
|
}
|
|
|
|
oop ShenandoahStrDedupQueue::pop_impl() {
|
|
assert(Thread::current() == StringDedupThread::thread(), "Must be dedup thread");
|
|
while (true) {
|
|
if (_consumer_queue == NULL) {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
_consumer_queue = _published_queues;
|
|
_published_queues = NULL;
|
|
}
|
|
|
|
// there is nothing
|
|
if (_consumer_queue == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
oop obj = NULL;
|
|
if (pop_candidate(obj)) {
|
|
assert(ShenandoahStringDedup::is_candidate(obj), "Must be a candidate");
|
|
return obj;
|
|
}
|
|
assert(obj == NULL, "No more candidate");
|
|
}
|
|
}
|
|
|
|
bool ShenandoahStrDedupQueue::pop_candidate(oop& obj) {
|
|
ShenandoahQueueBuffer* to_release = NULL;
|
|
bool suc = true;
|
|
do {
|
|
if (_consumer_queue->is_empty()) {
|
|
ShenandoahQueueBuffer* buf = _consumer_queue;
|
|
_consumer_queue = _consumer_queue->next();
|
|
buf->set_next(to_release);
|
|
to_release = buf;
|
|
|
|
if (_consumer_queue == NULL) {
|
|
suc = false;
|
|
break;
|
|
}
|
|
}
|
|
obj = _consumer_queue->pop();
|
|
} while (obj == NULL);
|
|
|
|
if (to_release != NULL) {
|
|
MonitorLocker ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag);
|
|
release_buffers(to_release);
|
|
}
|
|
|
|
return suc;
|
|
}
|
|
|
|
ShenandoahQueueBuffer* ShenandoahStrDedupQueue::new_buffer() {
|
|
assert_lock_strong(StringDedupQueue_lock);
|
|
if (_free_list != NULL) {
|
|
assert(_num_free_buffer > 0, "Sanity");
|
|
ShenandoahQueueBuffer* buf = _free_list;
|
|
_free_list = _free_list->next();
|
|
_num_free_buffer --;
|
|
buf->reset();
|
|
return buf;
|
|
} else {
|
|
assert(_num_free_buffer == 0, "Sanity");
|
|
_total_buffers ++;
|
|
return new ShenandoahQueueBuffer;
|
|
}
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::release_buffers(ShenandoahQueueBuffer* list) {
|
|
assert_lock_strong(StringDedupQueue_lock);
|
|
while (list != NULL) {
|
|
ShenandoahQueueBuffer* tmp = list;
|
|
list = list->next();
|
|
if (_num_free_buffer < _max_free_buffer) {
|
|
tmp->set_next(_free_list);
|
|
_free_list = tmp;
|
|
_num_free_buffer ++;
|
|
} else {
|
|
_total_buffers --;
|
|
delete tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::print_statistics_impl() {
|
|
Log(gc, stringdedup) log;
|
|
log.debug(" Queue:");
|
|
log.debug(" Total buffers: " SIZE_FORMAT " (" SIZE_FORMAT " %s). " SIZE_FORMAT " buffers are on free list",
|
|
_total_buffers,
|
|
byte_size_in_proper_unit(_total_buffers * sizeof(ShenandoahQueueBuffer)),
|
|
proper_unit_for_byte_size(_total_buffers * sizeof(ShenandoahQueueBuffer)),
|
|
_num_free_buffer);
|
|
}
|
|
|
|
class VerifyQueueClosure : public OopClosure {
|
|
private:
|
|
ShenandoahHeap* _heap;
|
|
public:
|
|
VerifyQueueClosure();
|
|
|
|
void do_oop(oop* o);
|
|
void do_oop(narrowOop* o) {
|
|
ShouldNotCallThis();
|
|
}
|
|
};
|
|
|
|
VerifyQueueClosure::VerifyQueueClosure() :
|
|
_heap(ShenandoahHeap::heap()) {
|
|
}
|
|
|
|
void VerifyQueueClosure::do_oop(oop* o) {
|
|
if (*o != NULL) {
|
|
oop obj = *o;
|
|
shenandoah_assert_correct(o, obj);
|
|
assert(java_lang_String::is_instance(obj), "Object must be a String");
|
|
}
|
|
}
|
|
|
|
void ShenandoahStrDedupQueue::verify_impl() {
|
|
VerifyQueueClosure vcl;
|
|
for (size_t index = 0; index < num_queues(); index ++) {
|
|
ShenandoahQueueBuffer* buf = queue_at(index);
|
|
while (buf != NULL) {
|
|
buf->oops_do(&vcl);
|
|
buf = buf->next();
|
|
}
|
|
}
|
|
}
|