Path: blob/master/src/hotspot/share/gc/shared/blockOffsetTable.cpp
40957 views
/*1* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "gc/shared/blockOffsetTable.inline.hpp"26#include "gc/shared/collectedHeap.inline.hpp"27#include "gc/shared/space.inline.hpp"28#include "memory/iterator.hpp"29#include "memory/universe.hpp"30#include "logging/log.hpp"31#include "oops/oop.inline.hpp"32#include "runtime/java.hpp"33#include "services/memTracker.hpp"3435//////////////////////////////////////////////////////////////////////36// BlockOffsetSharedArray37//////////////////////////////////////////////////////////////////////3839BlockOffsetSharedArray::BlockOffsetSharedArray(MemRegion reserved,40size_t init_word_size):41_reserved(reserved), _end(NULL)42{43size_t size = compute_size(reserved.word_size());44ReservedSpace rs(size);45if (!rs.is_reserved()) {46vm_exit_during_initialization("Could not reserve enough space for heap offset array");47}4849MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);5051if (!_vs.initialize(rs, 0)) {52vm_exit_during_initialization("Could not reserve enough space for heap offset array");53}54_offset_array = (u_char*)_vs.low_boundary();55resize(init_word_size);56log_trace(gc, bot)("BlockOffsetSharedArray::BlockOffsetSharedArray: ");57log_trace(gc, bot)(" rs.base(): " INTPTR_FORMAT " rs.size(): " INTPTR_FORMAT " rs end(): " INTPTR_FORMAT,58p2i(rs.base()), rs.size(), p2i(rs.base() + rs.size()));59log_trace(gc, bot)(" _vs.low_boundary(): " INTPTR_FORMAT " _vs.high_boundary(): " INTPTR_FORMAT,60p2i(_vs.low_boundary()), p2i(_vs.high_boundary()));61}6263void BlockOffsetSharedArray::resize(size_t new_word_size) {64assert(new_word_size <= _reserved.word_size(), "Resize larger than reserved");65size_t new_size = compute_size(new_word_size);66size_t old_size = _vs.committed_size();67size_t delta;68char* high = _vs.high();69_end = _reserved.start() + new_word_size;70if (new_size > old_size) {71delta = ReservedSpace::page_align_size_up(new_size - old_size);72assert(delta > 0, "just checking");73if (!_vs.expand_by(delta)) {74// Do better than this for Merlin75vm_exit_out_of_memory(delta, OOM_MMAP_ERROR, "offset table expansion");76}77assert(_vs.high() == high + delta, "invalid expansion");78} else {79delta = ReservedSpace::page_align_size_down(old_size - new_size);80if (delta == 0) return;81_vs.shrink_by(delta);82assert(_vs.high() == high - delta, "invalid expansion");83}84}8586bool BlockOffsetSharedArray::is_card_boundary(HeapWord* p) const {87assert(p >= _reserved.start(), "just checking");88size_t delta = pointer_delta(p, _reserved.start());89return (delta & right_n_bits((int)BOTConstants::LogN_words)) == (size_t)NoBits;90}919293//////////////////////////////////////////////////////////////////////94// BlockOffsetArray95//////////////////////////////////////////////////////////////////////9697BlockOffsetArray::BlockOffsetArray(BlockOffsetSharedArray* array,98MemRegion mr, bool init_to_zero_) :99BlockOffsetTable(mr.start(), mr.end()),100_array(array)101{102assert(_bottom <= _end, "arguments out of order");103set_init_to_zero(init_to_zero_);104if (!init_to_zero_) {105// initialize cards to point back to mr.start()106set_remainder_to_point_to_start(mr.start() + BOTConstants::N_words, mr.end());107_array->set_offset_array(0, 0); // set first card to 0108}109}110111112// The arguments follow the normal convention of denoting113// a right-open interval: [start, end)114void115BlockOffsetArray::116set_remainder_to_point_to_start(HeapWord* start, HeapWord* end, bool reducing) {117118check_reducing_assertion(reducing);119if (start >= end) {120// The start address is equal to the end address (or to121// the right of the end address) so there are not cards122// that need to be updated..123return;124}125126// Write the backskip value for each region.127//128// offset129// card 2nd 3rd130// | +- 1st | |131// v v v v132// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-133// |x|0|0|0|0|0|0|0|1|1|1|1|1|1| ... |1|1|1|1|2|2|2|2|2|2| ...134// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-135// 11 19 75136// 12137//138// offset card is the card that points to the start of an object139// x - offset value of offset card140// 1st - start of first logarithmic region141// 0 corresponds to logarithmic value N_words + 0 and 2**(3 * 0) = 1142// 2nd - start of second logarithmic region143// 1 corresponds to logarithmic value N_words + 1 and 2**(3 * 1) = 8144// 3rd - start of third logarithmic region145// 2 corresponds to logarithmic value N_words + 2 and 2**(3 * 2) = 64146//147// integer below the block offset entry is an example of148// the index of the entry149//150// Given an address,151// Find the index for the address152// Find the block offset table entry153// Convert the entry to a back slide154// (e.g., with today's, offset = 0x81 =>155// back slip = 2**(3*(0x81 - N_words)) = 2**3) = 8156// Move back N (e.g., 8) entries and repeat with the157// value of the new entry158//159size_t start_card = _array->index_for(start);160size_t end_card = _array->index_for(end-1);161assert(start ==_array->address_for_index(start_card), "Precondition");162assert(end ==_array->address_for_index(end_card)+BOTConstants::N_words, "Precondition");163set_remainder_to_point_to_start_incl(start_card, end_card, reducing); // closed interval164}165166167// Unlike the normal convention in this code, the argument here denotes168// a closed, inclusive interval: [start_card, end_card], cf set_remainder_to_point_to_start()169// above.170void171BlockOffsetArray::set_remainder_to_point_to_start_incl(size_t start_card, size_t end_card, bool reducing) {172173check_reducing_assertion(reducing);174if (start_card > end_card) {175return;176}177assert(start_card > _array->index_for(_bottom), "Cannot be first card");178assert(_array->offset_array(start_card-1) <= BOTConstants::N_words,179"Offset card has an unexpected value");180size_t start_card_for_region = start_card;181u_char offset = max_jubyte;182for (uint i = 0; i < BOTConstants::N_powers; i++) {183// -1 so that the the card with the actual offset is counted. Another -1184// so that the reach ends in this region and not at the start185// of the next.186size_t reach = start_card - 1 + (BOTConstants::power_to_cards_back(i+1) - 1);187offset = BOTConstants::N_words + i;188if (reach >= end_card) {189_array->set_offset_array(start_card_for_region, end_card, offset, reducing);190start_card_for_region = reach + 1;191break;192}193_array->set_offset_array(start_card_for_region, reach, offset, reducing);194start_card_for_region = reach + 1;195}196assert(start_card_for_region > end_card, "Sanity check");197DEBUG_ONLY(check_all_cards(start_card, end_card);)198}199200// The card-interval [start_card, end_card] is a closed interval; this201// is an expensive check -- use with care and only under protection of202// suitable flag.203void BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) const {204205if (end_card < start_card) {206return;207}208guarantee(_array->offset_array(start_card) == BOTConstants::N_words, "Wrong value in second card");209u_char last_entry = BOTConstants::N_words;210for (size_t c = start_card + 1; c <= end_card; c++ /* yeah! */) {211u_char entry = _array->offset_array(c);212guarantee(entry >= last_entry, "Monotonicity");213if (c - start_card > BOTConstants::power_to_cards_back(1)) {214guarantee(entry > BOTConstants::N_words, "Should be in logarithmic region");215}216size_t backskip = BOTConstants::entry_to_cards_back(entry);217size_t landing_card = c - backskip;218guarantee(landing_card >= (start_card - 1), "Inv");219if (landing_card >= start_card) {220guarantee(_array->offset_array(landing_card) <= entry, "Monotonicity");221} else {222guarantee(landing_card == (start_card - 1), "Tautology");223// Note that N_words is the maximum offset value224guarantee(_array->offset_array(landing_card) <= BOTConstants::N_words, "Offset value");225}226last_entry = entry; // remember for monotonicity test227}228}229230231void232BlockOffsetArray::alloc_block(HeapWord* blk_start, HeapWord* blk_end) {233assert(blk_start != NULL && blk_end > blk_start,234"phantom block");235single_block(blk_start, blk_end);236}237238// Action_mark - update the BOT for the block [blk_start, blk_end).239// Current typical use is for splitting a block.240// Action_single - udpate the BOT for an allocation.241// Action_verify - BOT verification.242void243BlockOffsetArray::do_block_internal(HeapWord* blk_start,244HeapWord* blk_end,245Action action, bool reducing) {246assert(_sp->is_in_reserved(blk_start),247"reference must be into the space");248assert(_sp->is_in_reserved(blk_end-1),249"limit must be within the space");250// This is optimized to make the test fast, assuming we only rarely251// cross boundaries.252uintptr_t end_ui = (uintptr_t)(blk_end - 1);253uintptr_t start_ui = (uintptr_t)blk_start;254// Calculate the last card boundary preceding end of blk255intptr_t boundary_before_end = (intptr_t)end_ui;256clear_bits(boundary_before_end, right_n_bits((int)BOTConstants::LogN));257if (start_ui <= (uintptr_t)boundary_before_end) {258// blk starts at or crosses a boundary259// Calculate index of card on which blk begins260size_t start_index = _array->index_for(blk_start);261// Index of card on which blk ends262size_t end_index = _array->index_for(blk_end - 1);263// Start address of card on which blk begins264HeapWord* boundary = _array->address_for_index(start_index);265assert(boundary <= blk_start, "blk should start at or after boundary");266if (blk_start != boundary) {267// blk starts strictly after boundary268// adjust card boundary and start_index forward to next card269boundary += BOTConstants::N_words;270start_index++;271}272assert(start_index <= end_index, "monotonicity of index_for()");273assert(boundary <= (HeapWord*)boundary_before_end, "tautology");274switch (action) {275case Action_mark: {276if (init_to_zero()) {277_array->set_offset_array(start_index, boundary, blk_start, reducing);278break;279} // Else fall through to the next case280}281case Action_single: {282_array->set_offset_array(start_index, boundary, blk_start, reducing);283// We have finished marking the "offset card". We need to now284// mark the subsequent cards that this blk spans.285if (start_index < end_index) {286HeapWord* rem_st = _array->address_for_index(start_index) + BOTConstants::N_words;287HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words;288set_remainder_to_point_to_start(rem_st, rem_end, reducing);289}290break;291}292case Action_check: {293_array->check_offset_array(start_index, boundary, blk_start);294// We have finished checking the "offset card". We need to now295// check the subsequent cards that this blk spans.296check_all_cards(start_index + 1, end_index);297break;298}299default:300ShouldNotReachHere();301}302}303}304305// The range [blk_start, blk_end) represents a single contiguous block306// of storage; modify the block offset table to represent this307// information; Right-open interval: [blk_start, blk_end)308// NOTE: this method does _not_ adjust _unallocated_block.309void310BlockOffsetArray::single_block(HeapWord* blk_start,311HeapWord* blk_end) {312do_block_internal(blk_start, blk_end, Action_single);313}314315void BlockOffsetArray::verify() const {316// For each entry in the block offset table, verify that317// the entry correctly finds the start of an object at the318// first address covered by the block or to the left of that319// first address.320321size_t next_index = 1;322size_t last_index = last_active_index();323324// Use for debugging. Initialize to NULL to distinguish the325// first iteration through the while loop.326HeapWord* last_p = NULL;327HeapWord* last_start = NULL;328oop last_o = NULL;329330while (next_index <= last_index) {331// Use an address past the start of the address for332// the entry.333HeapWord* p = _array->address_for_index(next_index) + 1;334if (p >= _end) {335// That's all of the allocated block table.336return;337}338// block_start() asserts that start <= p.339HeapWord* start = block_start(p);340// First check if the start is an allocated block and only341// then if it is a valid object.342oop o = cast_to_oop(start);343assert(!Universe::is_fully_initialized() ||344_sp->is_free_block(start) ||345oopDesc::is_oop_or_null(o), "Bad object was found");346next_index++;347last_p = p;348last_start = start;349last_o = o;350}351}352353//////////////////////////////////////////////////////////////////////354// BlockOffsetArrayContigSpace355//////////////////////////////////////////////////////////////////////356357HeapWord* BlockOffsetArrayContigSpace::block_start_unsafe(const void* addr) const {358assert(_array->offset_array(0) == 0, "objects can't cross covered areas");359360// Otherwise, find the block start using the table.361assert(_bottom <= addr && addr < _end,362"addr must be covered by this Array");363size_t index = _array->index_for(addr);364// We must make sure that the offset table entry we use is valid. If365// "addr" is past the end, start at the last known one and go forward.366index = MIN2(index, _next_offset_index-1);367HeapWord* q = _array->address_for_index(index);368369uint offset = _array->offset_array(index); // Extend u_char to uint.370while (offset > BOTConstants::N_words) {371// The excess of the offset from N_words indicates a power of Base372// to go back by.373size_t n_cards_back = BOTConstants::entry_to_cards_back(offset);374q -= (BOTConstants::N_words * n_cards_back);375assert(q >= _sp->bottom(), "Went below bottom!");376index -= n_cards_back;377offset = _array->offset_array(index);378}379while (offset == BOTConstants::N_words) {380assert(q >= _sp->bottom(), "Went below bottom!");381q -= BOTConstants::N_words;382index--;383offset = _array->offset_array(index);384}385assert(offset < BOTConstants::N_words, "offset too large");386q -= offset;387HeapWord* n = q;388389while (n <= addr) {390debug_only(HeapWord* last = q); // for debugging391q = n;392n += _sp->block_size(n);393}394assert(q <= addr, "wrong order for current and arg");395assert(addr <= n, "wrong order for arg and next");396return q;397}398399//400// _next_offset_threshold401// | _next_offset_index402// v v403// +-------+-------+-------+-------+-------+404// | i-1 | i | i+1 | i+2 | i+3 |405// +-------+-------+-------+-------+-------+406// ( ^ ]407// block-start408//409410void BlockOffsetArrayContigSpace::alloc_block_work(HeapWord* blk_start,411HeapWord* blk_end) {412assert(blk_start != NULL && blk_end > blk_start,413"phantom block");414assert(blk_end > _next_offset_threshold,415"should be past threshold");416assert(blk_start <= _next_offset_threshold,417"blk_start should be at or before threshold");418assert(pointer_delta(_next_offset_threshold, blk_start) <= BOTConstants::N_words,419"offset should be <= BlockOffsetSharedArray::N");420assert(_sp->is_in_reserved(blk_start),421"reference must be into the space");422assert(_sp->is_in_reserved(blk_end-1),423"limit must be within the space");424assert(_next_offset_threshold ==425_array->_reserved.start() + _next_offset_index*BOTConstants::N_words,426"index must agree with threshold");427428debug_only(size_t orig_next_offset_index = _next_offset_index;)429430// Mark the card that holds the offset into the block. Note431// that _next_offset_index and _next_offset_threshold are not432// updated until the end of this method.433_array->set_offset_array(_next_offset_index,434_next_offset_threshold,435blk_start);436437// We need to now mark the subsequent cards that this blk spans.438439// Index of card on which blk ends.440size_t end_index = _array->index_for(blk_end - 1);441442// Are there more cards left to be updated?443if (_next_offset_index + 1 <= end_index) {444HeapWord* rem_st = _array->address_for_index(_next_offset_index + 1);445// Calculate rem_end this way because end_index446// may be the last valid index in the covered region.447HeapWord* rem_end = _array->address_for_index(end_index) + BOTConstants::N_words;448set_remainder_to_point_to_start(rem_st, rem_end);449}450451// _next_offset_index and _next_offset_threshold updated here.452_next_offset_index = end_index + 1;453// Calculate _next_offset_threshold this way because end_index454// may be the last valid index in the covered region.455_next_offset_threshold = _array->address_for_index(end_index) + BOTConstants::N_words;456assert(_next_offset_threshold >= blk_end, "Incorrect offset threshold");457458#ifdef ASSERT459// The offset can be 0 if the block starts on a boundary. That460// is checked by an assertion above.461size_t start_index = _array->index_for(blk_start);462HeapWord* boundary = _array->address_for_index(start_index);463assert((_array->offset_array(orig_next_offset_index) == 0 &&464blk_start == boundary) ||465(_array->offset_array(orig_next_offset_index) > 0 &&466_array->offset_array(orig_next_offset_index) <= BOTConstants::N_words),467"offset array should have been set");468for (size_t j = orig_next_offset_index + 1; j <= end_index; j++) {469assert(_array->offset_array(j) > 0 &&470_array->offset_array(j) <= (u_char) (BOTConstants::N_words+BOTConstants::N_powers-1),471"offset array should have been set");472}473#endif474}475476HeapWord* BlockOffsetArrayContigSpace::initialize_threshold() {477_next_offset_index = _array->index_for(_bottom);478_next_offset_index++;479_next_offset_threshold =480_array->address_for_index(_next_offset_index);481return _next_offset_threshold;482}483484void BlockOffsetArrayContigSpace::zero_bottom_entry() {485size_t bottom_index = _array->index_for(_bottom);486_array->set_offset_array(bottom_index, 0);487}488489size_t BlockOffsetArrayContigSpace::last_active_index() const {490return _next_offset_index == 0 ? 0 : _next_offset_index - 1;491}492493494