示例#1
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.

                // 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);
        }
示例#2
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);
        }
示例#3
0
        internal static unsafe object GetCastableTargetIfPossible(ICastableObject castableObject, EEType *interfaceType, bool produceException, ref Exception exception)
        {
            CastableObjectCacheEntry <object>[] cache = Unsafe.As <CastableObject>(castableObject).Cache;

            object targetObjectInitial = null;

            if (cache != null)
            {
                targetObjectInitial = CacheLookup(cache, new IntPtr(interfaceType));
                if (targetObjectInitial != null)
                {
                    if (targetObjectInitial != s_castFailCanary)
                    {
                        return(targetObjectInitial);
                    }
                    else if (!produceException)
                    {
                        return(null);
                    }
                }
            }

            // Call into the object to determine if the runtime can perform the cast. This will return null if it fails.
            object targetObject = castableObject.CastToInterface(new EETypePtr(new IntPtr(interfaceType)), produceException, out exception);

            // If the target object is null, and that result has already been cached, just return null now.
            // Otherwise, we need to store the canary in the cache so future failing "is" checks can be fast
            if (targetObject == null)
            {
                if (targetObjectInitial != null)
                {
                    return(null);
                }
                else
                {
                    targetObject = s_castFailCanary;
                }
            }

            InternalCalls.RhpAcquireCastCacheLock();
            // Assuming we reach here, we should attempt to add the newly discovered targetObject to the per-object cache

            // First, check to see if something is already there

            // we may have replaced the cache object since the earlier acquisition in this method. Re-acquire the cache object
            // here.
            cache = Unsafe.As <CastableObject>(castableObject).Cache;
            object targetObjectInCache = null;

            if (cache != null)
            {
                targetObjectInCache = CacheLookup(cache, new IntPtr(interfaceType));
            }

            if (targetObjectInCache == null)
            {
                // If the target object still isn't in the cache by this point, add it now
                AddToCastableCache(castableObject, interfaceType, targetObject);
                targetObjectInCache = targetObject;
            }
            InternalCalls.RhpReleaseCastCacheLock();

            if (targetObjectInCache != s_castFailCanary)
            {
                return(targetObjectInCache);
            }
            else
            {
                return(null);
            }
        }