public void TryAllocateTest() { IMemorySlab target = CreateIMemorySlab(); //allocate 1 byte long smallLength = 1; IMemoryBlock allocatedBlock = null; bool result1 = target.TryAllocate(smallLength, out allocatedBlock); Assert.AreEqual <long>(smallLength, allocatedBlock.Length); Assert.AreEqual <long>(0, allocatedBlock.StartLocation); Assert.AreEqual <bool>(true, result1); //allocate rest of slab long restLength = totalSize - 1; IMemoryBlock allocatedBlock2 = null; bool result2 = target.TryAllocate(restLength, out allocatedBlock2); Assert.AreEqual <long>(restLength, allocatedBlock2.Length); Assert.AreEqual <long>(1, allocatedBlock2.StartLocation); Assert.AreEqual <bool>(true, result2); //Now try to allocate another byte and expect it to fail IMemoryBlock allocatedBlock3 = null; bool result3 = target.TryAllocate(smallLength, out allocatedBlock3); Assert.AreEqual <bool>(false, result3); //Clean up target.Free(allocatedBlock); target.Free(allocatedBlock2); }
public MBC3Cartridge(byte[] romData) { _romData = romData; _ramData = new byte[32768]; ROM = new LambdaMemoryBlock(32768, ReadRom, WriteRom); RAM = new LambdaMemoryBlock(8192, ReadRam, WriteRam); }
public MemoryWindow([NotNull] IMemoryBlock memoryBlock, int offset, long size) { if (memoryBlock == null) { throw new ArgumentNullException(nameof(memoryBlock)); } if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (size > memoryBlock.Size - offset) { throw new ArgumentOutOfRangeException(nameof(size), "The window size is larger than the size of the target block."); } Pointer = memoryBlock.GetPointer() + offset; Size = size; mReadable = memoryBlock is IReadableMemory; mWritable = memoryBlock is IWritableMemory; if (!mReadable && !mWritable) { // neither readable nor writable!? must be some unknown memory restriction... mReadable = mWritable = true; } }
public static Bitmap RenderTile(IMemoryBlock vram, int tileIndex) { if (tileIndex < 0 || tileIndex >= 384) { throw new ArgumentException("Invalid tile index.", nameof(tileIndex)); } var shades = new[] { new Pixel(255, 255, 255), new Pixel(192, 192, 192), new Pixel(96, 96, 96), new Pixel(0, 0, 0), }; var tile = new Bitmap(8, 8); var tileOffset = tileIndex << 4; for (int y = 0; y < 8; y++) { var lower = vram[tileOffset + y * 2]; var upper = vram[tileOffset + y * 2 + 1]; for (int x = 0; x < 8; x++) { var shadeId = (upper.GetBit(7 - x) ? 2 : 0) + (lower.GetBit(7 - x) ? 1 : 0); var shade = shades[shadeId]; tile[x, y] = shade; } } return(tile); }
public RomOnlyCartridge(byte[] romData) { Debug.Assert(romData.Length == 32768); ROM = new MemoryBlock(romData); // TODO apparently some small carts DO have a (non-switchable) RAM RAM = new MemorySink(); }
public TextureView([NotNull] IMemoryBlock memory, int stride, TextureFormat format) { if (memory == null) { throw new ArgumentNullException(nameof(memory)); } if (stride <= 0) { throw new ArgumentOutOfRangeException(nameof(stride)); } mMemory = memory; mFormat = format; mReadableMemory = new ReadOnlyMemoryWindow(memory); mStride = stride; mWidth = stride >> 2; mHeight = (int)(memory.Size / stride); mReadable = memory is IReadableMemory; mWritable = memory is IWritableMemory; if (!mReadable && !mWritable) { // neither readable nor writable!? must be some unknown memory restriction... mReadable = mWritable = true; } }
public static IEnumerator <byte> InstructionAt(this IMemoryBlock memory, ushort address) { while (true) { yield return(memory[address++]); } }
public static void Dump(this IMemoryBlock memory, TextWriter output) { for (int i = 0; i < memory.Size; i++) { if (i % 16 == 0) { output.Write($"0x{i:X4} : "); } output.Write($"{memory[i]:X2} "); if (i % 16 != 15) { continue; } output.Write(": "); for (int j = i - 15; j <= i; j++) { output.Write(memory[j].ToDisplayableChar()); output.Write(" "); } output.WriteLine(); } output.Flush(); }
/// <summary> /// Marks an unallocated contiguous block as allocated /// </summary> /// <param name="block">newly allocated block</param> protected void RemoveFreeBlock(IMemoryBlock block) { dictStartLoc.Remove(block.StartLocation); dictEndLoc.Remove(block.EndLocation); if (freeBlocksList[block.Length].Count == 1) { freeBlocksList.Remove(block.Length); if (GetLargest() == block.Length) { //Get the true largest if (freeBlocksList.Count == 0) { SetLargest(0); } else { long[] indices = new long[freeBlocksList.Count]; freeBlocksList.Keys.CopyTo(indices, 0); SetLargest(indices[indices.LongLength - 1]); } } } else { freeBlocksList[block.Length].Remove(block.StartLocation); } }
private void ReadMask(PipeStream stream) { IndexOfResult result = stream.IndexOf((int)this.Length); int index = 0; if (result.Start.ID == result.End.ID) { index = MarkBytes(result.Start.Bytes, result.StartPostion, result.EndPostion, index); } else { index = MarkBytes(result.Start.Bytes, result.StartPostion, result.Start.Length - 1, index); IMemoryBlock next = result.Start.NextMemory; while (next != null) { if (next.ID == result.End.ID) { index = MarkBytes(next.Bytes, 0, result.EndPostion, index); break; } else { index = MarkBytes(next.Bytes, 0, next.Length - 1, index); } next = result.Start.NextMemory; } } }
/// <summary> /// Frees an allocated memory block. /// </summary> /// <param name="allocatedBlock">Allocated memory block to be freed</param> /// <remarks>This method does not verify if the allocatedBlock is indeed from this slab. Callers should make sure that the allocatedblock belongs to the right slab.</remarks> public void Free(IMemoryBlock allocatedBlock) { //NOTE: This method can call the pool to do some cleanup (which holds locks), therefore do not call this method from within any lock //Or you'll get into a deadlock. lock (sync) { //Attempt to coalesce/merge free blocks around the allocateblock to be freed. long?newFreeStartLocation = null; long newFreeSize = 0; if (allocatedBlock.StartLocation > 0) { //Check if block before this one is free long startLocBefore; if (dictEndLoc.TryGetValue(allocatedBlock.StartLocation - 1, out startLocBefore)) { //Yup, so remove the free block newFreeStartLocation = startLocBefore; newFreeSize += (allocatedBlock.StartLocation - startLocBefore); RemoveFreeBlock(dictStartLoc[startLocBefore], true); } } //Include AllocatedBlock if (!newFreeStartLocation.HasValue) { newFreeStartLocation = allocatedBlock.StartLocation; } newFreeSize += allocatedBlock.Length; if (allocatedBlock.EndLocation + 1 < Size) { // Check if block next to (below) this one is free FreeSpace blockAfter; if (dictStartLoc.TryGetValue(allocatedBlock.EndLocation + 1, out blockAfter)) { //Yup, remove the free block newFreeSize += blockAfter.Length; RemoveFreeBlock(blockAfter, true); } } //Mark entire contiguous block as free -- and set Largest if need be: //The length of the AddFreeBlock call will always be longer than or equals to any of the RemoveFreeBlock // calls, so it's SetLargest logic will always work. AddFreeBlock(newFreeStartLocation.Value, newFreeSize, false); } if (GetLargest() == slabSize) { //This slab is empty. prod pool to do some cleanup if (pool != null) { pool.TryFreeSlabs(); } } }
public void LengthTest() { IMemoryBlock target = CreateIMemoryBlock(); long actual; actual = target.Length; Assert.AreEqual <long>(length, actual); }
public MBC1Cartridge(byte[] romData) { _romData = romData; // 32 KByte of RAM (TODO actual available RAM depends on concrete cartridge?) _ramData = new byte[32768]; ROM = new LambdaMemoryBlock(32768, ReadRom, WriteRom); RAM = new LambdaMemoryBlock(8192, ReadRam, WriteRam); }
public void StartLocationTest() { IMemoryBlock target = CreateIMemoryBlock(); long actual; actual = target.StartLocation; Assert.AreEqual <long>(startLoc, actual); }
public void SlabTest() { IMemoryBlock target = CreateIMemoryBlock(); IMemorySlab actual; actual = target.Slab; Assert.AreEqual <IMemorySlab>(slab, actual); }
public static IMemoryBlock CastTo(this IMemoryBlock source, NPTypeCode to) { switch (to) { #if _REGEN1 %foreach supported_dtypes,supported_dtypes_lowercase% case NPTypeCode.#1: return CastTo<#2>(source); %
public MBC2Cartridge(byte[] romData) { _romData = romData; // MBC2 has 512 x 4 bits of RAM on addresses 0xA000-0xA1FF. _ramData = new byte[512]; ROM = new LambdaMemoryBlock(32768, ReadRom, WriteRom); RAM = new LambdaMemoryBlock(8192, ReadRam, WriteRam); }
public MBC5Cartridge(byte[] romData) { _romData = romData; // Has maximum of 16 banks of 8KBytes each. _ramData = new byte[8192 * 16]; ROM = new LambdaMemoryBlock(32768, ReadRom, WriteRom); RAM = new LambdaMemoryBlock(8192, ReadRam, WriteRam); }
/// <summary> /// Attempts to allocate a memory block of a specified length. /// </summary> /// <param name="length">Length, in bytes, of memory block</param> /// <param name="allocatedBlock">Allocated memory block</param> /// <returns>True, if memory block was allocated. False, if otherwise</returns> public virtual bool TryAllocate(long length, out IMemoryBlock allocatedBlock) { allocatedBlock = null; lock (sync) { if (GetLargest() < length) { return(false); } //search freeBlocksList looking for the smallest available free block long[] keys = new long[freeBlocksList.Count]; freeBlocksList.Keys.CopyTo(keys, 0); int index = System.Array.BinarySearch <long>(keys, length); if (index < 0) { index = ~index; if (index >= keys.LongLength) { return(false); } } //Grab the first memoryblock in the freeBlockList innerSortedDictionary //There is guanranteed to be an innerSortedDictionary with at least 1 key=value pair IMemoryBlock foundBlock = null; foreach (KeyValuePair <long, IMemoryBlock> kvPair in freeBlocksList[keys[index]]) { foundBlock = kvPair.Value; break; } //Remove existing free block RemoveFreeBlock(foundBlock); if (foundBlock.Length == length) { //Perfect match allocatedBlock = foundBlock; } else { //FoundBlock is larger than requested block size allocatedBlock = new MemoryBlock(foundBlock.StartLocation, length, this); long newFreeStartLocation = allocatedBlock.EndLocation + 1; long newFreeSize = foundBlock.Length - length; //add new Freeblock with the smaller remaining space AddFreeBlock(newFreeStartLocation, newFreeSize); } } return(true); }
/// <summary> /// Initializes a new instance of the ManagedBuffer class, specifying the memory block that the ManagedBuffer reads and writes to. /// </summary> /// <param name="allocatedMemoryBlock">Underlying allocated memory block</param> internal ManagedBuffer(IMemoryBlock allocatedMemoryBlock) { if (allocatedMemoryBlock == null) { throw new ArgumentNullException("AllocatedMemoryBlock"); } memoryBlock = allocatedMemoryBlock; slabArray = null; }
public void EndLocationTest() { //Correct Property IMemoryBlock target = CreateIMemoryBlock(); long actual; actual = target.EndLocation; Assert.AreEqual <long>(startLoc + length - 1, actual); }
/// <summary> /// Initializes a new instance of the ManagedBuffer class, specifying the slab to be associated with the ManagedBuffer. /// This constructor creates an empty (zero-length) buffer. /// </summary> /// <param name="slab">The Memory Slab to be associated with the ManagedBuffer</param> internal ManagedBuffer(IMemorySlab slab) { if (slab == null) { throw new ArgumentNullException("SlabArray"); } memoryBlock = null; this.slabArray = slab.Array; }
public void TryAllocateTest3() { IMemorySlab target = CreateIMemorySlab(); //allocate invalid length long badLength = -1; IMemoryBlock allocatedBlock = null; bool result1 = target.TryAllocate(badLength, out allocatedBlock); }
public ReadOnlyMemoryWindow([NotNull] IMemoryBlock memoryBlock) { if (memoryBlock == null) { throw new ArgumentNullException(nameof(memoryBlock)); } Pointer = memoryBlock.GetPointer(); Size = memoryBlock.Size; }
/// <summary> /// Copies the entire contents of this storage to given address (using <see cref="Count"/>). /// </summary> /// <param name="dst">The block to copy to.</param> public static unsafe void CopyTo(this IMemoryBlock src, void *dstAddress, int countOffsetDesitinion) { if (dstAddress == null) { throw new ArgumentNullException(nameof(dstAddress)); } var bytesCount = src.BytesLength; Buffer.MemoryCopy(src.Address, (byte *)dstAddress + countOffsetDesitinion * src.ItemLength, bytesCount, bytesCount); }
/// <summary> /// Frees an allocated memory block. /// </summary> /// <param name="allocatedBlock">Allocated memory block to be freed</param> /// <remarks>This method does not detect if the allocatedBlock is indeed from this slab. Callers should make sure that the allocatedblock belongs to the right slab.</remarks> public virtual void Free(IMemoryBlock allocatedBlock) { lock (sync) { //Attempt to coalesce/merge free blocks around the allocateblock to be freed. long?newFreeStartLocation = null; long newFreeSize = 0; if (allocatedBlock.StartLocation > 0) { //Check if block before this one is free IMemoryBlock blockBefore; if (dictEndLoc.TryGetValue(allocatedBlock.StartLocation - 1, out blockBefore)) { //Yup, so delete it newFreeStartLocation = blockBefore.StartLocation; newFreeSize += blockBefore.Length; RemoveFreeBlock(blockBefore); } } //Include AllocatedBlock if (!newFreeStartLocation.HasValue) { newFreeStartLocation = allocatedBlock.StartLocation; } newFreeSize += allocatedBlock.Length; if (allocatedBlock.EndLocation + 1 < Size) { // Check if block next to (below) this one is free IMemoryBlock blockAfter; if (dictStartLoc.TryGetValue(allocatedBlock.EndLocation + 1, out blockAfter)) { //Yup, delete it newFreeSize += blockAfter.Length; RemoveFreeBlock(blockAfter); } } //Mark entire contiguous block as free AddFreeBlock(newFreeStartLocation.Value, newFreeSize); } if (GetLargest() == Size) { //This slab is empty. prod pool to do some cleanup if (pool != null) { pool.TryFreeSlab(); } } }
/// <summary> /// Copies the entire contents of this storage to given address. /// </summary> /// <param name="src">The source of the copying</param> /// <param name="dstAddress">The address to copy to.</param> public static unsafe void CopyTo(this IMemoryBlock src, void *dstAddress) { if (dstAddress == null) { throw new ArgumentNullException(nameof(dstAddress)); } var bytesCount = src.BytesLength; Buffer.MemoryCopy(src.Address, dstAddress, bytesCount, bytesCount); }
public UnmanagedStream([NotNull] IReadWriteMemory memory) { if (memory == null) { throw new ArgumentNullException(nameof(memory)); } mMemory = memory; CanRead = true; CanSeek = true; CanWrite = true; }
public MemoryWindow([NotNull] IMemoryBlock memoryBlock) { if (memoryBlock == null) { throw new ArgumentNullException(nameof(memoryBlock)); } Pointer = memoryBlock.GetPointer(); Size = memoryBlock.Size; mReadable = memoryBlock is IReadableMemory; mWritable = memoryBlock is IWritableMemory; }
public static Bitmap RenderTilemapSmall(IMemoryBlock vram, IRegister <bool> tilemapSelect) { var tilemap = new Bitmap(32, 32); var tilemapOffset = tilemapSelect.Value ? 0x1C00 : 0x1800; for (int i = 0; i < 1024; i++) { var x = i % 32; var y = i / 32; var tileIndex = vram[tilemapOffset + y * 32 + x]; tilemap[x, y] = tileIndex != 0 ? new Pixel(tileIndex, tileIndex, tileIndex) : new Pixel(0xFF, 0xFF, 0xFF); } return(tilemap); }
/// <summary> /// Attempts to allocate a memory block of a specified length. /// </summary> /// <param name="length">Length, in bytes, of memory block</param> /// <param name="allocatedBlock">Allocated memory block</param> /// <returns>True, if memory block was allocated. False, if otherwise</returns> public virtual bool TryAllocate(long length, out IMemoryBlock allocatedBlock) { allocatedBlock = null; lock (sync) { if (GetLargest() < length) return false; //search freeBlocksList looking for the smallest available free block long[] keys = new long[freeBlocksList.Count]; freeBlocksList.Keys.CopyTo(keys, 0); int index = System.Array.BinarySearch<long>(keys, length); if (index < 0) { index = ~index; if (index >= keys.LongLength) { return false; } } //Grab the first memoryblock in the freeBlockList innerSortedDictionary //There is guanranteed to be an innerSortedDictionary with at least 1 key=value pair IMemoryBlock foundBlock = null; foreach (KeyValuePair<long, IMemoryBlock> kvPair in freeBlocksList[keys[index]]) { foundBlock = kvPair.Value; break; } //Remove existing free block RemoveFreeBlock(foundBlock); if (foundBlock.Length == length) { //Perfect match allocatedBlock = foundBlock; } else { //FoundBlock is larger than requested block size allocatedBlock = new MemoryBlock(foundBlock.StartLocation, length, this); long newFreeStartLocation = allocatedBlock.EndLocation + 1; long newFreeSize = foundBlock.Length - length; //add new Freeblock with the smaller remaining space AddFreeBlock(newFreeStartLocation, newFreeSize); } } return true; }
/// <summary> /// Frees an allocated memory block. /// </summary> /// <param name="allocatedBlock">Allocated memory block to be freed</param> /// <remarks>This method does not verify if the allocatedBlock is indeed from this slab. Callers should make sure that the allocatedblock belongs to the right slab.</remarks> public void Free(IMemoryBlock allocatedBlock) { //NOTE: This method can call the pool to do some cleanup (which holds locks), therefore do not call this method from within any lock //Or you'll get into a deadlock. lock (sync) { //Attempt to coalesce/merge free blocks around the allocateblock to be freed. long? newFreeStartLocation = null; long newFreeSize = 0; if (allocatedBlock.StartLocation > 0) { //Check if block before this one is free long startLocBefore; if (dictEndLoc.TryGetValue(allocatedBlock.StartLocation - 1, out startLocBefore)) { //Yup, so remove the free block newFreeStartLocation = startLocBefore; newFreeSize += (allocatedBlock.StartLocation - startLocBefore); RemoveFreeBlock(dictStartLoc[startLocBefore], true); } } //Include AllocatedBlock if (!newFreeStartLocation.HasValue) newFreeStartLocation = allocatedBlock.StartLocation; newFreeSize += allocatedBlock.Length; if (allocatedBlock.EndLocation + 1 < Size) { // Check if block next to (below) this one is free FreeSpace blockAfter; if (dictStartLoc.TryGetValue(allocatedBlock.EndLocation + 1, out blockAfter)) { //Yup, remove the free block newFreeSize += blockAfter.Length; RemoveFreeBlock(blockAfter, true); } } //Mark entire contiguous block as free -- and set Largest if need be: //The length of the AddFreeBlock call will always be longer than or equals to any of the RemoveFreeBlock // calls, so it's SetLargest logic will always work. AddFreeBlock(newFreeStartLocation.Value, newFreeSize, false); } if (GetLargest() == slabSize) { //This slab is empty. prod pool to do some cleanup if (pool != null) { pool.TryFreeSlabs(); } } }
/// <summary> /// Attempts to allocate a memory block of a specified length. /// </summary> /// <param name="length">Length, in bytes, of memory block</param> /// <param name="allocatedBlock">Allocated memory block</param> /// <returns>True, if memory block was allocated. False, if otherwise</returns> public bool TryAllocate(long length, out IMemoryBlock allocatedBlock) { return TryAllocate(length, length, out allocatedBlock) > 0; }
//**************************************************** // Method: Partition // // Purpose: Constructor initializes the partition. //**************************************************** public Partition(int partitionNumber, int absoluteStartingAddress, IMemoryBlock memoryBlock) { this.partitionNumber = partitionNumber; this.absoluteStartingAddress = absoluteStartingAddress; this.memoryBlock = memoryBlock; }
/// <summary> /// Initializes a new instance of the ManagedBuffer class, specifying the memory block that the ManagedBuffer reads and writes to. /// </summary> /// <param name="allocatedMemoryBlock">Underlying allocated memory block</param> internal ManagedBuffer(IMemoryBlock allocatedMemoryBlock) { if (allocatedMemoryBlock == null) throw new ArgumentNullException("AllocatedMemoryBlock"); memoryBlock = allocatedMemoryBlock; slabArray = null; }
/// <summary> /// Helper method that searches for free block in an array of slabs and returns the allocated block /// </summary> /// <param name="length">Requested length of memory block</param> /// <param name="slabs">Array of slabs to search</param> /// <param name="allocatedBlock">Allocated memory block</param> /// <returns>True if memory block was successfully allocated. False, if otherwise</returns> private static bool TryAllocateBlockInSlabs(long length, IMemorySlab[] slabs, out IMemoryBlock allocatedBlock) { allocatedBlock = null; for (int i = 0; i < slabs.Length; i++) { if (slabs[i].LargestFreeBlockSize >= length) { if (slabs[i].TryAllocate(length, out allocatedBlock)) { return true; } } } return false; }
/// <summary> /// Initializes a new instance of the ManagedBuffer class, specifying the slab to be associated with the ManagedBuffer. /// This constructor creates an empty (zero-length) buffer. /// </summary> /// <param name="slab">The Memory Slab to be associated with the ManagedBuffer</param> internal ManagedBuffer(IMemorySlab slab) { if (slab == null) throw new ArgumentNullException("SlabArray"); memoryBlock = null; this.slabArray = slab.Array; }
public void BufferConstructorTest2() { IMemoryBlock[] emptyBlocks = new IMemoryBlock[0]; ManagedBuffer target = new ManagedBuffer(emptyBlocks); }
/// <summary> /// Attempts to allocate a memory block of length between minLength and maxLength (both inclusive) /// </summary> /// <param name="minLength">The minimum acceptable length</param> /// <param name="maxLength">The maximum acceptable length</param> /// <param name="allocatedBlock">Allocated memory block</param> /// <returns>Length of allocated block if successful, zero otherwise</returns> /// <remarks>This overload is useful when multiple threads are concurrently working on the slab and the caller wants to allocate a block up to a desired size</remarks> public long TryAllocate(long minLength, long maxLength, out IMemoryBlock allocatedBlock) { if (minLength > maxLength) throw new ArgumentException("minLength is greater than maxLength", "minLength"); if (minLength <= 0) throw new ArgumentOutOfRangeException("minLength must be greater than zero", "minLength"); if (maxLength <= 0) throw new ArgumentOutOfRangeException("maxLength must be greater than zero", "maxLength"); allocatedBlock = null; lock (sync) { if (freeBlocksList.Count == 0) return 0; long[] keys = new long[freeBlocksList.Count]; freeBlocksList.Keys.CopyTo(keys, 0); //Leave if the largest free block cannot hold minLength if (keys[keys.LongLength - 1] < minLength) { return 0; } //search freeBlocksList looking for the smallest available free block than can fit maxLength long length = maxLength; int index = System.Array.BinarySearch<long>(keys, maxLength); if (index < 0) { index = ~index; if (index >= keys.Length) { //index is set to the largest free block which can hold minLength index = keys.Length - 1; //length is set to the size of that free block length = keys[index]; } } //Grab the first memoryblock in the freeBlockList innerSortedDictionary //There is guanranteed to be at least one in the innerList FreeSpace foundBlock = dictStartLoc[freeBlocksList[keys[index]][0]]; if (foundBlock.Length == length) { //Perfect match: //Remove existing free block -- and set Largest if need be RemoveFreeBlock(foundBlock, false); allocatedBlock = new MemoryBlock(foundBlock.Offset, foundBlock.Length, this); } else { //FoundBlock is larger than requested block size //Shrink the existing free memory block by the new allocation ShrinkFreeMemoryBlock(foundBlock, foundBlock.Length - length); allocatedBlock = new MemoryBlock(foundBlock.Offset, length, this); } return length; } }
/// <summary> /// Frees an allocated memory block. /// </summary> /// <param name="allocatedBlock">Allocated memory block to be freed</param> /// <remarks>This method does not detect if the allocatedBlock is indeed from this slab. Callers should make sure that the allocatedblock belongs to the right slab.</remarks> public virtual void Free(IMemoryBlock allocatedBlock) { lock (sync) { //Attempt to coalesce/merge free blocks around the allocateblock to be freed. long? newFreeStartLocation = null; long newFreeSize = 0; if (allocatedBlock.StartLocation > 0) { //Check if block before this one is free IMemoryBlock blockBefore; if (dictEndLoc.TryGetValue(allocatedBlock.StartLocation - 1, out blockBefore)) { //Yup, so delete it newFreeStartLocation = blockBefore.StartLocation; newFreeSize += blockBefore.Length; RemoveFreeBlock(blockBefore); } } //Include AllocatedBlock if (!newFreeStartLocation.HasValue) newFreeStartLocation = allocatedBlock.StartLocation; newFreeSize += allocatedBlock.Length; if (allocatedBlock.EndLocation + 1 < Size) { // Check if block next to (below) this one is free IMemoryBlock blockAfter; if (dictStartLoc.TryGetValue(allocatedBlock.EndLocation + 1, out blockAfter)) { //Yup, delete it newFreeSize += blockAfter.Length; RemoveFreeBlock(blockAfter); } } //Mark entire contiguous block as free AddFreeBlock(newFreeStartLocation.Value, newFreeSize); } if (GetLargest() == Size) { //This slab is empty. prod pool to do some cleanup if (pool != null) { pool.TryFreeSlab(); } } }