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); }
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); }
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); }
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); } }
/// <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; }
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 } }
public static void DebugBreak() { EH.FallbackFailFast(RhFailFastReason.InternalError, null); }