| File: Linker.Steps\SealerStep.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// 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.Collections.Generic; using System.Diagnostics; using Mono.Cecil; using Mono.Collections.Generic; namespace Mono.Linker.Steps { public class SealerStep : BaseStep { HashSet<TypeDefinition>? referencedBaseTypeCache; public SealerStep() { } protected override void ProcessAssembly(AssemblyDefinition assembly) { if (!Context.CanApplyOptimization(CodeOptimizations.Sealer, assembly)) return; foreach (var type in assembly.MainModule.Types) ProcessType(type); } protected override void EndProcess() { referencedBaseTypeCache = null; } bool IsSubclassed(TypeDefinition type) { if (referencedBaseTypeCache == null) { referencedBaseTypeCache = new HashSet<TypeDefinition>(); foreach (var a in Context.GetAssemblies()) { if (!Annotations.IsMarked(a)) continue; PopulateCache(a.MainModule.Types); void PopulateCache(Collection<TypeDefinition> types) { foreach (var t in types) { var btd = Context.TryResolve(t.BaseType); if (btd != null) referencedBaseTypeCache.Add(btd); if (t.HasNestedTypes) { PopulateCache(t.NestedTypes); } } } } } var bt = Context.TryResolve(type); return bt != null && referencedBaseTypeCache.Contains(bt); } void ProcessType(TypeDefinition type) { if (type.HasNestedTypes) { foreach (var nt in type.NestedTypes) { ProcessType(nt); } } // // interface members are virtual (and we cannot change this) // if (type.IsInterface) return; // // the code does not include any subclass for this type // if (!type.IsAbstract && !type.IsSealed && !IsSubclassed(type)) SealType(type); if (!type.HasMethods) return; // process methods to see if we can seal or devirtualize them foreach (var method in type.Methods) { if (method.IsFinal || !method.IsVirtual || method.IsAbstract || method.IsRuntime) continue; Debug.Assert(Annotations.IsMarked(method)); if (!Annotations.IsMarked(method)) continue; var overrides = Annotations.GetOverrides(method); // // cannot de-virtualize nor seal methods if something overrides them // if (IsAnyOverrideMarked(overrides)) continue; SealMethod(method); // subclasses might need this method to satisfy an interface requirement // and requires dispatch/virtual support if (!type.IsSealed) continue; var bases = Annotations.GetBaseMethods(method); // Devirtualize if a method is not override to existing marked methods if (!IsAnyBaseMarked(bases)) method.IsVirtual = method.IsFinal = method.IsNewSlot = false; } } protected virtual void SealType(TypeDefinition type) { type.IsSealed = true; } protected virtual void SealMethod(MethodDefinition method) { method.IsFinal = true; } bool IsAnyOverrideMarked(IEnumerable<OverrideInformation>? list) { if (list == null) return false; foreach (var m in list) { if (Annotations.IsMarked(m.Override)) return true; } return false; } bool IsAnyBaseMarked(IEnumerable<OverrideInformation>? list) { if (list == null) return false; foreach (var m in list) { if (Annotations.IsMarked(m.Base)) return true; } return false; } } }