--- /dev/null 2013-02-14 13:46:41.000000000 -0800 +++ new/src/share/vm/gc_implementation/g1/g1HeapSpanningTable.hpp 2013-02-14 13:46:41.017226797 -0800 @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_G1HEAPSPANNINGTABLE_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_G1HEAPSPANNINGTABLE_HPP + +#include "memory/allocation.hpp" + +// The G1HeapSpanningTable class is a utility class that provides +// facilities to subclasses that divide the G1 heap into fixed size +// chunks (e.g. heap regions) and use an array or arrays that have one +// entry per such chunk. It provides methods that can retrieve an +// array element given either an index or a heap address. For the case +// where the given heap address is known to be valid (i.e., within the +// G1 heap) a fast look-up is also provided (using a version of the +// array pointer that is biased to address 0). The G1HeaSpanningTable +// class keeps track of both the max length of the array as well as +// which part of it is actively used. +// +// The implementation has been split over two classes. +// G1HeapSpanningTableBase is the base class that contains all the fields +// and methods that appear in the .cpp file. G1HeapSpanningTable is the +// parameterized class on the array element type. The reason for the +// split is that we found that compilers like all the methods of a +// parametarized class to be in the .hpp file and this was the only +// way to put some of the methods in the .cpp file. + +class G1HeapSpanningTableBase VALUE_OBJ_CLASS_SPEC { +protected: + enum { + // Currently, in all the uses of this class the default value of + // array's elements is 0. If this changes in the future we can + // allow the subclasses to parametarize it. + DefaultValue = 0 + }; + + // The address of the first reserved word in the heap. + HeapWord* _heap_bottom; + + // The active bound of the heap, i.e., the address of the last + // committed word in the heap + 1. + HeapWord* _heap_end; + + // The maximum bound of the heap, i.e., the address of the last + // reserved word in the heap + 1. + HeapWord* _max_heap_end; + + // The active number of array elements. + uint _length; + + // The maximum value _length has ever grown to. + uint _length_high_watermark; + + // The max number of array elements. + uint _max_length; + + // The log of the heap subdivision size in bytes. + uint _shift_by; + + // The size of the array elements in bytes. This is here for + // convenience to avoid passing it to any method that needs it. + size_t _elem_size_bytes; + + // Return the number of array elements for the given heap bound. + uint length_for(HeapWord* end) { + assert(_heap_bottom <= end && end <= _max_heap_end, + err_msg("end: "PTR_FORMAT" bottom: "PTR_FORMAT" max end: "PTR_FORMAT, \ + end, _heap_bottom, _max_heap_end)); + size_t diff_bytes = pointer_delta(end, _heap_bottom, sizeof(char)); + uint length = (uint) (diff_bytes >> _shift_by); + assert(((size_t)(length << _shift_by)) == diff_bytes, "sanity"); + assert(length <= _max_length, + err_msg("length: %u max length: %u", length, _max_length)); + return length; + } + + // Set all elements of the given array to the default value. + void clear(void* array); + + // Returns true if all the entries of the given array are the default + // value, false otherwise. + bool check_cleared(void* array); + + // Allocate, clear, and return a new array. + void* create_new_array_base(); + + // Size of the array in bytes. + size_t array_size_bytes() { + return (size_t) _max_length * _elem_size_bytes; + } + + // Update all fields to reflect that the heap end has been moved. + // Return the previous heap end. + HeapWord* update_heap_end(HeapWord* new_end); + + // Do sanity checking. + void verify_optional() PRODUCT_RETURN; + + // Empty constructor, we'll do all initialization in the initialize() method. + G1HeapSpanningTableBase() { } + + void initialize_base(HeapWord* bottom, HeapWord* max_end, + size_t elem_size_bytes, uint shift_by); + +public: + // Return the active number of array elements. + uint length() const { return _length; } + + // Return the maximum number of array elements. + uint max_length() const { return _max_length; } + + // Determine whether the address falls into the G1 heap or not. + bool in_g1_heap(HeapWord* addr) const { + assert(addr == NULL || addr >= _heap_bottom, + err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT, addr, _heap_bottom)); + // We always check against _max_heap_end instead of_heap_end. + // Sometimes we expand the heap during a GC concurrently + // with other threads and this avoids any potential races. + return addr != NULL && addr < _max_heap_end; + } +}; + +template +class G1HeapSpanningTable : public G1HeapSpanningTableBase { +protected: + // getters and setters with index + + // Return the element of the given array at the given index. Assume + // the index is valid. This is a convenience method that does sanity + // checking on the index. + T get(T* array, uint index) const { + assert(index < _length, err_msg("index: %u length: %u", index, _length)); + return array[index]; + } + + // Set the element of the given array at the given index to the + // given value. Assume the index is valid. This is a convenience + // method that does sanity checking on the index. + void set(T* array, uint index, T value) { + assert(index < _length, err_msg("index: %u length: %u", index, _length)); + array[index] = value; + } + + // getters with address (normal and fast versions) + + // Map a heap address to a biased index. Assume that the address is valid. + uintx addr_to_index_biased(HeapWord* addr) const { + assert(_heap_bottom <= addr && addr < _max_heap_end, + err_msg("addr: "PTR_FORMAT" bottom: "PTR_FORMAT" end: "PTR_FORMAT, + addr, _heap_bottom, _max_heap_end)); + return (uintx) addr >> _shift_by; + } + + // Return the element of the given array that corresponds to the + // given address. The array should be the biased version. If the + // address is not valid, return the default value. + T get(T* array_biased, HeapWord* addr) const { + if (in_g1_heap(addr)) { + return get_unsafe(array_biased, addr); + } else { + return (T) DefaultValue; + } + } + + // Return the element of the given array that corresponds to the + // given address. The array should be the biased version. Assume + // that the address is valid. + T get_unsafe(T* array_biased, HeapWord* addr) const { + // No need to check the validity of addr as addr_to_index_biased() + // will do so. + uintx index_biased = addr_to_index_biased(addr); + return array_biased[index_biased]; + } + + // Allocate, clear, and return a new array. + T* create_new_array() { return (T*) create_new_array_base(); } + + // Return the biased (to address 0) address of the given array. + T* get_biased_array(T* array) { + T* array_biased = array - (uintx) ((uintptr_t) _heap_bottom >> _shift_by); + assert(&array[0] == &array_biased[addr_to_index_biased(_heap_bottom)], + "array slot 0 should be the same as as the biased slot for bottom"); + return array_biased; + } + + // Empty constructor, we'll do all initialization in the initialize() method. + G1HeapSpanningTable() { } + + void initialize_base(HeapWord* bottom, HeapWord* max_end, uint shift_by) { + G1HeapSpanningTableBase::initialize_base(bottom, max_end, + (size_t) sizeof(T), shift_by); + } +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1HEAPSPANNINGTABLE_HPP