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   }