Skip to content

Commit a7b101f

Browse files
Specialize __GetFieldHelper per generic instantiation (#117253)
1 parent d4ae57c commit a7b101f

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

src/coreclr/tools/Common/TypeSystem/IL/Stubs/ValueTypeGetFieldHelperMethodOverride.cs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,25 @@
33

44
using System.Collections.Generic;
55

6+
using ILCompiler;
7+
68
using Internal.TypeSystem;
79

10+
using Debug = System.Diagnostics.Debug;
11+
812
namespace Internal.IL.Stubs
913
{
1014
/// <summary>
1115
/// Synthetic method override of "int ValueType.__GetFieldHelper(Int32, out MethodTable*)". This method is injected
1216
/// into all value types that cannot have their Equals(object) and GetHashCode() methods operate on individual
1317
/// bytes. The purpose of the override is to provide access to the value types' fields and their types.
1418
/// </summary>
15-
public sealed partial class ValueTypeGetFieldHelperMethodOverride : ILStubMethod
19+
public sealed partial class ValueTypeGetFieldHelperMethodOverride : SpecializableILStubMethod
1620
{
17-
private DefType _owningType;
21+
private MetadataType _owningType;
1822
private MethodSignature _signature;
1923

20-
internal ValueTypeGetFieldHelperMethodOverride(DefType owningType)
24+
internal ValueTypeGetFieldHelperMethodOverride(MetadataType owningType)
2125
{
2226
_owningType = owningType;
2327
}
@@ -57,21 +61,29 @@ public override MethodSignature Signature
5761

5862
public override MethodIL EmitIL()
5963
{
60-
TypeDesc owningType = _owningType.InstantiateAsOpen();
64+
return EmitILCommon(null);
65+
}
66+
67+
public override MethodIL EmitIL(MethodDesc specializedMethod)
68+
{
69+
Debug.Assert(specializedMethod.GetTypicalMethodDefinition() == this);
70+
return new InstantiatedMethodIL(specializedMethod, EmitILCommon(specializedMethod));
71+
}
72+
73+
private MethodIL EmitILCommon(MethodDesc contextMethod)
74+
{
75+
var owningType = (MetadataType)_owningType.InstantiateAsOpen();
6176

6277
ILEmitter emitter = new ILEmitter();
6378

64-
if (_owningType is MetadataType mdType)
79+
// Types marked as InlineArray aren't supported by
80+
// the built-in Equals() or GetHashCode().
81+
if (owningType.IsInlineArray)
6582
{
66-
// Types marked as InlineArray aren't supported by
67-
// the built-in Equals() or GetHashCode().
68-
if (mdType.IsInlineArray)
69-
{
70-
var stream = emitter.NewCodeStream();
71-
MethodDesc thrower = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowNotSupportedInlineArrayEqualsGetHashCode");
72-
stream.EmitCallThrowHelper(emitter, thrower);
73-
return emitter.Link(this);
74-
}
83+
var stream = emitter.NewCodeStream();
84+
MethodDesc thrower = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowNotSupportedInlineArrayEqualsGetHashCode");
85+
stream.EmitCallThrowHelper(emitter, thrower);
86+
return emitter.Link(this);
7587
}
7688

7789
TypeDesc methodTableType = Context.SystemModule.GetKnownType("Internal.Runtime", "MethodTable");
@@ -95,20 +107,27 @@ public override MethodIL EmitIL()
95107
getFieldStream.EmitLabel(label);
96108
getFieldStream.EmitLdArg(2);
97109

98-
// We need something we can instantiate EETypePtrOf over. Also, the classlib
110+
// We need something we can instantiate MethodTable.Of over. Also, the classlib
99111
// code doesn't handle pointers.
100112
TypeDesc boxableFieldType = field.FieldType;
101113
if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer)
102114
boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr);
103115

116+
// We're trying to do some optimizations below that can benefit from knowing the concrete
117+
// type after substitutions.
118+
TypeDesc fieldTypeForOptimizationChecks = boxableFieldType.IsSignatureVariable
119+
? boxableFieldType.InstantiateSignature(contextMethod.OwningType.Instantiation, default)
120+
: boxableFieldType;
121+
104122
// The fact that the type is a reference type is sufficient for the callers.
105-
// Don't unnecessarily create an MethodTable for the field type.
106-
if (!boxableFieldType.IsSignatureVariable && !boxableFieldType.IsValueType)
123+
// Don't unnecessarily create a MethodTable for the field type.
124+
if (!fieldTypeForOptimizationChecks.IsValueType)
107125
boxableFieldType = Context.GetWellKnownType(WellKnownType.Object);
108126

109127
// If this is an enum, it's okay to Equals/GetHashCode the underlying type.
110-
// Don't unnecessarily create an MethodTable for the enum.
111-
boxableFieldType = boxableFieldType.UnderlyingType;
128+
// Don't unnecessarily create a MethodTable for the enum.
129+
if (fieldTypeForOptimizationChecks.IsEnum)
130+
boxableFieldType = fieldTypeForOptimizationChecks.UnderlyingType;
112131

113132
MethodDesc mtOfFieldMethod = methodTableOfMethod.MakeInstantiatedMethod(boxableFieldType);
114133
getFieldStream.Emit(ILOpcode.call, emitter.NewToken(mtOfFieldMethod));

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/CompilerTypeSystemContext.ValueTypeMethods.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ public partial class CompilerTypeSystemContext
1616
private MethodDesc _objectEqualsMethod;
1717
private MetadataType _iAsyncStateMachineType;
1818

19-
private sealed class ValueTypeMethodHashtable : LockFreeReaderHashtable<DefType, MethodDesc>
19+
private sealed class ValueTypeMethodHashtable : LockFreeReaderHashtable<MetadataType, MethodDesc>
2020
{
21-
protected override int GetKeyHashCode(DefType key) => key.GetHashCode();
21+
protected override int GetKeyHashCode(MetadataType key) => key.GetHashCode();
2222
protected override int GetValueHashCode(MethodDesc value) => value.OwningType.GetHashCode();
23-
protected override bool CompareKeyToValue(DefType key, MethodDesc value) => key == value.OwningType;
23+
protected override bool CompareKeyToValue(MetadataType key, MethodDesc value) => key == value.OwningType;
2424
protected override bool CompareValueToValue(MethodDesc v1, MethodDesc v2) => v1.OwningType == v2.OwningType;
2525

26-
protected override MethodDesc CreateValueFromKey(DefType key)
26+
protected override MethodDesc CreateValueFromKey(MetadataType key)
2727
{
2828
return new ValueTypeGetFieldHelperMethodOverride(key);
2929
}
@@ -37,7 +37,7 @@ protected virtual IEnumerable<MethodDesc> GetAllMethodsForValueType(TypeDesc val
3737

3838
if (RequiresValueTypeGetFieldHelperMethod((MetadataType)valueTypeDefinition))
3939
{
40-
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((DefType)valueTypeDefinition);
40+
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((MetadataType)valueTypeDefinition);
4141

4242
if (valueType != valueTypeDefinition)
4343
{
@@ -60,7 +60,7 @@ protected virtual IEnumerable<MethodDesc> GetAllMethodsForAttribute(TypeDesc att
6060

6161
if (RequiresAttributeGetFieldHelperMethod(attributeTypeDefinition))
6262
{
63-
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((DefType)attributeTypeDefinition);
63+
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((MetadataType)attributeTypeDefinition);
6464

6565
if (attributeType != attributeTypeDefinition)
6666
{

0 commit comments

Comments
 (0)