tinyheap.inc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. EndAddr: pointer;
  35. end;
  36. const
  37. TinyHeapMinBlock = 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), sizeof(pointer));
  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. concatenated: boolean;
  107. begin
  108. repeat
  109. concatenated := false;
  110. b := addr;
  111. b^.Next := TinyHeapBlocks;
  112. b^.Size := Size;
  113. b^.EndAddr := pointer(TTinyHeapPointerArithmeticType(addr)+size);
  114. if TinyHeapBlocks = nil then
  115. TinyHeapBlocks := b
  116. else
  117. begin
  118. p := TinyHeapBlocks;
  119. prev := nil;
  120. while assigned(p) do
  121. begin
  122. if p^.EndAddr = addr then
  123. begin
  124. addr:=p;
  125. size:=p^.size+size;
  126. if prev = nil then
  127. TinyHeapBlocks:=p^.next
  128. else
  129. prev^.next:=p^.next;
  130. concatenated:=true;
  131. break;
  132. end
  133. else if p = b^.EndAddr then
  134. begin
  135. size:=p^.size+size;
  136. if prev = nil then
  137. TinyHeapBlocks:=p^.next
  138. else
  139. prev^.next:=p^.next;
  140. concatenated:=true;
  141. break;
  142. end;
  143. prev := p;
  144. p := p^.next;
  145. end;
  146. if not concatenated then
  147. begin
  148. p := TinyHeapBlocks;
  149. prev := nil;
  150. while assigned(p) and (p^.Size < size) do
  151. begin
  152. prev := p;
  153. p := p^.Next;
  154. end;
  155. if assigned(prev) then
  156. begin
  157. b^.Next := p;
  158. prev^.Next := b;
  159. end
  160. else
  161. TinyHeapBlocks := b;
  162. end;
  163. end;
  164. until not concatenated;
  165. end;
  166. function SysTinyFreeMem(Addr: Pointer): ptruint;
  167. var
  168. sz: ptruint;
  169. begin
  170. {$ifdef DEBUG_TINY_HEAP}
  171. Writeln('SysTinyFreeMem(', ptruint(Addr), ')');
  172. {$endif DEBUG_TINY_HEAP}
  173. if addr=nil then
  174. begin
  175. result:=0;
  176. exit;
  177. end;
  178. sz := Align(FindSize(addr)+SizeOf(TTinyHeapMemBlockSize), sizeof(pointer));
  179. InternalTinyFreeMem(@PTinyHeapMemBlockSize(addr)[-1], sz);
  180. result := sz;
  181. end;
  182. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  183. begin
  184. result := SysTinyFreeMem(addr);
  185. end;
  186. function SysTinyMemSize(p: pointer): ptruint;
  187. begin
  188. result := findsize(p);
  189. end;
  190. function SysTinyAllocMem(size: ptruint): pointer;
  191. begin
  192. result := SysTinyGetMem(size);
  193. if result<>nil then
  194. FillChar(result^,SysTinyMemSize(result),0);
  195. end;
  196. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  197. var
  198. sz: ptruint;
  199. begin
  200. {$ifdef DEBUG_TINY_HEAP}
  201. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  202. {$endif DEBUG_TINY_HEAP}
  203. if size=0 then
  204. result := nil
  205. else
  206. result := AllocMem(size);
  207. if result <> nil then
  208. begin
  209. if p <> nil then
  210. begin
  211. sz := FindSize(p);
  212. if sz > size then
  213. sz := size;
  214. move(pbyte(p)^, pbyte(result)^, sz);
  215. end;
  216. end;
  217. SysTinyFreeMem(p);
  218. p := result;
  219. {$ifdef DEBUG_TINY_HEAP}
  220. Writeln(ptruint(result));
  221. {$endif DEBUG_TINY_HEAP}
  222. end;
  223. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  224. begin
  225. {$ifdef DEBUG_TINY_HEAP}
  226. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  227. {$endif DEBUG_TINY_HEAP}
  228. if (ptruint(AAddress) and 1) <> 0 then
  229. begin
  230. Inc(AAddress);
  231. Dec(ASize);
  232. end;
  233. if (ASize and 1) <> 0 then
  234. Dec(ASize);
  235. PTinyHeapMemBlockSize(AAddress)^ := ASize - SizeOf(TTinyHeapMemBlockSize);
  236. FreeMem(Pointer(PTinyHeapMemBlockSize(AAddress) + 1), ASize - SizeOf(TTinyHeapMemBlockSize));
  237. end;
  238. const
  239. TinyHeapMemoryManager: TMemoryManager = (
  240. NeedLock: false; // Obsolete
  241. GetMem: @SysTinyGetMem;
  242. FreeMem: @SysTinyFreeMem;
  243. FreeMemSize: @SysTinyFreeMemSize;
  244. AllocMem: @SysTinyAllocMem;
  245. ReAllocMem: @SysTinyReAllocMem;
  246. MemSize: @SysTinyMemSize;
  247. InitThread: nil;
  248. DoneThread: nil;
  249. RelocateHeap: nil;
  250. GetHeapStatus: nil;
  251. GetFPCHeapStatus: nil;
  252. );