Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@

using System.Collections.Generic;

using ILCompiler;

using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace Internal.IL.Stubs
{
/// <summary>
/// Synthetic method override of "int ValueType.__GetFieldHelper(Int32, out MethodTable*)". This method is injected
/// into all value types that cannot have their Equals(object) and GetHashCode() methods operate on individual
/// bytes. The purpose of the override is to provide access to the value types' fields and their types.
/// </summary>
public sealed partial class ValueTypeGetFieldHelperMethodOverride : ILStubMethod
public sealed partial class ValueTypeGetFieldHelperMethodOverride : SpecializableILStubMethod
{
private DefType _owningType;
private MetadataType _owningType;
private MethodSignature _signature;

internal ValueTypeGetFieldHelperMethodOverride(DefType owningType)
internal ValueTypeGetFieldHelperMethodOverride(MetadataType owningType)
{
_owningType = owningType;
}
Expand Down Expand Up @@ -57,21 +61,29 @@ public override MethodSignature Signature

public override MethodIL EmitIL()
{
TypeDesc owningType = _owningType.InstantiateAsOpen();
return EmitILCommon(null);
}

public override MethodIL EmitIL(MethodDesc specializedMethod)
{
Debug.Assert(specializedMethod.GetTypicalMethodDefinition() == this);
return new InstantiatedMethodIL(specializedMethod, EmitILCommon(specializedMethod));
}

private MethodIL EmitILCommon(MethodDesc contextMethod)
{
var owningType = (MetadataType)_owningType.InstantiateAsOpen();

ILEmitter emitter = new ILEmitter();

if (_owningType is MetadataType mdType)
// Types marked as InlineArray aren't supported by
// the built-in Equals() or GetHashCode().
if (owningType.IsInlineArray)
{
// Types marked as InlineArray aren't supported by
// the built-in Equals() or GetHashCode().
if (mdType.IsInlineArray)
{
var stream = emitter.NewCodeStream();
MethodDesc thrower = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowNotSupportedInlineArrayEqualsGetHashCode");
stream.EmitCallThrowHelper(emitter, thrower);
return emitter.Link(this);
}
var stream = emitter.NewCodeStream();
MethodDesc thrower = Context.GetHelperEntryPoint("ThrowHelpers", "ThrowNotSupportedInlineArrayEqualsGetHashCode");
stream.EmitCallThrowHelper(emitter, thrower);
return emitter.Link(this);
}

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

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

// We're trying to do some optimizations below that can benefit from knowing the concrete
// type after substitutions.
TypeDesc fieldTypeForOptimizationChecks = boxableFieldType.IsSignatureVariable
? boxableFieldType.InstantiateSignature(contextMethod.OwningType.Instantiation, default)
: boxableFieldType;

// The fact that the type is a reference type is sufficient for the callers.
// Don't unnecessarily create an MethodTable for the field type.
if (!boxableFieldType.IsSignatureVariable && !boxableFieldType.IsValueType)
// Don't unnecessarily create a MethodTable for the field type.
if (!fieldTypeForOptimizationChecks.IsValueType)
boxableFieldType = Context.GetWellKnownType(WellKnownType.Object);

// If this is an enum, it's okay to Equals/GetHashCode the underlying type.
// Don't unnecessarily create an MethodTable for the enum.
boxableFieldType = boxableFieldType.UnderlyingType;
// Don't unnecessarily create a MethodTable for the enum.
if (fieldTypeForOptimizationChecks.IsEnum)
boxableFieldType = fieldTypeForOptimizationChecks.UnderlyingType;

MethodDesc mtOfFieldMethod = methodTableOfMethod.MakeInstantiatedMethod(boxableFieldType);
getFieldStream.Emit(ILOpcode.call, emitter.NewToken(mtOfFieldMethod));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ public partial class CompilerTypeSystemContext
private MethodDesc _objectEqualsMethod;
private MetadataType _iAsyncStateMachineType;

private sealed class ValueTypeMethodHashtable : LockFreeReaderHashtable<DefType, MethodDesc>
private sealed class ValueTypeMethodHashtable : LockFreeReaderHashtable<MetadataType, MethodDesc>
{
protected override int GetKeyHashCode(DefType key) => key.GetHashCode();
protected override int GetKeyHashCode(MetadataType key) => key.GetHashCode();
protected override int GetValueHashCode(MethodDesc value) => value.OwningType.GetHashCode();
protected override bool CompareKeyToValue(DefType key, MethodDesc value) => key == value.OwningType;
protected override bool CompareKeyToValue(MetadataType key, MethodDesc value) => key == value.OwningType;
protected override bool CompareValueToValue(MethodDesc v1, MethodDesc v2) => v1.OwningType == v2.OwningType;

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

if (RequiresValueTypeGetFieldHelperMethod((MetadataType)valueTypeDefinition))
{
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((DefType)valueTypeDefinition);
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((MetadataType)valueTypeDefinition);

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

if (RequiresAttributeGetFieldHelperMethod(attributeTypeDefinition))
{
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((DefType)attributeTypeDefinition);
MethodDesc getFieldHelperMethod = _valueTypeMethodHashtable.GetOrCreateValue((MetadataType)attributeTypeDefinition);

if (attributeType != attributeTypeDefinition)
{
Expand Down
Loading