Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/coreclr/vm/genericdict.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,12 @@ Dictionary::PopulateEntry(
th = th.GetMethodTable()->GetMethodTableMatchingParentClass(declaringType.AsMethodTable());
}

th.GetMethodTable()->EnsureInstanceActive();
if (!th.IsTypeDesc())
{
MethodTable* pMT = th.AsMethodTable();
_ASSERTE(pMT != NULL);
pMT->EnsureInstanceActive();
}

result = (CORINFO_GENERIC_HANDLE)th.AsPtr();
break;
Expand Down
17 changes: 17 additions & 0 deletions src/coreclr/vm/unsafeaccessors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,23 @@ bool MethodDesc::TryGenerateUnsafeAccessor(DynamicResolver** resolver, COR_ILMET
context.TargetTypeSig = context.DeclarationMetaSig.GetArgProps();
(void)context.TargetTypeSig.PeekElemType(&firstArgCorType);
firstArgType = context.DeclarationMetaSig.GetLastTypeHandleThrowing();

// For instance member access, the first argument is the receiver ("this").
// For value types the receiver must be passed byref. A byref receiver can also occur for reference
// types depending on the declaration signature.
//
// However, when emitting the metadata token for the accessed member, the owning type must not be
// a byref. Keeping the byref here can lead to incorrect shared generic context lookups at runtime.
//
// No special handling is required for other forms of type parameterization here:
// * Arrays and generic instantiations are part of the owning type identity and must not be stripped.
// * Other forms (eg. pointers) are not valid target types and will be rejected by ValidateTargetType().
if ((context.Kind == UnsafeAccessorKind::Method || context.Kind == UnsafeAccessorKind::Field)
&& firstArgCorType == ELEMENT_TYPE_BYREF)
{
// Consume byref token.
(void)context.TargetTypeSig.GetElemType(nullptr);
}
}

// Using the kind type, perform the following:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,31 @@

using Xunit;

struct Struct { }
struct Struct
{
public Type Value;
private void SetType(Type type)
{
Value = type;
}
private void SetType<T>()
{
Value = typeof(T);
}
}

struct GenericStruct<T>
{
public Type Value;
private void SetType(Type type)
{
Value = type;
}
private void SetType<U>()
{
Value = typeof(U);
}
}

interface I1 { }

Expand Down Expand Up @@ -112,6 +136,12 @@ static class Accessors<V>
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "CreateMessage")]
public extern static string CreateMessage(GenericBase<V> b, V v);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SetType")]
public extern static void SetType(ref GenericStruct<V> s, Type type);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SetType")]
public extern static void SetType<U>(ref GenericStruct<V> s);

[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "ElementType")]
public extern static Type ElementType(MyList<V> l);

Expand All @@ -128,6 +158,15 @@ static class Accessors<V>
public extern static ref V GetPrivateStaticField(MyList<V> d);
}

static class Accessors
{
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SetType")]
public extern static void SetType<U>(ref Struct s);

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SetType")]
public extern static void SetType(ref Struct s, Type type);
}

[Fact]
public static void Verify_Generic_AccessStaticFieldClass()
{
Expand Down Expand Up @@ -459,6 +498,68 @@ public static void Verify_Generic_GenericTypeGenericStaticMethod()
}
}

[Fact]
public static void Verify_Generic_Structs()
{
Console.WriteLine($"Running {nameof(Verify_Generic_Structs)}");

{
Struct s = new();
Accessors.SetType(ref s, typeof(int));
Assert.Equal(typeof(int), s.Value);
Accessors.SetType(ref s, typeof(string));
Assert.Equal(typeof(string), s.Value);
Accessors.SetType(ref s, typeof(Struct));
Assert.Equal(typeof(Struct), s.Value);
Accessors.SetType(ref s, typeof(GenericStruct<int>));
Assert.Equal(typeof(GenericStruct<int>), s.Value);
Accessors.SetType(ref s, typeof(GenericStruct<string>));
Assert.Equal(typeof(GenericStruct<string>), s.Value);
}

{
Struct s = new();
Accessors.SetType<int>(ref s);
Assert.Equal(typeof(int), s.Value);
Accessors.SetType<string>(ref s);
Assert.Equal(typeof(string), s.Value);
Accessors.SetType<Struct>(ref s);
Assert.Equal(typeof(Struct), s.Value);
Accessors.SetType<GenericStruct<int>>(ref s);
Assert.Equal(typeof(GenericStruct<int>), s.Value);
Accessors.SetType<GenericStruct<string>>(ref s);
Assert.Equal(typeof(GenericStruct<string>), s.Value);
}

{
GenericStruct<int> s = new();
Accessors<int>.SetType(ref s, typeof(int));
Assert.Equal(typeof(int), s.Value);
Accessors<int>.SetType<string>(ref s);
Assert.Equal(typeof(string), s.Value);
Accessors<int>.SetType<Struct>(ref s);
Assert.Equal(typeof(Struct), s.Value);
Accessors<int>.SetType<GenericStruct<int>>(ref s);
Assert.Equal(typeof(GenericStruct<int>), s.Value);
Accessors<int>.SetType<GenericStruct<string>>(ref s);
Assert.Equal(typeof(GenericStruct<string>), s.Value);
}

{
GenericStruct<string> s = new();
Accessors<string>.SetType(ref s, typeof(int));
Assert.Equal(typeof(int), s.Value);
Accessors<string>.SetType<string>(ref s);
Assert.Equal(typeof(string), s.Value);
Accessors<string>.SetType<Struct>(ref s);
Assert.Equal(typeof(Struct), s.Value);
Accessors<string>.SetType<GenericStruct<int>>(ref s);
Assert.Equal(typeof(GenericStruct<int>), s.Value);
Accessors<string>.SetType<GenericStruct<string>>(ref s);
Assert.Equal(typeof(GenericStruct<string>), s.Value);
}
}

class MethodWithConstraints
{
private string M<T, U>() where T : U, I2<T>
Expand Down
Loading