JDK-6858243 : CMS: Fencing needed for hw with weak memory model
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: hs16,1.4.2,1.4.2_12
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2009-07-08
  • Updated: 2016-04-25
  • Resolved: 2010-08-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7Resolved
Related Reports
Duplicate :  
Duplicate :  
Description
CMS: Fencing needed for hw with weak memory model

Comments
SUGGESTED FIX hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp: 1305: | assert(promoInfo->has_spooling_space(), "Control point invariant"); | HeapWord* obj_ptr = ps->lab.alloc(word_sz); | if (obj_ptr == NULL) { | obj_ptr = expand_and_par_lab_allocate(ps, word_sz); | if (obj_ptr == NULL) { 1310: | return NULL; | } | } + | OrderAccess::release(); | oop obj = oop(obj_ptr); | assert(obj->klass() == NULL, "Object should be uninitialized here."); 1315: | // 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; | if (word_sz > (size_t)oopDesc::header_size()) { 1320: | Copy::aligned_disjoint_words(old_ptr + oopDesc::header_size(), | obj_ptr + oopDesc::header_size(), | word_sz - oopDesc::header_size()); + | OrderAccess::release(); | } | 1325: | if (UseCompressedOops) { | // Copy gap missed by (aligned) header size calculation above | obj->set_klass_gap(old->klass_gap()); | } | 1330: | // 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 1335: | // (i.e., insertion of klass pointer) until after, so that it | // atomically becomes a promoted object. | if (promoInfo->tracking()) { | promoInfo->track((PromotedObject*)obj, old->klass()); | } hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp: |size_t CompactibleFreeListSpace::block_size(const HeapWord* p) const { | NOT_PRODUCT(verify_objects_initialized()); | assert(MemRegion(bottom(), end()).contains(p), "p not in space"); 805: | // 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. | while (true) { | // We must do this until we get a consistent view of the object. 810: | if (FreeChunk::indicatesFreeChunk(p)) { | volatile FreeChunk* fc = (volatile FreeChunk*)p; | size_t res = fc->size(); + | OrderAccess::acquire(); | // If the object is still a free chunk, return the size, else it | // has been allocated so try again. 815: | if (FreeChunk::indicatesFreeChunk(p)) { | assert(res != 0, "Block size should not be 0"); | return res; | } | } else { 820: | // 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."); | oop o = (oop)p; 825: | assert(o->is_parsable(), "Should be parsable"); | assert(o->is_oop(true /* ignore mark word */), "Should be an oop."); + | OrderAccess::acquire(); | size_t res = o->size_given_klass(k->klass_part()); | res = adjustObjectSize(res); | assert(res != 0, "Block size should not be 0"); 830: | return res; | } | } | } | } ... | if (res != NULL) { | splitBirth(size); | repairLinearAllocBlock(blk); | } else if (blk->_ptr != NULL) { 1300: | res = blk->_ptr; | size_t blk_size = blk->_word_size; | blk->_word_size -= size; | blk->_ptr += size; | splitBirth(size); 1305: | repairLinearAllocBlock(blk); + | OrderAccess::release(); | // 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. | _bt.split_block(res, blk_size, size); // adjust block offset table 1310: | } | return res; |} | |HeapWord* CompactibleFreeListSpace::getChunkFromLinearAllocBlockRemainder( 1315: | LinearAllocBlock* blk, | size_t size) { | assert_locked(); | assert(size >= MinChunkSize, "too small"); | 1320: | HeapWord* res = NULL; | // This is the common case. Keep it simple. | if (blk->_word_size >= size + MinChunkSize) { | assert(blk->_ptr != NULL, "consistency check"); | res = blk->_ptr; 1325: | // Note that the BOT is up-to-date for the linAB before allocation. It | // indicates the start of the linAB. The split_block() updates the | // BOT for the linAB after the allocation (indicates the start of the | // next chunk to be allocated). | size_t blk_size = blk->_word_size; 1330: | blk->_word_size -= size; | blk->_ptr += size; | splitBirth(size); | repairLinearAllocBlock(blk); + | OrderAccess::release(); | // Update BOT last so that other (parallel) GC threads see a consistent 1335: | // view of the BOT and free blocks. | // Above must occur before BOT is updated below. | _bt.split_block(res, blk_size, size); // adjust block offset table | _bt.allocated(res, size); | } 1340: | return res; |} ... 1675: |FreeChunk* | CompactibleFreeListSpace::splitChunkAndReturnRemainder(FreeChunk* chunk, | size_t new_size) { | assert_locked(); | size_t size = chunk->size(); 1680: | assert(size > new_size, "Split from a smaller block?"); | assert(is_aligned(chunk), "alignment problem"); | assert(size == adjustObjectSize(size), "alignment problem"); | size_t rem_size = size - new_size; | assert(rem_size == adjustObjectSize(rem_size), "alignment problem"); 1685: | assert(rem_size >= MinChunkSize, "Free chunk smaller than minimum"); | FreeChunk* ffc = (FreeChunk*)((HeapWord*)chunk + new_size); | assert(is_aligned(ffc), "alignment problem"); | ffc->setSize(rem_size); | ffc->linkNext(NULL); 1690: | ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + | OrderAccess::release(); | // Above must occur before BOT is updated below. | // adjust block offset table | _bt.split_block((HeapWord*)chunk, chunk->size(), new_size); | if (rem_size < SmallForDictionary) { 1695: | bool is_par = (SharedHeap::heap()->n_par_threads() > 0); | if (is_par) _indexedFreeListParLocks[rem_size]->lock(); | returnChunkToFreeList(ffc); | split(size, rem_size); | if (is_par) _indexedFreeListParLocks[rem_size]->unlock(); 1700: | } else { | returnChunkToDictionary(ffc); | split(size ,rem_size); | } | chunk->setSize(new_size); 1705: | return chunk; |} ... 2650: | while ((fc = fl_for_cur_sz.getChunkAtHead()) != NULL) { | // Must do this in reverse order, so that anybody attempting to | // access the main chunk sees it as a single free block until we | // change it. | size_t fc_size = fc->size(); 2655: | for (int i = k-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. + | OrderAccess::release(); 2660: | // 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); | fc_size -= word_sz; | _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); 2665: | _bt.verify_single_block((HeapWord*)fc, fc_size); | _bt.verify_single_block((HeapWord*)ffc, ffc->size()); | // Push this on "fl". | fl->returnChunkAtHead(ffc); | } ... | // Note that we hold the lock until we decide if we're going to give 2710: | // back the remainder to the dictionary, since a contending allocator | // may otherwise see the heap as empty. (We're willing to take that | // hit if the block is a small block.) | if (rem > 0) { | size_t prefix_size = n * word_sz; 2715: | 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. + | OrderAccess::release(); | // Above must occur before BOT is updated below. 2720: | _bt.split_block((HeapWord*)fc, fc->size(), prefix_size); | if (rem >= IndexSetSize) { | returnChunkToDictionary(rem_fc); | dictionary()->dictCensusUpdate(fc->size(), | true /*split*/, 2725: | true /*birth*/); | rem_fc = NULL; | } ... 2740: | // Now do the splitting up. | // Must do this in reverse order, so that anybody attempting to | // access the main chunk sees it as a single free block until we | // change it. | size_t fc_size = n * word_sz; 2745: | // All but first chunk in this loop | for (ssize_t i = n-1; i > 0; i--) { | FreeChunk* ffc = (FreeChunk*)((HeapWord*)fc + i * word_sz); | ffc->setSize(word_sz); | ffc->linkNext(NULL); 2750: | ffc->linkPrev(NULL); // Mark as a free block for other (parallel) GC threads. + | OrderAccess::release(); | // Above must occur before BOT is updated below. | // splitting from the right, fc_size == (n - i + 1) * wordsize | _bt.mark_block((HeapWord*)ffc, word_sz); | fc_size -= word_sz; 2755: | _bt.verify_not_unallocated((HeapWord*)ffc, ffc->size()); | _bt.verify_single_block((HeapWord*)ffc, ffc->size()); | _bt.verify_single_block((HeapWord*)fc, fc_size); | // Push this on "fl". | fl->returnChunkAtHead(ffc); 2760: | }
08-07-2009