/
shenandoahReferenceProcessor.hpp
193 lines (157 loc) · 7.27 KB
/
shenandoahReferenceProcessor.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2021, Red Hat, Inc. and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP
#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP
#include "gc/shared/referenceDiscoverer.hpp"
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessorStats.hpp"
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
#include "memory/allocation.hpp"
class ShenandoahMarkRefsSuperClosure;
class WorkGang;
static const size_t reference_type_count = REF_PHANTOM + 1;
typedef size_t Counters[reference_type_count];
/*
* Shenandoah concurrent reference processing
*
* Concurrent reference processing is made up of two main phases:
* 1. Concurrent reference marking: Discover all j.l.r.Reference objects and determine reachability of all live objects.
* 2. Concurrent reference processing: For all discoved j.l.r.References, determine whether to keep them alive or clean
* them. Also, clean and enqueue relevant references concurrently.
*
* Concurrent reference marking:
* The goal here is to establish the kind of reachability for all objects on the heap. We distinguish two kinds of
* reachability:
* - An object is 'strongly reachable' if it can be found by searching transitively from GC roots.
* - An object is 'finalizably reachable' if it is not strongly reachable, but can be found by searching
* from the referents of FinalReferences.
*
* These reachabilities are implemented in shenandoahMarkBitMap.*
* Conceptually, marking starts with a strong wavefront at the GC roots. Whenever a Reference object is encountered,
* it may be discovered by the ShenandoahReferenceProcessor. If it is discovered, it
* gets added to the discovered list, and that wavefront stops there, except when it's a FinalReference, in which
* case the wavefront switches to finalizable marking and marks through the referent. When a Reference is not
* discovered, e.g. if it's a SoftReference that is not eligible for discovery, then marking continues as if the
* Reference was a regular object. Whenever a strong wavefront encounters an object that is already marked
* finalizable, then the object's reachability is upgraded to strong.
*
* Concurrent reference processing:
* This happens after the concurrent marking phase and the final marking pause, when reachability for all objects
* has been established.
* The discovered list is scanned and for each reference is decided what to do:
* - If the referent is reachable (finalizable for PhantomReference, strong for all others), then the Reference
* is dropped from the discovered list and otherwise ignored
* - Otherwise its referent becomes cleared and the Reference added to the pending list, from which it will later
* be processed (e.g. enqueued in its ReferenceQueue) by the Java ReferenceHandler thread.
*
* In order to prevent resurrection by Java threads calling Reference.get() concurrently while we are clearing
* referents, we employ a special barrier, the native LRB, which returns NULL when the referent is unreachable.
*/
class ShenandoahRefProcThreadLocal : public CHeapObj<mtGC> {
private:
void* _discovered_list;
ShenandoahMarkRefsSuperClosure* _mark_closure;
Counters _encountered_count;
Counters _discovered_count;
Counters _enqueued_count;
public:
ShenandoahRefProcThreadLocal();
ShenandoahRefProcThreadLocal(const ShenandoahRefProcThreadLocal&) = delete; // non construction-copyable
ShenandoahRefProcThreadLocal& operator=(const ShenandoahRefProcThreadLocal&) = delete; // non copyable
void reset();
ShenandoahMarkRefsSuperClosure* mark_closure() const {
return _mark_closure;
}
void set_mark_closure(ShenandoahMarkRefsSuperClosure* mark_closure) {
_mark_closure = mark_closure;
}
template<typename T>
T* discovered_list_addr();
template<typename T>
oop discovered_list_head() const;
template<typename T>
void set_discovered_list_head(oop head);
size_t encountered(ReferenceType type) const {
return _encountered_count[type];
}
size_t discovered(ReferenceType type) const {
return _discovered_count[type];
}
size_t enqueued(ReferenceType type) const {
return _enqueued_count[type];
}
void inc_encountered(ReferenceType type) {
_encountered_count[type]++;
}
void inc_discovered(ReferenceType type) {
_discovered_count[type]++;
}
void inc_enqueued(ReferenceType type) {
_enqueued_count[type]++;
}
};
class ShenandoahReferenceProcessor : public ReferenceDiscoverer {
private:
ReferencePolicy* _soft_reference_policy;
ShenandoahRefProcThreadLocal* _ref_proc_thread_locals;
oop _pending_list;
void* _pending_list_tail; // T*
volatile uint _iterate_discovered_list_id;
ReferenceProcessorStats _stats;
template <typename T>
bool is_inactive(oop reference, oop referent, ReferenceType type) const;
bool is_strongly_live(oop referent) const;
bool is_softly_live(oop reference, ReferenceType type) const;
template <typename T>
bool should_discover(oop reference, ReferenceType type) const;
template <typename T>
bool should_drop(oop reference, ReferenceType type) const;
template <typename T>
void make_inactive(oop reference, ReferenceType type) const;
template <typename T>
bool discover(oop reference, ReferenceType type, uint worker_id);
template <typename T>
oop drop(oop reference, ReferenceType type);
template <typename T>
T* keep(oop reference, ReferenceType type, uint worker_id);
template <typename T>
void process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id);
void enqueue_references_locked();
void enqueue_references(bool concurrent);
void collect_statistics();
template<typename T>
void clean_discovered_list(T* list);
public:
ShenandoahReferenceProcessor(uint max_workers);
void reset_thread_locals();
void set_mark_closure(uint worker_id, ShenandoahMarkRefsSuperClosure* mark_closure);
void set_soft_reference_policy(bool clear);
bool discover_reference(oop obj, ReferenceType type) override;
void process_references(ShenandoahPhaseTimings::Phase phase, WorkGang* workers, bool concurrent);
const ReferenceProcessorStats& reference_process_stats() { return _stats; }
void work();
void abandon_partial_discovery();
};
#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP