tinyheap.inc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. if addr=nil then
  158. begin
  159. result:=0;
  160. exit;
  161. end;
  162. sz := Align(FindSize(addr)+SizeOf(ptruint), sizeof(pointer));
  163. InternalTinyFreeMem(@pptruint(addr)[-1], sz);
  164. result := sz;
  165. end;
  166. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  167. begin
  168. result := SysTinyFreeMem(addr);
  169. end;
  170. function SysTinyMemSize(p: pointer): ptruint;
  171. begin
  172. result := findsize(p);
  173. end;
  174. function SysTinyAllocMem(size: ptruint): pointer;
  175. begin
  176. result := SysTinyGetMem(size);
  177. if result<>nil then
  178. FillChar(result^,SysTinyMemSize(result),0);
  179. end;
  180. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  181. var
  182. sz: ptruint;
  183. begin
  184. {$ifdef DEBUG_TINY_HEAP}
  185. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  186. {$endif DEBUG_TINY_HEAP}
  187. if size=0 then
  188. result := nil
  189. else
  190. result := AllocMem(size);
  191. if result <> nil then
  192. begin
  193. if p <> nil then
  194. begin
  195. sz := FindSize(p);
  196. if sz > size then
  197. sz := size;
  198. move(pbyte(p)^, pbyte(result)^, sz);
  199. end;
  200. end;
  201. SysTinyFreeMem(p);
  202. p := result;
  203. {$ifdef DEBUG_TINY_HEAP}
  204. Writeln(ptruint(result));
  205. {$endif DEBUG_TINY_HEAP}
  206. end;
  207. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  208. begin
  209. {$ifdef DEBUG_TINY_HEAP}
  210. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  211. {$endif DEBUG_TINY_HEAP}
  212. if (ptruint(AAddress) and 1) <> 0 then
  213. begin
  214. Inc(AAddress);
  215. Dec(ASize);
  216. end;
  217. if (ASize and 1) <> 0 then
  218. Dec(ASize);
  219. pptruint(AAddress)^ := ASize - SizeOf(ptruint);
  220. FreeMem(pptruint(AAddress) + 1, ASize - SizeOf(ptruint));
  221. end;
  222. const
  223. TinyHeapMemoryManager: TMemoryManager = (
  224. NeedLock: false; // Obsolete
  225. GetMem: @SysTinyGetMem;
  226. FreeMem: @SysTinyFreeMem;
  227. FreeMemSize: @SysTinyFreeMemSize;
  228. AllocMem: @SysTinyAllocMem;
  229. ReAllocMem: @SysTinyReAllocMem;
  230. MemSize: @SysTinyMemSize;
  231. InitThread: nil;
  232. DoneThread: nil;
  233. RelocateHeap: nil;
  234. GetHeapStatus: nil;
  235. GetFPCHeapStatus: nil;
  236. );