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