33
44using System . Collections . Generic ;
55
6+ using ILCompiler ;
7+
68using Internal . TypeSystem ;
79
10+ using Debug = System . Diagnostics . Debug ;
11+
812namespace 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 ) ) ;
0 commit comments