1 /* 2 * Copyright (c) 2013, 2015, 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_SHENANDOAHCONCURRENTMARK_HPP 25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_HPP 26 27 #include "gc/shared/taskqueue.hpp" 28 #include "gc/shared/workgroup.hpp" 29 #include "gc/shenandoah/shenandoahTaskqueue.hpp" 30 #include "gc/shenandoah/shenandoahOopClosures.hpp" 31 32 typedef ObjArrayChunkedTask SCMTask; 33 typedef BufferedOverflowTaskQueue<SCMTask, mtGC> ShenandoahBufferedOverflowTaskQueue; 34 typedef Padded<ShenandoahBufferedOverflowTaskQueue> SCMObjToScanQueue; 35 36 #ifdef ASSERT 37 class ShenandoahVerifyRootsClosure1 : public OopClosure { 38 private: 39 template <class T> 40 inline void do_oop_work(T* p); 41 42 public: 43 void do_oop(oop* p); 44 void do_oop(narrowOop* p); 45 }; 46 #endif 47 48 class ShenandoahConcurrentMark: public CHeapObj<mtGC> { 49 50 private: 51 ShenandoahHeap* _heap; 52 53 // The per-worker-thread work queues 54 SCMObjToScanQueueSet* _task_queues; 55 56 bool _process_references; 57 bool _unload_classes; 58 59 jbyte _claimed_codecache; 60 61 // Used for buffering per-region liveness data. 62 // Needed since ShenandoahHeapRegion uses atomics to update liveness. 63 // 64 // The array has max-workers elements, each of which is an array of 65 // jushort * max_regions. The choice of jushort is not accidental: 66 // there is a tradeoff between static/dynamic footprint that translates 67 // into cache pressure (which is already high during marking), and 68 // too many atomic updates. size_t/jint is too large, jbyte is too small. 69 jushort** _liveness_local; 70 71 private: 72 template <class T, bool COUNT_LIVENESS> 73 inline void do_task(SCMObjToScanQueue* q, T* cl, jushort* live_data, SCMTask* task); 74 75 template <class T> 76 inline void do_chunked_array_start(SCMObjToScanQueue* q, T* cl, oop array); 77 78 template <class T> 79 inline void do_chunked_array(SCMObjToScanQueue* q, T* cl, oop array, int chunk, int pow); 80 81 inline void count_liveness(jushort* live_data, oop obj); 82 83 // Actual mark loop with closures set up 84 template <class T, bool CANCELLABLE, bool DRAIN_SATB, bool COUNT_LIVENESS> 85 void mark_loop_work(T* cl, jushort* live_data, uint worker_id, ParallelTaskTerminator *t); 86 87 template <bool CANCELLABLE, bool DRAIN_SATB, bool COUNT_LIVENESS, bool CLASS_UNLOAD, bool UPDATE_REFS, bool UPDATE_MATRIX> 88 void mark_loop_prework(uint worker_id, ParallelTaskTerminator *terminator, ReferenceProcessor *rp); 89 90 // ------------------------ Currying dynamic arguments to template args ---------------------------- 91 92 template <bool B1, bool B2, bool B3, bool B4, bool B5> 93 void mark_loop_5(uint w, ParallelTaskTerminator* t, ReferenceProcessor* rp, bool b6) { 94 if (b6) { 95 mark_loop_prework<B1, B2, B3, B4, B5, true>(w, t, rp); 96 } else { 97 mark_loop_prework<B1, B2, B3, B4, B5, false>(w, t, rp); 98 } 99 }; 100 101 template <bool B1, bool B2, bool B3, bool B4> 102 void mark_loop_4(uint w, ParallelTaskTerminator* t, ReferenceProcessor* rp, bool b5, bool b6) { 103 if (b5) { 104 mark_loop_5<B1, B2, B3, B4, true>(w, t, rp, b6); 105 } else { 106 mark_loop_5<B1, B2, B3, B4, false>(w, t, rp, b6); 107 } 108 }; 109 110 template <bool B1, bool B2, bool B3> 111 void mark_loop_3(uint w, ParallelTaskTerminator* t, ReferenceProcessor* rp, bool b4, bool b5, bool b6) { 112 if (b4) { 113 mark_loop_4<B1, B2, B3, true>(w, t, rp, b5, b6); 114 } else { 115 mark_loop_4<B1, B2, B3, false>(w, t, rp, b5, b6); 116 } 117 }; 118 119 template <bool B1, bool B2> 120 void mark_loop_2(uint w, ParallelTaskTerminator* t, ReferenceProcessor* rp, bool b3, bool b4, bool b5, bool b6) { 121 if (b3) { 122 mark_loop_3<B1, B2, true>(w, t, rp, b4, b5, b6); 123 } else { 124 mark_loop_3<B1, B2, false>(w, t, rp, b4, b5, b6); 125 } 126 }; 127 128 template <bool B1> 129 void mark_loop_1(uint w, ParallelTaskTerminator* t, ReferenceProcessor* rp, bool b2, bool b3, bool b4, bool b5, bool b6) { 130 if (b2) { 131 mark_loop_2<B1, true>(w, t, rp, b3, b4, b5, b6); 132 } else { 133 mark_loop_2<B1, false>(w, t, rp, b3, b4, b5, b6); 134 } 135 }; 136 137 // ------------------------ END: Currying dynamic arguments to template args ---------------------------- 138 139 public: 140 // We need to do this later when the heap is already created. 141 void initialize(uint workers); 142 143 void set_process_references(bool pr); 144 bool process_references() const; 145 146 void set_unload_classes(bool uc); 147 bool unload_classes() const; 148 149 bool claim_codecache(); 150 void clear_claim_codecache(); 151 152 template<class T, UpdateRefsMode UPDATE_REFS, bool UPDATE_MATRIX> 153 static inline void mark_through_ref(T* p, ShenandoahHeap* heap, SCMObjToScanQueue* q, ShenandoahConnectionMatrix* conn_matrix); 154 155 void mark_from_roots(); 156 157 // Prepares unmarked root objects by marking them and putting 158 // them into the marking task queue. 159 void init_mark_roots(); 160 void mark_roots(); 161 void update_roots(); 162 void final_update_roots(); 163 164 void shared_finish_mark_from_roots(bool full_gc); 165 void finish_mark_from_roots(); 166 // Those are only needed public because they're called from closures. 167 168 // Mark loop entry. 169 // Translates dynamic arguments to template parameters with progressive currying. 170 void mark_loop(uint worker_id, ParallelTaskTerminator* terminator, ReferenceProcessor *rp, 171 bool cancellable, bool drain_satb, bool count_liveness, bool class_unload, 172 bool update_refs, bool update_matrix) { 173 if (cancellable) { 174 mark_loop_1<true>(worker_id, terminator, rp, drain_satb, count_liveness, class_unload, update_refs, update_matrix); 175 } else { 176 mark_loop_1<false>(worker_id, terminator, rp, drain_satb, count_liveness, class_unload, update_refs, update_matrix); 177 } 178 } 179 180 inline bool try_queue(SCMObjToScanQueue* q, SCMTask &task); 181 182 SCMObjToScanQueue* get_queue(uint worker_id); 183 void clear_queue(SCMObjToScanQueue *q); 184 185 inline bool try_draining_satb_buffer(SCMObjToScanQueue *q, SCMTask &task); 186 void drain_satb_buffers(uint worker_id, bool remark = false); 187 SCMObjToScanQueueSet* task_queues() { return _task_queues;} 188 189 jushort* get_liveness(uint worker_id); 190 191 void cancel(); 192 193 private: 194 195 #ifdef ASSERT 196 void verify_roots(); 197 #endif 198 199 void weak_refs_work(); 200 201 #if TASKQUEUE_STATS 202 static void print_taskqueue_stats_hdr(outputStream* const st = tty); 203 void print_taskqueue_stats() const; 204 void reset_taskqueue_stats(); 205 #endif // TASKQUEUE_STATS 206 207 }; 208 209 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_HPP