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