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 ShenandoahParallelCodeCacheIterator VALUE_OBJ_CLASS_SPEC { 38 friend class CodeCache; 39 private: 40 volatile int _claimed_idx; 41 volatile bool _finished; 42 public: 43 ShenandoahParallelCodeCacheIterator(); 44 void parallel_blobs_do(CodeBlobClosure* f); 45 }; 46 47 // ShenandoahNMethod tuple records the internal locations of oop slots within the nmethod. 48 // This allows us to quickly scan the oops without doing the nmethod-internal scans, that 49 // sometimes involves parsing the machine code. Note it does not record the oops themselves, 50 // because it would then require handling these tuples as the new class of roots. 51 class ShenandoahNMethod : public CHeapObj<mtGC> { 52 private: 53 nmethod* _nm; 54 oop** _oops; 55 int _oops_count; 56 57 public: 58 ShenandoahNMethod(nmethod *nm, GrowableArray<oop*>* oops); 59 ~ShenandoahNMethod(); 60 61 nmethod* nm() { 62 return _nm; 63 } 64 65 bool has_cset_oops(ShenandoahHeap* heap); 66 67 void assert_alive_and_correct() PRODUCT_RETURN; 68 void assert_same_oops(GrowableArray<oop*>* oops) PRODUCT_RETURN; 69 70 static bool find_with_nmethod(void* nm, ShenandoahNMethod* other) { 71 return other->_nm == nm; 72 } 73 }; 74 75 class ShenandoahCodeRootsIterator VALUE_OBJ_CLASS_SPEC { 76 friend class ShenandoahCodeRoots; 77 protected: 78 ShenandoahHeap* _heap; 79 ShenandoahParallelCodeCacheIterator _par_iterator; 80 ShenandoahSharedFlag _seq_claimed; 81 volatile jlong _claimed; 82 protected: 83 ShenandoahCodeRootsIterator(); 84 ~ShenandoahCodeRootsIterator(); 85 86 template<bool CSET_FILTER> 87 void dispatch_parallel_blobs_do(CodeBlobClosure *f); 88 89 template<bool CSET_FILTER> 90 void fast_parallel_blobs_do(CodeBlobClosure *f); 91 }; 92 93 class ShenandoahAllCodeRootsIterator : public ShenandoahCodeRootsIterator { 94 public: 95 ShenandoahAllCodeRootsIterator() : ShenandoahCodeRootsIterator() {}; 96 void possibly_parallel_blobs_do(CodeBlobClosure *f); 97 }; 98 99 class ShenandoahCsetCodeRootsIterator : public ShenandoahCodeRootsIterator { 100 public: 101 ShenandoahCsetCodeRootsIterator() : ShenandoahCodeRootsIterator() {}; 102 void possibly_parallel_blobs_do(CodeBlobClosure* f); 103 }; 104 105 class ShenandoahCodeRoots : public CHeapObj<mtGC> { 106 friend class ShenandoahHeap; 107 friend class ShenandoahCodeRootsLock; 108 friend class ShenandoahCodeRootsIterator; 109 110 public: 111 static void initialize(); 112 static void add_nmethod(nmethod* nm); 113 static void remove_nmethod(nmethod* nm); 114 115 /** 116 * Provides the iterator over all nmethods in the code cache that have oops. 117 * @return 118 */ 119 static ShenandoahAllCodeRootsIterator iterator(); 120 121 /** 122 * Provides the iterator over nmethods that have at least one oop in collection set. 123 * @return 124 */ 125 static ShenandoahCsetCodeRootsIterator cset_iterator(); 126 127 private: 128 static volatile jint _recorded_nms_lock; 129 static GrowableArray<ShenandoahNMethod*>* _recorded_nms; 130 131 static void acquire_lock(bool write) { 132 volatile jint* loc = &_recorded_nms_lock; 133 if (write) { 134 while ((OrderAccess::load_acquire(loc) != 0) || 135 Atomic::cmpxchg(-1, loc, 0) != 0) { 136 SpinPause(); 137 } 138 assert (*loc == -1, "acquired for write"); 139 } else { 140 while (true) { 141 jint cur = OrderAccess::load_acquire(loc); 142 if (cur >= 0) { 143 if (Atomic::cmpxchg(cur + 1, loc, cur) == cur) { 144 // Success! 145 assert (*loc > 0, "acquired for read"); 146 return; 147 } 148 } 149 SpinPause(); 150 } 151 } 152 } 153 154 static void release_lock(bool write) { 155 volatile jint* loc = &ShenandoahCodeRoots::_recorded_nms_lock; 156 if (write) { 157 OrderAccess::release_store_fence(loc, 0); 158 } else { 159 Atomic::dec(loc); 160 } 161 } 162 }; 163 164 // Very simple unranked read-write lock 165 class ShenandoahCodeRootsLock : public StackObj { 166 friend class ShenandoahCodeRoots; 167 private: 168 const bool _write; 169 public: 170 ShenandoahCodeRootsLock(bool write) : _write(write) { 171 ShenandoahCodeRoots::acquire_lock(write); 172 } 173 174 ~ShenandoahCodeRootsLock() { 175 ShenandoahCodeRoots::release_lock(_write); 176 } 177 }; 178 179 #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHCODEROOTS_HPP