Commit c17964fd authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Omit excess landing pads with StaticSingletonManager

Summary:
[Folly] Omit excess landing pads with `StaticSingletonManager` when the type of the global is nothrow-default-constructible.

This changes behavior for nothrow-default-constructible types to terminate immediately if the process is out of memory while performing the bookkeeping around attempting to instantiate a global.

Reviewed By: andriigrynenko

Differential Revision: D14203826

fbshipit-source-id: 8c9becde3b245d6b027c97bd8541c48745727dff
parent 83b597e5
......@@ -184,7 +184,7 @@ void SingletonHolder<T>::destroyInstance() {
template <typename T>
SingletonHolder<T>::SingletonHolder(
TypeDescriptor typeDesc,
SingletonVault& vault)
SingletonVault& vault) noexcept
: SingletonHolderBase(typeDesc), vault_(vault) {}
template <typename T>
......
......@@ -279,7 +279,8 @@ struct SingletonVaultState {
// SingletonHolders.
class SingletonHolderBase {
public:
explicit SingletonHolderBase(TypeDescriptor typeDesc) : type_(typeDesc) {}
explicit SingletonHolderBase(TypeDescriptor typeDesc) noexcept
: type_(typeDesc) {}
virtual ~SingletonHolderBase() = default;
TypeDescriptor type() const {
......@@ -325,7 +326,7 @@ struct SingletonHolder : public SingletonHolderBase {
template <typename Tag, typename VaultTag>
struct Impl;
SingletonHolder(TypeDescriptor type, SingletonVault& vault);
SingletonHolder(TypeDescriptor type, SingletonVault& vault) noexcept;
enum class SingletonHolderState {
NotRegistered,
......@@ -409,7 +410,8 @@ class SingletonVault {
static Type defaultVaultType();
explicit SingletonVault(Type type = defaultVaultType()) : type_(type) {}
explicit SingletonVault(Type type = defaultVaultType()) noexcept
: type_(type) {}
// Destructor is only called by unit tests to check destroyInstances.
~SingletonVault();
......@@ -726,7 +728,7 @@ class LeakySingleton {
enum class State { NotRegistered, Dead, Living };
struct Entry {
Entry() {}
Entry() noexcept {}
Entry(const Entry&) = delete;
Entry& operator=(const Entry&) = delete;
......
......@@ -30,7 +30,7 @@ SingletonThreadLocalBase::UniqueBase::UniqueBase(
Ref tag,
Ref make,
Ref tltag,
Value& value) {
Value& value) noexcept {
if (!value.init) {
value.init = true;
value.make = &make;
......
......@@ -43,7 +43,7 @@ class SingletonThreadLocalBase {
};
template <typename T, typename Tag, typename Make, typename TLTag>
explicit UniqueBase(TypeTuple<T, Tag, Make, TLTag>)
explicit UniqueBase(TypeTuple<T, Tag, Make, TLTag>) noexcept
: UniqueBase(
typeid(T),
typeid(Tag),
......@@ -51,7 +51,7 @@ class SingletonThreadLocalBase {
typeid(TLTag),
detail::createGlobal<Value, TypeTuple<T, Tag, UniqueBase>>()) {}
UniqueBase(Ref type, Ref tag, Ref make, Ref tltag, Value& value);
UniqueBase(Ref type, Ref tag, Ref make, Ref tltag, Value& value) noexcept;
};
};
......@@ -98,7 +98,7 @@ template <
class SingletonThreadLocal : private detail::SingletonThreadLocalBase {
private:
struct Unique final : UniqueBase {
Unique() : UniqueBase(detail::TypeTuple<T, Tag, Make, TLTag>{}) {}
Unique() noexcept : UniqueBase(detail::TypeTuple<T, Tag, Make, TLTag>{}) {}
};
static Unique unique;
......
......@@ -61,7 +61,7 @@ class StaticSingletonManagerWithRtti {
// function, but typeid is not constexpr under msvc
static Arg arg{{nullptr}, FOLLY_TYPE_INFO_OF(TypeTuple<T, Tag>), make<T>};
auto const v = arg.cache.load(std::memory_order_acquire);
auto const p = FOLLY_LIKELY(!!v) ? v : create_(arg);
auto const p = FOLLY_LIKELY(!!v) ? v : create_<noexcept(T())>(arg);
return *static_cast<T*>(p);
}
......@@ -80,6 +80,11 @@ class StaticSingletonManagerWithRtti {
return new T();
}
template <bool Noexcept>
FOLLY_ATTR_VISIBILITY_HIDDEN FOLLY_ALWAYS_INLINE static void* create_(
Arg& arg) noexcept(Noexcept) {
return create_(arg);
}
FOLLY_NOINLINE static void* create_(Arg& arg);
};
......
......@@ -21,10 +21,34 @@
namespace folly {
namespace detail {
FOLLY_ATTR_WEAK void check_doit() {}
namespace {
template <bool Noexcept>
struct MayThrow {
FOLLY_NOINLINE MayThrow() noexcept(Noexcept) {
check_doit();
}
FOLLY_NOINLINE ~MayThrow() {
check_doit();
}
};
} // namespace
extern "C" int* check() {
return &createGlobal<int, void>();
}
extern "C" void* check_throw() {
MayThrow<false> obj;
return &createGlobal<MayThrow<false>, void>();
}
extern "C" void* check_nothrow() {
MayThrow<false> obj;
return &createGlobal<MayThrow<true>, void>();
}
struct StaticSingletonManagerTest : public testing::Test {};
template <typename T>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment