diff --git a/src/coreclr/gc/gcload.cpp b/src/coreclr/gc/gcload.cpp index 0549ca856a9b6..12cc857a049c9 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 9ab98386c71a4..7fc234eca4add 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 1dc0fd8d91d99..fa0828fc034e8 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 455f6b446795b..17135f6c4e405 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 aba41341a2709..f7bd609553fc8 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 674d54a95e059..b1faf0d413086 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 b75435c4df0f8..af84d21ab3b4b 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 7977343d17d5a..f0a4afd09b187 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 364216788ba61..84357b26ae221 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 b894c9dc1f1c8..883332600e88d 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 eee208cfb2de0..434f9a9ee1c88 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 bbc0c99d4f597..6ad8c4dec561f 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;