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