/// <summary> /// Attempt a virtual dispatch on a given instanceType based on the method found via a metadata token /// </summary> private static bool TryDispatchMethodOnTarget_Inner(NativeFormatModuleInfo module, int metadataToken, RuntimeTypeHandle targetInstanceType, out IntPtr methodAddress) { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING TypeSystemContext context = TypeSystemContextFactory.Create(); NativeFormatMetadataUnit metadataUnit = context.ResolveMetadataUnit(module); MethodDesc targetMethod = metadataUnit.GetMethod(metadataToken.AsHandle(), null); TypeDesc instanceType = context.ResolveRuntimeTypeHandle(targetInstanceType); MethodDesc realTargetMethod = targetMethod; // For non-interface methods we support the target method not being the exact target. (This allows // a canonical method to be passed in and work for any generic type instantiation.) if (!targetMethod.OwningType.IsInterface) { realTargetMethod = instanceType.FindMethodOnTypeWithMatchingTypicalMethod(targetMethod); } bool success = LazyVTableResolver.TryDispatchMethodOnTarget(instanceType, realTargetMethod, out methodAddress); TypeSystemContextFactory.Recycle(context); return(success); #else methodAddress = IntPtr.Zero; return(false); #endif }
/// <summary> /// Attempt to convert the dispatch cell to a metadata token to a more efficient vtable dispatch or interface/slot dispatch. /// Failure to convert is not a correctness issue. We also support performing a dispatch based on metadata token alone. /// </summary> private static DispatchCellInfo ConvertDispatchCellInfo_Inner(NativeFormatModuleInfo module, DispatchCellInfo cellInfo) { Debug.Assert(cellInfo.CellType == DispatchCellType.MetadataToken); TypeSystemContext context = TypeSystemContextFactory.Create(); MethodDesc targetMethod = context.ResolveMetadataUnit(module).GetMethod(cellInfo.MetadataToken.AsHandle(), null); Debug.Assert(!targetMethod.HasInstantiation); // At this time we do not support generic virtuals through the dispatch mechanism Debug.Assert(targetMethod.IsVirtual); if (targetMethod.OwningType.IsInterface) { if (!LazyVTableResolver.TryGetInterfaceSlotNumberFromMethod(targetMethod, out cellInfo.InterfaceSlot)) { // Unable to resolve interface method. Fail, by not mutating cellInfo return cellInfo; } if (!targetMethod.OwningType.RetrieveRuntimeTypeHandleIfPossible()) { new TypeBuilder().BuildType(targetMethod.OwningType); } cellInfo.CellType = DispatchCellType.InterfaceAndSlot; cellInfo.InterfaceType = targetMethod.OwningType.RuntimeTypeHandle.ToIntPtr(); cellInfo.MetadataToken = 0; } else { // Virtual function case, attempt to resolve to a VTable slot offset. // If the offset is less than 4096 update the cellInfo #if DEBUG // The path of resolving a metadata token at dispatch time is relatively rare in practice. // Force it to occur in debug builds with much more regularity if ((s_ConvertDispatchCellInfoCounter % 16) == 0) { s_ConvertDispatchCellInfoCounter++; TypeSystemContextFactory.Recycle(context); return cellInfo; } s_ConvertDispatchCellInfoCounter++; #endif int slotIndexOfMethod = LazyVTableResolver.VirtualMethodToSlotIndex(targetMethod); int vtableOffset = -1; if (slotIndexOfMethod >= 0) vtableOffset = LazyVTableResolver.SlotIndexToEETypeVTableOffset(slotIndexOfMethod); if ((vtableOffset < 4096) && (vtableOffset != -1)) { cellInfo.CellType = DispatchCellType.VTableOffset; cellInfo.VTableOffset = checked((uint)vtableOffset); cellInfo.MetadataToken = 0; } // Otherwise, do nothing, and resolve with a metadata dispatch later } TypeSystemContextFactory.Recycle(context); return cellInfo; }