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() { ...@@ -184,7 +184,7 @@ void SingletonHolder<T>::destroyInstance() {
template <typename T> template <typename T>
SingletonHolder<T>::SingletonHolder( SingletonHolder<T>::SingletonHolder(
TypeDescriptor typeDesc, TypeDescriptor typeDesc,
SingletonVault& vault) SingletonVault& vault) noexcept
: SingletonHolderBase(typeDesc), vault_(vault) {} : SingletonHolderBase(typeDesc), vault_(vault) {}
template <typename T> template <typename T>
......
...@@ -279,7 +279,8 @@ struct SingletonVaultState { ...@@ -279,7 +279,8 @@ struct SingletonVaultState {
// SingletonHolders. // SingletonHolders.
class SingletonHolderBase { class SingletonHolderBase {
public: public:
explicit SingletonHolderBase(TypeDescriptor typeDesc) : type_(typeDesc) {} explicit SingletonHolderBase(TypeDescriptor typeDesc) noexcept
: type_(typeDesc) {}
virtual ~SingletonHolderBase() = default; virtual ~SingletonHolderBase() = default;
TypeDescriptor type() const { TypeDescriptor type() const {
...@@ -325,7 +326,7 @@ struct SingletonHolder : public SingletonHolderBase { ...@@ -325,7 +326,7 @@ struct SingletonHolder : public SingletonHolderBase {
template <typename Tag, typename VaultTag> template <typename Tag, typename VaultTag>
struct Impl; struct Impl;
SingletonHolder(TypeDescriptor type, SingletonVault& vault); SingletonHolder(TypeDescriptor type, SingletonVault& vault) noexcept;
enum class SingletonHolderState { enum class SingletonHolderState {
NotRegistered, NotRegistered,
...@@ -409,7 +410,8 @@ class SingletonVault { ...@@ -409,7 +410,8 @@ class SingletonVault {
static Type defaultVaultType(); 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. // Destructor is only called by unit tests to check destroyInstances.
~SingletonVault(); ~SingletonVault();
...@@ -726,7 +728,7 @@ class LeakySingleton { ...@@ -726,7 +728,7 @@ class LeakySingleton {
enum class State { NotRegistered, Dead, Living }; enum class State { NotRegistered, Dead, Living };
struct Entry { struct Entry {
Entry() {} Entry() noexcept {}
Entry(const Entry&) = delete; Entry(const Entry&) = delete;
Entry& operator=(const Entry&) = delete; Entry& operator=(const Entry&) = delete;
......
...@@ -30,7 +30,7 @@ SingletonThreadLocalBase::UniqueBase::UniqueBase( ...@@ -30,7 +30,7 @@ SingletonThreadLocalBase::UniqueBase::UniqueBase(
Ref tag, Ref tag,
Ref make, Ref make,
Ref tltag, Ref tltag,
Value& value) { Value& value) noexcept {
if (!value.init) { if (!value.init) {
value.init = true; value.init = true;
value.make = &make; value.make = &make;
......
...@@ -43,7 +43,7 @@ class SingletonThreadLocalBase { ...@@ -43,7 +43,7 @@ class SingletonThreadLocalBase {
}; };
template <typename T, typename Tag, typename Make, typename TLTag> 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( : UniqueBase(
typeid(T), typeid(T),
typeid(Tag), typeid(Tag),
...@@ -51,7 +51,7 @@ class SingletonThreadLocalBase { ...@@ -51,7 +51,7 @@ class SingletonThreadLocalBase {
typeid(TLTag), typeid(TLTag),
detail::createGlobal<Value, TypeTuple<T, Tag, UniqueBase>>()) {} 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 < ...@@ -98,7 +98,7 @@ template <
class SingletonThreadLocal : private detail::SingletonThreadLocalBase { class SingletonThreadLocal : private detail::SingletonThreadLocalBase {
private: private:
struct Unique final : UniqueBase { struct Unique final : UniqueBase {
Unique() : UniqueBase(detail::TypeTuple<T, Tag, Make, TLTag>{}) {} Unique() noexcept : UniqueBase(detail::TypeTuple<T, Tag, Make, TLTag>{}) {}
}; };
static Unique unique; static Unique unique;
......
...@@ -61,7 +61,7 @@ class StaticSingletonManagerWithRtti { ...@@ -61,7 +61,7 @@ class StaticSingletonManagerWithRtti {
// function, but typeid is not constexpr under msvc // function, but typeid is not constexpr under msvc
static Arg arg{{nullptr}, FOLLY_TYPE_INFO_OF(TypeTuple<T, Tag>), make<T>}; 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 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); return *static_cast<T*>(p);
} }
...@@ -80,6 +80,11 @@ class StaticSingletonManagerWithRtti { ...@@ -80,6 +80,11 @@ class StaticSingletonManagerWithRtti {
return new T(); 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); FOLLY_NOINLINE static void* create_(Arg& arg);
}; };
......
...@@ -21,10 +21,34 @@ ...@@ -21,10 +21,34 @@
namespace folly { namespace folly {
namespace detail { 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() { extern "C" int* check() {
return &createGlobal<int, void>(); 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 {}; struct StaticSingletonManagerTest : public testing::Test {};
template <typename T> 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