-
Notifications
You must be signed in to change notification settings - Fork 263
Description
Version
2.0.220131.2
Summary
Using SizeBench, some reasonable fraction of our DLL is taken up in winrt::impl::implements_delegate methods that aren't foldable for one of two reasons:
- The offset of the reference count member shifts around from +10 to +18 depending on the complexity of the delegate
- The "which guid are you?" checks end up generating relative
lea ...operations.
Reproducible example
No response
Expected behavior
It may be a linker/optimizer bug that the folder is not working "hard enough."
Actual behavior
Multiple nonfolded specializations of delegate types taking ~1% of binary space (~15k out of ~1500k).
Additional comments
In other places, I've used a "base" type to move as many things down to non-templated members as possible, with a templated caller sending in a parameters. For instance, in base.h, this appears to work and collapse all those methods into a small handful of specialized "push some parameters and call a helper" method.
Things that could use a similar treatment:
- winrt::event::add - make_agile_delegate's use of guid_of
- root_implements - find_interface use of guids
- await_adapter::await_suspend - looks like vtable handling
In my 1.5mb DLL, SizeBench claims those three waste another 1%.
namespace winrt::impl
{
#if defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable:4458) // declaration hides class member (okay because we do not use named members of base class)
#endif
struct implements_delegate_base
{
WINRT_IMPL_NOINLINE uint32_t __stdcall AddRef() noexcept
{
return ++m_references;
}
WINRT_IMPL_NOINLINE uint32_t __stdcall Release() noexcept
{
return --m_references;
}
WINRT_IMPL_NOINLINE uint32_t QueryInterfaceCommon(guid const& id, void** result, unknown_abi* abi_t_ptr, guid const& delegate_id) noexcept
{
if ((delegate_id == id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = abi_t_ptr;
AddRef();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(abi_t_ptr, result);
}
*result = nullptr;
return error_no_interface;
}
public:
atomic_ref_count m_references{ 1 };
};
template <typename T, typename H>
struct implements_delegate : implements_delegate_base, abi_t<T>, H, update_module_lock
{
implements_delegate(H&& handler) : H(std::forward<H>(handler))
{
}
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final { return implements_delegate_base::QueryInterfaceCommon(id, result, static_cast<abi_t<T>*>(this), guid_of<T>()); }
uint32_t __stdcall AddRef() noexcept final { return implements_delegate_base::AddRef(); }
uint32_t __stdcall Release() noexcept final
{
auto remaining = implements_delegate_base::Release();
if (remaining == 0)
{
delete static_cast<delegate<T, H>*>(this);
}
return remaining;
}
};