Example #1
0
        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;
            }
        }
Example #2
0
        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();
        }
Example #3
0
        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;
            }
        }
Example #4
0
        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));
        }