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
6 changes: 6 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ partial interface IRuntimeTypeSystem : IContract
public virtual bool IsString(TypeHandle typeHandle);
// True if the MethodTable represents a type that contains managed references
public virtual bool ContainsGCPointers(TypeHandle typeHandle);
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
public virtual bool RequiresAlign8(TypeHandle typeHandle);
// True if the MethodTable represents a continuation type used by the async continuation feature
public virtual bool IsContinuation(TypeHandle typeHandle);
public virtual bool IsDynamicStatics(TypeHandle typeHandle);
Expand Down Expand Up @@ -273,6 +275,7 @@ internal partial struct RuntimeTypeSystem_1
Category_TruePrimitive = 0x00070000,
Category_Interface = 0x000C0000,
Collectible = 0x00200000,
RequiresAlign8 = 0x00800000,
ContainsGCPointers = 0x01000000,
ContainsGenericVariables = 0x20000000,
HasComponentSize = 0x80000000, // This is set if lower 16 bits is used for the component size,
Expand Down Expand Up @@ -319,6 +322,7 @@ internal partial struct RuntimeTypeSystem_1
public ushort ComponentSize => HasComponentSize ? ComponentSizeBits : (ushort)0;
public bool HasInstantiation => !TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_NonGeneric);
public bool ContainsGCPointers => GetFlag(WFLAGS_HIGH.ContainsGCPointers) != 0;
public bool RequiresAlign8 => GetFlag(WFLAGS_HIGH.RequiresAlign8) != 0;
public bool IsCollectible => GetFlag(WFLAGS_HIGH.Collectible) != 0;
public bool IsDynamicStatics => GetFlag(WFLAGS2_ENUM.DynamicStatics) != 0;
public bool IsGenericTypeDefinition => TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_TypicalInstantiation);
Expand Down Expand Up @@ -540,6 +544,8 @@ Contracts used:

