summaryrefslogtreecommitdiffstats
path: root/base/allocator
diff options
context:
space:
mode:
authordalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-02 00:00:23 +0000
committerdalecurtis@chromium.org <dalecurtis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-02 00:00:23 +0000
commit3689fb64ddacde3b46cce696d0ef9ee03ec835fc (patch)
tree2d19c33d64ea9ac5fe5fd228cc8a772dd82db959 /base/allocator
parent5ebd6a63921d1a77859d8b38e2b436d4d4306ed4 (diff)
downloadchromium_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.cc61
-rw-r--r--base/allocator/allocator_unittests.cc33
-rw-r--r--base/allocator/win_allocator.cc24
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"