duke@435: /* stefank@2314: * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: jmasa@3730: #ifndef SHARE_VM_MEMORY_FREELIST_HPP jmasa@3730: #define SHARE_VM_MEMORY_FREELIST_HPP stefank@2314: stefank@2314: #include "gc_implementation/shared/allocationStats.hpp" stefank@2314: duke@435: class CompactibleFreeListSpace; duke@435: jmasa@3730: // A class for maintaining a free list of Chunk's. The FreeList duke@435: // maintains a the structure of the list (head, tail, etc.) plus duke@435: // statistics for allocations from the list. The links between items duke@435: // are not part of FreeList. The statistics are jmasa@3730: // used to make decisions about coalescing Chunk's when they duke@435: // are swept during collection. duke@435: // duke@435: // See the corresponding .cpp file for a description of the specifics duke@435: // for that implementation. duke@435: duke@435: class Mutex; jmasa@3730: template class TreeList; jmasa@3730: template class PrintTreeCensusClosure; duke@435: jmasa@3730: template duke@435: class FreeList VALUE_OBJ_CLASS_SPEC { duke@435: friend class CompactibleFreeListSpace; dcubed@587: friend class VMStructs; jmasa@3730: friend class PrintTreeCensusClosure; ysr@1580: ysr@1580: private: jmasa@3730: Chunk* _head; // Head of list of free chunks jmasa@3730: Chunk* _tail; // Tail of list of free chunks ysr@1580: size_t _size; // Size in Heap words of each chunk duke@435: ssize_t _count; // Number of entries in list duke@435: size_t _hint; // next larger size list with a positive surplus duke@435: ysr@1580: AllocationStats _allocation_stats; // allocation-related statistics duke@435: duke@435: #ifdef ASSERT duke@435: Mutex* _protecting_lock; duke@435: #endif duke@435: duke@435: // Asserts false if the protecting lock (if any) is not held. duke@435: void assert_proper_lock_protection_work() const PRODUCT_RETURN; duke@435: void assert_proper_lock_protection() const { duke@435: #ifdef ASSERT duke@435: if (_protecting_lock != NULL) duke@435: assert_proper_lock_protection_work(); duke@435: #endif duke@435: } duke@435: duke@435: // Initialize the allocation statistics. duke@435: protected: ysr@1580: void init_statistics(bool split_birth = false); duke@435: void set_count(ssize_t v) { _count = v;} ysr@1580: void increment_count() { ysr@1580: _count++; ysr@1580: } ysr@1580: duke@435: void decrement_count() { duke@435: _count--; ysr@447: assert(_count >= 0, "Count should not be negative"); ysr@447: } duke@435: duke@435: public: duke@435: // Constructor duke@435: // Construct a list without any entries. duke@435: FreeList(); duke@435: // Construct a list with "fc" as the first (and lone) entry in the list. jmasa@3730: FreeList(Chunk* fc); duke@435: duke@435: // Reset the head, tail, hint, and count of a free list. duke@435: void reset(size_t hint); duke@435: duke@435: // Declare the current free list to be protected by the given lock. duke@435: #ifdef ASSERT duke@435: void set_protecting_lock(Mutex* protecting_lock) { duke@435: _protecting_lock = protecting_lock; duke@435: } duke@435: #endif duke@435: duke@435: // Accessors. jmasa@3730: Chunk* head() const { duke@435: assert_proper_lock_protection(); duke@435: return _head; duke@435: } jmasa@3730: void set_head(Chunk* v) { duke@435: assert_proper_lock_protection(); duke@435: _head = v; duke@435: assert(!_head || _head->size() == _size, "bad chunk size"); duke@435: } duke@435: // Set the head of the list and set the prev field of non-null duke@435: // values to NULL. jmasa@3730: void link_head(Chunk* v) { duke@435: assert_proper_lock_protection(); duke@435: set_head(v); duke@435: // If this method is not used (just set the head instead), duke@435: // this check can be avoided. duke@435: if (v != NULL) { jmasa@3732: v->link_prev(NULL); duke@435: } duke@435: } duke@435: jmasa@3730: Chunk* tail() const { duke@435: assert_proper_lock_protection(); duke@435: return _tail; duke@435: } jmasa@3730: void set_tail(Chunk* v) { duke@435: assert_proper_lock_protection(); duke@435: _tail = v; duke@435: assert(!_tail || _tail->size() == _size, "bad chunk size"); duke@435: } duke@435: // Set the tail of the list and set the next field of non-null duke@435: // values to NULL. jmasa@3730: void link_tail(Chunk* v) { duke@435: assert_proper_lock_protection(); duke@435: set_tail(v); duke@435: if (v != NULL) { jmasa@3732: v->clear_next(); duke@435: } duke@435: } duke@435: duke@435: // No locking checks in read-accessors: lock-free reads (only) are benign. duke@435: // Readers are expected to have the lock if they are doing work that duke@435: // requires atomicity guarantees in sections of code. duke@435: size_t size() const { duke@435: return _size; duke@435: } duke@435: void set_size(size_t v) { duke@435: assert_proper_lock_protection(); duke@435: _size = v; duke@435: } duke@435: ssize_t count() const { duke@435: return _count; duke@435: } duke@435: size_t hint() const { duke@435: return _hint; duke@435: } duke@435: void set_hint(size_t v) { duke@435: assert_proper_lock_protection(); duke@435: assert(v == 0 || _size < v, "Bad hint"); _hint = v; duke@435: } duke@435: duke@435: // Accessors for statistics duke@435: AllocationStats* allocation_stats() { duke@435: assert_proper_lock_protection(); duke@435: return &_allocation_stats; duke@435: } duke@435: duke@435: ssize_t desired() const { duke@435: return _allocation_stats.desired(); duke@435: } ysr@447: void set_desired(ssize_t v) { ysr@447: assert_proper_lock_protection(); ysr@447: _allocation_stats.set_desired(v); ysr@447: } duke@435: void compute_desired(float inter_sweep_current, ysr@1580: float inter_sweep_estimate, ysr@1580: float intra_sweep_estimate) { duke@435: assert_proper_lock_protection(); duke@435: _allocation_stats.compute_desired(_count, duke@435: inter_sweep_current, ysr@1580: inter_sweep_estimate, ysr@1580: intra_sweep_estimate); duke@435: } jmasa@3732: ssize_t coal_desired() const { jmasa@3732: return _allocation_stats.coal_desired(); duke@435: } jmasa@3732: void set_coal_desired(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_coal_desired(v); duke@435: } duke@435: duke@435: ssize_t surplus() const { duke@435: return _allocation_stats.surplus(); duke@435: } duke@435: void set_surplus(ssize_t v) { duke@435: assert_proper_lock_protection(); duke@435: _allocation_stats.set_surplus(v); duke@435: } duke@435: void increment_surplus() { duke@435: assert_proper_lock_protection(); duke@435: _allocation_stats.increment_surplus(); duke@435: } duke@435: void decrement_surplus() { duke@435: assert_proper_lock_protection(); duke@435: _allocation_stats.decrement_surplus(); duke@435: } duke@435: jmasa@3732: ssize_t bfr_surp() const { jmasa@3732: return _allocation_stats.bfr_surp(); duke@435: } jmasa@3732: void set_bfr_surp(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_bfr_surp(v); duke@435: } jmasa@3732: ssize_t prev_sweep() const { jmasa@3732: return _allocation_stats.prev_sweep(); duke@435: } jmasa@3732: void set_prev_sweep(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_prev_sweep(v); duke@435: } jmasa@3732: ssize_t before_sweep() const { jmasa@3732: return _allocation_stats.before_sweep(); duke@435: } jmasa@3732: void set_before_sweep(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_before_sweep(v); duke@435: } duke@435: jmasa@3732: ssize_t coal_births() const { jmasa@3732: return _allocation_stats.coal_births(); duke@435: } jmasa@3732: void set_coal_births(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_coal_births(v); duke@435: } jmasa@3732: void increment_coal_births() { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.increment_coal_births(); duke@435: } duke@435: jmasa@3732: ssize_t coal_deaths() const { jmasa@3732: return _allocation_stats.coal_deaths(); duke@435: } jmasa@3732: void set_coal_deaths(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_coal_deaths(v); duke@435: } jmasa@3732: void increment_coal_deaths() { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.increment_coal_deaths(); duke@435: } duke@435: jmasa@3732: ssize_t split_births() const { jmasa@3732: return _allocation_stats.split_births(); duke@435: } jmasa@3732: void set_split_births(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_split_births(v); duke@435: } jmasa@3732: void increment_split_births() { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.increment_split_births(); duke@435: } duke@435: jmasa@3732: ssize_t split_deaths() const { jmasa@3732: return _allocation_stats.split_deaths(); duke@435: } jmasa@3732: void set_split_deaths(ssize_t v) { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.set_split_deaths(v); duke@435: } jmasa@3732: void increment_split_deaths() { duke@435: assert_proper_lock_protection(); jmasa@3732: _allocation_stats.increment_split_deaths(); duke@435: } duke@435: duke@435: NOT_PRODUCT( jmasa@3732: // For debugging. The "_returned_bytes" in all the lists are summed duke@435: // and compared with the total number of bytes swept during a duke@435: // collection. jmasa@3732: size_t returned_bytes() const { return _allocation_stats.returned_bytes(); } jmasa@3732: void set_returned_bytes(size_t v) { _allocation_stats.set_returned_bytes(v); } jmasa@3732: void increment_returned_bytes_by(size_t v) { jmasa@3732: _allocation_stats.set_returned_bytes(_allocation_stats.returned_bytes() + v); duke@435: } duke@435: ) duke@435: duke@435: // Unlink head of list and return it. Returns NULL if duke@435: // the list is empty. jmasa@3732: Chunk* get_chunk_at_head(); duke@435: duke@435: // Remove the first "n" or "count", whichever is smaller, chunks from the duke@435: // list, setting "fl", which is required to be empty, to point to them. jmasa@3730: void getFirstNChunksFromList(size_t n, FreeList* fl); duke@435: duke@435: // Unlink this chunk from it's free list jmasa@3732: void remove_chunk(Chunk* fc); duke@435: duke@435: // Add this chunk to this free list. jmasa@3732: void return_chunk_at_head(Chunk* fc); jmasa@3732: void return_chunk_at_tail(Chunk* fc); duke@435: duke@435: // Similar to returnChunk* but also records some diagnostic duke@435: // information. jmasa@3732: void return_chunk_at_head(Chunk* fc, bool record_return); jmasa@3732: void return_chunk_at_tail(Chunk* fc, bool record_return); duke@435: duke@435: // Prepend "fl" (whose size is required to be the same as that of "this") duke@435: // to the front of "this" list. jmasa@3730: void prepend(FreeList* fl); duke@435: duke@435: // Verify that the chunk is in the list. duke@435: // found. Return NULL if "fc" is not found. jmasa@3732: bool verify_chunk_in_free_list(Chunk* fc) const; ysr@447: ysr@1580: // Stats verification ysr@1580: void verify_stats() const PRODUCT_RETURN; ysr@1580: ysr@447: // Printing support ysr@447: static void print_labels_on(outputStream* st, const char* c); ysr@447: void print_on(outputStream* st, const char* c = NULL) const; duke@435: }; stefank@2314: jmasa@3730: #endif // SHARE_VM_MEMORY_FREELIST_HPP