Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
173b84d
Add reflection introspection support for function pointers
steveharter May 31, 2022
e546ee2
Fix compiler issue; test MLC to NetFramework
steveharter Jan 23, 2023
36e07d6
Fix compile issue; prep for review
steveharter Jan 23, 2023
e755c1c
Compile issue with MLC under certain conditions
steveharter Jan 23, 2023
b3b64ff
compile issue cont'd; lazy load mods on root
steveharter Jan 23, 2023
3aef789
compile issues cont'd; prepare for review
steveharter Jan 24, 2023
f76c75d
Remove Node back reference; fix edge case test failure
steveharter Jan 24, 2023
73b15b3
Increase test coverage; add missing recursive check
steveharter Jan 24, 2023
1361142
Various feedback; support mods on generic type parameters
steveharter Jan 26, 2023
520a3f5
Merge branch 'main' of https://github.com/steveharter/runtime into Fc…
steveharter Jan 26, 2023
64a987e
Fix MLC edge case; Native AOT test enable\disable
steveharter Jan 26, 2023
5f8a81e
Native AOT test enable\disable; add a generic test
steveharter Jan 26, 2023
2df9d2b
Native AOT test enable\disable; fix missing overload
steveharter Jan 26, 2023
0a6ff32
Add TODOs based on review discussion; MLC field optimization
steveharter Jan 27, 2023
784df92
Merge branch 'main' into FcnPtr
jkotas Feb 1, 2023
8c06d3c
Replace nested signature indices by TypeSignature type
jkotas Jan 31, 2023
f40e506
Move tests into separate classes; other misc non-functional
steveharter Feb 13, 2023
4610e93
Throw NSE for modified type members than may return an unmodified type
steveharter Feb 14, 2023
ca45bd8
Merge branch 'main' of https://github.com/dotnet/runtime into FcnPtr
steveharter Feb 14, 2023
70529f0
Throw NSE on modified type Equals() and GetHashCode()
steveharter Feb 15, 2023
9770a2d
Fix tests for WASI
steveharter Feb 15, 2023
14a9007
Remove unnecessary high overhead tests
steveharter Feb 16, 2023
69ccd75
Merge branch 'main' of https://github.com/dotnet/runtime into FcnPtr
steveharter Feb 16, 2023
f76331c
Fix merge error
steveharter Feb 16, 2023
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
Prev Previous commit
Next Next commit
Throw NSE on modified type Equals() and GetHashCode()
  • Loading branch information
steveharter committed Feb 15, 2023
commit 70529f0e3ef3ee98b95a9a75be9572c485d6ada5
2 changes: 1 addition & 1 deletion src/coreclr/vm/runtimehandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ FCIMPL1(FC_BOOL_RET, RuntimeTypeHandle::IsUnmanagedFunctionPointer, ReflectClass
if (typeHandle.IsFnPtrType())
{
FnPtrTypeDesc* fnPtr = typeHandle.AsFnPtrType();
unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_UNMANAGED) == IMAGE_CEE_CS_CALLCONV_UNMANAGED;
unmanaged = (fnPtr->GetCallConv() & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_UNMANAGED;
}

FC_RETURN_BOOL(unmanaged);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ public static unsafe void UnmanagedCallConvs_Return_Modified()
Assert.True(fcnPtr2.IsUnmanagedFunctionPointer);

Assert.NotSame(fcnPtr1, fcnPtr2);
Assert.False(fcnPtr1.IsFunctionPointerEqual(fcnPtr2));

Type retType = fcnPtr1.GetFunctionPointerReturnType();
Assert.True(typeof(int).Project().IsFunctionPointerEqual(retType.UnderlyingSystemType));
Expand Down
19 changes: 6 additions & 13 deletions src/libraries/Common/tests/System/FunctionPointerEqualityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,12 @@ public static unsafe void ObjectEquals_ModifiedTypes()

MethodInfo m1 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue1), Bindings);
Type t1 = m1.ReturnParameter.GetModifiedParameterType();
Assert.NotSame(t1, t1.UnderlyingSystemType);

