Exemple #1
0
        public unsafe void FreeThunk(IntPtr thunkAddress)
        {
            // TODO: optimize the implementation and make it lock-free
            // or at least change it to a per-heap lock instead of a global lock.

            IntPtr dataAddress = TryGetThunkDataAddress(thunkAddress);

            if (dataAddress == IntPtr.Zero)
            {
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            }

#if DEBUG
            if (!IsThunkInHeap(thunkAddress))
            {
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            }

            // Debug flag indicating the thunk is no longer used
            *((IntPtr *)(dataAddress + IntPtr.Size)) = new IntPtr(-1);
#endif

            InternalCalls.RhpAcquireThunkPoolLock();

            *((IntPtr *)(dataAddress)) = _nextAvailableThunkPtr;
            _nextAvailableThunkPtr     = dataAddress;

            InternalCalls.RhpReleaseThunkPoolLock();
        }
        private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
        {
            DispatchCellInfo cellInfo;

            InternalCalls.RhpGetDispatchCellInfo(pCell, out cellInfo);
            IntPtr pTargetCode = RhResolveDispatchWorker(pObject, (void *)pCell, ref cellInfo);

            if (pTargetCode != IntPtr.Zero)
            {
                // We don't update the dispatch cell cache if this is IDynamicInterfaceCastable because this
                // scenario is by-design dynamic. There is no guarantee that another instance with the same MethodTable
                // as the one we just resolved would do the resolution the same way. We will need to ask again.
                if (!pObject.GetMethodTable()->IsIDynamicInterfaceCastable)
                {
                    return(InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.GetMethodTable(), ref cellInfo));
                }
                else
                {
                    return(pTargetCode);
                }
            }

            // "Valid method implementation was not found."
            EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            return(IntPtr.Zero);
        }
Exemple #3
0
        unsafe private static IntPtr RhpCastableObjectResolve(IntPtr callerTransitionBlockParam, IntPtr pCell)
        {
            IntPtr locationOfThisPointer = callerTransitionBlockParam + TransitionBlock.GetThisOffset();
            object pObject = Unsafe.As <IntPtr, Object>(ref *(IntPtr *)locationOfThisPointer);

            DispatchCellInfo cellInfo;

            InternalCalls.RhpGetDispatchCellInfo(pCell, out cellInfo);
            if (cellInfo.CellType != DispatchCellType.InterfaceAndSlot)
            {
                // Dispatch cell used for castable object resolve is not InterfaceAndSlot. This should not be possible
                // as all metadata based cells should have been converted to interface and slot cells by this time.
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                return(IntPtr.Zero);
            }

            EEType *pInterfaceType = cellInfo.InterfaceType.ToPointer();

            Exception e            = null;
            object    targetObject = GetCastableTargetIfPossible((ICastableObject)pObject, pInterfaceType, false, ref e);

            if (targetObject == null)
            {
                EH.FailFastViaClasslib(RhFailFastReason.InternalError, null, pObject.EEType->GetAssociatedModuleAddress());
            }

            Unsafe.As <IntPtr, Object>(ref *(IntPtr *)locationOfThisPointer) = targetObject;

            InternalCalls.RhpSetTLSDispatchCell(pCell);
            return(InternalCalls.RhpGetTailCallTLSDispatchCell());
        }
        private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void *cell, ref DispatchCellInfo cellInfo)
        {
            // Type of object we're dispatching on.
            MethodTable *pInstanceType = pObject.GetMethodTable();

            if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot)
            {
                // Type whose DispatchMap is used. Usually the same as the above but for types which implement IDynamicInterfaceCastable
                // we may repeat this process with an alternate type.
                MethodTable *pResolvingInstanceType = pInstanceType;

                IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                                             cellInfo.InterfaceType.ToPointer(),
                                                                                             cellInfo.InterfaceSlot,
                                                                                             ppGenericContext: null);
                if (pTargetCode == IntPtr.Zero && pInstanceType->IsIDynamicInterfaceCastable)
                {
                    // Dispatch not resolved through normal dispatch map, try using the IDynamicInterfaceCastable
                    // This will either give us the appropriate result, or throw.
                    var pfnGetInterfaceImplementation = (delegate * < object, MethodTable *, ushort, IntPtr >)
                                                        pInstanceType->GetClasslibFunction(ClassLibFunctionId.IDynamicCastableGetInterfaceImplementation);
                    pTargetCode = pfnGetInterfaceImplementation(pObject, cellInfo.InterfaceType.ToPointer(), cellInfo.InterfaceSlot);
                    Diagnostics.Debug.Assert(pTargetCode != IntPtr.Zero);
                }
                return(pTargetCode);
            }
            else if (cellInfo.CellType == DispatchCellType.VTableOffset)
            {
                // Dereference VTable
                return(*(IntPtr *)(((byte *)pInstanceType) + cellInfo.VTableOffset));
            }
            else
            {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING_AND_SUPPORTS_TOKEN_BASED_DISPATCH_CELLS
                // Attempt to convert dispatch cell to non-metadata form if we haven't acquired a cache for this cell yet
                if (cellInfo.HasCache == 0)
                {
                    cellInfo = InternalTypeLoaderCalls.ConvertMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), cellInfo);
                    if (cellInfo.CellType != DispatchCellType.MetadataToken)
                    {
                        return(RhResolveDispatchWorker(pObject, cell, ref cellInfo));
                    }
                }

                // If that failed, go down the metadata resolution path
                return(InternalTypeLoaderCalls.ResolveMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), (int)cellInfo.MetadataToken, new IntPtr(pInstanceType)));
