1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/g1/g1BlockOffsetTable.hpp Thu Jun 05 15:57:56 2008 -0700 1.3 @@ -0,0 +1,487 @@ 1.4 +/* 1.5 + * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +// The CollectedHeap type requires subtypes to implement a method 1.29 +// "block_start". For some subtypes, notably generational 1.30 +// systems using card-table-based write barriers, the efficiency of this 1.31 +// operation may be important. Implementations of the "BlockOffsetArray" 1.32 +// class may be useful in providing such efficient implementations. 1.33 +// 1.34 +// While generally mirroring the structure of the BOT for GenCollectedHeap, 1.35 +// the following types are tailored more towards G1's uses; these should, 1.36 +// however, be merged back into a common BOT to avoid code duplication 1.37 +// and reduce maintenance overhead. 1.38 +// 1.39 +// G1BlockOffsetTable (abstract) 1.40 +// -- G1BlockOffsetArray (uses G1BlockOffsetSharedArray) 1.41 +// -- G1BlockOffsetArrayContigSpace 1.42 +// 1.43 +// A main impediment to the consolidation of this code might be the 1.44 +// effect of making some of the block_start*() calls non-const as 1.45 +// below. Whether that might adversely affect performance optimizations 1.46 +// that compilers might normally perform in the case of non-G1 1.47 +// collectors needs to be carefully investigated prior to any such 1.48 +// consolidation. 1.49 + 1.50 +// Forward declarations 1.51 +class ContiguousSpace; 1.52 +class G1BlockOffsetSharedArray; 1.53 + 1.54 +class G1BlockOffsetTable VALUE_OBJ_CLASS_SPEC { 1.55 + friend class VMStructs; 1.56 +protected: 1.57 + // These members describe the region covered by the table. 1.58 + 1.59 + // The space this table is covering. 1.60 + HeapWord* _bottom; // == reserved.start 1.61 + HeapWord* _end; // End of currently allocated region. 1.62 + 1.63 +public: 1.64 + // Initialize the table to cover the given space. 1.65 + // The contents of the initial table are undefined. 1.66 + G1BlockOffsetTable(HeapWord* bottom, HeapWord* end) : 1.67 + _bottom(bottom), _end(end) 1.68 + { 1.69 + assert(_bottom <= _end, "arguments out of order"); 1.70 + } 1.71 + 1.72 + // Note that the committed size of the covered space may have changed, 1.73 + // so the table size might also wish to change. 1.74 + virtual void resize(size_t new_word_size) = 0; 1.75 + 1.76 + virtual void set_bottom(HeapWord* new_bottom) { 1.77 + assert(new_bottom <= _end, "new_bottom > _end"); 1.78 + _bottom = new_bottom; 1.79 + resize(pointer_delta(_end, _bottom)); 1.80 + } 1.81 + 1.82 + // Requires "addr" to be contained by a block, and returns the address of 1.83 + // the start of that block. (May have side effects, namely updating of 1.84 + // shared array entries that "point" too far backwards. This can occur, 1.85 + // for example, when LAB allocation is used in a space covered by the 1.86 + // table.) 1.87 + virtual HeapWord* block_start_unsafe(const void* addr) = 0; 1.88 + // Same as above, but does not have any of the possible side effects 1.89 + // discussed above. 1.90 + virtual HeapWord* block_start_unsafe_const(const void* addr) const = 0; 1.91 + 1.92 + // Returns the address of the start of the block containing "addr", or 1.93 + // else "null" if it is covered by no block. (May have side effects, 1.94 + // namely updating of shared array entries that "point" too far 1.95 + // backwards. This can occur, for example, when lab allocation is used 1.96 + // in a space covered by the table.) 1.97 + inline HeapWord* block_start(const void* addr); 1.98 + // Same as above, but does not have any of the possible side effects 1.99 + // discussed above. 1.100 + inline HeapWord* block_start_const(const void* addr) const; 1.101 +}; 1.102 + 1.103 +// This implementation of "G1BlockOffsetTable" divides the covered region 1.104 +// into "N"-word subregions (where "N" = 2^"LogN". An array with an entry 1.105 +// for each such subregion indicates how far back one must go to find the 1.106 +// start of the chunk that includes the first word of the subregion. 1.107 +// 1.108 +// Each BlockOffsetArray is owned by a Space. However, the actual array 1.109 +// may be shared by several BlockOffsetArrays; this is useful 1.110 +// when a single resizable area (such as a generation) is divided up into 1.111 +// several spaces in which contiguous allocation takes place, 1.112 +// such as, for example, in G1 or in the train generation.) 1.113 + 1.114 +// Here is the shared array type. 1.115 + 1.116 +class G1BlockOffsetSharedArray: public CHeapObj { 1.117 + friend class G1BlockOffsetArray; 1.118 + friend class G1BlockOffsetArrayContigSpace; 1.119 + friend class VMStructs; 1.120 + 1.121 +private: 1.122 + // The reserved region covered by the shared array. 1.123 + MemRegion _reserved; 1.124 + 1.125 + // End of the current committed region. 1.126 + HeapWord* _end; 1.127 + 1.128 + // Array for keeping offsets for retrieving object start fast given an 1.129 + // address. 1.130 + VirtualSpace _vs; 1.131 + u_char* _offset_array; // byte array keeping backwards offsets 1.132 + 1.133 + // Bounds checking accessors: 1.134 + // For performance these have to devolve to array accesses in product builds. 1.135 + u_char offset_array(size_t index) const { 1.136 + assert(index < _vs.committed_size(), "index out of range"); 1.137 + return _offset_array[index]; 1.138 + } 1.139 + 1.140 + void set_offset_array(size_t index, u_char offset) { 1.141 + assert(index < _vs.committed_size(), "index out of range"); 1.142 + assert(offset <= N_words, "offset too large"); 1.143 + _offset_array[index] = offset; 1.144 + } 1.145 + 1.146 + void set_offset_array(size_t index, HeapWord* high, HeapWord* low) { 1.147 + assert(index < _vs.committed_size(), "index out of range"); 1.148 + assert(high >= low, "addresses out of order"); 1.149 + assert(pointer_delta(high, low) <= N_words, "offset too large"); 1.150 + _offset_array[index] = (u_char) pointer_delta(high, low); 1.151 + } 1.152 + 1.153 + void set_offset_array(HeapWord* left, HeapWord* right, u_char offset) { 1.154 + assert(index_for(right - 1) < _vs.committed_size(), 1.155 + "right address out of range"); 1.156 + assert(left < right, "Heap addresses out of order"); 1.157 + size_t num_cards = pointer_delta(right, left) >> LogN_words; 1.158 + memset(&_offset_array[index_for(left)], offset, num_cards); 1.159 + } 1.160 + 1.161 + void set_offset_array(size_t left, size_t right, u_char offset) { 1.162 + assert(right < _vs.committed_size(), "right address out of range"); 1.163 + assert(left <= right, "indexes out of order"); 1.164 + size_t num_cards = right - left + 1; 1.165 + memset(&_offset_array[left], offset, num_cards); 1.166 + } 1.167 + 1.168 + void check_offset_array(size_t index, HeapWord* high, HeapWord* low) const { 1.169 + assert(index < _vs.committed_size(), "index out of range"); 1.170 + assert(high >= low, "addresses out of order"); 1.171 + assert(pointer_delta(high, low) <= N_words, "offset too large"); 1.172 + assert(_offset_array[index] == pointer_delta(high, low), 1.173 + "Wrong offset"); 1.174 + } 1.175 + 1.176 + bool is_card_boundary(HeapWord* p) const; 1.177 + 1.178 + // Return the number of slots needed for an offset array 1.179 + // that covers mem_region_words words. 1.180 + // We always add an extra slot because if an object 1.181 + // ends on a card boundary we put a 0 in the next 1.182 + // offset array slot, so we want that slot always 1.183 + // to be reserved. 1.184 + 1.185 + size_t compute_size(size_t mem_region_words) { 1.186 + size_t number_of_slots = (mem_region_words / N_words) + 1; 1.187 + return ReservedSpace::page_align_size_up(number_of_slots); 1.188 + } 1.189 + 1.190 +public: 1.191 + enum SomePublicConstants { 1.192 + LogN = 9, 1.193 + LogN_words = LogN - LogHeapWordSize, 1.194 + N_bytes = 1 << LogN, 1.195 + N_words = 1 << LogN_words 1.196 + }; 1.197 + 1.198 + // Initialize the table to cover from "base" to (at least) 1.199 + // "base + init_word_size". In the future, the table may be expanded 1.200 + // (see "resize" below) up to the size of "_reserved" (which must be at 1.201 + // least "init_word_size".) The contents of the initial table are 1.202 + // undefined; it is the responsibility of the constituent 1.203 + // G1BlockOffsetTable(s) to initialize cards. 1.204 + G1BlockOffsetSharedArray(MemRegion reserved, size_t init_word_size); 1.205 + 1.206 + // Notes a change in the committed size of the region covered by the 1.207 + // table. The "new_word_size" may not be larger than the size of the 1.208 + // reserved region this table covers. 1.209 + void resize(size_t new_word_size); 1.210 + 1.211 + void set_bottom(HeapWord* new_bottom); 1.212 + 1.213 + // Updates all the BlockOffsetArray's sharing this shared array to 1.214 + // reflect the current "top"'s of their spaces. 1.215 + void update_offset_arrays(); 1.216 + 1.217 + // Return the appropriate index into "_offset_array" for "p". 1.218 + inline size_t index_for(const void* p) const; 1.219 + 1.220 + // Return the address indicating the start of the region corresponding to 1.221 + // "index" in "_offset_array". 1.222 + inline HeapWord* address_for_index(size_t index) const; 1.223 +}; 1.224 + 1.225 +// And here is the G1BlockOffsetTable subtype that uses the array. 1.226 + 1.227 +class G1BlockOffsetArray: public G1BlockOffsetTable { 1.228 + friend class G1BlockOffsetSharedArray; 1.229 + friend class G1BlockOffsetArrayContigSpace; 1.230 + friend class VMStructs; 1.231 +private: 1.232 + enum SomePrivateConstants { 1.233 + N_words = G1BlockOffsetSharedArray::N_words, 1.234 + LogN = G1BlockOffsetSharedArray::LogN 1.235 + }; 1.236 + 1.237 + // The following enums are used by do_block_helper 1.238 + enum Action { 1.239 + Action_single, // BOT records a single block (see single_block()) 1.240 + Action_mark, // BOT marks the start of a block (see mark_block()) 1.241 + Action_check // Check that BOT records block correctly 1.242 + // (see verify_single_block()). 1.243 + }; 1.244 + 1.245 + // This is the array, which can be shared by several BlockOffsetArray's 1.246 + // servicing different 1.247 + G1BlockOffsetSharedArray* _array; 1.248 + 1.249 + // The space that owns this subregion. 1.250 + Space* _sp; 1.251 + 1.252 + // If "_sp" is a contiguous space, the field below is the view of "_sp" 1.253 + // as a contiguous space, else NULL. 1.254 + ContiguousSpace* _csp; 1.255 + 1.256 + // If true, array entries are initialized to 0; otherwise, they are 1.257 + // initialized to point backwards to the beginning of the covered region. 1.258 + bool _init_to_zero; 1.259 + 1.260 + // The portion [_unallocated_block, _sp.end()) of the space that 1.261 + // is a single block known not to contain any objects. 1.262 + // NOTE: See BlockOffsetArrayUseUnallocatedBlock flag. 1.263 + HeapWord* _unallocated_block; 1.264 + 1.265 + // Sets the entries 1.266 + // corresponding to the cards starting at "start" and ending at "end" 1.267 + // to point back to the card before "start": the interval [start, end) 1.268 + // is right-open. 1.269 + void set_remainder_to_point_to_start(HeapWord* start, HeapWord* end); 1.270 + // Same as above, except that the args here are a card _index_ interval 1.271 + // that is closed: [start_index, end_index] 1.272 + void set_remainder_to_point_to_start_incl(size_t start, size_t end); 1.273 + 1.274 + // A helper function for BOT adjustment/verification work 1.275 + void do_block_internal(HeapWord* blk_start, HeapWord* blk_end, Action action); 1.276 + 1.277 +protected: 1.278 + 1.279 + ContiguousSpace* csp() const { return _csp; } 1.280 + 1.281 + // Returns the address of a block whose start is at most "addr". 1.282 + // If "has_max_index" is true, "assumes "max_index" is the last valid one 1.283 + // in the array. 1.284 + inline HeapWord* block_at_or_preceding(const void* addr, 1.285 + bool has_max_index, 1.286 + size_t max_index) const; 1.287 + 1.288 + // "q" is a block boundary that is <= "addr"; "n" is the address of the 1.289 + // next block (or the end of the space.) Return the address of the 1.290 + // beginning of the block that contains "addr". Does so without side 1.291 + // effects (see, e.g., spec of block_start.) 1.292 + inline HeapWord* 1.293 + forward_to_block_containing_addr_const(HeapWord* q, HeapWord* n, 1.294 + const void* addr) const; 1.295 + 1.296 + // "q" is a block boundary that is <= "addr"; return the address of the 1.297 + // beginning of the block that contains "addr". May have side effects 1.298 + // on "this", by updating imprecise entries. 1.299 + inline HeapWord* forward_to_block_containing_addr(HeapWord* q, 1.300 + const void* addr); 1.301 + 1.302 + // "q" is a block boundary that is <= "addr"; "n" is the address of the 1.303 + // next block (or the end of the space.) Return the address of the 1.304 + // beginning of the block that contains "addr". May have side effects 1.305 + // on "this", by updating imprecise entries. 1.306 + HeapWord* forward_to_block_containing_addr_slow(HeapWord* q, 1.307 + HeapWord* n, 1.308 + const void* addr); 1.309 + 1.310 + // Requires that "*threshold_" be the first array entry boundary at or 1.311 + // above "blk_start", and that "*index_" be the corresponding array 1.312 + // index. If the block starts at or crosses "*threshold_", records 1.313 + // "blk_start" as the appropriate block start for the array index 1.314 + // starting at "*threshold_", and for any other indices crossed by the 1.315 + // block. Updates "*threshold_" and "*index_" to correspond to the first 1.316 + // index after the block end. 1.317 + void alloc_block_work2(HeapWord** threshold_, size_t* index_, 1.318 + HeapWord* blk_start, HeapWord* blk_end); 1.319 + 1.320 +public: 1.321 + // The space may not have it's bottom and top set yet, which is why the 1.322 + // region is passed as a parameter. If "init_to_zero" is true, the 1.323 + // elements of the array are initialized to zero. Otherwise, they are 1.324 + // initialized to point backwards to the beginning. 1.325 + G1BlockOffsetArray(G1BlockOffsetSharedArray* array, MemRegion mr, 1.326 + bool init_to_zero); 1.327 + 1.328 + // Note: this ought to be part of the constructor, but that would require 1.329 + // "this" to be passed as a parameter to a member constructor for 1.330 + // the containing concrete subtype of Space. 1.331 + // This would be legal C++, but MS VC++ doesn't allow it. 1.332 + void set_space(Space* sp); 1.333 + 1.334 + // Resets the covered region to the given "mr". 1.335 + void set_region(MemRegion mr); 1.336 + 1.337 + // Resets the covered region to one with the same _bottom as before but 1.338 + // the "new_word_size". 1.339 + void resize(size_t new_word_size); 1.340 + 1.341 + // These must be guaranteed to work properly (i.e., do nothing) 1.342 + // when "blk_start" ("blk" for second version) is "NULL". 1.343 + virtual void alloc_block(HeapWord* blk_start, HeapWord* blk_end); 1.344 + virtual void alloc_block(HeapWord* blk, size_t size) { 1.345 + alloc_block(blk, blk + size); 1.346 + } 1.347 + 1.348 + // The following methods are useful and optimized for a 1.349 + // general, non-contiguous space. 1.350 + 1.351 + // The given arguments are required to be the starts of adjacent ("blk1" 1.352 + // before "blk2") well-formed blocks covered by "this". After this call, 1.353 + // they should be considered to form one block. 1.354 + virtual void join_blocks(HeapWord* blk1, HeapWord* blk2); 1.355 + 1.356 + // Given a block [blk_start, blk_start + full_blk_size), and 1.357 + // a left_blk_size < full_blk_size, adjust the BOT to show two 1.358 + // blocks [blk_start, blk_start + left_blk_size) and 1.359 + // [blk_start + left_blk_size, blk_start + full_blk_size). 1.360 + // It is assumed (and verified in the non-product VM) that the 1.361 + // BOT was correct for the original block. 1.362 + void split_block(HeapWord* blk_start, size_t full_blk_size, 1.363 + size_t left_blk_size); 1.364 + 1.365 + // Adjust the BOT to show that it has a single block in the 1.366 + // range [blk_start, blk_start + size). All necessary BOT 1.367 + // cards are adjusted, but _unallocated_block isn't. 1.368 + void single_block(HeapWord* blk_start, HeapWord* blk_end); 1.369 + void single_block(HeapWord* blk, size_t size) { 1.370 + single_block(blk, blk + size); 1.371 + } 1.372 + 1.373 + // Adjust BOT to show that it has a block in the range 1.374 + // [blk_start, blk_start + size). Only the first card 1.375 + // of BOT is touched. It is assumed (and verified in the 1.376 + // non-product VM) that the remaining cards of the block 1.377 + // are correct. 1.378 + void mark_block(HeapWord* blk_start, HeapWord* blk_end); 1.379 + void mark_block(HeapWord* blk, size_t size) { 1.380 + mark_block(blk, blk + size); 1.381 + } 1.382 + 1.383 + // Adjust _unallocated_block to indicate that a particular 1.384 + // block has been newly allocated or freed. It is assumed (and 1.385 + // verified in the non-product VM) that the BOT is correct for 1.386 + // the given block. 1.387 + inline void allocated(HeapWord* blk_start, HeapWord* blk_end) { 1.388 + // Verify that the BOT shows [blk, blk + blk_size) to be one block. 1.389 + verify_single_block(blk_start, blk_end); 1.390 + if (BlockOffsetArrayUseUnallocatedBlock) { 1.391 + _unallocated_block = MAX2(_unallocated_block, blk_end); 1.392 + } 1.393 + } 1.394 + 1.395 + inline void allocated(HeapWord* blk, size_t size) { 1.396 + allocated(blk, blk + size); 1.397 + } 1.398 + 1.399 + inline void freed(HeapWord* blk_start, HeapWord* blk_end); 1.400 + 1.401 + inline void freed(HeapWord* blk, size_t size); 1.402 + 1.403 + virtual HeapWord* block_start_unsafe(const void* addr); 1.404 + virtual HeapWord* block_start_unsafe_const(const void* addr) const; 1.405 + 1.406 + // Requires "addr" to be the start of a card and returns the 1.407 + // start of the block that contains the given address. 1.408 + HeapWord* block_start_careful(const void* addr) const; 1.409 + 1.410 + // If true, initialize array slots with no allocated blocks to zero. 1.411 + // Otherwise, make them point back to the front. 1.412 + bool init_to_zero() { return _init_to_zero; } 1.413 + 1.414 + // Verification & debugging - ensure that the offset table reflects the fact 1.415 + // that the block [blk_start, blk_end) or [blk, blk + size) is a 1.416 + // single block of storage. NOTE: can;t const this because of 1.417 + // call to non-const do_block_internal() below. 1.418 + inline void verify_single_block(HeapWord* blk_start, HeapWord* blk_end) { 1.419 + if (VerifyBlockOffsetArray) { 1.420 + do_block_internal(blk_start, blk_end, Action_check); 1.421 + } 1.422 + } 1.423 + 1.424 + inline void verify_single_block(HeapWord* blk, size_t size) { 1.425 + verify_single_block(blk, blk + size); 1.426 + } 1.427 + 1.428 + // Verify that the given block is before _unallocated_block 1.429 + inline void verify_not_unallocated(HeapWord* blk_start, 1.430 + HeapWord* blk_end) const { 1.431 + if (BlockOffsetArrayUseUnallocatedBlock) { 1.432 + assert(blk_start < blk_end, "Block inconsistency?"); 1.433 + assert(blk_end <= _unallocated_block, "_unallocated_block problem"); 1.434 + } 1.435 + } 1.436 + 1.437 + inline void verify_not_unallocated(HeapWord* blk, size_t size) const { 1.438 + verify_not_unallocated(blk, blk + size); 1.439 + } 1.440 + 1.441 + void check_all_cards(size_t left_card, size_t right_card) const; 1.442 +}; 1.443 + 1.444 +// A subtype of BlockOffsetArray that takes advantage of the fact 1.445 +// that its underlying space is a ContiguousSpace, so that its "active" 1.446 +// region can be more efficiently tracked (than for a non-contiguous space). 1.447 +class G1BlockOffsetArrayContigSpace: public G1BlockOffsetArray { 1.448 + friend class VMStructs; 1.449 + 1.450 + // allocation boundary at which offset array must be updated 1.451 + HeapWord* _next_offset_threshold; 1.452 + size_t _next_offset_index; // index corresponding to that boundary 1.453 + 1.454 + // Work function to be called when allocation start crosses the next 1.455 + // threshold in the contig space. 1.456 + void alloc_block_work1(HeapWord* blk_start, HeapWord* blk_end) { 1.457 + alloc_block_work2(&_next_offset_threshold, &_next_offset_index, 1.458 + blk_start, blk_end); 1.459 + } 1.460 + 1.461 + 1.462 + public: 1.463 + G1BlockOffsetArrayContigSpace(G1BlockOffsetSharedArray* array, MemRegion mr); 1.464 + 1.465 + // Initialize the threshold to reflect the first boundary after the 1.466 + // bottom of the covered region. 1.467 + HeapWord* initialize_threshold(); 1.468 + 1.469 + // Zero out the entry for _bottom (offset will be zero). 1.470 + void zero_bottom_entry(); 1.471 + 1.472 + // Return the next threshold, the point at which the table should be 1.473 + // updated. 1.474 + HeapWord* threshold() const { return _next_offset_threshold; } 1.475 + 1.476 + // These must be guaranteed to work properly (i.e., do nothing) 1.477 + // when "blk_start" ("blk" for second version) is "NULL". In this 1.478 + // implementation, that's true because NULL is represented as 0, and thus 1.479 + // never exceeds the "_next_offset_threshold". 1.480 + void alloc_block(HeapWord* blk_start, HeapWord* blk_end) { 1.481 + if (blk_end > _next_offset_threshold) 1.482 + alloc_block_work1(blk_start, blk_end); 1.483 + } 1.484 + void alloc_block(HeapWord* blk, size_t size) { 1.485 + alloc_block(blk, blk+size); 1.486 + } 1.487 + 1.488 + HeapWord* block_start_unsafe(const void* addr); 1.489 + HeapWord* block_start_unsafe_const(const void* addr) const; 1.490 +};