Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahCodeRoots.cpp
38920 views
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
#include "precompiled.hpp"
25
#include "code/codeCache.hpp"
26
#include "code/nmethod.hpp"
27
#include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"
28
#include "gc_implementation/shenandoah/shenandoahCodeRoots.hpp"
29
#include "memory/resourceArea.hpp"
30
#include "runtime/vmThread.hpp"
31
32
ShenandoahParallelCodeCacheIterator::ShenandoahParallelCodeCacheIterator() :
33
_claimed_idx(0), _finished(false) {
34
}
35
36
void ShenandoahParallelCodeCacheIterator::parallel_blobs_do(CodeBlobClosure* f) {
37
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
38
39
/*
40
* Parallel code heap walk.
41
*
42
* This code makes all threads scan all code heaps, but only one thread would execute the
43
* closure on given blob. This is achieved by recording the "claimed" blocks: if a thread
44
* had claimed the block, it can process all blobs in it. Others have to fast-forward to
45
* next attempt without processing.
46
*
47
* Late threads would return immediately if iterator is finished.
48
*/
49
50
if (_finished) {
51
return;
52
}
53
54
int stride = 256; // educated guess
55
int stride_mask = stride - 1;
56
assert (is_power_of_2(stride), "sanity");
57
58
int count = 0;
59
bool process_block = true;
60
61
for (CodeBlob *cb = CodeCache::first(); cb != NULL; cb = CodeCache::next(cb)) {
62
int current = count++;
63
if ((current & stride_mask) == 0) {
64
process_block = (current >= _claimed_idx) &&
65
(Atomic::cmpxchg(current + stride, &_claimed_idx, current) == current);
66
}
67
if (process_block) {
68
if (cb->is_alive()) {
69
f->do_code_blob(cb);
70
#ifdef ASSERT
71
if (cb->is_nmethod())
72
((nmethod*)cb)->verify_scavenge_root_oops();
73
#endif
74
}
75
}
76
}
77
78
_finished = true;
79
}
80
81
class ShenandoahNMethodOopDetector : public OopClosure {
82
private:
83
ResourceMark rm; // For growable array allocation below.
84
GrowableArray<oop*> _oops;
85
86
public:
87
ShenandoahNMethodOopDetector() : _oops(10) {};
88
89
void do_oop(oop* o) {
90
_oops.append(o);
91
}
92
93
void do_oop(narrowOop* o) {
94
fatal("NMethods should not have compressed oops embedded.");
95
}
96
97
GrowableArray<oop*>* oops() {
98
return &_oops;
99
}
100
101
bool has_oops() {
102
return !_oops.is_empty();
103
}
104
};
105
106
ShenandoahCodeRoots::PaddedLock ShenandoahCodeRoots::_recorded_nms_lock;
107
GrowableArray<ShenandoahNMethod*>* ShenandoahCodeRoots::_recorded_nms;
108
109
void ShenandoahCodeRoots::initialize() {
110
_recorded_nms_lock._lock = 0;
111
_recorded_nms = new (ResourceObj::C_HEAP, mtGC) GrowableArray<ShenandoahNMethod*>(100, true, mtGC);
112
}
113
114
void ShenandoahCodeRoots::add_nmethod(nmethod* nm) {
115
switch (ShenandoahCodeRootsStyle) {
116
case 0:
117
case 1:
118
break;
119
case 2: {
120
ShenandoahNMethodOopDetector detector;
121
nm->oops_do(&detector);
122
123
if (detector.has_oops()) {
124
ShenandoahNMethod* nmr = new ShenandoahNMethod(nm, detector.oops());
125
nmr->assert_alive_and_correct();
126
127
ShenandoahCodeRootsLock lock(true);
128
129
int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod);
130
if (idx != -1) {
131
ShenandoahNMethod* old = _recorded_nms->at(idx);
132
_recorded_nms->at_put(idx, nmr);
133
delete old;
134
} else {
135
_recorded_nms->append(nmr);
136
}
137
}
138
break;
139
}
140
default:
141
ShouldNotReachHere();
142
}
143
};
144
145
void ShenandoahCodeRoots::remove_nmethod(nmethod* nm) {
146
switch (ShenandoahCodeRootsStyle) {
147
case 0:
148
case 1: {
149
break;
150
}
151
case 2: {
152
ShenandoahNMethodOopDetector detector;
153
nm->oops_do(&detector, /* allow_zombie = */ true);
154
155
if (detector.has_oops()) {
156
ShenandoahCodeRootsLock lock(true);
157
158
int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod);
159
assert(idx != -1, err_msg("nmethod " PTR_FORMAT " should be registered", p2i(nm)));
160
ShenandoahNMethod* old = _recorded_nms->at(idx);
161
old->assert_same_oops(detector.oops());
162
_recorded_nms->delete_at(idx);
163
delete old;
164
}
165
break;
166
}
167
default:
168
ShouldNotReachHere();
169
}
170
}
171
172
ShenandoahCodeRootsIterator::ShenandoahCodeRootsIterator() :
173
_heap(ShenandoahHeap::heap()),
174
_claimed(0) {
175
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
176
assert(!Thread::current()->is_Worker_thread(), "Should not be acquired by workers");
177
switch (ShenandoahCodeRootsStyle) {
178
case 0:
179
case 1:
180
break;
181
case 2:
182
ShenandoahCodeRoots::acquire_lock(false);
183
break;
184
default:
185
ShouldNotReachHere();
186
}
187
}
188
189
ShenandoahCodeRootsIterator::~ShenandoahCodeRootsIterator() {
190
switch (ShenandoahCodeRootsStyle) {
191
case 0:
192
case 1: {
193
// No need to do anything here
194
break;
195
}
196
case 2: {
197
ShenandoahCodeRoots::release_lock(false);
198
break;
199
}
200
default:
201
ShouldNotReachHere();
202
}
203
}
204
205
template<bool CSET_FILTER>
206
void ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do(CodeBlobClosure *f) {
207
switch (ShenandoahCodeRootsStyle) {
208
case 0: {
209
if (_seq_claimed.try_set()) {
210
CodeCache::blobs_do(f);
211
}
212
break;
213
}
214
case 1: {
215
_par_iterator.parallel_blobs_do(f);
216
break;
217
}
218
case 2: {
219
ShenandoahCodeRootsIterator::fast_parallel_blobs_do<CSET_FILTER>(f);
220
break;
221
}
222
default:
223
ShouldNotReachHere();
224
}
225
}
226
227
void ShenandoahAllCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) {
228
ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do<false>(f);
229
}
230
231
void ShenandoahCsetCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) {
232
ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do<true>(f);
233
}
234
235
template <bool CSET_FILTER>
236
void ShenandoahCodeRootsIterator::fast_parallel_blobs_do(CodeBlobClosure *f) {
237
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");
238
239
size_t stride = 256; // educated guess
240
241
GrowableArray<ShenandoahNMethod*>* list = ShenandoahCodeRoots::_recorded_nms;
242
243
jlong max = list->length();
244
while (_claimed < max) {
245
size_t cur = (size_t)Atomic::add(stride, &_claimed); // Note: in JDK 8, add() returns old value
246
size_t start = cur;
247
size_t end = MIN2(cur + stride, (size_t) max);
248
if (start >= (size_t)max) break;
249
250
for (size_t idx = start; idx < end; idx++) {
251
ShenandoahNMethod* nmr = list->at((int) idx);
252
nmr->assert_alive_and_correct();
253
254
if (CSET_FILTER && !nmr->has_cset_oops(_heap)) {
255
continue;
256
}
257
258
f->do_code_blob(nmr->nm());
259
}
260
}
261
}
262
263
ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>* oops) {
264
_nm = nm;
265
_oops = NEW_C_HEAP_ARRAY(oop*, oops->length(), mtGC);
266
_oops_count = oops->length();
267
for (int c = 0; c < _oops_count; c++) {
268
_oops[c] = oops->at(c);
269
}
270
}
271
272
ShenandoahNMethod::~ShenandoahNMethod() {
273
if (_oops != NULL) {
274
FREE_C_HEAP_ARRAY(oop*, _oops, mtGC);
275
}
276
}
277
278
bool ShenandoahNMethod::has_cset_oops(ShenandoahHeap *heap) {
279
for (int c = 0; c < _oops_count; c++) {
280
oop o = oopDesc::load_heap_oop(_oops[c]);
281
if (heap->in_collection_set(o)) {
282
return true;
283
}
284
}
285
return false;
286
}
287
288
#ifdef ASSERT
289
void ShenandoahNMethod::assert_alive_and_correct() {
290
assert(_nm->is_alive(), "only alive nmethods here");
291
assert(_oops_count > 0, "should have filtered nmethods without oops before");
292
ShenandoahHeap* heap = ShenandoahHeap::heap();
293
for (int c = 0; c < _oops_count; c++) {
294
oop *loc = _oops[c];
295
assert(_nm->code_contains((address) loc) || _nm->oops_contains(loc), "nmethod should contain the oop*");
296
oop o = oopDesc::load_heap_oop(loc);
297
shenandoah_assert_correct_except(loc, o,
298
o == NULL ||
299
heap->is_full_gc_move_in_progress() ||
300
(VMThread::vm_operation() != NULL) && (VMThread::vm_operation()->type() == VM_Operation::VMOp_HeapWalkOperation)
301
);
302
}
303
}
304
305
void ShenandoahNMethod::assert_same_oops(GrowableArray<oop*>* oops) {
306
assert(_oops_count == oops->length(), "should have the same number of oop*");
307
for (int c = 0; c < _oops_count; c++) {
308
assert(_oops[c] == oops->at(c), "should be the same oop*");
309
}
310
}
311
#endif
312
313