void PrintMap(TypeDefinition type) { if (!type.HasMethods) { return; } Console.WriteLine("Type {0} map", type); foreach (MethodDefinition method in type.Methods) { if (!method.IsVirtual) { continue; } Console.WriteLine(" Method {0} map", method); IEnumerable <MethodDefinition> overrides = Annotations.GetOverrides(method); foreach (var @override in overrides ?? new MethodDefinition[0]) { Console.WriteLine(" HasOverride {0}", @override); } IEnumerable <MethodDefinition> bases = Annotations.GetBaseMethods(method); foreach (var @base in bases ?? new MethodDefinition[0]) { Console.WriteLine(" Base {0}", @base); } } }
void ProcessVirtualMethod(MethodDefinition method) { IList overrides = Annotations.GetOverrides(method); if (overrides == null) { return; } foreach (MethodDefinition @override in overrides) { ProcessOverride(@override); } }
bool IsOverridenInUserCode(MethodDefinition method) { if (!method.IsVirtual) { return(false); } var overrides = Annotations.GetOverrides(method); if (overrides == null || overrides.Count == 0) { return(false); } foreach (MethodDefinition @override in overrides) { if (!IsProductMethod(@override)) { return(true); } } return(false); }
void ProcessDispose(MethodDefinition bd, MethodDefinition cd) { bool skip = false; // did we detect some fields that could be removed ? if (dispose_methods.Contains(cd)) { // removed unmarked fields skip = FilterDispose(cd); // return value tells us if the Dispose method is now "empty" and could be skipped to the next // (non-empty) base.Dispose if (skip) { // if it does nothing then it should not be part of the final binary //cd.DeclaringType.Methods.Remove (cd); } } var overrides = Annotations.GetOverrides(cd); if (overrides == null) { return; } // every subclass-Dispose should be calling base-Dispose foreach (MethodDefinition od in overrides) { // we do not need to process unmarked code (it won't be part of the final binary) if (!Annotations.IsMarked(od)) { continue; } // we do NOT process non-generated code - we could break user code if (!od.IsGeneratedCode(LinkContext)) { continue; } ProcessDispose(skip ? bd : cd, od); // check if we need to replace the base.Dipose call if (bd == cd) { continue; } // replace "base.Dispose". In C# this always looks fine - but in IL it's the base type that's // used (and needs to change to remove the "empty" Dispose methods) foreach (Instruction ins in od.Body.Instructions) { if (ins.OpCode.Code != Code.Call) { continue; } // we can cross the assembly borders and the Dispose method might not be // part of the existing member references so we import it in such cases if (od.Module != bd.Module) { ins.Operand = od.Module.ImportReference(bd); } else { ins.Operand = bd; } break; } } }
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 (IsAnyMarked(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 (!IsAnyMarked(bases)) { method.IsVirtual = method.IsFinal = method.IsNewSlot = false; } } }
protected override void Process(TypeDefinition type) { // interface members are virtual (and we cannot change this) // we cannot seal interfaces either if (type.IsInterface) { return; } // only optimize code that was marked earlier (the rest will be swept away) if (!Annotations.IsMarked(type)) { return; } // if we do not include any subclass for this type if (!type.IsAbstract && !type.IsSealed && !IsSubclassed(type)) { type.IsSealed = true; #if DEBUG Console.WriteLine("Seal {0} ({1})", type, ++seal); #endif } if (!type.HasMethods) { return; } // process virtual 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; } if (!Annotations.IsMarked(method)) { continue; } var overrides = Annotations.GetOverrides(method); // we cannot de-virtualize nor seal methods if something overrides them if (overrides != null) { // sanity (disable IsSealed == true above) //if (type.IsSealed) // Console.WriteLine (); continue; } // we can seal the method (final in IL / !virtual in C#) method.IsFinal = true; #if DEBUG Console.WriteLine("Final {0} ({1})", method, ++final); #endif // subclasses might need this method to satisfy an interface requirement // and requires dispatch/virtual support if (!type.IsSealed) { continue; } var bases = Annotations.GetBaseMethods(method); // look if this method is an override to existing _marked_ methods if (!AreMarked(bases)) { method.IsVirtual = false; #if DEBUG Console.WriteLine("Devirtualize {0} ({1})", method, ++devirtualize); #endif } } }