protected virtual object DynamicInvokeImpl(object[] args) { if (IsDynamicDelegate()) { // DynamicDelegate case object result = ((Func <object[], object>)m_helperObject)(args); DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } else { IntPtr invokeThunk = this.GetThunk(DelegateInvokeThunk); #if PROJECTN object result = InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, this, invokeThunk, IntPtr.Zero, this, args, binderBundle: null, wrapInTargetInvocationException: true); #else IntPtr genericDictionary = IntPtr.Zero; if (FunctionPointerOps.IsGenericMethodPointer(invokeThunk)) { unsafe { GenericMethodDescriptor *descriptor = FunctionPointerOps.ConvertToGenericDescriptor(invokeThunk); genericDictionary = descriptor->InstantiationArgument; invokeThunk = descriptor->MethodFunctionPointer; } } object result = InvokeUtils.CallDynamicInvokeMethod(this.m_firstParameter, this.m_functionPointer, null, invokeThunk, genericDictionary, this, args, binderBundle: null, wrapInTargetInvocationException: true, invokeMethodHelperIsThisCall: false); #endif DebugAnnotations.PreviousCallContainsDebuggerStepInCode(); return(result); } }
public static IntPtr ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(IntPtr unboxingFunctionPointer, RuntimeTypeHandle declaringType) { if (FunctionPointerOps.IsGenericMethodPointer(unboxingFunctionPointer)) { // Handle shared generic methods unsafe { GenericMethodDescriptor *functionPointerDescriptor = FunctionPointerOps.ConvertToGenericDescriptor(unboxingFunctionPointer); IntPtr nonUnboxingTarget = RuntimeAugments.GetCodeTarget(functionPointerDescriptor->MethodFunctionPointer); Debug.Assert(nonUnboxingTarget != functionPointerDescriptor->MethodFunctionPointer); Debug.Assert(nonUnboxingTarget == RuntimeAugments.GetCodeTarget(nonUnboxingTarget)); return(FunctionPointerOps.GetGenericMethodFunctionPointer(nonUnboxingTarget, functionPointerDescriptor->InstantiationArgument)); } } // GetCodeTarget will look through simple unboxing stubs (ones that consist of adjusting the this pointer and then // jumping to the target. IntPtr exactTarget = RuntimeAugments.GetCodeTarget(unboxingFunctionPointer); if (RuntimeAugments.IsGenericType(declaringType)) { IntPtr fatFunctionPointerTarget; // This check looks for unboxing and instantiating stubs generated via the compiler backend if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(exactTarget, out fatFunctionPointerTarget)) { // If this is an unboxing and instantiating stub, use separate table, find target, and create fat function pointer exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(fatFunctionPointerTarget, declaringType.ToIntPtr()); } #if FEATURE_UNIVERSAL_GENERICS else { IntPtr newExactTarget; // This check looks for unboxing and instantiating stubs generated dynamically as thunks in the calling convention converter if (CallConverterThunk.TryGetNonUnboxingFunctionPointerFromUnboxingAndInstantiatingStub(exactTarget, declaringType, out newExactTarget)) { // CallingConventionConverter determined non-unboxing stub exactTarget = newExactTarget; } else { // Target method was a method on a generic, but it wasn't a shared generic, and thus none of the above // complex unboxing stub digging logic was necessary. Do nothing, and use exactTarget as discovered // from GetCodeTarget } } #endif } return(exactTarget); }
private bool UpdateCalleeFunctionPointer(IntPtr newFunctionPointer) { if (FunctionPointerOps.IsGenericMethodPointer(newFunctionPointer)) { GenericMethodDescriptor *genericTarget = FunctionPointerOps.ConvertToGenericDescriptor(newFunctionPointer); _instantiatingStubArgument = genericTarget->InstantiationArgument; _functionPointerToCall = genericTarget->MethodFunctionPointer; return(true); } else { _functionPointerToCall = newFunctionPointer; return(false); } }
private unsafe static IntPtr ResolveCallOnReferenceTypeCacheMiss(IntPtr context, IntPtr callDescIntPtr, object contextObject, out IntPtr auxResult) { auxResult = IntPtr.Zero; // Perform a normal GVM dispatch, then change the function pointer to dereference the this pointer. GenericConstrainedCallDesc *callDesc = (GenericConstrainedCallDesc *)callDescIntPtr; IntPtr target = RuntimeAugments.GVMLookupForSlot(contextObject.GetType().TypeHandle, callDesc->_constrainedMethod); if (FunctionPointerOps.IsGenericMethodPointer(target)) { GenericMethodDescriptor *genMethodDesc = FunctionPointerOps.ConvertToGenericDescriptor(target); IntPtr actualCodeTarget = GetThunkThatDereferencesThisPointerAndTailCallsTarget(genMethodDesc->MethodFunctionPointer); return(FunctionPointerOps.GetGenericMethodFunctionPointer(actualCodeTarget, genMethodDesc->InstantiationArgument)); } else { return(GetThunkThatDereferencesThisPointerAndTailCallsTarget(target)); } }
private unsafe static IntPtr ResolveCallOnValueType(IntPtr unused, IntPtr callDescIntPtr) #endif { GenericConstrainedCallDesc *callDesc = (GenericConstrainedCallDesc *)callDescIntPtr; IntPtr targetAsVirtualCall = RuntimeAugments.GVMLookupForSlot(callDesc->_constraintType, callDesc->_constrainedMethod); IntPtr exactTarget = IntPtr.Zero; if (FunctionPointerOps.IsGenericMethodPointer(targetAsVirtualCall)) { GenericMethodDescriptor *genMethodDesc = FunctionPointerOps.ConvertToGenericDescriptor(targetAsVirtualCall); IntPtr actualCodeTarget = RuntimeAugments.GetCodeTarget(genMethodDesc->MethodFunctionPointer); exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(actualCodeTarget, genMethodDesc->InstantiationArgument); } else { IntPtr actualCodeTarget = RuntimeAugments.GetCodeTarget(targetAsVirtualCall); IntPtr callConverterThunk; if (CallConverterThunk.TryGetNonUnboxingFunctionPointerFromUnboxingAndInstantiatingStub(actualCodeTarget, callDesc->_constraintType, out callConverterThunk)) { actualCodeTarget = callConverterThunk; } exactTarget = actualCodeTarget; } // Ensure that all threads will have their function pointers completely published before updating callDesc. // as the ExactTarget is read from callDesc by binder generated code without a barrier, we need a barrier here // to ensure that the new function pointer data is valid on all threads Interlocked.MemoryBarrier(); // Its possible for multiple threads to race to set exact target. Check to see we always set the same value if (callDesc->_exactTarget != IntPtr.Zero) { Debug.Assert(callDesc->_exactTarget == exactTarget); } callDesc->_exactTarget = exactTarget; return(exactTarget); }
private string GetTargetMethodsDescriptionForDebugger() { if (m_functionPointer == GetThunk(MulticastThunk)) { // Multi-cast delegates return the Target of the last delegate in the list Delegate[] invocationList = (Delegate[])m_helperObject; int invocationCount = (int)m_extraFunctionPointerOrData; StringBuilder builder = new StringBuilder(); for (int c = 0; c < invocationCount; c++) { if (c != 0) { builder.Append(", "); } builder.Append(invocationList[c].GetTargetMethodsDescriptionForDebugger()); } return(builder.ToString()); } else { RuntimeTypeHandle typeOfFirstParameterIfInstanceDelegate; bool isOpenThunk; IntPtr functionPointer = GetFunctionPointer(out typeOfFirstParameterIfInstanceDelegate, out isOpenThunk); if (!FunctionPointerOps.IsGenericMethodPointer(functionPointer)) { return(DebuggerFunctionPointerFormattingHook(functionPointer, typeOfFirstParameterIfInstanceDelegate)); } else { unsafe { GenericMethodDescriptor *pointerDef = FunctionPointerOps.ConvertToGenericDescriptor(functionPointer); return(DebuggerFunctionPointerFormattingHook(pointerDef->InstantiationArgument, typeOfFirstParameterIfInstanceDelegate)); } } } }