public bool ContainsGCPointers(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[TypeHandle.Address].Flags.ContainsGCPointers;

public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;

public bool IsDynamicStatics(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[TypeHandle.Address].Flags.IsDynamicStatics;

public ushort GetNumInterfaces(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? 0 : _methodTables[TypeHandle.Address].NumInterfaces;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -3819,7 +3819,7 @@ public :
// enum_flag_unused = 0x00400000,

#ifdef FEATURE_64BIT_ALIGNMENT
enum_flag_RequiresAlign8 = 0x00800000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
enum_flag_RequiresAlign8 = 0x00800000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly) [cDAC] [RuntimeTypeSystem]: Contract depends on this value
#endif

enum_flag_ContainsGCPointers = 0x01000000, // Contains object references. [cDAC] [RuntimeTypeSystem]: Contract depends on this value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ public interface IRuntimeTypeSystem : IContract
bool IsString(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a type that contains managed references
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
bool RequiresAlign8(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a continuation type used by the async continuation feature
bool IsContinuation(TypeHandle typeHandle) => throw new NotImplementedException();
bool IsDynamicStatics(TypeHandle typeHandle) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ private Data.EEClass GetClassData(TypeHandle typeHandle)

public bool IsString(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsString;
public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
&& _continuationMethodTablePointer != TargetPointer.Null
&& _methodTables[typeHandle.Address].ParentMethodTable == _continuationMethodTablePointer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ internal enum WFLAGS_HIGH : uint
Category_TruePrimitive = 0x00070000,
Category_Interface = 0x000C0000,
Collectible = 0x00200000, // GC depends on this bit.
RequiresAlign8 = 0x00800000,

ContainsGCPointers = 0x01000000,
ContainsGenericVariables = 0x20000000,
Expand Down Expand Up @@ -99,6 +100,7 @@ private bool TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag)
public ushort ComponentSize => HasComponentSize ? ComponentSizeBits : (ushort)0;
public bool HasInstantiation => !TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_NonGeneric);
public bool ContainsGCPointers => GetFlag(WFLAGS_HIGH.ContainsGCPointers) != 0;
public bool RequiresAlign8 => GetFlag(WFLAGS_HIGH.RequiresAlign8) != 0;
public bool IsCollectible => GetFlag(WFLAGS_HIGH.Collectible) != 0;
public bool IsDynamicStatics => GetFlag(WFLAGS2_ENUM.DynamicStatics) != 0;
public bool IsGenericTypeDefinition => TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_TypicalInstantiation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,40 @@ public int GetVarArgSig(ulong VASigCookieAddr, ulong* pArgBase, DacDbiTargetBuff
=> _legacy is not null ? _legacy.GetVarArgSig(VASigCookieAddr, pArgBase, pRetVal) : HResults.E_NOTIMPL;

public int RequiresAlign8(ulong thExact, Interop.BOOL* pResult)
=> _legacy is not null ? _legacy.RequiresAlign8(thExact, pResult) : HResults.E_NOTIMPL;
{
*pResult = Interop.BOOL.FALSE;
int hr = HResults.S_OK;
RuntimeInfoArchitecture arch = _target.Contracts.RuntimeInfo.GetTargetArchitecture();
try
{
// Some 32-bit platform ABIs require 64-bit alignment (FEATURE_64BIT_ALIGNMENT).
if (arch == RuntimeInfoArchitecture.Arm || arch == RuntimeInfoArchitecture.Wasm)
{
Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
Contracts.TypeHandle th = rts.GetTypeHandle(new TargetPointer(thExact));
*pResult = rts.RequiresAlign8(th) ? Interop.BOOL.TRUE : Interop.BOOL.FALSE;
}
else
{
throw new NotImplementedException();
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
Comment thread
barosiak marked this conversation as resolved.
}
#if DEBUG
if (_legacy is not null)
{
Interop.BOOL resultLocal;
int hrLocal = _legacy.RequiresAlign8(thExact, &resultLocal);
Comment thread
barosiak marked this conversation as resolved.
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
Debug.Assert(*pResult == resultLocal, $"cDAC: {*pResult}, DAC: {resultLocal}");
}
#endif
return hr;
}

public int ResolveExactGenericArgsToken(uint dwExactGenericArgsTokenIndex, ulong rawToken, ulong* pRetVal)
=> _legacy is not null ? _legacy.ResolveExactGenericArgsToken(dwExactGenericArgsTokenIndex, rawToken, pRetVal) : HResults.E_NOTIMPL;
Expand Down
43 changes: 43 additions & 0 deletions src/native/managed/cdac/tests/MethodTableTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ internal static (string Name, ulong Value)[] CreateContractGlobals(MockRTS rtsBu
(nameof(Constants.Globals.ArrayBaseSize), rtsBuilder.ArrayBaseSize),
];

public static IEnumerable<object[]> StdArchBool()
{
foreach (object[] arch in new MockTarget.StdArch())
{
yield return [.. arch, true];
yield return [.. arch, false];
}
}

internal static TestPlaceholderTarget CreateTarget(MockTarget.Architecture arch, Action<MockRTS> configure)
{
var targetBuilder = new TestPlaceholderTarget.Builder(arch);
Expand Down Expand Up @@ -499,4 +508,38 @@ public void ValidateContinuationMethodTablePointer(MockTarget.Architecture arch)
Assert.Equal(continuationInstanceMethodTablePtr.Value, continuationTypeHandle.Address.Value);
Assert.True(contract.IsContinuation(continuationTypeHandle));
}

[Theory]
[MemberData(nameof(StdArchBool))]
public void RequiresAlign8(MockTarget.Architecture arch, bool flagSet)
{
TargetPointer methodTablePtr = default;
TestPlaceholderTarget target = CreateTarget(
arch,
rtsBuilder =>
{
if (flagSet)
{
MockEEClass eeClass = rtsBuilder.AddEEClass("Align8Type");
eeClass.CorTypeAttr = (uint)(System.Reflection.TypeAttributes.Public | System.Reflection.TypeAttributes.Class);

MockMethodTable methodTable = rtsBuilder.AddMethodTable("Align8Type");
methodTable.MTFlags = (uint)(MethodTableFlags_1.WFLAGS_HIGH.Category_ValueType | MethodTableFlags_1.WFLAGS_HIGH.RequiresAlign8);
methodTable.BaseSize = rtsBuilder.Builder.TargetTestHelpers.ObjectBaseSize;
methodTable.ParentMethodTable = rtsBuilder.SystemObjectMethodTable.Address;
methodTable.NumVirtuals = 3;
methodTablePtr = methodTable.Address;
eeClass.MethodTable = methodTable.Address;
methodTable.EEClassOrCanonMT = eeClass.Address;
}
else
{
methodTablePtr = rtsBuilder.SystemObjectMethodTable.Address;
}
});

IRuntimeTypeSystem contract = target.Contracts.RuntimeTypeSystem;
Contracts.TypeHandle typeHandle = contract.GetTypeHandle(methodTablePtr);
Assert.Equal(flagSet, contract.RequiresAlign8(typeHandle));
}
}
Loading