tinyheap.inc 7.3 KB

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