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