|
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 |