1 /* 2 * Copyright (c) 2017, 2018, Red Hat, Inc. and/or its affiliates. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 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 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 * 22 */ 23 24 #include "precompiled.hpp" 25 26 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp" 27 #include "gc_implementation/shenandoah/shenandoahStrDedupQueue.hpp" 28 #include "gc_implementation/shenandoah/shenandoahStrDedupQueue.inline.hpp" 29 #include "gc_implementation/shenandoah/shenandoahStringDedup.hpp" 30 #include "memory/allocation.inline.hpp" 31 #include "runtime/atomic.hpp" 32 33 ShenandoahStrDedupQueue::ShenandoahStrDedupQueue(ShenandoahStrDedupQueueSet* queue_set, uint num) : 34 _queue_set(queue_set), _current_list(NULL), _queue_num(num) { 35 assert(num < _queue_set->num_queues(), "Not valid queue number"); 36 } 37 38 ShenandoahStrDedupQueue::~ShenandoahStrDedupQueue() { 39 if (_current_list != NULL) { 40 delete _current_list; 41 } 42 } 43 44 void ShenandoahStrDedupQueue::oops_do(OopClosure* cl) { 45 if (_current_list != NULL) { 46 _current_list->oops_do(cl); 47 } 48 } 49 50 ShenandoahStrDedupQueueSet::ShenandoahStrDedupQueueSet(uint n) : 51 _num_queues(n), _free_list(NULL), _num_free_queues(0), _terminated(false), _claimed(0) { 52 _lock = new Monitor(Mutex::leaf, "ShenandoahStrDedupQueueLock", false); 53 54 _local_queues = NEW_C_HEAP_ARRAY(ShenandoahStrDedupQueue*, num_queues(), mtGC); 55 _outgoing_work_list = NEW_C_HEAP_ARRAY(QueueChunkedList*, num_queues(), mtGC); 56 57 for (uint index = 0; index < num_queues(); index ++) { 58 _local_queues[index] = new ShenandoahStrDedupQueue(this, index); 59 _outgoing_work_list[index] = NULL; 60 } 61 } 62 63 ShenandoahStrDedupQueueSet::~ShenandoahStrDedupQueueSet() { 64 QueueChunkedList* q; 65 QueueChunkedList* tmp; 66 67 for (uint index = 0; index < num_queues(); index ++) { 68 if (_local_queues[index] != NULL) { 69 delete _local_queues[index]; 70 } 71 72 q = _outgoing_work_list[index]; 73 while (q != NULL) { 74 tmp = q; 75 q = q->next(); 76 delete tmp; 77 } 78 } 79 80 q = _free_list; 81 while (q != NULL) { 82 tmp = q; 83 q = tmp->next(); 84 delete tmp; 85 } 86 87 FREE_C_HEAP_ARRAY(ShenandoahStrDedupQueue*, _local_queues, mtGC); 88 FREE_C_HEAP_ARRAY(QueueChunkedList*, _outgoing_work_list, mtGC); 89 90 delete _lock; 91 } 92 93 94 size_t ShenandoahStrDedupQueueSet::claim() { 95 size_t index = (size_t)Atomic::add(1, (volatile jint*)&_claimed) - 1; 96 return index; 97 } 98 99 void ShenandoahStrDedupQueueSet::parallel_oops_do(OopClosure* cl) { 100 assert(cl != NULL, "No closure"); 101 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 102 size_t claimed_index; 103 while ((claimed_index = claim()) < num_queues()) { 104 queue_at(claimed_index)->oops_do(cl); 105 QueueChunkedList* head = _outgoing_work_list[claimed_index]; 106 while (head != NULL) { 107 head->oops_do(cl); 108 head = head->next(); 109 } 110 } 111 } 112 113 void ShenandoahStrDedupQueueSet::oops_do_slow(OopClosure* cl) { 114 assert(cl != NULL, "No closure"); 115 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); 116 for (size_t index = 0; index < num_queues(); index ++) { 117 queue_at(index)->oops_do(cl); 118 QueueChunkedList* head = _outgoing_work_list[index]; 119 while (head != NULL) { 120 head->oops_do(cl); 121 head = head->next(); 122 } 123 } 124 } 125 126 void ShenandoahStrDedupQueueSet::terminate() { 127 MonitorLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 128 _terminated = true; 129 locker.notify_all(); 130 } 131 132 void ShenandoahStrDedupQueueSet::release_chunked_list(QueueChunkedList* q) { 133 assert(q != NULL, "null queue"); 134 MutexLockerEx locker(lock(), Mutex::_no_safepoint_check_flag); 135 if (_num_free_queues >= 2 * num_queues()) { 136 delete q; 137 } else { 138 q->set_next(_free_list); 139 _free_list = q; 140 _num_free_queues ++; 141 } 142 } 143 144 QueueChunkedList* ShenandoahStrDedupQueueSet::allocate_no_lock() { 145 assert_lock_strong(lock()); 146 147 if (_free_list != NULL) { 148 QueueChunkedList* q = _free_list; 149 _free_list = _free_list->next(); 150 _num_free_queues --; 151 q->reset(); 152 return q; 153 } else { 154 return new QueueChunkedList(); 155 } 156 } 157 158 QueueChunkedList* ShenandoahStrDedupQueueSet::allocate_chunked_list() { 159 MutexLockerEx locker(_lock, Mutex::_no_safepoint_check_flag); 160 return allocate_no_lock(); 161 } 162 163 QueueChunkedList* ShenandoahStrDedupQueueSet::push_and_get_atomic(QueueChunkedList* q, uint queue_num) { 164 QueueChunkedList* head = _outgoing_work_list[queue_num]; 165 QueueChunkedList* result; 166 q->set_next(head); 167 while ((result = (QueueChunkedList*)Atomic::cmpxchg_ptr(q, &_outgoing_work_list[queue_num], head)) != head) { 168 head = result; 169 q->set_next(head); 170 } 171 172 { 173 MutexLockerEx locker(lock(), Mutex::_no_safepoint_check_flag); 174 q = allocate_no_lock(); 175 lock()->notify(); 176 } 177 return q; 178 } 179 180 QueueChunkedList* ShenandoahStrDedupQueueSet::remove_work_list_atomic(uint queue_num) { 181 assert(queue_num < num_queues(), "Invalid queue number"); 182 183 QueueChunkedList* list = _outgoing_work_list[queue_num]; 184 QueueChunkedList* result; 185 while ((result = (QueueChunkedList*)Atomic::cmpxchg_ptr((QueueChunkedList*)NULL, &_outgoing_work_list[queue_num], list)) != list) { 186 list = result; 187 } 188 189 return list; 190 } 191 192 void ShenandoahStrDedupQueueSet::parallel_cleanup() { 193 ShenandoahStrDedupQueueCleanupClosure cl; 194 parallel_oops_do(&cl); 195 }