MethodInfo m2 = holder.GetMethod(nameof(FunctionPointerHolder.MethodIntReturnValue2), Bindings);
Type t2 = m2.ReturnParameter.GetModifiedParameterType();

Assert.False(ReferenceEquals(t1, t1.UnderlyingSystemType));

// Modified types do not support Equals other than when references are equal.
Assert.True(t1.Equals(t1));
Assert.False(t1.Equals(t2));
Assert.False(((object)t1).Equals(t2));
Assert.False(t1.Equals((object)t2));
Assert.NotSame(t1, t2);
}

[Fact]
Expand All @@ -64,11 +59,8 @@ public static unsafe void ObjectEquals_OneSideModifiedType()
Type modifiedType = m1.ReturnParameter.GetModifiedParameterType();
Type t = typeof(int).Project();

Assert.False(ReferenceEquals(modifiedType, modifiedType.UnderlyingSystemType));
Assert.False(ReferenceEquals(modifiedType, t));
Assert.False(modifiedType.Equals(t));
Assert.False(((object)modifiedType).Equals(t));
Assert.False(modifiedType.Equals((object)t));
Assert.NotSame(modifiedType, modifiedType.UnderlyingSystemType);
Assert.NotSame(modifiedType, t);
}

[Theory]
Expand Down Expand Up @@ -166,7 +158,8 @@ public static unsafe void CallingConvention_Modified(string methodName1, string
Type fnPtrType1 = m1.GetParameters()[0].GetModifiedParameterType();
Type fnPtrType2 = m2.GetParameters()[0].GetModifiedParameterType();

Assert.True(fnPtrType1.IsFunctionPointerNotEqual(fnPtrType2));
// Modified types don't support Equals, so just verify instance.
Assert.NotSame(fnPtrType1, fnPtrType2);
}

private unsafe class FunctionPointerHolder
Expand Down
11 changes: 5 additions & 6 deletions src/libraries/Common/tests/System/FunctionPointerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public static unsafe void TypeMembers()
Assert.Equal(TypeAttributes.Public, t.Attributes);
Assert.Null(t.BaseType);
Assert.False(t.ContainsGenericParameters);
Assert.False(t.ContainsGenericParameters);
Assert.False(t.DeclaredConstructors.Any());
Assert.False(t.DeclaredEvents.Any());
Assert.False(t.DeclaredFields.Any());
Expand Down Expand Up @@ -233,11 +232,11 @@ public static unsafe void Property(string name, string expectedToString)

Type fnPtrType = p.PropertyType;
Assert.Equal(expectedToString, fnPtrType.ToString());
VerifyFieldOrProperty(fnPtrType, isModified: false);
VerifyFieldOrProperty(fnPtrType);

fnPtrType = p.GetModifiedPropertyType();
Assert.Equal(expectedToString, fnPtrType.ToString());
VerifyFieldOrProperty(fnPtrType, isModified: true);
VerifyFieldOrProperty(fnPtrType);
}

[Theory]
Expand All @@ -253,14 +252,14 @@ public static unsafe void Field(string name, string expectedToString)

Type fnPtrType = f.FieldType;
Assert.Equal(expectedToString, fnPtrType.ToString());
VerifyFieldOrProperty(fnPtrType, isModified: false);
VerifyFieldOrProperty(fnPtrType);

fnPtrType = f.GetModifiedFieldType();
Assert.Equal(expectedToString, fnPtrType.ToString());
VerifyFieldOrProperty(fnPtrType, isModified: true);
VerifyFieldOrProperty(fnPtrType);
}

