From f6c04bd7959bb08300d2c314c15e0b7e0052674c Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Wed, 12 Oct 2022 16:44:44 +0800 Subject: [PATCH 1/4] Replace __declspec(empty_bases) with conditional macro WINRT_IMPL_EMPTY_BASES The __declspec(empty_bases) attribute is only supported by MSVC or Clang using the MSVC ABI to enable Empty Base Class Optimization (EBCO). GCC or Clang using the MinGW ABI already perform EBCO and do not support this attribute. --- cppwinrt/code_writers.h | 12 ++++++------ cppwinrt/component_writers.h | 4 ++-- strings/base_composable.h | 2 +- strings/base_delegate.h | 6 +++--- strings/base_implements.h | 8 ++++---- strings/base_macros.h | 6 ++++++ strings/base_meta.h | 4 ++-- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index c9f99c9ea..4f968c1bb 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -348,7 +348,7 @@ namespace cppwinrt return; } - auto format = R"( template <%> struct __declspec(empty_bases) %; + auto format = R"( template <%> struct WINRT_IMPL_EMPTY_BASES %; )"; w.write(format, @@ -1962,7 +1962,7 @@ namespace cppwinrt static void write_dispatch_overridable(writer& w, TypeDef const& class_type) { auto format = R"(template -struct __declspec(empty_bases) produce_dispatch_to_overridable +struct WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable : produce_dispatch_to_overridable_base { %}; @@ -2378,7 +2378,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable if (empty(generics)) { - auto format = R"( struct __declspec(empty_bases) % : + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : winrt::Windows::Foundation::IInspectable, impl::consume_t<%>% { @@ -2401,7 +2401,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable type_name = remove_tick(type_name); auto format = R"( template <%> - struct __declspec(empty_bases) % : + struct WINRT_IMPL_EMPTY_BASES % : winrt::Windows::Foundation::IInspectable, impl::consume_t<%>% {% @@ -3147,7 +3147,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto type_name = type.TypeName(); auto factories = get_factories(w, type); - auto format = R"( struct __declspec(empty_bases) % : %%% + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : %%% { %(std::nullptr_t) noexcept {} %(void* ptr, take_ownership_from_abi_t) noexcept : %(ptr, take_ownership_from_abi) {} @@ -3172,7 +3172,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable auto type_name = type.TypeName(); auto factories = get_factories(w, type); - auto format = R"( struct __declspec(empty_bases) % : %% + auto format = R"( struct WINRT_IMPL_EMPTY_BASES % : %% { %(std::nullptr_t) noexcept {} %(void* ptr, take_ownership_from_abi_t) noexcept : %(ptr, take_ownership_from_abi) {} diff --git a/cppwinrt/component_writers.h b/cppwinrt/component_writers.h index fcfeddac0..1f6a2dbf1 100644 --- a/cppwinrt/component_writers.h +++ b/cppwinrt/component_writers.h @@ -743,7 +743,7 @@ catch (...) { return winrt::to_hresult(); } auto format = R"(namespace winrt::@::implementation { template - struct __declspec(empty_bases) %_base : implements%%% + struct WINRT_IMPL_EMPTY_BASES %_base : implements%%% { using base_type = %_base; using class_type = @::%; @@ -836,7 +836,7 @@ catch (...) { return winrt::to_hresult(); } auto format = R"(namespace winrt::@::factory_implementation { template - struct __declspec(empty_bases) %T : implements + struct WINRT_IMPL_EMPTY_BASES %T : implements { using instance_type = @::%; diff --git a/strings/base_composable.h b/strings/base_composable.h index efeb55877..7f675c970 100644 --- a/strings/base_composable.h +++ b/strings/base_composable.h @@ -27,7 +27,7 @@ namespace winrt::impl }; template - class __declspec(empty_bases) produce_dispatch_to_overridable_base + class WINRT_IMPL_EMPTY_BASES produce_dispatch_to_overridable_base { protected: D& shim() noexcept diff --git a/strings/base_delegate.h b/strings/base_delegate.h index 1ba8b4d69..599fb9bce 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -151,7 +151,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) delegate_base : Windows::Foundation::IUnknown + struct WINRT_IMPL_EMPTY_BASES delegate_base : Windows::Foundation::IUnknown { delegate_base(std::nullptr_t = nullptr) noexcept {} delegate_base(void* ptr, take_ownership_from_abi_t) noexcept : IUnknown(ptr, take_ownership_from_abi) {} @@ -201,13 +201,13 @@ namespace winrt::impl WINRT_EXPORT namespace winrt { template - struct __declspec(empty_bases) delegate : impl::delegate_base + struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; template - struct __declspec(empty_bases) delegate : impl::delegate_base + struct WINRT_IMPL_EMPTY_BASES delegate : impl::delegate_base { using impl::delegate_base::delegate_base; }; diff --git a/strings/base_implements.h b/strings/base_implements.h index 8016bef28..fb3595e7e 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -749,7 +749,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) root_implements_composing_outer + struct WINRT_IMPL_EMPTY_BASES root_implements_composing_outer { protected: static constexpr bool is_composing = false; @@ -757,7 +757,7 @@ namespace winrt::impl }; template <> - struct __declspec(empty_bases) root_implements_composing_outer + struct WINRT_IMPL_EMPTY_BASES root_implements_composing_outer { template auto try_as() const noexcept @@ -775,7 +775,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) root_implements_composable_inner + struct WINRT_IMPL_EMPTY_BASES root_implements_composable_inner { protected: static constexpr inspectable_abi* outer() noexcept { return nullptr; } @@ -785,7 +785,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) root_implements_composable_inner : producer + struct WINRT_IMPL_EMPTY_BASES root_implements_composable_inner : producer { protected: inspectable_abi* outer() noexcept { return m_outer; } diff --git a/strings/base_macros.h b/strings/base_macros.h index c1d0617c8..a66291ec7 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -47,6 +47,12 @@ #define WINRT_IMPL_NOINLINE #endif +#if defined(_MSC_VER) +#define WINRT_IMPL_EMPTY_BASES __declspec(empty_bases) +#else +#define WINRT_IMPL_EMPTY_BASES +#endif + #ifdef __IUnknown_INTERFACE_DEFINED__ #define WINRT_IMPL_IUNKNOWN_DEFINED #else diff --git a/strings/base_meta.h b/strings/base_meta.h index 0e800c49f..061a9f587 100644 --- a/strings/base_meta.h +++ b/strings/base_meta.h @@ -171,7 +171,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) require : require_one... + struct WINRT_IMPL_EMPTY_BASES require : require_one... {}; template @@ -184,7 +184,7 @@ namespace winrt::impl }; template - struct __declspec(empty_bases) base : base_one... + struct WINRT_IMPL_EMPTY_BASES base : base_one... {}; template From 569602cf1c74764219ae306f4e6937be37624b52 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Wed, 12 Oct 2022 17:22:06 +0800 Subject: [PATCH 2/4] Replace __declspec(novtable) with conditional macro WINRT_IMPL_NOVTABLE The attribute __declspec(novtable) is only supported by MSVC or Clang using the MSVC ABI. Since this is only an optimization, we can leave it out for MinGW ABI to allow it to compile. --- cppwinrt/code_writers.h | 6 +++--- strings/base_abi.h | 36 ++++++++++++++++++------------------ strings/base_delegate.h | 2 +- strings/base_fast_forward.h | 9 ++++++++- strings/base_implements.h | 2 +- strings/base_macros.h | 6 ++++++ 6 files changed, 37 insertions(+), 24 deletions(-) diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h index 4f968c1bb..24d45bdf3 100644 --- a/cppwinrt/code_writers.h +++ b/cppwinrt/code_writers.h @@ -765,7 +765,7 @@ namespace cppwinrt { auto format = R"( template <> struct abi<%> { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_NOVTABLE type : inspectable_abi { )"; @@ -775,7 +775,7 @@ namespace cppwinrt { auto format = R"( template <%> struct abi<%> { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_NOVTABLE type : inspectable_abi { )"; @@ -816,7 +816,7 @@ namespace cppwinrt { auto format = R"( template <%> struct abi<%> { - struct __declspec(novtable) type : unknown_abi + struct WINRT_IMPL_NOVTABLE type : unknown_abi { virtual int32_t __stdcall Invoke(%) noexcept = 0; }; diff --git a/strings/base_abi.h b/strings/base_abi.h index b14e8d85f..d1eab2950 100644 --- a/strings/base_abi.h +++ b/strings/base_abi.h @@ -3,7 +3,7 @@ namespace winrt::impl { template <> struct abi { - struct __declspec(novtable) type + struct WINRT_IMPL_NOVTABLE type { virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; virtual uint32_t __stdcall AddRef() noexcept = 0; @@ -15,7 +15,7 @@ namespace winrt::impl template <> struct abi { - struct __declspec(novtable) type : unknown_abi + struct WINRT_IMPL_NOVTABLE type : unknown_abi { virtual int32_t __stdcall GetIids(uint32_t* count, guid** ids) noexcept = 0; virtual int32_t __stdcall GetRuntimeClassName(void** name) noexcept = 0; @@ -27,20 +27,20 @@ namespace winrt::impl template <> struct abi { - struct __declspec(novtable) type : inspectable_abi + struct WINRT_IMPL_NOVTABLE type : inspectable_abi { virtual int32_t __stdcall ActivateInstance(void** instance) noexcept = 0; }; }; - struct __declspec(novtable) IAgileObject : unknown_abi {}; + struct WINRT_IMPL_NOVTABLE IAgileObject : unknown_abi {}; - struct __declspec(novtable) IAgileReference : unknown_abi + struct WINRT_IMPL_NOVTABLE IAgileReference : unknown_abi { virtual int32_t __stdcall Resolve(guid const& id, void** object) noexcept = 0; }; - struct __declspec(novtable) IMarshal : unknown_abi + struct WINRT_IMPL_NOVTABLE IMarshal : unknown_abi { virtual int32_t __stdcall GetUnmarshalClass(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, guid* pCid) noexcept = 0; virtual int32_t __stdcall GetMarshalSizeMax(guid const& riid, void* pv, uint32_t dwDestContext, void* pvDestContext, uint32_t mshlflags, uint32_t* pSize) noexcept = 0; @@ -50,20 +50,20 @@ namespace winrt::impl virtual int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept = 0; }; - struct __declspec(novtable) IGlobalInterfaceTable : unknown_abi + struct WINRT_IMPL_NOVTABLE IGlobalInterfaceTable : unknown_abi { virtual int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, uint32_t* cookie) noexcept = 0; virtual int32_t __stdcall RevokeInterfaceFromGlobal(uint32_t cookie) noexcept = 0; virtual int32_t __stdcall GetInterfaceFromGlobal(uint32_t cookie, guid const& iid, void** object) noexcept = 0; }; - struct __declspec(novtable) IStaticLifetime : inspectable_abi + struct WINRT_IMPL_NOVTABLE IStaticLifetime : inspectable_abi { virtual int32_t __stdcall unused() noexcept = 0; virtual int32_t __stdcall GetCollection(void** value) noexcept = 0; }; - struct __declspec(novtable) IStaticLifetimeCollection : inspectable_abi + struct WINRT_IMPL_NOVTABLE IStaticLifetimeCollection : inspectable_abi { virtual int32_t __stdcall Lookup(void*, void**) noexcept = 0; virtual int32_t __stdcall unused() noexcept = 0; @@ -74,23 +74,23 @@ namespace winrt::impl virtual int32_t __stdcall unused4() noexcept = 0; }; - struct __declspec(novtable) IWeakReference : unknown_abi + struct WINRT_IMPL_NOVTABLE IWeakReference : unknown_abi { virtual int32_t __stdcall Resolve(guid const& iid, void** objectReference) noexcept = 0; }; - struct __declspec(novtable) IWeakReferenceSource : unknown_abi + struct WINRT_IMPL_NOVTABLE IWeakReferenceSource : unknown_abi { virtual int32_t __stdcall GetWeakReference(IWeakReference** weakReference) noexcept = 0; }; - struct __declspec(novtable) IRestrictedErrorInfo : unknown_abi + struct WINRT_IMPL_NOVTABLE IRestrictedErrorInfo : unknown_abi { virtual int32_t __stdcall GetErrorDetails(bstr* description, int32_t* error, bstr* restrictedDescription, bstr* capabilitySid) noexcept = 0; virtual int32_t __stdcall GetReference(bstr* reference) noexcept = 0; }; - struct __declspec(novtable) IErrorInfo : unknown_abi + struct WINRT_IMPL_NOVTABLE IErrorInfo : unknown_abi { virtual int32_t __stdcall GetGUID(guid* value) noexcept = 0; virtual int32_t __stdcall GetSource(bstr* value) noexcept = 0; @@ -99,7 +99,7 @@ namespace winrt::impl virtual int32_t __stdcall GetHelpContext(uint32_t* value) noexcept = 0; }; - struct __declspec(novtable) ILanguageExceptionErrorInfo2 : unknown_abi + struct WINRT_IMPL_NOVTABLE ILanguageExceptionErrorInfo2 : unknown_abi { virtual int32_t __stdcall GetLanguageException(void** exception) noexcept = 0; virtual int32_t __stdcall GetPreviousLanguageExceptionErrorInfo(ILanguageExceptionErrorInfo2** previous) noexcept = 0; @@ -109,12 +109,12 @@ namespace winrt::impl struct ICallbackWithNoReentrancyToApplicationSTA; - struct __declspec(novtable) IContextCallback : unknown_abi + struct WINRT_IMPL_NOVTABLE IContextCallback : unknown_abi { virtual int32_t __stdcall ContextCallback(int32_t(__stdcall* callback)(com_callback_args*), com_callback_args* args, guid const& iid, int method, void* reserved) noexcept = 0; }; - struct __declspec(novtable) IServerSecurity : unknown_abi + struct WINRT_IMPL_NOVTABLE IServerSecurity : unknown_abi { virtual int32_t __stdcall QueryBlanket(uint32_t*, uint32_t*, wchar_t**, uint32_t*, uint32_t*, void**, uint32_t*) noexcept = 0; virtual int32_t __stdcall ImpersonateClient() noexcept = 0; @@ -122,12 +122,12 @@ namespace winrt::impl virtual int32_t __stdcall IsImpersonating() noexcept = 0; }; - struct __declspec(novtable) IBufferByteAccess : unknown_abi + struct WINRT_IMPL_NOVTABLE IBufferByteAccess : unknown_abi { virtual int32_t __stdcall Buffer(uint8_t** value) noexcept = 0; }; - struct __declspec(novtable) IMemoryBufferByteAccess : unknown_abi + struct WINRT_IMPL_NOVTABLE IMemoryBufferByteAccess : unknown_abi { virtual int32_t __stdcall GetBuffer(uint8_t** value, uint32_t* capacity) noexcept = 0; }; diff --git a/strings/base_delegate.h b/strings/base_delegate.h index 599fb9bce..e99fd4813 100644 --- a/strings/base_delegate.h +++ b/strings/base_delegate.h @@ -91,7 +91,7 @@ namespace winrt::impl } template - struct __declspec(novtable) variadic_delegate_abi : unknown_abi + struct WINRT_IMPL_NOVTABLE variadic_delegate_abi : unknown_abi { virtual R invoke(Args const& ...) = 0; }; diff --git a/strings/base_fast_forward.h b/strings/base_fast_forward.h index 298403197..88d99469a 100644 --- a/strings/base_fast_forward.h +++ b/strings/base_fast_forward.h @@ -4,6 +4,12 @@ #define WINRT_IMPL_STRING_1(expression) #expression #define WINRT_IMPL_STRING(expression) WINRT_IMPL_STRING_1(expression) +#if defined(_MSC_VER) +#define WINRT_IMPL_FF_NOVTABLE __declspec(novtable) +#else +#define WINRT_IMPL_FF_NOVTABLE +#endif + #if !defined(WINRT_FAST_ABI_SIZE) #define WINRT_FAST_ABI_SIZE % #endif @@ -30,7 +36,7 @@ namespace winrt::impl } }; - struct __declspec(novtable) inspectable + struct WINRT_IMPL_FF_NOVTABLE inspectable { virtual int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept = 0; virtual uint32_t __stdcall AddRef() noexcept = 0; @@ -130,3 +136,4 @@ namespace winrt #undef WINRT_IMPL_STRING #undef WINRT_IMPL_STRING_1 +#undef WINRT_IMPL_FF_NOVTABLE diff --git a/strings/base_implements.h b/strings/base_implements.h index fb3595e7e..a81df5f8e 100644 --- a/strings/base_implements.h +++ b/strings/base_implements.h @@ -800,7 +800,7 @@ namespace winrt::impl }; template - struct __declspec(novtable) root_implements + struct WINRT_IMPL_NOVTABLE root_implements : root_implements_composing_outer...>> , root_implements_composable_inner...>> , module_lock_updater...>> diff --git a/strings/base_macros.h b/strings/base_macros.h index a66291ec7..c4ec6645b 100644 --- a/strings/base_macros.h +++ b/strings/base_macros.h @@ -53,6 +53,12 @@ #define WINRT_IMPL_EMPTY_BASES #endif +#if defined(_MSC_VER) +#define WINRT_IMPL_NOVTABLE __declspec(novtable) +#else +#define WINRT_IMPL_NOVTABLE +#endif + #ifdef __IUnknown_INTERFACE_DEFINED__ #define WINRT_IMPL_IUNKNOWN_DEFINED #else From 57d392fa07d7d29c4753df3898d0bc81112a2ffa Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Wed, 12 Oct 2022 19:36:11 +0800 Subject: [PATCH 3/4] Add __GNUC__ version of WINRT_IMPL_LINK This uses weak alias symbols to emulate the MSVC-specific `/alternatename` linker feature. --- strings/base_extern.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/strings/base_extern.h b/strings/base_extern.h index 7782f3bcb..b4e3eeed0 100644 --- a/strings/base_extern.h +++ b/strings/base_extern.h @@ -83,6 +83,7 @@ extern "C" int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; } +#if defined(_MSC_VER) #ifdef _M_HYBRID #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count)) #elif _M_ARM64EC @@ -92,6 +93,13 @@ extern "C" #else #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:WINRT_IMPL_" #function "=" #function)) #endif +#elif defined(__GNUC__) +#if defined(__i386__) +#define WINRT_IMPL_LINK(function, count) __asm__(".weak _WINRT_IMPL_" #function "@" #count "\n.set _WINRT_IMPL_" #function "@" #count ", _" #function "@" #count); +#else +#define WINRT_IMPL_LINK(function, count) __asm__(".weak WINRT_IMPL_" #function "\n.set WINRT_IMPL_" #function ", " #function); +#endif +#endif WINRT_IMPL_LINK(LoadLibraryW, 4) WINRT_IMPL_LINK(FreeLibrary, 4) From 559c680bee2060cbb1c1e7ba4dc33f594630987a Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Wed, 12 Oct 2022 20:45:49 +0800 Subject: [PATCH 4/4] Add `#include ` unconditionally to support mingw-w64 --- strings/base_error.h | 1 - strings/base_includes.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/strings/base_error.h b/strings/base_error.h index 44b955b95..69e23adbd 100644 --- a/strings/base_error.h +++ b/strings/base_error.h @@ -1,6 +1,5 @@ #if defined(_MSC_VER) -#include #define WINRT_IMPL_RETURNADDRESS() _ReturnAddress() #elif defined(__GNUC__) #define WINRT_IMPL_RETURNADDRESS() __builtin_extract_return_addr(__builtin_return_address(0)) diff --git a/strings/base_includes.h b/strings/base_includes.h index 8fe598212..d514b415e 100644 --- a/strings/base_includes.h +++ b/strings/base_includes.h @@ -1,4 +1,5 @@ +#include #include #include #include