diff --git a/src/share/vm/memory/metablock.cpp b/src/share/vm/memory/metablock.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8aa6a9f83721ec30140afb22ea409f941ed6faab --- /dev/null +++ b/src/share/vm/memory/metablock.cpp @@ -0,0 +1,75 @@ +/* + * 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 "memory/allocation.hpp" +#include "memory/metablock.hpp" +#include "utilities/copy.hpp" +#include "utilities/debug.hpp" + +// Blocks of space for metadata are allocated out of Metachunks. +// +// Metachunk are allocated out of MetadataVirtualspaces and once +// allocated there is no explicit link between a Metachunk and +// the MetadataVirtualspaces from which it was allocated. +// +// Each SpaceManager maintains a +// list of the chunks it is using and the current chunk. The current +// chunk is the chunk from which allocations are done. Space freed in +// a chunk is placed on the free list of blocks (BlockFreelist) and +// reused from there. +// +// Future modification +// +// The Metachunk can conceivable be replaced by the Chunk in +// allocation.hpp. Note that the latter Chunk is the space for +// allocation (allocations from the chunk are out of the space in +// the Chunk after the header for the Chunk) where as Metachunks +// point to space in a VirtualSpace. To replace Metachunks with +// Chunks, change Chunks so that they can be allocated out of a VirtualSpace. +size_t Metablock::_min_block_byte_size = sizeof(Metablock); + +#ifdef ASSERT +size_t Metablock::_overhead = + Chunk::aligned_overhead_size(sizeof(Metablock)) / BytesPerWord; +#else +size_t Metablock::_overhead = 0; +#endif + +// New blocks returned by the Metaspace are zero initialized. +// We should fix the constructors to not assume this instead. +Metablock* Metablock::initialize(MetaWord* p, size_t word_size) { + if (p == NULL) { + return NULL; + } + + Metablock* result = (Metablock*) p; + + // Clear the memory + Copy::fill_to_aligned_words((HeapWord*)result, word_size); +#ifdef ASSERT + result->set_word_size(word_size); +#endif + return result; +} diff --git a/src/share/vm/memory/metachunk.cpp b/src/share/vm/memory/metachunk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b71a1165eff6cdea8244b446e77f59210a2a9c8 --- /dev/null +++ b/src/share/vm/memory/metachunk.cpp @@ -0,0 +1,117 @@ +/* + * 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 "memory/allocation.hpp" +#include "memory/metachunk.hpp" +#include "utilities/copy.hpp" +#include "utilities/debug.hpp" + +// +// Future modification +// +// The Metachunk can conceivable be replaced by the Chunk in +// allocation.hpp. Note that the latter Chunk is the space for +// allocation (allocations from the chunk are out of the space in +// the Chunk after the header for the Chunk) where as Metachunks +// point to space in a VirtualSpace. To replace Metachunks with +// Chunks, change Chunks so that they can be allocated out of a VirtualSpace. + +const size_t metadata_chunk_initialize = 0xf7f7f7f7; + +size_t Metachunk::_overhead = + Chunk::aligned_overhead_size(sizeof(Metachunk)) / BytesPerWord; + +// Metachunk methods + +Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) { + // Set bottom, top, and end. Allow space for the Metachunk itself + Metachunk* chunk = (Metachunk*) ptr; + + MetaWord* chunk_bottom = ptr + _overhead; + chunk->set_bottom(ptr); + chunk->set_top(chunk_bottom); + MetaWord* chunk_end = ptr + word_size; + assert(chunk_end > chunk_bottom, "Chunk must be too small"); + chunk->set_end(chunk_end); + chunk->set_next(NULL); + chunk->set_word_size(word_size); +#ifdef ASSERT + size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord)); + Copy::fill_to_words((HeapWord*) chunk_bottom, data_word_size, metadata_chunk_initialize); +#endif + return chunk; +} + + +MetaWord* Metachunk::allocate(size_t word_size) { + MetaWord* result = NULL; + // If available, bump the pointer to allocate. + if (free_word_size() >= word_size) { + result = _top; + _top = _top + word_size; + } + return result; +} + +// _bottom points to the start of the chunk including the overhead. +size_t Metachunk::used_word_size() { + return pointer_delta(_top, _bottom, sizeof(MetaWord)); +} + +size_t Metachunk::free_word_size() { + return pointer_delta(_end, _top, sizeof(MetaWord)); +} + +size_t Metachunk::capacity_word_size() { + return pointer_delta(_end, _bottom, sizeof(MetaWord)); +} + +void Metachunk::print_on(outputStream* st) const { + st->print_cr("Metachunk:" + " bottom " PTR_FORMAT " top " PTR_FORMAT + " end " PTR_FORMAT " size " SIZE_FORMAT, + bottom(), top(), end(), word_size()); +} + +#ifndef PRODUCT +void Metachunk::mangle() { + // Mangle the payload of the chunk and not the links that + // maintain list of chunks. + HeapWord* start = (HeapWord*)(bottom() + overhead()); + size_t word_size = capacity_word_size() - overhead(); + Copy::fill_to_words(start, word_size, metadata_chunk_initialize); +} +#endif // PRODUCT + +void Metachunk::verify() { +#ifdef ASSERT + // Cannot walk through the blocks unless the blocks have + // headers with sizes. + assert(_bottom <= _top && + _top <= _end, + "Chunk has been smashed"); +#endif + return; +} diff --git a/src/share/vm/memory/metaspace.cpp b/src/share/vm/memory/metaspace.cpp index 1e83247adc15aea1727d167f57f13ed40d1c01d6..42870cd0fda3b8022a59358decd6a226e50f1230 100644 --- a/src/share/vm/memory/metaspace.cpp +++ b/src/share/vm/memory/metaspace.cpp @@ -52,7 +52,6 @@ const bool metaspace_slow_verify = false; const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; size_t const allocation_from_dictionary_limit = 64 * K; -const size_t metadata_chunk_initialize = 0xf7f7f7f7; const size_t metadata_deallocate = 0xf5f5f5f5; MetaWord* last_allocated = 0; @@ -92,22 +91,6 @@ bool MetaspaceGC::_should_concurrent_collect = false; // chunk is the chunk from which allocations are done. Space freed in // a chunk is placed on the free list of blocks (BlockFreelist) and // reused from there. -// -// Future modification -// -// The Metachunk can conceivable be replaced by the Chunk in -// allocation.hpp. Note that the latter Chunk is the space for -// allocation (allocations from the chunk are out of the space in -// the Chunk after the header for the Chunk) where as Metachunks -// point to space in a VirtualSpace. To replace Metachunks with -// Chunks, change Chunks so that they can be allocated out of a VirtualSpace. -size_t Metablock::_min_block_byte_size = sizeof(Metablock); -#ifdef ASSERT - size_t Metablock::_overhead = - Chunk::aligned_overhead_size(sizeof(Metablock)) / BytesPerWord; -#else - size_t Metablock::_overhead = 0; -#endif // Pointer to list of Metachunks. class ChunkList VALUE_OBJ_CLASS_SPEC { @@ -623,6 +606,7 @@ class SpaceManager : public CHeapObj { void locked_print_chunks_in_use_on(outputStream* st) const; void verify(); + void verify_chunk_size(Metachunk* chunk); NOT_PRODUCT(void mangle_freed_chunks();) #ifdef ASSERT void verify_allocation_total(); @@ -631,8 +615,6 @@ class SpaceManager : public CHeapObj { uint const SpaceManager::_small_chunk_limit = 4; - - const char* SpaceManager::_expand_lock_name = "SpaceManager chunk allocation lock"; const int SpaceManager::_expand_lock_rank = Monitor::leaf - 1; @@ -641,103 +623,6 @@ Mutex* const SpaceManager::_expand_lock = SpaceManager::_expand_lock_name, Mutex::_allow_vm_block_flag); -size_t Metachunk::_overhead = - Chunk::aligned_overhead_size(sizeof(Metachunk)) / BytesPerWord; - -// New blocks returned by the Metaspace are zero initialized. -// We should fix the constructors to not assume this instead. -Metablock* Metablock::initialize(MetaWord* p, size_t word_size) { - if (p == NULL) { - return NULL; - } - - Metablock* result = (Metablock*) p; - - // Clear the memory - Copy::fill_to_aligned_words((HeapWord*)result, word_size); -#ifdef ASSERT - result->set_word_size(word_size); -#endif - return result; -} - -// Metachunk methods - -Metachunk* Metachunk::initialize(MetaWord* ptr, size_t word_size) { - // Set bottom, top, and end. Allow space for the Metachunk itself - Metachunk* chunk = (Metachunk*) ptr; - - MetaWord* chunk_bottom = ptr + _overhead; - chunk->set_bottom(ptr); - chunk->set_top(chunk_bottom); - MetaWord* chunk_end = ptr + word_size; - assert(chunk_end > chunk_bottom, "Chunk must be too small"); - chunk->set_end(chunk_end); - chunk->set_next(NULL); - chunk->set_word_size(word_size); -#ifdef ASSERT - size_t data_word_size = pointer_delta(chunk_end, chunk_bottom, sizeof(MetaWord)); - Copy::fill_to_words((HeapWord*) chunk_bottom, data_word_size, metadata_chunk_initialize); -#endif - return chunk; -} - - -MetaWord* Metachunk::allocate(size_t word_size) { - MetaWord* result = NULL; - // If available, bump the pointer to allocate. - if (free_word_size() >= word_size) { - result = _top; - _top = _top + word_size; - } - return result; -} - -// _bottom points to the start of the chunk including the overhead. -size_t Metachunk::used_word_size() { - return pointer_delta(_top, _bottom, sizeof(MetaWord)); -} - -size_t Metachunk::free_word_size() { - return pointer_delta(_end, _top, sizeof(MetaWord)); -} - -size_t Metachunk::capacity_word_size() { - return pointer_delta(_end, _bottom, sizeof(MetaWord)); -} - -void Metachunk::print_on(outputStream* st) const { - st->print_cr("Metachunk:" - " bottom " PTR_FORMAT " top " PTR_FORMAT - " end " PTR_FORMAT " size " SIZE_FORMAT, - bottom(), top(), end(), word_size()); -} - -#ifndef PRODUCT -void Metachunk::mangle() { - // Mangle the payload of the chunk and not the links that - // maintain list of chunks. - HeapWord* start = (HeapWord*)(bottom() + overhead()); - size_t word_size = capacity_word_size() - overhead(); - Copy::fill_to_words(start, word_size, metadata_chunk_initialize); -} -#endif // PRODUCT - -void Metachunk::verify() { -#ifdef ASSERT - // Cannot walk through the blocks unless the blocks have - // headers with sizes. - assert(_bottom <= _top && - _top <= _end, - "Chunk has been smashed"); - assert(SpaceManager::is_humongous(_word_size) || - _word_size == SpaceManager::MediumChunk || - _word_size == SpaceManager::SmallChunk, - "Chunk size is wrong"); -#endif - return; -} - // BlockFreelist methods BlockFreelist::BlockFreelist() : _dictionary(NULL) {} @@ -2214,12 +2099,21 @@ void SpaceManager::verify() { Metachunk* curr = chunks_in_use(i); while (curr != NULL) { curr->verify(); + verify_chunk_size(curr); curr = curr->next(); } } } } +void SpaceManager::verify_chunk_size(Metachunk* chunk) { + assert(is_humongous(chunk->word_size()) || + chunk->word_size() == MediumChunk || + chunk->word_size() == SmallChunk, + "Chunk size is wrong"); + return; +} + #ifdef ASSERT void SpaceManager::verify_allocation_total() { #if 0