mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
7045397: NPG: Add freelists to class loader arenas
Reviewed-by: coleenp, stefank, jprovino, ohair
This commit is contained in:
parent
8277d1355e
commit
37bddeb62b
20 changed files with 1547 additions and 1223 deletions
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp"
|
||||
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
||||
#include "memory/freeBlockDictionary.hpp"
|
||||
#include "memory/sharedHeap.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
template <>
|
||||
void AdaptiveFreeList<FreeChunk>::print_on(outputStream* st, const char* c) const {
|
||||
if (c != NULL) {
|
||||
st->print("%16s", c);
|
||||
} else {
|
||||
st->print(SIZE_FORMAT_W(16), size());
|
||||
}
|
||||
st->print("\t"
|
||||
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t"
|
||||
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\n",
|
||||
bfr_surp(), surplus(), desired(), prev_sweep(), before_sweep(),
|
||||
count(), coal_births(), coal_deaths(), split_births(), split_deaths());
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
AdaptiveFreeList<Chunk>::AdaptiveFreeList() : FreeList<Chunk>(), _hint(0) {
|
||||
init_statistics();
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
AdaptiveFreeList<Chunk>::AdaptiveFreeList(Chunk* fc) : FreeList<Chunk>(fc), _hint(0) {
|
||||
init_statistics();
|
||||
#ifndef PRODUCT
|
||||
_allocation_stats.set_returned_bytes(size() * HeapWordSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::initialize() {
|
||||
FreeList<Chunk>::initialize();
|
||||
set_hint(0);
|
||||
init_statistics(true /* split_birth */);
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::reset(size_t hint) {
|
||||
FreeList<Chunk>::reset();
|
||||
set_hint(hint);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::assert_proper_lock_protection_work() const {
|
||||
assert(protecting_lock() != NULL, "Don't call this directly");
|
||||
assert(ParallelGCThreads > 0, "Don't call this directly");
|
||||
Thread* thr = Thread::current();
|
||||
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
|
||||
// assert that we are holding the freelist lock
|
||||
} else if (thr->is_GC_task_thread()) {
|
||||
assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
|
||||
} else if (thr->is_Java_thread()) {
|
||||
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
|
||||
} else {
|
||||
ShouldNotReachHere(); // unaccounted thread type?
|
||||
}
|
||||
}
|
||||
#endif
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::init_statistics(bool split_birth) {
|
||||
_allocation_stats.initialize(split_birth);
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
size_t AdaptiveFreeList<Chunk>::get_better_size() {
|
||||
|
||||
// A candidate chunk has been found. If it is already under
|
||||
// populated and there is a hinT, REturn the hint(). Else
|
||||
// return the size of this chunk.
|
||||
if (surplus() <= 0) {
|
||||
if (hint() != 0) {
|
||||
return hint();
|
||||
} else {
|
||||
return size();
|
||||
}
|
||||
} else {
|
||||
// This list has a surplus so use it.
|
||||
return size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
|
||||
assert_proper_lock_protection();
|
||||
return_chunk_at_head(chunk, true);
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
|
||||
FreeList<Chunk>::return_chunk_at_head(chunk, record_return);
|
||||
#ifdef ASSERT
|
||||
if (record_return) {
|
||||
increment_returned_bytes_by(size()*HeapWordSize);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
|
||||
return_chunk_at_tail(chunk, true);
|
||||
}
|
||||
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
|
||||
FreeList<Chunk>::return_chunk_at_tail(chunk, record_return);
|
||||
#ifdef ASSERT
|
||||
if (record_return) {
|
||||
increment_returned_bytes_by(size()*HeapWordSize);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
template <class Chunk>
|
||||
void AdaptiveFreeList<Chunk>::verify_stats() const {
|
||||
// The +1 of the LH comparand is to allow some "looseness" in
|
||||
// checking: we usually call this interface when adding a block
|
||||
// and we'll subsequently update the stats; we cannot update the
|
||||
// stats beforehand because in the case of the large-block BT
|
||||
// dictionary for example, this might be the first block and
|
||||
// in that case there would be no place that we could record
|
||||
// the stats (which are kept in the block itself).
|
||||
assert((_allocation_stats.prev_sweep() + _allocation_stats.split_births()
|
||||
+ _allocation_stats.coal_births() + 1) // Total Production Stock + 1
|
||||
>= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths()
|
||||
+ (ssize_t)count()), // Total Current Stock + depletion
|
||||
err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT
|
||||
" violates Conservation Principle: "
|
||||
"prev_sweep(" SIZE_FORMAT ")"
|
||||
" + split_births(" SIZE_FORMAT ")"
|
||||
" + coal_births(" SIZE_FORMAT ") + 1 >= "
|
||||
" split_deaths(" SIZE_FORMAT ")"
|
||||
" coal_deaths(" SIZE_FORMAT ")"
|
||||
" + count(" SSIZE_FORMAT ")",
|
||||
this, size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(),
|
||||
_allocation_stats.split_births(), _allocation_stats.split_deaths(),
|
||||
_allocation_stats.coal_deaths(), count()));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Needs to be after the definitions have been seen.
|
||||
template class AdaptiveFreeList<FreeChunk>;
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2010, 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_MEMORY_ADAPTIVEFREELIST_HPP
|
||||
#define SHARE_VM_MEMORY_ADAPTIVEFREELIST_HPP
|
||||
|
||||
#include "memory/freeList.hpp"
|
||||
#include "gc_implementation/shared/allocationStats.hpp"
|
||||
|
||||
class CompactibleFreeListSpace;
|
||||
|
||||
// A class for maintaining a free list of Chunk's. The FreeList
|
||||
// maintains a the structure of the list (head, tail, etc.) plus
|
||||
// statistics for allocations from the list. The links between items
|
||||
// are not part of FreeList. The statistics are
|
||||
// used to make decisions about coalescing Chunk's when they
|
||||
// are swept during collection.
|
||||
//
|
||||
// See the corresponding .cpp file for a description of the specifics
|
||||
// for that implementation.
|
||||
|
||||
class Mutex;
|
||||
|
||||
template <class Chunk>
|
||||
class AdaptiveFreeList : public FreeList<Chunk> {
|
||||
friend class CompactibleFreeListSpace;
|
||||
friend class VMStructs;
|
||||
// friend class PrintTreeCensusClosure<Chunk, FreeList_t>;
|
||||
|
||||
size_t _hint; // next larger size list with a positive surplus
|
||||
|
||||
AllocationStats _allocation_stats; // allocation-related statistics
|
||||
|
||||
public:
|
||||
|
||||
AdaptiveFreeList();
|
||||
AdaptiveFreeList(Chunk* fc);
|
||||
|
||||
using FreeList<Chunk>::assert_proper_lock_protection;
|
||||
#ifdef ASSERT
|
||||
using FreeList<Chunk>::protecting_lock;
|
||||
#endif
|
||||
using FreeList<Chunk>::count;
|
||||
using FreeList<Chunk>::size;
|
||||
using FreeList<Chunk>::verify_chunk_in_free_list;
|
||||
using FreeList<Chunk>::getFirstNChunksFromList;
|
||||
using FreeList<Chunk>::print_on;
|
||||
void return_chunk_at_head(Chunk* fc, bool record_return);
|
||||
void return_chunk_at_head(Chunk* fc);
|
||||
void return_chunk_at_tail(Chunk* fc, bool record_return);
|
||||
void return_chunk_at_tail(Chunk* fc);
|
||||
using FreeList<Chunk>::return_chunk_at_tail;
|
||||
using FreeList<Chunk>::remove_chunk;
|
||||
using FreeList<Chunk>::prepend;
|
||||
using FreeList<Chunk>::print_labels_on;
|
||||
using FreeList<Chunk>::get_chunk_at_head;
|
||||
|
||||
// Initialize.
|
||||
void initialize();
|
||||
|
||||
// Reset the head, tail, hint, and count of a free list.
|
||||
void reset(size_t hint);
|
||||
|
||||
void assert_proper_lock_protection_work() const PRODUCT_RETURN;
|
||||
|
||||
void print_on(outputStream* st, const char* c = NULL) const;
|
||||
|
||||
size_t hint() const {
|
||||
return _hint;
|
||||
}
|
||||
void set_hint(size_t v) {
|
||||
assert_proper_lock_protection();
|
||||
assert(v == 0 || size() < v, "Bad hint");
|
||||
_hint = v;
|
||||
}
|
||||
|
||||
size_t get_better_size();
|
||||
|
||||
// Accessors for statistics
|
||||
void init_statistics(bool split_birth = false);
|
||||
|
||||
AllocationStats* allocation_stats() {
|
||||
assert_proper_lock_protection();
|
||||
return &_allocation_stats;
|
||||
}
|
||||
|
||||
ssize_t desired() const {
|
||||
return _allocation_stats.desired();
|
||||
}
|
||||
void set_desired(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_desired(v);
|
||||
}
|
||||
void compute_desired(float inter_sweep_current,
|
||||
float inter_sweep_estimate,
|
||||
float intra_sweep_estimate) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.compute_desired(count(),
|
||||
inter_sweep_current,
|
||||
inter_sweep_estimate,
|
||||
intra_sweep_estimate);
|
||||
}
|
||||
ssize_t coal_desired() const {
|
||||
return _allocation_stats.coal_desired();
|
||||
}
|
||||
void set_coal_desired(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_coal_desired(v);
|
||||
}
|
||||
|
||||
ssize_t surplus() const {
|
||||
return _allocation_stats.surplus();
|
||||
}
|
||||
void set_surplus(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_surplus(v);
|
||||
}
|
||||
void increment_surplus() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.increment_surplus();
|
||||
}
|
||||
void decrement_surplus() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.decrement_surplus();
|
||||
}
|
||||
|
||||
ssize_t bfr_surp() const {
|
||||
return _allocation_stats.bfr_surp();
|
||||
}
|
||||
void set_bfr_surp(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_bfr_surp(v);
|
||||
}
|
||||
ssize_t prev_sweep() const {
|
||||
return _allocation_stats.prev_sweep();
|
||||
}
|
||||
void set_prev_sweep(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_prev_sweep(v);
|
||||
}
|
||||
ssize_t before_sweep() const {
|
||||
return _allocation_stats.before_sweep();
|
||||
}
|
||||
void set_before_sweep(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_before_sweep(v);
|
||||
}
|
||||
|
||||
ssize_t coal_births() const {
|
||||
return _allocation_stats.coal_births();
|
||||
}
|
||||
void set_coal_births(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_coal_births(v);
|
||||
}
|
||||
void increment_coal_births() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.increment_coal_births();
|
||||
}
|
||||
|
||||
ssize_t coal_deaths() const {
|
||||
return _allocation_stats.coal_deaths();
|
||||
}
|
||||
void set_coal_deaths(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_coal_deaths(v);
|
||||
}
|
||||
void increment_coal_deaths() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.increment_coal_deaths();
|
||||
}
|
||||
|
||||
ssize_t split_births() const {
|
||||
return _allocation_stats.split_births();
|
||||
}
|
||||
void set_split_births(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_split_births(v);
|
||||
}
|
||||
void increment_split_births() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.increment_split_births();
|
||||
}
|
||||
|
||||
ssize_t split_deaths() const {
|
||||
return _allocation_stats.split_deaths();
|
||||
}
|
||||
void set_split_deaths(ssize_t v) {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.set_split_deaths(v);
|
||||
}
|
||||
void increment_split_deaths() {
|
||||
assert_proper_lock_protection();
|
||||
_allocation_stats.increment_split_deaths();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// For debugging. The "_returned_bytes" in all the lists are summed
|
||||
// and compared with the total number of bytes swept during a
|
||||
// collection.
|
||||
size_t returned_bytes() const { return _allocation_stats.returned_bytes(); }
|
||||
void set_returned_bytes(size_t v) { _allocation_stats.set_returned_bytes(v); }
|
||||
void increment_returned_bytes_by(size_t v) {
|
||||
_allocation_stats.set_returned_bytes(_allocation_stats.returned_bytes() + v);
|
||||
}
|
||||
// Stats verification
|
||||
void verify_stats() const;
|
||||
#endif // NOT PRODUCT
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_MEMORY_ADAPTIVEFREELIST_HPP
|
|
@ -91,7 +91,7 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
|
|||
_collector(NULL)
|
||||
{
|
||||
assert(sizeof(FreeChunk) / BytesPerWord <= MinChunkSize,
|
||||
"FreeChunk is larger than expected");
|
||||
"FreeChunk is larger than expected");
|
||||
_bt.set_space(this);
|
||||
initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
|
||||
// We have all of "mr", all of which we place in the dictionary
|
||||
|
@ -101,14 +101,14 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
|
|||
// implementation, namely, the simple binary tree (splaying
|
||||
// temporarily disabled).
|
||||
switch (dictionaryChoice) {
|
||||
case FreeBlockDictionary<FreeChunk>::dictionaryBinaryTree:
|
||||
_dictionary = new BinaryTreeDictionary<FreeChunk, AdaptiveFreeList>(mr);
|
||||
break;
|
||||
case FreeBlockDictionary<FreeChunk>::dictionarySplayTree:
|
||||
case FreeBlockDictionary<FreeChunk>::dictionarySkipList:
|
||||
default:
|
||||
warning("dictionaryChoice: selected option not understood; using"
|
||||
" default BinaryTreeDictionary implementation instead.");
|
||||
case FreeBlockDictionary<FreeChunk>::dictionaryBinaryTree:
|
||||
_dictionary = new BinaryTreeDictionary<FreeChunk>(mr, use_adaptive_freelists);
|
||||
break;
|
||||
}
|
||||
assert(_dictionary != NULL, "CMS dictionary initialization");
|
||||
// The indexed free lists are initially all empty and are lazily
|
||||
|
@ -453,7 +453,7 @@ const {
|
|||
reportIndexedFreeListStatistics();
|
||||
gclog_or_tty->print_cr("Layout of Indexed Freelists");
|
||||
gclog_or_tty->print_cr("---------------------------");
|
||||
FreeList<FreeChunk>::print_labels_on(st, "size");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
|
||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
_indexedFreeList[i].print_on(gclog_or_tty);
|
||||
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
|
||||
|
@ -1319,7 +1319,7 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromGreater(size_t numWords) {
|
|||
size_t currSize = numWords + MinChunkSize;
|
||||
assert(currSize % MinObjAlignment == 0, "currSize should be aligned");
|
||||
for (i = currSize; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||
if (fl->head()) {
|
||||
ret = getFromListGreater(fl, numWords);
|
||||
assert(ret == NULL || ret->is_free(), "Should be returning a free chunk");
|
||||
|
@ -1702,7 +1702,9 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) {
|
|||
_dictionary->return_chunk(chunk);
|
||||
#ifndef PRODUCT
|
||||
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
|
||||
TreeChunk<FreeChunk>::as_TreeChunk(chunk)->list()->verify_stats();
|
||||
TreeChunk<FreeChunk, AdaptiveFreeList>* tc = TreeChunk<FreeChunk, AdaptiveFreeList>::as_TreeChunk(chunk);
|
||||
TreeList<FreeChunk, AdaptiveFreeList>* tl = tc->list();
|
||||
tl->verify_stats();
|
||||
}
|
||||
#endif // PRODUCT
|
||||
}
|
||||
|
@ -1745,7 +1747,7 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats(
|
|||
{
|
||||
MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag);
|
||||
ec = dictionary()->find_largest_dict(); // get largest block
|
||||
if (ec != NULL && ec->end() == chunk) {
|
||||
if (ec != NULL && ec->end() == (uintptr_t*) chunk) {
|
||||
// It's a coterminal block - we can coalesce.
|
||||
size_t old_size = ec->size();
|
||||
coalDeath(old_size);
|
||||
|
@ -1850,11 +1852,11 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) {
|
|||
the excess is >= MIN_CHUNK. */
|
||||
size_t start = align_object_size(numWords + MinChunkSize);
|
||||
if (start < IndexSetSize) {
|
||||
FreeList<FreeChunk>* it = _indexedFreeList;
|
||||
AdaptiveFreeList<FreeChunk>* it = _indexedFreeList;
|
||||
size_t hint = _indexedFreeList[start].hint();
|
||||
while (hint < IndexSetSize) {
|
||||
assert(hint % MinObjAlignment == 0, "hint should be aligned");
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[hint];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[hint];
|
||||
if (fl->surplus() > 0 && fl->head() != NULL) {
|
||||
// Found a list with surplus, reset original hint
|
||||
// and split out a free chunk which is returned.
|
||||
|
@ -1873,7 +1875,7 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) {
|
|||
}
|
||||
|
||||
/* Requires fl->size >= numWords + MinChunkSize */
|
||||
FreeChunk* CompactibleFreeListSpace::getFromListGreater(FreeList<FreeChunk>* fl,
|
||||
FreeChunk* CompactibleFreeListSpace::getFromListGreater(AdaptiveFreeList<FreeChunk>* fl,
|
||||
size_t numWords) {
|
||||
FreeChunk *curr = fl->head();
|
||||
size_t oldNumWords = curr->size();
|
||||
|
@ -2155,7 +2157,7 @@ void CompactibleFreeListSpace::beginSweepFLCensus(
|
|||
assert_locked();
|
||||
size_t i;
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||
if (PrintFLSStatistics > 1) {
|
||||
gclog_or_tty->print("size[%d] : ", i);
|
||||
}
|
||||
|
@ -2174,7 +2176,7 @@ void CompactibleFreeListSpace::setFLSurplus() {
|
|||
assert_locked();
|
||||
size_t i;
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
fl->set_surplus(fl->count() -
|
||||
(ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent));
|
||||
}
|
||||
|
@ -2185,7 +2187,7 @@ void CompactibleFreeListSpace::setFLHints() {
|
|||
size_t i;
|
||||
size_t h = IndexSetSize;
|
||||
for (i = IndexSetSize - 1; i != 0; i -= IndexSetStride) {
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
fl->set_hint(h);
|
||||
if (fl->surplus() > 0) {
|
||||
h = i;
|
||||
|
@ -2197,7 +2199,7 @@ void CompactibleFreeListSpace::clearFLCensus() {
|
|||
assert_locked();
|
||||
size_t i;
|
||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
fl->set_prev_sweep(fl->count());
|
||||
fl->set_coal_births(0);
|
||||
fl->set_coal_deaths(0);
|
||||
|
@ -2224,7 +2226,7 @@ void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
|
|||
|
||||
bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
||||
if (size < SmallForDictionary) {
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
return (fl->coal_desired() < 0) ||
|
||||
((int)fl->count() > fl->coal_desired());
|
||||
} else {
|
||||
|
@ -2234,14 +2236,14 @@ bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
|||
|
||||
void CompactibleFreeListSpace::smallCoalBirth(size_t size) {
|
||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
fl->increment_coal_births();
|
||||
fl->increment_surplus();
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::smallCoalDeath(size_t size) {
|
||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
fl->increment_coal_deaths();
|
||||
fl->decrement_surplus();
|
||||
}
|
||||
|
@ -2250,7 +2252,7 @@ void CompactibleFreeListSpace::coalBirth(size_t size) {
|
|||
if (size < SmallForDictionary) {
|
||||
smallCoalBirth(size);
|
||||
} else {
|
||||
dictionary()->dict_census_udpate(size,
|
||||
dictionary()->dict_census_update(size,
|
||||
false /* split */,
|
||||
true /* birth */);
|
||||
}
|
||||
|
@ -2260,7 +2262,7 @@ void CompactibleFreeListSpace::coalDeath(size_t size) {
|
|||
if(size < SmallForDictionary) {
|
||||
smallCoalDeath(size);
|
||||
} else {
|
||||
dictionary()->dict_census_udpate(size,
|
||||
dictionary()->dict_census_update(size,
|
||||
false /* split */,
|
||||
false /* birth */);
|
||||
}
|
||||
|
@ -2268,14 +2270,14 @@ void CompactibleFreeListSpace::coalDeath(size_t size) {
|
|||
|
||||
void CompactibleFreeListSpace::smallSplitBirth(size_t size) {
|
||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
fl->increment_split_births();
|
||||
fl->increment_surplus();
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::smallSplitDeath(size_t size) {
|
||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||
fl->increment_split_deaths();
|
||||
fl->decrement_surplus();
|
||||
}
|
||||
|
@ -2284,7 +2286,7 @@ void CompactibleFreeListSpace::split_birth(size_t size) {
|
|||
if (size < SmallForDictionary) {
|
||||
smallSplitBirth(size);
|
||||
} else {
|
||||
dictionary()->dict_census_udpate(size,
|
||||
dictionary()->dict_census_update(size,
|
||||
true /* split */,
|
||||
true /* birth */);
|
||||
}
|
||||
|
@ -2294,7 +2296,7 @@ void CompactibleFreeListSpace::splitDeath(size_t size) {
|
|||
if (size < SmallForDictionary) {
|
||||
smallSplitDeath(size);
|
||||
} else {
|
||||
dictionary()->dict_census_udpate(size,
|
||||
dictionary()->dict_census_update(size,
|
||||
true /* split */,
|
||||
false /* birth */);
|
||||
}
|
||||
|
@ -2517,10 +2519,10 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const {
|
|||
|
||||
#ifndef PRODUCT
|
||||
void CompactibleFreeListSpace::check_free_list_consistency() const {
|
||||
assert(_dictionary->min_size() <= IndexSetSize,
|
||||
assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size() <= IndexSetSize),
|
||||
"Some sizes can't be allocated without recourse to"
|
||||
" linear allocation buffers");
|
||||
assert(BinaryTreeDictionary<FreeChunk>::min_tree_chunk_size*HeapWordSize == sizeof(TreeChunk<FreeChunk>),
|
||||
assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size()*HeapWordSize == sizeof(TreeChunk<FreeChunk, AdaptiveFreeList>)),
|
||||
"else MIN_TREE_CHUNK_SIZE is wrong");
|
||||
assert(IndexSetStart != 0, "IndexSetStart not initialized");
|
||||
assert(IndexSetStride != 0, "IndexSetStride not initialized");
|
||||
|
@ -2529,15 +2531,15 @@ void CompactibleFreeListSpace::check_free_list_consistency() const {
|
|||
|
||||
void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
||||
assert_lock_strong(&_freelistLock);
|
||||
FreeList<FreeChunk> total;
|
||||
AdaptiveFreeList<FreeChunk> total;
|
||||
gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count);
|
||||
FreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
size_t total_free = 0;
|
||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||
const FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
const AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||
total_free += fl->count() * fl->size();
|
||||
if (i % (40*IndexSetStride) == 0) {
|
||||
FreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||
}
|
||||
fl->print_on(gclog_or_tty);
|
||||
total.set_bfr_surp( total.bfr_surp() + fl->bfr_surp() );
|
||||
|
@ -2620,7 +2622,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
|||
res = _cfls->getChunkFromDictionaryExact(word_sz);
|
||||
if (res == NULL) return NULL;
|
||||
} else {
|
||||
FreeList<FreeChunk>* fl = &_indexedFreeList[word_sz];
|
||||
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[word_sz];
|
||||
if (fl->count() == 0) {
|
||||
// Attempt to refill this local free list.
|
||||
get_from_global_pool(word_sz, fl);
|
||||
|
@ -2640,7 +2642,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
|||
|
||||
// Get a chunk of blocks of the right size and update related
|
||||
// book-keeping stats
|
||||
void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList<FreeChunk>* fl) {
|
||||
void CFLS_LAB::get_from_global_pool(size_t word_sz, AdaptiveFreeList<FreeChunk>* fl) {
|
||||
// Get the #blocks we want to claim
|
||||
size_t n_blks = (size_t)_blocks_to_claim[word_sz].average();
|
||||
assert(n_blks > 0, "Error");
|
||||
|
@ -2722,7 +2724,7 @@ void CFLS_LAB::retire(int tid) {
|
|||
if (num_retire > 0) {
|
||||
_cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]);
|
||||
// Reset this list.
|
||||
_indexedFreeList[i] = FreeList<FreeChunk>();
|
||||
_indexedFreeList[i] = AdaptiveFreeList<FreeChunk>();
|
||||
_indexedFreeList[i].set_size(i);
|
||||
}
|
||||
}
|
||||
|
@ -2736,7 +2738,7 @@ void CFLS_LAB::retire(int tid) {
|
|||
}
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList<FreeChunk>* fl) {
|
||||
void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList<FreeChunk>* fl) {
|
||||
assert(fl->count() == 0, "Precondition.");
|
||||
assert(word_sz < CompactibleFreeListSpace::IndexSetSize,
|
||||
"Precondition");
|
||||
|
@ -2752,12 +2754,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
|||
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
|
||||
(CMSSplitIndexedFreeListBlocks || k <= 1);
|
||||
k++, cur_sz = k * word_sz) {
|
||||
FreeList<FreeChunk> fl_for_cur_sz; // Empty.
|
||||
AdaptiveFreeList<FreeChunk> fl_for_cur_sz; // Empty.
|
||||
fl_for_cur_sz.set_size(cur_sz);
|
||||
{
|
||||
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
FreeList<FreeChunk>* gfl = &_indexedFreeList[cur_sz];
|
||||
AdaptiveFreeList<FreeChunk>* gfl = &_indexedFreeList[cur_sz];
|
||||
if (gfl->count() != 0) {
|
||||
// nn is the number of chunks of size cur_sz that
|
||||
// we'd need to split k-ways each, in order to create
|
||||
|
@ -2832,12 +2834,11 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
|||
MutexLockerEx x(parDictionaryAllocLock(),
|
||||
Mutex::_no_safepoint_check_flag);
|
||||
while (n > 0) {
|
||||
fc = dictionary()->get_chunk(MAX2(n * word_sz,
|
||||
_dictionary->min_size()),
|
||||
fc = dictionary()->get_chunk(MAX2(n * word_sz, _dictionary->min_size()),
|
||||
FreeBlockDictionary<FreeChunk>::atLeast);
|
||||
if (fc != NULL) {
|
||||
_bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk
|
||||
dictionary()->dict_census_udpate(fc->size(),
|
||||
dictionary()->dict_census_update(fc->size(),
|
||||
true /*split*/,
|
||||
false /*birth*/);
|
||||
break;
|
||||
|
@ -2890,7 +2891,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
|||
fc->set_size(prefix_size);
|
||||
if (rem >= IndexSetSize) {
|
||||
returnChunkToDictionary(rem_fc);
|
||||
dictionary()->dict_census_udpate(rem, true /*split*/, true /*birth*/);
|
||||
dictionary()->dict_census_update(rem, true /*split*/, true /*birth*/);
|
||||
rem_fc = NULL;
|
||||
}
|
||||
// Otherwise, return it to the small list below.
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
||||
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
||||
|
||||
#include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp"
|
||||
#include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp"
|
||||
#include "memory/binaryTreeDictionary.hpp"
|
||||
#include "memory/blockOffsetTable.inline.hpp"
|
||||
|
@ -38,6 +39,7 @@
|
|||
class CompactibleFreeListSpace;
|
||||
class BlkClosure;
|
||||
class BlkClosureCareful;
|
||||
class FreeChunk;
|
||||
class UpwardsObjectClosure;
|
||||
class ObjectClosureCareful;
|
||||
class Klass;
|
||||
|
@ -131,7 +133,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
|||
FreeBlockDictionary<FreeChunk>::DictionaryChoice _dictionaryChoice;
|
||||
FreeBlockDictionary<FreeChunk>* _dictionary; // ptr to dictionary for large size blocks
|
||||
|
||||
FreeList<FreeChunk> _indexedFreeList[IndexSetSize];
|
||||
AdaptiveFreeList<FreeChunk> _indexedFreeList[IndexSetSize];
|
||||
// indexed array for small size blocks
|
||||
// allocation stategy
|
||||
bool _fitStrategy; // Use best fit strategy.
|
||||
|
@ -168,7 +170,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
|||
// If the count of "fl" is negative, it's absolute value indicates a
|
||||
// number of free chunks that had been previously "borrowed" from global
|
||||
// list of size "word_sz", and must now be decremented.
|
||||
void par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList<FreeChunk>* fl);
|
||||
void par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList<FreeChunk>* fl);
|
||||
|
||||
// Allocation helper functions
|
||||
// Allocate using a strategy that takes from the indexed free lists
|
||||
|
@ -214,7 +216,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
|||
// and return it. The split off remainder is returned to
|
||||
// the free lists. The old name for getFromListGreater
|
||||
// was lookInListGreater.
|
||||
FreeChunk* getFromListGreater(FreeList<FreeChunk>* fl, size_t numWords);
|
||||
FreeChunk* getFromListGreater(AdaptiveFreeList<FreeChunk>* fl, size_t numWords);
|
||||
// Get a chunk in the indexed free list or dictionary,
|
||||
// by considering a larger chunk and splitting it.
|
||||
FreeChunk* getChunkFromGreater(size_t numWords);
|
||||
|
@ -621,7 +623,7 @@ class CFLS_LAB : public CHeapObj<mtGC> {
|
|||
CompactibleFreeListSpace* _cfls;
|
||||
|
||||
// Our local free lists.
|
||||
FreeList<FreeChunk> _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
|
||||
AdaptiveFreeList<FreeChunk> _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
|
||||
|
||||
// Initialized from a command-line arg.
|
||||
|
||||
|
@ -634,7 +636,7 @@ class CFLS_LAB : public CHeapObj<mtGC> {
|
|||
size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize];
|
||||
|
||||
// Internal work method
|
||||
void get_from_global_pool(size_t word_sz, FreeList<FreeChunk>* fl);
|
||||
void get_from_global_pool(size_t word_sz, AdaptiveFreeList<FreeChunk>* fl);
|
||||
|
||||
public:
|
||||
CFLS_LAB(CompactibleFreeListSpace* cfls);
|
||||
|
|
|
@ -9143,7 +9143,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) {
|
|||
size_t shrinkable_size_in_bytes = chunk_at_end->size();
|
||||
size_t aligned_shrinkable_size_in_bytes =
|
||||
align_size_down(shrinkable_size_in_bytes, os::vm_page_size());
|
||||
assert(unallocated_start <= chunk_at_end->end(),
|
||||
assert(unallocated_start <= (HeapWord*) chunk_at_end->end(),
|
||||
"Inconsistent chunk at end of space");
|
||||
size_t bytes = MIN2(desired_bytes, aligned_shrinkable_size_in_bytes);
|
||||
size_t word_size_before = heap_word_size(_virtual_space.committed_size());
|
||||
|
@ -9210,7 +9210,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) {
|
|||
|
||||
assert(_cmsSpace->unallocated_block() <= _cmsSpace->end(),
|
||||
"Inconsistency at end of space");
|
||||
assert(chunk_at_end->end() == _cmsSpace->end(),
|
||||
assert(chunk_at_end->end() == (uintptr_t*) _cmsSpace->end(),
|
||||
"Shrinking is inconsistent");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -133,7 +133,7 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
|
|||
}
|
||||
|
||||
// Return the address past the end of this chunk
|
||||
HeapWord* end() const { return ((HeapWord*) this) + size(); }
|
||||
uintptr_t* end() const { return ((uintptr_t*) this) + size(); }
|
||||
|
||||
// debugging
|
||||
void verify() const PRODUCT_RETURN;
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
||||
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
||||
|
||||
typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList> AFLBinaryTreeDictionary;
|
||||
|
||||
#define VM_STRUCTS_CMS(nonstatic_field, \
|
||||
volatile_nonstatic_field, \
|
||||
static_field) \
|
||||
|
@ -38,14 +40,8 @@
|
|||
nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \
|
||||
nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \
|
||||
static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \
|
||||
volatile_nonstatic_field(FreeChunk, _size, size_t) \
|
||||
nonstatic_field(FreeChunk, _next, FreeChunk*) \
|
||||
nonstatic_field(FreeChunk, _prev, FreeChunk*) \
|
||||
nonstatic_field(LinearAllocBlock, _word_size, size_t) \
|
||||
nonstatic_field(FreeList<FreeChunk>, _size, size_t) \
|
||||
nonstatic_field(FreeList<FreeChunk>, _count, ssize_t) \
|
||||
nonstatic_field(BinaryTreeDictionary<FreeChunk>,_total_size, size_t) \
|
||||
nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary<FreeChunk>*) \
|
||||
nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \
|
||||
nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList<FreeChunk>) \
|
||||
nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock)
|
||||
|
||||
|
@ -60,19 +56,17 @@
|
|||
declare_toplevel_type(CMSCollector) \
|
||||
declare_toplevel_type(CMSBitMap) \
|
||||
declare_toplevel_type(FreeChunk) \
|
||||
declare_toplevel_type(Metablock) \
|
||||
declare_toplevel_type(ConcurrentMarkSweepThread*) \
|
||||
declare_toplevel_type(ConcurrentMarkSweepGeneration*) \
|
||||
declare_toplevel_type(SurrogateLockerThread*) \
|
||||
declare_toplevel_type(CompactibleFreeListSpace*) \
|
||||
declare_toplevel_type(CMSCollector*) \
|
||||
declare_toplevel_type(FreeChunk*) \
|
||||
declare_toplevel_type(BinaryTreeDictionary<FreeChunk>*) \
|
||||
declare_toplevel_type(FreeBlockDictionary<FreeChunk>*) \
|
||||
declare_toplevel_type(FreeList<FreeChunk>*) \
|
||||
declare_toplevel_type(FreeList<FreeChunk>) \
|
||||
declare_toplevel_type(AFLBinaryTreeDictionary*) \
|
||||
declare_toplevel_type(LinearAllocBlock) \
|
||||
declare_toplevel_type(FreeBlockDictionary<FreeChunk>) \
|
||||
declare_type(BinaryTreeDictionary<FreeChunk>, FreeBlockDictionary<FreeChunk>)
|
||||
declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary<FreeChunk>) \
|
||||
declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary<FreeChunk>) \
|
||||
|
||||
#define VM_INT_CONSTANTS_CMS(declare_constant) \
|
||||
declare_constant(Generation::ConcurrentMarkSweep) \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue