2
0

tinyheap.inc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2011 by the Free Pascal development team.
  4. Tiny heap manager for the i8086 near heap, embedded targets, etc.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. { The heap, implemented here is TP7-compatible in the i8086 far data memory
  12. models. It's basically a linked list of free blocks, which are kept ordered by
  13. start address. The FreeList variable points to the start of the list. Each
  14. free block, except the last one, contains a TTinyHeapBlock structure, which
  15. holds the block size and a pointer to the next free block. The HeapPtr
  16. variable points to the last free block, indicating the end of the list. The
  17. last block is special in that it doesn't contain a TTinyHeapBlock structure.
  18. Instead its size is determined by the pointer difference (HeapEnd-HeapPtr).
  19. It *can* become zero sized, when all the memory inside of it is allocated, in
  20. which case, HeapPtr will become equal to HeapEnd. }
  21. {$ifdef cpui8086}
  22. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  23. {$define FPC_HEAP_HUGE}
  24. {$endif}
  25. {$endif cpui8086}
  26. {$ifdef FPC_HEAP_HUGE}
  27. {$HugePointerArithmeticNormalization On}
  28. {$HugePointerComparisonNormalization On}
  29. {$endif FPC_HEAP_HUGE}
  30. type
  31. { TTinyHeapMemBlockSize holds the size of an *allocated* memory block,
  32. and is written at position:
  33. memblockstart-sizeof(TTinyHeapMemBlockSize) }
  34. PTinyHeapMemBlockSize = ^TTinyHeapMemBlockSize; {$ifdef FPC_HEAP_HUGE}huge;{$endif}
  35. TTinyHeapMemBlockSize = PtrUInt;
  36. { TTinyHeapFreeBlockSize holds the size of a *free* memory block, as a
  37. part of the TTinyHeapBlock structure }
  38. {$ifdef FPC_HEAP_HUGE}
  39. TTinyHeapFreeBlockSize = record
  40. OfsSize: Word;
  41. SegSize: Word;
  42. end;
  43. {$else FPC_HEAP_HUGE}
  44. TTinyHeapFreeBlockSize = PtrUInt;
  45. {$endif FPC_HEAP_HUGE}
  46. TTinyHeapPointerArithmeticType = ^Byte; {$ifdef FPC_HEAP_HUGE}huge;{$endif}
  47. PTinyHeapBlock = ^TTinyHeapBlock;
  48. TTinyHeapBlock = record
  49. Next: PTinyHeapBlock;
  50. Size: TTinyHeapFreeBlockSize;
  51. end;
  52. const
  53. TinyHeapMinBlock = sizeof(TTinyHeapBlock);
  54. TinyHeapAllocGranularity = sizeof(TTinyHeapBlock);
  55. function EncodeTinyHeapFreeBlockSize(Size: PtrUInt): TTinyHeapFreeBlockSize; inline;
  56. begin
  57. {$ifdef FPC_HEAP_HUGE}
  58. EncodeTinyHeapFreeBlockSize.OfsSize := Size and 15;
  59. EncodeTinyHeapFreeBlockSize.SegSize := Size shr 4;
  60. {$else FPC_HEAP_HUGE}
  61. EncodeTinyHeapFreeBlockSize := Size;
  62. {$endif FPC_HEAP_HUGE}
  63. end;
  64. function DecodeTinyHeapFreeBlockSize(Size: TTinyHeapFreeBlockSize): PtrUInt; inline;
  65. begin
  66. {$ifdef FPC_HEAP_HUGE}
  67. DecodeTinyHeapFreeBlockSize := (PtrUInt(Size.SegSize) shl 4) + Size.OfsSize;
  68. {$else FPC_HEAP_HUGE}
  69. DecodeTinyHeapFreeBlockSize := Size;
  70. {$endif FPC_HEAP_HUGE}
  71. end;
  72. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt); forward;
  73. function FindSize(p: pointer): TTinyHeapMemBlockSize;
  74. begin
  75. FindSize := PTinyHeapMemBlockSize(p)[-1];
  76. end;
  77. function SysTinyGetMem(Size: ptruint): pointer;
  78. var
  79. p, prev, p2: PTinyHeapBlock;
  80. AllocSize, RestSize: ptruint;
  81. begin
  82. {$ifdef DEBUG_TINY_HEAP}
  83. Write('SysTinyGetMem(', Size, ')=');
  84. {$endif DEBUG_TINY_HEAP}
  85. AllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  86. p := FreeList;
  87. prev := nil;
  88. while (p<>HeapPtr) and (DecodeTinyHeapFreeBlockSize(p^.Size) < AllocSize) do
  89. begin
  90. prev := p;
  91. p := p^.Next;
  92. end;
  93. if p<>HeapPtr then
  94. begin
  95. result := @PTinyHeapMemBlockSize(p)[1];
  96. if DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize >= TinyHeapMinBlock then
  97. RestSize := DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize
  98. else
  99. begin
  100. AllocSize := DecodeTinyHeapFreeBlockSize(p^.Size);
  101. RestSize := 0;
  102. end;
  103. if RestSize > 0 then
  104. begin
  105. p2 := pointer(TTinyHeapPointerArithmeticType(p)+AllocSize);
  106. p2^.Next := p^.Next;
  107. p2^.Size := EncodeTinyHeapFreeBlockSize(RestSize);
  108. if prev = nil then
  109. FreeList := p2
  110. else
  111. prev^.next := p2;
  112. end
  113. else
  114. begin
  115. if prev = nil then
  116. FreeList := p^.Next
  117. else
  118. prev^.next := p^.next;
  119. end;
  120. PTinyHeapMemBlockSize(p)^ := size;
  121. end
  122. else
  123. begin
  124. { p=HeapPtr }
  125. if PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr))<AllocSize then
  126. if ReturnNilIfGrowHeapFails then
  127. Result := nil
  128. else
  129. HandleError(203);
  130. result := @PTinyHeapMemBlockSize(HeapPtr)[1];
  131. PTinyHeapMemBlockSize(HeapPtr)^ := size;
  132. HeapPtr := pointer(TTinyHeapPointerArithmeticType(HeapPtr)+AllocSize);
  133. if prev = nil then
  134. FreeList := HeapPtr
  135. else
  136. prev^.next := HeapPtr;
  137. end;
  138. {$ifdef DEBUG_TINY_HEAP}
  139. Writeln(ptruint(Result));
  140. {$endif DEBUG_TINY_HEAP}
  141. end;
  142. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  143. var
  144. mem: Pointer;
  145. memp: ptruint;
  146. begin
  147. if alignment <= sizeof(pointer) then
  148. result := GetMem(size)
  149. else
  150. begin
  151. mem := GetMem(Size+Alignment-1);
  152. memp := align(ptruint(mem), Alignment);
  153. InternalTinyFreeMem(mem, TTinyHeapPointerArithmeticType(memp)-TTinyHeapPointerArithmeticType(mem));
  154. result := pointer(memp);
  155. end;
  156. end;
  157. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt);
  158. var
  159. p, prev: PTinyHeapBlock;
  160. begin
  161. p := FreeList;
  162. prev := nil;
  163. while (p<>HeapPtr) and (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(Addr)) do
  164. begin
  165. prev := p;
  166. p := p^.Next;
  167. end;
  168. { join with previous block? }
  169. if assigned(prev) and ((TTinyHeapPointerArithmeticType(prev)+DecodeTinyHeapFreeBlockSize(prev^.Size)) = TTinyHeapPointerArithmeticType(Addr)) then
  170. begin
  171. Addr:=prev;
  172. Size:=DecodeTinyHeapFreeBlockSize(prev^.size)+Size;
  173. end
  174. else
  175. if assigned(prev) then
  176. prev^.Next := Addr
  177. else
  178. FreeList := Addr;
  179. { join with next block? }
  180. if TTinyHeapPointerArithmeticType(p)=(TTinyHeapPointerArithmeticType(Addr)+Size) then
  181. begin
  182. if p=HeapPtr then
  183. HeapPtr:=Addr
  184. else
  185. begin
  186. PTinyHeapBlock(Addr)^.Next:=p^.Next;
  187. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size+DecodeTinyHeapFreeBlockSize(p^.Size));
  188. end;
  189. end
  190. else
  191. begin
  192. PTinyHeapBlock(Addr)^.Next:=p;
  193. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size);
  194. end;
  195. end;
  196. function SysTinyFreeMem(Addr: Pointer): ptruint;
  197. var
  198. sz: ptruint;
  199. begin
  200. {$ifdef DEBUG_TINY_HEAP}
  201. Writeln('SysTinyFreeMem(', ptruint(Addr), ')');
  202. {$endif DEBUG_TINY_HEAP}
  203. if addr=nil then
  204. begin
  205. result:=0;
  206. exit;
  207. end;
  208. if (TTinyHeapPointerArithmeticType(addr) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  209. (TTinyHeapPointerArithmeticType(addr) >= TTinyHeapPointerArithmeticType(HeapEnd)) then
  210. HandleError(204);
  211. sz := Align(FindSize(addr)+SizeOf(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  212. InternalTinyFreeMem(@PTinyHeapMemBlockSize(addr)[-1], sz);
  213. result := sz;
  214. end;
  215. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  216. begin
  217. result := SysTinyFreeMem(addr);
  218. end;
  219. function SysTinyMemSize(p: pointer): ptruint;
  220. begin
  221. result := findsize(p);
  222. end;
  223. function SysTinyAllocMem(size: ptruint): pointer;
  224. begin
  225. result := SysTinyGetMem(size);
  226. if result<>nil then
  227. FillChar(result^,SysTinyMemSize(result),0);
  228. end;
  229. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  230. var
  231. sz: ptruint;
  232. begin
  233. {$ifdef DEBUG_TINY_HEAP}
  234. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  235. {$endif DEBUG_TINY_HEAP}
  236. if size=0 then
  237. result := nil
  238. else
  239. result := AllocMem(size);
  240. if result <> nil then
  241. begin
  242. if p <> nil then
  243. begin
  244. sz := FindSize(p);
  245. if sz > size then
  246. sz := size;
  247. move(pbyte(p)^, pbyte(result)^, sz);
  248. end;
  249. end;
  250. SysTinyFreeMem(p);
  251. p := result;
  252. {$ifdef DEBUG_TINY_HEAP}
  253. Writeln(ptruint(result));
  254. {$endif DEBUG_TINY_HEAP}
  255. end;
  256. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  257. var
  258. alignment_inc: smallint;
  259. p: PTinyHeapBlock;
  260. begin
  261. {$ifdef DEBUG_TINY_HEAP}
  262. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  263. {$endif DEBUG_TINY_HEAP}
  264. alignment_inc := TTinyHeapPointerArithmeticType(align(AAddress,TinyHeapAllocGranularity))-TTinyHeapPointerArithmeticType(AAddress);
  265. Inc(AAddress,alignment_inc);
  266. Dec(ASize,alignment_inc);
  267. Dec(ASize,ASize mod TinyHeapAllocGranularity);
  268. if HeapOrg=nil then
  269. begin
  270. HeapOrg:=AAddress;
  271. HeapPtr:=AAddress;
  272. FreeList:=AAddress;
  273. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  274. end
  275. else
  276. begin
  277. if (TTinyHeapPointerArithmeticType(HeapOrg) > TTinyHeapPointerArithmeticType(AAddress)) then
  278. HeapOrg:=AAddress;
  279. if TTinyHeapPointerArithmeticType(AAddress) > TTinyHeapPointerArithmeticType(HeapEnd) then
  280. begin
  281. if TTinyHeapPointerArithmeticType(HeapPtr) = TTinyHeapPointerArithmeticType(HeapEnd) then
  282. begin
  283. if FreeList=HeapPtr then
  284. FreeList:=AAddress
  285. else
  286. begin
  287. p:=FreeList;
  288. while p^.Next<>HeapPtr do
  289. p:=p^.Next;
  290. PTinyHeapBlock(HeapPtr)^.Next:=AAddress;
  291. end;
  292. end
  293. else
  294. begin
  295. PTinyHeapBlock(HeapPtr)^.Size:=EncodeTinyHeapFreeBlockSize(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  296. PTinyHeapBlock(HeapPtr)^.Next:=AAddress;
  297. end;
  298. HeapPtr:=AAddress;
  299. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  300. end
  301. else if TTinyHeapPointerArithmeticType(AAddress) = TTinyHeapPointerArithmeticType(HeapEnd) then
  302. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize)
  303. else
  304. InternalTinyFreeMem(AAddress, ASize);
  305. end;
  306. end;
  307. const
  308. TinyHeapMemoryManager: TMemoryManager = (
  309. NeedLock: false; // Obsolete
  310. GetMem: @SysTinyGetMem;
  311. FreeMem: @SysTinyFreeMem;
  312. FreeMemSize: @SysTinyFreeMemSize;
  313. AllocMem: @SysTinyAllocMem;
  314. ReAllocMem: @SysTinyReAllocMem;
  315. MemSize: @SysTinyMemSize;
  316. InitThread: nil;
  317. DoneThread: nil;
  318. RelocateHeap: nil;
  319. GetHeapStatus: nil;
  320. GetFPCHeapStatus: nil;
  321. );