From 699d0f41880c0f00c29232a200f72d209570f3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 16 Nov 2021 16:17:05 +0900 Subject: [PATCH 1/8] Integration of changes in shared files from runtimelab/NativeAOT --- src/coreclr/gc/gcload.cpp | 2 + src/coreclr/jit/importer.cpp | 8 +++ .../Compiler/CompilerTypeSystemContext.cs | 6 ++ .../Target_X64/X64Emitter.cs | 6 ++ .../Compiler/DevirtualizationManager.cs | 11 +++ .../Common/Compiler/DisplayNameHelpers.cs | 16 +++++ src/coreclr/tools/Common/Compiler/Logger.cs | 12 +++- .../ReferenceSource/MessageContainer.cs | 43 +++++++++--- .../Logging/ReferenceSource/MessageOrigin.cs | 68 +++++++++++++------ .../Logging/ReferenceSource/README.md | 2 +- .../Common/Internal/Runtime/ModuleHeaders.cs | 1 + .../tools/Common/JitInterface/CorInfoImpl.cs | 46 ++++++++++--- .../Common/MetadataFieldLayoutAlgorithm.cs | 4 +- 13 files changed, 183 insertions(+), 42 deletions(-) diff --git a/src/coreclr/gc/gcload.cpp b/src/coreclr/gc/gcload.cpp index 0549ca856a9b60..12cc857a049c93 100644 --- a/src/coreclr/gc/gcload.cpp +++ b/src/coreclr/gc/gcload.cpp @@ -78,10 +78,12 @@ GC_Initialize( // various components may want to query the current configuration. GCConfig::Initialize(); +#ifndef FEATURE_REDHAWK // GCToOSInterface is initialized directly if (!GCToOSInterface::Initialize()) { return E_FAIL; } +#endif IGCHandleManager* handleManager = CreateGCHandleManager(); if (handleManager == nullptr) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 9ab98386c71a4a..7fc234eca4addd 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -20884,6 +20884,14 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, return; } + // Delegate Invoke method doesn't have a body and gets special cased instead. + // Don't even bother trying to inline it. + if (call->IsDelegateInvoke()) + { + inlineResult.NoteFatal(InlineObservation::CALLEE_HAS_NO_BODY); + return; + } + // Tail recursion elimination takes precedence over inlining. // TODO: We may want to do some of the additional checks from fgMorphCall // here to reduce the chance we don't inline a call that won't be optimized diff --git a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs index 1dc0fd8d91d999..fa0828fc034e86 100644 --- a/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs +++ b/src/coreclr/tools/Common/Compiler/CompilerTypeSystemContext.cs @@ -193,6 +193,12 @@ private EcmaModule AddModule(string filePath, string expectedSimpleName, bool us if (oldModuleData == null) { peReader = OpenPEFile(filePath, out mappedViewAccessor); + +#if !READYTORUN + if (peReader.HasMetadata && (peReader.PEHeaders.CorHeader.Flags & (CorFlags.ILLibrary | CorFlags.ILOnly)) == 0) + throw new NotSupportedException($"Error: C++/CLI is not supported: '{filePath}'"); +#endif + pdbReader = PortablePdbSymbolReader.TryOpenEmbedded(peReader, GetMetadataStringDecoder()) ?? OpenAssociatedSymbolFile(filePath, peReader); } else diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs index 455f6b446795b3..17135f6c4e405a 100644 --- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs +++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/Target_X64/X64Emitter.cs @@ -174,6 +174,12 @@ public void EmitRETIfEqual() Builder.EmitByte(0xC3); } + public void EmitCompareToZero(Register reg) + { + AddrMode rexAddrMode = new AddrMode(Register.RegDirect | reg, null, 0, 0, AddrModeSize.Int64); + EmitIndirInstructionSize(0x84, reg, ref rexAddrMode); + } + public void EmitZeroReg(Register reg) { // High 32 bits get cleared automatically when using 32bit registers diff --git a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs index aba41341a27095..f7bd609553fc87 100644 --- a/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs +++ b/src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs @@ -201,5 +201,16 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType return impl; } + +#if !READYTORUN + /// + /// Gets a value indicating whether it might be possible to obtain a constructed type data structure for the given type. + /// + /// + /// This is a bit of a hack, but devirtualization manager has a global view of all allocated types + /// so it can answer this question. + /// + public virtual bool CanConstructType(TypeDesc type) => true; +#endif } } diff --git a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs index 674d54a95e0597..b1faf0d4130866 100644 --- a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs +++ b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Text; using Internal.TypeSystem; @@ -11,6 +12,21 @@ namespace ILCompiler { internal static class DisplayNameHelpers { + public static string GetDisplayName(this TypeSystemEntity entity) + { + return entity switch + { + MethodDesc method => method.GetDisplayName(), + FieldDesc field => field.GetDisplayName(), + TypeDesc type => type.GetDisplayName(), +#if !READYTORUN + PropertyPseudoDesc property => property.GetDisplayName(), + EventPseudoDesc @event => @event.GetDisplayName(), +#endif + _ => throw new InvalidOperationException(), + }; + } + public static string GetDisplayName(this MethodDesc method) { var sb = new StringBuilder(); diff --git a/src/coreclr/tools/Common/Compiler/Logger.cs b/src/coreclr/tools/Common/Compiler/Logger.cs index b75435c4df0f84..af84d21ab3b4bb 100644 --- a/src/coreclr/tools/Common/Compiler/Logger.cs +++ b/src/coreclr/tools/Common/Compiler/Logger.cs @@ -94,13 +94,23 @@ public void LogWarning(string text, int code, string origin, string subcategory internal bool IsWarningSuppressed(int code, MessageOrigin origin) { + // This is causing too much noise + // https://github.com/dotnet/runtimelab/issues/1591 + if (code == 2110 || code == 2111 || code == 2113 || code == 2115) + return true; + if (_suppressedWarnings.Contains(code)) return true; IEnumerable> suppressions = null; // TODO: Suppressions with different scopes - + + if (origin.MemberDefinition is TypeDesc type) + { + var ecmaType = type.GetTypeDefinition() as EcmaType; + suppressions = ecmaType?.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "UnconditionalSuppressMessageAttribute"); + } if (origin.MemberDefinition is MethodDesc method) { diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs index 7977343d17d5a3..f0a4afd09b1875 100644 --- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs +++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs @@ -1,8 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text; using Mono.Cecil; @@ -40,7 +41,7 @@ namespace Mono.Linker /// Create an error message. /// /// Humanly readable message describing the error - /// Unique error ID. Please see https://github.com/mono/linker/blob/main/docs/error-codes.md + /// Unique error ID. Please see https://github.com/dotnet/linker/blob/main/docs/error-codes.md /// for the list of errors and possibly add a new one /// Optionally, further categorize this error /// Filename, line, and column where the error was found @@ -80,7 +81,7 @@ public static MessageContainer CreateCustomErrorMessage (string text, int code, /// /// Context with the relevant warning suppression info. /// Humanly readable message describing the warning - /// Unique warning ID. Please see https://github.com/mono/linker/blob/main/docs/error-codes.md + /// Unique warning ID. Please see https://github.com/dotnet/linker/blob/main/docs/error-codes.md /// for the list of warnings and possibly add a new one /// /// Filename or member where the warning is coming from /// Optionally, further categorize this warning @@ -140,14 +141,31 @@ private static MessageContainer CreateWarningMessageContainer (LinkContext conte return new MessageContainer (MessageCategory.Warning, text, code, subcategory, origin); } + public bool IsWarningMessage ([NotNullWhen (true)] out int? code) + { + code = null; + + if (Category is MessageCategory.Warning or MessageCategory.WarningAsError) { + // Warning messages always have a code. + code = Code!; + return true; + } + + return false; + } + static bool TryLogSingleWarning (LinkContext context, int code, MessageOrigin origin, string subcategory) { if (subcategory != MessageSubCategory.TrimAnalysis) return false; - Debug.Assert (origin.MemberDefinition != null); - var declaringType = origin.MemberDefinition?.DeclaringType ?? (origin.MemberDefinition as TypeDefinition); - var assembly = declaringType.Module.Assembly; + Debug.Assert (origin.Provider != null); + var assembly = origin.Provider switch { + AssemblyDefinition asm => asm, + TypeDefinition type => type.Module.Assembly, + IMemberDefinition member => member.DeclaringType.Module.Assembly, + _ => throw new NotSupportedException () + }; Debug.Assert (assembly != null); if (assembly == null) @@ -228,17 +246,22 @@ public string ToMSBuildString () sb.Append (" ") .Append (cat) .Append (" IL") - .Append (Code.Value.ToString ("D4")) + // Warning and error messages always have a code. + .Append (Code!.Value.ToString ("D4")) .Append (": "); } else { sb.Append (" "); } - if (Origin?.MemberDefinition != null) { - if (Origin?.MemberDefinition is MethodDefinition method) + if (Origin?.Provider != null) { + if (Origin?.Provider is MethodDefinition method) sb.Append (method.GetDisplayName ()); + else if (Origin?.Provider is IMemberDefinition member) + sb.Append (member.FullName); + else if (Origin?.Provider is AssemblyDefinition assembly) + sb.Append (assembly.Name.Name); else - sb.Append (Origin?.MemberDefinition.FullName); + throw new NotSupportedException (); sb.Append (": "); } diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs index 364216788ba61f..84357b26ae221d 100644 --- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs +++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Diagnostics; using System.Linq; using System.Text; using Mono.Cecil; @@ -13,10 +14,14 @@ namespace Mono.Linker { #nullable enable public string? FileName { get; } - public IMemberDefinition? MemberDefinition { get; } - - readonly IMemberDefinition _suppressionContextMember; - public IMemberDefinition? SuppressionContextMember { get => _suppressionContextMember ?? MemberDefinition; } + public ICustomAttributeProvider? Provider { get; } + readonly ICustomAttributeProvider _suppressionContextMember; + public ICustomAttributeProvider? SuppressionContextMember { + get { + Debug.Assert (_suppressionContextMember == null || _suppressionContextMember is IMemberDefinition || _suppressionContextMember is AssemblyDefinition); + return _suppressionContextMember ?? Provider; + } + } #nullable disable public int SourceLine { get; } public int SourceColumn { get; } @@ -24,8 +29,13 @@ namespace Mono.Linker const int HiddenLineNumber = 0xfeefee; - public MessageOrigin (IMemberDefinition memberDefinition) - : this (memberDefinition, null) + public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset = null) + : this (memberDefinition as ICustomAttributeProvider, ilOffset) + { + } + + public MessageOrigin (ICustomAttributeProvider provider) + : this (provider, null) { } @@ -34,31 +44,43 @@ public MessageOrigin (string fileName, int sourceLine = 0, int sourceColumn = 0) FileName = fileName; SourceLine = sourceLine; SourceColumn = sourceColumn; - MemberDefinition = null; + Provider = null; _suppressionContextMember = null; ILOffset = null; } - public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset) - : this (memberDefinition, ilOffset, null) + public MessageOrigin (ICustomAttributeProvider provider, int? ilOffset) + : this (provider, ilOffset, null) { } - public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset, IMemberDefinition suppressionContextMember) + public MessageOrigin (ICustomAttributeProvider provider, int? ilOffset, ICustomAttributeProvider suppressionContextMember) { + Debug.Assert (provider == null || provider is IMemberDefinition || provider is AssemblyDefinition); + Debug.Assert (suppressionContextMember == null || suppressionContextMember is IMemberDefinition || provider is AssemblyDefinition); FileName = null; - MemberDefinition = memberDefinition; + Provider = provider; _suppressionContextMember = suppressionContextMember; SourceLine = 0; SourceColumn = 0; ILOffset = ilOffset; } + public MessageOrigin (MessageOrigin other, IMemberDefinition suppressionContextMember) + { + FileName = other.FileName; + Provider = other.Provider; + _suppressionContextMember = suppressionContextMember; + SourceLine = other.SourceLine; + SourceColumn = other.SourceColumn; + ILOffset = other.ILOffset; + } + public override string ToString () { int sourceLine = SourceLine, sourceColumn = SourceColumn; string fileName = FileName; - if (MemberDefinition is MethodDefinition method && + if (Provider is MethodDefinition method && method.DebugInformation.HasSequencePoints) { var offset = ILOffset ?? 0; SequencePoint correspondingSequencePoint = method.DebugInformation.SequencePoints @@ -94,20 +116,24 @@ public override string ToString () } public bool Equals (MessageOrigin other) => - (FileName, MemberDefinition, SourceLine, SourceColumn, ILOffset) == (other.FileName, other.MemberDefinition, other.SourceLine, other.SourceColumn, other.ILOffset); + (FileName, Provider, SourceLine, SourceColumn, ILOffset) == (other.FileName, other.Provider, other.SourceLine, other.SourceColumn, other.ILOffset); public override bool Equals (object obj) => obj is MessageOrigin messageOrigin && Equals (messageOrigin); - public override int GetHashCode () => (FileName, MemberDefinition, SourceLine, SourceColumn).GetHashCode (); + public override int GetHashCode () => (FileName, Provider, SourceLine, SourceColumn).GetHashCode (); public static bool operator == (MessageOrigin lhs, MessageOrigin rhs) => lhs.Equals (rhs); public static bool operator != (MessageOrigin lhs, MessageOrigin rhs) => !lhs.Equals (rhs); public int CompareTo (MessageOrigin other) { - if (MemberDefinition != null && other.MemberDefinition != null) { - TypeDefinition thisTypeDef = (MemberDefinition as TypeDefinition) ?? MemberDefinition.DeclaringType; - TypeDefinition otherTypeDef = (other.MemberDefinition as TypeDefinition) ?? other.MemberDefinition.DeclaringType; - int result = (thisTypeDef?.Module?.Assembly?.Name?.Name, thisTypeDef?.Name, MemberDefinition?.Name).CompareTo - ((otherTypeDef?.Module?.Assembly?.Name?.Name, otherTypeDef?.Name, other.MemberDefinition?.Name)); + if (Provider != null && other.Provider != null) { + var thisMember = Provider as IMemberDefinition; + var otherMember = other.Provider as IMemberDefinition; + TypeDefinition thisTypeDef = (Provider as TypeDefinition) ?? (Provider as IMemberDefinition)?.DeclaringType; + TypeDefinition otherTypeDef = (other.Provider as TypeDefinition) ?? (other.Provider as IMemberDefinition)?.DeclaringType; + var thisAssembly = thisTypeDef?.Module.Assembly ?? Provider as AssemblyDefinition; + var otherAssembly = otherTypeDef?.Module.Assembly ?? other.Provider as AssemblyDefinition; + int result = (thisAssembly.Name.Name, thisTypeDef?.Name, thisMember?.Name).CompareTo + ((otherAssembly.Name.Name, otherTypeDef?.Name, otherMember?.Name)); if (result != 0) return result; @@ -115,7 +141,7 @@ public int CompareTo (MessageOrigin other) return ILOffset.Value.CompareTo (other.ILOffset); return ILOffset == null ? (other.ILOffset == null ? 0 : 1) : -1; - } else if (MemberDefinition == null && other.MemberDefinition == null) { + } else if (Provider == null && other.Provider == null) { if (FileName != null && other.FileName != null) { return string.Compare (FileName, other.FileName); } else if (FileName == null && other.FileName == null) { @@ -125,7 +151,7 @@ public int CompareTo (MessageOrigin other) return (FileName == null) ? 1 : -1; } - return (MemberDefinition == null) ? 1 : -1; + return (Provider == null) ? 1 : -1; } } } diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md index b894c9dc1f1c81..883332600e88d0 100644 --- a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md +++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md @@ -1 +1 @@ -Sources from the mono/linker repo at commit 012efef292663aa38f9047896942cdcc8765b8e0. \ No newline at end of file +Sources from the dotnet/linker repo at commit c0567db0b9088e2ad4144cd0fe2a985611ec28f0. diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index eee208cfb2de0f..434f9a9ee1c888 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -84,6 +84,7 @@ public enum ReadyToRunSectionType ThreadStaticIndex = 210, LoopHijackFlag = 211, ImportAddressTables = 212, + ModuleInitializerList = 213, // Sections 300 - 399 are reserved for RhFindBlob backwards compatibility ReadonlyBlobRegionStart = 300, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index bbc0c99d4f597f..6ad8c4dec561fd 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -1265,25 +1265,38 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) methodWithTokenDecl = new MethodWithToken(decl, declToken, null, false, null, devirtualizedMethodOwner: decl.OwningType); } MethodWithToken methodWithTokenImpl; +#endif if (decl == originalImpl) { +#if READYTORUN methodWithTokenImpl = methodWithTokenDecl; +#endif if (info->pResolvedTokenVirtualMethod != null) { info->resolvedTokenDevirtualizedMethod = *info->pResolvedTokenVirtualMethod; } else { - info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, decl, methodWithTokenDecl); + info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, decl +#if READYTORUN + , methodWithTokenDecl +#endif + ); } info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); } else { +#if READYTORUN methodWithTokenImpl = new MethodWithToken(nonUnboxingImpl, resolver.GetModuleTokenForMethod(nonUnboxingImpl.GetTypicalMethodDefinition()), null, unboxingStub, null, devirtualizedMethodOwner: impl.OwningType); +#endif - info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, impl, methodWithTokenImpl); + info->resolvedTokenDevirtualizedMethod = CreateResolvedTokenFromMethod(this, impl +#if READYTORUN + , methodWithTokenImpl +#endif + ); if (unboxingStub) { @@ -1297,6 +1310,7 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) } } +#if READYTORUN // Testing has not shown that concerns about virtual matching are significant // Only generate verification for builds with the stress mode enabled if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout) @@ -1304,9 +1318,6 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) ISymbolNode virtualResolutionNode = _compilation.SymbolNodeFactory.CheckVirtualFunctionOverride(methodWithTokenDecl, objType, methodWithTokenImpl); _methodCodeNode.Fixups.Add(virtualResolutionNode); } -#else - info->resolvedTokenDevirtualizedMethod = default(CORINFO_RESOLVED_TOKEN); - info->resolvedTokenDevirtualizedUnboxedMethod = default(CORINFO_RESOLVED_TOKEN); #endif info->detail = CORINFO_DEVIRTUALIZATION_DETAIL.CORINFO_DEVIRTUALIZATION_SUCCESS; info->devirtualizedMethod = ObjectToHandle(impl); @@ -1315,9 +1326,21 @@ private bool resolveVirtualMethod(CORINFO_DEVIRTUALIZATION_INFO* info) return true; + static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInterface, MethodDesc method #if READYTORUN - static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInterface, MethodDesc method, MethodWithToken methodWithToken) + , MethodWithToken methodWithToken +#endif + ) { +#if !READYTORUN + MethodDesc unboxedMethodDesc = method.IsUnboxingThunk() ? method.GetUnboxedMethod() : method; + var methodWithToken = new + { + Method = unboxedMethodDesc, + OwningType = unboxedMethodDesc.OwningType, + }; +#endif + CORINFO_RESOLVED_TOKEN result = default(CORINFO_RESOLVED_TOKEN); MethodILScope scope = jitInterface._compilation.GetMethodIL(methodWithToken.Method); if (scope == null) @@ -1326,19 +1349,22 @@ static CORINFO_RESOLVED_TOKEN CreateResolvedTokenFromMethod(CorInfoImpl jitInter } result.tokenScope = jitInterface.ObjectToHandle(scope); result.tokenContext = jitInterface.contextFromMethod(method); +#if READYTORUN result.token = methodWithToken.Token.Token; if (methodWithToken.Token.TokenType != CorTokenType.mdtMethodDef) { Debug.Assert(false); // This should never happen, but we protect against total failure with the throw below. throw new RequiresRuntimeJitException("Attempt to devirtualize and unable to create token for devirtualized method"); } +#else + result.token = (mdToken)0x06BAAAAD; +#endif result.tokenType = CorInfoTokenKind.CORINFO_TOKENKIND_DevirtualizedMethod; result.hClass = jitInterface.ObjectToHandle(methodWithToken.OwningType); result.hMethod = jitInterface.ObjectToHandle(method); return result; } -#endif } private CORINFO_METHOD_STRUCT_* getUnboxedEntry(CORINFO_METHOD_STRUCT_* ftn, ref bool requiresInstMethodTableArg) @@ -3773,7 +3799,11 @@ private HRESULT getPgoInstrumentationResults(CORINFO_METHOD_STRUCT_* ftnHnd, ref } else { - ComputeJitPgoInstrumentationSchema(ObjectToHandle, pgoResultsSchemas, out var nativeSchemas, out var instrumentationData); + ComputeJitPgoInstrumentationSchema(ObjectToHandle, pgoResultsSchemas, out var nativeSchemas, out var instrumentationData +#if !READYTORUN + , _compilation.CanConstructType +#endif + ); pgoResults.pInstrumentationData = (byte*)GetPin(instrumentationData); pgoResults.countSchemaItems = (uint)nativeSchemas.Length; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index f445bb1a1fc70b..995aa0d573c740 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -173,7 +173,9 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat { return ComputeExplicitFieldLayout(type, numInstanceFields); } - else if (type.IsSequentialLayout || type.IsEnum || type.Context.Target.Abi == TargetAbi.CppCodegen) + // Sequential layout has to be respected for blittable types only. We use approximation and respect it for + // all types without GC references (ie C# unmanaged types). + else if (type.IsSequentialLayout && !type.ContainsGCPointers) { return ComputeSequentialFieldLayout(type, numInstanceFields); } From 800cf0e3d24528a5b66d09c278c803628d554cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 18 Nov 2021 17:36:45 +0900 Subject: [PATCH 2/8] Fix test failures --- .../Common/MetadataFieldLayoutAlgorithm.cs | 4 +-- .../ArchitectureSpecificFieldLayoutTests.cs | 14 +++++----- .../GCPointerMapTests.cs | 8 +++--- .../InstanceFieldLayoutTests.cs | 26 +++++++++---------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 995aa0d573c740..7c5ae7e36bc8d8 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -174,8 +174,8 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat return ComputeExplicitFieldLayout(type, numInstanceFields); } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for - // all types without GC references (ie C# unmanaged types). - else if (type.IsSequentialLayout && !type.ContainsGCPointers) + // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. + else if (type.IsSequentialLayout && (type.IsCanonicalSubtype(CanonicalFormKind.Universal) || !type.ContainsGCPointers)) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs index 067486f858c168..08405b28d66756 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs @@ -99,19 +99,19 @@ public void TestAlignmentBehavior_LongIntEnumStruct() Assert.Equal(0x20, tX64.InstanceByteCountUnaligned.AsInt); Assert.Equal(0x20, tARM.InstanceByteCountUnaligned.AsInt); - Assert.Equal(0x20, tX86.InstanceByteCountUnaligned.AsInt); + Assert.Equal(0x18, tX86.InstanceByteCountUnaligned.AsInt); Assert.Equal(0x20, tX64.InstanceByteCount.AsInt); Assert.Equal(0x20, tARM.InstanceByteCount.AsInt); - Assert.Equal(0x20, tX86.InstanceByteCount.AsInt); + Assert.Equal(0x18, tX86.InstanceByteCount.AsInt); Assert.Equal(0x8, tX64.InstanceFieldAlignment.AsInt); Assert.Equal(0x8, tARM.InstanceFieldAlignment.AsInt); - Assert.Equal(0x8, tX86.InstanceFieldAlignment.AsInt); + Assert.Equal(0x4, tX86.InstanceFieldAlignment.AsInt); Assert.Equal(0x20, tX64.InstanceFieldSize.AsInt); Assert.Equal(0x20, tARM.InstanceFieldSize.AsInt); - Assert.Equal(0x20, tX86.InstanceFieldSize.AsInt); + Assert.Equal(0x18, tX86.InstanceFieldSize.AsInt); Assert.Equal(0x0, tX64.GetField("_1").Offset.AsInt); Assert.Equal(0x0, tARM.GetField("_1").Offset.AsInt); @@ -123,18 +123,18 @@ public void TestAlignmentBehavior_LongIntEnumStruct() Assert.Equal(0x10, tX64.GetField("_3").Offset.AsInt); Assert.Equal(0x10, tARM.GetField("_3").Offset.AsInt); - Assert.Equal(0x10, tX86.GetField("_3").Offset.AsInt); + Assert.Equal(0xC, tX86.GetField("_3").Offset.AsInt); Assert.Equal(0x18, tX64.GetField("_4").Offset.AsInt); Assert.Equal(0x18, tARM.GetField("_4").Offset.AsInt); - Assert.Equal(0x18, tX86.GetField("_4").Offset.AsInt); + Assert.Equal(0x14, tX86.GetField("_4").Offset.AsInt); MetadataType tX64FieldStruct = _testModuleX64.GetType(_namespace, _type + "FieldStruct"); MetadataType tX86FieldStruct = _testModuleX86.GetType(_namespace, _type + "FieldStruct"); MetadataType tARMFieldStruct = _testModuleARM.GetType(_namespace, _type + "FieldStruct"); Assert.Equal(0x8, tX64FieldStruct.GetField("_struct").Offset.AsInt); - Assert.Equal(0x8, tX86FieldStruct.GetField("_struct").Offset.AsInt); + Assert.Equal(0x4, tX86FieldStruct.GetField("_struct").Offset.AsInt); Assert.Equal(0x8, tARMFieldStruct.GetField("_struct").Offset.AsInt); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs index 51578a171105a8..a8ba4e5e037be0 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs @@ -41,13 +41,13 @@ public void TestInstanceMap() { var map = GCPointerMap.FromInstanceLayout(classWithStringField); Assert.Equal(4, map.Size); - Assert.Equal("0010", map.ToString()); + Assert.Equal("0100", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(mixedStruct); Assert.Equal(5, map.Size); - Assert.Equal("01001", map.ToString()); + Assert.Equal("11000", map.ToString()); } { @@ -60,13 +60,13 @@ public void TestInstanceMap() { var map = GCPointerMap.FromInstanceLayout(doubleMixedStructLayout); Assert.Equal(10, map.Size); - Assert.Equal("0100101001", map.ToString()); + Assert.Equal("1100011000", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(explicitlyFarPointer); Assert.Equal(117, map.Size); - Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000001001", map.ToString()); + Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000011000", map.ToString()); } { diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs index e92749b5ab272d..fe19939af73ea7 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs @@ -150,22 +150,22 @@ public void TestSequentialTypeLayout() switch (f.Name) { case "MyInt": - Assert.Equal(0x8, f.Offset.AsInt); + Assert.Equal(0x20, f.Offset.AsInt); break; case "MyBool": - Assert.Equal(0xC, f.Offset.AsInt); + Assert.Equal(0x26, f.Offset.AsInt); break; case "MyChar": - Assert.Equal(0xE, f.Offset.AsInt); + Assert.Equal(0x24, f.Offset.AsInt); break; case "MyString": - Assert.Equal(0x10, f.Offset.AsInt); + Assert.Equal(0x8, f.Offset.AsInt); break; case "MyByteArray": - Assert.Equal(0x18, f.Offset.AsInt); + Assert.Equal(0x10, f.Offset.AsInt); break; case "MyClass1SelfRef": - Assert.Equal(0x20, f.Offset.AsInt); + Assert.Equal(0x18, f.Offset.AsInt); break; default: Assert.True(false); @@ -226,19 +226,19 @@ public void TestSequentialTypeLayoutStruct() switch (f.Name) { case "b1": - Assert.Equal(0x0, f.Offset.AsInt); + Assert.Equal(0xC, f.Offset.AsInt); break; case "b2": - Assert.Equal(0x1, f.Offset.AsInt); + Assert.Equal(0xD, f.Offset.AsInt); break; case "b3": - Assert.Equal(0x2, f.Offset.AsInt); + Assert.Equal(0xE, f.Offset.AsInt); break; case "i1": - Assert.Equal(0x4, f.Offset.AsInt); + Assert.Equal(0x8, f.Offset.AsInt); break; case "s1": - Assert.Equal(0x8, f.Offset.AsInt); + Assert.Equal(0x0, f.Offset.AsInt); break; default: Assert.True(false); @@ -269,10 +269,10 @@ public void TestSequentialTypeLayoutStructEmbedded() switch (f.Name) { case "MyStruct0": - Assert.Equal(0x0, f.Offset.AsInt); + Assert.Equal(0x8, f.Offset.AsInt); break; case "MyBool": - Assert.Equal(0x10, f.Offset.AsInt); + Assert.Equal(0x0, f.Offset.AsInt); break; default: Assert.True(false); From 24edc80d9d88230902e166831f3aa51f29d0b47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 03:26:49 +0900 Subject: [PATCH 3/8] Fix universal canon --- .../TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +- .../CanonicalizationTests.cs | 2 +- .../RuntimeDeterminedTypesTests.cs | 2 +- .../TestTypeSystemContext.cs | 9 +++++++-- .../UniversalGenericFieldLayoutTests.cs | 6 +++--- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 7c5ae7e36bc8d8..26534038259b80 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -175,7 +175,7 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. - else if (type.IsSequentialLayout && (type.IsCanonicalSubtype(CanonicalFormKind.Universal) || !type.ContainsGCPointers)) + else if (type.IsSequentialLayout && (type.Context.SupportsUniversalCanon || !type.ContainsGCPointers)) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs index d3f2c6c6036d67..9a133c18abb27d 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs @@ -25,7 +25,7 @@ public class CanonicalizationTests public CanonicalizationTests() { - _context = new TestTypeSystemContext(TargetArchitecture.Unknown); + _context = new TestTypeSystemContext(TargetArchitecture.Unknown, supportsUniversalCanon: true); var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly"); _context.SetSystemModule(systemModule); diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs index a394a562af9f5f..4712ad10666415 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs @@ -23,7 +23,7 @@ public class RuntimeDeterminedTypesTests public RuntimeDeterminedTypesTests() { - _context = new TestTypeSystemContext(TargetArchitecture.Unknown); + _context = new TestTypeSystemContext(TargetArchitecture.Unknown, supportsUniversalCanon: true); var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly"); _context.SetSystemModule(systemModule); diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs index 0fbd0b6a35329e..4a7daa030423ff 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -26,12 +26,14 @@ class TestTypeSystemContext : MetadataTypeSystemContext MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); + bool _supportsUniversalCanon; public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined; - public TestTypeSystemContext(TargetArchitecture arch) + public TestTypeSystemContext(TargetArchitecture arch, bool supportsUniversalCanon = false) : base(new TargetDetails(arch, TargetOS.Unknown, TargetAbi.Unknown)) { + _supportsUniversalCanon = supportsUniversalCanon; } public ModuleDesc GetModuleForSimpleName(string simpleName) @@ -92,6 +94,7 @@ public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) { + Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed); else @@ -100,6 +103,7 @@ protected override Instantiation ConvertInstantiationToCanonForm(Instantiation i protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) { + Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); else @@ -108,6 +112,7 @@ protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalForm protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) { + Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); else @@ -129,7 +134,7 @@ protected override bool ComputeHasGCStaticBase(FieldDesc field) } - public override bool SupportsUniversalCanon => true; + public override bool SupportsUniversalCanon => _supportsUniversalCanon; public override bool SupportsCanon => true; } } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs index c0680f2ebbb2d5..428c33a7000108 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs @@ -22,19 +22,19 @@ public class UniversalGenericFieldLayoutTests public UniversalGenericFieldLayoutTests() { // Architecture specific tests may use these contexts - _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64); + _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64, supportsUniversalCanon: true); var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly"); _contextX64.SetSystemModule(systemModuleX64); _testModuleX64 = systemModuleX64; - _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM); + _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM, supportsUniversalCanon: true); var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly"); _contextARM.SetSystemModule(systemModuleARM); _testModuleARM = systemModuleARM; - _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86); + _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86, supportsUniversalCanon: true); var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly"); _contextX86.SetSystemModule(systemModuleX86); From a706a0575f6120e1ee483cc8a27d2d97796fd202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 03:44:22 +0900 Subject: [PATCH 4/8] Sigh --- .../tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs | 1 + .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 5 ++++- .../tools/Common/TypeSystem/Common/TypeSystemContext.cs | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs b/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs index 091f26bfda510c..a2f66d94d88bc8 100644 --- a/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs +++ b/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs @@ -92,6 +92,7 @@ protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, Canon throw new NotSupportedException(); } + internal partial void InternalGetSupportsUniversalCanon(ref bool flag) => flag = SupportsUniversalCanon; public abstract bool SupportsCanon { get; } public abstract bool SupportsUniversalCanon { get; } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 26534038259b80..05388e24df1fab 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -169,13 +169,16 @@ out instanceByteSizeAndAlignment protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields) { + bool supportsUniversalCanon = false; + type.Context.InternalGetSupportsUniversalCanon(ref supportsUniversalCanon); + if (type.IsExplicitLayout) { return ComputeExplicitFieldLayout(type, numInstanceFields); } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. - else if (type.IsSequentialLayout && (type.Context.SupportsUniversalCanon || !type.ContainsGCPointers)) + else if (type.IsSequentialLayout && (supportsUniversalCanon || !type.ContainsGCPointers)) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs index fcb47f42d3c92d..05589b69888d3b 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs @@ -813,5 +813,7 @@ internal TypeFlags ComputeTypeFlags(TypeDesc type, TypeFlags flags, TypeFlags ma /// Determine if the type implements IDynamicInterfaceCastable /// protected internal abstract bool IsIDynamicInterfaceCastableInterface(DefType type); + + internal partial void InternalGetSupportsUniversalCanon(ref bool flag); } } From c4b74ba79ab47f5f295d7b3b5f76869e47cb5598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 06:07:30 +0900 Subject: [PATCH 5/8] Revert "Sigh" This reverts commit a706a0575f6120e1ee483cc8a27d2d97796fd202. --- .../tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs | 1 - .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 5 +---- .../tools/Common/TypeSystem/Common/TypeSystemContext.cs | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs b/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs index a2f66d94d88bc8..091f26bfda510c 100644 --- a/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs +++ b/src/coreclr/tools/Common/TypeSystem/Canon/TypeSystemContext.Canon.cs @@ -92,7 +92,6 @@ protected internal virtual TypeDesc ConvertToCanon(TypeDesc typeToConvert, Canon throw new NotSupportedException(); } - internal partial void InternalGetSupportsUniversalCanon(ref bool flag) => flag = SupportsUniversalCanon; public abstract bool SupportsCanon { get; } public abstract bool SupportsUniversalCanon { get; } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 05388e24df1fab..26534038259b80 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -169,16 +169,13 @@ out instanceByteSizeAndAlignment protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(MetadataType type, int numInstanceFields) { - bool supportsUniversalCanon = false; - type.Context.InternalGetSupportsUniversalCanon(ref supportsUniversalCanon); - if (type.IsExplicitLayout) { return ComputeExplicitFieldLayout(type, numInstanceFields); } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. - else if (type.IsSequentialLayout && (supportsUniversalCanon || !type.ContainsGCPointers)) + else if (type.IsSequentialLayout && (type.Context.SupportsUniversalCanon || !type.ContainsGCPointers)) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs index 05589b69888d3b..fcb47f42d3c92d 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeSystemContext.cs @@ -813,7 +813,5 @@ internal TypeFlags ComputeTypeFlags(TypeDesc type, TypeFlags flags, TypeFlags ma /// Determine if the type implements IDynamicInterfaceCastable /// protected internal abstract bool IsIDynamicInterfaceCastableInterface(DefType type); - - internal partial void InternalGetSupportsUniversalCanon(ref bool flag); } } From 0bc3512db4f41cb381dc993d93f21375b58aeddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 06:07:36 +0900 Subject: [PATCH 6/8] Revert "Fix universal canon" This reverts commit 24edc80d9d88230902e166831f3aa51f29d0b47a. --- .../TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 2 +- .../CanonicalizationTests.cs | 2 +- .../RuntimeDeterminedTypesTests.cs | 2 +- .../TestTypeSystemContext.cs | 9 ++------- .../UniversalGenericFieldLayoutTests.cs | 6 +++--- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 26534038259b80..7c5ae7e36bc8d8 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -175,7 +175,7 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. - else if (type.IsSequentialLayout && (type.Context.SupportsUniversalCanon || !type.ContainsGCPointers)) + else if (type.IsSequentialLayout && (type.IsCanonicalSubtype(CanonicalFormKind.Universal) || !type.ContainsGCPointers)) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs index 9a133c18abb27d..d3f2c6c6036d67 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CanonicalizationTests.cs @@ -25,7 +25,7 @@ public class CanonicalizationTests public CanonicalizationTests() { - _context = new TestTypeSystemContext(TargetArchitecture.Unknown, supportsUniversalCanon: true); + _context = new TestTypeSystemContext(TargetArchitecture.Unknown); var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly"); _context.SetSystemModule(systemModule); diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs index 4712ad10666415..a394a562af9f5f 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/RuntimeDeterminedTypesTests.cs @@ -23,7 +23,7 @@ public class RuntimeDeterminedTypesTests public RuntimeDeterminedTypesTests() { - _context = new TestTypeSystemContext(TargetArchitecture.Unknown, supportsUniversalCanon: true); + _context = new TestTypeSystemContext(TargetArchitecture.Unknown); var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly"); _context.SetSystemModule(systemModule); diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs index 4a7daa030423ff..0fbd0b6a35329e 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/TestTypeSystemContext.cs @@ -26,14 +26,12 @@ class TestTypeSystemContext : MetadataTypeSystemContext MetadataRuntimeInterfacesAlgorithm _metadataRuntimeInterfacesAlgorithm = new MetadataRuntimeInterfacesAlgorithm(); ArrayOfTRuntimeInterfacesAlgorithm _arrayOfTRuntimeInterfacesAlgorithm; VirtualMethodAlgorithm _virtualMethodAlgorithm = new MetadataVirtualMethodAlgorithm(); - bool _supportsUniversalCanon; public CanonicalizationMode CanonMode { get; set; } = CanonicalizationMode.RuntimeDetermined; - public TestTypeSystemContext(TargetArchitecture arch, bool supportsUniversalCanon = false) + public TestTypeSystemContext(TargetArchitecture arch) : base(new TargetDetails(arch, TargetOS.Unknown, TargetAbi.Unknown)) { - _supportsUniversalCanon = supportsUniversalCanon; } public ModuleDesc GetModuleForSimpleName(string simpleName) @@ -94,7 +92,6 @@ public override VirtualMethodAlgorithm GetVirtualMethodAlgorithmForType(TypeDesc protected override Instantiation ConvertInstantiationToCanonForm(Instantiation instantiation, CanonicalFormKind kind, out bool changed) { - Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertInstantiationToCanonForm(instantiation, kind, out changed); else @@ -103,7 +100,6 @@ protected override Instantiation ConvertInstantiationToCanonForm(Instantiation i protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalFormKind kind) { - Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); else @@ -112,7 +108,6 @@ protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, CanonicalForm protected override TypeDesc ConvertToCanon(TypeDesc typeToConvert, ref CanonicalFormKind kind) { - Debug.Assert(kind != CanonicalFormKind.Universal || _supportsUniversalCanon); if (CanonMode == CanonicalizationMode.Standard) return StandardCanonicalizationAlgorithm.ConvertToCanon(typeToConvert, kind); else @@ -134,7 +129,7 @@ protected override bool ComputeHasGCStaticBase(FieldDesc field) } - public override bool SupportsUniversalCanon => _supportsUniversalCanon; + public override bool SupportsUniversalCanon => true; public override bool SupportsCanon => true; } } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs index 428c33a7000108..c0680f2ebbb2d5 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/UniversalGenericFieldLayoutTests.cs @@ -22,19 +22,19 @@ public class UniversalGenericFieldLayoutTests public UniversalGenericFieldLayoutTests() { // Architecture specific tests may use these contexts - _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64, supportsUniversalCanon: true); + _contextX64 = new TestTypeSystemContext(TargetArchitecture.X64); var systemModuleX64 = _contextX64.CreateModuleForSimpleName("CoreTestAssembly"); _contextX64.SetSystemModule(systemModuleX64); _testModuleX64 = systemModuleX64; - _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM, supportsUniversalCanon: true); + _contextARM = new TestTypeSystemContext(TargetArchitecture.ARM); var systemModuleARM = _contextARM.CreateModuleForSimpleName("CoreTestAssembly"); _contextARM.SetSystemModule(systemModuleARM); _testModuleARM = systemModuleARM; - _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86, supportsUniversalCanon: true); + _contextX86 = new TestTypeSystemContext(TargetArchitecture.X86); var systemModuleX86 = _contextX86.CreateModuleForSimpleName("CoreTestAssembly"); _contextX86.SetSystemModule(systemModuleX86); From 896634c232c2807977e5f71664c41eef93a2fbe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 06:07:42 +0900 Subject: [PATCH 7/8] Revert "Fix test failures" This reverts commit 800cf0e3d24528a5b66d09c278c803628d554cc1. --- .../Common/MetadataFieldLayoutAlgorithm.cs | 4 +-- .../ArchitectureSpecificFieldLayoutTests.cs | 14 +++++----- .../GCPointerMapTests.cs | 8 +++--- .../InstanceFieldLayoutTests.cs | 26 +++++++++---------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 7c5ae7e36bc8d8..995aa0d573c740 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -174,8 +174,8 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat return ComputeExplicitFieldLayout(type, numInstanceFields); } // Sequential layout has to be respected for blittable types only. We use approximation and respect it for - // all types without GC references (ie C# unmanaged types). Universal canonical instances might be blittable. - else if (type.IsSequentialLayout && (type.IsCanonicalSubtype(CanonicalFormKind.Universal) || !type.ContainsGCPointers)) + // all types without GC references (ie C# unmanaged types). + else if (type.IsSequentialLayout && !type.ContainsGCPointers) { return ComputeSequentialFieldLayout(type, numInstanceFields); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs index 08405b28d66756..067486f858c168 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ArchitectureSpecificFieldLayoutTests.cs @@ -99,19 +99,19 @@ public void TestAlignmentBehavior_LongIntEnumStruct() Assert.Equal(0x20, tX64.InstanceByteCountUnaligned.AsInt); Assert.Equal(0x20, tARM.InstanceByteCountUnaligned.AsInt); - Assert.Equal(0x18, tX86.InstanceByteCountUnaligned.AsInt); + Assert.Equal(0x20, tX86.InstanceByteCountUnaligned.AsInt); Assert.Equal(0x20, tX64.InstanceByteCount.AsInt); Assert.Equal(0x20, tARM.InstanceByteCount.AsInt); - Assert.Equal(0x18, tX86.InstanceByteCount.AsInt); + Assert.Equal(0x20, tX86.InstanceByteCount.AsInt); Assert.Equal(0x8, tX64.InstanceFieldAlignment.AsInt); Assert.Equal(0x8, tARM.InstanceFieldAlignment.AsInt); - Assert.Equal(0x4, tX86.InstanceFieldAlignment.AsInt); + Assert.Equal(0x8, tX86.InstanceFieldAlignment.AsInt); Assert.Equal(0x20, tX64.InstanceFieldSize.AsInt); Assert.Equal(0x20, tARM.InstanceFieldSize.AsInt); - Assert.Equal(0x18, tX86.InstanceFieldSize.AsInt); + Assert.Equal(0x20, tX86.InstanceFieldSize.AsInt); Assert.Equal(0x0, tX64.GetField("_1").Offset.AsInt); Assert.Equal(0x0, tARM.GetField("_1").Offset.AsInt); @@ -123,18 +123,18 @@ public void TestAlignmentBehavior_LongIntEnumStruct() Assert.Equal(0x10, tX64.GetField("_3").Offset.AsInt); Assert.Equal(0x10, tARM.GetField("_3").Offset.AsInt); - Assert.Equal(0xC, tX86.GetField("_3").Offset.AsInt); + Assert.Equal(0x10, tX86.GetField("_3").Offset.AsInt); Assert.Equal(0x18, tX64.GetField("_4").Offset.AsInt); Assert.Equal(0x18, tARM.GetField("_4").Offset.AsInt); - Assert.Equal(0x14, tX86.GetField("_4").Offset.AsInt); + Assert.Equal(0x18, tX86.GetField("_4").Offset.AsInt); MetadataType tX64FieldStruct = _testModuleX64.GetType(_namespace, _type + "FieldStruct"); MetadataType tX86FieldStruct = _testModuleX86.GetType(_namespace, _type + "FieldStruct"); MetadataType tARMFieldStruct = _testModuleARM.GetType(_namespace, _type + "FieldStruct"); Assert.Equal(0x8, tX64FieldStruct.GetField("_struct").Offset.AsInt); - Assert.Equal(0x4, tX86FieldStruct.GetField("_struct").Offset.AsInt); + Assert.Equal(0x8, tX86FieldStruct.GetField("_struct").Offset.AsInt); Assert.Equal(0x8, tARMFieldStruct.GetField("_struct").Offset.AsInt); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs index a8ba4e5e037be0..51578a171105a8 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/GCPointerMapTests.cs @@ -41,13 +41,13 @@ public void TestInstanceMap() { var map = GCPointerMap.FromInstanceLayout(classWithStringField); Assert.Equal(4, map.Size); - Assert.Equal("0100", map.ToString()); + Assert.Equal("0010", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(mixedStruct); Assert.Equal(5, map.Size); - Assert.Equal("11000", map.ToString()); + Assert.Equal("01001", map.ToString()); } { @@ -60,13 +60,13 @@ public void TestInstanceMap() { var map = GCPointerMap.FromInstanceLayout(doubleMixedStructLayout); Assert.Equal(10, map.Size); - Assert.Equal("1100011000", map.ToString()); + Assert.Equal("0100101001", map.ToString()); } { var map = GCPointerMap.FromInstanceLayout(explicitlyFarPointer); Assert.Equal(117, map.Size); - Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000011000", map.ToString()); + Assert.Equal("100000000000000000000000000000000000000000000000000000000000000010000000000000001000000000000000000000000000000001001", map.ToString()); } { diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs index fe19939af73ea7..e92749b5ab272d 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/InstanceFieldLayoutTests.cs @@ -150,22 +150,22 @@ public void TestSequentialTypeLayout() switch (f.Name) { case "MyInt": - Assert.Equal(0x20, f.Offset.AsInt); + Assert.Equal(0x8, f.Offset.AsInt); break; case "MyBool": - Assert.Equal(0x26, f.Offset.AsInt); + Assert.Equal(0xC, f.Offset.AsInt); break; case "MyChar": - Assert.Equal(0x24, f.Offset.AsInt); + Assert.Equal(0xE, f.Offset.AsInt); break; case "MyString": - Assert.Equal(0x8, f.Offset.AsInt); + Assert.Equal(0x10, f.Offset.AsInt); break; case "MyByteArray": - Assert.Equal(0x10, f.Offset.AsInt); + Assert.Equal(0x18, f.Offset.AsInt); break; case "MyClass1SelfRef": - Assert.Equal(0x18, f.Offset.AsInt); + Assert.Equal(0x20, f.Offset.AsInt); break; default: Assert.True(false); @@ -226,19 +226,19 @@ public void TestSequentialTypeLayoutStruct() switch (f.Name) { case "b1": - Assert.Equal(0xC, f.Offset.AsInt); + Assert.Equal(0x0, f.Offset.AsInt); break; case "b2": - Assert.Equal(0xD, f.Offset.AsInt); + Assert.Equal(0x1, f.Offset.AsInt); break; case "b3": - Assert.Equal(0xE, f.Offset.AsInt); + Assert.Equal(0x2, f.Offset.AsInt); break; case "i1": - Assert.Equal(0x8, f.Offset.AsInt); + Assert.Equal(0x4, f.Offset.AsInt); break; case "s1": - Assert.Equal(0x0, f.Offset.AsInt); + Assert.Equal(0x8, f.Offset.AsInt); break; default: Assert.True(false); @@ -269,10 +269,10 @@ public void TestSequentialTypeLayoutStructEmbedded() switch (f.Name) { case "MyStruct0": - Assert.Equal(0x8, f.Offset.AsInt); + Assert.Equal(0x0, f.Offset.AsInt); break; case "MyBool": - Assert.Equal(0x0, f.Offset.AsInt); + Assert.Equal(0x10, f.Offset.AsInt); break; default: Assert.True(false); From 907db288f8cea9172e51c1a96fe70bffadab34f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 19 Nov 2021 06:09:29 +0900 Subject: [PATCH 8/8] Undo change --- .../Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs index 995aa0d573c740..f445bb1a1fc70b 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs @@ -173,9 +173,7 @@ protected virtual ComputedInstanceFieldLayout ComputeInstanceFieldLayout(Metadat { return ComputeExplicitFieldLayout(type, numInstanceFields); } - // Sequential layout has to be respected for blittable types only. We use approximation and respect it for - // all types without GC references (ie C# unmanaged types). - else if (type.IsSequentialLayout && !type.ContainsGCPointers) + else if (type.IsSequentialLayout || type.IsEnum || type.Context.Target.Abi == TargetAbi.CppCodegen) { return ComputeSequentialFieldLayout(type, numInstanceFields); }