public static unsafe IntPtr Get(RuntimeTypeHandle constraintType, RuntimeMethodHandle constrainedMethod) { lock (s_genericConstrainedCallDescs) { // Get list of constrained call descs associated with a given type LowLevelList <IntPtr> associatedCallDescs; if (!s_genericConstrainedCallDescs.TryGetValue(constraintType, out associatedCallDescs)) { associatedCallDescs = new LowLevelList <IntPtr>(); s_genericConstrainedCallDescs.Add(constraintType, associatedCallDescs); } // Perform linear scan of associated call descs to see if one matches for (int i = 0; i < associatedCallDescs.Count; i++) { GenericConstrainedCallDesc *callDesc = (GenericConstrainedCallDesc *)associatedCallDescs[i]; Debug.Assert(constraintType.Equals(callDesc->_constraintType)); if (callDesc->_constrainedMethod != constrainedMethod) { continue; } // Found matching entry. return(associatedCallDescs[i]); } // Did not find match, allocate a new one and add it to the lookup list IntPtr newCallDescPtr = MemoryHelpers.AllocateMemory(sizeof(GenericConstrainedCallDesc)); GenericConstrainedCallDesc *newCallDesc = (GenericConstrainedCallDesc *)newCallDescPtr; newCallDesc->_exactTarget = IntPtr.Zero; if (RuntimeAugments.IsValueType(constraintType)) { newCallDesc->_lookupFunc = s_resolveCallOnValueTypeFuncPtr; } else { newCallDesc->_lookupFunc = s_resolveCallOnReferenceTypeFuncPtr; } newCallDesc->_constraintType = constraintType; newCallDesc->_constrainedMethod = constrainedMethod; associatedCallDescs.Add(newCallDescPtr); return(newCallDescPtr); } }
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); }