#else
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                return(IntPtr.Zero);
#endif
            }
        }
        private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
        {
            DispatchCellInfo cellInfo;

            InternalCalls.RhpGetDispatchCellInfo(pCell, out cellInfo);
            IntPtr pTargetCode = RhResolveDispatchWorker(pObject, (void *)pCell, ref cellInfo);

            if (pTargetCode != IntPtr.Zero)
            {
                return(InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.EEType, ref cellInfo));
            }

            // "Valid method implementation was not found."
            EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            return(IntPtr.Zero);
        }
        internal static unsafe IntPtr GetCastableObjectDispatchCellThunk(EEType *pInstanceType, IntPtr pDispatchCell)
        {
            IntPtr pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell);

            if (pTargetCode != default(IntPtr))
            {
                return(pTargetCode);
            }

            InternalCalls.RhpAcquireCastCacheLock();
            {
                // Look in the cache again after taking the lock

                pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell);
                if (pTargetCode != default(IntPtr))
                {
                    return(pTargetCode);
                }


                // Allocate a new thunk. Failure to allocate one will result in a fail-fast. We don't return nulls from this API.

                // TODO: The allocation of thunks here looks like a layering duck tape. The allocation of the raw
                // thunks should be a core runtime service (ie it should live in MRT).
                // Delete the callback logic once this moves to MRT.

                IntPtr pAllocateThunkFunction = (IntPtr)InternalCalls.RhpGetClasslibFunction(
                    pInstanceType->GetAssociatedModuleAddress(),
                    EH.ClassLibFunctionId.AllocateThunkWithData);

                pTargetCode = CalliIntrinsics.Call <IntPtr>(
                    pAllocateThunkFunction,
                    InternalCalls.RhpGetCastableObjectDispatch_CommonStub(),
                    pDispatchCell,
                    InternalCalls.RhpGetCastableObjectDispatchHelper_TailCalled());

                if (pTargetCode == IntPtr.Zero)
                {
                    EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                }

                AddToThunkCache(pDispatchCell, pTargetCode);
            }
            InternalCalls.RhpReleaseCastCacheLock();

            return(pTargetCode);
        }
        private static IntPtr RhpCidResolve_Worker(object pObject, IntPtr pCell)
        {
            EEType *pInterfaceType;
            ushort  slot;

            InternalCalls.RhpGetDispatchCellInfo(pCell, &pInterfaceType, &slot);
            IntPtr pTargetCode = RhResolveDispatchWorker(pObject, pInterfaceType, slot);

            if (pTargetCode != IntPtr.Zero)
            {
                return(InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.EEType));
            }

            // "Valid method implementation was not found."
            EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            return(IntPtr.Zero);
        }
Exemple #8
0
        internal static unsafe IntPtr GetCastableObjectDispatchCellThunk(EEType *pInstanceType, IntPtr pDispatchCell)
        {
            IntPtr pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell);

            if (pTargetCode != default(IntPtr))
            {
                return(pTargetCode);
            }

            InternalCalls.RhpAcquireCastCacheLock();
            {
                // Look in the cache again after taking the lock

                pTargetCode = CacheLookup(s_ThunkBasedDispatchCellTargets, pDispatchCell);
                if (pTargetCode != default(IntPtr))
                {
                    return(pTargetCode);
                }

                // Allocate a new thunk. Failure to allocate one will result in a fail-fast. We don't return nulls from this API.

                if (s_thunksHeap == null)
                {
                    s_thunksHeap = ThunksHeap.CreateThunksHeap(InternalCalls.RhpGetCastableObjectDispatch_CommonStub());
                    if (s_thunksHeap == null)
                    {
                        EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                    }
                }

                pTargetCode = s_thunksHeap.AllocateThunk();
                if (pTargetCode == IntPtr.Zero)
                {
                    EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                }

                s_thunksHeap.SetThunkData(pTargetCode, pDispatchCell, InternalCalls.RhpGetCastableObjectDispatchHelper_TailCalled());

                AddToThunkCache(pDispatchCell, pTargetCode);
            }
            InternalCalls.RhpReleaseCastCacheLock();

            return(pTargetCode);
        }
