tinyheap.inc 8.4 KB

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