Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Bug: implements_delegate non-fold-ability #1334

Copy link
Copy link
@jonwis

Description

@jonwis
Issue body actions

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;
        }
    };
Reactions are currently unavailable

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.