diff --git a/rtl/inc/tinyheap.inc b/rtl/inc/tinyheap.inc index e7444274c8..e4c1d6991e 100644 --- a/rtl/inc/tinyheap.inc +++ b/rtl/inc/tinyheap.inc @@ -260,6 +260,9 @@ function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer; var oldsize, OldAllocSize, NewAllocSize: ptruint; + after_block, before_block: PTinyHeapBlock; + after_block_size: PtrUInt; + new_after_block: PTinyHeapBlock; begin {$ifdef DEBUG_TINY_HEAP} Write('SysTinyReAllocMem(', HexStr(p), ',', size, ')='); @@ -299,15 +302,75 @@ end else begin - result := AllocMem(size); - if result <> nil then + { we're increasing the memory block size. First, find if there are free memory blocks immediately + before and after our memory block. } + after_block := FreeList; + before_block := nil; + while (after_block<>HeapPtr) and (TTinyHeapPointerArithmeticType(after_block) < TTinyHeapPointerArithmeticType(p)) do begin - if oldsize > size then - oldsize := size; - move(pbyte(p)^, pbyte(result)^, oldsize); + before_block := after_block; + after_block := after_block^.Next; + end; + { is after_block immediately after our block? } + if after_block=Pointer(TTinyHeapPointerArithmeticType(p)+(OldAllocSize-PtrUInt(SizeOf(TTinyHeapMemBlockSize)))) then + begin + if after_block = HeapPtr then + after_block_size := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr)) + else + after_block_size := DecodeTinyHeapFreeBlockSize(after_block^.size); + end + else + after_block_size := 0; + { is there enough room after the block? } + if (OldAllocSize+after_block_size)>=NewAllocSize then + begin + if after_block = HeapPtr then + begin + HeapPtr:=Pointer(TTinyHeapPointerArithmeticType(HeapPtr)+(NewAllocSize-OldAllocSize)); + if assigned(before_block) then + before_block^.Next := HeapPtr + else + FreeList := HeapPtr; + end + else + begin + if (NewAllocSize-OldAllocSize)=after_block_size then + begin + if assigned(before_block) then + before_block^.Next := after_block^.Next + else + FreeList := after_block^.Next; + end + else + begin + new_after_block := PTinyHeapBlock(TTinyHeapPointerArithmeticType(after_block)+(NewAllocSize-OldAllocSize)); + new_after_block^.Next:=after_block^.Next; + new_after_block^.Size:=EncodeTinyHeapFreeBlockSize(after_block_size-(NewAllocSize-OldAllocSize)); + if assigned(before_block) then + before_block^.Next := new_after_block + else + FreeList := new_after_block; + end; + end; + PTinyHeapMemBlockSize(p)[-1] := size; + FillChar((TTinyHeapPointerArithmeticType(p)+oldsize)^, size-oldsize, 0); + end + else + begin + { is before_block immediately before our block? } + //if assigned(before_block) and (Pointer(TTinyHeapPointerArithmeticType(before_block)+DecodeTinyHeapFreeBlockSize(before_block^.Size))=Pointer(TTinyHeapPointerArithmeticType(p)-SizeOf(TTinyHeapMemBlockSize))) then + // ; + + result := AllocMem(size); + if result <> nil then + begin + if oldsize > size then + oldsize := size; + move(pbyte(p)^, pbyte(result)^, oldsize); + end; + SysTinyFreeMem(p); + p := result; end; - SysTinyFreeMem(p); - p := result; end; end; {$ifdef DEBUG_TINY_HEAP}