Skip to content

Commit 63e3eb5

Browse files
sbomerdotnet-bot
authored andcommitted
Make default rooting behavior consistent (dotnet#3124)
Now specifying an assembly as a root without any other qualifiers will default to rooting everything. Commit migrated from dotnet@e775974
1 parent 64988c9 commit 63e3eb5

File tree

11 files changed

+3199
-0
lines changed

11 files changed

+3199
-0
lines changed

src/tools/illink/src/ILLink.Tasks/LinkTask.cs

Lines changed: 511 additions & 0 deletions
Large diffs are not rendered by default.

src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets

Lines changed: 352 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.IO;
5+
using ILLink.Shared;
6+
using Mono.Cecil;
7+
8+
namespace Mono.Linker.Steps
9+
{
10+
public class RootAssemblyInput : BaseStep
11+
{
12+
readonly string fileName;
13+
readonly AssemblyRootMode rootMode;
14+
15+
public RootAssemblyInput (string fileName, AssemblyRootMode rootMode)
16+
{
17+
this.fileName = fileName;
18+
this.rootMode = rootMode;
19+
}
20+
21+
protected override void Process ()
22+
{
23+
AssemblyDefinition? assembly = LoadAssemblyFile ();
24+
if (assembly == null)
25+
return;
26+
27+
var di = new DependencyInfo (DependencyKind.RootAssembly, assembly);
28+
var origin = new MessageOrigin (assembly);
29+
30+
AssemblyAction action = Context.Annotations.GetAction (assembly);
31+
switch (action) {
32+
case AssemblyAction.Copy:
33+
Annotations.Mark (assembly.MainModule, di, origin);
34+
// Mark Step will take care of marking whole assembly
35+
return;
36+
case AssemblyAction.CopyUsed:
37+
case AssemblyAction.Link:
38+
break;
39+
default:
40+
Context.LogError (null, DiagnosticId.RootAssemblyCannotUseAction, assembly.Name.ToString (), action.ToString ());
41+
return;
42+
}
43+
44+
switch (rootMode) {
45+
case AssemblyRootMode.EntryPoint:
46+
var ep = assembly.MainModule.EntryPoint;
47+
if (ep == null) {
48+
Context.LogError (null, DiagnosticId.RootAssemblyDoesNotHaveEntryPoint, assembly.Name.ToString ());
49+
return;
50+
}
51+
52+
Annotations.Mark (ep.DeclaringType, di, origin);
53+
Annotations.AddPreservedMethod (ep.DeclaringType, ep);
54+
break;
55+
case AssemblyRootMode.VisibleMembers:
56+
var preserve_visible = TypePreserveMembers.Visible;
57+
if (MarkInternalsVisibleTo (assembly))
58+
preserve_visible |= TypePreserveMembers.Internal;
59+
60+
MarkAndPreserve (assembly, preserve_visible);
61+
break;
62+
63+
case AssemblyRootMode.Library:
64+
var preserve_library = TypePreserveMembers.Visible | TypePreserveMembers.Library;
65+
if (MarkInternalsVisibleTo (assembly))
66+
preserve_library |= TypePreserveMembers.Internal;
67+
68+
MarkAndPreserve (assembly, preserve_library);
69+
70+
// Assembly root mode wins over any enabled optimization which
71+
// could conflict with library rooting behaviour
72+
Context.Optimizations.Disable (
73+
CodeOptimizations.Sealer |
74+
CodeOptimizations.UnusedTypeChecks |
75+
CodeOptimizations.UnreachableBodies |
76+
CodeOptimizations.UnusedInterfaces |
77+
CodeOptimizations.RemoveDescriptors |
78+
CodeOptimizations.RemoveLinkAttributes |
79+
CodeOptimizations.RemoveSubstitutions |
80+
CodeOptimizations.RemoveDynamicDependencyAttribute |
81+
CodeOptimizations.OptimizeTypeHierarchyAnnotations, assembly.Name.Name);
82+
83+
// Enable EventSource special handling
84+
Context.DisableEventSourceSpecialHandling = false;
85+
86+
// No metadata trimming
87+
Context.MetadataTrimming = MetadataTrimming.None;
88+
break;
89+
case AssemblyRootMode.AllMembers:
90+
Context.Annotations.SetAction (assembly, AssemblyAction.Copy);
91+
return;
92+
}
93+
}
94+
95+
AssemblyDefinition? LoadAssemblyFile ()
96+
{
97+
AssemblyDefinition? assembly;
98+
99+
if (File.Exists (fileName)) {
100+
assembly = Context.Resolver.GetAssembly (fileName);
101+
AssemblyDefinition? loaded = Context.GetLoadedAssembly (assembly.Name.Name);
102+
103+
// The same assembly could be already loaded if there are multiple inputs pointing to same file
104+
if (loaded != null)
105+
return loaded;
106+
107+
Context.Resolver.CacheAssembly (assembly);
108+
return assembly;
109+
}
110+
111+
//
112+
// Quirks mode for netcore to support passing ambiguous assembly name
113+
//
114+
assembly = Context.TryResolve (fileName);
115+
if (assembly == null)
116+
Context.LogError (null, DiagnosticId.RootAssemblyCouldNotBeFound, fileName);
117+
118+
return assembly;
119+
}
120+
121+
void MarkAndPreserve (AssemblyDefinition assembly, TypePreserveMembers preserve)
122+
{
123+
var module = assembly.MainModule;
124+
if (module.HasExportedTypes)
125+
foreach (var type in module.ExportedTypes)
126+
MarkAndPreserve (assembly, type, preserve);
127+
128+
foreach (var type in module.Types)
129+
MarkAndPreserve (type, preserve);
130+
}
131+
132+
void MarkAndPreserve (TypeDefinition type, TypePreserveMembers preserve)
133+
{
134+
TypePreserveMembers preserve_anything = preserve;
135+
if ((preserve & TypePreserveMembers.Visible) != 0 && !IsTypeVisible (type))
136+
preserve_anything &= ~TypePreserveMembers.Visible;
137+
138+
if ((preserve & TypePreserveMembers.Internal) != 0 && IsTypePrivate (type))
139+
preserve_anything &= ~TypePreserveMembers.Internal;
140+
141+
// Keep all interfaces and interface members in library mode
142+
if ((preserve & TypePreserveMembers.Library) != 0 && type.IsInterface) {
143+
Annotations.Mark (type, new DependencyInfo (DependencyKind.RootAssembly, type.Module.Assembly), new MessageOrigin (type.Module.Assembly));
144+
Annotations.SetPreserve (type, TypePreserve.All);
145+
}
146+
147+
switch (preserve_anything) {
148+
case 0:
149+
return;
150+
case TypePreserveMembers.Library:
151+
//
152+
// In library mode private type can have members kept for serialization if
153+
// the type is referenced
154+
//
155+
preserve = preserve_anything;
156+
Annotations.SetMembersPreserve (type, preserve);
157+
break;
158+
default:
159+
Annotations.Mark (type, new DependencyInfo (DependencyKind.RootAssembly, type.Module.Assembly), new MessageOrigin (type.Module.Assembly));
160+
Annotations.SetMembersPreserve (type, preserve);
161+
break;
162+
}
163+
164+
if (!type.HasNestedTypes)
165+
return;
166+
167+
foreach (TypeDefinition nested in type.NestedTypes)
168+
MarkAndPreserve (nested, preserve);
169+
}
170+
171+
void MarkAndPreserve (AssemblyDefinition assembly, ExportedType type, TypePreserveMembers preserve)
172+
{
173+
var di = new DependencyInfo (DependencyKind.RootAssembly, assembly);
174+
var origin = new MessageOrigin (assembly);
175+
Context.Annotations.Mark (type, di, origin);
176+
Context.Annotations.Mark (assembly.MainModule, di, origin);
177+
Annotations.SetMembersPreserve (type, preserve);
178+
}
179+
180+
static bool IsTypeVisible (TypeDefinition type)
181+
{
182+
return type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly;
183+
}
184+
185+
static bool IsTypePrivate (TypeDefinition type)
186+
{
187+
return type.IsNestedPrivate;
188+
}
189+
190+
bool MarkInternalsVisibleTo (AssemblyDefinition assembly)
191+
{
192+
foreach (CustomAttribute attribute in assembly.CustomAttributes) {
193+
if (attribute.Constructor.DeclaringType.IsTypeOf ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute")) {
194+
Context.Annotations.Mark (attribute, new DependencyInfo (DependencyKind.RootAssembly, assembly));
195+
return true;
196+
}
197+
}
198+
199+
return false;
200+
}
201+
}
202+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Mono.Linker
5+
{
6+
public enum AssemblyRootMode
7+
{
8+
AllMembers = 0,
9+
EntryPoint,
10+
VisibleMembers,
11+
Library
12+
}
13+
}

0 commit comments

Comments
 (0)