Use C++11 alignment primitives
Removes the compiler-specific base #define ALIGNOF and replace uses with alignof.
Replaces some uses of ALIGNAS with alignas. These are not all replaced,
and a note is added to the definition about the problems with alignas.
This came from https://codereview.chromium.org/2670873002/
Remove base::AlignedMemory and replace with alignas(type) char[size].
std::aligned_storage has some limitations. The style guide is updated to note these and mark it disallowed. It is also updated for alignas and alignof.
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel
Review-Url: https://codereview.chromium.org/2932053002
Cr-Commit-Position: refs/heads/master@{#479169}
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
index d8290115..e302f45 100644
--- a/base/memory/aligned_memory.h
+++ b/base/memory/aligned_memory.h
@@ -2,24 +2,9 @@
// 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();
-//
-// Alternatively, a runtime sized aligned allocation can be created:
+#include <type_traits>
+
+// A runtime sized aligned allocation can be created:
//
// float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
//
@@ -48,52 +33,7 @@
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_t data_[Size]; \
- void* void_data() { return static_cast<void*>(data_); } \
- const void* void_data() const { return static_cast<const void*>(data_); } \
- template <typename Type> \
- Type* data_as() { \
- return static_cast<Type*>(void_data()); \
- } \
- template <typename Type> \
- const Type* data_as() const { \
- return static_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);
-
-#undef BASE_DECL_ALIGNED_MEMORY
-
+// This can be replaced with std::aligned_malloc when we have C++17.
BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
inline void AlignedFree(void* ptr) {
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
index 892c50e..e354f38 100644
--- a/base/memory/aligned_memory_unittest.cc
+++ b/base/memory/aligned_memory_unittest.cc
@@ -12,84 +12,35 @@
#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, 128> raw128;
-
- EXPECT_EQ(8u, ALIGNOF(raw8));
- EXPECT_EQ(16u, ALIGNOF(raw16));
- EXPECT_EQ(128u, ALIGNOF(raw128));
-
- EXPECT_ALIGNED(raw8.void_data(), 8);
- EXPECT_ALIGNED(raw16.void_data(), 16);
- EXPECT_ALIGNED(raw128.void_data(), 128);
-
- // NaCl x86-64 compiler emits non-validating instructions for >128
- // bytes alignment.
- // http://www.chromium.org/nativeclient/design-documents/nacl-sfi-model-on-x86-64-systems
- // TODO(hamaji): Ideally, NaCl compiler for x86-64 should workaround
- // this limitation and this #if should be removed.
- // https://code.google.com/p/nativeclient/issues/detail?id=3463
-#if !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
- AlignedMemory<8, 256> raw256;
- EXPECT_EQ(256u, ALIGNOF(raw256));
- EXPECT_ALIGNED(raw256.void_data(), 256);
-
- AlignedMemory<8, 4096> raw4096;
- EXPECT_EQ(4096u, ALIGNOF(raw4096));
- EXPECT_ALIGNED(raw4096.void_data(), 4096);
-#endif // !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
-}
+namespace base {
TEST(AlignedMemoryTest, DynamicAllocation) {
- void* p = base::AlignedAlloc(8, 8);
+ void* p = AlignedAlloc(8, 8);
EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 8);
- base::AlignedFree(p);
+ AlignedFree(p);
- p = base::AlignedAlloc(8, 16);
+ p = AlignedAlloc(8, 16);
EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 16);
- base::AlignedFree(p);
+ AlignedFree(p);
- p = base::AlignedAlloc(8, 256);
+ p = AlignedAlloc(8, 256);
EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 256);
- base::AlignedFree(p);
+ AlignedFree(p);
- p = base::AlignedAlloc(8, 4096);
+ p = AlignedAlloc(8, 4096);
EXPECT_TRUE(p);
EXPECT_ALIGNED(p, 4096);
- base::AlignedFree(p);
+ AlignedFree(p);
}
TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
- std::unique_ptr<float, base::AlignedFreeDeleter> p(
- static_cast<float*>(base::AlignedAlloc(8, 8)));
+ std::unique_ptr<float, AlignedFreeDeleter> p(
+ static_cast<float*>(AlignedAlloc(8, 8)));
EXPECT_TRUE(p.get());
EXPECT_ALIGNED(p.get(), 8);
}
-} // namespace
+} // namespace base
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
index f401f62d..e968d04 100644
--- a/base/memory/manual_constructor.h
+++ b/base/memory/manual_constructor.h
@@ -34,17 +34,15 @@
// Support users creating arrays of ManualConstructor<>s. This ensures that
// the array itself has the correct alignment.
static void* operator new[](size_t size) {
- return AlignedAlloc(size, ALIGNOF(Type));
+ return AlignedAlloc(size, alignof(Type));
}
static void operator delete[](void* mem) {
AlignedFree(mem);
}
- inline Type* get() {
- return space_.template data_as<Type>();
- }
+ inline Type* get() { return reinterpret_cast<Type*>(space_); }
inline const Type* get() const {
- return space_.template data_as<Type>();
+ return reinterpret_cast<const Type*>(space_);
}
inline Type* operator->() { return get(); }
@@ -55,7 +53,7 @@
template <typename... Ts>
inline void Init(Ts&&... params) {
- new(space_.void_data()) Type(std::forward<Ts>(params)...);
+ new (space_) Type(std::forward<Ts>(params)...);
}
inline void InitFromMove(ManualConstructor<Type>&& o) {
@@ -67,7 +65,7 @@
}
private:
- AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
+ alignas(Type) char space_[sizeof(Type)];
};
} // namespace base
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index 5c58d5fe..d604910 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -24,7 +24,6 @@
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/memory/aligned_memory.h"
#include "base/threading/thread_restrictions.h"
namespace base {
@@ -115,7 +114,7 @@
if (subtle::NoBarrier_AtomicExchange(&dead_, 1))
return NULL;
- return new(buffer_.void_data()) Type();
+ return new (buffer_) Type();
}
static void Delete(Type* p) {
@@ -130,14 +129,13 @@
static void Resurrect() { subtle::NoBarrier_Store(&dead_, 0); }
private:
- static AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+ alignas(Type) static char buffer_[sizeof(Type)];
// Signal the object was already deleted, so it is not revived.
static subtle::Atomic32 dead_;
};
template <typename Type>
-AlignedMemory<sizeof(Type), ALIGNOF(Type)>
- StaticMemorySingletonTraits<Type>::buffer_;
+alignas(Type) char StaticMemorySingletonTraits<Type>::buffer_[sizeof(Type)];
template <typename Type>
subtle::Atomic32 StaticMemorySingletonTraits<Type>::dead_ = 0;
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
index a15145c..e129215 100644
--- a/base/memory/singleton_unittest.cc
+++ b/base/memory/singleton_unittest.cc
@@ -16,6 +16,14 @@
typedef void (*CallbackFunc)();
+template <size_t alignment>
+class AlignedData {
+ public:
+ AlignedData() {}
+ ~AlignedData() {}
+ alignas(alignment) char data_[alignment];
+};
+
class IntSingleton {
public:
static IntSingleton* GetInstance() {
@@ -269,19 +277,17 @@
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_t>* align4 =
AlignedTestSingleton<int32_t>::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();
+ AlignedTestSingleton<AlignedData<32>>* align32 =
+ AlignedTestSingleton<AlignedData<32>>::GetInstance();
+ AlignedTestSingleton<AlignedData<128>>* align128 =
+ AlignedTestSingleton<AlignedData<128>>::GetInstance();
+ AlignedTestSingleton<AlignedData<4096>>* align4096 =
+ AlignedTestSingleton<AlignedData<4096>>::GetInstance();
EXPECT_ALIGNED(align4, 4);
EXPECT_ALIGNED(align32, 32);