8296785: Use realloc for CHeap-allocated BitMaps
Reviewed-by: stuefe, aboldtch
This commit is contained in:
parent
a53be204cb
commit
373e52c0ab
src/hotspot/share
test/hotspot/gtest/memory
@ -627,6 +627,8 @@ class ArrayAllocator : public AllStatic {
|
|||||||
static E* allocate_malloc(size_t length, MEMFLAGS flags);
|
static E* allocate_malloc(size_t length, MEMFLAGS flags);
|
||||||
static E* allocate_mmap(size_t length, MEMFLAGS flags);
|
static E* allocate_mmap(size_t length, MEMFLAGS flags);
|
||||||
|
|
||||||
|
static E* reallocate_malloc(E* addr, size_t new_length, MEMFLAGS flags);
|
||||||
|
|
||||||
static void free_malloc(E* addr, size_t length);
|
static void free_malloc(E* addr, size_t length);
|
||||||
static void free_mmap(E* addr, size_t length);
|
static void free_mmap(E* addr, size_t length);
|
||||||
|
|
||||||
@ -656,6 +658,7 @@ class MallocArrayAllocator : public AllStatic {
|
|||||||
static size_t size_for(size_t length);
|
static size_t size_for(size_t length);
|
||||||
|
|
||||||
static E* allocate(size_t length, MEMFLAGS flags);
|
static E* allocate(size_t length, MEMFLAGS flags);
|
||||||
|
static E* reallocate(E* addr, size_t new_length, MEMFLAGS flags);
|
||||||
static void free(E* addr);
|
static void free(E* addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +101,12 @@ E* MallocArrayAllocator<E>::allocate(size_t length, MEMFLAGS flags) {
|
|||||||
return (E*)AllocateHeap(size_for(length), flags);
|
return (E*)AllocateHeap(size_for(length), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template <class E>
|
||||||
|
E* MallocArrayAllocator<E>::reallocate(E* addr, size_t new_length, MEMFLAGS flags) {
|
||||||
|
return (E*)ReallocateHeap((char*)addr, size_for(new_length), flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class E>
|
||||||
void MallocArrayAllocator<E>::free(E* addr) {
|
void MallocArrayAllocator<E>::free(E* addr) {
|
||||||
FreeHeap(addr);
|
FreeHeap(addr);
|
||||||
}
|
}
|
||||||
@ -130,8 +135,17 @@ E* ArrayAllocator<E>::allocate(size_t length, MEMFLAGS flags) {
|
|||||||
return allocate_mmap(length, flags);
|
return allocate_mmap(length, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class E>
|
||||||
|
E* ArrayAllocator<E>::reallocate_malloc(E* addr, size_t new_length, MEMFLAGS flags) {
|
||||||
|
return MallocArrayAllocator<E>::reallocate(addr, new_length, flags);
|
||||||
|
}
|
||||||
|
|
||||||
template <class E>
|
template <class E>
|
||||||
E* ArrayAllocator<E>::reallocate(E* old_addr, size_t old_length, size_t new_length, MEMFLAGS flags) {
|
E* ArrayAllocator<E>::reallocate(E* old_addr, size_t old_length, size_t new_length, MEMFLAGS flags) {
|
||||||
|
if (should_use_malloc(old_length) && should_use_malloc(new_length)) {
|
||||||
|
return reallocate_malloc(old_addr, new_length, flags);
|
||||||
|
}
|
||||||
|
|
||||||
E* new_addr = (new_length > 0)
|
E* new_addr = (new_length > 0)
|
||||||
? allocate(new_length, flags)
|
? allocate(new_length, flags)
|
||||||
: NULL;
|
: NULL;
|
||||||
@ -147,17 +161,17 @@ E* ArrayAllocator<E>::reallocate(E* old_addr, size_t old_length, size_t new_leng
|
|||||||
return new_addr;
|
return new_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template <class E>
|
||||||
void ArrayAllocator<E>::free_malloc(E* addr, size_t length) {
|
void ArrayAllocator<E>::free_malloc(E* addr, size_t length) {
|
||||||
MallocArrayAllocator<E>::free(addr);
|
MallocArrayAllocator<E>::free(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template <class E>
|
||||||
void ArrayAllocator<E>::free_mmap(E* addr, size_t length) {
|
void ArrayAllocator<E>::free_mmap(E* addr, size_t length) {
|
||||||
MmapArrayAllocator<E>::free(addr, length);
|
MmapArrayAllocator<E>::free(addr, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class E>
|
template <class E>
|
||||||
void ArrayAllocator<E>::free(E* addr, size_t length) {
|
void ArrayAllocator<E>::free(E* addr, size_t length) {
|
||||||
if (addr != NULL) {
|
if (addr != NULL) {
|
||||||
if (should_use_malloc(length)) {
|
if (should_use_malloc(length)) {
|
||||||
|
@ -36,40 +36,69 @@ using idx_t = BitMap::idx_t;
|
|||||||
|
|
||||||
STATIC_ASSERT(sizeof(bm_word_t) == BytesPerWord); // "Implementation assumption."
|
STATIC_ASSERT(sizeof(bm_word_t) == BytesPerWord); // "Implementation assumption."
|
||||||
|
|
||||||
|
// For the BitMaps with allocators that don't support reallocate
|
||||||
template <class BitMapWithAllocator>
|
template <class BitMapWithAllocator>
|
||||||
bm_word_t* GrowableBitMap<BitMapWithAllocator>::reallocate(bm_word_t* old_map, idx_t old_size_in_bits, idx_t new_size_in_bits, bool clear) {
|
static bm_word_t* pseudo_reallocate(const BitMapWithAllocator& derived, bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) {
|
||||||
size_t old_size_in_words = calc_size_in_words(old_size_in_bits);
|
assert(new_size_in_words > 0, "precondition");
|
||||||
size_t new_size_in_words = calc_size_in_words(new_size_in_bits);
|
|
||||||
|
|
||||||
bm_word_t* map = NULL;
|
|
||||||
BitMapWithAllocator* derived = static_cast<BitMapWithAllocator*>(this);
|
|
||||||
|
|
||||||
if (new_size_in_words > 0) {
|
|
||||||
map = derived->allocate(new_size_in_words);
|
|
||||||
|
|
||||||
if (old_map != NULL) {
|
|
||||||
Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) map,
|
|
||||||
MIN2(old_size_in_words, new_size_in_words));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clear && (new_size_in_bits > old_size_in_bits)) {
|
|
||||||
// If old_size_in_bits is not word-aligned, then the preceding
|
|
||||||
// copy can include some trailing bits in the final copied word
|
|
||||||
// that also need to be cleared. See clear_range_within_word.
|
|
||||||
bm_word_t mask = bit_mask(old_size_in_bits) - 1;
|
|
||||||
map[raw_to_words_align_down(old_size_in_bits)] &= mask;
|
|
||||||
// Clear the remaining full words.
|
|
||||||
clear_range_of_words(map, old_size_in_words, new_size_in_words);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bm_word_t* map = derived.allocate(new_size_in_words);
|
||||||
if (old_map != NULL) {
|
if (old_map != NULL) {
|
||||||
derived->free(old_map, old_size_in_words);
|
Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) map,
|
||||||
|
MIN2(old_size_in_words, new_size_in_words));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
derived.free(old_map, old_size_in_words);
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class BitMapWithAllocator>
|
||||||
|
void GrowableBitMap<BitMapWithAllocator>::initialize(idx_t size_in_bits, bool clear) {
|
||||||
|
assert(map() == NULL, "precondition");
|
||||||
|
assert(size() == 0, "precondition");
|
||||||
|
|
||||||
|
resize(size_in_bits, clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class BitMapWithAllocator>
|
||||||
|
void GrowableBitMap<BitMapWithAllocator>::reinitialize(idx_t new_size_in_bits, bool clear) {
|
||||||
|
// Remove previous bits - no need to clear
|
||||||
|
resize(0, false /* clear */);
|
||||||
|
|
||||||
|
initialize(new_size_in_bits, clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class BitMapWithAllocator>
|
||||||
|
void GrowableBitMap<BitMapWithAllocator>::resize(idx_t new_size_in_bits, bool clear) {
|
||||||
|
const size_t old_size_in_bits = size();
|
||||||
|
bm_word_t* const old_map = map();
|
||||||
|
|
||||||
|
const size_t old_size_in_words = calc_size_in_words(size());
|
||||||
|
const size_t new_size_in_words = calc_size_in_words(new_size_in_bits);
|
||||||
|
|
||||||
|
BitMapWithAllocator* derived = static_cast<BitMapWithAllocator*>(this);
|
||||||
|
|
||||||
|
if (new_size_in_words == 0) {
|
||||||
|
derived->free(old_map, old_size_in_words);
|
||||||
|
update(NULL, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bm_word_t* map = derived->reallocate(old_map, old_size_in_words, new_size_in_words);
|
||||||
|
if (clear && (new_size_in_bits > old_size_in_bits)) {
|
||||||
|
// If old_size_in_bits is not word-aligned, then the preceding
|
||||||
|
// copy can include some trailing bits in the final copied word
|
||||||
|
// that also need to be cleared. See clear_range_within_word.
|
||||||
|
bm_word_t mask = bit_mask(old_size_in_bits) - 1;
|
||||||
|
map[raw_to_words_align_down(old_size_in_bits)] &= mask;
|
||||||
|
// Clear the remaining full words.
|
||||||
|
clear_range_of_words(map, old_size_in_words, new_size_in_words);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(map, new_size_in_bits);
|
||||||
|
}
|
||||||
|
|
||||||
ArenaBitMap::ArenaBitMap(Arena* arena, idx_t size_in_bits, bool clear)
|
ArenaBitMap::ArenaBitMap(Arena* arena, idx_t size_in_bits, bool clear)
|
||||||
: GrowableBitMap<ArenaBitMap>(), _arena(arena) {
|
: GrowableBitMap<ArenaBitMap>(), _arena(arena) {
|
||||||
initialize(size_in_bits, clear);
|
initialize(size_in_bits, clear);
|
||||||
@ -79,6 +108,10 @@ bm_word_t* ArenaBitMap::allocate(idx_t size_in_words) const {
|
|||||||
return (bm_word_t*)_arena->Amalloc(size_in_words * BytesPerWord);
|
return (bm_word_t*)_arena->Amalloc(size_in_words * BytesPerWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bm_word_t* ArenaBitMap::reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const {
|
||||||
|
return pseudo_reallocate(*this, old_map, old_size_in_words, new_size_in_words);
|
||||||
|
}
|
||||||
|
|
||||||
ResourceBitMap::ResourceBitMap(idx_t size_in_bits, bool clear)
|
ResourceBitMap::ResourceBitMap(idx_t size_in_bits, bool clear)
|
||||||
: GrowableBitMap<ResourceBitMap>() {
|
: GrowableBitMap<ResourceBitMap>() {
|
||||||
initialize(size_in_bits, clear);
|
initialize(size_in_bits, clear);
|
||||||
@ -88,6 +121,10 @@ bm_word_t* ResourceBitMap::allocate(idx_t size_in_words) const {
|
|||||||
return (bm_word_t*)NEW_RESOURCE_ARRAY(bm_word_t, size_in_words);
|
return (bm_word_t*)NEW_RESOURCE_ARRAY(bm_word_t, size_in_words);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bm_word_t* ResourceBitMap::reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const {
|
||||||
|
return pseudo_reallocate(*this, old_map, old_size_in_words, new_size_in_words);
|
||||||
|
}
|
||||||
|
|
||||||
CHeapBitMap::CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags, bool clear)
|
CHeapBitMap::CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags, bool clear)
|
||||||
: GrowableBitMap<CHeapBitMap>(), _flags(flags) {
|
: GrowableBitMap<CHeapBitMap>(), _flags(flags) {
|
||||||
initialize(size_in_bits, clear);
|
initialize(size_in_bits, clear);
|
||||||
@ -105,6 +142,10 @@ void CHeapBitMap::free(bm_word_t* map, idx_t size_in_words) const {
|
|||||||
ArrayAllocator<bm_word_t>::free(map, size_in_words);
|
ArrayAllocator<bm_word_t>::free(map, size_in_words);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bm_word_t* CHeapBitMap::reallocate(bm_word_t* map, size_t old_size_in_words, size_t new_size_in_words) const {
|
||||||
|
return ArrayAllocator<bm_word_t>::reallocate(map, old_size_in_words, new_size_in_words, _flags);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
void BitMap::verify_size(idx_t size_in_bits) {
|
void BitMap::verify_size(idx_t size_in_bits) {
|
||||||
assert(size_in_bits <= max_size_in_bits(),
|
assert(size_in_bits <= max_size_in_bits(),
|
||||||
|
@ -326,43 +326,28 @@ class BitMap {
|
|||||||
template <class BitMapWithAllocator>
|
template <class BitMapWithAllocator>
|
||||||
class GrowableBitMap : public BitMap {
|
class GrowableBitMap : public BitMap {
|
||||||
protected:
|
protected:
|
||||||
bm_word_t* reallocate(bm_word_t* map, idx_t old_size_in_bits, idx_t new_size_in_bits, bool clear);
|
|
||||||
|
|
||||||
GrowableBitMap() : GrowableBitMap(nullptr, 0) {}
|
GrowableBitMap() : GrowableBitMap(nullptr, 0) {}
|
||||||
GrowableBitMap(bm_word_t* map, idx_t size_in_bits) : BitMap(map, size_in_bits) {}
|
GrowableBitMap(bm_word_t* map, idx_t size_in_bits) : BitMap(map, size_in_bits) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Set up and clear the bitmap memory.
|
// Set up and optionally clear the bitmap memory.
|
||||||
//
|
//
|
||||||
// Precondition: The bitmap was default constructed and has
|
// Precondition: The bitmap was default constructed and has
|
||||||
// not yet had memory allocated via resize or (re)initialize.
|
// not yet had memory allocated via resize or (re)initialize.
|
||||||
void initialize(idx_t size_in_bits, bool clear = true) {
|
void initialize(idx_t size_in_bits, bool clear = true);
|
||||||
assert(map() == NULL, "precondition");
|
|
||||||
assert(size() == 0, "precondition");
|
|
||||||
|
|
||||||
resize(size_in_bits, clear);
|
// Set up and optionally clear the bitmap memory.
|
||||||
}
|
|
||||||
|
|
||||||
// Set up and clear the bitmap memory.
|
|
||||||
//
|
//
|
||||||
// Can be called on previously initialized bitmaps.
|
// Can be called on previously initialized bitmaps.
|
||||||
void reinitialize(idx_t new_size_in_bits, bool clear = true) {
|
void reinitialize(idx_t new_size_in_bits, bool clear = true);
|
||||||
// Remove previous bits - no need to clear
|
|
||||||
resize(0, false /* clear */);
|
|
||||||
|
|
||||||
initialize(new_size_in_bits, clear);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Protected functions, that are used by BitMap sub-classes that support them.
|
// Protected functions, that are used by BitMap sub-classes that support them.
|
||||||
|
|
||||||
// Resize the backing bitmap memory.
|
// Resize the backing bitmap memory.
|
||||||
//
|
//
|
||||||
// Old bits are transferred to the new memory
|
// Old bits are transferred to the new memory
|
||||||
// and the extended memory is cleared.
|
// and the extended memory is optionally cleared.
|
||||||
void resize(idx_t new_size_in_bits, bool clear = true) {
|
void resize(idx_t new_size_in_bits, bool clear = true);
|
||||||
bm_word_t* new_map = reallocate(map(), size(), new_size_in_bits, clear);
|
|
||||||
update(new_map, new_size_in_bits);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// A concrete implementation of the "abstract" BitMap class.
|
// A concrete implementation of the "abstract" BitMap class.
|
||||||
@ -381,12 +366,12 @@ class ArenaBitMap : public GrowableBitMap<ArenaBitMap> {
|
|||||||
NONCOPYABLE(ArenaBitMap);
|
NONCOPYABLE(ArenaBitMap);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Clears the bitmap memory.
|
|
||||||
ArenaBitMap(Arena* arena, idx_t size_in_bits, bool clear = true);
|
ArenaBitMap(Arena* arena, idx_t size_in_bits, bool clear = true);
|
||||||
|
|
||||||
bm_word_t* allocate(idx_t size_in_words) const;
|
bm_word_t* allocate(idx_t size_in_words) const;
|
||||||
|
bm_word_t* reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const;
|
||||||
void free(bm_word_t* map, idx_t size_in_words) const {
|
void free(bm_word_t* map, idx_t size_in_words) const {
|
||||||
// ArenaBitMaps currently don't free memory.
|
// ArenaBitMaps don't free memory.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -397,8 +382,9 @@ class ResourceBitMap : public GrowableBitMap<ResourceBitMap> {
|
|||||||
explicit ResourceBitMap(idx_t size_in_bits, bool clear = true);
|
explicit ResourceBitMap(idx_t size_in_bits, bool clear = true);
|
||||||
|
|
||||||
bm_word_t* allocate(idx_t size_in_words) const;
|
bm_word_t* allocate(idx_t size_in_words) const;
|
||||||
|
bm_word_t* reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const;
|
||||||
void free(bm_word_t* map, idx_t size_in_words) const {
|
void free(bm_word_t* map, idx_t size_in_words) const {
|
||||||
// ResourceBitMaps currently don't free memory.
|
// ResourceBitMaps don't free memory.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -417,6 +403,7 @@ class CHeapBitMap : public GrowableBitMap<CHeapBitMap> {
|
|||||||
~CHeapBitMap();
|
~CHeapBitMap();
|
||||||
|
|
||||||
bm_word_t* allocate(idx_t size_in_words) const;
|
bm_word_t* allocate(idx_t size_in_words) const;
|
||||||
|
bm_word_t* reallocate(bm_word_t* old_map, size_t old_size_in_words, size_t new_size_in_words) const;
|
||||||
void free(bm_word_t* map, idx_t size_in_words) const;
|
void free(bm_word_t* map, idx_t size_in_words) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
99
test/hotspot/gtest/memory/test_arrayAllocator.cpp
Normal file
99
test/hotspot/gtest/memory/test_arrayAllocator.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 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.inline.hpp"
|
||||||
|
#include "unittest.hpp"
|
||||||
|
|
||||||
|
using Element = struct TestArrayAllocatorElement {
|
||||||
|
double a;
|
||||||
|
int b;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void fill(Element* elements, int start, int size) {
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
new (&elements[start + i]) Element{0.0, start + i};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Element* allocate_and_fill(int size) {
|
||||||
|
Element* const elements = MallocArrayAllocator<Element>::allocate(size, mtTest);
|
||||||
|
|
||||||
|
fill(elements, 0, size);
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_VM(ArrayAllocator, allocate) {
|
||||||
|
const int size = 10;
|
||||||
|
|
||||||
|
Element* const elements = allocate_and_fill(size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
ASSERT_EQ(elements[i].b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MallocArrayAllocator<Element>::free(elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_VM(ArrayAllocator, reallocate_0) {
|
||||||
|
const int size = 10;
|
||||||
|
|
||||||
|
Element* const elements = allocate_and_fill(size);
|
||||||
|
|
||||||
|
Element* const ret = MallocArrayAllocator<Element>::reallocate(elements, 0, mtTest);
|
||||||
|
ASSERT_NE(ret, nullptr) << "We've chosen to NOT return nullptr when reallcting with 0";
|
||||||
|
|
||||||
|
MallocArrayAllocator<Element>::free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_VM(ArrayAllocator, reallocate_shrink) {
|
||||||
|
const int size = 10;
|
||||||
|
|
||||||
|
Element* const elements = allocate_and_fill(size);
|
||||||
|
|
||||||
|
Element* const ret = MallocArrayAllocator<Element>::reallocate(elements, size / 2, mtTest);
|
||||||
|
|
||||||
|
for (int i = 0; i < size / 2; i++) {
|
||||||
|
ASSERT_EQ(ret[i].b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MallocArrayAllocator<Element>::free(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_VM(ArrayAllocator, reallocate_grow) {
|
||||||
|
const int size = 10;
|
||||||
|
|
||||||
|
Element* const elements = allocate_and_fill(size);
|
||||||
|
|
||||||
|
Element* const ret = MallocArrayAllocator<Element>::reallocate(elements, size * 2, mtTest);
|
||||||
|
|
||||||
|
fill(ret, size, size);
|
||||||
|
|
||||||
|
for (int i = 0; i < size * 2; i++) {
|
||||||
|
ASSERT_EQ(ret[i].b, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
MallocArrayAllocator<Element>::free(ret);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user