|
// 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;
}
}
}
|