Skip to content

[API Proposal]: Methods to support ByRefLike types in "is-type" IL sequences #105435

Open
@AaronRobinsonMSFT

Description

@AaronRobinsonMSFT

Background and motivation

Due to the non-boxing requirment of ByRefLike types, it is complicated to express generic IL instructions for methods where the allows ref struct constraint is applied, given existing semantics of certain IL instructions. This is particularly limiting when attempting an "is-type" check (that is, x is Y y). These APIs will be provided and their semantics defined in coordination with the Roslyn team to help us avoid augmenting the definitions of certain IL instruction, in specific sequences - see option two in the below design notes. ECMA-335 doesn't dictate details of .NET APIs, so adding APIs avoids any ECMA-335 augmentation with respect to IL instruction semantics.

See further design notes in byreflike-generics.md.

API Proposal

namespace System.Runtime.CompilerServices
{
    public static class RuntimeHelpers
    {
        // Replacement for the [box; isinst; brfalse/true] sequence.
        public static bool IsInstanceOf<TFrom, TTo>(TFrom source)
            where TFrom: allows ref struct
            where TTo: allows ref struct;

        // Replacement for the [box; isinst; unbox.any] sequence.
        // Would throw InvalidCastException for invalid use at run-time.
        // For example:
        //  TFrom: RS, TTo: object      => always throws
        //  TFrom: RS, TTo: <interface> => always throws
        public static TTo CastTo<TFrom, TTo>(TFrom source)
            where TFrom: allows ref struct
            where TTo: allows ref struct;
    }
}

API Usage

This API is not meant to be used directly by user code. It called by Roslyn generated code to perform "is-type" checks involving ByRefLike types.

Instead of the following IL sequences for "is-type":

// Type check
ldarg.0
    box <Source>
    isinst <Target>
    brfalse.s NOT_INST

// Unbox and store unboxed instance
ldarg.0
    box <Source>
    isinst <Target>
    unbox.any <Target>
stloc.X

NOT_INST:

The following C# will now be possible:

TTo result;
if (RuntimeHelpers.IsInstanceOf<TFrom, TTo>(source))
{
    result = RuntimeHelpers.CastTo<TFrom, TTo>(source);
}

Alternative Designs

The troublesome IL sequences can be identified to support ByRefLike types when detected by the JIT or Interpreter. This requires changing the semantic meaning of some IL instructions, but only in certain sequences and then updating ECMA-335. This was the approach attempted in .NET 9 and has proven to be very difficult to reconcile with the broader ecosystem with the needed language.

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions