Skip to content

Commit

Permalink
Updates
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronRobinsonMSFT committed Jul 1, 2024
1 parent c43cddd commit 391c7f6
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 56 deletions.
7 changes: 4 additions & 3 deletions docs/design/features/byreflike-generics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
73 changes: 23 additions & 50 deletions src/tests/Loader/classloader/generics/ByRefLike/InvalidCSharp.il
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -724,18 +705,10 @@
}

.method public hidebysig static
object BoxAsObject() cil managed
object BoxAsObject<byreflike Y>(!!Y) cil managed noinlining
{
.locals init (
[0] valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
)

ldloca.s 0
initobj valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
ldloca.s 0
ldloc 0
ldfld !0 valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>::Field
call instance object valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>::BoxAsObject(!0)
ldarg.0
box !!Y
ret
}

Expand Down Expand Up @@ -937,32 +910,23 @@
}

.method public hidebysig static
void AllocArrayOfT_Invalid() cil managed
bool AllocArray<byreflike Y>() cil managed noinlining
{
.locals init (
[0] valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
)

ldloca.s 0
initobj valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
ldloca.s 0
call instance bool valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>::AllocArrayOfT()
pop
ldc.i4.1
newarr !!Y
ldnull
cgt.un
ret
}

.method public hidebysig static
void AllocMultiDimArrayOfT_Invalid() cil managed
bool AllocMultiDimArray<byreflike Y>() cil managed noinlining
{
.locals init (
[0] valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
)

ldloca.s 0
initobj valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>
ldloca.s 0
call instance bool valuetype InvalidCSharp.GenericByRefLike_Over`1<valuetype ByRefLikeType>::AllocMultiDimArrayOfT()
pop
ldc.i4.1
ldc.i4.1
newobj instance void !!Y[0..., 0...]::.ctor(int32, int32)
ldnull
cgt.un
ret
}

Expand All @@ -975,6 +939,15 @@
ret
}

.method public hidebysig static
string CallStringOnObject<byreflike T>(!!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
{
Expand Down
7 changes: 4 additions & 3 deletions src/tests/Loader/classloader/generics/ByRefLike/Validate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TypeLoadException>(() => { Exec.AllocArrayOfT_Invalid(); });
Assert.Throws<TypeLoadException>(() => { Exec.AllocMultiDimArrayOfT_Invalid(); });
Assert.Throws<TypeLoadException>(() => { Exec.AllocArray<RS>(); });
Assert.Throws<TypeLoadException>(() => { Exec.AllocMultiDimArray<RS>(); });
Assert.Throws<TypeLoadException>(() => { Exec.GenericClassWithStaticField_Invalid(); });

// Test that explicitly tries to box a ByRefLike type.
Assert.Throws<InvalidProgramException>(() => { Exec.BoxAsObject(); });
Assert.Throws<InvalidProgramException>(() => { Exec.BoxAsObject<RS>(new RS()); });
Assert.Throws<InvalidProgramException>(() => { Exec.CallStringOnObject<RS>(new RS()); });
}

[Fact]
Expand Down

0 comments on commit 391c7f6

Please sign in to comment.