Exemple #9
0
        public static void RhpReversePInvokeBadTransition()
        {
            IntPtr returnAddress = BinderIntrinsics.GetReturnAddress();

            if (returnAddress != IntPtr.Zero)
            {
                EH.FailFastViaClasslib(
                    RhFailFastReason.IllegalNativeCallableEntry,
                    null,
                    returnAddress);
            }
            else
            {
                // @HACKHACK: we need to force the method to have an EBP frame so that we can use the
                // GetReturnAddress() intrinsic above.  This seems to be the smallest way to do this.
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                throw EH.GetClasslibException(ExceptionIDs.Arithmetic, returnAddress);
            }
        }
Exemple #10
0
        /// <summary>
        /// This method sets the two data fields for a thunk.
        /// Caution: No checks are made to verify that the thunk address is that of a
        /// valid thunk in use. The caller of this API is responsible for providing a valid
        /// address of a thunk that was not previously freed.
        /// </summary>
        public unsafe void SetThunkData(IntPtr thunkAddress, IntPtr context, IntPtr target)
        {
            IntPtr dataAddress = TryGetThunkDataAddress(thunkAddress);

            if (dataAddress == IntPtr.Zero)
            {
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            }

#if DEBUG
            if (!IsThunkInHeap(thunkAddress))
            {
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            }
#endif

            // Update the data that will be used by the thunk that was allocated
            *((IntPtr *)(dataAddress)) = context;
            *((IntPtr *)(dataAddress + IntPtr.Size)) = target;
        }
        private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void *cell, ref DispatchCellInfo cellInfo)
        {
            // Type of object we're dispatching on.
            EEType *pInstanceType = pObject.EEType;

            if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot)
            {
                // Type whose DispatchMap is used.
                EEType *pResolvingInstanceType = pInstanceType;

                IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                                             cellInfo.InterfaceType.ToPointer(),
                                                                                             cellInfo.InterfaceSlot);
                return(pTargetCode);
            }
            else if (cellInfo.CellType == DispatchCellType.VTableOffset)
            {
                // Dereference VTable
                return(*(IntPtr *)(((byte *)pInstanceType) + cellInfo.VTableOffset));
            }
            else
            {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING_AND_SUPPORTS_TOKEN_BASED_DISPATCH_CELLS
                // Attempt to convert dispatch cell to non-metadata form if we haven't acquired a cache for this cell yet
                if (cellInfo.HasCache == 0)
                {
                    cellInfo = InternalTypeLoaderCalls.ConvertMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), cellInfo);
                    if (cellInfo.CellType != DispatchCellType.MetadataToken)
                    {
                        return(RhResolveDispatchWorker(pObject, cell, ref cellInfo));
                    }
                }

                // If that failed, go down the metadata resolution path
                return(InternalTypeLoaderCalls.ResolveMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), (int)cellInfo.MetadataToken, new IntPtr(pInstanceType)));
#else
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                return(IntPtr.Zero);
#endif
            }
        }
        private static IntPtr RhpCidResolve(object pObject, IntPtr pCell)
        {
            try
            {
                EEType* pInterfaceType;
                ushort slot;
                InternalCalls.RhpGetDispatchCellInfo(pCell, &pInterfaceType, &slot);
                IntPtr pTargetCode = RhResolveDispatchWorker(pObject, pInterfaceType, slot);
                if (pTargetCode != IntPtr.Zero)
                {
                    return InternalCalls.RhpUpdateDispatchCellCache(pCell, pTargetCode, pObject.EEType);
                }
            }
            catch
            {
                // Exceptions are not permitted to escape from runtime->managed callbacks
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            }

            // "Valid method implementation was not found."
            EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            return IntPtr.Zero;
        }
