internal CallConversionParameters(CallConversionInfo conversionInfo, IntPtr callerTransitionBlockParam) { // Make sure the thred static variable has been initialized for this thread s_pinnedGCHandles = s_pinnedGCHandles ?? new GCHandleContainer(); _conversionInfo = conversionInfo; _callerTransitionBlock = (byte *)callerTransitionBlockParam.ToPointer(); _functionPointerToCall = conversionInfo.TargetFunctionPointer; _instantiatingStubArgument = conversionInfo.InstantiatingStubArgument; _delegateData = default(DelegateData); _calleeArgs = default(ArgIterator); _invokeReturnValue = IntPtr.Zero; _copyReturnValue = true; _dynamicInvokeParams = null; _dynamicInvokeByRefObjectArgs = null; // // Setup input argument iterator for the caller // ArgIteratorData callerIteratorData; if (conversionInfo.IsDelegateDynamicInvokeThunk) { callerIteratorData = s_delegateDynamicInvokeImplArgIteratorData; } else if (conversionInfo.IsReflectionDynamicInvokerThunk) { callerIteratorData = s_reflectionDynamicInvokeImplArgIteratorData; } else { callerIteratorData = conversionInfo.ArgIteratorData; } _callerArgs = new ArgIterator(callerIteratorData, callerIteratorData.HasThis() ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, conversionInfo.CallerHasParamType, conversionInfo.CallerHasExtraParameterWhichIsFunctionTarget, conversionInfo.CallerForcedByRefData, false, false); // Setup input bool forceCalleeHasParamType = false; // If the callee MAY have a param type, we need to know before we create the callee arg iterator // To do this we need to actually load the target address and see if it has the generic method pointer // bit set. if (conversionInfo.CalleeMayHaveParamType) { ArgIterator callerArgsLookupTargetFunctionPointer = new ArgIterator(conversionInfo.ArgIteratorData, conversionInfo.ArgIteratorData.HasThis() ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, conversionInfo.CallerHasParamType, conversionInfo.CallerHasExtraParameterWhichIsFunctionTarget, conversionInfo.CallerForcedByRefData, false, false); // Find the last valid caller offset. That's the offset of the target function pointer. int ofsCallerValid = TransitionBlock.InvalidOffset; while (true) { // Setup argument offsets. int ofsCallerTemp = callerArgsLookupTargetFunctionPointer.GetNextOffset(); // Check to see if we've handled all the arguments that we are to pass to the callee. if (TransitionBlock.InvalidOffset == ofsCallerTemp) { break; } ofsCallerValid = ofsCallerTemp; } if (ofsCallerValid == TransitionBlock.InvalidOffset) { throw new InvalidProgramException(); } int stackSizeCaller = callerArgsLookupTargetFunctionPointer.GetArgSize(); Debug.Assert(stackSizeCaller == IntPtr.Size); void * pSrc = _callerTransitionBlock + ofsCallerValid; IntPtr tempFunctionPointer = *((IntPtr *)pSrc); forceCalleeHasParamType = UpdateCalleeFunctionPointer(tempFunctionPointer); } // Retrieve target function pointer and instantiation argument for delegate thunks if (conversionInfo.IsDelegateThunk) { Debug.Assert(_callerArgs.HasThis() && !_conversionInfo.IsUnboxingThunk); IntPtr locationOfThisPointer = (IntPtr)(_callerTransitionBlock + ArgIterator.GetThisOffset()); _delegateData._delegateObject = (Delegate)Unsafe.As <IntPtr, Object>(ref *(IntPtr *)locationOfThisPointer); Debug.Assert(_delegateData._delegateObject != null); RuntimeAugments.GetDelegateData( _delegateData._delegateObject, out _delegateData._firstParameter, out _delegateData._helperObject, out _delegateData._extraFunctionPointerOrData, out _delegateData._functionPointer); if (conversionInfo.TargetDelegateFunctionIsExtraFunctionPointerOrDataField) { if (conversionInfo.IsOpenInstanceDelegateThunk) { _delegateData._boxedFirstParameter = BoxedCallerFirstArgument; Debug.Assert(_delegateData._boxedFirstParameter != null); _callerArgs.Reset(); IntPtr resolvedTargetFunctionPointer = OpenMethodResolver.ResolveMethod(_delegateData._extraFunctionPointerOrData, _delegateData._boxedFirstParameter); forceCalleeHasParamType = UpdateCalleeFunctionPointer(resolvedTargetFunctionPointer); } else { forceCalleeHasParamType = UpdateCalleeFunctionPointer(_delegateData._extraFunctionPointerOrData); } } else if (conversionInfo.IsMulticastDelegate) { _delegateData._multicastTargetCount = (int)_delegateData._extraFunctionPointerOrData; } } // // Setup output argument iterator for the callee // _calleeArgs = new ArgIterator(conversionInfo.ArgIteratorData, (conversionInfo.ArgIteratorData.HasThis() && !conversionInfo.IsStaticDelegateThunk) ? CallingConvention.ManagedInstance : CallingConvention.ManagedStatic, forceCalleeHasParamType || conversionInfo.CalleeHasParamType, false, conversionInfo.CalleeForcedByRefData, conversionInfo.IsOpenInstanceDelegateThunk, conversionInfo.IsClosedStaticDelegate); // The function pointer, 'hasParamType', and 'hasThis' flags for the callee arg iterator need to be computed/read from the caller's // input arguments in the case of a reflection invoker thunk (the target method pointer and 'hasThis' flags are // passed in as parameters from the caller, not loaded from a static method signature in native layout) if (conversionInfo.IsReflectionDynamicInvokerThunk) { ComputeCalleeFlagsAndFunctionPointerForReflectionInvokeThunk(); } #if CALLINGCONVENTION_CALLEE_POPS // Ensure that the count of bytes in the stack is available _callerArgs.CbStackPop(); #endif }
/// <summary> /// This function is called from the lazy vtable resolver thunks via the UniversalTransitionThunk to compute /// the correct resolution of a virtual dispatch. /// </summary> /// <param name="callerTransitionBlockParam">pointer to the arguments of the called function</param> /// <param name="eeTypePointerOffsetAsIntPtr">eeTypePointerOffsetAsIntPtr is the offset from the start of the EEType to the vtable slot</param> /// <returns>function pointer of correct override of virtual function</returns> unsafe private static IntPtr VTableResolveThunk(IntPtr callerTransitionBlockParam, IntPtr eeTypePointerOffsetAsIntPtr) { int eeTypePointerOffset = (int)eeTypePointerOffsetAsIntPtr; int vtableSlotIndex = EETypeVTableOffsetToSlotIndex(eeTypePointerOffset); Debug.Assert(eeTypePointerOffset == SlotIndexToEETypeVTableOffset(vtableSlotIndex)); // Assert that the round trip through the slot calculations is good EEType **thisPointer = *((EEType ***)(((byte *)callerTransitionBlockParam) + ArgIterator.GetThisOffset())); EEType * eeType = *thisPointer; RuntimeTypeHandle rth = eeType->ToRuntimeTypeHandle(); TypeSystemContext context = TypeSystemContextFactory.Create(); TypeDesc type = context.ResolveRuntimeTypeHandle(rth); IntPtr functionPointer = ResolveVirtualVTableFunction(type, vtableSlotIndex); eeType->GetVTableStartAddress()[vtableSlotIndex] = functionPointer; TypeSystemContextFactory.Recycle(context); return(functionPointer); }