// Enumerate all possible virtual slots of a type public static IEnumerable <MethodDesc> EnumAllVirtualSlots(MetadataType type) { MethodDescHashtable alreadyEnumerated = new MethodDescHashtable(); if (!type.IsInterface) { do { foreach (MethodDesc m in type.GetAllMethods()) { if (!m.IsVirtual) { continue; } MethodDesc possibleVirtual = FindSlotDefiningMethodForVirtualMethod(m); if (!alreadyEnumerated.Contains(possibleVirtual)) { alreadyEnumerated.AddOrGetExisting(possibleVirtual); yield return(possibleVirtual); } } type = type.MetadataBaseType; } while (type != null); } }
private static void FindBaseUnificationGroup(MetadataType currentType, UnificationGroup unificationGroup) { MethodDesc originalDefiningMethod = unificationGroup.DefiningMethod; MethodDesc methodImpl = FindImplFromDeclFromMethodImpls(currentType, unificationGroup.DefiningMethod); if (methodImpl != null) { if (methodImpl.RequiresSlotUnification()) { unificationGroup.AddMethodRequiringSlotUnification(unificationGroup.DefiningMethod); unificationGroup.AddMethodRequiringSlotUnification(methodImpl); } unificationGroup.SetDefiningMethod(methodImpl); } MethodDesc nameSigMatchMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(unificationGroup.DefiningMethod, currentType, reverseMethodSearch: true); MetadataType baseType = currentType.MetadataBaseType; // Unless the current type has a name/sig match for the group, look to the base type to define the unification group further if ((nameSigMatchMethod == null) && (baseType != null)) { FindBaseUnificationGroup(baseType, unificationGroup); } Debug.Assert(unificationGroup.IsInGroupOrIsDefiningSlot(originalDefiningMethod)); // Now, we have the unification group from the type, or have discovered its defined on the current type. // Adjust the group to contain all of the elements that are added to it on this type, remove the components that // have seperated themselves from the group // Start with removing methods that seperated themselves from the group via name/sig matches MethodDescHashtable separatedMethods = null; foreach (MethodDesc memberMethod in unificationGroup.Members) { MethodDesc nameSigMatchMemberMethod = FindMatchingVirtualMethodOnTypeByNameAndSigWithSlotCheck(memberMethod, currentType, reverseMethodSearch: true); if (nameSigMatchMemberMethod != null && nameSigMatchMemberMethod != memberMethod) { if (separatedMethods == null) { separatedMethods = new MethodDescHashtable(); } separatedMethods.AddOrGetExisting(memberMethod); } } if (separatedMethods != null) { foreach (MethodDesc seperatedMethod in MethodDescHashtable.Enumerator.Get(separatedMethods)) { unificationGroup.RemoveFromGroup(seperatedMethod); } } // Next find members which have seperated or added themselves to the group via MethodImpls foreach (MethodImplRecord methodImplRecord in currentType.VirtualMethodImplsForType) { MethodDesc declSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Decl); MethodDesc implSlot = FindSlotDefiningMethodForVirtualMethod(methodImplRecord.Body); if (unificationGroup.IsInGroup(declSlot) && !unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) { unificationGroup.RemoveFromGroup(declSlot); if (separatedMethods == null) { separatedMethods = new MethodDescHashtable(); } separatedMethods.AddOrGetExisting(declSlot); if (unificationGroup.RequiresSlotUnification(declSlot) || implSlot.RequiresSlotUnification()) { if (implSlot.Signature.EqualsWithCovariantReturnType(unificationGroup.DefiningMethod.Signature)) { unificationGroup.AddMethodRequiringSlotUnification(declSlot); unificationGroup.AddMethodRequiringSlotUnification(implSlot); unificationGroup.SetDefiningMethod(implSlot); } } continue; } if (!unificationGroup.IsInGroupOrIsDefiningSlot(declSlot)) { if (unificationGroup.IsInGroupOrIsDefiningSlot(implSlot)) { // Add decl to group. // To do so, we need to have the Unification Group of the decl slot, as it may have multiple members itself UnificationGroup addDeclGroup = new UnificationGroup(declSlot); FindBaseUnificationGroup(baseType, addDeclGroup); Debug.Assert( addDeclGroup.IsInGroupOrIsDefiningSlot(declSlot) || (addDeclGroup.RequiresSlotUnification(declSlot) && addDeclGroup.DefiningMethod.Signature.EqualsWithCovariantReturnType(declSlot.Signature))); foreach (MethodDesc methodImplRequiredToRemainInEffect in addDeclGroup.MethodsRequiringSlotUnification) { unificationGroup.AddMethodRequiringSlotUnification(methodImplRequiredToRemainInEffect); } // Add all members from the decl's unification group except for ones that have been seperated by name/sig matches // or previously processed methodimpls. NOTE: This implies that method impls are order dependent. if (separatedMethods == null || !separatedMethods.Contains(addDeclGroup.DefiningMethod)) { unificationGroup.AddToGroup(addDeclGroup.DefiningMethod); } foreach (MethodDesc addDeclGroupMemberMethod in addDeclGroup.Members) { if (separatedMethods == null || !separatedMethods.Contains(addDeclGroupMemberMethod)) { unificationGroup.AddToGroup(addDeclGroupMemberMethod); } } if (unificationGroup.RequiresSlotUnification(declSlot)) { unificationGroup.AddMethodRequiringSlotUnification(implSlot); } else if (implSlot == unificationGroup.DefiningMethod && implSlot.RequiresSlotUnification()) { unificationGroup.AddMethodRequiringSlotUnification(declSlot); unificationGroup.AddMethodRequiringSlotUnification(implSlot); } } else if (unificationGroup.RequiresSlotUnification(declSlot)) { if (implSlot.Signature.EqualsWithCovariantReturnType(unificationGroup.DefiningMethod.Signature)) { unificationGroup.AddMethodRequiringSlotUnification(implSlot); unificationGroup.SetDefiningMethod(implSlot); } } } } }