From da59334c5ea01cca7bb5c566f7ae8b0ee9a471da Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 15 Jan 2020 21:35:14 -0800 Subject: [PATCH] util: make offsetof/parent-of-member actually constexpr --- .../source/cfg/cfg_override.cpp | 2 + .../libvapours/include/vapours/defines.hpp | 1 + .../vapours/util/util_intrusive_list.hpp | 4 +- .../util/util_intrusive_red_black_tree.hpp | 4 +- .../vapours/util/util_parent_of_member.hpp | 223 ++++++++++++++++-- .../include/vapours/util/util_scope_guard.hpp | 12 +- 6 files changed, 211 insertions(+), 35 deletions(-) diff --git a/libraries/libstratosphere/source/cfg/cfg_override.cpp b/libraries/libstratosphere/source/cfg/cfg_override.cpp index 4aef8609e..baa49c3dd 100644 --- a/libraries/libstratosphere/source/cfg/cfg_override.cpp +++ b/libraries/libstratosphere/source/cfg/cfg_override.cpp @@ -84,6 +84,8 @@ namespace ams::cfg { .override_any_app = true, }; + bool g_loaded_override_config = false; + char g_hbl_sd_path[0x100] = "/atmosphere/hbl.nsp"; /* Helpers. */ diff --git a/libraries/libvapours/include/vapours/defines.hpp b/libraries/libvapours/include/vapours/defines.hpp index 629b3723f..c2ead65f2 100644 --- a/libraries/libvapours/include/vapours/defines.hpp +++ b/libraries/libvapours/include/vapours/defines.hpp @@ -34,6 +34,7 @@ #define ALIGNED(algn) __attribute__((aligned(algn))) #define NORETURN __attribute__((noreturn)) #define WEAK_SYMBOL __attribute__((weak)) +#define ALWAYS_INLINE_LAMBDA __attribute__((always_inline)) #define ALWAYS_INLINE inline __attribute__((always_inline)) #define NOINLINE __attribute__((noinline)) diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp index 3e06ade36..4323220fb 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp @@ -557,11 +557,11 @@ namespace ams::util { } static constexpr Derived &GetParent(IntrusiveListNode &node) { - return static_cast(util::GetParentReference(&node)); + return util::GetParentReference(&node); } static constexpr Derived const &GetParent(IntrusiveListNode const &node) { - return static_cast(util::GetParentReference(&node)); + return util::GetParentReference(&node); } }; diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp index 088286dd5..19f004b89 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_red_black_tree.hpp @@ -257,11 +257,11 @@ namespace ams::util { } static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { - return static_cast(util::GetParentPointer(node)); + return util::GetParentPointer(node); } static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { - return static_cast(util::GetParentPointer(node)); + return util::GetParentPointer(node); } }; diff --git a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp index 4402e927b..18d7a0cb5 100644 --- a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp +++ b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp @@ -21,21 +21,80 @@ namespace ams::util { namespace impl { - template - union OffsetOfImpl { - Member Parent::* ptr; - intptr_t offset; + template + struct OffsetOfUnionHolder { + template + union UnionImpl { + static constexpr size_t GetOffset() { return Offset; } + + struct { + char padding[Offset]; + MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; + } data; + UnionImpl next_union; + }; + + template + union UnionImpl { + static constexpr size_t GetOffset() { return 0; } + + struct { + MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; + } data; + UnionImpl next_union; + }; + + template + union UnionImpl { /* Empty */ }; }; - template - constexpr inline Parent *GetParentOfMemberImpl(Member *member, Member Parent::* ptr) { - return reinterpret_cast(reinterpret_cast(member) - OffsetOfImpl{ ptr }.offset); - } + template + struct OffsetOfCalculator { + using UnionHolder = typename OffsetOfUnionHolder::template UnionImpl; + union Union { + char c; + UnionHolder first_union; + ParentType parent; - template - constexpr inline Parent const *GetParentOfMemberImpl(Member const *member, Member Parent::* ptr) { - return reinterpret_cast(reinterpret_cast(member) - OffsetOfImpl{ ptr }.offset); - } + /* This coerces the active member to be c. */ + constexpr Union() : c() { /* ... */ } + }; + static constexpr Union U = {}; + + static constexpr const MemberType *GetNextAddress(const MemberType *start, const MemberType *target) { + while (start < target) { + start++; + } + return start; + } + + static constexpr std::ptrdiff_t GetDifference(const MemberType *start, const MemberType *target) { + return (target - start) * sizeof(MemberType); + } + + template + static constexpr std::ptrdiff_t OffsetOfImpl(MemberType ParentType::*member, CurUnion &cur_union) { + constexpr size_t Offset = CurUnion::GetOffset(); + const auto target = std::addressof(U.parent.*member); + const auto start = std::addressof(cur_union.data.members[0]); + const auto next = GetNextAddress(start, target); + + if (next < target) { + if constexpr (Offset + 1 < alignof(MemberType)) { + return OffsetOfImpl(member, cur_union.next_union); + } else { + static_assert(Offset + 1 <= alignof(MemberType)); + } + } + + return (next - start) * sizeof(MemberType) + Offset; + } + + + static constexpr std::ptrdiff_t OffsetOf(MemberType ParentType::*member) { + return OffsetOfImpl(member, U.first_union); + } + }; template struct GetMemberPointerTraits; @@ -52,26 +111,140 @@ namespace ams::util { template using GetMemberType = typename GetMemberPointerTraits::Member; + template> + constexpr inline std::ptrdiff_t OffsetOf = [] { + using DeducedParentType = GetParentType; + using MemberType = GetMemberType; + static_assert(std::is_base_of::value || std::is_same::value); + + return OffsetOfCalculator::OffsetOf(MemberPtr); + }(); + } - template - constexpr inline impl::GetParentType *GetParentPointer(impl::GetMemberType *member) { - return impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + template> + constexpr ALWAYS_INLINE RealParentType &GetParentReference(impl::GetMemberType *member) { + constexpr std::ptrdiff_t Offset = impl::OffsetOf; + uint8_t *addr = static_cast(static_cast(member)); + addr -= Offset; + return *static_cast(static_cast(addr)); } - template - constexpr inline impl::GetParentType const *GetParentPointer(impl::GetMemberType const *member) { - return impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + template> + constexpr ALWAYS_INLINE RealParentType const &GetParentReference(impl::GetMemberType const *member) { + constexpr std::ptrdiff_t Offset = impl::OffsetOf; + const uint8_t *addr = static_cast(static_cast(member)); + addr -= Offset; + return *static_cast(static_cast(addr)); } - template - constexpr inline impl::GetParentType &GetParentReference(impl::GetMemberType *member) { - return *impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + template> + constexpr ALWAYS_INLINE RealParentType *GetParentPointer(impl::GetMemberType *member) { + return std::addressof(GetParentReference(member)); } - template - constexpr inline impl::GetParentType const &GetParentReference(impl::GetMemberType const *member) { - return *impl::GetParentOfMemberImpl, impl::GetMemberType>(member, MemberPtr); + template> + constexpr ALWAYS_INLINE RealParentType const *GetParentPointer(impl::GetMemberType const *member) { + return std::addressof(GetParentReference(member)); } -} \ No newline at end of file + namespace test { + + struct Struct1 { + uint32_t a; + }; + + struct Struct2 { + uint32_t b; + }; + + struct Struct3 : public Struct1, Struct2 { + uint32_t c; + }; + + static_assert(impl::OffsetOf<&Struct1::a> == 0); + static_assert(impl::OffsetOf<&Struct2::b> == 0); + static_assert(impl::OffsetOf<&Struct3::a> == 0); + static_assert(impl::OffsetOf<&Struct3::b> == 0); + + + static_assert(impl::OffsetOf<&Struct3::a, Struct3> == 0 || impl::OffsetOf<&Struct3::b, Struct3> == 0); + static_assert(impl::OffsetOf<&Struct3::a, Struct3> == sizeof(Struct2) || impl::OffsetOf<&Struct3::b, Struct3> == sizeof(Struct1)); + static_assert(impl::OffsetOf<&Struct3::c> == sizeof(Struct1) + sizeof(Struct2)); + + constexpr Struct3 TestStruct3 = {}; + + static_assert(std::addressof(TestStruct3) == GetParentPointer<&Struct3::a, Struct3>(std::addressof(TestStruct3.a))); + static_assert(std::addressof(TestStruct3) == GetParentPointer<&Struct3::b, Struct3>(std::addressof(TestStruct3.b))); + static_assert(std::addressof(TestStruct3) == GetParentPointer<&Struct3::c, Struct3>(std::addressof(TestStruct3.c))); + + struct CharArray { + char c0; + char c1; + char c2; + char c3; + char c4; + char c5; + char c6; + char c7; + }; + + static_assert(impl::OffsetOf<&CharArray::c0> == 0); + static_assert(impl::OffsetOf<&CharArray::c1> == 1); + static_assert(impl::OffsetOf<&CharArray::c2> == 2); + static_assert(impl::OffsetOf<&CharArray::c3> == 3); + static_assert(impl::OffsetOf<&CharArray::c4> == 4); + static_assert(impl::OffsetOf<&CharArray::c5> == 5); + static_assert(impl::OffsetOf<&CharArray::c6> == 6); + static_assert(impl::OffsetOf<&CharArray::c7> == 7); + + constexpr CharArray TestCharArray = {}; + + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c0>(std::addressof(TestCharArray.c0))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c1>(std::addressof(TestCharArray.c1))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c2>(std::addressof(TestCharArray.c2))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c3>(std::addressof(TestCharArray.c3))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c4>(std::addressof(TestCharArray.c4))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c5>(std::addressof(TestCharArray.c5))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c6>(std::addressof(TestCharArray.c6))); + static_assert(std::addressof(TestCharArray) == GetParentPointer<&CharArray::c7>(std::addressof(TestCharArray.c7))); + + } + +} + +/* Defines, for use by other code. */ + +#define OFFSETOF(parent, member) (::ams::util::OffsetOf<&parent::member, parent>) + +#define AMS_GET_PARENT_TYPE_IMPL(parent, argt) typename std::conditional::value, \ + typename std::conditional::type>::value, \ + const parent, \ + parent \ + >::type, \ + typename std::conditional::type>::value, \ + const parent, \ + parent \ + >::type \ + >::type + +#define GET_PARENT_PTR(parent, member, _arg) ([](GetParentPtrArgType &arg) ALWAYS_INLINE_LAMBDA -> AMS_GET_PARENT_TYPE_IMPL(parent, GetParentPtrArgType) * { \ + using ParentPtrType = typename std::conditional::value, const parent, parent>::type *; \ + if constexpr (std::is_pointer::value) { \ + static_assert(std::is_same::type, typename std::remove_cv::type>::type>::value); \ + return ::ams::util::GetParentPointer<&parent::member, parent>(arg); \ + } else { \ + static_assert(std::is_same::type, typename std::remove_cv::type>::type>::value); \ + return ::ams::util::GetParentPointer<&parent::member, parent>(std::addressof(arg)); \ + } \ +}(_arg)) + +#define GET_PARENT_REF(parent, member, _arg) ([](GetParentPtrArgType &arg) ALWAYS_INLINE_LAMBDA -> AMS_GET_PARENT_TYPE_IMPL(parent, GetParentPtrArgType) & { \ + if constexpr (std::is_pointer::value) { \ + static_assert(std::is_same::type, typename std::remove_cv::type>::type>::value); \ + return ::ams::util::GetParentReference<&parent::member, parent>(arg); \ + } else { \ + static_assert(std::is_same::type, typename std::remove_cv::type>::type>::value); \ + return ::ams::util::GetParentReference<&parent::member, parent>(std::addressof(arg)); \ + } \ +}(_arg)) diff --git a/libraries/libvapours/include/vapours/util/util_scope_guard.hpp b/libraries/libvapours/include/vapours/util/util_scope_guard.hpp index a48d825e8..fc6ad842c 100644 --- a/libraries/libvapours/include/vapours/util/util_scope_guard.hpp +++ b/libraries/libvapours/include/vapours/util/util_scope_guard.hpp @@ -29,24 +29,24 @@ namespace ams::util { F f; bool active; public: - constexpr ScopeGuard(F f) : f(std::move(f)), active(true) { } - ~ScopeGuard() { if (active) { f(); } } - void Cancel() { active = false; } + constexpr ALWAYS_INLINE ScopeGuard(F f) : f(std::move(f)), active(true) { } + ALWAYS_INLINE ~ScopeGuard() { if (active) { f(); } } + ALWAYS_INLINE void Cancel() { active = false; } - ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { + ALWAYS_INLINE ScopeGuard(ScopeGuard&& rhs) : f(std::move(rhs.f)), active(rhs.active) { rhs.Cancel(); } }; template - constexpr ScopeGuard MakeScopeGuard(F f) { + constexpr ALWAYS_INLINE ScopeGuard MakeScopeGuard(F f) { return ScopeGuard(std::move(f)); } enum class ScopeGuardOnExit {}; template - constexpr ScopeGuard operator+(ScopeGuardOnExit, F&& f) { + constexpr ALWAYS_INLINE ScopeGuard operator+(ScopeGuardOnExit, F&& f) { return ScopeGuard(std::forward(f)); }