[libcxx] r345281 - Implement sized deallocation for std::allocator and friends.

Eric Fiselier eric at efcs.ca
Thu Oct 25 10:21:30 PDT 2018


Author: ericwf
Date: Thu Oct 25 10:21:30 2018
New Revision: 345281

URL: http://llvm.org/viewvc/llvm-project?rev=345281&view=rev
Log:
Implement sized deallocation for std::allocator and friends.

Summary:
C++14 sized deallocation is disabled by default due to ABI concerns. However, when a user manually enables it then libc++ should take advantage of it since sized deallocation can provide a significant performance win depending on the underlying malloc implementation. (Note that libc++'s definitions of sized delete don't do anything special yet, but users are free to provide their own).

This patch updates __libcpp_deallocate to selectively call sized operator delete when it's available. `__libcpp_deallocate_unsized` should be used when the size of the allocation is unknown.

On Apple this patch makes no attempt to determine if the sized operator delete is unavailable, only that the language feature is enabled. This could cause a compile error when using `std::allocator`, but the same compile error would occur whenever the user calls `new`, so I don't think it's a problem.

Reviewers: ldionne, mclow.lists

Reviewed By: ldionne

Subscribers: rsmith, ckennelly, libcxx-commits, christof

Differential Revision: https://reviews.llvm.org/D53120

Added:
    libcxx/trunk/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
Modified:
    libcxx/trunk/include/__sso_allocator
    libcxx/trunk/include/experimental/dynarray
    libcxx/trunk/include/memory
    libcxx/trunk/include/new
    libcxx/trunk/include/valarray
    libcxx/trunk/src/experimental/memory_resource.cpp

Modified: libcxx/trunk/include/__sso_allocator
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__sso_allocator?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/include/__sso_allocator (original)
+++ libcxx/trunk/include/__sso_allocator Thu Oct 25 10:21:30 2018
@@ -57,12 +57,12 @@ public:
         }
         return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
     }
-    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type)
+    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n)
     {
         if (__p == (pointer)&buf_)
             __allocated_ = false;
         else
-            _VSTD::__libcpp_deallocate(__p, __alignof(_Tp));
+            _VSTD::__libcpp_deallocate(__p, __n * sizeof(_Tp), __alignof(_Tp));
     }
     _LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);}
 

Modified: libcxx/trunk/include/experimental/dynarray
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/experimental/dynarray?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/include/experimental/dynarray (original)
+++ libcxx/trunk/include/experimental/dynarray Thu Oct 25 10:21:30 2018
@@ -145,8 +145,8 @@ private:
     }
 
     static inline _LIBCPP_INLINE_VISIBILITY
-    void __deallocate_value(value_type* __ptr ) noexcept {
-        _VSTD::__libcpp_deallocate(static_cast<void *>(__ptr), __alignof(value_type));
+    void __deallocate_value(value_type* __ptr, size_t __count) noexcept {
+        _VSTD::__libcpp_deallocate(static_cast<void *>(__ptr), sizeof(value_type) * __count, __alignof(value_type));
     }
 
 public:
@@ -266,7 +266,7 @@ dynarray<_Tp>::~dynarray()
     value_type *__data = data () + __size_;
     for ( size_t i = 0; i < __size_; ++i )
         (--__data)->value_type::~value_type();
-    __deallocate_value( __base_ );
+    __deallocate_value(__base_, __size_);
 }
 
 template <class _Tp>

Modified: libcxx/trunk/include/memory
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/memory?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/include/memory (original)
+++ libcxx/trunk/include/memory Thu Oct 25 10:21:30 2018
@@ -1799,8 +1799,8 @@ public:
                                  " 'n' exceeds maximum supported size");
         return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
         }
-    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
-        {_VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));}
+    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT
+        {_VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), __alignof(_Tp));}
     _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
         {return size_type(~0) / sizeof(_Tp);}
 #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -1900,8 +1900,8 @@ public:
                                  " 'n' exceeds maximum supported size");
         return static_cast<pointer>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), __alignof(_Tp)));
     }
