tinyheap.inc 7.7 KB

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