private static void VerifyFieldOrProperty(Type fnPtrType, bool isModified)
private static void VerifyFieldOrProperty(Type fnPtrType)
{
Assert.Null(fnPtrType.FullName);
Assert.Null(fnPtrType.AssemblyQualifiedName);
Expand Down
6 changes: 6 additions & 0 deletions src/libraries/Common/tests/System/ModifiedTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ void UnmodifiedTypeMembers(Type t)
Assert.False(t.GetOptionalCustomModifiers().Any());
Assert.False(t.GetRequiredCustomModifiers().Any());
Assert.True(t.IsPrimitive);
Assert.True(((object)t).Equals(t));
Assert.True(t.Equals(t));
Assert.Equal(t.GetHashCode(), t.GetHashCode());
Assert.NotNull(t.BaseType);
Assert.Null(t.DeclaringType);
Assert.Null(t.ReflectedType);
Expand All @@ -132,6 +135,9 @@ void ModifiedTypeMembers(Type t)
Assert.False(t.GetOptionalCustomModifiers().Any());
Assert.True(t.GetRequiredCustomModifiers().Any()); // The volatile modifier.
Assert.True(t.IsPrimitive);
Assert.Throws<NotSupportedException>(() => ((object)t).Equals(t));
Assert.Throws<NotSupportedException>(() => t.Equals(t));
Assert.Throws<NotSupportedException>(() => t.GetHashCode());
Assert.Throws<NotSupportedException>(() => t.BaseType);
Assert.Throws<NotSupportedException>(() => t.DeclaringType);
Assert.Throws<NotSupportedException>(() => t.ReflectedType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,27 +65,12 @@ public override Type[] GetOptionalCustomModifiers()
return GetCustomModifiers(required: false);
}

// Modified types do not support Equals other than when references are equal.
// Modified types do not support Equals. That would need to include custom modifiers and any parameterized types recursively.
// UnderlyingSystemType.Equals() should should be used if basic equality is necessary.
// Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively.
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (!(obj is ModifiedType))
return false;

return ReferenceEquals(this, obj);
}

