This patch fixes std::allocator, and more specifically, all users of __libcpp_allocate and __libcpp_deallocate, to support over-aligned types. __libcpp_allocate/deallocate now take an alignment parameter, and when the specified alignment is greater than that supported by malloc/new, the aligned version of operator new is called (assuming it's available). When aligned new isn't available, the old behavior has been kept, and the alignment parameter is ignored. This patch depends on recent changes to __builtin_operator_new/delete which allow them to be used to call any regular new/delete operator. By using __builtin_operator_new/delete when possible, the new/delete erasure optimization is maintained. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@328180 91177308-0d34-0410-b5e6-96231b3b80d8
144 lines
4.0 KiB
C++
144 lines
4.0 KiB
C++
//===------------------------ memory_resource.cpp -------------------------===//
|
|
//
|
|
// 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.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "experimental/memory_resource"
|
|
|
|
#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
|
|
#include "atomic"
|
|
#elif !defined(_LIBCPP_HAS_NO_THREADS)
|
|
#include "mutex"
|
|
#endif
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
|
|
|
|
// memory_resource
|
|
|
|
//memory_resource::~memory_resource() {}
|
|
|
|
// new_delete_resource()
|
|
|
|
class _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
|
|
: public memory_resource
|
|
{
|
|
public:
|
|
~__new_delete_memory_resource_imp() = default;
|
|
|
|
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 bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
|
|
{ return &__other == this; }
|
|
};
|
|
|
|
// null_memory_resource()
|
|
|
|
class _LIBCPP_TYPE_VIS __null_memory_resource_imp
|
|
: public memory_resource
|
|
{
|
|
public:
|
|
~__null_memory_resource_imp() = default;
|
|
|
|
protected:
|
|
virtual void* do_allocate(size_t, size_t) {
|
|
__throw_bad_alloc();
|
|
}
|
|
virtual void do_deallocate(void *, size_t, size_t) {}
|
|
virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
|
|
{ return &__other == this; }
|
|
};
|
|
|
|
namespace {
|
|
|
|
union ResourceInitHelper {
|
|
struct {
|
|
__new_delete_memory_resource_imp new_delete_res;
|
|
__null_memory_resource_imp null_res;
|
|
} resources;
|
|
char dummy;
|
|
_LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
|
|
~ResourceInitHelper() {}
|
|
};
|
|
// When compiled in C++14 this initialization should be a constant expression.
|
|
// Only in C++11 is "init_priority" needed to ensure initialization order.
|
|
#if _LIBCPP_STD_VER > 11
|
|
_LIBCPP_SAFE_STATIC
|
|
#endif
|
|
ResourceInitHelper res_init __attribute__((init_priority (101)));
|
|
|
|
} // end namespace
|
|
|
|
|
|
memory_resource * new_delete_resource() _NOEXCEPT {
|
|
return &res_init.resources.new_delete_res;
|
|
}
|
|
|
|
memory_resource * null_memory_resource() _NOEXCEPT {
|
|
return &res_init.resources.null_res;
|
|
}
|
|
|
|
// default_memory_resource()
|
|
|
|
static memory_resource *
|
|
__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
|
|
{
|
|
#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
|
|
_LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
|
|
ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
|
|
if (set) {
|
|
new_res = new_res ? new_res : new_delete_resource();
|
|
// TODO: Can a weaker ordering be used?
|
|
return _VSTD::atomic_exchange_explicit(
|
|
&__res, new_res, memory_order::memory_order_acq_rel);
|
|
}
|
|
else {
|
|
return _VSTD::atomic_load_explicit(
|
|
&__res, memory_order::memory_order_acquire);
|
|
}
|
|
#elif !defined(_LIBCPP_HAS_NO_THREADS)
|
|
_LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
|
|
static mutex res_lock;
|
|
if (set) {
|
|
new_res = new_res ? new_res : new_delete_resource();
|
|
lock_guard<mutex> guard(res_lock);
|
|
memory_resource * old_res = res;
|
|
res = new_res;
|
|
return old_res;
|
|
} else {
|
|
lock_guard<mutex> guard(res_lock);
|
|
return res;
|
|
}
|
|
#else
|
|
_LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
|
|
if (set) {
|
|
new_res = new_res ? new_res : new_delete_resource();
|
|
memory_resource * old_res = res;
|
|
res = new_res;
|
|
return old_res;
|
|
} else {
|
|
return res;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
memory_resource * get_default_resource() _NOEXCEPT
|
|
{
|
|
return __default_memory_resource();
|
|
}
|
|
|
|
memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
|
|
{
|
|
return __default_memory_resource(true, __new_res);
|
|
}
|
|
|
|
_LIBCPP_END_NAMESPACE_LFTS_PMR
|