tinyheap.inc 7.2 KB

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