tonyp@2715: /* tonyp@3713: * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. tonyp@2715: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. tonyp@2715: * tonyp@2715: * This code is free software; you can redistribute it and/or modify it tonyp@2715: * under the terms of the GNU General Public License version 2 only, as tonyp@2715: * published by the Free Software Foundation. tonyp@2715: * tonyp@2715: * This code is distributed in the hope that it will be useful, but WITHOUT tonyp@2715: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or tonyp@2715: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License tonyp@2715: * version 2 for more details (a copy is included in the LICENSE file that tonyp@2715: * accompanied this code). tonyp@2715: * tonyp@2715: * You should have received a copy of the GNU General Public License version tonyp@2715: * 2 along with this work; if not, write to the Free Software Foundation, tonyp@2715: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. tonyp@2715: * tonyp@2715: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA tonyp@2715: * or visit www.oracle.com if you need additional information or have any tonyp@2715: * questions. tonyp@2715: * tonyp@2715: */ tonyp@2715: tonyp@2715: #include "precompiled.hpp" tonyp@2715: #include "gc_implementation/g1/g1AllocRegion.inline.hpp" tonyp@2715: #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" tonyp@2715: tonyp@2715: G1CollectedHeap* G1AllocRegion::_g1h = NULL; tonyp@2715: HeapRegion* G1AllocRegion::_dummy_region = NULL; tonyp@2715: tonyp@2715: void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) { tonyp@2715: assert(_dummy_region == NULL, "should be set once"); tonyp@2715: assert(dummy_region != NULL, "pre-condition"); tonyp@2715: assert(dummy_region->free() == 0, "pre-condition"); tonyp@2715: tonyp@2715: // Make sure that any allocation attempt on this region will fail tonyp@2715: // and will not trigger any asserts. tonyp@2715: assert(allocate(dummy_region, 1, false) == NULL, "should fail"); tonyp@2715: assert(par_allocate(dummy_region, 1, false) == NULL, "should fail"); tonyp@2715: assert(allocate(dummy_region, 1, true) == NULL, "should fail"); tonyp@2715: assert(par_allocate(dummy_region, 1, true) == NULL, "should fail"); tonyp@2715: tonyp@2715: _g1h = g1h; tonyp@2715: _dummy_region = dummy_region; tonyp@2715: } tonyp@2715: tonyp@2715: void G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region, tonyp@2715: bool bot_updates) { tonyp@2715: assert(alloc_region != NULL && alloc_region != _dummy_region, tonyp@2715: "pre-condition"); tonyp@2715: tonyp@2715: // Other threads might still be trying to allocate using a CAS out tonyp@2715: // of the region we are trying to retire, as they can do so without tonyp@2715: // holding the lock. So, we first have to make sure that noone else tonyp@2715: // can allocate out of it by doing a maximal allocation. Even if our tonyp@2715: // CAS attempt fails a few times, we'll succeed sooner or later tonyp@2715: // given that failed CAS attempts mean that the region is getting tonyp@2715: // closed to being full. tonyp@2715: size_t free_word_size = alloc_region->free() / HeapWordSize; tonyp@2715: tonyp@2715: // This is the minimum free chunk we can turn into a dummy tonyp@2715: // object. If the free space falls below this, then noone can tonyp@2715: // allocate in this region anyway (all allocation requests will be tonyp@2715: // of a size larger than this) so we won't have to perform the dummy tonyp@2715: // allocation. tonyp@2715: size_t min_word_size_to_fill = CollectedHeap::min_fill_size(); tonyp@2715: tonyp@2715: while (free_word_size >= min_word_size_to_fill) { tonyp@2715: HeapWord* dummy = par_allocate(alloc_region, free_word_size, bot_updates); tonyp@2715: if (dummy != NULL) { tonyp@2715: // If the allocation was successful we should fill in the space. tonyp@2715: CollectedHeap::fill_with_object(dummy, free_word_size); tonyp@2715: alloc_region->set_pre_dummy_top(dummy); tonyp@2715: break; tonyp@2715: } tonyp@2715: tonyp@2715: free_word_size = alloc_region->free() / HeapWordSize; tonyp@2715: // It's also possible that someone else beats us to the tonyp@2715: // allocation and they fill up the region. In that case, we can tonyp@2715: // just get out of the loop. tonyp@2715: } tonyp@2715: assert(alloc_region->free() / HeapWordSize < min_word_size_to_fill, tonyp@2715: "post-condition"); tonyp@2715: } tonyp@2715: tonyp@2715: void G1AllocRegion::retire(bool fill_up) { tonyp@2715: assert(_alloc_region != NULL, ar_ext_msg(this, "not initialized properly")); tonyp@2715: tonyp@2715: trace("retiring"); tonyp@2715: HeapRegion* alloc_region = _alloc_region; tonyp@2715: if (alloc_region != _dummy_region) { tonyp@2715: // We never have to check whether the active region is empty or not, tonyp@2715: // and potentially free it if it is, given that it's guaranteed that tonyp@2715: // it will never be empty. tonyp@2715: assert(!alloc_region->is_empty(), tonyp@2715: ar_ext_msg(this, "the alloc region should never be empty")); tonyp@2715: tonyp@2715: if (fill_up) { tonyp@2715: fill_up_remaining_space(alloc_region, _bot_updates); tonyp@2715: } tonyp@2715: tonyp@2715: assert(alloc_region->used() >= _used_bytes_before, tonyp@2715: ar_ext_msg(this, "invariant")); tonyp@2715: size_t allocated_bytes = alloc_region->used() - _used_bytes_before; tonyp@2715: retire_region(alloc_region, allocated_bytes); tonyp@2715: _used_bytes_before = 0; tonyp@2715: _alloc_region = _dummy_region; tonyp@2715: } tonyp@2715: trace("retired"); tonyp@2715: } tonyp@2715: tonyp@2715: HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size, tonyp@2715: bool force) { tonyp@2715: assert(_alloc_region == _dummy_region, ar_ext_msg(this, "pre-condition")); tonyp@2715: assert(_used_bytes_before == 0, ar_ext_msg(this, "pre-condition")); tonyp@2715: tonyp@2715: trace("attempting region allocation"); tonyp@2715: HeapRegion* new_alloc_region = allocate_new_region(word_size, force); tonyp@2715: if (new_alloc_region != NULL) { tonyp@2715: new_alloc_region->reset_pre_dummy_top(); tonyp@2715: // Need to do this before the allocation tonyp@2715: _used_bytes_before = new_alloc_region->used(); tonyp@2715: HeapWord* result = allocate(new_alloc_region, word_size, _bot_updates); tonyp@2715: assert(result != NULL, ar_ext_msg(this, "the allocation should succeeded")); tonyp@2715: tonyp@2715: OrderAccess::storestore(); tonyp@2715: // Note that we first perform the allocation and then we store the tonyp@2715: // region in _alloc_region. This is the reason why an active region tonyp@2715: // can never be empty. tonyp@2715: _alloc_region = new_alloc_region; tonyp@3028: _count += 1; tonyp@2715: trace("region allocation successful"); tonyp@2715: return result; tonyp@2715: } else { tonyp@2715: trace("region allocation failed"); tonyp@2715: return NULL; tonyp@2715: } tonyp@2715: ShouldNotReachHere(); tonyp@2715: } tonyp@2715: tonyp@2715: void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) { tonyp@3713: msg->append("[%s] %s c: %u b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT, tonyp@3028: _name, message, _count, BOOL_TO_STR(_bot_updates), tonyp@2715: _alloc_region, _used_bytes_before); tonyp@2715: } tonyp@2715: tonyp@2715: void G1AllocRegion::init() { tonyp@2715: trace("initializing"); tonyp@2715: assert(_alloc_region == NULL && _used_bytes_before == 0, tonyp@2715: ar_ext_msg(this, "pre-condition")); tonyp@3028: assert(_dummy_region != NULL, ar_ext_msg(this, "should have been set")); tonyp@2715: _alloc_region = _dummy_region; tonyp@3028: _count = 0; tonyp@2715: trace("initialized"); tonyp@2715: } tonyp@2715: tonyp@3028: void G1AllocRegion::set(HeapRegion* alloc_region) { tonyp@3028: trace("setting"); tonyp@3028: // We explicitly check that the region is not empty to make sure we tonyp@3028: // maintain the "the alloc region cannot be empty" invariant. tonyp@3028: assert(alloc_region != NULL && !alloc_region->is_empty(), tonyp@3028: ar_ext_msg(this, "pre-condition")); tonyp@3028: assert(_alloc_region == _dummy_region && tonyp@3028: _used_bytes_before == 0 && _count == 0, tonyp@3028: ar_ext_msg(this, "pre-condition")); tonyp@3028: tonyp@3028: _used_bytes_before = alloc_region->used(); tonyp@3028: _alloc_region = alloc_region; tonyp@3028: _count += 1; tonyp@3028: trace("set"); tonyp@3028: } tonyp@3028: tonyp@2715: HeapRegion* G1AllocRegion::release() { tonyp@2715: trace("releasing"); tonyp@2715: HeapRegion* alloc_region = _alloc_region; tonyp@2715: retire(false /* fill_up */); tonyp@3028: assert(_alloc_region == _dummy_region, tonyp@3028: ar_ext_msg(this, "post-condition of retire()")); tonyp@2715: _alloc_region = NULL; tonyp@2715: trace("released"); tonyp@2715: return (alloc_region == _dummy_region) ? NULL : alloc_region; tonyp@2715: } tonyp@2715: tonyp@2715: #if G1_ALLOC_REGION_TRACING tonyp@2715: void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) { tonyp@2715: // All the calls to trace that set either just the size or the size tonyp@2715: // and the result are considered part of level 2 tracing and are tonyp@2715: // skipped during level 1 tracing. tonyp@2715: if ((word_size == 0 && result == NULL) || (G1_ALLOC_REGION_TRACING > 1)) { tonyp@2715: const size_t buffer_length = 128; tonyp@2715: char hr_buffer[buffer_length]; tonyp@2715: char rest_buffer[buffer_length]; tonyp@2715: tonyp@2715: HeapRegion* alloc_region = _alloc_region; tonyp@2715: if (alloc_region == NULL) { tonyp@2715: jio_snprintf(hr_buffer, buffer_length, "NULL"); tonyp@2715: } else if (alloc_region == _dummy_region) { tonyp@2715: jio_snprintf(hr_buffer, buffer_length, "DUMMY"); tonyp@2715: } else { tonyp@2715: jio_snprintf(hr_buffer, buffer_length, tonyp@2715: HR_FORMAT, HR_FORMAT_PARAMS(alloc_region)); tonyp@2715: } tonyp@2715: tonyp@2715: if (G1_ALLOC_REGION_TRACING > 1) { tonyp@2715: if (result != NULL) { tonyp@2715: jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT" "PTR_FORMAT, tonyp@2715: word_size, result); tonyp@2715: } else if (word_size != 0) { tonyp@2715: jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size); tonyp@2715: } else { tonyp@2715: jio_snprintf(rest_buffer, buffer_length, ""); tonyp@2715: } tonyp@2715: } else { tonyp@2715: jio_snprintf(rest_buffer, buffer_length, ""); tonyp@2715: } tonyp@2715: tonyp@3713: tty->print_cr("[%s] %u %s : %s %s", tonyp@3028: _name, _count, hr_buffer, str, rest_buffer); tonyp@2715: } tonyp@2715: } tonyp@2715: #endif // G1_ALLOC_REGION_TRACING tonyp@2715: tonyp@2715: G1AllocRegion::G1AllocRegion(const char* name, tonyp@2715: bool bot_updates) tonyp@2715: : _name(name), _bot_updates(bot_updates), tonyp@3028: _alloc_region(NULL), _count(0), _used_bytes_before(0) { } tonyp@2715: