提交 569b6fe2 编写于 作者: Y ysr

6948538: CMS: BOT walkers can fall into object allocation and initialization cracks

Summary: GC workers now recognize an intermediate transient state of blocks which are allocated but have not yet completed initialization. blk_start() calls do not attempt to determine the size of a block in the transient state, rather waiting for the block to become initialized so that it is safe to query its size. Audited and ensured the order of initialization of object fields (klass, free bit and size) to respect block state transition protocol. Also included some new assertion checking code enabled in debug mode.
Reviewed-by: chrisphi, johnc, poonam
上级 8d445df7
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, 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
......@@ -402,6 +402,29 @@ size_t CompactibleFreeListSpace::max_alloc_in_words() const {
return res;
}
void LinearAllocBlock::print_on(outputStream* st) const {
st->print_cr(" LinearAllocBlock: ptr = " PTR_FORMAT ", word_size = " SIZE_FORMAT
", refillsize = " SIZE_FORMAT ", allocation_size_limit = " SIZE_FORMAT,
_ptr, _word_size, _refillSize, _allocation_size_limit);
}
void CompactibleFreeListSpace::print_on(outputStream* st) const {
st->print_cr("COMPACTIBLE FREELIST SPACE");
st->print_cr(" Space:");
Space::print_on(st);
st->print_cr("promoInfo:");
_promoInfo.print_on(st);
st->print_cr("_smallLinearAllocBlock");
_smallLinearAllocBlock.print_on(st);
// dump_memory_block(_smallLinearAllocBlock->_ptr, 128);
st->print_cr(" _fitStrategy = %s, _adaptive_freelists = %s",
_fitStrategy?"true":"false", _adaptive_freelists?"true":"false");
}
void CompactibleFreeListSpace::print_indexed_free_lists(outputStream* st)
const {
reportIndexedFreeListStatistics();
......@@ -557,13 +580,15 @@ size_t CompactibleFreeListSpace::maxChunkSizeInIndexedFreeLists() const {
void CompactibleFreeListSpace::set_end(HeapWord* value) {
HeapWord* prevEnd = end();
assert(prevEnd != value, "unnecessary set_end call");
assert(prevEnd == NULL || value >= unallocated_block(), "New end is below unallocated block");
assert(prevEnd == NULL || !BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(),
"New end is below unallocated block");
_end = value;
if (prevEnd != NULL) {
// Resize the underlying block offset table.
_bt.resize(pointer_delta(value, bottom()));
if (value <= prevEnd) {
assert(value >= unallocated_block(), "New end is below unallocated block");
assert(!BlockOffsetArrayUseUnallocatedBlock || value >= unallocated_block(),
"New end is below unallocated block");
} else {
// Now, take this new chunk and add it to the free blocks.
// Note that the BOT has not yet been updated for this block.
......@@ -938,7 +963,6 @@ HeapWord* CompactibleFreeListSpace::block_start_careful(const void* p) const {
size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const {
NOT_PRODUCT(verify_objects_initialized());
assert(MemRegion(bottom(), end()).contains(p), "p not in space");
// This must be volatile, or else there is a danger that the compiler
// will compile the code below into a sometimes-infinite loop, by keeping
// the value read the first time in a register.
......@@ -957,7 +981,7 @@ size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const {
// must read from what 'p' points to in each loop.
klassOop k = ((volatile oopDesc*)p)->klass_or_null();
if (k != NULL) {
assert(k->is_oop(true /* ignore mark word */), "Should really be klass oop.");
assert(k->is_oop(true /* ignore mark word */), "Should be klass oop");
oop o = (oop)p;
assert(o->is_parsable(), "Should be parsable");
assert(o->is_oop(true /* ignore mark word */), "Should be an oop.");
......@@ -1231,7 +1255,6 @@ HeapWord* CompactibleFreeListSpace::allocate_adaptive_freelists(size_t size) {
// satisfy the request. This is different that
// evm.
// Don't record chunk off a LinAB? smallSplitBirth(size);
} else {
// Raid the exact free lists larger than size, even if they are not
// overpopulated.
......@@ -1449,6 +1472,7 @@ CompactibleFreeListSpace::getChunkFromLinearAllocBlock(LinearAllocBlock *blk,
// Update BOT last so that other (parallel) GC threads see a consistent
// view of the BOT and free blocks.
// Above must occur before BOT is updated below.
OrderAccess::storestore();
_bt.split_block(res, blk_size, size); // adjust block offset table
}
return res;
......@@ -1477,6 +1501,7 @@ HeapWord* CompactibleFreeListSpace::getChunkFromLinearAllocBlockRemainder(
// Update BOT last so that other (parallel) GC threads see a consistent
// view of the BOT and free blocks.
// Above must occur before BOT is updated below.
OrderAccess::storestore();
_bt.split_block(res, blk_size, size); // adjust block offset table
_bt.allocated(res, size);
}
......@@ -1856,6 +1881,8 @@ CompactibleFreeListSpace::splitChunkAndReturnRemainder(FreeChunk* chunk,
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
// Above must occur before BOT is updated below.
// adjust block offset table
OrderAccess::storestore();
assert(chunk->isFree() && ffc->isFree(), "Error");
_bt.split_block((HeapWord*)chunk, chunk->size(), new_size);
if (rem_size < SmallForDictionary) {
bool is_par = (SharedHeap::heap()->n_par_threads() > 0);
......@@ -1911,8 +1938,7 @@ void CompactibleFreeListSpace::save_marks() {
// mark the "end" of the used space at the time of this call;
// note, however, that promoted objects from this point
// on are tracked in the _promoInfo below.
set_saved_mark_word(BlockOffsetArrayUseUnallocatedBlock ?
unallocated_block() : end());
set_saved_mark_word(unallocated_block());
// inform allocator that promotions should be tracked.
assert(_promoInfo.noPromotions(), "_promoInfo inconsistency");
_promoInfo.startTrackingPromotions();
......@@ -2238,8 +2264,7 @@ void CompactibleFreeListSpace::split(size_t from, size_t to1) {
}
void CompactibleFreeListSpace::print() const {
tty->print(" CompactibleFreeListSpace");
Space::print();
Space::print_on(tty);
}
void CompactibleFreeListSpace::prepare_for_verify() {
......@@ -2253,18 +2278,28 @@ class VerifyAllBlksClosure: public BlkClosure {
private:
const CompactibleFreeListSpace* _sp;
const MemRegion _span;
HeapWord* _last_addr;
size_t _last_size;
bool _last_was_obj;
bool _last_was_live;
public:
VerifyAllBlksClosure(const CompactibleFreeListSpace* sp,
MemRegion span) : _sp(sp), _span(span) { }
MemRegion span) : _sp(sp), _span(span),
_last_addr(NULL), _last_size(0),
_last_was_obj(false), _last_was_live(false) { }
virtual size_t do_blk(HeapWord* addr) {
size_t res;
bool was_obj = false;
bool was_live = false;
if (_sp->block_is_obj(addr)) {
was_obj = true;
oop p = oop(addr);
guarantee(p->is_oop(), "Should be an oop");
res = _sp->adjustObjectSize(p->size());
if (_sp->obj_is_alive(addr)) {
was_live = true;
p->verify();
}
} else {
......@@ -2275,7 +2310,20 @@ class VerifyAllBlksClosure: public BlkClosure {
"Chunk should be on a free list");
}
}
guarantee(res != 0, "Livelock: no rank reduction!");
if (res == 0) {
gclog_or_tty->print_cr("Livelock: no rank reduction!");
gclog_or_tty->print_cr(
" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
" Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
addr, res, was_obj ?"true":"false", was_live ?"true":"false",
_last_addr, _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false");
_sp->print_on(gclog_or_tty);
guarantee(false, "Seppuku!");
}
_last_addr = addr;
_last_size = res;
_last_was_obj = was_obj;
_last_was_live = was_live;
return res;
}
};
......@@ -2521,7 +2569,7 @@ void CFLS_LAB::modify_initialization(size_t n, unsigned wt) {
HeapWord* CFLS_LAB::alloc(size_t word_sz) {
FreeChunk* res;
word_sz = _cfls->adjustObjectSize(word_sz);
guarantee(word_sz == _cfls->adjustObjectSize(word_sz), "Error");
if (word_sz >= CompactibleFreeListSpace::IndexSetSize) {
// This locking manages sync with other large object allocations.
MutexLockerEx x(_cfls->parDictionaryAllocLock(),
......@@ -2667,12 +2715,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
(CMSSplitIndexedFreeListBlocks || k <= 1);
k++, cur_sz = k * word_sz) {
FreeList* gfl = &_indexedFreeList[cur_sz];
FreeList fl_for_cur_sz; // Empty.
fl_for_cur_sz.set_size(cur_sz);
{
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
Mutex::_no_safepoint_check_flag);
FreeList* gfl = &_indexedFreeList[cur_sz];
if (gfl->count() != 0) {
// nn is the number of chunks of size cur_sz that
// we'd need to split k-ways each, in order to create
......@@ -2685,9 +2733,9 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
// we increment the split death count by the number of blocks
// we just took from the cur_sz-size blocks list and which
// we will be splitting below.
ssize_t deaths = _indexedFreeList[cur_sz].splitDeaths() +
ssize_t deaths = gfl->splitDeaths() +
fl_for_cur_sz.count();
_indexedFreeList[cur_sz].set_splitDeaths(deaths);
gfl->set_splitDeaths(deaths);
}
}
}
......@@ -2703,18 +2751,25 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
// access the main chunk sees it as a single free block until we
// change it.
size_t fc_size = fc->size();
assert(fc->isFree(), "Error");
for (int i = k-1; i >= 0; i--) {
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
assert((i != 0) ||
((fc == ffc) && ffc->isFree() &&
(ffc->size() == k*word_sz) && (fc_size == word_sz)),
"Counting error");
ffc->setSize(word_sz);
ffc->linkNext(NULL);
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
ffc->linkNext(NULL);
// Above must occur before BOT is updated below.
// splitting from the right, fc_size == (k - i + 1) * wordsize
_bt.mark_block((HeapWord*)ffc, word_sz);
OrderAccess::storestore();
// splitting from the right, fc_size == i * word_sz
_bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */);
fc_size -= word_sz;
_bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
assert(fc_size == i*word_sz, "Error");
_bt.verify_not_unallocated((HeapWord*)ffc, word_sz);
_bt.verify_single_block((HeapWord*)fc, fc_size);
_bt.verify_single_block((HeapWord*)ffc, ffc->size());
_bt.verify_single_block((HeapWord*)ffc, word_sz);
// Push this on "fl".
fl->returnChunkAtHead(ffc);
}
......@@ -2744,7 +2799,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
_dictionary->minSize()),
FreeBlockDictionary::atLeast);
if (fc != NULL) {
_bt.allocated((HeapWord*)fc, fc->size()); // update _unallocated_blk
_bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk
dictionary()->dictCensusUpdate(fc->size(),
true /*split*/,
false /*birth*/);
......@@ -2754,8 +2809,10 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
}
}
if (fc == NULL) return;
assert((ssize_t)n >= 1, "Control point invariant");
// Otherwise, split up that block.
assert((ssize_t)n >= 1, "Control point invariant");
assert(fc->isFree(), "Error: should be a free block");
_bt.verify_single_block((HeapWord*)fc, fc->size());
const size_t nn = fc->size() / word_sz;
n = MIN2(nn, n);
assert((ssize_t)n >= 1, "Control point invariant");
......@@ -2773,6 +2830,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
// dictionary and return, leaving "fl" empty.
if (n == 0) {
returnChunkToDictionary(fc);
assert(fl->count() == 0, "We never allocated any blocks");
return;
}
......@@ -2785,11 +2843,14 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
size_t prefix_size = n * word_sz;
rem_fc = (FreeChunk*)((HeapWord*)fc + prefix_size);
rem_fc->setSize(rem);
rem_fc->linkNext(NULL);
rem_fc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
rem_fc->linkNext(NULL);
// Above must occur before BOT is updated below.
assert((ssize_t)n > 0 && prefix_size > 0 && rem_fc > fc, "Error");
OrderAccess::storestore();
_bt.split_block((HeapWord*)fc, fc->size(), prefix_size);
assert(fc->isFree(), "Error");
fc->setSize(prefix_size);
if (rem >= IndexSetSize) {
returnChunkToDictionary(rem_fc);
dictionary()->dictCensusUpdate(rem, true /*split*/, true /*birth*/);
......@@ -2815,11 +2876,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
for (ssize_t i = n-1; i > 0; i--) {
FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz);
ffc->setSize(word_sz);
ffc->linkNext(NULL);
ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads.
ffc->linkNext(NULL);
// Above must occur before BOT is updated below.
OrderAccess::storestore();
// splitting from the right, fc_size == (n - i + 1) * wordsize
_bt.mark_block((HeapWord*)ffc, word_sz);
_bt.mark_block((HeapWord*)ffc, word_sz, true /* reducing */);
fc_size -= word_sz;
_bt.verify_not_unallocated((HeapWord*)ffc, ffc->size());
_bt.verify_single_block((HeapWord*)ffc, ffc->size());
......@@ -2828,9 +2890,11 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
fl->returnChunkAtHead(ffc);
}
// First chunk
assert(fc->isFree() && fc->size() == n*word_sz, "Error: should still be a free block");
// The blocks above should show their new sizes before the first block below
fc->setSize(word_sz);
fc->linkPrev(NULL); // idempotent wrt free-ness, see assert above
fc->linkNext(NULL);
fc->linkPrev(NULL);
_bt.verify_not_unallocated((HeapWord*)fc, fc->size());
_bt.verify_single_block((HeapWord*)fc, fc->size());
fl->returnChunkAtHead(fc);
......
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, 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
......@@ -48,6 +48,8 @@ class LinearAllocBlock VALUE_OBJ_CLASS_SPEC {
size_t _word_size;
size_t _refillSize;
size_t _allocation_size_limit; // largest size that will be allocated
void print_on(outputStream* st) const;
};
// Concrete subclass of CompactibleSpace that implements
......@@ -249,10 +251,14 @@ class CompactibleFreeListSpace: public CompactibleSpace {
size_t numFreeBlocksInIndexedFreeLists() const;
// Accessor
HeapWord* unallocated_block() const {
if (BlockOffsetArrayUseUnallocatedBlock) {
HeapWord* ub = _bt.unallocated_block();
assert(ub >= bottom() &&
ub <= end(), "space invariant");
return ub;
} else {
return end();
}
}
void freed(HeapWord* start, size_t size) {
_bt.freed(start, size);
......@@ -476,6 +482,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
// Debugging support
void print() const;
void print_on(outputStream* st) const;
void prepare_for_verify();
void verify(bool allow_dirty) const;
void verifyFreeLists() const PRODUCT_RETURN;
......
......@@ -1019,7 +1019,7 @@ HeapWord* ConcurrentMarkSweepGeneration::allocate(size_t size,
}
HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size,
bool tlab) {
bool tlab /* ignored */) {
assert_lock_strong(freelistLock());
size_t adjustedSize = CompactibleFreeListSpace::adjustObjectSize(size);
HeapWord* res = cmsSpace()->allocate(adjustedSize);
......@@ -1032,6 +1032,11 @@ HeapWord* ConcurrentMarkSweepGeneration::have_lock_and_allocate(size_t size,
// allowing the object to be blackened (and its references scanned)
// either during a preclean phase or at the final checkpoint.
if (res != NULL) {
// We may block here with an uninitialized object with
// its mark-bit or P-bits not yet set. Such objects need
// to be safely navigable by block_start().
assert(oop(res)->klass_or_null() == NULL, "Object should be uninitialized here.");
assert(!((FreeChunk*)res)->isFree(), "Error, block will look free but show wrong size");
collector()->direct_allocated(res, adjustedSize);
_direct_allocated_words += adjustedSize;
// allocation counters
......@@ -1061,8 +1066,14 @@ void CMSCollector::direct_allocated(HeapWord* start, size_t size) {
// [see comments preceding SweepClosure::do_blk() below for details]
// 1. need to mark the object as live so it isn't collected
// 2. need to mark the 2nd bit to indicate the object may be uninitialized
// 3. need to mark the end of the object so sweeper can skip over it
// if it's uninitialized when the sweeper reaches it.
// 3. need to mark the end of the object so marking, precleaning or sweeping
// can skip over uninitialized or unparsable objects. An allocated
// object is considered uninitialized for our purposes as long as
// its klass word is NULL. (Unparsable objects are those which are
// initialized in the sense just described, but whose sizes can still
// not be correctly determined. Note that the class of unparsable objects
// can only occur in the perm gen. All old gen objects are parsable
// as soon as they are initialized.)
_markBitMap.mark(start); // object is live
_markBitMap.mark(start + 1); // object is potentially uninitialized?
_markBitMap.mark(start + size - 1);
......@@ -1088,7 +1099,13 @@ void CMSCollector::promoted(bool par, HeapWord* start,
// We don't need to mark the object as uninitialized (as
// in direct_allocated above) because this is being done with the
// world stopped and the object will be initialized by the
// time the sweeper gets to look at it.
// time the marking, precleaning or sweeping get to look at it.
// But see the code for copying objects into the CMS generation,
// where we need to ensure that concurrent readers of the
// block offset table are able to safely navigate a block that
// is in flux from being free to being allocated (and in
// transition while being copied into) and subsequently
// becoming a bona-fide object when the copy/promotion is complete.
assert(SafepointSynchronize::is_at_safepoint(),
"expect promotion only at safepoints");
......@@ -1304,6 +1321,48 @@ ConcurrentMarkSweepGeneration::allocation_limit_reached(Space* space,
return collector()->allocation_limit_reached(space, top, word_sz);
}
// IMPORTANT: Notes on object size recognition in CMS.
// ---------------------------------------------------
// A block of storage in the CMS generation is always in
// one of three states. A free block (FREE), an allocated
// object (OBJECT) whose size() method reports the correct size,
// and an intermediate state (TRANSIENT) in which its size cannot
// be accurately determined.
// STATE IDENTIFICATION: (32 bit and 64 bit w/o COOPS)
// -----------------------------------------------------
// FREE: klass_word & 1 == 1; mark_word holds block size
//
// OBJECT: klass_word installed; klass_word != 0 && klass_word & 0 == 0;
// obj->size() computes correct size
// [Perm Gen objects needs to be "parsable" before they can be navigated]
//
// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
//
// STATE IDENTIFICATION: (64 bit+COOPS)
// ------------------------------------
// FREE: mark_word & CMS_FREE_BIT == 1; mark_word & ~CMS_FREE_BIT gives block_size
//
// OBJECT: klass_word installed; klass_word != 0;
// obj->size() computes correct size
// [Perm Gen comment above continues to hold]
//
// TRANSIENT: klass_word == 0; size is indeterminate until we become an OBJECT
//
//
// STATE TRANSITION DIAGRAM
//
// mut / parnew mut / parnew
// FREE --------------------> TRANSIENT ---------------------> OBJECT --|
// ^ |
// |------------------------ DEAD <------------------------------------|
// sweep mut
//
// While a block is in TRANSIENT state its size cannot be determined
// so readers will either need to come back later or stall until
// the size can be determined. Note that for the case of direct
// allocation, P-bits, when available, may be used to determine the
// size of an object that may not yet have been initialized.
// Things to support parallel young-gen collection.
oop
ConcurrentMarkSweepGeneration::par_promote(int thread_num,
......@@ -1331,33 +1390,39 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num,
}
}
assert(promoInfo->has_spooling_space(), "Control point invariant");
HeapWord* obj_ptr = ps->lab.alloc(word_sz);
const size_t alloc_sz = CompactibleFreeListSpace::adjustObjectSize(word_sz);
HeapWord* obj_ptr = ps->lab.alloc(alloc_sz);
if (obj_ptr == NULL) {
obj_ptr = expand_and_par_lab_allocate(ps, word_sz);
obj_ptr = expand_and_par_lab_allocate(ps, alloc_sz);
if (obj_ptr == NULL) {
return NULL;
}
}
oop obj = oop(obj_ptr);
OrderAccess::storestore();
assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
// IMPORTANT: See note on object initialization for CMS above.
// Otherwise, copy the object. Here we must be careful to insert the
// klass pointer last, since this marks the block as an allocated object.
// Except with compressed oops it's the mark word.
HeapWord* old_ptr = (HeapWord*)old;
// Restore the mark word copied above.
obj->set_mark(m);
assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
OrderAccess::storestore();
if (UseCompressedOops) {
// Copy gap missed by (aligned) header size calculation below
obj->set_klass_gap(old->klass_gap());
}
if (word_sz > (size_t)oopDesc::header_size()) {
Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(),
obj_ptr + oopDesc::header_size(),
word_sz - oopDesc::header_size());
}
if (UseCompressedOops) {
// Copy gap missed by (aligned) header size calculation above
obj->set_klass_gap(old->klass_gap());
}
// Restore the mark word copied above.
obj->set_mark(m);
// Now we can track the promoted object, if necessary. We take care
// to delay the transition from uninitialized to full object
// (i.e., insertion of klass pointer) until after, so that it
......@@ -1365,18 +1430,22 @@ ConcurrentMarkSweepGeneration::par_promote(int thread_num,
if (promoInfo->tracking()) {
promoInfo->track((PromotedObject*)obj, old->klass());
}
assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
assert(!((FreeChunk*)obj_ptr)->isFree(), "Error, block will look free but show wrong size");
assert(old->is_oop(), "Will use and dereference old klass ptr below");
// Finally, install the klass pointer (this should be volatile).
OrderAccess::storestore();
obj->set_klass(old->klass());
// We should now be able to calculate the right size for this object
assert(obj->is_oop() && obj->size() == (int)word_sz, "Error, incorrect size computed for promoted object");
assert(old->is_oop(), "Will dereference klass ptr below");
collector()->promoted(true, // parallel
obj_ptr, old->is_objArray(), word_sz);
NOT_PRODUCT(
Atomic::inc(&_numObjectsPromoted);
Atomic::add((jint)CompactibleFreeListSpace::adjustObjectSize(obj->size()),
&_numWordsPromoted);
Atomic::inc_ptr(&_numObjectsPromoted);
Atomic::add_ptr(alloc_sz, &_numWordsPromoted);
)
return obj;
......
......@@ -1010,10 +1010,10 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
// Non-product stat counters
NOT_PRODUCT(
int _numObjectsPromoted;
int _numWordsPromoted;
int _numObjectsAllocated;
int _numWordsAllocated;
size_t _numObjectsPromoted;
size_t _numWordsPromoted;
size_t _numObjectsAllocated;
size_t _numWordsAllocated;
)
// Used for sizing decisions
......
/*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, 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
......@@ -116,9 +116,15 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
void clearPrev() { _prev = NULL; }
void clearNext() { _next = NULL; }
void markNotFree() {
LP64_ONLY(if (UseCompressedOops) set_mark(markOopDesc::prototype());)
// Also set _prev to null
// Set _prev (klass) to null before (if) clearing the mark word below
_prev = NULL;
#ifdef _LP64
if (UseCompressedOops) {
OrderAccess::storestore();
set_mark(markOopDesc::prototype());
}
#endif
assert(!isFree(), "Error");
}
// Return the address past the end of this chunk
......
......@@ -330,7 +330,7 @@ void PromotionInfo::verify() const {
void PromotionInfo::print_on(outputStream* st) const {
SpoolBlock* curSpool = NULL;
size_t i = 0;
st->print_cr("start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")",
st->print_cr(" start & end indices: [" SIZE_FORMAT ", " SIZE_FORMAT ")",
_firstIndex, _nextIndex);
for (curSpool = _spoolHead; curSpool != _spoolTail && curSpool != NULL;
curSpool = curSpool->nextSpoolBlock) {
......@@ -350,7 +350,7 @@ void PromotionInfo::print_on(outputStream* st) const {
st->print_cr(" free ");
i++;
}
st->print_cr(SIZE_FORMAT " header spooling blocks", i);
st->print_cr(" " SIZE_FORMAT " header spooling blocks", i);
}
void SpoolBlock::print_on(outputStream* st) const {
......
//
// Copyright (c) 2004, 2009, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 2004, 2010, 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
......@@ -34,6 +34,8 @@ binaryTreeDictionary.cpp spaceDecorator.hpp
binaryTreeDictionary.hpp freeBlockDictionary.hpp
binaryTreeDictionary.hpp freeList.hpp
blockOffsetTable.inline.hpp concurrentMarkSweepGeneration.hpp
cmsAdaptiveSizePolicy.cpp cmsAdaptiveSizePolicy.hpp
cmsAdaptiveSizePolicy.cpp defNewGeneration.hpp
cmsAdaptiveSizePolicy.cpp gcStats.hpp
......@@ -85,7 +87,7 @@ cmsOopClosures.hpp genOopClosures.hpp
cmsOopClosures.inline.hpp cmsOopClosures.hpp
cmsOopClosures.inline.hpp concurrentMarkSweepGeneration.hpp
cmsPermGen.cpp blockOffsetTable.hpp
cmsPermGen.cpp blockOffsetTable.inline.hpp
cmsPermGen.cpp cSpaceCounters.hpp
cmsPermGen.cpp cmsPermGen.hpp
cmsPermGen.cpp collectedHeap.inline.hpp
......@@ -121,6 +123,7 @@ compactibleFreeListSpace.cpp universe.inline.hpp
compactibleFreeListSpace.cpp vmThread.hpp
compactibleFreeListSpace.hpp binaryTreeDictionary.hpp
compactibleFreeListSpace.hpp blockOffsetTable.inline.hpp
compactibleFreeListSpace.hpp freeList.hpp
compactibleFreeListSpace.hpp promotionInfo.hpp
compactibleFreeListSpace.hpp space.hpp
......
......@@ -225,7 +225,6 @@ arrayOop.cpp oop.inline.hpp
arrayOop.cpp symbolOop.hpp
arrayOop.hpp oop.hpp
arrayOop.hpp universe.hpp
arrayOop.hpp universe.inline.hpp
assembler.cpp assembler.hpp
......@@ -236,7 +235,6 @@ assembler.cpp icache.hpp
assembler.cpp os.hpp
assembler.hpp allocation.hpp
assembler.hpp allocation.inline.hpp
assembler.hpp debug.hpp
assembler.hpp growableArray.hpp
assembler.hpp oopRecorder.hpp
......@@ -330,7 +328,7 @@ blockOffsetTable.cpp collectedHeap.inline.hpp
blockOffsetTable.cpp iterator.hpp
blockOffsetTable.cpp java.hpp
blockOffsetTable.cpp oop.inline.hpp
blockOffsetTable.cpp space.hpp
blockOffsetTable.cpp space.inline.hpp
blockOffsetTable.cpp universe.hpp
blockOffsetTable.hpp globalDefinitions.hpp
......@@ -338,6 +336,7 @@ blockOffsetTable.hpp memRegion.hpp
blockOffsetTable.hpp virtualspace.hpp
blockOffsetTable.inline.hpp blockOffsetTable.hpp
blockOffsetTable.inline.hpp safepoint.hpp
blockOffsetTable.inline.hpp space.hpp
bytecode.cpp bytecode.hpp
......@@ -1807,7 +1806,7 @@ generateOopMap.hpp signature.hpp
generateOopMap.hpp universe.inline.hpp
generation.cpp allocation.inline.hpp
generation.cpp blockOffsetTable.hpp
generation.cpp blockOffsetTable.inline.hpp
generation.cpp cardTableRS.hpp
generation.cpp collectedHeap.inline.hpp
generation.cpp copy.hpp
......@@ -3436,7 +3435,7 @@ perfMemory_<os_family>.cpp perfMemory.hpp
perfMemory_<os_family>.cpp resourceArea.hpp
perfMemory_<os_family>.cpp vmSymbols.hpp
permGen.cpp blockOffsetTable.hpp
permGen.cpp blockOffsetTable.inline.hpp
permGen.cpp cSpaceCounters.hpp
permGen.cpp collectedHeap.inline.hpp
permGen.cpp compactPermGen.hpp
......@@ -3805,7 +3804,7 @@ sizes.cpp sizes.hpp
sizes.hpp allocation.hpp
sizes.hpp globalDefinitions.hpp
space.cpp blockOffsetTable.hpp
space.cpp blockOffsetTable.inline.hpp
space.cpp copy.hpp
space.cpp defNewGeneration.hpp
space.cpp genCollectedHeap.hpp
......@@ -3835,7 +3834,6 @@ space.hpp prefetch.hpp
space.hpp watermark.hpp
space.hpp workgroup.hpp
space.inline.hpp blockOffsetTable.inline.hpp
space.inline.hpp collectedHeap.hpp
space.inline.hpp safepoint.hpp
space.inline.hpp space.hpp
......
/*
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2010, 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
......@@ -103,13 +103,13 @@ void BlockOffsetSharedArray::serialize(SerializeOopClosure* soc,
//////////////////////////////////////////////////////////////////////
BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array,
MemRegion mr, bool init_to_zero) :
MemRegion mr, bool init_to_zero_) :
BlockOffsetTable(mr.start(), mr.end()),
_array(array),
_init_to_zero(init_to_zero)
_array(array)
{
assert(_bottom <= _end, "arguments out of order");
if (!_init_to_zero) {
set_init_to_zero(init_to_zero_);
if (!init_to_zero_) {
// initialize cards to point back to mr.start()
set_remainder_to_point_to_start(mr.start() + N_words, mr.end());
_array->set_offset_array(0, 0); // set first card to 0
......@@ -121,8 +121,9 @@ BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array,
// a right-open interval: [start, end)
void
BlockOffsetArray::
set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) {
set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) {
check_reducing_assertion(reducing);
if (start >= end) {
// The start address is equal to the end address (or to
// the right of the end address) so there are not cards
......@@ -167,7 +168,7 @@ set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) {
size_t end_card = _array->index_for(end-1);
assert(start ==_array->address_for_index(start_card), "Precondition");
assert(end ==_array->address_for_index(end_card)+N_words, "Precondition");
set_remainder_to_point_to_start_incl(start_card, end_card); // closed interval
set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval
}
......@@ -175,7 +176,9 @@ set_remainder_to_point_to_start(HeapWord* start, HeapWord* end) {
// a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start()
// above.
void
BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card) {
BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card, bool reducing) {
check_reducing_assertion(reducing);
if (start_card > end_card) {
return;
}
......@@ -191,11 +194,11 @@ BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t
size_t reach = start_card - 1 + (power_to_cards_back(i+1) - 1);
offset = N_words + i;
if (reach >= end_card) {
_array->set_offset_array(start_card_for_region, end_card, offset);
_array->set_offset_array(start_card_for_region, end_card, offset, reducing);
start_card_for_region = reach + 1;
break;
}
_array->set_offset_array(start_card_for_region, reach, offset);
_array->set_offset_array(start_card_for_region, reach, offset, reducing);
start_card_for_region = reach + 1;
}
assert(start_card_for_region > end_card, "Sanity check");
......@@ -211,8 +214,10 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const
return;
}
guarantee(_array->offset_array(start_card) == N_words, "Wrong value in second card");
u_char last_entry = N_words;
for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) {
u_char entry = _array->offset_array(c);
guarantee(entry >= last_entry, "Monotonicity");
if (c - start_card > power_to_cards_back(1)) {
guarantee(entry > N_words, "Should be in logarithmic region");
}
......@@ -220,11 +225,13 @@ void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const
size_t landing_card = c - backskip;
guarantee(landing_card >= (start_card - 1), "Inv");
if (landing_card >= start_card) {
guarantee(_array->offset_array(landing_card) <= entry, "monotonicity");
guarantee(_array->offset_array(landing_card) <= entry, "Monotonicity");
} else {
guarantee(landing_card == start_card - 1, "Tautology");
guarantee(landing_card == (start_card - 1), "Tautology");
// Note that N_words is the maximum offset value
guarantee(_array->offset_array(landing_card) <= N_words, "Offset value");
}
last_entry = entry; // remember for monotonicity test
}
}
......@@ -243,7 +250,7 @@ BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {
void
BlockOffsetArray::do_block_internal(HeapWord* blk_start,
HeapWord* blk_end,
Action action) {
Action action, bool reducing) {
assert(Universe::heap()->is_in_reserved(blk_start),
"reference must be into the heap");
assert(Universe::heap()->is_in_reserved(blk_end-1),
......@@ -275,18 +282,18 @@ BlockOffsetArray::do_block_internal(HeapWord* blk_start,
switch (action) {
case Action_mark: {
if (init_to_zero()) {
_array->set_offset_array(start_index, boundary, blk_start);
_array->set_offset_array(start_index, boundary, blk_start, reducing);
break;
} // Else fall through to the next case
}
case Action_single: {
_array->set_offset_array(start_index, boundary, blk_start);
_array->set_offset_array(start_index, boundary, blk_start, reducing);
// We have finished marking the "offset card". We need to now
// mark the subsequent cards that this blk spans.
if (start_index < end_index) {
HeapWord* rem_st = _array->address_for_index(start_index) + N_words;
HeapWord* rem_end = _array->address_for_index(end_index) + N_words;
set_remainder_to_point_to_start(rem_st, rem_end);
set_remainder_to_point_to_start(rem_st, rem_end, reducing);
}
break;
}
......@@ -395,7 +402,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk,
// Indices for starts of prefix block and suffix block.
size_t pref_index = _array->index_for(pref_addr);
if (_array->address_for_index(pref_index) != pref_addr) {
// pref_addr deos not begin pref_index
// pref_addr does not begin pref_index
pref_index++;
}
......@@ -430,18 +437,18 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk,
if (num_suff_cards > 0) {
HeapWord* boundary = _array->address_for_index(suff_index);
// Set the offset card for suffix block
_array->set_offset_array(suff_index, boundary, suff_addr);
_array->set_offset_array(suff_index, boundary, suff_addr, true /* reducing */);
// Change any further cards that need changing in the suffix
if (num_pref_cards > 0) {
if (num_pref_cards >= num_suff_cards) {
// Unilaterally fix all of the suffix cards: closed card
// index interval in args below.
set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1);
set_remainder_to_point_to_start_incl(suff_index + 1, end_index - 1, true /* reducing */);
} else {
// Unilaterally fix the first (num_pref_cards - 1) following
// the "offset card" in the suffix block.
set_remainder_to_point_to_start_incl(suff_index + 1,
suff_index + num_pref_cards - 1);
suff_index + num_pref_cards - 1, true /* reducing */);
// Fix the appropriate cards in the remainder of the
// suffix block -- these are the last num_pref_cards
// cards in each power block of the "new" range plumbed
......@@ -461,7 +468,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk,
// is non-null.
if (left_index <= right_index) {
_array->set_offset_array(left_index, right_index,
N_words + i - 1);
N_words + i - 1, true /* reducing */);
} else {
more = false; // we are done
}
......@@ -482,7 +489,7 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk,
more = false;
}
assert(left_index <= right_index, "Error");
_array->set_offset_array(left_index, right_index, N_words + i - 1);
_array->set_offset_array(left_index, right_index, N_words + i - 1, true /* reducing */);
i++;
}
}
......@@ -501,14 +508,13 @@ void BlockOffsetArrayNonContigSpace::split_block(HeapWord* blk,
// any cards subsequent to the first one.
void
BlockOffsetArrayNonContigSpace::mark_block(HeapWord* blk_start,
HeapWord* blk_end) {
do_block_internal(blk_start, blk_end, Action_mark);
HeapWord* blk_end, bool reducing) {
do_block_internal(blk_start, blk_end, Action_mark, reducing);
}
HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe(
const void* addr) const {
assert(_array->offset_array(0) == 0, "objects can't cross covered areas");
assert(_bottom <= addr && addr < _end,
"addr must be covered by this Array");
// Must read this exactly once because it can be modified by parallel
......@@ -542,9 +548,10 @@ HeapWord* BlockOffsetArrayNonContigSpace::block_start_unsafe(
debug_only(HeapWord* last = q); // for debugging
q = n;
n += _sp->block_size(n);
assert(n > q, err_msg("Looping at: " INTPTR_FORMAT, n));
}
assert(q <= addr, "wrong order for current and arg");
assert(addr <= n, "wrong order for arg and next");
assert(q <= addr, err_msg("wrong order for current (" INTPTR_FORMAT ") <= arg (" INTPTR_FORMAT ")", q, addr));
assert(addr <= n, err_msg("wrong order for arg (" INTPTR_FORMAT ") <= next (" INTPTR_FORMAT ")", addr, n));
return q;
}
......@@ -727,9 +734,8 @@ void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start,
_next_offset_index = end_index + 1;
// Calculate _next_offset_threshold this way because end_index
// may be the last valid index in the covered region.
_next_offset_threshold = _array->address_for_index(end_index) +
N_words;
assert(_next_offset_threshold >= blk_end, "Incorrent offset threshold");
_next_offset_threshold = _array->address_for_index(end_index) + N_words;
assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold");
#ifdef ASSERT
// The offset can be 0 if the block starts on a boundary. That
......
/*
* Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2010, 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
......@@ -107,6 +107,8 @@ class BlockOffsetSharedArray: public CHeapObj {
N_words = 1 << LogN_words
};
bool _init_to_zero;
// The reserved region covered by the shared array.
MemRegion _reserved;
......@@ -125,17 +127,28 @@ class BlockOffsetSharedArray: public CHeapObj {
assert(index < _vs.committed_size(), "index out of range");
return _offset_array[index];
}
void set_offset_array(size_t index, u_char offset) {
// An assertion-checking helper method for the set_offset_array() methods below.
void check_reducing_assertion(bool reducing);
void set_offset_array(size_t index, u_char offset, bool reducing = false) {
check_reducing_assertion(reducing);
assert(index < _vs.committed_size(), "index out of range");
assert(!reducing || _offset_array[index] >= offset, "Not reducing");
_offset_array[index] = offset;
}
void set_offset_array(size_t index, HeapWord* high, HeapWord* low) {
void set_offset_array(size_t index, HeapWord* high, HeapWord* low, bool reducing = false) {
check_reducing_assertion(reducing);
assert(index < _vs.committed_size(), "index out of range");
assert(high >= low, "addresses out of order");
assert(pointer_delta(high, low) <= N_words, "offset too large");
assert(!reducing || _offset_array[index] >= (u_char)pointer_delta(high, low),
"Not reducing");
_offset_array[index] = (u_char)pointer_delta(high, low);
}
void set_offset_array(HeapWord* left, HeapWord* right, u_char offset) {
void set_offset_array(HeapWord* left, HeapWord* right, u_char offset, bool reducing = false) {
check_reducing_assertion(reducing);
assert(index_for(right - 1) < _vs.committed_size(),
"right address out of range");
assert(left < right, "Heap addresses out of order");
......@@ -150,12 +163,14 @@ class BlockOffsetSharedArray: public CHeapObj {
size_t i = index_for(left);
const size_t end = i + num_cards;
for (; i < end; i++) {
assert(!reducing || _offset_array[i] >= offset, "Not reducing");
_offset_array[i] = offset;
}
}
}
void set_offset_array(size_t left, size_t right, u_char offset) {
void set_offset_array(size_t left, size_t right, u_char offset, bool reducing = false) {
check_reducing_assertion(reducing);
assert(right < _vs.committed_size(), "right address out of range");
assert(left <= right, "indexes out of order");
size_t num_cards = right - left + 1;
......@@ -169,6 +184,7 @@ class BlockOffsetSharedArray: public CHeapObj {
size_t i = left;
const size_t end = i + num_cards;
for (; i < end; i++) {
assert(!reducing || _offset_array[i] >= offset, "Not reducing");
_offset_array[i] = offset;
}
}
......@@ -212,6 +228,11 @@ public:
void set_bottom(HeapWord* new_bottom);
// Whether entries should be initialized to zero. Used currently only for
// error checking.
void set_init_to_zero(bool val) { _init_to_zero = val; }
bool init_to_zero() { return _init_to_zero; }
// Updates all the BlockOffsetArray's sharing this shared array to
// reflect the current "top"'s of their spaces.
void update_offset_arrays(); // Not yet implemented!
......@@ -285,17 +306,23 @@ class BlockOffsetArray: public BlockOffsetTable {
// initialized to point backwards to the beginning of the covered region.
bool _init_to_zero;
// An assertion-checking helper method for the set_remainder*() methods below.
void check_reducing_assertion(bool reducing) { _array->check_reducing_assertion(reducing); }
// Sets the entries
// corresponding to the cards starting at "start" and ending at "end"
// to point back to the card before "start": the interval [start, end)
// is right-open.
void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end);
// is right-open. The last parameter, reducing, indicates whether the
// updates to individual entries always reduce the entry from a higher
// to a lower value. (For example this would hold true during a temporal
// regime during which only block splits were updating the BOT.
void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing = false);
// Same as above, except that the args here are a card _index_ interval
// that is closed: [start_index, end_index]
void set_remainder_to_point_to_start_incl(size_t start, size_t end);
void set_remainder_to_point_to_start_incl(size_t start, size_t end, bool reducing = false);
// A helper function for BOT adjustment/verification work
void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action);
void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action, bool reducing = false);
public:
// The space may not have its bottom and top set yet, which is why the
......@@ -303,7 +330,7 @@ class BlockOffsetArray: public BlockOffsetTable {
// elements of the array are initialized to zero. Otherwise, they are
// initialized to point backwards to the beginning.
BlockOffsetArray(BlockOffsetSharedArray* array, MemRegion mr,
bool init_to_zero);
bool init_to_zero_);
// Note: this ought to be part of the constructor, but that would require
// "this" to be passed as a parameter to a member constructor for
......@@ -358,6 +385,12 @@ class BlockOffsetArray: public BlockOffsetTable {
// If true, initialize array slots with no allocated blocks to zero.
// Otherwise, make them point back to the front.
bool init_to_zero() { return _init_to_zero; }
// Corresponding setter
void set_init_to_zero(bool val) {
_init_to_zero = val;
assert(_array != NULL, "_array should be non-NULL");
_array->set_init_to_zero(val);
}
// Debugging
// Return the index of the last entry in the "active" region.
......@@ -424,16 +457,16 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray {
// of BOT is touched. It is assumed (and verified in the
// non-product VM) that the remaining cards of the block
// are correct.
void mark_block(HeapWord* blk_start, HeapWord* blk_end);
void mark_block(HeapWord* blk, size_t size) {
mark_block(blk, blk + size);
void mark_block(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false);
void mark_block(HeapWord* blk, size_t size, bool reducing = false) {
mark_block(blk, blk + size, reducing);
}
// Adjust _unallocated_block to indicate that a particular
// block has been newly allocated or freed. It is assumed (and
// verified in the non-product VM) that the BOT is correct for
// the given block.
void allocated(HeapWord* blk_start, HeapWord* blk_end) {
void allocated(HeapWord* blk_start, HeapWord* blk_end, bool reducing = false) {
// Verify that the BOT shows [blk, blk + blk_size) to be one block.
verify_single_block(blk_start, blk_end);
if (BlockOffsetArrayUseUnallocatedBlock) {
......@@ -441,14 +474,12 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray {
}
}
void allocated(HeapWord* blk, size_t size) {
allocated(blk, blk + size);
void allocated(HeapWord* blk, size_t size, bool reducing = false) {
allocated(blk, blk + size, reducing);
}
void freed(HeapWord* blk_start, HeapWord* blk_end);
void freed(HeapWord* blk, size_t size) {
freed(blk, blk + size);
}
void freed(HeapWord* blk, size_t size);
HeapWord* block_start_unsafe(const void* addr) const;
......@@ -456,7 +487,6 @@ class BlockOffsetArrayNonContigSpace: public BlockOffsetArray {
// start of the block that contains the given address.
HeapWord* block_start_careful(const void* addr) const;
// Verification & debugging: ensure that the offset table reflects
// the fact that the block [blk_start, blk_end) or [blk, blk + size)
// is a single block of storage. NOTE: can't const this because of
......
/*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2010, 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
......@@ -55,10 +55,22 @@ inline HeapWord* BlockOffsetSharedArray::address_for_index(size_t index) const {
return result;
}
inline void BlockOffsetSharedArray::check_reducing_assertion(bool reducing) {
assert(reducing || !SafepointSynchronize::is_at_safepoint() || init_to_zero() ||
Thread::current()->is_VM_thread() ||
Thread::current()->is_ConcurrentGC_thread() ||
((!Thread::current()->is_ConcurrentGC_thread()) &&
ParGCRareEvent_lock->owned_by_self()), "Crack");
}
//////////////////////////////////////////////////////////////////////////
// BlockOffsetArrayNonContigSpace inlines
//////////////////////////////////////////////////////////////////////////
inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk,
size_t size) {
freed(blk, blk + size);
}
inline void BlockOffsetArrayNonContigSpace::freed(HeapWord* blk_start,
HeapWord* blk_end) {
// Verify that the BOT shows [blk_start, blk_end) to be one block.
......
......@@ -1712,7 +1712,7 @@ class CommandLineFlags {
develop(bool, VerifyBlockOffsetArray, false, \
"Do (expensive!) block offset array verification") \
\
product(bool, BlockOffsetArrayUseUnallocatedBlock, trueInDebug, \
product(bool, BlockOffsetArrayUseUnallocatedBlock, false, \
"Maintain _unallocated_block in BlockOffsetArray" \
" (currently applicable only to CMS collector)") \
\
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册