--- old/src/share/vm/memory/metaspace.cpp 2016-11-18 14:11:25.322408638 +0100 +++ new/src/share/vm/memory/metaspace.cpp 2016-11-18 14:11:25.210405001 +0100 @@ -111,6 +111,9 @@ size_t _free_chunks_total; size_t _free_chunks_count; + // Return the fixed chunk size for the given list index + size_t list_chunk_size(ChunkIndex index) const; + void dec_free_chunks_total(size_t v) { assert(_free_chunks_count > 0 && _free_chunks_total > 0, @@ -153,7 +156,7 @@ // Map a size to a list index assuming that there are lists // for special, small, medium, and humongous chunks. - static ChunkIndex list_index(size_t size); + ChunkIndex list_index(size_t size) const; // Remove the chunk from its freelist. It is // expected to be on one of the _free_chunks[] lists. @@ -249,6 +252,40 @@ void print_on(outputStream* st) const; }; +void ChunkManager_test_list_index() { + ChunkManager manager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk); + + // Test previous bug where a query for a humongous class metachunk, + // incorrectly matched the non-class medium metachunk size. + { + assert(MediumChunk > ClassMediumChunk, "Precondition for test"); + + ChunkIndex index = manager.list_index(MediumChunk); + + assert(index == HumongousIndex, + "Requested size is larger than ClassMediumChunk," + " so should return HumongousIndex. Got index: %d", (int)index); + } + + // Check the specified sizes as well. + { + ChunkIndex index = manager.list_index(ClassSpecializedChunk); + assert(index == SpecializedIndex, "Wrong index returned. Got index: %d", (int)index); + } + { + ChunkIndex index = manager.list_index(ClassSmallChunk); + assert(index == SmallIndex, "Wrong index returned. Got index: %d", (int)index); + } + { + ChunkIndex index = manager.list_index(ClassMediumChunk); + assert(index == MediumIndex, "Wrong index returned. Got index: %d", (int)index); + } + { + ChunkIndex index = manager.list_index(ClassMediumChunk + 1); + assert(index == HumongousIndex, "Wrong index returned. Got index: %d", (int)index); + } +} + class SmallBlocks : public CHeapObj { const static uint _small_block_max_size = sizeof(TreeChunk >)/HeapWordSize; const static uint _small_block_min_size = sizeof(Metablock)/HeapWordSize; @@ -2337,23 +2374,26 @@ } } -ChunkIndex ChunkManager::list_index(size_t size) { - switch (size) { - case SpecializedChunk: - assert(SpecializedChunk == ClassSpecializedChunk, - "Need branch for ClassSpecializedChunk"); - return SpecializedIndex; - case SmallChunk: - case ClassSmallChunk: - return SmallIndex; - case MediumChunk: - case ClassMediumChunk: - return MediumIndex; - default: - assert(size > MediumChunk || size > ClassMediumChunk, - "Not a humongous chunk"); - return HumongousIndex; +size_t ChunkManager::list_chunk_size(ChunkIndex index) const { + assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex, + "Bad index: %d", (int)index); + + return _free_chunks[index].size(); +} + +ChunkIndex ChunkManager::list_index(size_t size) const { + if (list_chunk_size(SpecializedIndex) == size) { + return SpecializedIndex; } + if (list_chunk_size(SmallIndex) == size) { + return SmallIndex; + } + if (list_chunk_size(MediumIndex) == size) { + return MediumIndex; + } + + assert(size > list_chunk_size(MediumIndex), "Not a humongous chunk"); + return HumongousIndex; } void SpaceManager::deallocate(MetaWord* p, size_t word_size) { @@ -2377,7 +2417,7 @@ // Find the correct list and and set the current // chunk for that list. - ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); + ChunkIndex index = chunk_manager()->list_index(new_chunk->word_size()); if (index != HumongousIndex) { retire_current_chunk(); --- /dev/null 2016-10-20 11:10:27.060007735 +0200 +++ new/test/native/memory/test_chunkManager.cpp 2016-11-18 14:11:25.414411625 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2016, 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 "unittest.hpp" + +void ChunkManager_test_list_index(); + +TEST(ChunkManager, list_index_humongous) { + ChunkManager_test_list_index(); +}