public static unsafe IntPtr GetNewThunksBlock() { IntPtr nextThunksBlock; // 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 < Constants.NumThunkBlocksPerMapping) { nextThunksBlock = s_currentlyMappedThunkBlocks[s_currentlyMappedThunkBlocksIndex++]; #if DEBUG s_currentlyMappedThunkBlocks[s_currentlyMappedThunkBlocksIndex - 1] = IntPtr.Zero; Debug.Assert(nextThunksBlock != IntPtr.Zero); #endif } else { nextThunksBlock = InternalCalls.RhAllocateThunksMapping(); if (nextThunksBlock == 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. 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 IntPtr currentThunksBlock = nextThunksBlock; int thunkBlockSize = InternalCalls.RhpGetThunkBlockSize(); for (int i = 0; i < Constants.NumThunkBlocksPerMapping; i++) { s_currentlyMappedThunkBlocks[i] = currentThunksBlock; currentThunksBlock += thunkBlockSize; } s_currentlyMappedThunkBlocksIndex = 1; } Debug.Assert(nextThunksBlock != 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. IntPtr dataAddress = InternalCalls.RhpGetThunkDataBlockAddress(nextThunksBlock); for (int i = 0; i < Constants.NumThunksPerBlock; i++) { if (i == (Constants.NumThunksPerBlock - 1)) { *((IntPtr *)(dataAddress)) = IntPtr.Zero; } else { *((IntPtr *)(dataAddress)) = dataAddress + Constants.ThunkDataSize; } #if DEBUG // Debug flag in the second data cell indicating the thunk is not used *((IntPtr *)(dataAddress + IntPtr.Size)) = new IntPtr(-1); #endif dataAddress += Constants.ThunkDataSize; } return(nextThunksBlock); }