-    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type) _NOEXCEPT
-        {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __alignof(_Tp));}
+    _LIBCPP_INLINE_VISIBILITY void deallocate(pointer __p, size_type __n) _NOEXCEPT
+        {_VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), __alignof(_Tp));}
     _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT
         {return size_type(~0) / sizeof(_Tp);}
 #if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_VARIADICS)
@@ -2052,7 +2052,7 @@ template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 void return_temporary_buffer(_Tp* __p) _NOEXCEPT
 {
-  _VSTD::__libcpp_deallocate((void*)__p, __alignof(_Tp));
+  _VSTD::__libcpp_deallocate_unsized((void*)__p, __alignof(_Tp));
 }
 
 #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR)

Modified: libcxx/trunk/include/new
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/new?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/include/new (original)
+++ libcxx/trunk/include/new Thu Oct 25 10:21:30 2018
@@ -104,12 +104,17 @@ void  operator delete[](void* ptr, void*
 #pragma GCC system_header
 #endif
 
-#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14
+#if !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation  < 201309L
+#define _LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION
+#endif
+
+#if !defined(_LIBCPP_BUILDING_LIBRARY) && _LIBCPP_STD_VER < 14 && \
+    defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION)
 # define _LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION
 #endif
 
 #if defined(_LIBCPP_HAS_NO_LIBRARY_SIZED_DEALLOCATION) || \
-    !defined(__cpp_sized_deallocation) || __cpp_sized_deallocation < 201309
+    defined(_LIBCPP_HAS_NO_LANGUAGE_SIZED_DEALLOCATION)
 # define _LIBCPP_HAS_NO_SIZED_DEALLOCATION
 #endif
 
@@ -255,24 +260,94 @@ inline _LIBCPP_INLINE_VISIBILITY void *_
 #endif
 }
 
-inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __align) {
+struct _DeallocateCaller {
+  static inline _LIBCPP_INLINE_VISIBILITY
+  void __do_deallocate_handle_size_align(void *__ptr, size_t __size, size_t __align) {
+#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
+    ((void)__align);
+    return __do_deallocate_handle_size(__ptr, __size);
+#else
+    if (__is_overaligned_for_new(__align)) {
+      const align_val_t __align_val = static_cast<align_val_t>(__align);
+      return __do_deallocate_handle_size(__ptr, __size, __align_val);
+    } else {
+      return __do_deallocate_handle_size(__ptr, __size);
+    }
+#endif
+  }
+
+  static inline _LIBCPP_INLINE_VISIBILITY
+  void __do_deallocate_handle_align(void *__ptr, size_t __align) {
+#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION)
+    ((void)__align);
+    return __do_call(__ptr);
+#else
+    if (__is_overaligned_for_new(__align)) {
+      const align_val_t __align_val = static_cast<align_val_t>(__align);
+      return __do_call(__ptr, __align_val);
+    } else {
+      return __do_call(__ptr);
+    }
+#endif
+  }
+
+ private:
+  static inline void __do_deallocate_handle_size(void *__ptr, size_t __size) {
+#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
+    ((void)__size);
+    return __do_call(__ptr);
+#else
+    return __do_call(__ptr, __size);
+#endif
+  }
+
 #ifndef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
-  if (__is_overaligned_for_new(__align)) {
-    const align_val_t __align_val = static_cast<align_val_t>(__align);
-# ifdef _LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE
-    return ::operator delete(__ptr, __align_val);
-# else
-    return __builtin_operator_delete(__ptr, __align_val);
-# endif
+  static inline void __do_deallocate_handle_size(void *__ptr, size_t __size, align_val_t __align) {
+#ifdef _LIBCPP_HAS_NO_SIZED_DEALLOCATION
+    ((void)__size);
+    return __do_call(__ptr, __align);
+#else
+    return __do_call(__ptr, __size, __align);
+#endif
   }
+#endif
+
+private:
+  template <class _A1, class _A2>
+  static inline void __do_call(void *__ptr, _A1 __a1, _A2 __a2) {
+#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
+    defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
+    return ::operator delete(__ptr, __a1, __a2);
 #else
-  ((void)__align);
+    return __builtin_operator_delete(__ptr, __a1, __a2);
+#endif
+  }
+
+  template <class _A1>
+  static inline void __do_call(void *__ptr, _A1 __a1) {
+#if defined(_LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE) || \
+    defined(_LIBCPP_HAS_NO_BUILTIN_OVERLOADED_OPERATOR_NEW_DELETE)
+    return ::operator delete(__ptr, __a1);
+#else
+    return __builtin_operator_delete(__ptr, __a1);
 #endif
+  }
+
+  static inline void __do_call(void *__ptr) {
 #ifdef _LIBCPP_HAS_NO_BUILTIN_OPERATOR_NEW_DELETE
-  return ::operator delete(__ptr);
+    return ::operator delete(__ptr);
 #else
-  return __builtin_operator_delete(__ptr);
+    return __builtin_operator_delete(__ptr);
 #endif
+  }
+};
+
+inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate(void* __ptr, size_t __size, size_t __align) {
+  _DeallocateCaller::__do_deallocate_handle_size_align(__ptr, __size, __align);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate_unsized(void* __ptr, size_t __align) {
+  _DeallocateCaller::__do_deallocate_handle_align(__ptr, __align);
 }
 
 #ifdef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED

Modified: libcxx/trunk/include/valarray
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/valarray?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/include/valarray (original)
+++ libcxx/trunk/include/valarray Thu Oct 25 10:21:30 2018
@@ -1054,7 +1054,7 @@ private:
     const _Up*
     end(const valarray<_Up>& __v);
 
-    void __clear();
+    void __clear(size_t __capacity);
     valarray& __assign_range(const value_type* __f, const value_type* __l);
 };
 
@@ -2762,13 +2762,13 @@ valarray<_Tp>::valarray(size_t __n)
         try
         {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-            for (; __n; --__n, ++__end_)
+            for (size_t __n_left = __n; __n_left; --__n_left, ++__end_)
                 ::new (__end_) value_type();
 #ifndef _LIBCPP_NO_EXCEPTIONS
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2797,13 +2797,13 @@ valarray<_Tp>::valarray(const value_type
         try
         {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-            for (; __n; ++__end_, ++__p, --__n)
+            for (size_t __n_left = __n; __n_left; ++__end_, ++__p, --__n_left)
                 ::new (__end_) value_type(*__p);
 #ifndef _LIBCPP_NO_EXCEPTIONS
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2829,7 +2829,7 @@ valarray<_Tp>::valarray(const valarray&
         }
         catch (...)
         {
-            __clear();
+            __clear(__v.size());
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2852,7 +2852,7 @@ valarray<_Tp>::valarray(initializer_list
     : __begin_(0),
       __end_(0)
 {
-    size_t __n = __il.size();
+    const size_t __n = __il.size();
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -2861,13 +2861,14 @@ _VSTD::__libcpp_allocate(__n * sizeof(va
         try
         {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-            for (const value_type* __p = __il.begin(); __n; ++__end_, ++__p, --__n)
+            size_t __n_left = __n;
+            for (const value_type* __p = __il.begin(); __n_left; ++__end_, ++__p, --__n_left)
                 ::new (__end_) value_type(*__p);
 #ifndef _LIBCPP_NO_EXCEPTIONS
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2881,7 +2882,7 @@ valarray<_Tp>::valarray(const slice_arra
     : __begin_(0),
       __end_(0)
 {
-    size_t __n = __sa.__size_;
+    const size_t __n = __sa.__size_;
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -2890,13 +2891,14 @@ valarray<_Tp>::valarray(const slice_arra
         try
         {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-            for (const value_type* __p = __sa.__vp_; __n; ++__end_, __p += __sa.__stride_, --__n)
+            size_t __n_left = __n;
+            for (const value_type* __p = __sa.__vp_; __n_left; ++__end_, __p += __sa.__stride_, --__n_left)
                 ::new (__end_) value_type(*__p);
 #ifndef _LIBCPP_NO_EXCEPTIONS
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2908,7 +2910,7 @@ valarray<_Tp>::valarray(const gslice_arr
     : __begin_(0),
       __end_(0)
 {
-    size_t __n = __ga.__1d_.size();
+    const size_t __n = __ga.__1d_.size();
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -2926,7 +2928,7 @@ valarray<_Tp>::valarray(const gslice_arr
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2938,7 +2940,7 @@ valarray<_Tp>::valarray(const mask_array
     : __begin_(0),
       __end_(0)
 {
-    size_t __n = __ma.__1d_.size();
+    const size_t __n = __ma.__1d_.size();
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -2956,7 +2958,7 @@ valarray<_Tp>::valarray(const mask_array
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2968,7 +2970,7 @@ valarray<_Tp>::valarray(const indirect_a
     : __begin_(0),
       __end_(0)
 {
-    size_t __n = __ia.__1d_.size();
+    const size_t __n = __ia.__1d_.size();
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -2986,7 +2988,7 @@ valarray<_Tp>::valarray(const indirect_a
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS
@@ -2997,7 +2999,7 @@ template <class _Tp>
 inline
 valarray<_Tp>::~valarray()
 {
-    __clear();
+    __clear(size());
 }
 
 template <class _Tp>
@@ -3007,7 +3009,7 @@ valarray<_Tp>::__assign_range(const valu
     size_t __n = __l - __f;
     if (size() != __n)
     {
-        __clear();
+        __clear(size());
         __begin_ = static_cast<value_type*>(
            _VSTD::__libcpp_allocate(__n * sizeof(value_type), __alignof(value_type)));
         __end_ = __begin_ + __n;
@@ -3034,7 +3036,7 @@ inline
 valarray<_Tp>&
 valarray<_Tp>::operator=(valarray&& __v) _NOEXCEPT
 {
-    __clear();
+    __clear(size());
     __begin_ = __v.__begin_;
     __end_ = __v.__end_;
     __v.__begin_ = nullptr;
@@ -3726,23 +3728,23 @@ valarray<_Tp>::apply(value_type __f(cons
 }
 
 template <class _Tp>
-void
-valarray<_Tp>::__clear()
+inline _LIBCPP_INLINE_VISIBILITY
+void valarray<_Tp>::__clear(size_t __capacity)
 {
-    if (__begin_ != nullptr)
-    {
-        while (__end_ != __begin_)
-            (--__end_)->~value_type();
-        _VSTD::__libcpp_deallocate(__begin_, __alignof(value_type));
-        __begin_ = __end_ = nullptr;
-    }
+  if (__begin_ != nullptr)
+  {
+    while (__end_ != __begin_)
+      (--__end_)->~value_type();
+    _VSTD::__libcpp_deallocate(__begin_, __capacity * sizeof(value_type), __alignof(value_type));
+    __begin_ = __end_ = nullptr;
+  }
 }
 
 template <class _Tp>
 void
 valarray<_Tp>::resize(size_t __n, value_type __x)
 {
-    __clear();
+    __clear(size());
     if (__n)
     {
         __begin_ = __end_ = static_cast<value_type*>(
@@ -3751,13 +3753,13 @@ valarray<_Tp>::resize(size_t __n, value_
         try
         {
 #endif  // _LIBCPP_NO_EXCEPTIONS
-            for (; __n; --__n, ++__end_)
+            for (size_t __n_left = __n; __n_left; --__n_left, ++__end_)
                 ::new (__end_) value_type(__x);
 #ifndef _LIBCPP_NO_EXCEPTIONS
         }
         catch (...)
         {
-            __clear();
+            __clear(__n);
             throw;
         }
 #endif  // _LIBCPP_NO_EXCEPTIONS

Modified: libcxx/trunk/src/experimental/memory_resource.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/experimental/memory_resource.cpp?rev=345281&r1=345280&r2=345281&view=diff
==============================================================================
--- libcxx/trunk/src/experimental/memory_resource.cpp (original)
+++ libcxx/trunk/src/experimental/memory_resource.cpp Thu Oct 25 10:21:30 2018
@@ -33,8 +33,9 @@ protected:
     virtual void* do_allocate(size_t __size, size_t __align)
         { return _VSTD::__libcpp_allocate(__size, __align); /* FIXME */}
 
-    virtual void do_deallocate(void * __p, size_t, size_t __align)
-        { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ }
+    virtual void do_deallocate(void* __p, size_t __n, size_t __align) {
+      _VSTD::__libcpp_deallocate(__p, __n, __align); /* FIXME */
+    }
 
     virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
         { return &__other == this; }

Added: libcxx/trunk/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp?rev=345281&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp (added)
+++ libcxx/trunk/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp Thu Oct 25 10:21:30 2018
@@ -0,0 +1,246 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// test libc++'s implementation of align_val_t, and the relevent new/delete
+// overloads in all dialects when -faligned-allocation is present.
+
+// Libc++ defers to the underlying MSVC library to provide the new/delete
+// definitions, which does not yet provide aligned allocation
+// XFAIL: LIBCXX-WINDOWS-FIXME
+
+// XFAIL: with_system_cxx_lib=macosx10.12
+// XFAIL: with_system_cxx_lib=macosx10.11
+// XFAIL: with_system_cxx_lib=macosx10.10
+// XFAIL: with_system_cxx_lib=macosx10.9
+// XFAIL: with_system_cxx_lib=macosx10.7
+// XFAIL: with_system_cxx_lib=macosx10.8
+
+// XFAIL: sanitizer-new-delete, ubsan
+
+// RUN: %build -faligned-allocation -fsized-deallocation
+// RUN: %run
+// RUN: %build -faligned-allocation -fno-sized-deallocation -DNO_SIZE
+// RUN: %run
+// RUN: %build -fno-aligned-allocation -fsized-deallocation -DNO_ALIGN
+// RUN: %run
+// RUN: %build -fno-aligned-allocation -fno-sized-deallocation -DNO_ALIGN -DNO_SIZE
+// RUN: %run
+
+#include <new>
+#include <typeinfo>
+#include <string>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct alloc_stats {
+  alloc_stats() { reset(); }
+
+  int aligned_sized_called;
+  int aligned_called;
+  int sized_called;
+  int plain_called;
+  int last_size;
+  int last_align;
+
+  void reset() {
+    aligned_sized_called = aligned_called = sized_called = plain_called = 0;
+    last_align = last_size = -1;
+  }
+
+  bool expect_plain() const {
+    assert(aligned_sized_called == 0);
+    assert(aligned_called == 0);
+    assert(sized_called == 0);
+    assert(last_size == -1);
+    assert(last_align == -1);
+    return plain_called == 1;
+  }
+
+  bool expect_size(int n) const {
+    assert(plain_called == 0);
+    assert(aligned_sized_called == 0);
+    assert(aligned_called == 0);
+    assert(last_size == n);
+    assert(last_align == -1);
+    return sized_called == 1;
+  }
+
+  bool expect_align(int a) const {
+    assert(plain_called == 0);
+    assert(aligned_sized_called == 0);
+    assert(sized_called == 0);
+    assert(last_size == -1);
+    assert(last_align == a);
+    return aligned_called == 1;
+  }
+
+  bool expect_size_align(int n, int a) const {
+    assert(plain_called == 0);
+    assert(sized_called == 0);
+    assert(aligned_called == 0);
+    assert(last_size == n);
+    assert(last_align == a);
+    return aligned_sized_called == 1;
+  }
+};
+alloc_stats stats;
+
+void operator delete(void* p)TEST_NOEXCEPT {
+  ::free(p);
+  stats.plain_called++;
+  stats.last_size = stats.last_align = -1;
+}
+
+#ifndef NO_SIZE
+void operator delete(void* p, size_t n)TEST_NOEXCEPT {
+  ::free(p);
+  stats.sized_called++;
+  stats.last_size = n;
+  stats.last_align = -1;
+}
+#endif
+
+#ifndef NO_ALIGN
+void operator delete(void* p, std::align_val_t a)TEST_NOEXCEPT {
+  ::free(p);
+  stats.aligned_called++;
+  stats.last_align = static_cast<int>(a);
+  stats.last_size = -1;
+}
+
+void operator delete(void* p, size_t n, std::align_val_t a)TEST_NOEXCEPT {
+  ::free(p);
+  stats.aligned_sized_called++;
+  stats.last_align = static_cast<int>(a);
+  stats.last_size = n;
+}
+#endif
+
+void test_libcpp_dealloc() {
+  void* p = nullptr;
+  size_t over_align_val = TEST_ALIGNOF(std::max_align_t) * 2;
+  size_t under_align_val = TEST_ALIGNOF(int);
+  size_t with_size_val = 2;
+
+  {
+    std::__libcpp_deallocate_unsized(p, under_align_val);
+    assert(stats.expect_plain());
+  }
+  stats.reset();
+
+#if defined(NO_SIZE) && defined(NO_ALIGN)
+  {
+    std::__libcpp_deallocate(p, with_size_val, over_align_val);
+    assert(stats.expect_plain());
+  }
+  stats.reset();
+#elif defined(NO_SIZE)
+  {
+    std::__libcpp_deallocate(p, with_size_val, over_align_val);
+    assert(stats.expect_align(over_align_val));
+  }
+  stats.reset();
+#elif defined(NO_ALIGN)
+  {
+    std::__libcpp_deallocate(p, with_size_val, over_align_val);
+    assert(stats.expect_size(with_size_val));
+  }
+  stats.reset();
+#else
+  {
+    std::__libcpp_deallocate(p, with_size_val, over_align_val);
+    assert(stats.expect_size_align(with_size_val, over_align_val));
+  }
+  stats.reset();
+  {
+    std::__libcpp_deallocate_unsized(p, over_align_val);
+    assert(stats.expect_align(over_align_val));
+  }
+  stats.reset();
+  {
+    std::__libcpp_deallocate(p, with_size_val, under_align_val);
+    assert(stats.expect_size(with_size_val));
+  }
+  stats.reset();
+#endif
+}
+
+struct TEST_ALIGNAS(128) AlignedType {
+  AlignedType() : elem(0) {}
+  TEST_ALIGNAS(128) char elem;
+};
+
+void test_allocator_and_new_match() {
+  stats.reset();
+#if defined(NO_SIZE) && defined(NO_ALIGN)
+  {
+    int* x = new int(42);
+    delete x;
+    assert(stats.expect_plain());
+  }
+  stats.reset();
+  {
+    AlignedType* a = new AlignedType();
+    delete a;
+    assert(stats.expect_plain());
+  }
+  stats.reset();
+#elif defined(NO_SIZE)
+  stats.reset();
+#if TEST_STD_VER >= 11
+  {
+    int* x = new int(42);
+    delete x;
+    assert(stats.expect_plain());
+  }
+#endif
+  stats.reset();
+  {
+    AlignedType* a = new AlignedType();
+    delete a;
+    assert(stats.expect_align(TEST_ALIGNOF(AlignedType)));
+  }
+  stats.reset();
+#elif defined(NO_ALIGN)
+  stats.reset();
+  {
+    int* x = new int(42);
+    delete x;
+    assert(stats.expect_size(sizeof(int)));
+  }
+  stats.reset();
+  {
+    AlignedType* a = new AlignedType();
+    delete a;
+    assert(stats.expect_size(sizeof(AlignedType)));
+  }
+  stats.reset();
+#else
+  stats.reset();
+  {
+    int* x = new int(42);
+    delete x;
+    assert(stats.expect_size(sizeof(int)));
+  }
+  stats.reset();
+  {
+    AlignedType* a = new AlignedType();
+    delete a;
+    assert(stats.expect_size_align(sizeof(AlignedType),
+                                   TEST_ALIGNOF(AlignedType)));
+  }
+  stats.reset();
+#endif
+}
+
+int main() {
+  test_libcpp_dealloc();
+  test_allocator_and_new_match();
+}




More information about the libcxx-commits mailing list