diff options
author | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-02 00:00:23 +0000 |
---|---|---|
committer | dalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-08-02 00:00:23 +0000 |
commit | 3689fb64ddacde3b46cce696d0ef9ee03ec835fc (patch) | |
tree | 2d19c33d64ea9ac5fe5fd228cc8a772dd82db959 /base/allocator | |
parent | 5ebd6a63921d1a77859d8b38e2b436d4d4306ed4 (diff) | |
download | chromium_src-3689fb64ddacde3b46cce696d0ef9ee03ec835fc.zip chromium_src-3689fb64ddacde3b46cce696d0ef9ee03ec835fc.tar.gz chromium_src-3689fb64ddacde3b46cce696d0ef9ee03ec835fc.tar.bz2 |
Modify allocator_shim to support _aligned_alloc(), _aligned_free().
As titled, pipes the Windows specific methods to the appropriate
internal allocators.
BUG=none
TEST=manual test with each allocator over various alignments.
Review URL: https://chromiumcodereview.appspot.com/10828054
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@149537 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/allocator')
-rw-r--r-- | base/allocator/allocator_shim.cc | 61 | ||||
-rw-r--r-- | base/allocator/allocator_unittests.cc | 33 | ||||
-rw-r--r-- | base/allocator/win_allocator.cc | 24 |
3 files changed, 117 insertions, 1 deletions
diff --git a/base/allocator/allocator_shim.cc b/base/allocator/allocator_shim.cc index fd6d741..9d3d932 100644 --- a/base/allocator/allocator_shim.cc +++ b/base/allocator/allocator_shim.cc @@ -65,6 +65,7 @@ void* je_realloc(void* p, size_t s); void je_free(void* s); size_t je_msize(void* p); bool je_malloc_init_hard(); +void* je_memalign(size_t a, size_t s); } extern "C" { @@ -299,6 +300,66 @@ extern "C" void _heap_term() {} // the rest of the CRT is still usable. extern "C" void* _crtheap = reinterpret_cast<void*>(1); +// Provide support for aligned memory through Windows only _aligned_malloc(). +void* _aligned_malloc(size_t size, size_t alignment) { + // _aligned_malloc guarantees parameter validation, so do so here. These + // checks are somewhat stricter than _aligned_malloc() since we're effectively + // using memalign() under the hood. + DCHECK_GT(size, 0U); + DCHECK_EQ(alignment & (alignment - 1), 0U); + DCHECK_EQ(alignment % sizeof(void*), 0U); + + void* ptr; + for (;;) { +#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING + switch (allocator) { + case JEMALLOC: + ptr = je_memalign(alignment, size); + break; + case WINHEAP: + case WINLFH: + ptr = win_heap_memalign(alignment, size); + break; + case TCMALLOC: + default: + ptr = tc_memalign(alignment, size); + break; + } +#else + // TCMalloc case. + ptr = tc_memalign(alignment, size); +#endif + if (ptr) { + // Sanity check alignment. + DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U); + return ptr; + } + + if (!new_mode || !call_new_handler(true)) + break; + } + return ptr; +} + +void _aligned_free(void* p) { + // Both JEMalloc and TCMalloc return pointers from memalign() that are safe to + // use with free(). Pointers allocated with win_heap_memalign() MUST be freed + // via win_heap_memalign_free() since the aligned pointer is not the real one. +#ifdef ENABLE_DYNAMIC_ALLOCATOR_SWITCHING + switch (allocator) { + case JEMALLOC: + je_free(p); + return; + case WINHEAP: + case WINLFH: + win_heap_memalign_free(p); + return; + } +#endif + // TCMalloc case. + do_free(p); +} + #endif // WIN32 #include "generic_allocators.cc" diff --git a/base/allocator/allocator_unittests.cc b/base/allocator/allocator_unittests.cc index a40afdf..cf8b74d 100644 --- a/base/allocator/allocator_unittests.cc +++ b/base/allocator/allocator_unittests.cc @@ -479,6 +479,39 @@ TEST(Allocators, Recalloc) { } } } + +// Test windows specific _aligned_malloc() and _aligned_free() methods. +TEST(Allocators, AlignedMalloc) { + // Try allocating data with a bunch of alignments and sizes + static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384}; + for (int size = 1; size > 0; size = NextSize(size)) { + for (int i = 0; i < ARRAYSIZE(kTestAlignments); ++i) { + unsigned char* ptr = static_cast<unsigned char*>( + _aligned_malloc(size, kTestAlignments[i])); + CheckAlignment(ptr, kTestAlignments[i]); + Fill(ptr, size); + EXPECT_TRUE(Valid(ptr, size)); + + // Make a second allocation of the same size and alignment to prevent + // allocators from passing this test by accident. Per jar, tcmalloc + // provides allocations for new (never before seen) sizes out of a thread + // local heap of a given "size class." Each time the test requests a new + // size, it will usually get the first element of a span, which is a + // 4K aligned allocation. + unsigned char* ptr2 = static_cast<unsigned char*>( + _aligned_malloc(size, kTestAlignments[i])); + CheckAlignment(ptr2, kTestAlignments[i]); + Fill(ptr2, size); + EXPECT_TRUE(Valid(ptr2, size)); + + // Should never happen, but sanity check just in case. + ASSERT_NE(ptr, ptr2); + _aligned_free(ptr); + _aligned_free(ptr2); + } + } +} + #endif diff --git a/base/allocator/win_allocator.cc b/base/allocator/win_allocator.cc index 8ae653a..4b979a0 100644 --- a/base/allocator/win_allocator.cc +++ b/base/allocator/win_allocator.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -47,4 +47,26 @@ size_t win_heap_msize(void* ptr) { return HeapSize(win_heap, 0, ptr); } +void* win_heap_memalign(size_t alignment, size_t size) { + // Reserve enough space to ensure we can align and set aligned_ptr[-1] to the + // original allocation for use with win_heap_memalign_free() later. + size_t allocation_size = size + (alignment - 1) + sizeof(void*); + + // Check for overflow. Alignment and size are checked in allocator_shim. + DCHECK_LT(size, allocation_size); + DCHECK_LT(alignment, allocation_size); + + void* ptr = win_heap_malloc(allocation_size); + char* aligned_ptr = static_cast<char*>(ptr) + sizeof(void*); + aligned_ptr += + alignment - reinterpret_cast<uintptr_t>(aligned_ptr) & (alignment - 1); + + reinterpret_cast<void**>(aligned_ptr)[-1] = ptr; + return aligned_ptr; +} + +void win_heap_memalign_free(void* ptr) { + win_heap_free(static_cast<void**>(ptr)[-1]); +} + } // extern "C" |