open Udiff src/hotspot/share/gc/shared/oopStorage.cpp (original) (raw)

< prev index next >

Print this page

rev 49824 : imported patch block_array rev 49826 : [mq]: active_array


@@ -26,24 +26,26 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageParState.inline.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" -#include "memory/resourceArea.hpp" #include "runtime/atomic.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/orderAccess.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/thread.hpp" #include "utilities/align.hpp" #include "utilities/count_trailing_zeros.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/ostream.hpp" +#include "utilities/spinYield.hpp"

OopStorage::BlockEntry::BlockEntry() : _prev(NULL), _next(NULL) {}

OopStorage::BlockEntry::~BlockEntry() { assert(_prev == NULL, "deleting attached block");


@@ -106,10 +108,98 @@ _get_entry(*next_blk)._prev = prev_blk; _get_entry(*prev_blk)._next = next_blk; } }

+OopStorage::BlockArray::BlockArray(size_t size) :


@@ -123,11 +213,11 @@ OopStorage::Block::Block(const OopStorage* owner, void* memory) : _data(), _allocated_bitmask(0), _owner(owner), _memory(memory),


@@ -144,14 +234,10 @@ // might help catch bugs. Volatile to prevent dead-store elimination. const_cast<uintx volatile&>(_allocated_bitmask) = 0; const_cast<OopStorage* volatile&>(_owner) = NULL; } -const OopStorage::BlockEntry& OopStorage::Block::get_active_entry(const Block& block) { - return block._active_entry; -}

const OopStorage::BlockEntry& OopStorage::Block::get_allocate_entry(const Block& block) { return block._allocate_entry; }

size_t OopStorage::Block::allocation_size() {


@@ -202,10 +288,24 @@ bool OopStorage::Block::contains(const oop* ptr) const { const oop* base = get_pointer(0); return (base <= ptr) && (ptr < (base + ARRAY_SIZE(_data))); } +size_t OopStorage::Block::active_index() const { + return _active_index; +} + +void OopStorage::Block::set_active_index(size_t index) { + _active_index = index; +} + +size_t OopStorage::Block::active_index_safe(const Block* block) { + STATIC_ASSERT(sizeof(intptr_t) == sizeof(block->_active_index)); + assert(CanUseSafeFetchN(), "precondition"); + return SafeFetchN((intptr_t*)&block->_active_index, 0); +} + unsigned OopStorage::Block::get_index(const oop* ptr) const { assert(contains(ptr), PTR_FORMAT " not in block " PTR_FORMAT, p2i(ptr), p2i(this)); return static_cast(ptr - get_pointer(0)); }

@@ -244,11 +344,11 @@ FREE_C_HEAP_ARRAY(char, memory); }

// This can return a false positive if ptr is not contained by some // block. For some uses, it is a precondition that ptr is valid, -// e.g. contained in some block in owner's _active_list. Other uses +// e.g. contained in some block in owner's _active_array. Other uses // require additional validation of the result. OopStorage::Block* OopStorage::Block::block_for_ptr(const OopStorage* owner, const oop* ptr) { assert(CanUseSafeFetchN(), "precondition"); STATIC_ASSERT(_data_pos == 0);


@@ -278,16 +378,16 @@ // Allocation // // Allocation involves the _allocate_list, which contains a subset of the // blocks owned by a storage object. This is a doubly-linked list, linked // through dedicated fields in the blocks. Full blocks are removed from this -// list, though they are still present in the _active_list. Empty blocks are +// list, though they are still present in the _active_array. Empty blocks are // kept at the end of the _allocate_list, to make it easy for empty block // deletion to find them. // // allocate(), and delete_empty_blocks_concurrent() lock the -// _allocate_mutex while performing any list modifications. +// _allocate_mutex while performing any list and array modifications. // // allocate() and release() update a block's _allocated_bitmask using CAS // loops. This prevents loss of updates even though release() performs // its updates without any locking. //


