forked from dotnet/linker
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
64988c9
commit 63e3eb5
Showing
11 changed files
with
3,199 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
352 changes: 352 additions & 0 deletions
352
src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets
Large diffs are not rendered by default.
Oops, something went wrong.
202 changes: 202 additions & 0 deletions
202
src/tools/illink/src/linker/Linker.Steps/RootAssemblyInputStep.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
// Copyright (c) .NET Foundation and contributors. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System.IO; | ||
using ILLink.Shared; | ||
using Mono.Cecil; | ||
|
||
namespace Mono.Linker.Steps | ||
{ | ||
public class RootAssemblyInput : BaseStep | ||
{ | ||
readonly string fileName; | ||
readonly AssemblyRootMode rootMode; | ||
|
||
public RootAssemblyInput (string fileName, AssemblyRootMode rootMode) | ||
{ | ||
this.fileName = fileName; | ||
this.rootMode = rootMode; | ||
} | ||
|
||
protected override void Process () | ||
{ | ||
AssemblyDefinition? assembly = LoadAssemblyFile (); | ||
if (assembly == null) | ||
return; | ||
|
||
var di = new DependencyInfo (DependencyKind.RootAssembly, assembly); | ||
var origin = new MessageOrigin (assembly); | ||
|
||
AssemblyAction action = Context.Annotations.GetAction (assembly); | ||
switch (action) { | ||
case AssemblyAction.Copy: | ||
Annotations.Mark (assembly.MainModule, di, origin); | ||
// Mark Step will take care of marking whole assembly | ||
return; | ||
case AssemblyAction.CopyUsed: | ||
case AssemblyAction.Link: | ||
break; | ||
default: | ||
Context.LogError (null, DiagnosticId.RootAssemblyCannotUseAction, assembly.Name.ToString (), action.ToString ()); | ||
return; | ||
} | ||
|
||
switch (rootMode) { | ||
case AssemblyRootMode.EntryPoint: | ||
var ep = assembly.MainModule.EntryPoint; | ||
if (ep == null) { | ||
Context.LogError (null, DiagnosticId.RootAssemblyDoesNotHaveEntryPoint, assembly.Name.ToString ()); | ||
return; | ||
} | ||
|
||
Annotations.Mark (ep.DeclaringType, di, origin); | ||
Annotations.AddPreservedMethod (ep.DeclaringType, ep); | ||
break; | ||
case AssemblyRootMode.VisibleMembers: | ||
var preserve_visible = TypePreserveMembers.Visible; | ||
if (MarkInternalsVisibleTo (assembly)) | ||
preserve_visible |= TypePreserveMembers.Internal; | ||
|
||
MarkAndPreserve (assembly, preserve_visible); | ||
break; | ||
|
||
case AssemblyRootMode.Library: | ||
var preserve_library = TypePreserveMembers.Visible | TypePreserveMembers.Library; | ||
if (MarkInternalsVisibleTo (assembly)) | ||
preserve_library |= TypePreserveMembers.Internal; | ||
|
||
MarkAndPreserve (assembly, preserve_library); | ||
|
||
// Assembly root mode wins over any enabled optimization which | ||
// could conflict with library rooting behaviour | ||
Context.Optimizations.Disable ( | ||
CodeOptimizations.Sealer | | ||
CodeOptimizations.UnusedTypeChecks | | ||
CodeOptimizations.UnreachableBodies | | ||
CodeOptimizations.UnusedInterfaces | | ||
CodeOptimizations.RemoveDescriptors | | ||
CodeOptimizations.RemoveLinkAttributes | | ||
CodeOptimizations.RemoveSubstitutions | | ||
CodeOptimizations.RemoveDynamicDependencyAttribute | | ||
CodeOptimizations.OptimizeTypeHierarchyAnnotations, assembly.Name.Name); | ||
|
||
// Enable EventSource special handling | ||
Context.DisableEventSourceSpecialHandling = false; | ||
|
||
// No metadata trimming | ||
Context.MetadataTrimming = MetadataTrimming.None; | ||
break; | ||
case AssemblyRootMode.AllMembers: | ||
Context.Annotations.SetAction (assembly, AssemblyAction.Copy); | ||
return; | ||
} | ||
} | ||
|
||
AssemblyDefinition? LoadAssemblyFile () | ||
{ | ||
AssemblyDefinition? assembly; | ||
|
||
if (File.Exists (fileName)) { | ||
assembly = Context.Resolver.GetAssembly (fileName); | ||
AssemblyDefinition? loaded = Context.GetLoadedAssembly (assembly.Name.Name); | ||
|
||
// The same assembly could be already loaded if there are multiple inputs pointing to same file | ||
if (loaded != null) | ||
return loaded; | ||
|
||
Context.Resolver.CacheAssembly (assembly); | ||
return assembly; | ||
} | ||
|
||
// | ||
// Quirks mode for netcore to support passing ambiguous assembly name | ||
// | ||
assembly = Context.TryResolve (fileName); | ||
if (assembly == null) | ||
Context.LogError (null, DiagnosticId.RootAssemblyCouldNotBeFound, fileName); | ||
|
||
return assembly; | ||
} | ||
|
||
void MarkAndPreserve (AssemblyDefinition assembly, TypePreserveMembers preserve) | ||
{ | ||
var module = assembly.MainModule; | ||
if (module.HasExportedTypes) | ||
foreach (var type in module.ExportedTypes) | ||
MarkAndPreserve (assembly, type, preserve); | ||
|
||
foreach (var type in module.Types) | ||
MarkAndPreserve (type, preserve); | ||
} | ||
|
||
void MarkAndPreserve (TypeDefinition type, TypePreserveMembers preserve) | ||
{ | ||
TypePreserveMembers preserve_anything = preserve; | ||
if ((preserve & TypePreserveMembers.Visible) != 0 && !IsTypeVisible (type)) | ||
preserve_anything &= ~TypePreserveMembers.Visible; | ||
|
||
if ((preserve & TypePreserveMembers.Internal) != 0 && IsTypePrivate (type)) | ||
preserve_anything &= ~TypePreserveMembers.Internal; | ||
|
||
// Keep all interfaces and interface members in library mode | ||
if ((preserve & TypePreserveMembers.Library) != 0 && type.IsInterface) { | ||
Annotations.Mark (type, new DependencyInfo (DependencyKind.RootAssembly, type.Module.Assembly), new MessageOrigin (type.Module.Assembly)); | ||
Annotations.SetPreserve (type, TypePreserve.All); | ||
} | ||
|
||
switch (preserve_anything) { | ||
case 0: | ||
return; | ||
case TypePreserveMembers.Library: | ||
// | ||
// In library mode private type can have members kept for serialization if | ||
// the type is referenced | ||
// | ||
preserve = preserve_anything; | ||
Annotations.SetMembersPreserve (type, preserve); | ||
break; | ||
default: | ||
Annotations.Mark (type, new DependencyInfo (DependencyKind.RootAssembly, type.Module.Assembly), new MessageOrigin (type.Module.Assembly)); | ||
Annotations.SetMembersPreserve (type, preserve); | ||
break; | ||
} | ||
|
||
if (!type.HasNestedTypes) | ||
return; | ||
|
||
foreach (TypeDefinition nested in type.NestedTypes) | ||
MarkAndPreserve (nested, preserve); | ||
} | ||
|
||
void MarkAndPreserve (AssemblyDefinition assembly, ExportedType type, TypePreserveMembers preserve) | ||
{ | ||
var di = new DependencyInfo (DependencyKind.RootAssembly, assembly); | ||
var origin = new MessageOrigin (assembly); | ||
Context.Annotations.Mark (type, di, origin); | ||
Context.Annotations.Mark (assembly.MainModule, di, origin); | ||
Annotations.SetMembersPreserve (type, preserve); | ||
} | ||
|
||
static bool IsTypeVisible (TypeDefinition type) | ||
{ | ||
return type.IsPublic || type.IsNestedPublic || type.IsNestedFamily || type.IsNestedFamilyOrAssembly; | ||
} | ||
|
||
static bool IsTypePrivate (TypeDefinition type) | ||
{ | ||
return type.IsNestedPrivate; | ||
} | ||
|
||
bool MarkInternalsVisibleTo (AssemblyDefinition assembly) | ||
{ | ||
foreach (CustomAttribute attribute in assembly.CustomAttributes) { | ||
if (attribute.Constructor.DeclaringType.IsTypeOf ("System.Runtime.CompilerServices", "InternalsVisibleToAttribute")) { | ||
Context.Annotations.Mark (attribute, new DependencyInfo (DependencyKind.RootAssembly, assembly)); | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Copyright (c) .NET Foundation and contributors. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
namespace Mono.Linker | ||
{ | ||
public enum AssemblyRootMode | ||
{ | ||
AllMembers = 0, | ||
EntryPoint, | ||
VisibleMembers, | ||
Library | ||
} | ||
} |
Oops, something went wrong.