READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 2
};
+enum ReadyToRunHFAElemType : DWORD
+{
+ READYTORUN_HFA_ELEMTYPE_None = 0,
+ READYTORUN_HFA_ELEMTYPE_Float32 = 1,
+ READYTORUN_HFA_ELEMTYPE_Float64 = 2,
+ READYTORUN_HFA_ELEMTYPE_Vector64 = 3,
+ READYTORUN_HFA_ELEMTYPE_Vector128 = 4,
+};
+
#endif // __READYTORUN_H__
TypeHandleToRuntimeTypeHandle,
}
+ // Enum used for HFA type recognition.
+ // Supported across architectures, so that it can be used in altjits and cross-compilation.
+ public enum ReadyToRunHFAElemType
+ {
+ None = 0,
+ Float32 = 1,
+ Float64 = 2,
+ Vector64 = 3,
+ Vector128 = 4,
+ }
+
public static class ReadyToRunRuntimeConstants
{
public const int READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11;
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using System.Diagnostics;
using Internal.JitInterface;
using Internal.Text;
{
public class FieldFixupSignature : Signature
{
+ public const int MaxCheckableOffset = 0x1FFFFFFF;
private readonly ReadyToRunFixupKind _fixupKind;
private readonly FieldDesc _fieldDesc;
- public FieldFixupSignature(ReadyToRunFixupKind fixupKind, FieldDesc fieldDesc)
+ public FieldFixupSignature(ReadyToRunFixupKind fixupKind, FieldDesc fieldDesc, NodeFactory factory)
{
_fixupKind = fixupKind;
_fieldDesc = fieldDesc;
// Ensure types in signature are loadable and resolvable, otherwise we'll fail later while emitting the signature
((CompilerTypeSystemContext)fieldDesc.Context).EnsureLoadableType(fieldDesc.OwningType);
+ Debug.Assert(factory.SignatureContext.GetTargetModule(_fieldDesc) != null);
}
public override int ClassCode => 271828182;
if (defType.IsHomogeneousAggregate)
{
- CorElementType elementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
+ ReadyToRunHFAElemType hfaElementType = (defType.ValueTypeShapeCharacteristics & ValueTypeShapeCharacteristics.AggregateMask) switch
{
- ValueTypeShapeCharacteristics.Float32Aggregate => CorElementType.ELEMENT_TYPE_R4,
- ValueTypeShapeCharacteristics.Float64Aggregate => CorElementType.ELEMENT_TYPE_R8,
- ValueTypeShapeCharacteristics.Vector64Aggregate => CorElementType.ELEMENT_TYPE_R8,
+ ValueTypeShapeCharacteristics.Float32Aggregate => ReadyToRunHFAElemType.Float32,
+ ValueTypeShapeCharacteristics.Float64Aggregate => ReadyToRunHFAElemType.Float64,
+ ValueTypeShapeCharacteristics.Vector64Aggregate => ReadyToRunHFAElemType.Vector64,
// See MethodTable::GetHFAType
- ValueTypeShapeCharacteristics.Vector128Aggregate => CorElementType.ELEMENT_TYPE_VALUETYPE,
- _ => CorElementType.Invalid
+ ValueTypeShapeCharacteristics.Vector128Aggregate => ReadyToRunHFAElemType.Vector128,
+ _ => throw new NotSupportedException()
};
- dataBuilder.EmitUInt((uint)elementType);
+ dataBuilder.EmitUInt((uint)hfaElementType);
}
if (alignment != pointerSize)
_codegenNodeFactory,
_codegenNodeFactory.HelperImports,
ReadyToRunHelper.DelayLoad_Helper,
- new FieldFixupSignature(ReadyToRunFixupKind.FieldAddress, key)
+ new FieldFixupSignature(ReadyToRunFixupKind.FieldAddress, key, _codegenNodeFactory)
);
});
{
return new PrecodeHelperImport(
_codegenNodeFactory,
- new FieldFixupSignature(ReadyToRunFixupKind.FieldOffset, key)
+ new FieldFixupSignature(ReadyToRunFixupKind.FieldOffset, key, _codegenNodeFactory)
);
});
{
return new PrecodeHelperImport(
_codegenNodeFactory,
- new FieldFixupSignature(_verifyTypeAndFieldLayout ? ReadyToRunFixupKind.Verify_FieldOffset : ReadyToRunFixupKind.Check_FieldOffset, key)
+ new FieldFixupSignature(_verifyTypeAndFieldLayout ? ReadyToRunFixupKind.Verify_FieldOffset : ReadyToRunFixupKind.Check_FieldOffset, key, _codegenNodeFactory)
);
});
{
return new PrecodeHelperImport(
_codegenNodeFactory,
- new FieldFixupSignature(ReadyToRunFixupKind.FieldHandle, field));
+ new FieldFixupSignature(ReadyToRunFixupKind.FieldHandle, field, _codegenNodeFactory));
}
private ISymbolNode CreateCctorTrigger(TypeDesc type)
CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE);
}
- if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+ if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset))
{
// ENCODE_CHECK_FIELD_OFFSET
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
else
if (helperId != ReadyToRunHelperId.Invalid)
{
- if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+ if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset))
{
// ENCODE_CHECK_FIELD_OFFSET
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
if (!type.IsValueType)
return false;
- return !_compilation.IsLayoutFixedInCurrentVersionBubble(type) || _compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout;
+ return !_compilation.IsLayoutFixedInCurrentVersionBubble(type) || (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !((MetadataType)type).IsNonVersionable());
}
private bool HasLayoutMetadata(TypeDesc type)
if (pMT.IsValueType)
{
// ENCODE_CHECK_FIELD_OFFSET
+ if (pResult->offset > FieldFixupSignature.MaxCheckableOffset)
+ throw new RequiresRuntimeJitException(callerMethod.ToString() + " -> " + field.ToString());
+
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
// No-op other than generating the check field offset fixup
}
}
else if (pMT.IsValueType)
{
- if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+ if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset))
{
// ENCODE_CHECK_FIELD_OFFSET
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
}
else if (_compilation.IsInheritanceChainLayoutFixedInCurrentVersionBubble(pMT.BaseType))
{
- if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+ if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset))
{
// ENCODE_CHECK_FIELD_OFFSET
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
{
PreventRecursiveFieldInlinesOutsideVersionBubble(field, callerMethod);
- if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout)
+ if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && !callerMethod.IsNonVersionable() && (pResult->offset <= FieldFixupSignature.MaxCheckableOffset))
{
// ENCODE_CHECK_FIELD_OFFSET
_methodCodeNode.Fixups.Add(_compilation.SymbolNodeFactory.CheckFieldOffset(field));
}
else
{
- isBlittable = !valueTypeHandle.GetMethodTable()->HasInstantiation() && valueTypeHandle.GetMethodTable()->IsBlittable();
+ isBlittable = valueTypeHandle.GetMethodTable()->IsBlittable();
}
break;
default:
DWORD baseOffset = CorSigUncompressData(pBlob);
DWORD fieldOffset = CorSigUncompressData(pBlob);
FieldDesc* pField = ZapSig::DecodeField(currentModule, pInfoModule, pBlob);
- pField->GetEnclosingMethodTable()->CheckRestore();
+ MethodTable *pEnclosingMT = pField->GetApproxEnclosingMethodTable();
+ pEnclosingMT->CheckRestore();
DWORD actualFieldOffset = pField->GetOffset();
if (!pField->IsStatic() && !pField->IsFieldOfValueType())
{
DWORD actualBaseOffset = 0;
if (!pField->IsStatic() &&
- pField->GetEnclosingMethodTable()->GetParentMethodTable() != NULL &&
- !pField->GetEnclosingMethodTable()->IsValueType())
+ pEnclosingMT->GetParentMethodTable() != NULL &&
+ !pEnclosingMT->IsValueType())
{
- actualBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pField->GetEnclosingMethodTable());
+ actualBaseOffset = ReadyToRunInfo::GetFieldBaseOffset(pEnclosingMT);
}
if ((fieldOffset != actualFieldOffset) || (baseOffset != actualBaseOffset))
SString fatalErrorString;
fatalErrorString.Printf(W("Verify_FieldOffset '%s.%s' %d!=%d || %d!=%d"),
- GetFullyQualifiedNameForClassW(pField->GetEnclosingMethodTable()),
+ GetFullyQualifiedNameForClassW(pEnclosingMT),
ssFieldName.GetUnicode(),
fieldOffset,
actualFieldOffset,
//
static_assert_no_msg(sizeof(READYTORUN_EXCEPTION_LOOKUP_TABLE_ENTRY) == sizeof(CORCOMPILE_EXCEPTION_LOOKUP_TABLE_ENTRY));
static_assert_no_msg(sizeof(READYTORUN_EXCEPTION_CLAUSE) == sizeof(CORCOMPILE_EXCEPTION_CLAUSE));
+
+//
+// ReadyToRunHFAElemType
+//
+static_assert_no_msg((int)READYTORUN_HFA_ELEMTYPE_None == (int)CORINFO_HFA_ELEM_NONE);
+static_assert_no_msg((int)READYTORUN_HFA_ELEMTYPE_Float32 == (int)CORINFO_HFA_ELEM_FLOAT);
+static_assert_no_msg((int)READYTORUN_HFA_ELEMTYPE_Float64 == (int)CORINFO_HFA_ELEM_DOUBLE);
+static_assert_no_msg((int)READYTORUN_HFA_ELEMTYPE_Vector64 == (int)CORINFO_HFA_ELEM_VECTOR64);
+static_assert_no_msg((int)READYTORUN_HFA_ELEMTYPE_Vector128 == (int)CORINFO_HFA_ELEM_VECTOR128);
+
echo -r:$CORE_ROOT/System.*.dll>>$__ResponseFile
echo -r:$CORE_ROOT/Microsoft.*.dll>>$__ResponseFile
echo -r:$CORE_ROOT/mscorlib.dll>>$__ResponseFile
+ echo --verify-type-and-field-layout>>$__ResponseFile
echo --targetarch:$(TargetArchitecture)>>$__ResponseFile
echo -O>>$__ResponseFile
echo !__InputFile!>>!__ResponseFile!
echo -o:!__OutputFile!>>!__ResponseFile!
echo --targetarch:$(TargetArchitecture)>>!__ResponseFile!
+ echo --verify-type-and-field-layout>>!__ResponseFile!
echo -O>>!__ResponseFile!
echo -r:!CORE_ROOT!\System.*.dll>>!__ResponseFile!
echo -r:!CORE_ROOT!\Microsoft.*.dll>>!__ResponseFile!
return true;
}
+ [StructLayout(LayoutKind.Explicit)]
+ struct ExplicitLayoutStruct16
+ {
+ [FieldOffset(0)]
+ public int x;
+ [FieldOffset(4)]
+ public int y;
+ [FieldOffset(8)]
+ public int z;
+ [FieldOffset(12)]
+ public int w;
+ public override string ToString() { return $"{x}{y}{z}{w}"; }
+ }
+ struct BlittableStruct<T>
+ {
+ public ExplicitLayoutStruct16 _explict;
+ public override string ToString() { return $"{_explict}"; }
+ }
+
+ struct StructWithGenericBlittableStruct
+ {
+ public BlittableStruct<short> _blittableGeneric;
+ public int _int;
+ public override string ToString() { return $"{_blittableGeneric}{_int}"; }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveOptimization)]
+ private static bool TestWithStructureNonBlittableFieldDueToGenerics_StringCompare(ref StructWithGenericBlittableStruct input)
+ {
+ StructWithGenericBlittableStruct s = new StructWithGenericBlittableStruct();
+ s._blittableGeneric._explict.x = 1;
+ s._blittableGeneric._explict.y = 2;
+ s._blittableGeneric._explict.z = 3;
+ s._blittableGeneric._explict.w = 4;
+ s._int = 5;
+
+ Console.WriteLine(input);
+ Console.WriteLine(s);
+
+ return s.Equals(input) && input.ToString() == "12345";
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static bool TestWithStructureNonBlittableFieldDueToGenerics()
+ {
+ StructWithGenericBlittableStruct s = new StructWithGenericBlittableStruct();
+ s._blittableGeneric._explict.x = 1;
+ s._blittableGeneric._explict.y = 2;
+ s._blittableGeneric._explict.z = 3;
+ s._blittableGeneric._explict.w = 4;
+ s._int = 5;
+
+ return TestWithStructureNonBlittableFieldDueToGenerics_StringCompare(ref s);
+ }
+
public static int Main(string[] args)
{
_passedTests = new List<string>();
RunTest("GenericLdtokenTest", GenericLdtokenTest());
RunTest("ArrayLdtokenTests", ArrayLdtokenTests());
RunTest("TestGenericMDArrayBehavior", TestGenericMDArrayBehavior());
+ RunTest("TestWithStructureNonBlittableFieldDueToGenerics", TestWithStructureNonBlittableFieldDueToGenerics());
File.Delete(TextFileName);