Skip to content

Update '[GeneratedComInterface]' to emit ILC-friendly vtables for RVA folding #114468

@Sergio0694

Description

@Sergio0694

Now that:

We could optimize the codegen for [GeneratedComInterface] to preinitialize the CCW vtable:

file unsafe partial interface InterfaceImplementation
{
    internal static void** CreateManagedVirtualFunctionTable()
    {
        void** vtable = (void**)global::System.Runtime.CompilerServices.RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(global::WindowsRuntime.IWeakReference), sizeof(void*) * 4);
        {
            nint v0, v1, v2;
            global::System.Runtime.InteropServices.ComWrappers.GetIUnknownImpl(out v0, out v1, out v2);
            vtable[0] = (void*)v0;
            vtable[1] = (void*)v1;
            vtable[2] = (void*)v2;
        }

        {
            vtable[3] = (void*)(delegate* unmanaged[MemberFunction]<global::System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch*, global::System.Guid*, void**, int> )&ABI_Resolve;
        }

        return vtable;
    }
}

This could instead be something like this:

file unsafe struct InterfaceImplementationVtable
{
    public delegate* unmanaged[MemberFunction]<void*, Guid*, void**, int> QueryInterface;
    public delegate* unmanaged[MemberFunction]<void*, uint> AddRef;
    public delegate* unmanaged[MemberFunction]<void*, uint> Release;
    public delegate* unmanaged[MemberFunction]<global::System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch*, global::System.Guid*, void**, int> Resolve;
}

file static class InterfaceImplementationVtableImpl
{
    [FixedAddressValueType]
    public static readonly InterfaceImplementationVtable Vtable;

    static InterfaceImplementationVtableImpl()
    {
        ComWrappers.GetIUnknownImpl(
            fpQueryInterface: out *(nint*)&((InterfaceImplementationVtable*)Unsafe.AsPointer(ref Vtbl))->QueryInterface,
            fpAddRef: out *(nint*)&((InterfaceImplementationVtable*)Unsafe.AsPointer(ref Vtbl))->AddRef,
            fpRelease: out *(nint*)&((InterfaceImplementationVtable*)Unsafe.AsPointer(ref Vtbl))->Release);

        Vtable.Resolve = &InterfaceImplementation.ABI_Resolve;
    }
}

file unsafe partial interface InterfaceImplementation
{
    internal static void** CreateManagedVirtualFunctionTable()
    {
        return (void**)Unsafe.AsPointer(in InterfaceImplementationVtableImpl.Vtable);
    }
}

This would be fully foldable on Native AOT, so that it gets:

  • No overhead to initialize it
  • No allocation at runtime
  • On Windows, it goes into a readonly PE section (pending)

cc. @jkoritzinsky

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions