Skip to content

Commit

Permalink
Fix ConstructedType for generic base types (dotnet#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbomer authored Oct 15, 2021
1 parent dc08007 commit 5e88adc
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 13 deletions.
27 changes: 25 additions & 2 deletions src/coreclr/tools/ILTrim/ILTrim.Exe/Program.cs
Original file line number Diff line number Diff line change
@@ -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.Collections.Generic;
using System.IO;
using System.Reflection.PortableExecutable;
Expand All @@ -15,6 +16,9 @@ static void Main(string[] args)
int i = 1;
List<string> referencePaths = new();
List<string> trimPaths = new();
string outputDir = null;
var logStrategy = LogStrategy.None;
string logFile = null;
while (args.Length > i) {
if (args[i] == "-r")
{
Expand All @@ -26,9 +30,28 @@ static void Main(string[] args)
trimPaths.Add(args[i + 1]);
i += 2;
}
else if (args[i] == "-o")
{
outputDir = args[i + 1];
i += 2;
}
else if (args[i] == "-l")
{
logStrategy = Enum.Parse<LogStrategy>(args[i + 1]);
if (logStrategy == LogStrategy.FirstMark || logStrategy == LogStrategy.FullGraph) {
logFile = args[i + 2];
i += 1;
}
i += 2;
}
else
{
throw new ArgumentException("Invalid argument");
}
}

Trimmer.TrimAssembly(inputPath, trimPaths, Directory.GetCurrentDirectory(), referencePaths);
outputDir ??= Directory.GetCurrentDirectory();
var settings = new TrimmerSettings(LogStrategy: logStrategy, LogFile: logFile);
Trimmer.TrimAssembly(inputPath, trimPaths, outputDir, referencePaths, settings);
}
}
}
34 changes: 34 additions & 0 deletions src/coreclr/tools/ILTrim/ILTrim.Tests.Cases/Basic/GenericType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Mono.Linker.Tests.Cases.Expectations.Assertions;

namespace Mono.Linker.Tests.Cases.Basic
{
[Kept]
class GenericType
{
[Kept]
public static void Main()
{
var c = new C();
}
}

[Kept]
[KeptMember(".ctor()")]
class A<T>
{
}

[Kept]
[KeptMember(".ctor()")]
[KeptBaseType(typeof(A<string>))]
class B<T> : A<string>
{
}

[Kept]
[KeptMember(".ctor()")]
[KeptBaseType(typeof(B<int>))]
class C : B<int>
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep

public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
{
DefType baseType = _type.BaseType;
// Call GetTypeDefinition in case the base is an instantiated generic type.
TypeDesc baseType = _type.BaseType?.GetTypeDefinition();
if (baseType != null)
{
yield return new(factory.ConstructedType((EcmaType)baseType), "Base type");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,18 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto

switch (methodOrFieldDef)
{
case EcmaMethod method:
if (factory.IsModuleTrimmed(method.Module))
case MethodDesc method:
if (method.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod && factory.IsModuleTrimmed(ecmaMethod.Module))
{
dependencies.Add(factory.GetNodeForToken(method.Module, method.Handle), "Target method def of member reference");
dependencies.Add(factory.GetNodeForToken(ecmaMethod.Module, ecmaMethod.Handle), "Target method def of member reference");
}
break;

case EcmaField field:
if (factory.IsModuleTrimmed(field.Module))
case FieldDesc field:
var ecmaField = (EcmaField)field.GetTypicalFieldDefinition();
if (factory.IsModuleTrimmed(ecmaField.Module))
{
dependencies.Add(factory.GetNodeForToken(field.Module, field.Handle), "Target field def of member reference");
dependencies.Add(factory.GetNodeForToken(ecmaField.Module, ecmaField.Handle), "Target field def of member reference");
}
break;
}
Expand Down
22 changes: 19 additions & 3 deletions src/coreclr/tools/ILTrim/ILTrim/Trimmer.cs
Original file line number Diff line number Diff line change
@@ -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.IO;
using System.Collections.Generic;
using System.Reflection;
Expand All @@ -15,7 +16,6 @@
using ILTrim.DependencyAnalysis;
using System.Linq;
using System.Threading.Tasks;
using System;

namespace ILTrim
{
Expand Down Expand Up @@ -46,9 +46,18 @@ public static void TrimAssembly(
EcmaModule corelib = context.GetModuleForSimpleName("System.Private.CoreLib");
context.SetSystemModule(corelib);

var factory = new NodeFactory(additionalTrimPaths.Select(p => Path.GetFileNameWithoutExtension(p)));
var trimmedAssemblies = new List<string>(additionalTrimPaths.Select(p => Path.GetFileNameWithoutExtension(p)));
trimmedAssemblies.Add(Path.GetFileNameWithoutExtension(inputPath));
var factory = new NodeFactory(trimmedAssemblies);

var analyzer = new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(factory, resultSorter: null);
DependencyAnalyzerBase<NodeFactory> analyzer = settings.LogStrategy switch
{
LogStrategy.None => new DependencyAnalyzer<NoLogStrategy<NodeFactory>, NodeFactory>(factory, resultSorter: null),
LogStrategy.FirstMark => new DependencyAnalyzer<FirstMarkLogStrategy<NodeFactory>, NodeFactory>(factory, resultSorter: null),
LogStrategy.FullGraph => new DependencyAnalyzer<FullGraphLogStrategy<NodeFactory>, NodeFactory>(factory, resultSorter: null),
LogStrategy.EventSource => new DependencyAnalyzer<EventSourceLogStrategy<NodeFactory>, NodeFactory>(factory, resultSorter: null),
_ => throw new ArgumentException("Invalid log strategy")
};
analyzer.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;

MethodDefinitionHandle entrypointToken = (MethodDefinitionHandle)MetadataTokens.Handle(module.PEReader.PEHeaders.CorHeader.EntryPointTokenOrRelativeVirtualAddress);
Expand All @@ -57,6 +66,8 @@ public static void TrimAssembly(
analyzer.ComputeMarkedNodes();

var writers = ModuleWriter.CreateWriters(factory, analyzer.MarkedNodeList);
if (!File.Exists(outputDir))
Directory.CreateDirectory(outputDir);
RunForEach(writers, writer =>
{
var ext = writer.AssemblyName == "test" ? ".exe" : ".dll";
Expand All @@ -65,6 +76,11 @@ public static void TrimAssembly(
writer.Save(outputStream);
});

if (settings.LogFile != null) {
using var logStream = File.OpenWrite(settings.LogFile);
DgmlWriter.WriteDependencyGraphToStream<NodeFactory>(logStream, analyzer, factory);
}

void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> nodesWithPendingDependencyCalculation) =>
RunForEach(
nodesWithPendingDependencyCalculation.OfType<MethodBodyNode>(),
Expand Down
12 changes: 11 additions & 1 deletion src/coreclr/tools/ILTrim/ILTrim/TrimmerSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,19 @@
namespace ILTrim
{
public record class TrimmerSettings(
int? MaxDegreeOfParallelism = null
int? MaxDegreeOfParallelism = null,
LogStrategy LogStrategy = LogStrategy.None,
string LogFile = null
)
{
public int EffectiveDegreeOfParallelism => MaxDegreeOfParallelism ?? Environment.ProcessorCount;
}

public enum LogStrategy
{
None,
FirstMark,
FullGraph,
EventSource
}
}

0 comments on commit 5e88adc

Please sign in to comment.