| File: Linker.Steps\AddBypassNGenStep.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.Diagnostics; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; namespace Mono.Linker.Steps { public class AddBypassNGenStep : BaseStep { AssemblyDefinition? coreLibAssembly; CustomAttribute? bypassNGenAttribute; protected override void ProcessAssembly(AssemblyDefinition assembly) { if (Annotations.GetAction(assembly) == AssemblyAction.AddBypassNGen) { coreLibAssembly = Context.Resolve(assembly.MainModule.TypeSystem.CoreLibrary); if (coreLibAssembly == null) return; bypassNGenAttribute = null; if (assembly == coreLibAssembly) { EnsureBypassNGenAttribute(assembly.MainModule); } foreach (var type in assembly.MainModule.Types) ProcessType(type); } } void ProcessType(TypeDefinition type) { if (type.HasMethods) ProcessMethods(type.Methods, type.Module); if (type.HasNestedTypes) ProcessNestedTypes(type); } void ProcessMethods(Collection<MethodDefinition> methods, ModuleDefinition module) { foreach (var method in methods) if (!Annotations.IsMarked(method)) { EnsureBypassNGenAttribute(module); method.CustomAttributes.Add(bypassNGenAttribute); } } void ProcessNestedTypes(TypeDefinition type) { for (int i = 0; i < type.NestedTypes.Count; i++) { var nested = type.NestedTypes[i]; ProcessType(nested); } } private void EnsureBypassNGenAttribute(ModuleDefinition targetModule) { Debug.Assert(coreLibAssembly != null); if (bypassNGenAttribute != null) { return; } ModuleDefinition corelibMainModule = coreLibAssembly.MainModule; TypeReference bypassNGenAttributeRef = new TypeReference("System.Runtime", "BypassNGenAttribute", corelibMainModule, targetModule.TypeSystem.CoreLibrary); TypeDefinition bypassNGenAttributeDef = corelibMainModule.MetadataResolver.Resolve(bypassNGenAttributeRef); MethodDefinition? bypassNGenAttributeDefaultConstructor = null; if (bypassNGenAttributeDef == null) { // System.Runtime.BypassNGenAttribute is not found in corelib. Add it. TypeReference systemAttributeRef = new TypeReference("System", "Attribute", corelibMainModule, targetModule.TypeSystem.CoreLibrary); TypeReference systemAttribute = corelibMainModule.MetadataResolver.Resolve(systemAttributeRef); systemAttribute = corelibMainModule.ImportReference(systemAttribute); if (systemAttribute == null) throw new System.ApplicationException("System.Attribute is not found in " + targetModule.TypeSystem.CoreLibrary.Name); MethodReference systemAttributeDefaultConstructorRef = new MethodReference(".ctor", corelibMainModule.TypeSystem.Void, systemAttributeRef); MethodReference systemAttributeDefaultConstructor = corelibMainModule.MetadataResolver.Resolve(systemAttributeDefaultConstructorRef); systemAttributeDefaultConstructor = corelibMainModule.ImportReference(systemAttributeDefaultConstructor); if (systemAttributeDefaultConstructor == null) throw new System.ApplicationException("System.Attribute has no default constructor"); bypassNGenAttributeDef = new TypeDefinition("System.Runtime", "BypassNGenAttribute", TypeAttributes.NotPublic | TypeAttributes.Sealed, systemAttribute); coreLibAssembly.MainModule.Types.Add(bypassNGenAttributeDef); if (Annotations.GetAction(coreLibAssembly) == AssemblyAction.Copy) { Annotations.SetAction(coreLibAssembly, AssemblyAction.Save); } const MethodAttributes ctorAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; bypassNGenAttributeDefaultConstructor = new MethodDefinition(".ctor", ctorAttributes, coreLibAssembly.MainModule.TypeSystem.Void); #pragma warning disable RS0030 // Anything after MarkStep should use Cecil directly as all method bodies should be processed by this point var instructions = bypassNGenAttributeDefaultConstructor.Body.Instructions; #pragma warning restore RS0030 instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Call, systemAttributeDefaultConstructor)); instructions.Add(Instruction.Create(OpCodes.Ret)); bypassNGenAttributeDef.Methods.Add(bypassNGenAttributeDefaultConstructor); } else { foreach (MethodDefinition method in bypassNGenAttributeDef.Methods) { if (method.IsConstructor && !method.IsStatic && !method.HasMetadataParameters()) { bypassNGenAttributeDefaultConstructor = method; break; } } if (bypassNGenAttributeDefaultConstructor == null) { throw new System.ApplicationException("System.Runtime.BypassNGenAttribute has no default constructor"); } } MethodReference defaultConstructorReference = targetModule.ImportReference(bypassNGenAttributeDefaultConstructor); bypassNGenAttribute = new CustomAttribute(defaultConstructorReference); } } }