1 /*
   2  * Copyright (c) 2017, 2018, 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 
  25 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
  26 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP
  27 
  28 #include "code/codeCache.hpp"
  29 #include "memory/allocation.hpp"
  30 #include "memory/iterator.hpp"
  31 #include "gc_implementation/shenandoah/shenandoahSharedVariables.hpp"
  32 
  33 class ShenandoahHeap;
  34 class ShenandoahHeapRegion;
  35 class ShenandoahCodeRootsLock;
  36 
  37 class ShenandoahCodeRootsIterator VALUE_OBJ_CLASS_SPEC {
  38   friend class ShenandoahCodeRoots;
  39 protected:
  40   ShenandoahHeap* _heap;
  41   ParallelCodeCacheIterator _par_iterator;
  42   ShenandoahSharedFlag _seq_claimed;
  43   volatile jlong _claimed;
  44 protected:
  45   ShenandoahCodeRootsIterator();
  46   ~ShenandoahCodeRootsIterator();
  47 
  48   template<bool CSET_FILTER>
  49   void dispatch_parallel_blobs_do(CodeBlobClosure *f);
  50 
  51   template<bool CSET_FILTER>
  52   void fast_parallel_blobs_do(CodeBlobClosure *f);
  53 };
  54 
  55 class ShenandoahAllCodeRootsIterator : public ShenandoahCodeRootsIterator {
  56 public:
  57   ShenandoahAllCodeRootsIterator() : ShenandoahCodeRootsIterator() {};
  58   void possibly_parallel_blobs_do(CodeBlobClosure *f);
  59 };
  60 
  61 class ShenandoahCsetCodeRootsIterator : public ShenandoahCodeRootsIterator {
  62 public:
  63   ShenandoahCsetCodeRootsIterator() : ShenandoahCodeRootsIterator() {};
  64   void possibly_parallel_blobs_do(CodeBlobClosure* f);
  65 };
  66 
  67 class ShenandoahCodeRoots : public CHeapObj<mtGC> {
  68   friend class ShenandoahHeap;
  69   friend class ShenandoahCodeRootsLock;
  70   friend class ShenandoahCodeRootsIterator;
  71 
  72 public:
  73   static void initialize();
  74   static void add_nmethod(nmethod* nm);
  75   static void remove_nmethod(nmethod* nm);
  76 
  77   /**
  78    * Provides the iterator over all nmethods in the code cache that have oops.
  79    * @return
  80    */
  81   static ShenandoahAllCodeRootsIterator iterator();
  82 
  83   /**
  84    * Provides the iterator over nmethods that have at least one oop in collection set.
  85    * @return
  86    */
  87   static ShenandoahCsetCodeRootsIterator cset_iterator();
  88 
  89 private:
  90   static volatile jint _recorded_nmethods_lock;
  91   static GrowableArray<nmethod*>* _recorded_nmethods;
  92 
  93   static void fast_add_nmethod(nmethod* nm);
  94   static void fast_remove_nmethod(nmethod* nm);
  95 
  96   static void acquire_lock(bool write) {
  97     volatile jint* loc = &_recorded_nmethods_lock;
  98     if (write) {
  99       while ((OrderAccess::load_acquire(loc) != 0) ||
 100              Atomic::cmpxchg(-1, loc, 0) != 0) {
 101         SpinPause();
 102       }
 103       assert (*loc == -1, "acquired for write");
 104     } else {
 105       while (true) {
 106         jint cur = OrderAccess::load_acquire(loc);
 107         if (cur >= 0) {
 108           if (Atomic::cmpxchg(cur + 1, loc, cur) == cur) {
 109             // Success!
 110             return;
 111           }
 112         }
 113         SpinPause();
 114       }
 115       assert (*loc > 1, "acquired for read");
 116     }
 117   }
 118 
 119   static void release_lock(bool write) {
 120     volatile jint* loc = &ShenandoahCodeRoots::_recorded_nmethods_lock;
 121     if (write) {
 122       OrderAccess::release_store_fence(loc, 0);
 123     } else {
 124       Atomic::dec(loc);
 125     }
 126   }
 127 };
 128 
 129 // Very simple unranked read-write lock
 130 class ShenandoahCodeRootsLock : public StackObj {
 131   friend class ShenandoahCodeRoots;
 132 private:
 133   const bool _write;
 134 public:
 135   ShenandoahCodeRootsLock(bool write) : _write(write) {
 136     ShenandoahCodeRoots::acquire_lock(write);
 137   }
 138 
 139   ~ShenandoahCodeRootsLock() {
 140     ShenandoahCodeRoots::release_lock(_write);
 141   }
 142 };
 143 
 144 #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP