提交 2db1d718 编写于 作者: T tonyp

7046558: G1: concurrent marking optimizations

Summary: Some optimizations to improve the concurrent marking phase: specialize the main oop closure, make sure a few methods in the fast path are properly inlined, a few more bits and pieces, and some cosmetic fixes.
Reviewed-by: stefank, johnc
上级 876798b4
......@@ -24,10 +24,11 @@
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "gc_implementation/g1/concurrentMark.hpp"
#include "gc_implementation/g1/concurrentMark.inline.hpp"
#include "gc_implementation/g1/concurrentMarkThread.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
......@@ -2546,20 +2547,25 @@ public:
};
void ConcurrentMark::deal_with_reference(oop obj) {
if (verbose_high())
if (verbose_high()) {
gclog_or_tty->print_cr("[global] we're dealing with reference "PTR_FORMAT,
(void*) obj);
}
HeapWord* objAddr = (HeapWord*) obj;
assert(obj->is_oop_or_null(true /* ignore mark word */), "Error");
if (_g1h->is_in_g1_reserved(objAddr)) {
assert(obj != NULL, "is_in_g1_reserved should ensure this");
HeapRegion* hr = _g1h->heap_region_containing(obj);
if (_g1h->is_obj_ill(obj, hr)) {
if (verbose_high())
assert(obj != NULL, "null check is implicit");
if (!_nextMarkBitMap->isMarked(objAddr)) {
// Only get the containing region if the object is not marked on the
// bitmap (otherwise, it's a waste of time since we won't do
// anything with it).
HeapRegion* hr = _g1h->heap_region_containing_raw(obj);
if (!hr->obj_allocated_since_next_marking(obj)) {
if (verbose_high()) {
gclog_or_tty->print_cr("[global] "PTR_FORMAT" is not considered "
"marked", (void*) obj);
}
// we need to mark it first
if (_nextMarkBitMap->parMark(objAddr)) {
......@@ -2567,11 +2573,12 @@ void ConcurrentMark::deal_with_reference(oop obj) {
// CAS done in parMark(objAddr) above
HeapWord* finger = _finger;
if (objAddr < finger) {
if (verbose_high())
if (verbose_high()) {
gclog_or_tty->print_cr("[global] below the global finger "
"("PTR_FORMAT"), pushing it", finger);
}
if (!mark_stack_push(obj)) {
if (verbose_low())
if (verbose_low()) {
gclog_or_tty->print_cr("[global] global stack overflow during "
"deal_with_reference");
}
......@@ -2579,6 +2586,8 @@ void ConcurrentMark::deal_with_reference(oop obj) {
}
}
}
}
}
}
void ConcurrentMark::drainAllSATBBuffers() {
......@@ -2631,21 +2640,43 @@ ConcurrentMark::claim_region(int task_num) {
while (finger < _heap_end) {
assert(_g1h->is_in_g1_reserved(finger), "invariant");
// is the gap between reading the finger and doing the CAS too long?
HeapRegion* curr_region = _g1h->heap_region_containing(finger);
// Note on how this code handles humongous regions. In the
// normal case the finger will reach the start of a "starts
// humongous" (SH) region. Its end will either be the end of the
// last "continues humongous" (CH) region in the sequence, or the
// standard end of the SH region (if the SH is the only region in
// the sequence). That way claim_region() will skip over the CH
// regions. However, there is a subtle race between a CM thread
// executing this method and a mutator thread doing a humongous
// object allocation. The two are not mutually exclusive as the CM
// thread does not need to hold the Heap_lock when it gets
// here. So there is a chance that claim_region() will come across
// a free region that's in the progress of becoming a SH or a CH
// region. In the former case, it will either
// a) Miss the update to the region's end, in which case it will
// visit every subsequent CH region, will find their bitmaps
// empty, and do nothing, or
// b) Will observe the update of the region's end (in which case
// it will skip the subsequent CH regions).
// If it comes across a region that suddenly becomes CH, the
// scenario will be similar to b). So, the race between
// claim_region() and a humongous object allocation might force us
// to do a bit of unnecessary work (due to some unnecessary bitmap
// iterations) but it should not introduce and correctness issues.
HeapRegion* curr_region = _g1h->heap_region_containing_raw(finger);
HeapWord* bottom = curr_region->bottom();
HeapWord* end = curr_region->end();
HeapWord* limit = curr_region->next_top_at_mark_start();
if (verbose_low())
if (verbose_low()) {
gclog_or_tty->print_cr("[%d] curr_region = "PTR_FORMAT" "
"["PTR_FORMAT", "PTR_FORMAT"), "
"limit = "PTR_FORMAT,
task_num, curr_region, bottom, end, limit);
}
HeapWord* res =
(HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
// Is the gap between reading the finger and doing the CAS too long?
HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
if (res == finger) {
// we succeeded
......@@ -3191,6 +3222,22 @@ void ConcurrentMark::print_finger() {
}
#endif
void CMTask::scan_object(oop obj) {
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] we're scanning object "PTR_FORMAT,
_task_id, (void*) obj);
}
size_t obj_size = obj->size();
_words_scanned += obj_size;
obj->oop_iterate(_cm_oop_closure);
statsOnly( ++_objs_scanned );
check_limits();
}
// Closure for iteration over bitmaps
class CMBitMapClosure : public BitMapClosure {
private:
......@@ -3254,43 +3301,17 @@ public:
CMObjectClosure(CMTask* task) : _task(task) { }
};
// Closure for iterating over object fields
class CMOopClosure : public OopClosure {
private:
G1CollectedHeap* _g1h;
ConcurrentMark* _cm;
CMTask* _task;
public:
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
virtual void do_oop( oop* p) { do_oop_work(p); }
template <class T> void do_oop_work(T* p) {
assert( _g1h->is_in_g1_reserved((HeapWord*) p), "invariant");
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) p)), "invariant");
oop obj = oopDesc::load_decode_heap_oop(p);
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] we're looking at location "
"*"PTR_FORMAT" = "PTR_FORMAT,
_task->task_id(), p, (void*) obj);
_task->deal_with_reference(obj);
}
CMOopClosure(G1CollectedHeap* g1h,
G1CMOopClosure::G1CMOopClosure(G1CollectedHeap* g1h,
ConcurrentMark* cm,
CMTask* task)
: _g1h(g1h), _cm(cm), _task(task)
{
: _g1h(g1h), _cm(cm), _task(task) {
assert(_ref_processor == NULL, "should be initialized to NULL");
if (G1UseConcMarkReferenceProcessing) {
_ref_processor = g1h->ref_processor();
assert(_ref_processor != NULL, "should not be NULL");
}
}
};
}
void CMTask::setup_for_region(HeapRegion* hr) {
// Separated the asserts so that we know which one fires.
......@@ -3362,6 +3383,15 @@ void CMTask::clear_region_fields() {
_region_finger = NULL;
}
void CMTask::set_cm_oop_closure(G1CMOopClosure* cm_oop_closure) {
if (cm_oop_closure == NULL) {
assert(_cm_oop_closure != NULL, "invariant");
} else {
assert(_cm_oop_closure == NULL, "invariant");
}
_cm_oop_closure = cm_oop_closure;
}
void CMTask::reset(CMBitMap* nextMarkBitMap) {
guarantee(nextMarkBitMap != NULL, "invariant");
......@@ -3411,118 +3441,6 @@ bool CMTask::should_exit_termination() {
return !_cm->mark_stack_empty() || has_aborted();
}
// This determines whether the method below will check both the local
// and global fingers when determining whether to push on the stack a
// gray object (value 1) or whether it will only check the global one
// (value 0). The tradeoffs are that the former will be a bit more
// accurate and possibly push less on the stack, but it might also be
// a little bit slower.
#define _CHECK_BOTH_FINGERS_ 1
void CMTask::deal_with_reference(oop obj) {
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] we're dealing with reference = "PTR_FORMAT,
_task_id, (void*) obj);
++_refs_reached;
HeapWord* objAddr = (HeapWord*) obj;
assert(obj->is_oop_or_null(true /* ignore mark word */), "Error");
if (_g1h->is_in_g1_reserved(objAddr)) {
assert(obj != NULL, "is_in_g1_reserved should ensure this");
HeapRegion* hr = _g1h->heap_region_containing(obj);
if (_g1h->is_obj_ill(obj, hr)) {
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] "PTR_FORMAT" is not considered marked",
_task_id, (void*) obj);
// we need to mark it first
if (_nextMarkBitMap->parMark(objAddr)) {
// No OrderAccess:store_load() is needed. It is implicit in the
// CAS done in parMark(objAddr) above
HeapWord* global_finger = _cm->finger();
#if _CHECK_BOTH_FINGERS_
// we will check both the local and global fingers
if (_finger != NULL && objAddr < _finger) {
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] below the local finger ("PTR_FORMAT"), "
"pushing it", _task_id, _finger);
push(obj);
} else if (_curr_region != NULL && objAddr < _region_limit) {
// do nothing
} else if (objAddr < global_finger) {
// Notice that the global finger might be moving forward
// concurrently. This is not a problem. In the worst case, we
// mark the object while it is above the global finger and, by
// the time we read the global finger, it has moved forward
// passed this object. In this case, the object will probably
// be visited when a task is scanning the region and will also
// be pushed on the stack. So, some duplicate work, but no
// correctness problems.
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] below the global finger "
"("PTR_FORMAT"), pushing it",
_task_id, global_finger);
push(obj);
} else {
// do nothing
}
#else // _CHECK_BOTH_FINGERS_
// we will only check the global finger
if (objAddr < global_finger) {
// see long comment above
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] below the global finger "
"("PTR_FORMAT"), pushing it",
_task_id, global_finger);
push(obj);
}
#endif // _CHECK_BOTH_FINGERS_
}
}
}
}
void CMTask::push(oop obj) {
HeapWord* objAddr = (HeapWord*) obj;
assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
assert(!_g1h->is_obj_ill(obj), "invariant");
assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] pushing "PTR_FORMAT, _task_id, (void*) obj);
if (!_task_queue->push(obj)) {
// The local task queue looks full. We need to push some entries
// to the global stack.
if (_cm->verbose_medium())
gclog_or_tty->print_cr("[%d] task queue overflow, "
"moving entries to the global stack",
_task_id);
move_entries_to_global_stack();
// this should succeed since, even if we overflow the global
// stack, we should have definitely removed some entries from the
// local queue. So, there must be space on it.
bool success = _task_queue->push(obj);
assert(success, "invariant");
}
statsOnly( int tmp_size = _task_queue->size();
if (tmp_size > _local_max_size)
_local_max_size = tmp_size;
++_local_pushes );
}
void CMTask::reached_limit() {
assert(_words_scanned >= _words_scanned_limit ||
_refs_reached >= _refs_reached_limit ,
......@@ -4158,8 +4076,8 @@ void CMTask::do_marking_step(double time_target_ms,
// eventually called from this method, so it is OK to allocate these
// statically.
CMBitMapClosure bitmap_closure(this, _cm, _nextMarkBitMap);
CMOopClosure oop_closure(_g1h, _cm, this);
set_oop_closure(&oop_closure);
G1CMOopClosure cm_oop_closure(_g1h, _cm, this);
set_cm_oop_closure(&cm_oop_closure);
if (_cm->has_overflown()) {
// This can happen if the region stack or the mark stack overflows
......@@ -4435,7 +4353,7 @@ void CMTask::do_marking_step(double time_target_ms,
// Mainly for debugging purposes to make sure that a pointer to the
// closure which was statically allocated in this frame doesn't
// escape it by accident.
set_oop_closure(NULL);
set_cm_oop_closure(NULL);
double end_time_ms = os::elapsedVTime() * 1000.0;
double elapsed_time_ms = end_time_ms - _start_time_ms;
// Update the step history.
......@@ -4510,7 +4428,7 @@ CMTask::CMTask(int task_id,
_nextMarkBitMap(NULL), _hash_seed(17),
_task_queue(task_queue),
_task_queues(task_queues),
_oop_closure(NULL),
_cm_oop_closure(NULL),
_aborted_region(MemRegion()) {
guarantee(task_queue != NULL, "invariant");
guarantee(task_queues != NULL, "invariant");
......
......@@ -131,22 +131,22 @@ class CMBitMap : public CMBitMapRO {
void mark(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
_bm.at_put(heapWordToOffset(addr), true);
_bm.set_bit(heapWordToOffset(addr));
}
void clear(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
_bm.at_put(heapWordToOffset(addr), false);
_bm.clear_bit(heapWordToOffset(addr));
}
bool parMark(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
return _bm.par_at_put(heapWordToOffset(addr), true);
return _bm.par_set_bit(heapWordToOffset(addr));
}
bool parClear(HeapWord* addr) {
assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
"outside underlying space?");
return _bm.par_at_put(heapWordToOffset(addr), false);
return _bm.par_clear_bit(heapWordToOffset(addr));
}
void markRange(MemRegion mr);
void clearAll();
......@@ -928,7 +928,7 @@ private:
double _start_time_ms;
// the oop closure used for iterations over oops
OopClosure* _oop_closure;
G1CMOopClosure* _cm_oop_closure;
// the region this task is scanning, NULL if we're not scanning any
HeapRegion* _curr_region;
......@@ -1122,32 +1122,17 @@ public:
// Clears any recorded partially scanned region
void clear_aborted_region() { set_aborted_region(MemRegion()); }
void set_oop_closure(OopClosure* oop_closure) {
_oop_closure = oop_closure;
}
void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure);
// It grays the object by marking it and, if necessary, pushing it
// on the local queue
void deal_with_reference(oop obj);
inline void deal_with_reference(oop obj);
// It scans an object and visits its children.
void scan_object(oop obj) {
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
if (_cm->verbose_high())
gclog_or_tty->print_cr("[%d] we're scanning object "PTR_FORMAT,
_task_id, (void*) obj);
size_t obj_size = obj->size();
_words_scanned += obj_size;
obj->oop_iterate(_oop_closure);
statsOnly( ++_objs_scanned );
check_limits();
}
void scan_object(oop obj);
// It pushes an object on the local queue.
void push(oop obj);
inline void push(oop obj);
// These two move entries to/from the global stack.
void move_entries_to_global_stack();
......
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* 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_IMPLEMENTATION_G1_CONCURRENTMARK_INLINE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_INLINE_HPP
#include "gc_implementation/g1/concurrentMark.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
inline void CMTask::push(oop obj) {
HeapWord* objAddr = (HeapWord*) obj;
assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
assert(!_g1h->is_obj_ill(obj), "invariant");
assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] pushing "PTR_FORMAT, _task_id, (void*) obj);
}
if (!_task_queue->push(obj)) {
// The local task queue looks full. We need to push some entries
// to the global stack.
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%d] task queue overflow, "
"moving entries to the global stack",
_task_id);
}
move_entries_to_global_stack();
// this should succeed since, even if we overflow the global
// stack, we should have definitely removed some entries from the
// local queue. So, there must be space on it.
bool success = _task_queue->push(obj);
assert(success, "invariant");
}
statsOnly( int tmp_size = _task_queue->size();
if (tmp_size > _local_max_size)
_local_max_size = tmp_size;
++_local_pushes );
}
// This determines whether the method below will check both the local
// and global fingers when determining whether to push on the stack a
// gray object (value 1) or whether it will only check the global one
// (value 0). The tradeoffs are that the former will be a bit more
// accurate and possibly push less on the stack, but it might also be
// a little bit slower.
#define _CHECK_BOTH_FINGERS_ 1
inline void CMTask::deal_with_reference(oop obj) {
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] we're dealing with reference = "PTR_FORMAT,
_task_id, (void*) obj);
}
++_refs_reached;
HeapWord* objAddr = (HeapWord*) obj;
assert(obj->is_oop_or_null(true /* ignore mark word */), "Error");
if (_g1h->is_in_g1_reserved(objAddr)) {
assert(obj != NULL, "null check is implicit");
if (!_nextMarkBitMap->isMarked(objAddr)) {
// Only get the containing region if the object is not marked on the
// bitmap (otherwise, it's a waste of time since we won't do
// anything with it).
HeapRegion* hr = _g1h->heap_region_containing_raw(obj);
if (!hr->obj_allocated_since_next_marking(obj)) {
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] "PTR_FORMAT" is not considered marked",
_task_id, (void*) obj);
}
// we need to mark it first
if (_nextMarkBitMap->parMark(objAddr)) {
// No OrderAccess:store_load() is needed. It is implicit in the
// CAS done in parMark(objAddr) above
HeapWord* global_finger = _cm->finger();
#if _CHECK_BOTH_FINGERS_
// we will check both the local and global fingers
if (_finger != NULL && objAddr < _finger) {
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] below the local finger ("PTR_FORMAT"), "
"pushing it", _task_id, _finger);
}
push(obj);
} else if (_curr_region != NULL && objAddr < _region_limit) {
// do nothing
} else if (objAddr < global_finger) {
// Notice that the global finger might be moving forward
// concurrently. This is not a problem. In the worst case, we
// mark the object while it is above the global finger and, by
// the time we read the global finger, it has moved forward
// passed this object. In this case, the object will probably
// be visited when a task is scanning the region and will also
// be pushed on the stack. So, some duplicate work, but no
// correctness problems.
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] below the global finger "
"("PTR_FORMAT"), pushing it",
_task_id, global_finger);
}
push(obj);
} else {
// do nothing
}
#else // _CHECK_BOTH_FINGERS_
// we will only check the global finger
if (objAddr < global_finger) {
// see long comment above
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] below the global finger "
"("PTR_FORMAT"), pushing it",
_task_id, global_finger);
}
push(obj);
}
#endif // _CHECK_BOTH_FINGERS_
}
}
}
}
}
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTMARK_INLINE_HPP
......@@ -33,6 +33,7 @@ class DirtyCardToOopClosure;
class CMBitMap;
class CMMarkStack;
class G1ParScanThreadState;
class CMTask;
// A class that scans oops in a given heap region (much as OopsInGenClosure
// scans oops in a generation.)
......@@ -176,4 +177,16 @@ public:
int out_of_region() { return _out_of_region; }
};
// Closure for iterating over object fields during concurrent marking
class G1CMOopClosure : public OopClosure {
G1CollectedHeap* _g1h;
ConcurrentMark* _cm;
CMTask* _task;
public:
G1CMOopClosure(G1CollectedHeap* g1h, ConcurrentMark* cm, CMTask* task);
template <class T> void do_oop_nv(T* p);
virtual void do_oop( oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_HPP
......@@ -25,7 +25,7 @@
#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_INLINE_HPP
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_INLINE_HPP
#include "gc_implementation/g1/concurrentMark.hpp"
#include "gc_implementation/g1/concurrentMark.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/g1OopClosures.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
......@@ -108,5 +108,18 @@ template <class T> inline void G1ParPushHeapRSClosure::do_oop_nv(T* p) {
}
}
template <class T> inline void G1CMOopClosure::do_oop_nv(T* p) {
assert(_g1h->is_in_g1_reserved((HeapWord*) p), "invariant");
assert(!_g1h->is_on_master_free_list(
_g1h->heap_region_containing((HeapWord*) p)), "invariant");
oop obj = oopDesc::load_decode_heap_oop(p);
if (_cm->verbose_high()) {
gclog_or_tty->print_cr("[%d] we're looking at location "
"*"PTR_FORMAT" = "PTR_FORMAT,
_task->task_id(), p, (void*) obj);
}
_task->deal_with_reference(obj);
}
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1OOPCLOSURES_INLINE_HPP
......@@ -45,6 +45,7 @@ typedef G1ParCopyClosure<false, G1BarrierEvac, false> G1ParScanHeapEvacClosure;
class FilterIntoCSClosure;
class FilterOutOfRegionClosure;
class G1CMOopClosure;
#ifdef FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES
#error "FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES already defined."
......@@ -55,7 +56,8 @@ class FilterOutOfRegionClosure;
f(G1ParScanClosure,_nv) \
f(G1ParPushHeapRSClosure,_nv) \
f(FilterIntoCSClosure,_nv) \
f(FilterOutOfRegionClosure,_nv)
f(FilterOutOfRegionClosure,_nv) \
f(G1CMOopClosure,_nv)
#ifdef FURTHER_SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES
#error "FURTHER_SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES already defined."
......
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -161,11 +161,11 @@ class BitMap VALUE_OBJ_CLASS_SPEC {
// Set or clear the specified bit.
inline void set_bit(idx_t bit);
void clear_bit(idx_t bit);
inline void clear_bit(idx_t bit);
// Atomically set or clear the specified bit.
bool par_set_bit(idx_t bit);
bool par_clear_bit(idx_t bit);
inline bool par_set_bit(idx_t bit);
inline bool par_clear_bit(idx_t bit);
// Put the given value at the given offset. The parallel version
// will CAS the value into the bitmap and is quite a bit slower.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册