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 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 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 unsafe static IntPtr GetNewThunksBlock() { IntPtr nextThunkMapBlock; // Check the most recently mapped thunks block. Each mapping consists of multiple // thunk stubs pages, and multiple thunk data pages (typically 8 pages of each in a single mapping) if (s_currentlyMappedThunkBlocksIndex < NumThunkBlocksMapping) { nextThunkMapBlock = s_currentlyMappedThunkBlocks[s_currentlyMappedThunkBlocksIndex++]; #if DEBUG s_currentlyMappedThunkBlocks[s_currentlyMappedThunkBlocksIndex - 1] = IntPtr.Zero; Debug.Assert(nextThunkMapBlock != IntPtr.Zero); #endif } else { if (s_thunksTemplate == IntPtr.Zero) { // First, we use the thunks directly from the thunks template sections in the module until all // thunks in that template are used up. s_thunksTemplate = nextThunkMapBlock = InternalCalls.RhpGetThunksBase(); } else { // Compute and cache the current module's base address and the RVA of the thunks template if (s_thunksModuleBaseAddress == IntPtr.Zero) { EEType *pInstanceType = (new ThunkBlocks()).EEType; s_thunksModuleBaseAddress = InternalCalls.RhGetModuleFromPointer(pInstanceType); IntPtr thunkBase = InternalCalls.RhpGetThunksBase(); Debug.Assert(thunkBase != IntPtr.Zero); s_thunksTemplateRva = (int)(((nuint)thunkBase) - ((nuint)s_thunksModuleBaseAddress)); Debug.Assert(s_thunksTemplateRva % (int)Constants.AllocationGranularity == 0); } // We've already used the thunks tempate in the module for some previous thunks, and we // cannot reuse it here. Now we need to create a new mapping of the thunks section in order to have // more thunks nextThunkMapBlock = InternalCalls.RhAllocateThunksFromTemplate( s_thunksModuleBaseAddress, s_thunksTemplateRva, (int)(NumThunkBlocksMapping * Constants.PageSize * 2)); if (nextThunkMapBlock == IntPtr.Zero) { // We either ran out of memory and can't do anymore mappings of the thunks templates sections, // or we are using the managed runtime services fallback, which doesn't provide the // file mapping feature (ex: older version of mrt100.dll, or no mrt100.dll at all). // The only option is for the caller to attempt and recycle unused thunks to be able to // find some free entries. InternalCalls.RhpReleaseThunkPoolLock(); return(IntPtr.Zero); } } // Each mapping consists of multiple blocks of thunk stubs/data pairs. Keep track of those // so that we do not create a new mapping until all blocks in the sections we just mapped are consumed for (int i = 0; i < NumThunkBlocksMapping; i++) { s_currentlyMappedThunkBlocks[i] = nextThunkMapBlock + (int)(Constants.PageSize * i * 2); } s_currentlyMappedThunkBlocksIndex = 1; } Debug.Assert(nextThunkMapBlock != IntPtr.Zero); // Setup the thunks in the new block as a linked list of thunks. // Use the first data field of the thunk to build the linked list. int numThunksPerBlock = InternalCalls.RhpGetNumThunksPerBlock(); IntPtr dataAddress = nextThunkMapBlock + (int)Constants.PageSize; for (int i = 0; i < numThunksPerBlock; i++) { Debug.Assert(dataAddress == nextThunkMapBlock + (int)(Constants.PageSize + i * 2 * IntPtr.Size)); if (i == (numThunksPerBlock - 1)) { *((IntPtr *)(dataAddress)) = IntPtr.Zero; } else { *((IntPtr *)(dataAddress)) = dataAddress + 2 * IntPtr.Size; } #if DEBUG // Debug flag in the second data cell indicating the thunk is not used *((IntPtr *)(dataAddress + IntPtr.Size)) = new IntPtr(-1); #endif dataAddress += 2 * IntPtr.Size; } return(nextThunkMapBlock); }