pliden@6413: /* pliden@6413: * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. pliden@6413: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. pliden@6413: * pliden@6413: * This code is free software; you can redistribute it and/or modify it pliden@6413: * under the terms of the GNU General Public License version 2 only, as pliden@6413: * published by the Free Software Foundation. pliden@6413: * pliden@6413: * This code is distributed in the hope that it will be useful, but WITHOUT pliden@6413: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or pliden@6413: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License pliden@6413: * version 2 for more details (a copy is included in the LICENSE file that pliden@6413: * accompanied this code). pliden@6413: * pliden@6413: * You should have received a copy of the GNU General Public License version pliden@6413: * 2 along with this work; if not, write to the Free Software Foundation, pliden@6413: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. pliden@6413: * pliden@6413: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA pliden@6413: * or visit www.oracle.com if you need additional information or have any pliden@6413: * questions. pliden@6413: * pliden@6413: */ pliden@6413: pliden@6413: #include "precompiled.hpp" pliden@6413: #include "classfile/javaClasses.hpp" pliden@6413: #include "gc_implementation/g1/g1StringDedupQueue.hpp" pliden@6413: #include "memory/gcLocker.hpp" pliden@6413: #include "runtime/mutexLocker.hpp" pliden@6413: #include "utilities/stack.inline.hpp" pliden@6413: pliden@6413: G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; pliden@6413: const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue pliden@6413: const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue pliden@6413: pliden@6413: G1StringDedupQueue::G1StringDedupQueue() : pliden@6413: _cursor(0), pliden@6413: _empty(true), pliden@6413: _dropped(0) { pliden@6413: _nqueues = MAX2(ParallelGCThreads, (size_t)1); pliden@6413: _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); pliden@6413: for (size_t i = 0; i < _nqueues; i++) { pliden@6413: new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: G1StringDedupQueue::~G1StringDedupQueue() { pliden@6413: ShouldNotReachHere(); pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::create() { pliden@6413: assert(_queue == NULL, "One string deduplication queue allowed"); pliden@6413: _queue = new G1StringDedupQueue(); pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::wait() { pliden@6413: MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); pliden@6413: while (_queue->_empty) { pliden@6413: ml.wait(Mutex::_no_safepoint_check_flag); pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::push(uint worker_id, oop java_string) { pliden@6413: assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); pliden@6413: assert(worker_id < _queue->_nqueues, "Invalid queue"); pliden@6413: pliden@6413: // Push and notify waiter pliden@6413: G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; pliden@6413: if (!worker_queue.is_full()) { pliden@6413: worker_queue.push(java_string); pliden@6413: if (_queue->_empty) { pliden@6413: MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); pliden@6413: if (_queue->_empty) { pliden@6413: // Mark non-empty and notify waiter pliden@6413: _queue->_empty = false; pliden@6413: ml.notify(); pliden@6413: } pliden@6413: } pliden@6413: } else { pliden@6413: // Queue is full, drop the string and update the statistics pliden@6413: Atomic::inc_ptr(&_queue->_dropped); pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: oop G1StringDedupQueue::pop() { pliden@6413: assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); pliden@6413: No_Safepoint_Verifier nsv; pliden@6413: pliden@6413: // Try all queues before giving up pliden@6413: for (size_t tries = 0; tries < _queue->_nqueues; tries++) { pliden@6413: // The cursor indicates where we left of last time pliden@6413: G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; pliden@6413: while (!queue->is_empty()) { pliden@6413: oop obj = queue->pop(); pliden@6413: // The oop we pop can be NULL if it was marked pliden@6413: // dead. Just ignore those and pop the next oop. pliden@6413: if (obj != NULL) { pliden@6413: return obj; pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: // Try next queue pliden@6413: _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; pliden@6413: } pliden@6413: pliden@6413: // Mark empty pliden@6413: _queue->_empty = true; pliden@6413: pliden@6413: return NULL; pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { pliden@6413: // A worker thread first claims a queue, which ensures exclusive pliden@6413: // access to that queue, then continues to process it. pliden@6413: for (;;) { pliden@6413: // Grab next queue to scan pliden@6413: size_t queue = cl->claim_queue(); pliden@6413: if (queue >= _queue->_nqueues) { pliden@6413: // End of queues pliden@6413: break; pliden@6413: } pliden@6413: pliden@6413: // Scan the queue pliden@6413: unlink_or_oops_do(cl, queue); pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { pliden@6413: assert(queue < _queue->_nqueues, "Invalid queue"); pliden@6413: StackIterator iter(_queue->_queues[queue]); pliden@6413: while (!iter.is_empty()) { pliden@6413: oop* p = iter.next_addr(); pliden@6413: if (*p != NULL) { pliden@6413: if (cl->is_alive(*p)) { pliden@6413: cl->keep_alive(p); pliden@6413: } else { pliden@6413: // Clear dead reference pliden@6413: *p = NULL; pliden@6413: } pliden@6413: } pliden@6413: } pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::print_statistics(outputStream* st) { pliden@6413: st->print_cr( pliden@6413: " [Queue]\n" pliden@6413: " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); pliden@6413: } pliden@6413: pliden@6413: void G1StringDedupQueue::verify() { pliden@6413: for (size_t i = 0; i < _queue->_nqueues; i++) { pliden@6413: StackIterator iter(_queue->_queues[i]); pliden@6413: while (!iter.is_empty()) { pliden@6413: oop obj = iter.next(); pliden@6413: if (obj != NULL) { pliden@6413: guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); pliden@6413: guarantee(!obj->is_forwarded(), "Object must not be forwarded"); pliden@6413: guarantee(java_lang_String::is_instance(obj), "Object must be a String"); pliden@6413: } pliden@6413: } pliden@6413: } pliden@6413: }