/// <summary> /// Try to resolve a virtual call to targetMethod to its implementation on instanceType. /// </summary> /// <param name="instanceType">non-interface type</param> /// <param name="targetMethod">non-generic virtual or interface method</param> /// <param name="methodAddress">function pointer resolved</param> /// <returns>true if successful</returns> public static bool TryDispatchMethodOnTarget(TypeDesc instanceType, MethodDesc targetMethod, out IntPtr methodAddress) { methodAddress = IntPtr.Zero; if (targetMethod == null) return false; if (IsPregeneratedOrTemplateTypeLoaded(instanceType)) { if (targetMethod.OwningType.IsInterface) { ushort interfaceSlot; if (!TryGetInterfaceSlotNumberFromMethod(targetMethod, out interfaceSlot)) { return false; } methodAddress = RuntimeAugments.ResolveDispatchOnType(instanceType.GetRuntimeTypeHandle(), targetMethod.OwningType.GetRuntimeTypeHandle(), interfaceSlot); Debug.Assert(methodAddress != IntPtr.Zero); // TODO! This should happen for ICastable dispatch... return true; } else { unsafe { int vtableSlotIndex = LazyVTableResolver.VirtualMethodToSlotIndex(targetMethod); EEType* eeType = instanceType.GetRuntimeTypeHandle().ToEETypePtr(); IntPtr* vtableStart = (IntPtr*)(((byte*)eeType) + sizeof(EEType)); methodAddress = vtableStart[vtableSlotIndex]; return true; } } } MethodDesc targetVirtualMethod = targetMethod; DefType instanceDefType = instanceType.GetClosestDefType(); // For interface resolution, its a two step process, first get the virtual slot if (targetVirtualMethod.OwningType.IsInterface) { TypeDesc instanceDefTypeToExamine; MethodDesc newlyFoundVirtualMethod = ResolveInterfaceMethodToVirtualMethod(instanceType, out instanceDefTypeToExamine, targetVirtualMethod); targetVirtualMethod = newlyFoundVirtualMethod; // The pregenerated type must be the one that implements the interface method // Call into Redhawk to deal with this. if ((newlyFoundVirtualMethod == null) && (instanceDefTypeToExamine != null)) { ushort interfaceSlot; if (!TryGetInterfaceSlotNumberFromMethod(targetMethod, out interfaceSlot)) { return false; } methodAddress = RuntimeAugments.ResolveDispatchOnType(instanceDefTypeToExamine.GetRuntimeTypeHandle(), targetMethod.OwningType.GetRuntimeTypeHandle(), interfaceSlot); Debug.Assert(methodAddress != IntPtr.Zero); // TODO! This should happen for ICastable dispatch... return true; } } // VirtualSlot can be null if the interface method isn't really implemented. This should never happen, but since our // type loader doesn't check all interface overloads at load time, it could happen if (targetVirtualMethod == null) return false; // Resolve virtual method to exact method MethodDesc dispatchMethod = instanceDefType.FindVirtualFunctionTargetMethodOnObjectType(targetVirtualMethod); return TryGetVTableCallableAddress(dispatchMethod, out methodAddress); }
private static bool TryGetVirtualMethodFromSlot(TypeDesc definingType, int vtableSlotIndex, out MethodDesc slotDefiningMethod) { MethodNameAndSignature methodNameAndSig; bool success = TypeLoaderEnvironment.TryGetMethodMethodNameAndSigFromVTableSlotForPregeneratedOrTemplateType (definingType.Context, definingType.GetRuntimeTypeHandle(), vtableSlotIndex, out methodNameAndSig); if (!success) { slotDefiningMethod = null; return false; } TypeSystem.NativeFormat.NativeFormatType metadataDefiningType = definingType.GetClosestDefType().GetTypeDefinition() as TypeSystem.NativeFormat.NativeFormatType; // We're working with a NoMetadataType, or an ArrayType, neither of which have full metadata if (metadataDefiningType == null) { slotDefiningMethod = null; return false; } // TryGetMethodMethodNameAndSigFromVTableSlotForPregeneratedOrTemplateType is expected to only return methodNameAndSig with NativeLayoutSignatures in them. // If we start hitting the more general case, we can improve this algorithm. Debug.Assert(methodNameAndSig.Signature.IsNativeLayoutSignature); foreach (TypeSystem.NativeFormat.NativeFormatMethod method in metadataDefiningType.GetMethods()) { if (!method.IsVirtual) continue; if (method.HasInstantiation) continue; if (!method.Name.Equals(methodNameAndSig.Name)) continue; MethodSignatureComparer sigComparer = new MethodSignatureComparer(method.MetadataReader, method.Handle); if (!sigComparer.IsMatchingNativeLayoutMethodNameAndSignature(methodNameAndSig.Name, methodNameAndSig.Signature.NativeLayoutSignature)) continue; // At this point we've matched slotDefiningMethod = method; return true; } // Didn't find the method slotDefiningMethod = null; return false; }