Skip to content

Support precompiling 'ComInterfaceEntry.IID' fields from RVA span fields in ILC cctor interpreter (Native AOT) #114455

Closed
@Sergio0694

Description

@Sergio0694

Follow-up to #114355

Chatted about this offline with @MichalStrehovsky, opening this for tracking. This is a follow up to getting ILC to support folding ComInterfaceEntry arrays. The only additional on top of that is to also make ILC capable of folding the IID values when they're read from an RVA field (specifically, from a ref returning property that does a reinterpret-cast over an RVA field with the IID data), rather than just with a hardcoded Guid constructor inline. The reason this would be beneficial for us is that while a lot of these arrays would be in generated projections, we also have quite a lot of manual (ie. handwritten) projected types as well in CsWinRT (for custom mapped types), and having to manually hardcode all those IIDs would be quite error prone and difficult to maintain. If we could just reuse our static IIDs instead (which we already have), it'd make that much simpler.

We'd basically need to support this:

public struct MyTypeVtableEntries
{
    public ComInterfaceEntry IReferenceOfPoint;
    public ComInterfaceEntry IStringable;
    public ComInterfaceEntry IWeakReferenceSource;
    public ComInterfaceEntry IMarshal;
    public ComInterfaceEntry IAgileObject;
    public ComInterfaceEntry IInspectable;
    public ComInterfaceEntry IUnknown;
}

public static class MyTypeImpl
{
    [FixedAddressValueType]
    private static readonly MyTypeVtableEntries VtableEntries;

    static MyTypeImpl()
    {
        Entries.IReferenceOfPoint.IID = WellKnownInterfaceIds.IID_IReferenceOfPoint;
        Entries.IReferenceOfPoint.Vtable = PointReferenceImpl.AbiToProjectionVftablePtr;
        Entries.IStringable.IID = WellKnownInterfaceIds.IID_IStringable;
        Entries.IStringable.Vtable = IStringableImpl.AbiToProjectionVftablePtr;
        Entries.IWeakReferenceSource.IID = WellKnownInterfaceIds.IID_IWeakReferenceSource;
        Entries.IWeakReferenceSource.Vtable = IWeakReferenceSourceImpl.AbiToProjectionVftablePtr;
        Entries.IMarshal.IID = WellKnownInterfaceIds.IID_IMarshal;
        Entries.IMarshal.Vtable = IMarshalImpl.AbiToProjectionVftablePtr;
        Entries.IAgileObject.IID = WellKnownInterfaceIds.IID_IAgileObject;
        Entries.IAgileObject.Vtable = IUnknownImpl.AbiToProjectionVftablePtr;
        Entries.IInspectable.IID = WellKnownInterfaceIds.IID_IInspectable;
        Entries.IInspectable.Vtable = IInspectableImpl.AbiToProjectionVftablePtr;
        Entries.IUnknown.IID = WellKnownInterfaceIds.IID_IUnknown;
        Entries.IUnknown.Vtable = IUnknownImpl.AbiToProjectionVftablePtr;
    }
}

Where all of those WellKnownInterfaceIds.IID_ values are properties just like this one:

internal static ref readonly Guid IID_IReferenceOfPoint
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]   
    get
    {
        ReadOnlySpan<byte> data =
        [
            0x22, 0x4C, 0xF1, 0x84,
            0x0A, 0xA0,
            0x72, 0x52,
            0x8D,
            0x3D,
            0x82,
            0x11,
            0x2E,
            0x66,
            0xDF,
            0x00
        ];

        return ref Unsafe.As<byte, Guid>(ref MemoryMarshal.GetReference(data));
    }
}

The backing storage for those IIDs is guaranteed by Roslyn to already be an RVA field. We'd need ILC to recognize those reads and assignments to from these properties to the ComInterfaceEntry.IID fields, and just copy the entire content inline into that MyTypeVtableEntries buffer.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions