tinyheap.inc 7.3 KB

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