1 /*
   2  * Copyright (c) 2015, 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_SHENANDOAHBARRIERSET_INLINE_HPP
  25 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP
  26 
  27 #include "gc_implementation/shenandoah/shenandoahBarrierSet.hpp"
  28 #include "gc_implementation/shenandoah/shenandoahCollectionSet.inline.hpp"
  29 #include "gc_implementation/shenandoah/shenandoahForwarding.inline.hpp"
  30 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"
  31 #include "gc_implementation/shenandoah/shenandoahMarkingContext.inline.hpp"
  32 #include "memory/iterator.inline.hpp"
  33 #include "oops/oop.inline.hpp"
  34 
  35 inline oop ShenandoahBarrierSet::resolve_forwarded_not_null(oop p) {
  36   return ShenandoahForwarding::get_forwardee(p);
  37 }
  38 
  39 inline oop ShenandoahBarrierSet::resolve_forwarded(oop p) {
  40   if (((HeapWord*) p) != NULL) {
  41     return resolve_forwarded_not_null(p);
  42   } else {
  43     return p;
  44   }
  45 }
  46 
  47 inline oop ShenandoahBarrierSet::resolve_forwarded_not_null_mutator(oop p) {
  48   return ShenandoahForwarding::get_forwardee_mutator(p);
  49 }
  50 
  51 inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, oop* load_addr) {
  52   return load_reference_barrier_mutator_work(obj, load_addr);
  53 }
  54 
  55 inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, narrowOop* load_addr) {
  56   return load_reference_barrier_mutator_work(obj, load_addr);
  57 }
  58 
  59 template <class T>
  60 oop ShenandoahBarrierSet::load_reference_barrier_mutator_work(oop obj, T* load_addr) {
  61   assert(ShenandoahLoadRefBarrier, "should be enabled");
  62   shenandoah_assert_in_cset(load_addr, obj);
  63 
  64   oop fwd = resolve_forwarded_not_null_mutator(obj);
  65   if (obj == fwd) {
  66     assert(_heap->is_evacuation_in_progress(),
  67            "evac should be in progress");
  68     ShenandoahEvacOOMScope scope;
  69     fwd = _heap->evacuate_object(obj, Thread::current());
  70   }
  71 
  72   if (load_addr != NULL && fwd != obj) {
  73     // Since we are here and we know the load address, update the reference.
  74     ShenandoahHeap::cas_oop(fwd, load_addr, obj);
  75   }
  76 
  77   return fwd;
  78 }
  79 
  80 template <class T, bool HAS_FWD, bool EVAC, bool ENQUEUE>
  81 void ShenandoahBarrierSet::arraycopy_work(T* src, size_t count) {
  82   assert(HAS_FWD == _heap->has_forwarded_objects(), "Forwarded object status is sane");
  83 
  84   JavaThread* thread = JavaThread::current();
  85   ObjPtrQueue& queue = thread->satb_mark_queue();
  86   ShenandoahMarkingContext* ctx = _heap->marking_context();
  87   const ShenandoahCollectionSet* const cset = _heap->collection_set();
  88   T* end = src + count;
  89   for (T* elem_ptr = src; elem_ptr < end; elem_ptr++) {
  90     T o = oopDesc::load_heap_oop(elem_ptr);
  91     if (!oopDesc::is_null(o)) {
  92       oop obj = oopDesc::decode_heap_oop_not_null(o);
  93       if (HAS_FWD && cset->is_in(obj)) {
  94         oop fwd = resolve_forwarded_not_null(obj);
  95         if (EVAC && obj == fwd) {
  96           fwd = _heap->evacuate_object(obj, thread);
  97         }
  98         assert(obj != fwd || _heap->cancelled_gc(), "must be forwarded");
  99         oop witness = ShenandoahHeap::cas_oop(fwd, elem_ptr, o);
 100         obj = fwd;
 101       }
 102       if (ENQUEUE && !ctx->is_marked(obj)) {
 103         queue.enqueue_known_active(obj);
 104       }
 105     }
 106   }
 107 }
 108 
 109 template <class T>
 110 void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) {
 111   if (count == 0) {
 112     return;
 113   }
 114   int gc_state = _heap->gc_state();
 115   if ((gc_state & ShenandoahHeap::MARKING) != 0) {
 116     arraycopy_marking(src, dst, count);
 117   } else if ((gc_state & ShenandoahHeap::EVACUATION) != 0) {
 118     arraycopy_evacuation(src, count);
 119   } else if ((gc_state & ShenandoahHeap::UPDATEREFS) != 0) {
 120     arraycopy_update(src, count);
 121   }
 122 }
 123 
 124 template <class T>
 125 void ShenandoahBarrierSet::arraycopy_marking(T* src, T* dst, size_t count) {
 126   assert(_heap->is_concurrent_mark_in_progress(), "only during marking");
 127   T* array = ShenandoahSATBBarrier ? dst : src;
 128   if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(array))) {
 129     arraycopy_work<T, false, false, true>(array, count);
 130   }
 131 }
 132 
 133 inline bool ShenandoahBarrierSet::need_bulk_update(HeapWord* ary) {
 134   return ary < _heap->heap_region_containing(ary)->get_update_watermark();
 135 }
 136 
 137 template <class T>
 138 void ShenandoahBarrierSet::arraycopy_evacuation(T* src, size_t count) {
 139   assert(_heap->is_evacuation_in_progress(), "only during evacuation");
 140   if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
 141     ShenandoahEvacOOMScope oom_evac;
 142     arraycopy_work<T, true, true, false>(src, count);
 143   }
 144 }
 145 
 146 template <class T>
 147 void ShenandoahBarrierSet::arraycopy_update(T* src, size_t count) {
 148   assert(_heap->is_update_refs_in_progress(), "only during update-refs");
 149   if (need_bulk_update(reinterpret_cast<HeapWord*>(src))) {
 150     arraycopy_work<T, true, false, false>(src, count);
 151   }
 152 }
 153 
 154 #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP