Files
android_external_libcxx/src/experimental/memory_resource.cpp
Eric Fiselier a831287399 Fix PR22634 - std::allocator doesn't respect over-aligned types.
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
2018-03-22 04:42:56 +00:00

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