416 Block* block = block_for_allocation(); |
416 Block* block = block_for_allocation(); |
417 if (block == NULL) return NULL; // Block allocation failed. |
417 if (block == NULL) return NULL; // Block allocation failed. |
418 assert(!block->is_full(), "invariant"); |
418 assert(!block->is_full(), "invariant"); |
419 if (block->is_empty()) { |
419 if (block->is_empty()) { |
420 // Transitioning from empty to not empty. |
420 // Transitioning from empty to not empty. |
421 log_debug(oopstorage, blocks)("%s: block not empty " PTR_FORMAT, name(), p2i(block)); |
421 log_trace(oopstorage, blocks)("%s: block not empty " PTR_FORMAT, name(), p2i(block)); |
422 } |
422 } |
423 oop* result = block->allocate(); |
423 oop* result = block->allocate(); |
424 assert(result != NULL, "allocation failed"); |
424 assert(result != NULL, "allocation failed"); |
425 assert(!block->is_empty(), "postcondition"); |
425 assert(!block->is_empty(), "postcondition"); |
426 Atomic::inc(&_allocation_count); // release updates outside lock. |
426 Atomic::inc(&_allocation_count); // release updates outside lock. |
427 if (block->is_full()) { |
427 if (block->is_full()) { |
428 // Transitioning from not full to full. |
428 // Transitioning from not full to full. |
429 // Remove full blocks from consideration by future allocates. |
429 // Remove full blocks from consideration by future allocates. |
430 log_debug(oopstorage, blocks)("%s: block full " PTR_FORMAT, name(), p2i(block)); |
430 log_trace(oopstorage, blocks)("%s: block full " PTR_FORMAT, name(), p2i(block)); |
431 _allocation_list.unlink(*block); |
431 _allocation_list.unlink(*block); |
432 } |
432 } |
433 log_trace(oopstorage, ref)("%s: allocated " PTR_FORMAT, name(), p2i(result)); |
433 log_trace(oopstorage, ref)("%s: allocated " PTR_FORMAT, name(), p2i(result)); |
434 return result; |
434 return result; |
435 } |
435 } |
479 // Trying to add a block failed, but some other thread added to the |
479 // Trying to add a block failed, but some other thread added to the |
480 // list while we'd dropped the lock over the new block allocation. |
480 // list while we'd dropped the lock over the new block allocation. |
481 } else if (!reduce_deferred_updates()) { // Once more before failure. |
481 } else if (!reduce_deferred_updates()) { // Once more before failure. |
482 // Attempt to add a block failed, no other thread added a block, |
482 // Attempt to add a block failed, no other thread added a block, |
483 // and no deferred updated added a block, then allocation failed. |
483 // and no deferred updated added a block, then allocation failed. |
484 log_debug(oopstorage, blocks)("%s: failed block allocation", name()); |
484 log_info(oopstorage, blocks)("%s: failed block allocation", name()); |
485 return NULL; |
485 return NULL; |
486 } |
486 } |
487 } |
487 } |
488 } |
488 } |
489 |
489 |
571 |
571 |
572 static void log_release_transitions(uintx releasing, |
572 static void log_release_transitions(uintx releasing, |
573 uintx old_allocated, |
573 uintx old_allocated, |
574 const OopStorage* owner, |
574 const OopStorage* owner, |
575 const void* block) { |
575 const void* block) { |
576 Log(oopstorage, blocks) log; |
576 LogTarget(Trace, oopstorage, blocks) lt; |
577 LogStream ls(log.debug()); |
577 if (lt.is_enabled()) { |
578 if (is_full_bitmask(old_allocated)) { |
578 LogStream ls(lt); |
579 ls.print_cr("%s: block not full " PTR_FORMAT, owner->name(), p2i(block)); |
579 if (is_full_bitmask(old_allocated)) { |
580 } |
580 ls.print_cr("%s: block not full " PTR_FORMAT, owner->name(), p2i(block)); |
581 if (releasing == old_allocated) { |
581 } |
582 ls.print_cr("%s: block empty " PTR_FORMAT, owner->name(), p2i(block)); |
582 if (releasing == old_allocated) { |
|
583 ls.print_cr("%s: block empty " PTR_FORMAT, owner->name(), p2i(block)); |
|
584 } |
583 } |
585 } |
584 } |
586 } |
585 |
587 |
586 void OopStorage::Block::release_entries(uintx releasing, OopStorage* owner) { |
588 void OopStorage::Block::release_entries(uintx releasing, OopStorage* owner) { |
587 assert(releasing != 0, "preconditon"); |
589 assert(releasing != 0, "preconditon"); |
604 // reduce_deferred_updates will make any needed changes related to this |
606 // reduce_deferred_updates will make any needed changes related to this |
605 // block and _allocation_list. This deferral avoids _allocation_list |
607 // block and _allocation_list. This deferral avoids _allocation_list |
606 // updates and the associated locking here. |
608 // updates and the associated locking here. |
607 if ((releasing == old_allocated) || is_full_bitmask(old_allocated)) { |
609 if ((releasing == old_allocated) || is_full_bitmask(old_allocated)) { |
608 // Log transitions. Both transitions are possible in a single update. |
610 // Log transitions. Both transitions are possible in a single update. |
609 if (log_is_enabled(Debug, oopstorage, blocks)) { |
611 log_release_transitions(releasing, old_allocated, owner, this); |
610 log_release_transitions(releasing, old_allocated, owner, this); |
|
611 } |
|
612 // Attempt to claim responsibility for adding this block to the deferred |
612 // Attempt to claim responsibility for adding this block to the deferred |
613 // list, by setting the link to non-NULL by self-looping. If this fails, |
613 // list, by setting the link to non-NULL by self-looping. If this fails, |
614 // then someone else has made such a claim and the deferred update has not |
614 // then someone else has made such a claim and the deferred update has not |
615 // yet been processed and will include our change, so we don't need to do |
615 // yet been processed and will include our change, so we don't need to do |
616 // anything further. |
616 // anything further. |
629 // some. And the service thread will drain the entire deferred list |
629 // some. And the service thread will drain the entire deferred list |
630 // if there are any pending to-empty transitions. |
630 // if there are any pending to-empty transitions. |
631 if (releasing == old_allocated) { |
631 if (releasing == old_allocated) { |
632 owner->record_needs_cleanup(); |
632 owner->record_needs_cleanup(); |
633 } |
633 } |
634 log_debug(oopstorage, blocks)("%s: deferred update " PTR_FORMAT, |
634 log_trace(oopstorage, blocks)("%s: deferred update " PTR_FORMAT, |
635 owner->name(), p2i(this)); |
635 owner->name(), p2i(this)); |
636 } |
636 } |
637 } |
637 } |
638 // Release hold on empty block deletion. |
638 // Release hold on empty block deletion. |
639 Atomic::dec(&_release_refcount); |
639 Atomic::dec(&_release_refcount); |
679 if (is_empty_bitmask(allocated)) { |
679 if (is_empty_bitmask(allocated)) { |
680 _allocation_list.unlink(*block); |
680 _allocation_list.unlink(*block); |
681 _allocation_list.push_back(*block); |
681 _allocation_list.push_back(*block); |
682 } |
682 } |
683 |
683 |
684 log_debug(oopstorage, blocks)("%s: processed deferred update " PTR_FORMAT, |
684 log_trace(oopstorage, blocks)("%s: processed deferred update " PTR_FORMAT, |
685 name(), p2i(block)); |
685 name(), p2i(block)); |
686 return true; // Processed one pending update. |
686 return true; // Processed one pending update. |
687 } |
687 } |
688 |
688 |
689 inline void check_release_entry(const oop* entry) { |
689 inline void check_release_entry(const oop* entry) { |