diff --git a/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs b/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs index ca2dd5050024e4..7e29eaaf7c0587 100644 --- a/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs +++ b/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs @@ -530,7 +530,8 @@ protected static string GetAttribute(XPathNavigator nav, string attribute) public static string GetMethodSignature(MethodDesc meth, bool includeGenericParameters) { StringBuilder sb = new StringBuilder(); - CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature.ReturnType); + var formatter = new CecilTypeNameFormatter(meth); + formatter.AppendName(sb, meth.Signature.ReturnType); sb.Append(' '); sb.Append(meth.GetName()); if (includeGenericParameters && meth.HasInstantiation) @@ -545,7 +546,7 @@ public static string GetMethodSignature(MethodDesc meth, bool includeGenericPara if (i > 0) sb.Append(','); - CecilTypeNameFormatter.Instance.AppendName(sb, meth.Signature[i]); + formatter.AppendName(sb, meth.Signature[i]); } sb.Append(')'); @@ -572,7 +573,14 @@ protected void LogWarning(XPathNavigator position, DiagnosticId id, params strin private sealed class CecilTypeNameFormatter : TypeNameFormatter { - public static readonly CecilTypeNameFormatter Instance = new CecilTypeNameFormatter(); + public static readonly CecilTypeNameFormatter Instance = new CecilTypeNameFormatter(null); + + private readonly MethodDesc? _method; + + public CecilTypeNameFormatter(MethodDesc? method) + { + _method = method; + } public override void AppendName(StringBuilder sb, ArrayType type) { @@ -620,9 +628,21 @@ public override void AppendName(StringBuilder sb, GenericParameterDesc type) } public override void AppendName(StringBuilder sb, SignatureMethodVariable type) { + if (_method is not null && + type.Index < _method.Instantiation.Length && + _method.Instantiation[type.Index] is GenericParameterDesc genericParameter) + { + sb.Append(genericParameter.Name); + } } public override void AppendName(StringBuilder sb, SignatureTypeVariable type) { + if (_method is not null && + type.Index < _method.OwningType.Instantiation.Length && + _method.OwningType.Instantiation[type.Index] is GenericParameterDesc genericParameter) + { + sb.Append(genericParameter.Name); + } } protected override void AppendNameForInstantiatedType(StringBuilder sb, DefType type) { diff --git a/src/coreclr/tools/ILTrim.Core/DependencyAnalysis/TokenBased/MethodDefinitionNode.cs b/src/coreclr/tools/ILTrim.Core/DependencyAnalysis/TokenBased/MethodDefinitionNode.cs index d7de3c08ae45bd..4e2c7bf0f43f81 100644 --- a/src/coreclr/tools/ILTrim.Core/DependencyAnalysis/TokenBased/MethodDefinitionNode.cs +++ b/src/coreclr/tools/ILTrim.Core/DependencyAnalysis/TokenBased/MethodDefinitionNode.cs @@ -7,9 +7,12 @@ using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using Internal.IL; using Internal.TypeSystem; using Internal.TypeSystem.Ecma; +using Mono.Linker; + namespace ILCompiler.DependencyAnalysis { /// @@ -172,6 +175,8 @@ protected override EntityHandle WriteInternal(ModuleWritingContext writeContext) EcmaType ecmaType = (EcmaType)_module.GetObject(methodDef.GetDeclaringType()); MethodBodyNode bodyNode = writeContext.Factory.MethodBody(_module, Handle); int bodyOffset = bodyNode.Marked + || !writeContext.Factory.Settings.Optimizations.IsEnabled(CodeOptimizations.UnreachableBodies, _module.Assembly.GetName().Name) + || !IsWorthConvertingToThrow(methodDef) ? bodyNode.Write(writeContext) : writeContext.WriteUnreachableMethodBody(Handle, _module); @@ -201,6 +206,31 @@ protected override EntityHandle WriteInternal(ModuleWritingContext writeContext) return outputHandle; } + private bool IsWorthConvertingToThrow(MethodDefinition methodDef) + { + // Some bodies are cheaper size-wise to preserve as-is than to convert to a throw. + const int EmptyBodyLength = 0; // No IL body. + const int RetOnlyBodyLength = 1; // ret + const int NopRetBodyLength = 2; // nop; ret + + int rva = methodDef.RelativeVirtualAddress; + if (rva == 0) + return false; + + BlobReader ilReader = _module.PEReader.GetMethodBody(rva).GetILReader(); + int ilLength = ilReader.Length; + if (ilLength == EmptyBodyLength) + return false; + + if (ilLength == RetOnlyBodyLength) + return ilReader.ReadByte() != (byte)ILOpcode.ret; + + if (ilLength == NopRetBodyLength) + return ilReader.ReadByte() != (byte)ILOpcode.nop || ilReader.ReadByte() != (byte)ILOpcode.ret; + + return true; + } + public override string ToString() { // TODO: would be nice to have a common formatter we can call into that also includes owning type diff --git a/src/coreclr/tools/ILTrim.Tests/ILTrimExpectedFailures.txt b/src/coreclr/tools/ILTrim.Tests/ILTrimExpectedFailures.txt index 4f03cadcadc2be..f983efcd719741 100644 --- a/src/coreclr/tools/ILTrim.Tests/ILTrimExpectedFailures.txt +++ b/src/coreclr/tools/ILTrim.Tests/ILTrimExpectedFailures.txt @@ -119,7 +119,6 @@ DataFlow.GenericParameterDataFlowMarking DataFlow.GenericParameterWarningLocation DataFlow.InterfaceImplementedThroughBaseValidation DataFlow.IReflectDataflow -DataFlow.LocalDataFlowKeptMembers DataFlow.MemberTypes DataFlow.MemberTypesAllOnCopyAssembly DataFlow.MethodParametersDataFlow @@ -174,9 +173,7 @@ Generics.VariantCasting Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.CanDisableOverrideRemoval Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideOfAbstractIsKept Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideOfAbstractIsKeptNonEmpty -Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideOfVirtualCanBeRemoved Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideOfVirtualCanBeRemoved2 -Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideOfVirtualCanBeRemoved3 Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.OverrideThatAlsoFulfilsInterface Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.PreservesOverriddenMethodOverrideOfUsedVirtualStillRemoved Inheritance.AbstractClasses.NoKeptCtor.OverrideRemoval.PreservesOverriddenMethodOverrideOfUsedVirtualStillRemoved2 @@ -229,7 +226,6 @@ Inheritance.Interfaces.OnReferenceType.NoKeptCtor.LocalDowncastDoesNotCuaseOther Inheritance.Interfaces.OnReferenceType.NoKeptCtor.PreserveDependencyPreservesInterfaceMethod Inheritance.Interfaces.OnReferenceType.NoKeptCtor.UnusedTypeHasExplicitInterfaceMethodPreservedViaXml Inheritance.Interfaces.OnReferenceType.NoKeptCtor.UnusedTypeHasExplicitInterfacePropertyPreservedViaXml -Inheritance.Interfaces.OnReferenceType.NoKeptCtor.UnusedTypeHasInterfaceMethodPreservedViaXml Inheritance.Interfaces.OnReferenceType.NoKeptCtor.UnusedTypeWithPreserveMethodsAndInterfaceTypeMarked Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded.ArrayWithIndexAssignedToReturnValue Inheritance.Interfaces.OnReferenceType.NoKeptCtorButInterfaceNeeded.FieldDowncastedToInterface @@ -324,10 +320,7 @@ LinkXml.EmbeddedLinkXmlPreservesAdditionalAssemblyWithOverriddenMethod LinkXml.LinkXmlErrorCases LinkXml.UnusedFieldPreservedByLinkXmlIsKept LinkXml.UnusedInterfaceTypeOnTypeWithPreserveAllIsKept -LinkXml.UnusedMethodPreservedByLinkXmlIsKept LinkXml.UnusedNonRequiredTypeIsRemoved -LinkXml.UnusedTypeWithPreserveFieldsHasMethodsRemoved -LinkXml.UnusedTypeWithPreserveNothingAndPreserveMembers LinkXml.UsedNonRequiredExportedTypeIsKept LinkXml.UsedNonRequiredExportedTypeIsKeptWhenRooted LinkXml.UsedNonRequiredTypeIsKeptWithSingleMethod @@ -370,17 +363,13 @@ Reflection.AssemblyImportedViaReflectionWithDerivedType Reflection.CoreLibMessages Reflection.EventHanderTypeGetInvokeMethod Reflection.EventsUsedViaReflection -Reflection.ExpressionCallString Reflection.IsAssignableFrom Reflection.MethodsUsedViaReflection Reflection.MethodUsedViaReflection Reflection.ObjectGetType Reflection.ObjectGetTypeLibraryMode Reflection.ParametersUsedViaReflection -Reflection.PropertiesUsedViaReflection -Reflection.PropertyUsedViaReflection Reflection.RunClassConstructor -Reflection.RuntimeReflectionExtensionsCalls Reflection.TypeHierarchyLibraryModeSuppressions Reflection.TypeHierarchyReflectionWarnings Reflection.TypeMap @@ -392,7 +381,6 @@ RequiresCapability.ReflectionAccessFromCompilerGeneratedCode RequiresCapability.RequiresAccessedThrough RequiresCapability.RequiresAttributeMismatch RequiresCapability.RequiresCapabilityFromCopiedAssembly -RequiresCapability.RequiresCapabilityReflectionAnalysisEnabled RequiresCapability.RequiresExcludeStatics RequiresCapability.RequiresInCompilerGeneratedCode RequiresCapability.RequiresInCompilerGeneratedCodeRelease @@ -506,7 +494,6 @@ UnreachableBody.ExplicitInstructionCheck UnreachableBody.InterfaceMethod UnreachableBody.LinkedOtherIncludedLibrary UnreachableBody.LinkedOtherIncludedLibraryNoInstanceCtor -UnreachableBody.NotWorthConvertingEmpty UnreachableBody.NotWorthConvertingReturnDouble UnreachableBody.NotWorthConvertingReturnFalse UnreachableBody.NotWorthConvertingReturnFloat diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs index a3a54bd3ecd863..05293e62bf199e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/UnusedMethodPreservedByLinkXmlIsKept.cs @@ -38,9 +38,7 @@ private void NotPreservedMethod() { } - // NativeAOT fails to translate Cecil generic methods - // https://github.com/dotnet/runtime/issues/80462 - [Kept(By = Tool.Trimmer)] + [Kept] private void PreservedMethod5(T arg) { }