/// <summary> /// Resolve a virtual function call (to a virtual method, not an interface method) /// </summary> /// <param name="targetMethod"></param> /// <param name="objectType"></param> /// <returns>The override of the virtual method that should be called</returns> private static MethodDesc FindVirtualFunctionTargetMethodOnObjectType(MethodDesc targetMethod, MetadataType objectType) { // Step 1, convert objectType to uninstantiated form MetadataType uninstantiatedType = objectType; MethodDesc initialTargetMethod = targetMethod; InstantiatedType initialInstantiatedType = objectType as InstantiatedType; if (initialInstantiatedType != null) { uninstantiatedType = (MetadataType)initialInstantiatedType.GetTypeDefinition(); } // Step 2, convert targetMethod to method in type hierarchy of uninstantiated form targetMethod = targetMethod.GetMethodDefinition(); if (uninstantiatedType != objectType) { targetMethod = uninstantiatedType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod); } // Step 3, find unification group of target method UnificationGroup group = new UnificationGroup(FindSlotDefiningMethodForVirtualMethod(targetMethod)); FindBaseUnificationGroup(uninstantiatedType, group); // Step 4, name/sig match virtual function resolve MethodDesc resolutionTarget = FindNameSigOverrideForVirtualMethod(group.DefiningMethod, uninstantiatedType); if (resolutionTarget == null) { return(null); } // Step 5, convert resolution target from uninstantiated form target to objecttype target, // and instantiate as appropriate if (uninstantiatedType != objectType) { resolutionTarget = objectType.FindMethodOnTypeWithMatchingTypicalMethod(resolutionTarget); } if (initialTargetMethod.HasInstantiation) { resolutionTarget = resolutionTarget.MakeInstantiatedMethod(initialTargetMethod.Instantiation); } return(resolutionTarget); }
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); } } } } }