From 391c7f62199cf61b14349a751df85997e9c57dc5 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 1 Jul 2024 10:24:21 -0700 Subject: [PATCH] Updates --- docs/design/features/byreflike-generics.md | 7 +- .../generics/ByRefLike/InvalidCSharp.il | 73 ++++++------------- .../generics/ByRefLike/Validate.cs | 7 +- 3 files changed, 31 insertions(+), 56 deletions(-) diff --git a/docs/design/features/byreflike-generics.md b/docs/design/features/byreflike-generics.md index 89d30be4842ea..1526f65ac8a6b 100644 --- a/docs/design/features/byreflike-generics.md +++ b/docs/design/features/byreflike-generics.md @@ -9,13 +9,14 @@ Using ByRefLike types in Generic parameters is possible by building upon support Supporting ByRefLike type as Generic parameters will impact the following IL instructions: +Throws `InvalidProgramException`: - `box` – Types with ByRefLike parameters used in fields cannot be boxed. +- `constrained.callvirt` – When applied to a ByRefLike instance, if this IL sequence resolves to a method implemented on `object` or a default interface method, an error will occur during the attempt to box the ByRefLike instance. + +Throws `TypeLoadException`: - `stsfld` / `ldsfld` – Type fields of a ByRefLike parameter cannot be marked `static`. - `newarr` / `stelem` / `ldelem` / `ldelema` – Arrays are not able to contain ByRefLike types. - `newobj` – For multi-dimensional array construction. -- `constrained.callvirt` – When applied to a ByRefLike instance, if this IL sequence resolves to a method implemented on `object` or a default interface method, an error will occur during the attempt to box the ByRefLike instance. - -If any of the above instructions are attempted to be used with a ByRefLike type, the runtime will throw an `InvalidProgramException`. The following instructions are already set up to support this feature since their behavior will fail as currently defined due to the inability to box a ByRefLike type. diff --git a/src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il b/src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il index 36fd12c3248ac..f6b138fe7e016 100644 --- a/src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il +++ b/src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il @@ -93,14 +93,6 @@ ret } - .method public hidebysig - instance object BoxAsObject(!T) cil managed - { - ldarg.1 - box !T - ret - } - .method public hidebysig instance bool BoxUnboxAny(!T) cil managed { @@ -368,17 +360,6 @@ ret } - .method public hidebysig - instance bool AllocMultiDimArrayOfT() cil managed - { - ldc.i4.1 - ldc.i4.1 - newobj instance void !T[0..., 0...]::.ctor(int32, int32) - ldnull - cgt.un - ret - } - .method public hidebysig instance bool InstanceOfT( object o @@ -724,18 +705,10 @@ } .method public hidebysig static - object BoxAsObject() cil managed + object BoxAsObject(!!Y) cil managed noinlining { - .locals init ( - [0] valuetype InvalidCSharp.GenericByRefLike_Over`1 - ) - - ldloca.s 0 - initobj valuetype InvalidCSharp.GenericByRefLike_Over`1 - ldloca.s 0 - ldloc 0 - ldfld !0 valuetype InvalidCSharp.GenericByRefLike_Over`1::Field - call instance object valuetype InvalidCSharp.GenericByRefLike_Over`1::BoxAsObject(!0) + ldarg.0 + box !!Y ret } @@ -937,32 +910,23 @@ } .method public hidebysig static - void AllocArrayOfT_Invalid() cil managed + bool AllocArray() cil managed noinlining { - .locals init ( - [0] valuetype InvalidCSharp.GenericByRefLike_Over`1 - ) - - ldloca.s 0 - initobj valuetype InvalidCSharp.GenericByRefLike_Over`1 - ldloca.s 0 - call instance bool valuetype InvalidCSharp.GenericByRefLike_Over`1::AllocArrayOfT() - pop + ldc.i4.1 + newarr !!Y + ldnull + cgt.un ret } .method public hidebysig static - void AllocMultiDimArrayOfT_Invalid() cil managed + bool AllocMultiDimArray() cil managed noinlining { - .locals init ( - [0] valuetype InvalidCSharp.GenericByRefLike_Over`1 - ) - - ldloca.s 0 - initobj valuetype InvalidCSharp.GenericByRefLike_Over`1 - ldloca.s 0 - call instance bool valuetype InvalidCSharp.GenericByRefLike_Over`1::AllocMultiDimArrayOfT() - pop + ldc.i4.1 + ldc.i4.1 + newobj instance void !!Y[0..., 0...]::.ctor(int32, int32) + ldnull + cgt.un ret } @@ -975,6 +939,15 @@ ret } + .method public hidebysig static + string CallStringOnObject(!!T t) cil managed noinlining + { + ldarga.s 0 + constrained. !!T + callvirt instance string [System.Runtime]System.Object::ToString() + ret + } + .method public hidebysig static bool InstanceOfT(object) cil managed { diff --git a/src/tests/Loader/classloader/generics/ByRefLike/Validate.cs b/src/tests/Loader/classloader/generics/ByRefLike/Validate.cs index 511471782a58f..74150c04857ca 100644 --- a/src/tests/Loader/classloader/generics/ByRefLike/Validate.cs +++ b/src/tests/Loader/classloader/generics/ByRefLike/Validate.cs @@ -124,12 +124,13 @@ public static void Validate_InvalidOpCode_Scenarios() // These methods uses opcodes that are not able to handle ByRefLike type operands. // The TypeLoader prevents these invalid types from being constructed. We rely on // the failure to construct these invalid types to block opcode usage. - Assert.Throws(() => { Exec.AllocArrayOfT_Invalid(); }); - Assert.Throws(() => { Exec.AllocMultiDimArrayOfT_Invalid(); }); + Assert.Throws(() => { Exec.AllocArray(); }); + Assert.Throws(() => { Exec.AllocMultiDimArray(); }); Assert.Throws(() => { Exec.GenericClassWithStaticField_Invalid(); }); // Test that explicitly tries to box a ByRefLike type. - Assert.Throws(() => { Exec.BoxAsObject(); }); + Assert.Throws(() => { Exec.BoxAsObject(new RS()); }); + Assert.Throws(() => { Exec.CallStringOnObject(new RS()); }); } [Fact]