Esempio n. 1
0
        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);
            }
        }
Esempio n. 2
0
        // This function is known to the compiler.
        protected void InitializeClosedInstanceWithGVMResolution(object firstParameter, RuntimeMethodHandle tokenOfGenericVirtualMethod)
        {
            if (firstParameter == null)
            {
                throw new ArgumentException(SR.Arg_DlgtNullInst);
            }

            IntPtr functionResolution = TypeLoaderExports.GVMLookupForSlot(firstParameter, tokenOfGenericVirtualMethod);

            if (functionResolution == IntPtr.Zero)
            {
                // TODO! What to do when GVM resolution fails. Should never happen
                throw new InvalidOperationException();
            }
            if (!FunctionPointerOps.IsGenericMethodPointer(functionResolution))
            {
                m_functionPointer = functionResolution;
                m_firstParameter  = firstParameter;
            }
            else
            {
                m_firstParameter             = this;
                m_functionPointer            = GetThunk(ClosedInstanceThunkOverGenericMethod);
                m_extraFunctionPointerOrData = functionResolution;
                m_helperObject = firstParameter;
            }

            return;
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        public sealed override bool Equals([NotNullWhen(true)] object?obj)
        {
            if (obj == null)
            {
                return(false);
            }
            if (object.ReferenceEquals(this, obj))
            {
                return(true);
            }
            if (!InternalEqualTypes(this, obj))
            {
                return(false);
            }

            // Since this is a MulticastDelegate and we know
            // the types are the same, obj should also be a
            // MulticastDelegate
            Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!");
            var d = Unsafe.As <MulticastDelegate>(obj);

            // there are 2 kind of delegate kinds for comparison
            // 1- Multicast (m_helperObject is Delegate[])
            // 2- Single-cast delegate, which can be compared with a structural comparison

            IntPtr multicastThunk = GetThunk(MulticastThunk);

            if (m_functionPointer == multicastThunk)
            {
                return(d.m_functionPointer == multicastThunk && InvocationListEquals(d));
            }
            else
            {
                if (!object.ReferenceEquals(m_helperObject, d.m_helperObject) ||
                    (!FunctionPointerOps.Compare(m_extraFunctionPointerOrData, d.m_extraFunctionPointerOrData)) ||
                    (!FunctionPointerOps.Compare(m_functionPointer, d.m_functionPointer)))
                {
                    return(false);
                }

                // Those delegate kinds with thunks put themselves into the m_firstParameter, so we can't
                // blindly compare the m_firstParameter fields for equality.
                if (object.ReferenceEquals(m_firstParameter, this))
                {
                    return(object.ReferenceEquals(d.m_firstParameter, d));
                }

                return(object.ReferenceEquals(m_firstParameter, d.m_firstParameter));
            }
        }
Esempio n. 5
0
 // This is used to implement MethodInfo.CreateDelegate() in a desktop-compatible way. Yes, the desktop really
 // let you use that api to invoke an instance method with a null 'this'.
 private void InitializeClosedInstanceWithoutNullCheck(object firstParameter, IntPtr functionPointer)
 {
     if (!FunctionPointerOps.IsGenericMethodPointer(functionPointer))
     {
         m_functionPointer = functionPointer;
         m_firstParameter  = firstParameter;
     }
     else
     {
         m_firstParameter             = this;
         m_functionPointer            = GetThunk(ClosedInstanceThunkOverGenericMethod);
         m_extraFunctionPointerOrData = functionPointer;
         m_helperObject = firstParameter;
     }
 }
Esempio n. 6
0
 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);
     }
 }
Esempio n. 7
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));
                }
            }
Esempio n. 8
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);
            }
Esempio n. 9
0
        public override sealed bool Equals(Object obj)
        {
            if (obj == null || !InternalEqualTypes(this, obj))
            {
                return(false);
            }
            MulticastDelegate d = obj as MulticastDelegate;

            if (d == null)
            {
                return(false);
            }

            // there are 2 kind of delegate kinds for comparision
            // 1- Multicast (m_helperObject is Delegate[])
            // 2- Single-cast delegate, which can be compared with a structural comparision

            if (m_functionPointer == GetThunk(MulticastThunk))
            {
                return(InvocationListEquals(d));
            }
            else
            {
                if (!Object.ReferenceEquals(m_helperObject, d.m_helperObject) ||
                    (!FunctionPointerOps.Compare(m_extraFunctionPointerOrData, d.m_extraFunctionPointerOrData)) ||
                    (!FunctionPointerOps.Compare(m_functionPointer, d.m_functionPointer)))
                {
                    return(false);
                }

                // Those delegate kinds with thunks put themselves into the m_firstParamter, so we can't
                // blindly compare the m_firstParameter fields for equality.
                if (Object.ReferenceEquals(m_firstParameter, this))
                {
                    return(Object.ReferenceEquals(d.m_firstParameter, d));
                }

                return(Object.ReferenceEquals(m_firstParameter, d.m_firstParameter));
            }
        }
Esempio n. 10
0
        // This function is known to the IL Transformer.
        protected void InitializeClosedInstanceSlow(object firstParameter, IntPtr functionPointer)
        {
            // This method is like InitializeClosedInstance, but it handles ALL cases. In particular, it handles generic method with fun function pointers.

            if (firstParameter == null)
            {
                throw new ArgumentException(SR.Arg_DlgtNullInst);
            }

            if (!FunctionPointerOps.IsGenericMethodPointer(functionPointer))
            {
                m_functionPointer = functionPointer;
                m_firstParameter  = firstParameter;
            }
            else
            {
                m_firstParameter             = this;
                m_functionPointer            = GetThunk(ClosedInstanceThunkOverGenericMethod);
                m_extraFunctionPointerOrData = functionPointer;
                m_helperObject = firstParameter;
            }
        }
