summaryrefslogtreecommitdiffstats
path: root/base/memory
diff options
context:
space:
mode:
authorjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-23 17:52:20 +0000
committerjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-23 17:52:20 +0000
commitcd924d6e5efdf80f66283ac66987f2b339c381cf (patch)
tree89d2ccd8588e12669b93eb98117e8d76a766fbf2 /base/memory
parent2e8bb832c7b3867b3a10b81621830add0dd5bfb5 (diff)
downloadchromium_src-cd924d6e5efdf80f66283ac66987f2b339c381cf.zip
chromium_src-cd924d6e5efdf80f66283ac66987f2b339c381cf.tar.gz
chromium_src-cd924d6e5efdf80f66283ac66987f2b339c381cf.tar.bz2
Add ALIGNAS and ALIGNOF macros to ensure proper alignment of StaticMemorySingletonTraits
BUG=95006 Review URL: https://chromiumcodereview.appspot.com/9186057 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123270 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/memory')
-rw-r--r--base/memory/aligned_memory.h77
-rw-r--r--base/memory/aligned_memory_unittest.cc50
-rw-r--r--base/memory/singleton.h18
-rw-r--r--base/memory/singleton_unittest.cc37
4 files changed, 170 insertions, 12 deletions
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
new file mode 100644
index 0000000..dc9db90
--- /dev/null
+++ b/base/memory/aligned_memory.h
@@ -0,0 +1,77 @@
+// 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.
+
+// AlignedMemory is a POD type that gives you a portable way to specify static
+// or local stack data of a given alignment and size. For example, if you need
+// static storage for a class, but you want manual control over when the object
+// is constructed and destructed (you don't want static initialization and
+// destruction), use AlignedMemory:
+//
+// static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
+//
+// // ... at runtime:
+// new(my_class.void_data()) MyClass();
+//
+// // ... use it:
+// MyClass* mc = my_class.data_as<MyClass>();
+//
+// // ... later, to destruct my_class:
+// my_class.data_as<MyClass>()->MyClass::~MyClass();
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+
+namespace base {
+
+// AlignedMemory is specialized for all supported alignments.
+// Make sure we get a compiler error if someone uses an unsupported alignment.
+template <size_t Size, size_t ByteAlignment>
+struct AlignedMemory {};
+
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+ template <size_t Size> \
+ class AlignedMemory<Size, byte_alignment> { \
+ public: \
+ ALIGNAS(byte_alignment) uint8 data_[Size]; \
+ void* void_data() { return reinterpret_cast<void*>(data_); } \
+ const void* void_data() const { \
+ return reinterpret_cast<const void*>(data_); \
+ } \
+ template<typename Type> \
+ Type* data_as() { return reinterpret_cast<Type*>(void_data()); } \
+ template<typename Type> \
+ const Type* data_as() const { \
+ return reinterpret_cast<const Type*>(void_data()); \
+ } \
+ private: \
+ void* operator new(size_t); \
+ void operator delete(void*); \
+ }
+
+// Specialization for all alignments is required because MSVC (as of VS 2008)
+// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
+// Greater than 4096 alignment is not supported by some compilers, so 4096 is
+// the maximum specified here.
+BASE_DECL_ALIGNED_MEMORY(1);
+BASE_DECL_ALIGNED_MEMORY(2);
+BASE_DECL_ALIGNED_MEMORY(4);
+BASE_DECL_ALIGNED_MEMORY(8);
+BASE_DECL_ALIGNED_MEMORY(16);
+BASE_DECL_ALIGNED_MEMORY(32);
+BASE_DECL_ALIGNED_MEMORY(64);
+BASE_DECL_ALIGNED_MEMORY(128);
+BASE_DECL_ALIGNED_MEMORY(256);
+BASE_DECL_ALIGNED_MEMORY(512);
+BASE_DECL_ALIGNED_MEMORY(1024);
+BASE_DECL_ALIGNED_MEMORY(2048);
+BASE_DECL_ALIGNED_MEMORY(4096);
+
+} // base
+
+#endif // BASE_MEMORY_ALIGNED_MEMORY_H_
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
new file mode 100644
index 0000000..065e952
--- /dev/null
+++ b/base/memory/aligned_memory_unittest.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 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.
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define EXPECT_ALIGNED(ptr, align) \
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+namespace {
+
+using base::AlignedMemory;
+
+TEST(AlignedMemoryTest, StaticAlignment) {
+ static AlignedMemory<8, 8> raw8;
+ static AlignedMemory<8, 16> raw16;
+ static AlignedMemory<8, 256> raw256;
+ static AlignedMemory<8, 4096> raw4096;
+
+ EXPECT_EQ(8u, ALIGNOF(raw8));
+ EXPECT_EQ(16u, ALIGNOF(raw16));
+ EXPECT_EQ(256u, ALIGNOF(raw256));
+ EXPECT_EQ(4096u, ALIGNOF(raw4096));
+
+ EXPECT_ALIGNED(raw8.void_data(), 8);
+ EXPECT_ALIGNED(raw16.void_data(), 16);
+ EXPECT_ALIGNED(raw256.void_data(), 256);
+ EXPECT_ALIGNED(raw4096.void_data(), 4096);
+}
+
+TEST(AlignedMemoryTest, StackAlignment) {
+ AlignedMemory<8, 8> raw8;
+ AlignedMemory<8, 16> raw16;
+ AlignedMemory<8, 256> raw256;
+ AlignedMemory<8, 4096> raw4096;
+
+ EXPECT_EQ(8u, ALIGNOF(raw8));
+ EXPECT_EQ(16u, ALIGNOF(raw16));
+ EXPECT_EQ(256u, ALIGNOF(raw256));
+ EXPECT_EQ(4096u, ALIGNOF(raw4096));
+
+ EXPECT_ALIGNED(raw8.void_data(), 8);
+ EXPECT_ALIGNED(raw16.void_data(), 16);
+ EXPECT_ALIGNED(raw256.void_data(), 256);
+ EXPECT_ALIGNED(raw4096.void_data(), 4096);
+}
+
+} // namespace
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index d76070019..5549012 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -23,6 +23,7 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
#include "base/base_export.h"
+#include "base/memory/aligned_memory.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_restrictions.h"
@@ -106,18 +107,14 @@ struct StaticMemorySingletonTraits {
// WARNING: User has to deal with get() in the singleton class
// this is traits for returning NULL.
static Type* New() {
+ // Only constructs once and returns pointer; otherwise returns NULL.
if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
return NULL;
- Type* ptr = reinterpret_cast<Type*>(buffer_);
- // We are protected by a memory barrier.
- new(ptr) Type();
- return ptr;
+ return new(buffer_.void_data()) Type();
}
static void Delete(Type* p) {
- base::subtle::NoBarrier_Store(&dead_, 1);
- base::subtle::MemoryBarrier();
if (p != NULL)
p->Type::~Type();
}
@@ -131,16 +128,13 @@ struct StaticMemorySingletonTraits {
}
private:
- static const size_t kBufferSize = (sizeof(Type) +
- sizeof(intptr_t) - 1) / sizeof(intptr_t);
- static intptr_t buffer_[kBufferSize];
-
+ static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
// Signal the object was already deleted, so it is not revived.
static base::subtle::Atomic32 dead_;
};
-template <typename Type> intptr_t
- StaticMemorySingletonTraits<Type>::buffer_[kBufferSize];
+template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+ StaticMemorySingletonTraits<Type>::buffer_;
template <typename Type> base::subtle::Atomic32
StaticMemorySingletonTraits<Type>::dead_ = 0;
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
index 068148f..33928a7 100644
--- a/base/memory/singleton_unittest.cc
+++ b/base/memory/singleton_unittest.cc
@@ -110,6 +110,19 @@ struct CallbackSingletonWithStaticTrait::Trait
}
};
+template <class Type>
+class AlignedTestSingleton {
+ public:
+ AlignedTestSingleton() {}
+ ~AlignedTestSingleton() {}
+ static AlignedTestSingleton* GetInstance() {
+ return Singleton<AlignedTestSingleton,
+ StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+ }
+
+ Type type_;
+};
+
void SingletonNoLeak(CallbackFunc CallOnQuit) {
CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
@@ -250,3 +263,27 @@ TEST_F(SingletonTest, Basic) {
// The leaky singleton shouldn't leak since SingletonLeak has not been called.
VerifiesCallbacksNotCalled();
}
+
+#define EXPECT_ALIGNED(ptr, align) \
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST_F(SingletonTest, Alignment) {
+ using base::AlignedMemory;
+
+ // Create some static singletons with increasing sizes and alignment
+ // requirements. By ordering this way, the linker will need to do some work to
+ // ensure proper alignment of the static data.
+ AlignedTestSingleton<int32>* align4 =
+ AlignedTestSingleton<int32>::GetInstance();
+ AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
+ AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
+ AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
+ AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
+ AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
+ AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
+
+ EXPECT_ALIGNED(align4, 4);
+ EXPECT_ALIGNED(align32, 32);
+ EXPECT_ALIGNED(align128, 128);
+ EXPECT_ALIGNED(align4096, 4096);
+}