1
|
1 |
/*
|
|
2 |
* Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved.
|
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation.
|
|
8 |
*
|
|
9 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
10 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
11 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
12 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
13 |
* accompanied this code).
|
|
14 |
*
|
|
15 |
* You should have received a copy of the GNU General Public License version
|
|
16 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
17 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
18 |
*
|
|
19 |
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
|
20 |
* CA 95054 USA or visit www.sun.com if you need additional information or
|
|
21 |
* have any questions.
|
|
22 |
*
|
|
23 |
*/
|
|
24 |
|
|
25 |
// ReferenceProcessor class encapsulates the per-"collector" processing
|
|
26 |
// of "weak" references for GC. The interface is useful for supporting
|
|
27 |
// a generational abstraction, in particular when there are multiple
|
|
28 |
// generations that are being independently collected -- possibly
|
|
29 |
// concurrently and/or incrementally. Note, however, that the
|
|
30 |
// ReferenceProcessor class abstracts away from a generational setting
|
|
31 |
// by using only a heap interval (called "span" below), thus allowing
|
|
32 |
// its use in a straightforward manner in a general, non-generational
|
|
33 |
// setting.
|
|
34 |
//
|
|
35 |
// The basic idea is that each ReferenceProcessor object concerns
|
|
36 |
// itself with ("weak") reference processing in a specific "span"
|
|
37 |
// of the heap of interest to a specific collector. Currently,
|
|
38 |
// the span is a convex interval of the heap, but, efficiency
|
|
39 |
// apart, there seems to be no reason it couldn't be extended
|
|
40 |
// (with appropriate modifications) to any "non-convex interval".
|
|
41 |
|
|
42 |
// forward references
|
|
43 |
class ReferencePolicy;
|
|
44 |
class AbstractRefProcTaskExecutor;
|
|
45 |
class DiscoveredList;
|
|
46 |
|
|
47 |
class ReferenceProcessor : public CHeapObj {
|
|
48 |
friend class DiscoveredList;
|
|
49 |
friend class DiscoveredListIterator;
|
|
50 |
protected:
|
|
51 |
// End of list marker
|
|
52 |
static oop _sentinelRef;
|
|
53 |
MemRegion _span; // (right-open) interval of heap
|
|
54 |
// subject to wkref discovery
|
|
55 |
bool _discovering_refs; // true when discovery enabled
|
|
56 |
bool _discovery_is_atomic; // if discovery is atomic wrt
|
|
57 |
// other collectors in configuration
|
|
58 |
bool _discovery_is_mt; // true if reference discovery is MT.
|
|
59 |
bool _enqueuing_is_done; // true if all weak references enqueued
|
|
60 |
bool _processing_is_mt; // true during phases when
|
|
61 |
// reference processing is MT.
|
|
62 |
int _next_id; // round-robin counter in
|
|
63 |
// support of work distribution
|
|
64 |
|
|
65 |
// For collectors that do not keep GC marking information
|
|
66 |
// in the object header, this field holds a closure that
|
|
67 |
// helps the reference processor determine the reachability
|
|
68 |
// of an oop (the field is currently initialized to NULL for
|
|
69 |
// all collectors but the CMS collector).
|
|
70 |
BoolObjectClosure* _is_alive_non_header;
|
|
71 |
|
|
72 |
// The discovered ref lists themselves
|
|
73 |
int _num_q; // the MT'ness degree of the queues below
|
|
74 |
DiscoveredList* _discoveredSoftRefs; // pointer to array of oops
|
|
75 |
DiscoveredList* _discoveredWeakRefs;
|
|
76 |
DiscoveredList* _discoveredFinalRefs;
|
|
77 |
DiscoveredList* _discoveredPhantomRefs;
|
|
78 |
|
|
79 |
public:
|
|
80 |
int num_q() { return _num_q; }
|
|
81 |
DiscoveredList* discovered_soft_refs() { return _discoveredSoftRefs; }
|
|
82 |
static oop* sentinel_ref() { return &_sentinelRef; }
|
|
83 |
|
|
84 |
public:
|
|
85 |
// Process references with a certain reachability level.
|
|
86 |
void process_discovered_reflist(DiscoveredList refs_lists[],
|
|
87 |
ReferencePolicy* policy,
|
|
88 |
bool clear_referent,
|
|
89 |
BoolObjectClosure* is_alive,
|
|
90 |
OopClosure* keep_alive,
|
|
91 |
VoidClosure* complete_gc,
|
|
92 |
AbstractRefProcTaskExecutor* task_executor);
|
|
93 |
|
|
94 |
void process_phaseJNI(BoolObjectClosure* is_alive,
|
|
95 |
OopClosure* keep_alive,
|
|
96 |
VoidClosure* complete_gc);
|
|
97 |
|
|
98 |
// Work methods used by the method process_discovered_reflist
|
|
99 |
// Phase1: keep alive all those referents that are otherwise
|
|
100 |
// dead but which must be kept alive by policy (and their closure).
|
|
101 |
void process_phase1(DiscoveredList& refs_list_addr,
|
|
102 |
ReferencePolicy* policy,
|
|
103 |
BoolObjectClosure* is_alive,
|
|
104 |
OopClosure* keep_alive,
|
|
105 |
VoidClosure* complete_gc);
|
|
106 |
// Phase2: remove all those references whose referents are
|
|
107 |
// reachable.
|
|
108 |
inline void process_phase2(DiscoveredList& refs_list_addr,
|
|
109 |
BoolObjectClosure* is_alive,
|
|
110 |
OopClosure* keep_alive,
|
|
111 |
VoidClosure* complete_gc) {
|
|
112 |
if (discovery_is_atomic()) {
|
|
113 |
// complete_gc is ignored in this case for this phase
|
|
114 |
pp2_work(refs_list_addr, is_alive, keep_alive);
|
|
115 |
} else {
|
|
116 |
assert(complete_gc != NULL, "Error");
|
|
117 |
pp2_work_concurrent_discovery(refs_list_addr, is_alive,
|
|
118 |
keep_alive, complete_gc);
|
|
119 |
}
|
|
120 |
}
|
|
121 |
// Work methods in support of process_phase2
|
|
122 |
void pp2_work(DiscoveredList& refs_list_addr,
|
|
123 |
BoolObjectClosure* is_alive,
|
|
124 |
OopClosure* keep_alive);
|
|
125 |
void pp2_work_concurrent_discovery(
|
|
126 |
DiscoveredList& refs_list_addr,
|
|
127 |
BoolObjectClosure* is_alive,
|
|
128 |
OopClosure* keep_alive,
|
|
129 |
VoidClosure* complete_gc);
|
|
130 |
// Phase3: process the referents by either clearing them
|
|
131 |
// or keeping them alive (and their closure)
|
|
132 |
void process_phase3(DiscoveredList& refs_list_addr,
|
|
133 |
bool clear_referent,
|
|
134 |
BoolObjectClosure* is_alive,
|
|
135 |
OopClosure* keep_alive,
|
|
136 |
VoidClosure* complete_gc);
|
|
137 |
|
|
138 |
// Enqueue references with a certain reachability level
|
|
139 |
void enqueue_discovered_reflist(DiscoveredList& refs_list, oop* pending_list_addr);
|
|
140 |
|
|
141 |
// "Preclean" all the discovered reference lists
|
|
142 |
// by removing references with strongly reachable referents.
|
|
143 |
// The first argument is a predicate on an oop that indicates
|
|
144 |
// its (strong) reachability and the second is a closure that
|
|
145 |
// may be used to incrementalize or abort the precleaning process.
|
|
146 |
// The caller is responsible for taking care of potential
|
|
147 |
// interference with concurrent operations on these lists
|
|
148 |
// (or predicates involved) by other threads. Currently
|
|
149 |
// only used by the CMS collector.
|
|
150 |
void preclean_discovered_references(BoolObjectClosure* is_alive,
|
|
151 |
OopClosure* keep_alive,
|
|
152 |
VoidClosure* complete_gc,
|
|
153 |
YieldClosure* yield);
|
|
154 |
|
|
155 |
// Delete entries in the discovered lists that have
|
|
156 |
// either a null referent or are not active. Such
|
|
157 |
// Reference objects can result from the clearing
|
|
158 |
// or enqueueing of Reference objects concurrent
|
|
159 |
// with their discovery by a (concurrent) collector.
|
|
160 |
// For a definition of "active" see java.lang.ref.Reference;
|
|
161 |
// Refs are born active, become inactive when enqueued,
|
|
162 |
// and never become active again. The state of being
|
|
163 |
// active is encoded as follows: A Ref is active
|
|
164 |
// if and only if its "next" field is NULL.
|
|
165 |
void clean_up_discovered_references();
|
|
166 |
void clean_up_discovered_reflist(DiscoveredList& refs_list);
|
|
167 |
|
|
168 |
// Returns the name of the discovered reference list
|
|
169 |
// occupying the i / _num_q slot.
|
|
170 |
const char* list_name(int i);
|
|
171 |
|
|
172 |
protected:
|
|
173 |
// "Preclean" the given discovered reference list
|
|
174 |
// by removing references with strongly reachable referents.
|
|
175 |
// Currently used in support of CMS only.
|
|
176 |
void preclean_discovered_reflist(DiscoveredList& refs_list,
|
|
177 |
BoolObjectClosure* is_alive,
|
|
178 |
OopClosure* keep_alive,
|
|
179 |
VoidClosure* complete_gc,
|
|
180 |
YieldClosure* yield);
|
|
181 |
|
|
182 |
void enqueue_discovered_reflists(oop* pending_list_addr, AbstractRefProcTaskExecutor* task_executor);
|
|
183 |
int next_id() {
|
|
184 |
int id = _next_id;
|
|
185 |
if (++_next_id == _num_q) {
|
|
186 |
_next_id = 0;
|
|
187 |
}
|
|
188 |
return id;
|
|
189 |
}
|
|
190 |
DiscoveredList* get_discovered_list(ReferenceType rt);
|
|
191 |
inline void add_to_discovered_list_mt(DiscoveredList& refs_list, oop obj,
|
|
192 |
oop* discovered_addr);
|
|
193 |
void verify_ok_to_handle_reflists() PRODUCT_RETURN;
|
|
194 |
|
|
195 |
void abandon_partial_discovered_list(DiscoveredList& refs_list);
|
|
196 |
void abandon_partial_discovered_list_arr(DiscoveredList refs_lists[]);
|
|
197 |
|
|
198 |
// Calculate the number of jni handles.
|
|
199 |
unsigned int count_jni_refs();
|
|
200 |
|
|
201 |
// Balances reference queues.
|
|
202 |
void balance_queues(DiscoveredList ref_lists[]);
|
|
203 |
|
|
204 |
// Update (advance) the soft ref master clock field.
|
|
205 |
void update_soft_ref_master_clock();
|
|
206 |
|
|
207 |
public:
|
|
208 |
// constructor
|
|
209 |
ReferenceProcessor():
|
|
210 |
_span((HeapWord*)NULL, (HeapWord*)NULL),
|
|
211 |
_discoveredSoftRefs(NULL), _discoveredWeakRefs(NULL),
|
|
212 |
_discoveredFinalRefs(NULL), _discoveredPhantomRefs(NULL),
|
|
213 |
_discovering_refs(false),
|
|
214 |
_discovery_is_atomic(true),
|
|
215 |
_enqueuing_is_done(false),
|
|
216 |
_discovery_is_mt(false),
|
|
217 |
_is_alive_non_header(NULL),
|
|
218 |
_num_q(0),
|
|
219 |
_processing_is_mt(false),
|
|
220 |
_next_id(0)
|
|
221 |
{}
|
|
222 |
|
|
223 |
ReferenceProcessor(MemRegion span, bool atomic_discovery,
|
|
224 |
bool mt_discovery, int mt_degree = 1,
|
|
225 |
bool mt_processing = false);
|
|
226 |
|
|
227 |
// Allocates and initializes a reference processor.
|
|
228 |
static ReferenceProcessor* create_ref_processor(
|
|
229 |
MemRegion span,
|
|
230 |
bool atomic_discovery,
|
|
231 |
bool mt_discovery,
|
|
232 |
BoolObjectClosure* is_alive_non_header = NULL,
|
|
233 |
int parallel_gc_threads = 1,
|
|
234 |
bool mt_processing = false);
|
|
235 |
|
|
236 |
// RefDiscoveryPolicy values
|
|
237 |
enum {
|
|
238 |
ReferenceBasedDiscovery = 0,
|
|
239 |
ReferentBasedDiscovery = 1
|
|
240 |
};
|
|
241 |
|
|
242 |
static void init_statics();
|
|
243 |
|
|
244 |
public:
|
|
245 |
// get and set "is_alive_non_header" field
|
|
246 |
BoolObjectClosure* is_alive_non_header() {
|
|
247 |
return _is_alive_non_header;
|
|
248 |
}
|
|
249 |
void set_is_alive_non_header(BoolObjectClosure* is_alive_non_header) {
|
|
250 |
_is_alive_non_header = is_alive_non_header;
|
|
251 |
}
|
|
252 |
|
|
253 |
// get and set span
|
|
254 |
MemRegion span() { return _span; }
|
|
255 |
void set_span(MemRegion span) { _span = span; }
|
|
256 |
|
|
257 |
// start and stop weak ref discovery
|
|
258 |
void enable_discovery() { _discovering_refs = true; }
|
|
259 |
void disable_discovery() { _discovering_refs = false; }
|
|
260 |
bool discovery_enabled() { return _discovering_refs; }
|
|
261 |
|
|
262 |
// whether discovery is atomic wrt other collectors
|
|
263 |
bool discovery_is_atomic() const { return _discovery_is_atomic; }
|
|
264 |
void set_atomic_discovery(bool atomic) { _discovery_is_atomic = atomic; }
|
|
265 |
|
|
266 |
// whether discovery is done by multiple threads same-old-timeously
|
|
267 |
bool discovery_is_mt() const { return _discovery_is_mt; }
|
|
268 |
void set_mt_discovery(bool mt) { _discovery_is_mt = mt; }
|
|
269 |
|
|
270 |
// Whether we are in a phase when _processing_ is MT.
|
|
271 |
bool processing_is_mt() const { return _processing_is_mt; }
|
|
272 |
void set_mt_processing(bool mt) { _processing_is_mt = mt; }
|
|
273 |
|
|
274 |
// whether all enqueuing of weak references is complete
|
|
275 |
bool enqueuing_is_done() { return _enqueuing_is_done; }
|
|
276 |
void set_enqueuing_is_done(bool v) { _enqueuing_is_done = v; }
|
|
277 |
|
|
278 |
// iterate over oops
|
|
279 |
void weak_oops_do(OopClosure* f); // weak roots
|
|
280 |
static void oops_do(OopClosure* f); // strong root(s)
|
|
281 |
|
|
282 |
// Discover a Reference object, using appropriate discovery criteria
|
|
283 |
bool discover_reference(oop obj, ReferenceType rt);
|
|
284 |
|
|
285 |
// Process references found during GC (called by the garbage collector)
|
|
286 |
void process_discovered_references(ReferencePolicy* policy,
|
|
287 |
BoolObjectClosure* is_alive,
|
|
288 |
OopClosure* keep_alive,
|
|
289 |
VoidClosure* complete_gc,
|
|
290 |
AbstractRefProcTaskExecutor* task_executor);
|
|
291 |
|
|
292 |
public:
|
|
293 |
// Enqueue references at end of GC (called by the garbage collector)
|
|
294 |
bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL);
|
|
295 |
|
|
296 |
// debugging
|
|
297 |
void verify_no_references_recorded() PRODUCT_RETURN;
|
|
298 |
static void verify();
|
|
299 |
|
|
300 |
// clear the discovered lists (unlinking each entry).
|
|
301 |
void clear_discovered_references() PRODUCT_RETURN;
|
|
302 |
};
|
|
303 |
|
|
304 |
// A utility class to disable reference discovery in
|
|
305 |
// the scope which contains it, for given ReferenceProcessor.
|
|
306 |
class NoRefDiscovery: StackObj {
|
|
307 |
private:
|
|
308 |
ReferenceProcessor* _rp;
|
|
309 |
bool _was_discovering_refs;
|
|
310 |
public:
|
|
311 |
NoRefDiscovery(ReferenceProcessor* rp) : _rp(rp) {
|
|
312 |
if (_was_discovering_refs = _rp->discovery_enabled()) {
|
|
313 |
_rp->disable_discovery();
|
|
314 |
}
|
|
315 |
}
|
|
316 |
|
|
317 |
~NoRefDiscovery() {
|
|
318 |
if (_was_discovering_refs) {
|
|
319 |
_rp->enable_discovery();
|
|
320 |
}
|
|
321 |
}
|
|
322 |
};
|
|
323 |
|
|
324 |
|
|
325 |
// A utility class to temporarily mutate the span of the
|
|
326 |
// given ReferenceProcessor in the scope that contains it.
|
|
327 |
class ReferenceProcessorSpanMutator: StackObj {
|
|
328 |
private:
|
|
329 |
ReferenceProcessor* _rp;
|
|
330 |
MemRegion _saved_span;
|
|
331 |
|
|
332 |
public:
|
|
333 |
ReferenceProcessorSpanMutator(ReferenceProcessor* rp,
|
|
334 |
MemRegion span):
|
|
335 |
_rp(rp) {
|
|
336 |
_saved_span = _rp->span();
|
|
337 |
_rp->set_span(span);
|
|
338 |
}
|
|
339 |
|
|
340 |
~ReferenceProcessorSpanMutator() {
|
|
341 |
_rp->set_span(_saved_span);
|
|
342 |
}
|
|
343 |
};
|
|
344 |
|
|
345 |
// A utility class to temporarily change the MT'ness of
|
|
346 |
// reference discovery for the given ReferenceProcessor
|
|
347 |
// in the scope that contains it.
|
|
348 |
class ReferenceProcessorMTMutator: StackObj {
|
|
349 |
private:
|
|
350 |
ReferenceProcessor* _rp;
|
|
351 |
bool _saved_mt;
|
|
352 |
|
|
353 |
public:
|
|
354 |
ReferenceProcessorMTMutator(ReferenceProcessor* rp,
|
|
355 |
bool mt):
|
|
356 |
_rp(rp) {
|
|
357 |
_saved_mt = _rp->discovery_is_mt();
|
|
358 |
_rp->set_mt_discovery(mt);
|
|
359 |
}
|
|
360 |
|
|
361 |
~ReferenceProcessorMTMutator() {
|
|
362 |
_rp->set_mt_discovery(_saved_mt);
|
|
363 |
}
|
|
364 |
};
|
|
365 |
|
|
366 |
|
|
367 |
// A utility class to temporarily change the disposition
|
|
368 |
// of the "is_alive_non_header" closure field of the
|
|
369 |
// given ReferenceProcessor in the scope that contains it.
|
|
370 |
class ReferenceProcessorIsAliveMutator: StackObj {
|
|
371 |
private:
|
|
372 |
ReferenceProcessor* _rp;
|
|
373 |
BoolObjectClosure* _saved_cl;
|
|
374 |
|
|
375 |
public:
|
|
376 |
ReferenceProcessorIsAliveMutator(ReferenceProcessor* rp,
|
|
377 |
BoolObjectClosure* cl):
|
|
378 |
_rp(rp) {
|
|
379 |
_saved_cl = _rp->is_alive_non_header();
|
|
380 |
_rp->set_is_alive_non_header(cl);
|
|
381 |
}
|
|
382 |
|
|
383 |
~ReferenceProcessorIsAliveMutator() {
|
|
384 |
_rp->set_is_alive_non_header(_saved_cl);
|
|
385 |
}
|
|
386 |
};
|
|
387 |
|
|
388 |
// A utility class to temporarily change the disposition
|
|
389 |
// of the "discovery_is_atomic" field of the
|
|
390 |
// given ReferenceProcessor in the scope that contains it.
|
|
391 |
class ReferenceProcessorAtomicMutator: StackObj {
|
|
392 |
private:
|
|
393 |
ReferenceProcessor* _rp;
|
|
394 |
bool _saved_atomic_discovery;
|
|
395 |
|
|
396 |
public:
|
|
397 |
ReferenceProcessorAtomicMutator(ReferenceProcessor* rp,
|
|
398 |
bool atomic):
|
|
399 |
_rp(rp) {
|
|
400 |
_saved_atomic_discovery = _rp->discovery_is_atomic();
|
|
401 |
_rp->set_atomic_discovery(atomic);
|
|
402 |
}
|
|
403 |
|
|
404 |
~ReferenceProcessorAtomicMutator() {
|
|
405 |
_rp->set_atomic_discovery(_saved_atomic_discovery);
|
|
406 |
}
|
|
407 |
};
|
|
408 |
|
|
409 |
|
|
410 |
// A utility class to temporarily change the MT processing
|
|
411 |
// disposition of the given ReferenceProcessor instance
|
|
412 |
// in the scope that contains it.
|
|
413 |
class ReferenceProcessorMTProcMutator: StackObj {
|
|
414 |
private:
|
|
415 |
ReferenceProcessor* _rp;
|
|
416 |
bool _saved_mt;
|
|
417 |
|
|
418 |
public:
|
|
419 |
ReferenceProcessorMTProcMutator(ReferenceProcessor* rp,
|
|
420 |
bool mt):
|
|
421 |
_rp(rp) {
|
|
422 |
_saved_mt = _rp->processing_is_mt();
|
|
423 |
_rp->set_mt_processing(mt);
|
|
424 |
}
|
|
425 |
|
|
426 |
~ReferenceProcessorMTProcMutator() {
|
|
427 |
_rp->set_mt_processing(_saved_mt);
|
|
428 |
}
|
|
429 |
};
|
|
430 |
|
|
431 |
|
|
432 |
// This class is an interface used to implement task execution for the
|
|
433 |
// reference processing.
|
|
434 |
class AbstractRefProcTaskExecutor {
|
|
435 |
public:
|
|
436 |
|
|
437 |
// Abstract tasks to execute.
|
|
438 |
class ProcessTask;
|
|
439 |
class EnqueueTask;
|
|
440 |
|
|
441 |
// Executes a task using worker threads.
|
|
442 |
virtual void execute(ProcessTask& task) = 0;
|
|
443 |
virtual void execute(EnqueueTask& task) = 0;
|
|
444 |
|
|
445 |
// Switch to single threaded mode.
|
|
446 |
virtual void set_single_threaded_mode() { };
|
|
447 |
};
|
|
448 |
|
|
449 |
// Abstract reference processing task to execute.
|
|
450 |
class AbstractRefProcTaskExecutor::ProcessTask {
|
|
451 |
protected:
|
|
452 |
ProcessTask(ReferenceProcessor& ref_processor,
|
|
453 |
DiscoveredList refs_lists[],
|
|
454 |
bool marks_oops_alive)
|
|
455 |
: _ref_processor(ref_processor),
|
|
456 |
_refs_lists(refs_lists),
|
|
457 |
_marks_oops_alive(marks_oops_alive)
|
|
458 |
{ }
|
|
459 |
|
|
460 |
public:
|
|
461 |
virtual void work(unsigned int work_id, BoolObjectClosure& is_alive,
|
|
462 |
OopClosure& keep_alive,
|
|
463 |
VoidClosure& complete_gc) = 0;
|
|
464 |
|
|
465 |
// Returns true if a task marks some oops as alive.
|
|
466 |
bool marks_oops_alive() const
|
|
467 |
{ return _marks_oops_alive; }
|
|
468 |
|
|
469 |
protected:
|
|
470 |
ReferenceProcessor& _ref_processor;
|
|
471 |
DiscoveredList* _refs_lists;
|
|
472 |
const bool _marks_oops_alive;
|
|
473 |
};
|
|
474 |
|
|
475 |
// Abstract reference processing task to execute.
|
|
476 |
class AbstractRefProcTaskExecutor::EnqueueTask {
|
|
477 |
protected:
|
|
478 |
EnqueueTask(ReferenceProcessor& ref_processor,
|
|
479 |
DiscoveredList refs_lists[],
|
|
480 |
oop* pending_list_addr,
|
|
481 |
oop sentinel_ref,
|
|
482 |
int n_queues)
|
|
483 |
: _ref_processor(ref_processor),
|
|
484 |
_refs_lists(refs_lists),
|
|
485 |
_pending_list_addr(pending_list_addr),
|
|
486 |
_sentinel_ref(sentinel_ref),
|
|
487 |
_n_queues(n_queues)
|
|
488 |
{ }
|
|
489 |
|
|
490 |
public:
|
|
491 |
virtual void work(unsigned int work_id) = 0;
|
|
492 |
|
|
493 |
protected:
|
|
494 |
ReferenceProcessor& _ref_processor;
|
|
495 |
DiscoveredList* _refs_lists;
|
|
496 |
oop* _pending_list_addr;
|
|
497 |
oop _sentinel_ref;
|
|
498 |
int _n_queues;
|
|
499 |
};
|