private unsafe ThunksHeap(IntPtr commonStubAddress) { _commonStubAddress = commonStubAddress; _allocatedBlocks = new AllocatedBlock(); InternalCalls.RhpAcquireThunkPoolLock(); IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(); InternalCalls.RhpReleaseThunkPoolLock(); if (thunkStubsBlock != IntPtr.Zero) { IntPtr thunkDataBlock = InternalCalls.RhpGetThunkDataBlockAddress(thunkStubsBlock); // Address of the first thunk data cell should be at the begining of the thunks data block (page-aligned) Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0); // Update the last pointer value in the thunks data section with the value of the common stub address *(IntPtr *)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = commonStubAddress; Debug.Assert(*(IntPtr *)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == commonStubAddress); // Set the head and end of the linked list _nextAvailableThunkPtr = thunkDataBlock; _lastThunkPtr = _nextAvailableThunkPtr + Constants.ThunkDataSize * (Constants.NumThunksPerBlock - 1); _allocatedBlocks._blockBaseAddress = thunkStubsBlock; } }
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 unsafe ThunksHeap(IntPtr commonStubAddress) { _commonStubAddress = commonStubAddress; _allocatedBlocks = new AllocatedBlock(); InternalCalls.RhpAcquireThunkPoolLock(); IntPtr thunksBlock = ThunkBlocks.GetNewThunksBlock(); InternalCalls.RhpReleaseThunkPoolLock(); if (thunksBlock != IntPtr.Zero) { // Update the last pointer value in the thunks data section with the value of the common stub address *((IntPtr *)(thunksBlock + (int)(Constants.PageSize * 2 - IntPtr.Size))) = commonStubAddress; Debug.Assert(*((IntPtr *)(thunksBlock + (int)(Constants.PageSize * 2 - IntPtr.Size))) != IntPtr.Zero); // Set the head and end of the linked list _nextAvailableThunkPtr = thunksBlock + (int)Constants.PageSize; _lastThunkPtr = _nextAvailableThunkPtr + 2 * IntPtr.Size * (InternalCalls.RhpGetNumThunksPerBlock() - 1); _allocatedBlocks._blockBaseAddress = thunksBlock; } }
public unsafe IntPtr AllocateThunk() { // TODO: optimize the implementation and make it lock-free // or at least change it to a per-heap lock instead of a global lock. Debug.Assert(_nextAvailableThunkPtr != IntPtr.Zero); InternalCalls.RhpAcquireThunkPoolLock(); IntPtr nextAvailableThunkPtr = _nextAvailableThunkPtr; IntPtr nextNextAvailableThunkPtr = *((IntPtr *)(nextAvailableThunkPtr)); if (nextNextAvailableThunkPtr == IntPtr.Zero) { if (!ExpandHeap()) { InternalCalls.RhpReleaseThunkPoolLock(); return(IntPtr.Zero); } nextAvailableThunkPtr = _nextAvailableThunkPtr; nextNextAvailableThunkPtr = *((IntPtr *)(nextAvailableThunkPtr)); Debug.Assert(nextNextAvailableThunkPtr != IntPtr.Zero); } _nextAvailableThunkPtr = nextNextAvailableThunkPtr; InternalCalls.RhpReleaseThunkPoolLock(); Debug.Assert(nextAvailableThunkPtr != IntPtr.Zero); #if DEBUG // Reset debug flag indicating the thunk is now in use *((IntPtr *)(nextAvailableThunkPtr + IntPtr.Size)) = IntPtr.Zero; #endif int thunkIndex = (int)(((nuint)(nint)nextAvailableThunkPtr) - ((nuint)(nint)nextAvailableThunkPtr & ~Constants.PageSizeMask)); Debug.Assert((thunkIndex % Constants.ThunkDataSize) == 0); thunkIndex = thunkIndex / Constants.ThunkDataSize; IntPtr thunkAddress = InternalCalls.RhpGetThunkStubsBlockAddress(nextAvailableThunkPtr) + thunkIndex * Constants.ThunkCodeSize; return(SetThumbBit(thunkAddress)); }