Skip to content

Commit 1c8d37a

Browse files
Use MethodTable.Of in generated valuetype methods (#83325)
I thought it might improve codegen, but the improvements are marginal. Still, contributes to dotnet/runtimelab#232.
1 parent e247ef3 commit 1c8d37a

File tree

3 files changed

+26
-27
lines changed

3 files changed

+26
-27
lines changed

src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,7 @@ internal static unsafe object IsInstanceOfInterface(EETypePtr pTargetType, objec
344344
//
345345
[MethodImpl(MethodImplOptions.InternalCall)]
346346
[RuntimeImport(RuntimeLibrary, "RhBoxAny")]
347-
private static extern unsafe object RhBoxAny(ref byte pData, MethodTable* pEEType);
347+
internal static extern unsafe object RhBoxAny(ref byte pData, MethodTable* pEEType);
348348

349349
internal static unsafe object RhBoxAny(ref byte pData, EETypePtr pEEType)
350350
=> RhBoxAny(ref pData, pEEType.ToPointer());
@@ -372,7 +372,7 @@ internal static unsafe string RhNewString(EETypePtr pEEType, int length)
372372

373373
[MethodImpl(MethodImplOptions.InternalCall)]
374374
[RuntimeImport(RuntimeLibrary, "RhBox")]
375-
private static extern unsafe object RhBox(MethodTable* pEEType, ref byte data);
375+
internal static extern unsafe object RhBox(MethodTable* pEEType, ref byte data);
376376

377377
internal static unsafe object RhBox(EETypePtr pEEType, ref byte data)
378378
=> RhBox(pEEType.ToPointer(), ref data);

src/coreclr/nativeaot/System.Private.CoreLib/src/System/ValueType.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
using System.Runtime;
1515
using System.Runtime.CompilerServices;
1616

17-
using Internal.Runtime.Augments;
17+
using Internal.Runtime;
1818

1919
using Debug = System.Diagnostics.Debug;
2020

@@ -39,15 +39,15 @@ public abstract class ValueType
3939
// This API is a bit awkward because we want to avoid burning more than one vtable slot on this.
4040
// When index == GetNumFields, this method is expected to return the number of fields of this
4141
// valuetype. Otherwise, it returns the offset and type handle of the index-th field on this type.
42-
internal virtual int __GetFieldHelper(int index, out EETypePtr eeType)
42+
internal virtual unsafe int __GetFieldHelper(int index, out MethodTable* mt)
4343
{
4444
// Value types that don't override this method will use the fast path that looks at bytes, not fields.
4545
Debug.Assert(index == GetNumFields);
46-
eeType = default;
46+
mt = default;
4747
return UseFastHelper;
4848
}
4949

50-
public override bool Equals([NotNullWhen(true)] object? obj)
50+
public override unsafe bool Equals([NotNullWhen(true)] object? obj)
5151
{
5252
if (obj == null || obj.GetEETypePtr() != this.GetEETypePtr())
5353
return false;
@@ -71,7 +71,7 @@ public override bool Equals([NotNullWhen(true)] object? obj)
7171
// Foreach field, box and call the Equals method.
7272
for (int i = 0; i < numFields; i++)
7373
{
74-
int fieldOffset = __GetFieldHelper(i, out EETypePtr fieldType);
74+
int fieldOffset = __GetFieldHelper(i, out MethodTable* fieldType);
7575

7676
// Fetch the value of the field on both types
7777
object thisField = RuntimeImports.RhBoxAny(ref Unsafe.Add(ref thisRawData, fieldOffset), fieldType);
@@ -102,22 +102,22 @@ public override int GetHashCode()
102102
return hashCode;
103103
}
104104

105-
private int GetHashCodeImpl()
105+
private unsafe int GetHashCodeImpl()
106106
{
107107
int numFields = __GetFieldHelper(GetNumFields, out _);
108108

109109
if (numFields == UseFastHelper)
110-
return FastGetValueTypeHashCodeHelper(this.GetEETypePtr(), ref this.GetRawData());
110+
return FastGetValueTypeHashCodeHelper(this.GetMethodTable(), ref this.GetRawData());
111111

112112
return RegularGetValueTypeHashCode(ref this.GetRawData(), numFields);
113113
}
114114

115-
private static int FastGetValueTypeHashCodeHelper(EETypePtr type, ref byte data)
115+
private static unsafe int FastGetValueTypeHashCodeHelper(MethodTable* type, ref byte data)
116116
{
117117
// Sanity check - if there are GC references, we should not be hashing bytes
118-
Debug.Assert(!type.HasPointers);
118+
Debug.Assert(!type->HasGCPointers);
119119

120-
int size = (int)type.ValueTypeSize;
120+
int size = (int)type->ValueTypeSize;
121121
int hashCode = 0;
122122

123123
for (int i = 0; i < size / 4; i++)
@@ -128,31 +128,31 @@ private static int FastGetValueTypeHashCodeHelper(EETypePtr type, ref byte data)
128128
return hashCode;
129129
}
130130

131-
private int RegularGetValueTypeHashCode(ref byte data, int numFields)
131+
private unsafe int RegularGetValueTypeHashCode(ref byte data, int numFields)
132132
{
133133
int hashCode = 0;
134134

135135
// We only take the hashcode for the first non-null field. That's what the CLR does.
136136
for (int i = 0; i < numFields; i++)
137137
{
138-
int fieldOffset = __GetFieldHelper(i, out EETypePtr fieldType);
138+
int fieldOffset = __GetFieldHelper(i, out MethodTable* fieldType);
139139
ref byte fieldData = ref Unsafe.Add(ref data, fieldOffset);
140140

141-
Debug.Assert(!fieldType.IsPointer);
141+
Debug.Assert(!fieldType->IsPointerType);
142142

143-
if (fieldType.ElementType == Internal.Runtime.EETypeElementType.Single)
143+
if (fieldType->ElementType == EETypeElementType.Single)
144144
{
145145
hashCode = Unsafe.As<byte, float>(ref fieldData).GetHashCode();
146146
}
147-
else if (fieldType.ElementType == Internal.Runtime.EETypeElementType.Double)
147+
else if (fieldType->ElementType == EETypeElementType.Double)
148148
{
149149
hashCode = Unsafe.As<byte, double>(ref fieldData).GetHashCode();
150150
}
151-
else if (fieldType.IsPrimitive)
151+
else if (fieldType->IsPrimitive)
152152
{
153153
hashCode = FastGetValueTypeHashCodeHelper(fieldType, ref fieldData);
154154
}
155-
else if (fieldType.IsValueType)
155+
else if (fieldType->IsValueType)
156156
{
157157
// We have no option but to box since this value type could have
158158
// GC pointers (we could find out if we want though), or fields of type Double/Single (we can't

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
namespace Internal.IL.Stubs
99
{
1010
/// <summary>
11-
/// Synthetic method override of "int ValueType.__GetFieldHelper(Int32, out EETypePtr)". This method is injected
11+
/// Synthetic method override of "int ValueType.__GetFieldHelper(Int32, out MethodTable*)". This method is injected
1212
/// into all value types that cannot have their Equals(object) and GetHashCode() methods operate on individual
1313
/// bytes. The purpose of the override is to provide access to the value types' fields and their types.
1414
/// </summary>
@@ -46,7 +46,7 @@ public override MethodSignature Signature
4646
{
4747
TypeSystemContext context = _owningType.Context;
4848
TypeDesc int32Type = context.GetWellKnownType(WellKnownType.Int32);
49-
TypeDesc eeTypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr");
49+
TypeDesc eeTypePtrType = context.SystemModule.GetKnownType("Internal.Runtime", "MethodTable").MakePointerType();
5050

5151
_signature = new MethodSignature(0, 0, int32Type, new[] {
5252
int32Type,
@@ -64,9 +64,8 @@ public override MethodIL EmitIL()
6464

6565
ILEmitter emitter = new ILEmitter();
6666

67-
TypeDesc eeTypePtrType = Context.SystemModule.GetKnownType("System", "EETypePtr");
68-
MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null);
69-
ILToken eeTypePtrToken = emitter.NewToken(eeTypePtrType);
67+
TypeDesc methodTableType = Context.SystemModule.GetKnownType("Internal.Runtime", "MethodTable");
68+
MethodDesc methodTableOfMethod = methodTableType.GetKnownMethod("Of", null);
7069

7170
var switchStream = emitter.NewCodeStream();
7271
var getFieldStream = emitter.NewCodeStream();
@@ -98,10 +97,10 @@ public override MethodIL EmitIL()
9897
// Don't unnecessarily create an MethodTable for the enum.
9998
boxableFieldType = boxableFieldType.UnderlyingType;
10099

101-
MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType);
102-
getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField));
100+
MethodDesc mtOfFieldMethod = methodTableOfMethod.MakeInstantiatedMethod(boxableFieldType);
101+
getFieldStream.Emit(ILOpcode.call, emitter.NewToken(mtOfFieldMethod));
103102

104-
getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken);
103+
getFieldStream.Emit(ILOpcode.stind_i);
105104

106105
getFieldStream.EmitLdArg(0);
107106
getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field));

0 commit comments

Comments
 (0)