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 #include "precompiled.hpp" 25 #include "gc/g1/g1SATBCardTableModRefBS.hpp" 26 #include "gc/shenandoah/brooksPointer.hpp" 27 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 28 #include "gc/shenandoah/shenandoahBarrierSet.hpp" 29 #include "memory/universe.hpp" 30 #include "utilities/array.hpp" 31 32 class UpdateRefsForOopClosure: public ExtendedOopClosure { 33 34 private: 35 ShenandoahHeap* _heap; 36 public: 37 UpdateRefsForOopClosure() { 38 _heap = ShenandoahHeap::heap(); 39 } 40 41 void do_oop(oop* p) { 42 _heap->maybe_update_oop_ref(p); 43 } 44 45 void do_oop(narrowOop* p) { 46 Unimplemented(); 47 } 48 49 }; 50 51 ShenandoahBarrierSet::ShenandoahBarrierSet() : 52 BarrierSet(BarrierSet::FakeRtti(BarrierSet::ShenandoahBarrierSet)) 53 { 54 } 55 56 void ShenandoahBarrierSet::print_on(outputStream* st) const { 57 st->print("ShenandoahBarrierSet"); 58 } 59 60 bool ShenandoahBarrierSet::is_a(BarrierSet::Name bsn) { 61 return bsn == BarrierSet::ShenandoahBarrierSet; 62 } 63 64 bool ShenandoahBarrierSet::has_read_prim_array_opt() { 65 return true; 66 } 67 68 bool ShenandoahBarrierSet::has_read_prim_barrier() { 69 return false; 70 } 71 72 bool ShenandoahBarrierSet::has_read_ref_array_opt() { 73 return true; 74 } 75 76 bool ShenandoahBarrierSet::has_read_ref_barrier() { 77 return false; 78 } 79 80 bool ShenandoahBarrierSet::has_read_region_opt() { 81 return true; 82 } 83 84 bool ShenandoahBarrierSet::has_write_prim_array_opt() { 85 return true; 86 } 87 88 bool ShenandoahBarrierSet::has_write_prim_barrier() { 89 return false; 90 } 91 92 bool ShenandoahBarrierSet::has_write_ref_array_opt() { 93 return true; 94 } 95 96 bool ShenandoahBarrierSet::has_write_ref_barrier() { 97 return true; 98 } 99 100 bool ShenandoahBarrierSet::has_write_ref_pre_barrier() { 101 return true; 102 } 103 104 bool ShenandoahBarrierSet::has_write_region_opt() { 105 return true; 106 } 107 108 bool ShenandoahBarrierSet::is_aligned(HeapWord* hw) { 109 return true; 110 } 111 112 void ShenandoahBarrierSet::read_prim_array(MemRegion mr) { 113 Unimplemented(); 114 } 115 116 void ShenandoahBarrierSet::read_prim_field(HeapWord* hw, size_t s){ 117 Unimplemented(); 118 } 119 120 bool ShenandoahBarrierSet::read_prim_needs_barrier(HeapWord* hw, size_t s) { 121 return false; 122 } 123 124 void ShenandoahBarrierSet::read_ref_array(MemRegion mr) { 125 Unimplemented(); 126 } 127 128 void ShenandoahBarrierSet::read_ref_field(void* v) { 129 // tty->print_cr("read_ref_field: v = "PTR_FORMAT, v); 130 // return *v; 131 } 132 133 bool ShenandoahBarrierSet::read_ref_needs_barrier(void* v) { 134 Unimplemented(); 135 return false; 136 } 137 138 void ShenandoahBarrierSet::read_region(MemRegion mr) { 139 Unimplemented(); 140 } 141 142 void ShenandoahBarrierSet::resize_covered_region(MemRegion mr) { 143 Unimplemented(); 144 } 145 146 void ShenandoahBarrierSet::write_prim_array(MemRegion mr) { 147 Unimplemented(); 148 } 149 150 void ShenandoahBarrierSet::write_prim_field(HeapWord* hw, size_t s , juint x, juint y) { 151 Unimplemented(); 152 } 153 154 bool ShenandoahBarrierSet::write_prim_needs_barrier(HeapWord* hw, size_t s, juint x, juint y) { 155 Unimplemented(); 156 return false; 157 } 158 159 bool ShenandoahBarrierSet::need_update_refs_barrier() { 160 ShenandoahHeap* heap = ShenandoahHeap::heap(); 161 return heap->is_update_references_in_progress() || (heap->concurrent_mark_in_progress() && heap->need_update_refs()); 162 } 163 164 void ShenandoahBarrierSet::write_ref_array_work(MemRegion mr) { 165 if (! need_update_refs_barrier()) return; 166 ShenandoahHeap* heap = ShenandoahHeap::heap(); 167 for (HeapWord* word = mr.start(); word < mr.end(); word++) { 168 oop* oop_ptr = (oop*) word; 169 heap->maybe_update_oop_ref(oop_ptr); 170 } 171 } 172 173 template <class T> 174 void ShenandoahBarrierSet::write_ref_array_pre_work(T* dst, int count) { 175 176 #ifdef ASSERT 177 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 178 if (sh->is_in(dst) && 179 sh->heap_region_containing((HeapWord*) dst)->is_in_collection_set() && 180 ! sh->cancelled_concgc()) { 181 tty->print_cr("dst = "PTR_FORMAT, p2i(dst)); 182 sh->heap_region_containing((HeapWord*) dst)->print(); 183 assert(false, "We should have fixed this earlier"); 184 } 185 #endif 186 187 if (! JavaThread::satb_mark_queue_set().is_active()) return; 188 // tty->print_cr("write_ref_array_pre_work: "PTR_FORMAT", "INT32_FORMAT, dst, count); 189 T* elem_ptr = dst; 190 for (int i = 0; i < count; i++, elem_ptr++) { 191 T heap_oop = oopDesc::load_heap_oop(elem_ptr); 192 if (!oopDesc::is_null(heap_oop)) { 193 G1SATBCardTableModRefBS::enqueue(oopDesc::decode_heap_oop_not_null(heap_oop)); 194 } 195 // tty->print_cr("write_ref_array_pre_work: oop: "PTR_FORMAT, heap_oop); 196 } 197 } 198 199 void ShenandoahBarrierSet::write_ref_array_pre(oop* dst, int count, bool dest_uninitialized) { 200 if (! dest_uninitialized) { 201 write_ref_array_pre_work(dst, count); 202 } 203 } 204 205 void ShenandoahBarrierSet::write_ref_array_pre(narrowOop* dst, int count, bool dest_uninitialized) { 206 if (! dest_uninitialized) { 207 write_ref_array_pre_work(dst, count); 208 } 209 } 210 211 template <class T> 212 void ShenandoahBarrierSet::write_ref_field_pre_static(T* field, oop newVal) { 213 T heap_oop = oopDesc::load_heap_oop(field); 214 215 #ifdef ASSERT 216 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 217 if (sh->is_in(field) && 218 sh->heap_region_containing((HeapWord*)field)->is_in_collection_set() && 219 ! sh->cancelled_concgc()) { 220 tty->print_cr("field = "PTR_FORMAT, p2i(field)); 221 sh->heap_region_containing((HeapWord*)field)->print(); 222 assert(false, "We should have fixed this earlier"); 223 } 224 #endif 225 226 if (!oopDesc::is_null(heap_oop)) { 227 G1SATBCardTableModRefBS::enqueue(oopDesc::decode_heap_oop(heap_oop)); 228 // tty->print_cr("write_ref_field_pre_static: v = "PTR_FORMAT" o = "PTR_FORMAT" old: "PTR_FORMAT, field, newVal, heap_oop); 229 } 230 } 231 232 template <class T> 233 inline void ShenandoahBarrierSet::inline_write_ref_field_pre(T* field, oop newVal) { 234 write_ref_field_pre_static(field, newVal); 235 } 236 237 // These are the more general virtual versions. 238 void ShenandoahBarrierSet::write_ref_field_pre_work(oop* field, oop new_val) { 239 write_ref_field_pre_static(field, new_val); 240 } 241 242 void ShenandoahBarrierSet::write_ref_field_pre_work(narrowOop* field, oop new_val) { 243 write_ref_field_pre_static(field, new_val); 244 } 245 246 void ShenandoahBarrierSet::write_ref_field_pre_work(void* field, oop new_val) { 247 guarantee(false, "Not needed"); 248 } 249 250 void ShenandoahBarrierSet::write_ref_field_work(void* v, oop o, bool release) { 251 if (! need_update_refs_barrier()) return; 252 assert (! UseCompressedOops, "compressed oops not supported yet"); 253 ShenandoahHeap::heap()->maybe_update_oop_ref((oop*) v); 254 // tty->print_cr("write_ref_field_work: v = "PTR_FORMAT" o = "PTR_FORMAT, v, o); 255 } 256 257 void ShenandoahBarrierSet::write_region_work(MemRegion mr) { 258 259 if (! need_update_refs_barrier()) return; 260 261 // This is called for cloning an object (see jvm.cpp) after the clone 262 // has been made. We are not interested in any 'previous value' because 263 // it would be NULL in any case. But we *are* interested in any oop* 264 // that potentially need to be updated. 265 266 // tty->print_cr("write_region_work: "PTR_FORMAT", "PTR_FORMAT, mr.start(), mr.end()); 267 oop obj = oop(mr.start()); 268 assert(obj->is_oop(), "must be an oop"); 269 UpdateRefsForOopClosure cl; 270 obj->oop_iterate(&cl); 271 } 272 273 oop ShenandoahBarrierSet::read_barrier(oop src) { 274 return ShenandoahBarrierSet::resolve_oop_static(src); 275 } 276 277 oop ShenandoahBarrierSet::resolve_and_maybe_copy_oop_work(oop src) { 278 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 279 assert(src != NULL, "only evacuated non NULL oops"); 280 281 if (sh->in_cset_fast_test((HeapWord*) src)) { 282 return resolve_and_maybe_copy_oop_work2(src); 283 } else { 284 return src; 285 } 286 } 287 288 oop ShenandoahBarrierSet::resolve_and_maybe_copy_oop_work2(oop src) { 289 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 290 if (! sh->is_evacuation_in_progress()) { 291 // We may get here through a barrier that just took a safepoint that 292 // turned off evacuation. In this case, return right away. 293 return ShenandoahBarrierSet::resolve_oop_static(src); 294 } 295 assert(src != NULL, "only evacuated non NULL oops"); 296 assert(sh->heap_region_containing(src)->is_in_collection_set(), "only evacuate objects in collection set"); 297 assert(! sh->heap_region_containing(src)->is_humongous(), "never evacuate humongous objects"); 298 // TODO: Consider passing thread from caller. 299 oop dst = sh->evacuate_object(src, Thread::current()); 300 #ifdef ASSERT 301 if (ShenandoahTraceEvacuations) { 302 tty->print_cr("src = "PTR_FORMAT" dst = "PTR_FORMAT" src = "PTR_FORMAT" src-2 = "PTR_FORMAT, 303 p2i((HeapWord*) src), p2i((HeapWord*) dst), p2i((HeapWord*) src), p2i(((HeapWord*) src) - 2)); 304 } 305 #endif 306 assert(sh->is_in(dst), "result should be in the heap"); 307 return dst; 308 } 309 310 oop ShenandoahBarrierSet::resolve_and_maybe_copy_oopHelper(oop src) { 311 if (src != NULL) { 312 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 313 oop tmp = resolve_oop_static(src); 314 if (! sh->is_evacuation_in_progress()) { 315 return tmp; 316 } 317 return resolve_and_maybe_copy_oop_work(src); 318 } else { 319 return NULL; 320 } 321 } 322 323 JRT_LEAF(oopDesc*, ShenandoahBarrierSet::resolve_and_maybe_copy_oop_c2(oopDesc* src)) 324 oop result = ((ShenandoahBarrierSet*) oopDesc::bs())->resolve_and_maybe_copy_oop_work2(oop(src)); 325 // tty->print_cr("called C2 write barrier with: %p result: %p copy: %d", (oopDesc*) src, (oopDesc*) result, src != result); 326 return (oopDesc*) result; 327 JRT_END 328 329 IRT_LEAF(oopDesc*, ShenandoahBarrierSet::resolve_and_maybe_copy_oop_interp(oopDesc* src)) 330 oop result = ((ShenandoahBarrierSet*)oopDesc::bs())->resolve_and_maybe_copy_oop_work2(oop(src)); 331 // tty->print_cr("called interpreter write barrier with: %p result: %p", src, result); 332 return (oopDesc*) result; 333 IRT_END 334 335 JRT_LEAF(oopDesc*, ShenandoahBarrierSet::resolve_and_maybe_copy_oop_c1(JavaThread* thread, oopDesc* src)) 336 oop result = ((ShenandoahBarrierSet*)oopDesc::bs())->resolve_and_maybe_copy_oop_work2(oop(src)); 337 // tty->print_cr("called static write barrier (2) with: "PTR_FORMAT" result: "PTR_FORMAT, p2i(src), p2i((oopDesc*)(result))); 338 return (oopDesc*) result; 339 JRT_END 340 341 oop ShenandoahBarrierSet::write_barrier(oop src) { 342 ShenandoahHeap *sh = (ShenandoahHeap*) Universe::heap(); 343 oop result; 344 if (src != NULL && sh->is_in(src)) { 345 result = resolve_and_maybe_copy_oopHelper(src); 346 assert(sh->is_in(result), "result should be in the heap"); 347 } else { 348 result = src; 349 } 350 assert(result == NULL || (sh->is_in(result) && result->is_oop()), "resolved oop must be NULL, or a valid oop in the heap"); 351 return result; 352 }