Esempio n. 11
0
        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));
                    }
                }
            }
        }
Esempio n. 12
0
            private unsafe static IntPtr ResolveCallOnValueType(IntPtr unused, IntPtr callDescIntPtr)
#endif
            {
                NonGenericConstrainedCallDesc *callDesc = (NonGenericConstrainedCallDesc *)callDescIntPtr;
                IntPtr exactTarget        = IntPtr.Zero;
                IntPtr targetOnTypeVtable = RuntimeAugments.ResolveDispatchOnType(callDesc->_constraintType, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot);
                bool   decodeUnboxing     = true;

                if (!RuntimeAugments.IsInterface(callDesc->_constrainedMethodType))
                {
                    // Non-interface constrained call on a valuetype to a method that isn't GetHashCode/Equals/ToString?!?!
                    if (callDesc->_constrainedMethodSlot > s_MaxObjectVTableSlot)
                    {
                        throw new NotSupportedException();
                    }

                    RuntimeTypeHandle baseTypeHandle;
                    bool gotBaseType = RuntimeAugments.TryGetBaseType(callDesc->_constraintType, out baseTypeHandle);
                    Debug.Assert(gotBaseType);
                    if (targetOnTypeVtable == RuntimeAugments.ResolveDispatchOnType(baseTypeHandle, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot))
                    {
                        // In this case, the valuetype does not override the base types implementation of ToString(), GetHashCode(), or Equals(object)
                        decodeUnboxing = false;
                    }
                }

                if (decodeUnboxing)
                {
                    exactTarget = RuntimeAugments.GetCodeTarget(targetOnTypeVtable);
                    if (RuntimeAugments.IsGenericType(callDesc->_constraintType))
                    {
                        IntPtr fatFunctionPointerTarget;
                        if (TypeLoaderEnvironment.TryGetTargetOfUnboxingAndInstantiatingStub(exactTarget, out fatFunctionPointerTarget))
                        {
                            // If this is an unboxing and instantiating stub, use seperate table, find target, and create fat function pointer
                            exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(fatFunctionPointerTarget,
                                                                                             callDesc->_constraintType.ToIntPtr());
                        }
                        else
                        {
                            IntPtr newExactTarget;
                            if (CallConverterThunk.TryGetNonUnboxingFunctionPointerFromUnboxingAndInstantiatingStub(exactTarget,
                                                                                                                    callDesc->_constraintType, 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
                            }
                        }
                    }
                }
                else
                {
                    // Create a fat function pointer, where the instantiation argument is ConstraintType, and the target is BoxAndToString, BoxAndGetHashCode, or BoxAndEquals
                    IntPtr realTarget;

                    switch (callDesc->_constrainedMethodSlot)
                    {
                    case s_ToStringSlot:
                        realTarget = s_boxAndToStringFuncPtr;
                        break;

                    case s_GetHashCodeSlot:
                        realTarget = s_boxAndGetHashCodeFuncPtr;
                        break;

                    case s_EqualsSlot:
                        realTarget = s_boxAndEqualsFuncPtr;
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(realTarget, callDesc->_constraintType.ToIntPtr());
                }

                // 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);
            }
Esempio n. 13
0
            private static unsafe IntPtr ResolveCallOnValueType(IntPtr unused, IntPtr callDescIntPtr)
#endif
            {
                NonGenericConstrainedCallDesc *callDesc = (NonGenericConstrainedCallDesc *)callDescIntPtr;
                IntPtr exactTarget        = IntPtr.Zero;
                IntPtr targetOnTypeVtable = RuntimeAugments.ResolveDispatchOnType(callDesc->_constraintType, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot);
                bool   decodeUnboxing     = true;

                if (!RuntimeAugments.IsInterface(callDesc->_constrainedMethodType))
                {
                    // Non-interface constrained call on a valuetype to a method that isn't GetHashCode/Equals/ToString?!?!
                    if (callDesc->_constrainedMethodSlot > s_MaxObjectVTableSlot)
                    {
                        throw new NotSupportedException();
                    }

                    RuntimeTypeHandle baseTypeHandle;
                    bool gotBaseType = RuntimeAugments.TryGetBaseType(callDesc->_constraintType, out baseTypeHandle);
                    Debug.Assert(gotBaseType);
                    if (targetOnTypeVtable == RuntimeAugments.ResolveDispatchOnType(baseTypeHandle, callDesc->_constrainedMethodType, callDesc->_constrainedMethodSlot))
                    {
                        // In this case, the valuetype does not override the base types implementation of ToString(), GetHashCode(), or Equals(object)
                        decodeUnboxing = false;
                    }
                }

                if (decodeUnboxing)
                {
                    exactTarget = TypeLoaderEnvironment.ConvertUnboxingFunctionPointerToUnderlyingNonUnboxingPointer(targetOnTypeVtable, callDesc->_constraintType);
                }
                else
                {
                    // Create a fat function pointer, where the instantiation argument is ConstraintType, and the target is BoxAndToString, BoxAndGetHashCode, or BoxAndEquals
                    IntPtr realTarget;

                    switch (callDesc->_constrainedMethodSlot)
                    {
                    case s_ToStringSlot:
                        realTarget = s_boxAndToStringFuncPtr;
                        break;

                    case s_GetHashCodeSlot:
                        realTarget = s_boxAndGetHashCodeFuncPtr;
                        break;

                    case s_EqualsSlot:
                        realTarget = s_boxAndEqualsFuncPtr;
                        break;

                    default:
                        throw new NotSupportedException();
                    }

                    exactTarget = FunctionPointerOps.GetGenericMethodFunctionPointer(realTarget, callDesc->_constraintType.ToIntPtr());
                }

                // 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);
            }