1 /*
   2  * Copyright (c) 2013, 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 #include "precompiled.hpp"
  25 #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
  26 #include "gc_implementation/shenandoah/shenandoahAsserts.hpp"
  27 #include "gc_implementation/shenandoah/shenandoahBarrierSet.hpp"
  28 #include "gc_implementation/shenandoah/shenandoahBarrierSetClone.inline.hpp"
  29 #include "gc_implementation/shenandoah/shenandoahCollectorPolicy.hpp"
  30 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"
  31 #include "gc_implementation/shenandoah/heuristics/shenandoahHeuristics.hpp"
  32 #include "runtime/interfaceSupport.hpp"
  33 #include "utilities/macros.hpp"
  34 
  35 #ifdef COMPILER1
  36 #include "gc_implementation/shenandoah/c1/shenandoahBarrierSetC1.hpp"
  37 #endif
  38 #ifdef COMPILER2
  39 #include "gc_implementation/shenandoah/c2/shenandoahBarrierSetC2.hpp"
  40 #endif
  41 
  42 #if defined(TARGET_ARCH_aarch64)
  43 #include "shenandoahBarrierSetAssembler_aarch64.hpp"
  44 #elif defined(TARGET_ARCH_x86)
  45 #include "shenandoahBarrierSetAssembler_x86.hpp"
  46 #else
  47 #include "shenandoahBarrierSetAssembler_stub.hpp"
  48 #endif
  49 
  50 ShenandoahBarrierSet::ShenandoahBarrierSet(ShenandoahHeap* heap) :
  51   BarrierSet(),
  52   _heap(heap),
  53   _bsasm(new ShenandoahBarrierSetAssembler()),
  54   _bsc1(COMPILER1_PRESENT(new ShenandoahBarrierSetC1()) NOT_COMPILER1(NULL)),
  55   _bsc2(COMPILER2_PRESENT(new ShenandoahBarrierSetC2()) NOT_COMPILER2(NULL))
  56 {
  57   _kind = BarrierSet::ShenandoahBarrierSet;
  58 }
  59 
  60 ShenandoahBarrierSetAssembler* ShenandoahBarrierSet::bsasm() const {
  61   return _bsasm;
  62 }
  63 
  64 ShenandoahBarrierSetC1* ShenandoahBarrierSet::bsc1() const {
  65   return _bsc1;
  66 }
  67 
  68 ShenandoahBarrierSetC2* ShenandoahBarrierSet::bsc2() const {
  69   return _bsc2;
  70 }
  71 
  72 void ShenandoahBarrierSet::print_on(outputStream* st) const {
  73   st->print("ShenandoahBarrierSet");
  74 }
  75 
  76 bool ShenandoahBarrierSet::is_a(BarrierSet::Name bsn) {
  77   return bsn == BarrierSet::ShenandoahBarrierSet;
  78 }
  79 
  80 bool ShenandoahBarrierSet::has_read_prim_array_opt() {
  81   return true;
  82 }
  83 
  84 bool ShenandoahBarrierSet::has_read_prim_barrier() {
  85   return false;
  86 }
  87 
  88 bool ShenandoahBarrierSet::has_read_ref_array_opt() {
  89   return true;
  90 }
  91 
  92 bool ShenandoahBarrierSet::has_read_ref_barrier() {
  93   return false;
  94 }
  95 
  96 bool ShenandoahBarrierSet::has_read_region_opt() {
  97   return true;
  98 }
  99 
 100 bool ShenandoahBarrierSet::has_write_prim_array_opt() {
 101   return true;
 102 }
 103 
 104 bool ShenandoahBarrierSet::has_write_prim_barrier() {
 105   return false;
 106 }
 107 
 108 bool ShenandoahBarrierSet::has_write_ref_array_opt() {
 109   return true;
 110 }
 111 
 112 bool ShenandoahBarrierSet::has_write_ref_barrier() {
 113   return true;
 114 }
 115 
 116 bool ShenandoahBarrierSet::has_write_ref_pre_barrier() {
 117   return true;
 118 }
 119 
 120 bool ShenandoahBarrierSet::has_write_region_opt() {
 121   return true;
 122 }
 123 
 124 bool ShenandoahBarrierSet::is_aligned(HeapWord* hw) {
 125   return true;
 126 }
 127 
 128 bool ShenandoahBarrierSet::read_prim_needs_barrier(HeapWord* hw, size_t s) {
 129   return false;
 130 }
 131 
 132 void ShenandoahBarrierSet::read_ref_field(void* v) {
 133   //    tty->print_cr("read_ref_field: v = "PTR_FORMAT, v);
 134   // return *v;
 135 }
 136 
 137 template <class T>
 138 inline void ShenandoahBarrierSet::inline_write_ref_field_pre(T* field, oop newVal) {
 139   newVal = load_reference_barrier(newVal);
 140   storeval_barrier(newVal);
 141   if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) {
 142     T heap_oop = oopDesc::load_heap_oop(field);
 143     shenandoah_assert_not_in_cset_loc_except(field, ShenandoahHeap::heap()->cancelled_gc());
 144     if (!oopDesc::is_null(heap_oop)) {
 145       ShenandoahBarrierSet::barrier_set()->enqueue(oopDesc::decode_heap_oop(heap_oop));
 146     }
 147   }
 148 }
 149 
 150 // These are the more general virtual versions.
 151 void ShenandoahBarrierSet::write_ref_field_pre_work(oop* field, oop new_val) {
 152   inline_write_ref_field_pre(field, new_val);
 153 }
 154 
 155 void ShenandoahBarrierSet::write_ref_field_pre_work(narrowOop* field, oop new_val) {
 156   inline_write_ref_field_pre(field, new_val);
 157 }
 158 
 159 void ShenandoahBarrierSet::write_ref_field_work(void* v, oop o, bool release) {
 160   shenandoah_assert_not_in_cset_loc_except(v, _heap->cancelled_gc());
 161   shenandoah_assert_not_forwarded_except  (v, o, o == NULL || _heap->cancelled_gc() || !_heap->is_concurrent_mark_in_progress());
 162   shenandoah_assert_not_in_cset_except    (v, o, o == NULL || _heap->cancelled_gc() || !_heap->is_concurrent_mark_in_progress());
 163 }
 164 
 165 oop ShenandoahBarrierSet::load_reference_barrier_not_null(oop obj) {
 166   assert(obj != NULL, "");
 167   if (ShenandoahLoadRefBarrier && _heap->has_forwarded_objects()) {
 168     return load_reference_barrier_impl(obj);
 169   } else {
 170     return obj;
 171   }
 172 }
 173 
 174 oop ShenandoahBarrierSet::load_reference_barrier(oop obj) {
 175   if (obj != NULL) {
 176     return load_reference_barrier_not_null(obj);
 177   } else {
 178     return obj;
 179   }
 180 }
 181 
 182 
 183 oop ShenandoahBarrierSet::load_reference_barrier_impl(oop obj) {
 184   assert(ShenandoahLoadRefBarrier, "should be enabled");
 185   if (!oopDesc::is_null(obj)) {
 186     oop fwd = resolve_forwarded_not_null(obj);
 187     if (_heap->is_evacuation_in_progress() &&
 188         _heap->in_collection_set(obj) &&
 189         obj == fwd) {
 190       Thread *t = Thread::current();
 191       ShenandoahEvacOOMScope oom_evac_scope;
 192       return _heap->evacuate_object(obj, t);
 193     } else {
 194       return fwd;
 195     }
 196   } else {
 197     return obj;
 198   }
 199 }
 200 
 201 void ShenandoahBarrierSet::storeval_barrier(oop obj) {
 202   if (ShenandoahStoreValEnqueueBarrier && !oopDesc::is_null(obj) && _heap->is_concurrent_mark_in_progress()) {
 203     enqueue(obj);
 204   }
 205 }
 206 
 207 void ShenandoahBarrierSet::keep_alive_barrier(oop obj) {
 208   if (_heap->is_concurrent_mark_in_progress()) {
 209     enqueue(obj);
 210   }
 211 }
 212 
 213 void ShenandoahBarrierSet::enqueue(oop obj) {
 214   assert(JavaThread::satb_mark_queue_set().shared_satb_queue()->is_active(), "only get here when SATB active");
 215 
 216   // Filter marked objects before hitting the SATB queues. The same predicate would
 217   // be used by SATBMQ::filter to eliminate already marked objects downstream, but
 218   // filtering here helps to avoid wasteful SATB queueing work to begin with.
 219   if (!_heap->requires_marking(obj)) return;
 220 
 221   Thread* thr = Thread::current();
 222   if (thr->is_Java_thread()) {
 223     JavaThread* jt = (JavaThread*)thr;
 224     jt->satb_mark_queue().enqueue_known_active(obj);
 225   } else {
 226     MutexLockerEx x(Shared_SATB_Q_lock, Mutex::_no_safepoint_check_flag);
 227     JavaThread::satb_mark_queue_set().shared_satb_queue()->enqueue_known_active(obj);
 228   }
 229 }
 230 
 231 oop ShenandoahBarrierSet::atomic_compare_exchange_oop(oop exchange_value,
 232                                                       volatile HeapWord *dest,
 233                                                       oop compare_value) {
 234   if (UseCompressedOops) {
 235     // encode exchange and compare value from oop to T
 236     narrowOop val = oopDesc::encode_heap_oop(exchange_value);
 237     narrowOop cmp = oopDesc::encode_heap_oop(compare_value);
 238 
 239     narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
 240     // decode old from T to oop
 241     return oopDesc::decode_heap_oop(old);
 242   } else {
 243     return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
 244   }
 245 }
 246 
 247 oop ShenandoahBarrierSet::oop_atomic_cmpxchg_in_heap(oop new_value, volatile HeapWord* dest, oop compare_value) {
 248   oop expected;
 249   bool success;
 250   do {
 251     expected = compare_value;
 252     compare_value = atomic_compare_exchange_oop(new_value, dest, expected);
 253     success = (compare_value == expected);
 254   } while ((! success) && resolve_forwarded(compare_value) == resolve_forwarded(expected));
 255   oop result = load_reference_barrier(compare_value);
 256   if (ShenandoahSATBBarrier && success && result != NULL &&
 257         ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) {
 258     enqueue(result);
 259   }
 260   if (new_value != NULL) {
 261     storeval_barrier(new_value);
 262   }
 263   return result;
 264 }
 265 
 266 void ShenandoahBarrierSet::clone_barrier_runtime(oop src) {
 267   if (_heap->has_forwarded_objects() || (ShenandoahStoreValEnqueueBarrier && _heap->is_concurrent_mark_in_progress())) {
 268     clone_barrier(src);
 269   }
 270 }