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 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUPQUEUE_HPP 25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHSTRINGDEDUPQUEUE_HPP 26 27 #include "gc_implementation/shenandoah/shenandoahHeap.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 68 class ShenandoahStrDedupQueue : public CHeapObj<mtGC> { 69 private: 70 ShenandoahStrDedupQueueSet* _queue_set; 71 QueueChunkedList* _current_list; 72 uint _queue_num; 73 74 public: 75 ShenandoahStrDedupQueue(ShenandoahStrDedupQueueSet* queue_set, uint num); 76 ~ShenandoahStrDedupQueue(); 77 78 uint queue_num() const { return _queue_num; } 79 inline void push(oop java_string); 80 void oops_do(OopClosure* cl); 81 }; 82 83 class ShenandoahStrDedupThread; 84 85 class ShenandoahStrDedupQueueSet : public CHeapObj<mtGC> { 86 friend class ShenandoahStrDedupQueue; 87 friend class ShenandoahStrDedupThread; 88 89 private: 90 ShenandoahStrDedupQueue** _local_queues; 91 uint _num_queues; 92 QueueChunkedList* volatile * _outgoing_work_list; 93 94 QueueChunkedList* _free_list; 95 uint _num_free_queues; 96 97 Monitor* _lock; 98 99 bool _terminated; 100 101 volatile size_t _claimed; 102 103 public: 104 ShenandoahStrDedupQueueSet(uint n); 105 ~ShenandoahStrDedupQueueSet(); 106 107 uint num_queues() const { return _num_queues; } 108 109 ShenandoahStrDedupQueue* queue_at(size_t index) { 110 assert(index < num_queues(), "Index out of bound"); 111 return _local_queues[index]; 112 } 113 114 void clear_claimed() { _claimed = 0; } 115 void parallel_cleanup(); 116 void parallel_oops_do(OopClosure* cl); 117 118 // For verification only 119 void oops_do_slow(OopClosure* cl); 120 121 void terminate(); 122 bool has_terminated() { 123 return _terminated; 124 } 125 126 private: 127 void release_chunked_list(QueueChunkedList* l); 128 129 QueueChunkedList* allocate_chunked_list(); 130 QueueChunkedList* allocate_no_lock(); 131 132 // Atomic publish and retrieve outgoing work list. 133 // We don't have ABA problem, since there is only one dedup thread. 134 QueueChunkedList* push_and_get_atomic(QueueChunkedList* q, uint queue_num); 135 QueueChunkedList* remove_work_list_atomic(uint queue_num); 136 137 Monitor* lock() const { return _lock; } 138 139 size_t claim(); 140 }; 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()->next_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