--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Sat Aug 14 00:47:52 2010 -0700
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Aug 16 15:58:42 2010 -0700
@@ -1019,7 +1019,7 @@
}
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 @@
// 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 @@
// [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 @@
// 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 @@
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 @@
}
}
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 @@
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());
-
- assert(old->is_oop(), "Will dereference klass ptr below");
+ // 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");
+
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;