|
// 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 |
CodeOptimizations.SubstituteFeatureGuards, assembly.Name.Name);
// Enable EventSource special handling
Context.DisableEventSourceSpecialHandling = false;
// No metadata trimming
Context.MetadataTrimming = MetadataTrimming.None;
break;
case AssemblyRootMode.AllMembers:
Annotations.SetRootAssembly(assembly);
Annotations.Mark(assembly.MainModule, di, origin);
return;
}
}
AssemblyDefinition? LoadAssemblyFile()
{
AssemblyDefinition? assembly;
if (File.Exists(fileName))
{
assembly = Context.Resolver.GetAssembly(fileName);
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;
}
}
}
|