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 }