tinyheap.inc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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 = 16;
  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. InternalTinyFreeMem(pointer(ptruint(p)+AllocSize), RestSize);
  59. end
  60. else
  61. Result := nil;
  62. {$ifdef DEBUG_TINY_HEAP}
  63. Writeln(ptruint(Result));
  64. {$endif DEBUG_TINY_HEAP}
  65. end;
  66. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  67. var
  68. mem: Pointer;
  69. memp: ptruint;
  70. begin
  71. if alignment <= sizeof(pointer) then
  72. result := GetMem(size)
  73. else
  74. begin
  75. mem := GetMem(Size+Alignment-1);
  76. memp := align(ptruint(mem), Alignment);
  77. InternalTinyFreeMem(mem, ptruint(memp)-ptruint(mem));
  78. result := pointer(memp);
  79. end;
  80. end;
  81. procedure InternalTinyFreeMem(Addr: Pointer; Size: ptruint);
  82. var
  83. b, p, prev: PTinyHeapBlock;
  84. concatenated: boolean;
  85. begin
  86. concatenated := true;
  87. while concatenated do
  88. begin
  89. concatenated := false;
  90. b := addr;
  91. b^.Next := TinyHeapBlocks;
  92. b^.Size := Size;
  93. b^.EndAddr := pointer(ptruint(addr)+size);
  94. if TinyHeapBlocks = nil then
  95. TinyHeapBlocks := b
  96. else
  97. begin
  98. p := TinyHeapBlocks;
  99. prev := nil;
  100. while assigned(p) do
  101. begin
  102. if p^.EndAddr = addr then
  103. begin
  104. addr:=p;
  105. size:=p^.size+size;
  106. if prev = nil then
  107. TinyHeapBlocks:=p^.next
  108. else
  109. prev^.next:=p^.next;
  110. concatenated:=true;
  111. break;
  112. end
  113. else if p = b^.EndAddr then
  114. begin
  115. size:=p^.size+size;
  116. if prev = nil then
  117. TinyHeapBlocks:=p^.next
  118. else
  119. prev^.next:=p^.next;
  120. concatenated:=true;
  121. break;
  122. end;
  123. prev := p;
  124. p := p^.next;
  125. end;
  126. if not concatenated then
  127. begin
  128. p := TinyHeapBlocks;
  129. prev := nil;
  130. while assigned(p) and (p^.Size < size) do
  131. begin
  132. prev := p;
  133. p := p^.Next;
  134. end;
  135. if assigned(prev) then
  136. begin
  137. b^.Next := p;
  138. prev^.Next := b;
  139. end
  140. else
  141. TinyHeapBlocks := b;
  142. end;
  143. end;
  144. end;
  145. end;
  146. function SysTinyFreeMem(Addr: Pointer): ptruint;
  147. var
  148. sz: ptruint;
  149. begin
  150. {$ifdef DEBUG_TINY_HEAP}
  151. Writeln('SysTinyFreeMem(', ptruint(Addr), ')');
  152. {$endif DEBUG_TINY_HEAP}
  153. sz := Align(FindSize(addr)+SizeOf(ptruint), sizeof(pointer));
  154. InternalTinyFreeMem(@pptruint(addr)[-1], sz);
  155. result := sz;
  156. end;
  157. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  158. begin
  159. result := SysTinyFreeMem(addr);
  160. end;
  161. function SysTinyMemSize(p: pointer): ptruint;
  162. begin
  163. result := findsize(p);
  164. end;
  165. function SysTinyAllocMem(size: ptruint): pointer;
  166. begin
  167. result := SysTinyGetMem(size);
  168. if result<>nil then
  169. FillChar(result^,SysTinyMemSize(result),0);
  170. end;
  171. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  172. var
  173. sz: ptruint;
  174. begin
  175. {$ifdef DEBUG_TINY_HEAP}
  176. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  177. {$endif DEBUG_TINY_HEAP}
  178. result := AllocMem(size);
  179. if result <> nil then
  180. begin
  181. if p <> nil then
  182. begin
  183. sz := FindSize(p);
  184. if sz > size then
  185. sz := size;
  186. move(pbyte(p)^, pbyte(result)^, sz);
  187. end;
  188. end;
  189. SysTinyFreeMem(p);
  190. p := result;
  191. {$ifdef DEBUG_TINY_HEAP}
  192. Writeln(ptruint(result));
  193. {$endif DEBUG_TINY_HEAP}
  194. end;
  195. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  196. begin
  197. {$ifdef DEBUG_TINY_HEAP}
  198. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  199. {$endif DEBUG_TINY_HEAP}
  200. if (ptruint(AAddress) and 1) <> 0 then
  201. begin
  202. Inc(AAddress);
  203. Dec(ASize);
  204. end;
  205. if (ASize and 1) <> 0 then
  206. Dec(ASize);
  207. pptruint(AAddress)^ := ASize - SizeOf(ptruint);
  208. FreeMem(pptruint(AAddress) + 1, ASize - SizeOf(ptruint));
  209. end;
  210. const
  211. TinyHeapMemoryManager: TMemoryManager = (
  212. NeedLock: false; // Obsolete
  213. GetMem: @SysTinyGetMem;
  214. FreeMem: @SysTinyFreeMem;
  215. FreeMemSize: @SysTinyFreeMemSize;
  216. AllocMem: @SysTinyAllocMem;
  217. ReAllocMem: @SysTinyReAllocMem;
  218. MemSize: @SysTinyMemSize;
  219. InitThread: nil;
  220. DoneThread: nil;
  221. RelocateHeap: nil;
  222. GetHeapStatus: nil;
  223. GetFPCHeapStatus: nil;
  224. );