@@ -297,11 +397,11 @@ // removed from the _allocate_list so it won't be considered by future // allocations until some entries in it are released. // // release() is performed lock-free. release() first looks up the block for // the entry, using address alignment to find the enclosing block (thereby -// avoiding iteration over the _active_list). Once the block has been +// avoiding iteration over the _active_array). Once the block has been // determined, its _allocated_bitmask needs to be updated, and its position in // the _allocate_list may need to be updated. There are two cases: // // (a) If the block is neither full nor would become empty with the release of // the entry, only its _allocated_bitmask needs to be updated. But if the CAS


@@ -338,29 +438,33 @@ while (_allocate_list.head() == NULL) { if (!reduce_deferred_updates()) { // Failed to make new block, no other thread made a block // available while the mutex was released, and didn't get // one from a deferred update either, so return failure.


@@ -381,20 +485,122 @@ } log_info(oopstorage, ref)("%s: allocated " PTR_FORMAT, name(), p2i(result)); return result; }

+bool OopStorage::expand_active_array() {


@@ -544,24 +750,25 @@ char* dup = NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtGC); strcpy(dup, name); return dup; }

+const size_t initial_active_array_size = 8; + OopStorage::OopStorage(const char* name, Mutex* allocate_mutex, Mutex* active_mutex) : _name(dup_name(name)),


@@ -581,14 +788,17 @@ block->set_deferred_updates_next(NULL); } while ((block = _allocate_list.head()) != NULL) { _allocate_list.unlink(*block); }

void OopStorage::delete_empty_blocks_safepoint() { assert_at_safepoint();


@@ -596,36 +806,33 @@ // blocks available for deletion. while (reduce_deferred_updates()) {} // Don't interfere with a concurrent iteration. if (_concurrent_iteration_active) return; // Delete empty (and otherwise deletable) blocks from end of _allocate_list.

}

void OopStorage::delete_empty_blocks_concurrent() { MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag); // Other threads could be adding to the empty block count while we // release the mutex across the block deletions. Set an upper bound // on how many blocks we'll try to release, so other threads can't // cause an unbounded stay in this function.


@@ -633,16 +840,11 @@

 {
   MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag);
   // Don't interfere with a concurrent iteration.
   if (_concurrent_iteration_active) return;

@@ -651,57 +853,78 @@ }

OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const { const Block* block = find_block_or_null(ptr); if (block != NULL) {

size_t OopStorage::allocation_count() const { return _allocation_count; }

size_t OopStorage::block_count() const {

size_t OopStorage::total_memory_usage() const { size_t total_size = sizeof(OopStorage); total_size += strlen(name()) + 1;

// Parallel iteration support

-static char* not_started_marker_dummy = NULL; -static void* const not_started_marker = &not_started_marker_dummy; +uint OopStorage::BasicParState::default_estimated_thread_count(bool concurrent) {

-OopStorage::BasicParState::BasicParState(OopStorage* storage, bool concurrent) : +OopStorage::BasicParState::BasicParState(const OopStorage* storage,

OopStorage::BasicParState::~BasicParState() {

void OopStorage::BasicParState::update_iteration_state(bool value) { if (_concurrent) {


@@ -709,42 +932,62 @@ assert(_storage->_concurrent_iteration_active != value, "precondition"); _storage->_concurrent_iteration_active = value; } } -void OopStorage::BasicParState::ensure_iteration_started() { - if (!_concurrent) { - assert_at_safepoint(); - } - assert(!_concurrent || _storage->_concurrent_iteration_active, "invariant"); - // Ensure _next_block is not the not_started_marker, setting it to - // the _active_head to start the iteration if necessary. - if (OrderAccess::load_acquire(&_next_block) == not_started_marker) { - Atomic::cmpxchg(_storage->_active_head, &_next_block, not_started_marker); - } - assert(_next_block != not_started_marker, "postcondition"); -}

-OopStorage::Block* OopStorage::BasicParState::claim_next_block() {

+bool OopStorage::BasicParState::claim_next_segment(IterationData* data) {

}

const char* OopStorage::name() const { return _name; }

#ifndef PRODUCT

void OopStorage::print_on(outputStream* st) const { size_t allocations = _allocation_count;

< prev index next >