Exemple #13
0
        internal static unsafe void AddToExistingCache <V>(CastableObjectCacheEntry <V>[] cache, IntPtr key, V value)
        {
            uint hashcode  = unchecked ((uint)key.ToInt64());
            uint cacheMask = (uint)cache.Length - 1;
            uint bucket    = hashcode & cacheMask;
            uint curbucket = bucket;

            // hash algorithm is open addressing with linear probing

            while (curbucket < cache.Length)
            {
                if (cache[curbucket].Key == default(IntPtr))
                {
                    cache[curbucket].Key   = key;
                    cache[curbucket].Value = value;
                    return;
                }
                curbucket++;
            }

            // Handle wrap-around case
            curbucket = 0;
            while (curbucket < bucket)
            {
                if (cache[curbucket].Key == default(IntPtr))
                {
                    cache[curbucket].Key   = key;
                    cache[curbucket].Value = value;
                    return;
                }
                curbucket++;
            }

            EH.FallbackFailFast(RhFailFastReason.InternalError, null);
            return;
        }
        private static unsafe IntPtr RhResolveDispatchWorker(object pObject, void *cell, ref DispatchCellInfo cellInfo)
        {
            // Type of object we're dispatching on.
            EEType *pInstanceType = pObject.EEType;

            if (cellInfo.CellType == DispatchCellType.InterfaceAndSlot)
            {
                // Type whose DispatchMap is used. Usually the same as the above but for types which implement ICastable
                // we may repeat this process with an alternate type.
                EEType *pResolvingInstanceType = pInstanceType;

                IntPtr pTargetCode = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                                             cellInfo.InterfaceType.ToPointer(),
                                                                                             cellInfo.InterfaceSlot);

                if (pTargetCode == IntPtr.Zero && pInstanceType->IsICastable)
                {
                    // TODO!! BEGIN REMOVE THIS CODE WHEN WE REMOVE ICASTABLE
                    // Dispatch not resolved through normal dispatch map, try using the ICastable
                    // Call the ICastable.IsInstanceOfInterface method directly rather than via an interface
                    // dispatch since we know the method address statically. We ignore any cast error exception
                    // object passed back on failure (result == false) since IsInstanceOfInterface never throws.
                    IntPtr    pfnIsInstanceOfInterface = pInstanceType->ICastableIsInstanceOfInterfaceMethod;
                    Exception castError = null;
                    if (CalliIntrinsics.Call <bool>(pfnIsInstanceOfInterface, pObject, cellInfo.InterfaceType.ToPointer(), out castError))
                    {
                        IntPtr pfnGetImplTypeMethod = pInstanceType->ICastableGetImplTypeMethod;
                        pResolvingInstanceType = (EEType *)CalliIntrinsics.Call <IntPtr>(pfnGetImplTypeMethod, pObject, new IntPtr(cellInfo.InterfaceType.ToPointer()));
                        pTargetCode            = DispatchResolve.FindInterfaceMethodImplementationTarget(pResolvingInstanceType,
                                                                                                         cellInfo.InterfaceType.ToPointer(),
                                                                                                         cellInfo.InterfaceSlot);
                    }
                    else
                    // TODO!! END REMOVE THIS CODE WHEN WE REMOVE ICASTABLE
                    {
                        // Dispatch not resolved through normal dispatch map, using the CastableObject path
                        pTargetCode = InternalCalls.RhpGetCastableObjectDispatchHelper();
                    }
                }

                return(pTargetCode);
            }
            else if (cellInfo.CellType == DispatchCellType.VTableOffset)
            {
                // Dereference VTable
                return(*(IntPtr *)(((byte *)pInstanceType) + cellInfo.VTableOffset));
            }
            else
            {
#if SUPPORTS_NATIVE_METADATA_TYPE_LOADING
                // Attempt to convert dispatch cell to non-metadata form if we haven't acquired a cache for this cell yet
                if (cellInfo.HasCache == 0)
                {
                    cellInfo = InternalTypeLoaderCalls.ConvertMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), cellInfo);
                    if (cellInfo.CellType != DispatchCellType.MetadataToken)
                    {
                        return(RhResolveDispatchWorker(pObject, cell, ref cellInfo));
                    }
                }

                // If that failed, go down the metadata resolution path
                return(InternalTypeLoaderCalls.ResolveMetadataTokenDispatch(InternalCalls.RhGetModuleFromPointer(cell), (int)cellInfo.MetadataToken, new IntPtr(pInstanceType)));
#else
                EH.FallbackFailFast(RhFailFastReason.InternalError, null);
                return(IntPtr.Zero);
#endif
            }
        }
Exemple #15
0
 public static void DebugBreak()
 {
     EH.FallbackFailFast(RhFailFastReason.InternalError, null);
 }