/// <summary> /// Scan the type and its base types for an implementation of an interface method. Returns null if no /// implementation is found. /// </summary> public static MethodDesc ResolveInterfaceMethodTarget(this TypeDesc thisType, MethodDesc interfaceMethodToResolve) { Debug.Assert(interfaceMethodToResolve.OwningType.IsInterface); MethodDesc result = null; TypeDesc currentType = thisType; do { result = currentType.ResolveInterfaceMethodToVirtualMethodOnType(interfaceMethodToResolve); currentType = currentType.BaseType; }while (result == null && currentType != null); return(result); }
/// <summary> /// Attempts to resolve constrained call to <paramref name="interfaceMethod"/> into a concrete non-unboxing /// method on <paramref name="constrainedType"/>. /// The ability to resolve constraint methods is affected by the degree of code sharing we are performing /// for generic code. /// </summary> /// <returns>The resolved method or null if the constraint couldn't be resolved.</returns> public static MethodDesc TryResolveConstraintMethodApprox(this TypeDesc constrainedType, TypeDesc interfaceType, MethodDesc interfaceMethod, out bool forceRuntimeLookup) { forceRuntimeLookup = false; // We can't resolve constraint calls effectively for reference types, and there's // not a lot of perf. benefit in doing it anyway. if (!constrainedType.IsValueType) { return(null); } // Non-virtual methods called through constraints simply resolve to the specified method without constraint resolution. if (!interfaceMethod.IsVirtual) { return(null); } MethodDesc method; MethodDesc genInterfaceMethod = interfaceMethod.GetMethodDefinition(); if (genInterfaceMethod.OwningType.IsInterface) { // Sometimes (when compiling shared generic code) // we don't have enough exact type information at JIT time // even to decide whether we will be able to resolve to an unboxed entry point... // To cope with this case we always go via the helper function if there's any // chance of this happening by checking for all interfaces which might possibly // be compatible with the call (verification will have ensured that // at least one of them will be) // Enumerate all potential interface instantiations // TODO: this code assumes no shared generics Debug.Assert(interfaceType == interfaceMethod.OwningType); method = constrainedType.ResolveInterfaceMethodToVirtualMethodOnType(genInterfaceMethod); } else if (genInterfaceMethod.IsVirtual) { method = constrainedType.FindVirtualFunctionTargetMethodOnObjectType(genInterfaceMethod); } else { // The method will be null if calling a non-virtual instance // methods on System.Object, i.e. when these are used as a constraint. method = null; } if (method == null) { // Fall back to VSD return(null); } //#TryResolveConstraintMethodApprox_DoNotReturnParentMethod // Only return a method if the value type itself declares the method, // otherwise we might get a method from Object or System.ValueType if (!method.OwningType.IsValueType) { // Fall back to VSD return(null); } // We've resolved the method, ignoring its generic method arguments // If the method is a generic method then go and get the instantiated descriptor if (interfaceMethod.HasInstantiation) { method = method.MakeInstantiatedMethod(interfaceMethod.Instantiation); } Debug.Assert(method != null); //assert(!pMD->IsUnboxingStub()); return(method); }
/// <summary> /// Resolve a call on the interface method targetVirtualMethod, on the type instanceDefTypeToExamine utilizing metadata to /// its associated virtual method. /// </summary> /// <param name="instanceDefTypeToExamine">(in) The class type on which the interface call is made, (out) the class type where the search may continue using non-metadata means</param> /// <param name="targetVirtualMethod">The interface method to translate into a virtual method for execution</param> /// <returns>virtual method slot which implements the interface method OR null if an implementation should fall back to non-metadata based lookup.</returns> public static MethodDesc ResolveInterfaceMethodToVirtualMethod(TypeDesc instanceType, out TypeDesc instanceDefTypeToExamine, MethodDesc targetVirtualMethod) { instanceDefTypeToExamine = instanceType.GetClosestDefType(); MethodDesc newlyFoundVirtualMethod = null; LowLevelList<MethodDesc> variantTargets = null; if (targetVirtualMethod.OwningType.HasVariance) { foreach (TypeDesc type in instanceType.RuntimeInterfaces) { if (type != targetVirtualMethod.OwningType && type.GetTypeDefinition() == targetVirtualMethod.OwningType.GetTypeDefinition()) { // Check to see if these interfaces are appropriately assignable if (RuntimeAugments.IsAssignableFrom(targetVirtualMethod.OwningType.GetRuntimeTypeHandle(), type.GetRuntimeTypeHandle())) { if (variantTargets == null) variantTargets = new LowLevelList<MethodDesc>(); MethodDesc targetVariantMatch = type.Context.GetMethodForInstantiatedType( targetVirtualMethod.GetTypicalMethodDefinition(), (InstantiatedType)type); variantTargets.Add(targetVariantMatch); } } } } do { newlyFoundVirtualMethod = instanceDefTypeToExamine.ResolveInterfaceMethodToVirtualMethodOnType(targetVirtualMethod); if (newlyFoundVirtualMethod == null && variantTargets != null) { for (int i = 0; i < variantTargets.Count; i++) { newlyFoundVirtualMethod = instanceDefTypeToExamine.ResolveInterfaceMethodToVirtualMethodOnType(variantTargets[i]); if (newlyFoundVirtualMethod != null) break; } } instanceDefTypeToExamine = instanceDefTypeToExamine.BaseType; } while ((newlyFoundVirtualMethod == null) && (instanceDefTypeToExamine != null) && !IsPregeneratedOrTemplateTypeLoaded(instanceDefTypeToExamine)); return newlyFoundVirtualMethod; }