public override bool Equals(Type? other)
{
if (other is ModifiedType otherModifiedType)
{
return ReferenceEquals(this, otherModifiedType);
}
public override bool Equals([NotNullWhen(true)] object? obj) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
public override bool Equals(Type? other) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
public override int GetHashCode() => throw new NotSupportedException(SR.NotSupported_ModifiedType);

return false;
}
public override int GetHashCode() => _unmodifiedType.GetHashCode();
public override string ToString() => _unmodifiedType.ToString();
public override Type UnderlyingSystemType => _unmodifiedType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ internal abstract partial class RoModule
//
internal RoArrayType GetUniqueArrayType(RoType elementType)
{
return _szArrayDict.GetOrAdd(elementType, s_szArrayTypeFactory);
// Modified types do not support Equals\GetHashCode.
return elementType is RoModifiedType ?
s_szArrayTypeFactory(elementType) :
_szArrayDict.GetOrAdd(elementType, s_szArrayTypeFactory);
}
private static readonly Func<RoType, RoArrayType> s_szArrayTypeFactory = (e) => new RoArrayType(e, multiDim: false, rank: 1);
private readonly ConcurrentDictionary<RoType, RoArrayType> _szArrayDict = new ConcurrentDictionary<RoType, RoArrayType>();
Expand All @@ -22,7 +25,11 @@ internal RoArrayType GetUniqueArrayType(RoType elementType)
//
internal RoArrayType GetUniqueArrayType(RoType elementType, int rank)
{
return _mdArrayDict.GetOrAdd(new RoArrayType.Key(elementType, rank: rank), s_mdArrayTypeFactory);
// Modified types do not support Equals\GetHashCode.
RoArrayType.Key key = new(elementType, rank: rank);
return elementType is RoModifiedType ?
s_mdArrayTypeFactory(key) :
_mdArrayDict.GetOrAdd(key, s_mdArrayTypeFactory);
}
private static readonly Func<RoArrayType.Key, RoArrayType> s_mdArrayTypeFactory = (k) => new RoArrayType(k.ElementType, multiDim: true, rank: k.Rank);
private readonly ConcurrentDictionary<RoArrayType.Key, RoArrayType> _mdArrayDict = new ConcurrentDictionary<RoArrayType.Key, RoArrayType>();
Expand All @@ -32,7 +39,10 @@ internal RoArrayType GetUniqueArrayType(RoType elementType, int rank)
//
internal RoByRefType GetUniqueByRefType(RoType elementType)
{
return _byRefDict.GetOrAdd(elementType, s_byrefTypeFactory);
// Modified types do not support Equals\GetHashCode.
return elementType is RoModifiedType ?
s_byrefTypeFactory(elementType) :
_byRefDict.GetOrAdd(elementType, s_byrefTypeFactory);
}
private static readonly Func<RoType, RoByRefType> s_byrefTypeFactory = (e) => new RoByRefType(e);
private readonly ConcurrentDictionary<RoType, RoByRefType> _byRefDict = new ConcurrentDictionary<RoType, RoByRefType>();
Expand All @@ -42,7 +52,9 @@ internal RoByRefType GetUniqueByRefType(RoType elementType)
//
internal RoPointerType GetUniquePointerType(RoType elementType)
{
return _pointerDict.GetOrAdd(elementType, (e) => new RoPointerType(e));
return elementType is RoModifiedType ?
new RoPointerType(elementType) :
_pointerDict.GetOrAdd(elementType, (e) => new RoPointerType(e));
}
private readonly ConcurrentDictionary<RoType, RoPointerType> _pointerDict = new ConcurrentDictionary<RoType, RoPointerType>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,18 @@ public bool Equals(Key other)
return false;
for (int i = 0; i < GenericTypeArguments.Length; i++)
{
if (GenericTypeArguments[i] != other.GenericTypeArguments[i])
Type t1 = GenericTypeArguments[i];
Type t2 = other.GenericTypeArguments[i];

// Modified types do not support Equals\GetHashCode.
if (t1 is RoModifiedType || t2 is RoModifiedType)
{
return ReferenceEquals(t1, t2);
}
else if (t1 != t2)
{
return false;
}
}
return true;
}
Expand All @@ -43,7 +53,10 @@ public override int GetHashCode()
int hashCode = GenericTypeDefinition.GetHashCode();
for (int i = 0; i < GenericTypeArguments.Length; i++)
{
hashCode ^= GenericTypeArguments[i].GetHashCode();
RoType argType = GenericTypeArguments[i];
hashCode ^= argType is RoModifiedType ?
argType.UnderlyingSystemType.GetHashCode() :
argType.GetHashCode();
}
return hashCode;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,26 +110,12 @@ public override Type[] GetOptionalCustomModifiers()

public override Type UnderlyingSystemType => _unmodifiedType;

// Modified types do not support Equals other than when references are equal.
// Modified types do not support Equals. That would need to include custom modifiers and any parameterized types recursively.
// UnderlyingSystemType.Equals() should should be used if basic equality is necessary.
// Supporting Equals on a modified type would need to include custom modifiers and any parameterized types recursively.
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (!(obj is RoModifiedType))
return false;

return ReferenceEquals(this, obj);
}

public override bool Equals(Type? t)
{
if (!(t is RoModifiedType))
return false;

return ReferenceEquals(this, t);
}
public override bool Equals([NotNullWhen(true)] object? obj) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
public override bool Equals(Type? other) => throw new NotSupportedException(SR.NotSupported_ModifiedType);
public override int GetHashCode() => throw new NotSupportedException(SR.NotSupported_ModifiedType);

public override int GetHashCode() => _unmodifiedType.GetHashCode();
public override string ToString() => _unmodifiedType.ToString();
public sealed override bool IsEnum => _unmodifiedType.IsEnum;
protected sealed override bool IsPrimitiveImpl() => _unmodifiedType.IsPrimitive;
Expand Down