1 /* 2 * Copyright (c) 2017, 2018, Red Hat, Inc. All rights reserved. 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 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUPQUEUE_HPP 25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUPQUEUE_HPP 26 27 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp" 28 #include "memory/iterator.hpp" 29 #include "oops/oop.hpp" 30 #include "runtime/mutex.hpp" 31 32 template <size_t SIZE> 33 class ShenandoahStrDedupChunkedList : public CHeapObj<mtGC> { 34 private: 35 oop _oops[SIZE]; 36 ShenandoahStrDedupChunkedList<SIZE>* _next; 37 uint _index; 38 39 public: 40 ShenandoahStrDedupChunkedList() : _next(NULL), _index(0) { } 41 42 inline bool is_full() const { return _index == SIZE; } 43 inline bool is_empty() const { return _index == 0; } 44 inline void push(oop obj) { assert(!is_full(), "List is full"); _oops[_index ++] = obj; } 45 inline oop pop() { assert(!is_empty(), "List is empty"); return _oops[--_index]; } 46 inline size_t size() const { return _index; } 47 inline void reset() { 48 _index = 0; 49 _next = NULL; 50 } 51 52 void set_next(ShenandoahStrDedupChunkedList<SIZE>* q) { _next = q; } 53 ShenandoahStrDedupChunkedList<SIZE>* next() const { return _next; } 54 55 void oops_do(OopClosure* cl) { 56 assert(cl != NULL, "null closure"); 57 for (uint index = 0; index < size(); index ++) { 58 cl->do_oop(&_oops[index]); 59 } 60 } 61 }; 62 63 class ShenandoahStrDedupQueueSet; 64 65 typedef ShenandoahStrDedupChunkedList<64> QueueChunkedList; 66 67 class ShenandoahStrDedupQueue : public CHeapObj<mtGC> { 68 private: 69 ShenandoahStrDedupQueueSet* _queue_set; 70 QueueChunkedList* _current_list; 71 uint _queue_num; 72 73 public: 74 ShenandoahStrDedupQueue(ShenandoahStrDedupQueueSet* queue_set, uint num); 75 ~ShenandoahStrDedupQueue(); 76 77 uint queue_num() const { return _queue_num; } 78 inline void push(oop java_string); 79 void oops_do(OopClosure* cl); 80 }; 81 82 class ShenandoahStrDedupThread; 83 84 class ShenandoahStrDedupQueueSet : public CHeapObj<mtGC> { 85 friend class ShenandoahStrDedupQueue; 86 friend class ShenandoahStrDedupThread; 87 88 private: 89 ShenandoahStrDedupQueue** _local_queues; 90 uint _num_queues; 91 QueueChunkedList* volatile * _outgoing_work_list; 92 93 QueueChunkedList* _free_list; 94 uint _num_free_queues; 95 96 Monitor* _lock; 97 98 bool _terminated; 99 100 volatile size_t _claimed; 101 102 public: 103 ShenandoahStrDedupQueueSet(uint n); 104 ~ShenandoahStrDedupQueueSet(); 105 106 uint num_queues() const { return num_queues_nv(); } 107 108 ShenandoahStrDedupQueue* queue_at(size_t index) { 109 assert(index < num_queues(), "Index out of bound"); 110 return _local_queues[index]; 111 } 112 113 void clear_claimed() { _claimed = 0; } 114 void parallel_cleanup(); 115 void parallel_oops_do(OopClosure* cl); 116 117 // For verification only 118 void oops_do_slow(OopClosure* cl); 119 120 void terminate(); 121 bool has_terminated() { 122 return _terminated; 123 } 124 125 private: 126 inline uint num_queues_nv() const { return _num_queues; } 127 128 void release_chunked_list(QueueChunkedList* l); 129 130 QueueChunkedList* allocate_chunked_list(); 131 QueueChunkedList* allocate_no_lock(); 132 133 // Atomic publish and retrieve outgoing work list. 134 // We don't have ABA problem, since there is only one dedup thread. 135 QueueChunkedList* push_and_get_atomic(QueueChunkedList* q, uint queue_num); 136 QueueChunkedList* remove_work_list_atomic(uint queue_num); 137 138 Monitor* lock() const { return _lock; } 139 140 size_t claim(); 141 }; 142 143 class ShenandoahStrDedupQueueCleanupClosure : public OopClosure { 144 private: 145 ShenandoahHeap* _heap; 146 ShenandoahMarkingContext* const _mark_context; 147 148 template <class T> 149 inline void do_oop_work(T* p); 150 public: 151 ShenandoahStrDedupQueueCleanupClosure() : _heap(ShenandoahHeap::heap()), 152 _mark_context(ShenandoahHeap::heap()->marking_context()) { 153 } 154 155 inline void do_oop(oop* p) { do_oop_work(p); } 156 inline void do_oop(narrowOop* p) { do_oop_work(p); } 157 }; 158 159 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUPQUEUE_HPP