예제 #1
0
            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);
                }
            }
예제 #2
0
            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));
                }
            }
예제 #3
0
            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);
            }