1 /*
   2  * Copyright (c) 2019, 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 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP
  24 #define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP
  25 
  26 #include "gc/shared/barrierSetNMethod.hpp"
  27 #include "gc/shenandoah/shenandoahAsserts.hpp"
  28 #include "gc/shenandoah/shenandoahClosures.hpp"
  29 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
  30 #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
  31 #include "gc/shenandoah/shenandoahTraversalGC.hpp"
  32 #include "oops/compressedOops.inline.hpp"
  33 #include "runtime/thread.hpp"
  34 
  35 ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() :
  36   _mark_context(ShenandoahHeap::heap()->marking_context()) {
  37 }
  38 
  39 bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) {
  40   if (CompressedOops::is_null(obj)) {
  41     return false;
  42   }
  43   obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
  44   shenandoah_assert_not_forwarded_if(NULL, obj,
  45                                      (ShenandoahHeap::heap()->is_concurrent_mark_in_progress() ||
  46                                      ShenandoahHeap::heap()->is_concurrent_traversal_in_progress()));
  47   return _mark_context->is_marked(obj);
  48 }
  49 
  50 ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() :
  51   _mark_context(ShenandoahHeap::heap()->marking_context()) {
  52 }
  53 
  54 bool ShenandoahIsAliveClosure::do_object_b(oop obj) {
  55   if (CompressedOops::is_null(obj)) {
  56     return false;
  57   }
  58   shenandoah_assert_not_forwarded(NULL, obj);
  59   return _mark_context->is_marked(obj);
  60 }
  61 
  62 BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() {
  63   return ShenandoahHeap::heap()->has_forwarded_objects() ?
  64          reinterpret_cast<BoolObjectClosure*>(&_fwd_alive_cl) :
  65          reinterpret_cast<BoolObjectClosure*>(&_alive_cl);
  66 }
  67 
  68 ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() :
  69   _heap(ShenandoahHeap::heap()) {
  70 }
  71 
  72 template <class T>
  73 void ShenandoahUpdateRefsClosure::do_oop_work(T* p) {
  74   T o = RawAccess<>::oop_load(p);
  75   if (!CompressedOops::is_null(o)) {
  76     oop obj = CompressedOops::decode_not_null(o);
  77     _heap->update_with_forwarded_not_null(p, obj);
  78   }
  79 }
  80 
  81 void ShenandoahUpdateRefsClosure::do_oop(oop* p)       { do_oop_work(p); }
  82 void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); }
  83 
  84 ShenandoahTraversalUpdateRefsClosure::ShenandoahTraversalUpdateRefsClosure() :
  85   _heap(ShenandoahHeap::heap()),
  86   _traversal_set(ShenandoahHeap::heap()->traversal_gc()->traversal_set()) {
  87   assert(_heap->is_traversal_mode(), "Why we here?");
  88 }
  89 
  90 template <class T>
  91 void ShenandoahTraversalUpdateRefsClosure::do_oop_work(T* p) {
  92   T o = RawAccess<>::oop_load(p);
  93   if (!CompressedOops::is_null(o)) {
  94     oop obj = CompressedOops::decode_not_null(o);
  95     if (_heap->in_collection_set(obj) || _traversal_set->is_in((HeapWord*)obj)) {
  96       obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
  97       RawAccess<IS_NOT_NULL>::oop_store(p, obj);
  98     } else {
  99       shenandoah_assert_not_forwarded(p, obj);
 100     }
 101   }
 102 }
 103 
 104 void ShenandoahTraversalUpdateRefsClosure::do_oop(oop* p)       { do_oop_work(p); }
 105 void ShenandoahTraversalUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); }
 106 
 107 ShenandoahEvacuateUpdateRootsClosure::ShenandoahEvacuateUpdateRootsClosure() :
 108   _heap(ShenandoahHeap::heap()), _thread(Thread::current()) {
 109 }
 110 
 111 template <class T>
 112 void ShenandoahEvacuateUpdateRootsClosure::do_oop_work(T* p) {
 113   assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress");
 114 
 115   T o = RawAccess<>::oop_load(p);
 116   if (! CompressedOops::is_null(o)) {
 117     oop obj = CompressedOops::decode_not_null(o);
 118     if (_heap->in_collection_set(obj)) {
 119       shenandoah_assert_marked(p, obj);
 120       oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
 121       if (resolved == obj) {
 122         resolved = _heap->evacuate_object(obj, _thread);
 123       }
 124       RawAccess<IS_NOT_NULL>::oop_store(p, resolved);
 125     }
 126   }
 127 }
 128 void ShenandoahEvacuateUpdateRootsClosure::do_oop(oop* p) {
 129   do_oop_work(p);
 130 }
 131 
 132 void ShenandoahEvacuateUpdateRootsClosure::do_oop(narrowOop* p) {
 133   do_oop_work(p);
 134 }
 135 
 136 ShenandoahEvacUpdateOopStorageRootsClosure::ShenandoahEvacUpdateOopStorageRootsClosure() :
 137   _heap(ShenandoahHeap::heap()), _thread(Thread::current()) {
 138 }
 139 
 140 void ShenandoahEvacUpdateOopStorageRootsClosure::do_oop(oop* p) {
 141   assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress");
 142 
 143   oop obj = RawAccess<>::oop_load(p);
 144   if (! CompressedOops::is_null(obj)) {
 145     if (_heap->in_collection_set(obj)) {
 146       shenandoah_assert_marked(p, obj);
 147       oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
 148       if (resolved == obj) {
 149         resolved = _heap->evacuate_object(obj, _thread);
 150       }
 151 
 152       Atomic::cmpxchg(resolved, p, obj);
 153     }
 154   }
 155 }
 156 
 157 void ShenandoahEvacUpdateOopStorageRootsClosure::do_oop(narrowOop* p) {
 158   ShouldNotReachHere();
 159 }
 160 
 161 ShenandoahCodeBlobAndDisarmClosure::ShenandoahCodeBlobAndDisarmClosure(OopClosure* cl) :
 162   CodeBlobToOopClosure(cl, true /* fix_relocations */),
 163    _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) {
 164 }
 165 
 166 void ShenandoahCodeBlobAndDisarmClosure::do_code_blob(CodeBlob* cb) {
 167   nmethod* const nm = cb->as_nmethod_or_null();
 168   if (nm != NULL && !nm->test_set_oops_do_mark()) {
 169     assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here");
 170     CodeBlobToOopClosure::do_code_blob(cb);
 171     _bs->disarm(nm);
 172   }
 173 }
 174 
 175 #ifdef ASSERT
 176 template <class T>
 177 void ShenandoahAssertNotForwardedClosure::do_oop_work(T* p) {
 178   T o = RawAccess<>::oop_load(p);
 179   if (!CompressedOops::is_null(o)) {
 180     oop obj = CompressedOops::decode_not_null(o);
 181     shenandoah_assert_not_forwarded(p, obj);
 182   }
 183 }
 184 
 185 void ShenandoahAssertNotForwardedClosure::do_oop(narrowOop* p) { do_oop_work(p); }
 186 void ShenandoahAssertNotForwardedClosure::do_oop(oop* p)       { do_oop_work(p); }
 187 #endif
 188 
 189 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP