1 /*
   2  * Copyright (c) 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_INLINE_HPP
  25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_INLINE_HPP
  26 
  27 #include "gc/shenandoah/brooksPointer.hpp"
  28 #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp"
  29 #include "gc/shenandoah/shenandoahConcurrentMark.hpp"
  30 #include "memory/iterator.inline.hpp"
  31 #include "oops/oop.inline.hpp"
  32 #include "runtime/prefetch.inline.hpp"
  33 
  34 template <class T, bool COUNT_LIVENESS>
  35 void ShenandoahConcurrentMark::do_task(ShenandoahObjToScanQueue* q, T* cl, jushort* live_data, ShenandoahMarkTask* task) {
  36   oop obj = task->obj();
  37 
  38   assert(obj != NULL, "expect non-null object");
  39   assert(oopDesc::unsafe_equals(obj, ShenandoahBarrierSet::resolve_oop_static_not_null(obj)), "expect forwarded obj in queue");
  40   assert(_heap->cancelled_concgc()
  41          || oopDesc::bs()->is_safe(obj),
  42          "we don't want to mark objects in from-space");
  43   assert(_heap->is_in(obj), "referenced objects must be in the heap. No?");
  44   assert(_heap->is_marked(obj), "only marked objects on task queue");
  45 
  46   if (task->is_not_chunked()) {
  47     if (COUNT_LIVENESS) count_liveness(live_data, obj);
  48     if (obj->is_instance()) {
  49       // Case 1: Normal oop, process as usual.
  50       obj->oop_iterate(cl);
  51     } else if (obj->is_objArray()) {
  52       // Case 2: Object array instance and no chunk is set. Must be the first
  53       // time we visit it, start the chunked processing.
  54       do_chunked_array_start<T>(q, cl, obj);
  55     } else {
  56       // Case 3: Primitive array. Do nothing, no oops there. We use the same
  57       // performance tweak TypeArrayKlass::oop_oop_iterate_impl is using:
  58       // We skip iterating over the klass pointer since we know that
  59       // Universe::TypeArrayKlass never moves.
  60       assert (obj->is_typeArray(), "should be type array");
  61     }
  62   } else {
  63     // Case 4: Array chunk, has sensible chunk id. Process it.
  64     do_chunked_array<T>(q, cl, obj, task->chunk(), task->pow());
  65   }
  66 }
  67 
  68 inline void ShenandoahConcurrentMark::count_liveness(jushort* live_data, oop obj) {
  69   size_t region_idx = _heap->heap_region_index_containing(obj);
  70   jushort cur = live_data[region_idx];
  71   int size = obj->size() + BrooksPointer::word_size();
  72   int max = (1 << (sizeof(jushort) * 8)) - 1;
  73   if (size >= max) {
  74     // too big, add to region data directly
  75     _heap->regions()->get(region_idx)->increase_live_data_words(size);
  76   } else {
  77     int new_val = cur + size;
  78     if (new_val >= max) {
  79       // overflow, flush to region data
  80       _heap->regions()->get(region_idx)->increase_live_data_words(new_val);
  81       live_data[region_idx] = 0;
  82     } else {
  83       // still good, remember in locals
  84       live_data[region_idx] = (jushort) new_val;
  85     }
  86   }
  87 }
  88 
  89 template <class T>
  90 inline void ShenandoahConcurrentMark::do_chunked_array_start(ShenandoahObjToScanQueue* q, T* cl, oop obj) {
  91   assert(obj->is_objArray(), "expect object array");
  92   objArrayOop array = objArrayOop(obj);
  93   int len = array->length();
  94 
  95   if (len <= (int) ObjArrayMarkingStride*2) {
  96     // A few slices only, process directly
  97     array->oop_iterate_range(cl, 0, len);
  98   } else {
  99     int bits = log2_long(len);
 100     // Compensate for non-power-of-two arrays, cover the array in excess:
 101     if (len != (1 << bits)) bits++;
 102 
 103     // Only allow full chunks on the queue. This frees do_chunked_array() from checking from/to
 104     // boundaries against array->length(), touching the array header on every chunk.
 105     //
 106     // To do this, we cut the prefix in full-sized chunks, and submit them on the queue.
 107     // If the array is not divided in chunk sizes, then there would be an irregular tail,
 108     // which we will process separately.
 109 
 110     int last_idx = 0;
 111 
 112     int chunk = 1;
 113     int pow = bits;
 114 
 115     // Handle overflow
 116     if (pow >= 31) {
 117       assert (pow == 31, "sanity");
 118       pow--;
 119       chunk = 2;
 120       last_idx = (1 << pow);
 121       bool pushed = q->push(ShenandoahMarkTask(array, 1, pow));
 122       assert(pushed, "overflow queue should always succeed pushing");
 123     }
 124 
 125     // Split out tasks, as suggested in ObjArrayChunkedTask docs. Record the last
 126     // successful right boundary to figure out the irregular tail.
 127     while ((1 << pow) > (int)ObjArrayMarkingStride &&
 128            (chunk*2 < ShenandoahMarkTask::chunk_size())) {
 129       pow--;
 130       int left_chunk = chunk*2 - 1;
 131       int right_chunk = chunk*2;
 132       int left_chunk_end = left_chunk * (1 << pow);
 133       if (left_chunk_end < len) {
 134         bool pushed = q->push(ShenandoahMarkTask(array, left_chunk, pow));
 135         assert(pushed, "overflow queue should always succeed pushing");
 136         chunk = right_chunk;
 137         last_idx = left_chunk_end;
 138       } else {
 139         chunk = left_chunk;
 140       }
 141     }
 142 
 143     // Process the irregular tail, if present
 144     int from = last_idx;
 145     if (from < len) {
 146       array->oop_iterate_range(cl, from, len);
 147     }
 148   }
 149 }
 150 
 151 template <class T>
 152 inline void ShenandoahConcurrentMark::do_chunked_array(ShenandoahObjToScanQueue* q, T* cl, oop obj, int chunk, int pow) {
 153   assert(obj->is_objArray(), "expect object array");
 154   objArrayOop array = objArrayOop(obj);
 155 
 156   assert (ObjArrayMarkingStride > 0, "sanity");
 157 
 158   // Split out tasks, as suggested in ObjArrayChunkedTask docs. Avoid pushing tasks that
 159   // are known to start beyond the array.
 160   while ((1 << pow) > (int)ObjArrayMarkingStride && (chunk*2 < ShenandoahMarkTask::chunk_size())) {
 161     pow--;
 162     chunk *= 2;
 163     bool pushed = q->push(ShenandoahMarkTask(array, chunk - 1, pow));
 164     assert(pushed, "overflow queue should always succeed pushing");
 165   }
 166 
 167   int chunk_size = 1 << pow;
 168 
 169   int from = (chunk - 1) * chunk_size;
 170   int to = chunk * chunk_size;
 171 
 172 #ifdef ASSERT
 173   int len = array->length();
 174   assert (0 <= from && from < len, "from is sane: %d/%d", from, len);
 175   assert (0 < to && to <= len, "to is sane: %d/%d", to, len);
 176 #endif
 177 
 178   array->oop_iterate_range(cl, from, to);
 179 }
 180 
 181 inline bool ShenandoahConcurrentMark::try_queue(ShenandoahObjToScanQueue* q, ShenandoahMarkTask &task) {
 182   return (q->pop_buffer(task) ||
 183           q->pop_local(task) ||
 184           q->pop_overflow(task));
 185 }
 186 
 187 class ShenandoahSATBBufferClosure : public SATBBufferClosure {
 188 private:
 189   ShenandoahObjToScanQueue* _queue;
 190   ShenandoahHeap* _heap;
 191 public:
 192   ShenandoahSATBBufferClosure(ShenandoahObjToScanQueue* q) :
 193     _queue(q), _heap(ShenandoahHeap::heap())
 194   {
 195   }
 196 
 197   void do_buffer(void** buffer, size_t size) {
 198     for (size_t i = 0; i < size; ++i) {
 199       oop* p = (oop*) &buffer[i];
 200       ShenandoahConcurrentMark::mark_through_ref<oop, RESOLVE>(p, _heap, _queue);
 201     }
 202   }
 203 };
 204 
 205 inline bool ShenandoahConcurrentMark::try_draining_satb_buffer(ShenandoahObjToScanQueue *q, ShenandoahMarkTask &task) {
 206   ShenandoahSATBBufferClosure cl(q);
 207   SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
 208   bool had_refs = satb_mq_set.apply_closure_to_completed_buffer(&cl);
 209   return had_refs && try_queue(q, task);
 210 }
 211 
 212 template<class T, UpdateRefsMode UPDATE_REFS>
 213 inline void ShenandoahConcurrentMark::mark_through_ref(T *p, ShenandoahHeap* heap, ShenandoahObjToScanQueue* q) {
 214   T o = oopDesc::load_heap_oop(p);
 215   if (! oopDesc::is_null(o)) {
 216     oop obj = oopDesc::decode_heap_oop_not_null(o);
 217     switch (UPDATE_REFS) {
 218     case NONE:
 219       break;
 220     case RESOLVE:
 221       obj = ShenandoahBarrierSet::resolve_oop_static_not_null(obj);
 222       break;
 223     case SIMPLE:
 224       // We piggy-back reference updating to the marking tasks.
 225       obj = heap->update_oop_ref_not_null(p, obj);
 226       break;
 227     case CONCURRENT:
 228       obj = heap->maybe_update_oop_ref_not_null(p, obj);
 229       break;
 230     default:
 231       ShouldNotReachHere();
 232     }
 233     assert(oopDesc::unsafe_equals(obj, ShenandoahBarrierSet::resolve_oop_static(obj)), "need to-space object here");
 234 
 235     // Note: Only when concurrently updating references can obj become NULL here.
 236     // It happens when a mutator thread beats us by writing another value. In that
 237     // case we don't need to do anything else.
 238     if (UPDATE_REFS != CONCURRENT || !oopDesc::is_null(obj)) {
 239       assert(!oopDesc::is_null(obj), "Must not be null here");
 240       assert(heap->is_in(obj), "We shouldn't be calling this on objects not in the heap: " PTR_FORMAT, p2i(obj));
 241       assert(oopDesc::bs()->is_safe(obj), "Only mark objects in from-space");
 242 
 243       if (heap->mark(obj)) {
 244         log_develop_trace(gc, marking)("Marked obj: " PTR_FORMAT, p2i((HeapWord*) obj));
 245 
 246         bool pushed = q->push(ShenandoahMarkTask(obj));
 247         assert(pushed, "overflow queue should always succeed pushing");
 248       } else {
 249         log_develop_trace(gc, marking)("Failed to mark obj (already marked): " PTR_FORMAT, p2i((HeapWord*) obj));
 250         assert(heap->is_marked(obj), "Consistency: should be marked.");
 251       }
 252     }
 253   }
 254 }
 255 
 256 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTMARK_INLINE_HPP