Ejemplo n.º 1
0
        // 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);
            }
        }
Ejemplo n.º 2
0
        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);
                        }
                    }
                }
            }
        }