tinyheap.inc 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. {$ifdef cpui8086}
  12. {$if defined(FPC_X86_DATA_FAR) or defined(FPC_X86_DATA_HUGE)}
  13. {$define FPC_HEAP_HUGE}
  14. {$endif}
  15. {$endif cpui8086}
  16. {$ifdef FPC_HEAP_HUGE}
  17. {$HugePointerArithmeticNormalization On}
  18. {$HugePointerComparisonNormalization On}
  19. {$endif FPC_HEAP_HUGE}
  20. type
  21. { TTinyHeapMemBlockSize holds the size of an *allocated* memory block,
  22. and is written at position:
  23. memblockstart-sizeof(TTinyHeapMemBlockSize) }
  24. PTinyHeapMemBlockSize = ^TTinyHeapMemBlockSize; {$ifdef FPC_HEAP_HUGE}huge;{$endif}
  25. TTinyHeapMemBlockSize = PtrUInt;
  26. { TTinyHeapFreeBlockSize holds the size of a *free* memory block, as a
  27. part of the TTinyHeapBlock structure }
  28. TTinyHeapFreeBlockSize = PtrUInt;
  29. TTinyHeapPointerArithmeticType = ^Byte; {$ifdef FPC_HEAP_HUGE}huge;{$endif}
  30. PTinyHeapBlock = ^TTinyHeapBlock;
  31. TTinyHeapBlock = record
  32. Next: PTinyHeapBlock;
  33. Size: TTinyHeapFreeBlockSize;
  34. end;
  35. const
  36. TinyHeapMinBlock = sizeof(TTinyHeapBlock);
  37. TinyHeapAllocGranularity = sizeof(TTinyHeapBlock);
  38. var
  39. TinyHeapBlocks: PTinyHeapBlock = nil;
  40. procedure InternalTinyFreeMem(Addr: Pointer; Size: TTinyHeapFreeBlockSize); forward;
  41. function FindSize(p: pointer): TTinyHeapMemBlockSize;
  42. begin
  43. FindSize := PTinyHeapMemBlockSize(p)[-1];
  44. end;
  45. function SysTinyGetMem(Size: ptruint): pointer;
  46. var
  47. p, prev: PTinyHeapBlock;
  48. AllocSize, RestSize: ptruint;
  49. begin
  50. {$ifdef DEBUG_TINY_HEAP}
  51. Write('SysTinyGetMem(', Size, ')=');
  52. {$endif DEBUG_TINY_HEAP}
  53. AllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  54. p := TinyHeapBlocks;
  55. prev := nil;
  56. while assigned(p) and (p^.Size < AllocSize) do
  57. begin
  58. prev := p;
  59. p := p^.Next;
  60. end;
  61. if assigned(p) then
  62. begin
  63. result := @PTinyHeapMemBlockSize(p)[1];
  64. if p^.Size-AllocSize >= TinyHeapMinBlock then
  65. RestSize := p^.Size-AllocSize
  66. else
  67. begin
  68. AllocSize := p^.Size;
  69. RestSize := 0;
  70. end;
  71. if prev = nil then
  72. TinyHeapBlocks := p^.Next
  73. else
  74. prev^.next := p^.next;
  75. PTinyHeapMemBlockSize(p)^ := size;
  76. if RestSize > 0 then
  77. InternalTinyFreeMem(pointer(TTinyHeapPointerArithmeticType(p)+AllocSize), RestSize);
  78. end
  79. else
  80. if ReturnNilIfGrowHeapFails then
  81. Result := nil
  82. else
  83. HandleError(203);
  84. {$ifdef DEBUG_TINY_HEAP}
  85. Writeln(ptruint(Result));
  86. {$endif DEBUG_TINY_HEAP}
  87. end;
  88. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  89. var
  90. mem: Pointer;
  91. memp: ptruint;
  92. begin
  93. if alignment <= sizeof(pointer) then
  94. result := GetMem(size)
  95. else
  96. begin
  97. mem := GetMem(Size+Alignment-1);
  98. memp := align(ptruint(mem), Alignment);
  99. InternalTinyFreeMem(mem, TTinyHeapPointerArithmeticType(memp)-TTinyHeapPointerArithmeticType(mem));
  100. result := pointer(memp);
  101. end;
  102. end;
  103. procedure InternalTinyFreeMem(Addr: Pointer; Size: TTinyHeapFreeBlockSize);
  104. var
  105. b, p, prev: PTinyHeapBlock;
  106. EndAddr: Pointer;
  107. concatenated: boolean;
  108. begin
  109. repeat
  110. concatenated := false;
  111. b := addr;
  112. b^.Next := TinyHeapBlocks;
  113. b^.Size := Size;
  114. EndAddr := pointer(TTinyHeapPointerArithmeticType(addr)+size);
  115. if TinyHeapBlocks = nil then
  116. TinyHeapBlocks := b
  117. else
  118. begin
  119. p := TinyHeapBlocks;
  120. prev := nil;
  121. while assigned(p) do
  122. begin
  123. if (TTinyHeapPointerArithmeticType(p)+p^.Size) = TTinyHeapPointerArithmeticType(Addr) then
  124. begin
  125. addr:=p;
  126. size:=p^.size+size;
  127. if prev = nil then
  128. TinyHeapBlocks:=p^.next
  129. else
  130. prev^.next:=p^.next;
  131. concatenated:=true;
  132. break;
  133. end
  134. else if p = EndAddr then
  135. begin
  136. size:=p^.size+size;
  137. if prev = nil then
  138. TinyHeapBlocks:=p^.next
  139. else
  140. prev^.next:=p^.next;
  141. concatenated:=true;
  142. break;
  143. end;
  144. prev := p;
  145. p := p^.next;
  146. end;
  147. if not concatenated then
  148. begin
  149. p := TinyHeapBlocks;
  150. prev := nil;
  151. while assigned(p) and (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(b)) do
  152. begin
  153. prev := p;
  154. p := p^.Next;
  155. end;
  156. if assigned(prev) then
  157. begin
  158. b^.Next := p;
  159. prev^.Next := b;
  160. end
  161. else
  162. TinyHeapBlocks := b;
  163. end;
  164. end;
  165. until not concatenated;
  166. end;
  167. function SysTinyFreeMem(Addr: Pointer): ptruint;
  168. var
  169. sz: ptruint;
  170. begin
  171. {$ifdef DEBUG_TINY_HEAP}
  172. Writeln('SysTinyFreeMem(', ptruint(Addr), ')');
  173. {$endif DEBUG_TINY_HEAP}
  174. if addr=nil then
  175. begin
  176. result:=0;
  177. exit;
  178. end;
  179. if (TTinyHeapPointerArithmeticType(addr) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  180. (TTinyHeapPointerArithmeticType(addr) >= TTinyHeapPointerArithmeticType(HeapEnd)) then
  181. HandleError(204);
  182. sz := Align(FindSize(addr)+SizeOf(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  183. InternalTinyFreeMem(@PTinyHeapMemBlockSize(addr)[-1], sz);
  184. result := sz;
  185. end;
  186. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  187. begin
  188. result := SysTinyFreeMem(addr);
  189. end;
  190. function SysTinyMemSize(p: pointer): ptruint;
  191. begin
  192. result := findsize(p);
  193. end;
  194. function SysTinyAllocMem(size: ptruint): pointer;
  195. begin
  196. result := SysTinyGetMem(size);
  197. if result<>nil then
  198. FillChar(result^,SysTinyMemSize(result),0);
  199. end;
  200. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  201. var
  202. sz: ptruint;
  203. begin
  204. {$ifdef DEBUG_TINY_HEAP}
  205. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  206. {$endif DEBUG_TINY_HEAP}
  207. if size=0 then
  208. result := nil
  209. else
  210. result := AllocMem(size);
  211. if result <> nil then
  212. begin
  213. if p <> nil then
  214. begin
  215. sz := FindSize(p);
  216. if sz > size then
  217. sz := size;
  218. move(pbyte(p)^, pbyte(result)^, sz);
  219. end;
  220. end;
  221. SysTinyFreeMem(p);
  222. p := result;
  223. {$ifdef DEBUG_TINY_HEAP}
  224. Writeln(ptruint(result));
  225. {$endif DEBUG_TINY_HEAP}
  226. end;
  227. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  228. var
  229. alignment_inc: smallint;
  230. begin
  231. {$ifdef DEBUG_TINY_HEAP}
  232. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  233. {$endif DEBUG_TINY_HEAP}
  234. alignment_inc := TTinyHeapPointerArithmeticType(align(AAddress,TinyHeapAllocGranularity))-TTinyHeapPointerArithmeticType(AAddress);
  235. Inc(AAddress,alignment_inc);
  236. Dec(ASize,alignment_inc);
  237. Dec(ASize,ASize mod TinyHeapAllocGranularity);
  238. if (HeapOrg=nil) or (TTinyHeapPointerArithmeticType(HeapOrg) > TTinyHeapPointerArithmeticType(AAddress)) then
  239. HeapOrg:=AAddress;
  240. if (HeapEnd=nil) or (TTinyHeapPointerArithmeticType(HeapEnd) < (TTinyHeapPointerArithmeticType(AAddress)+ASize)) then
  241. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  242. InternalTinyFreeMem(AAddress, ASize);
  243. end;
  244. const
  245. TinyHeapMemoryManager: TMemoryManager = (
  246. NeedLock: false; // Obsolete
  247. GetMem: @SysTinyGetMem;
  248. FreeMem: @SysTinyFreeMem;
  249. FreeMemSize: @SysTinyFreeMemSize;
  250. AllocMem: @SysTinyAllocMem;
  251. ReAllocMem: @SysTinyReAllocMem;
  252. MemSize: @SysTinyMemSize;
  253. InitThread: nil;
  254. DoneThread: nil;
  255. RelocateHeap: nil;
  256. GetHeapStatus: nil;
  257. GetFPCHeapStatus: nil;
  258. );