Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
14 changes: 14 additions & 0 deletions src/coreclr/vm/unsafeaccessors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,20 @@ 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 on value types, the first argument (this) must be a byref.
// However, the target type used for token emission must not be parameterized. Keeping the
// byref here can lead to incorrect shared generic context lookups at runtime.
if ((context.Kind == UnsafeAccessorKind::Method || context.Kind == UnsafeAccessorKind::Field)
&& firstArgCorType == ELEMENT_TYPE_BYREF)
{
SigPointer targetTypeSig = context.TargetTypeSig;
CorElementType elemType;
IfFailThrow(targetTypeSig.GetElemType(&elemType));
_ASSERTE(elemType == ELEMENT_TYPE_BYREF);

context.TargetTypeSig = targetTypeSig;
}
}

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

using Xunit;

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

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

interface I1 { }

Expand Down Expand Up @@ -112,6 +142,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 +164,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 +504,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