tinyheap.inc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. {$ifdef FPC_HEAP_HUGE}
  29. TTinyHeapFreeBlockSize = record
  30. OfsSize: Word;
  31. SegSize: Word;
  32. end;
  33. {$else FPC_HEAP_HUGE}
  34. TTinyHeapFreeBlockSize = PtrUInt;
  35. {$endif FPC_HEAP_HUGE}
  36. TTinyHeapPointerArithmeticType = ^Byte; {$ifdef FPC_HEAP_HUGE}huge;{$endif}
  37. PTinyHeapBlock = ^TTinyHeapBlock;
  38. TTinyHeapBlock = record
  39. Next: PTinyHeapBlock;
  40. Size: TTinyHeapFreeBlockSize;
  41. end;
  42. const
  43. TinyHeapMinBlock = sizeof(TTinyHeapBlock);
  44. TinyHeapAllocGranularity = sizeof(TTinyHeapBlock);
  45. var
  46. FreeList: PTinyHeapBlock = nil;
  47. function EncodeTinyHeapFreeBlockSize(Size: PtrUInt): TTinyHeapFreeBlockSize; inline;
  48. begin
  49. {$ifdef FPC_HEAP_HUGE}
  50. EncodeTinyHeapFreeBlockSize.OfsSize := Size and 15;
  51. EncodeTinyHeapFreeBlockSize.SegSize := Size shr 4;
  52. {$else FPC_HEAP_HUGE}
  53. EncodeTinyHeapFreeBlockSize := Size;
  54. {$endif FPC_HEAP_HUGE}
  55. end;
  56. function DecodeTinyHeapFreeBlockSize(Size: TTinyHeapFreeBlockSize): PtrUInt; inline;
  57. begin
  58. {$ifdef FPC_HEAP_HUGE}
  59. DecodeTinyHeapFreeBlockSize := (PtrUInt(Size.SegSize) shl 4) + Size.OfsSize;
  60. {$else FPC_HEAP_HUGE}
  61. DecodeTinyHeapFreeBlockSize := Size;
  62. {$endif FPC_HEAP_HUGE}
  63. end;
  64. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt); forward;
  65. function FindSize(p: pointer): TTinyHeapMemBlockSize;
  66. begin
  67. FindSize := PTinyHeapMemBlockSize(p)[-1];
  68. end;
  69. function SysTinyGetMem(Size: ptruint): pointer;
  70. var
  71. p, prev, p2: PTinyHeapBlock;
  72. AllocSize, RestSize: ptruint;
  73. begin
  74. {$ifdef DEBUG_TINY_HEAP}
  75. Write('SysTinyGetMem(', Size, ')=');
  76. {$endif DEBUG_TINY_HEAP}
  77. AllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  78. p := FreeList;
  79. prev := nil;
  80. while assigned(p) and (DecodeTinyHeapFreeBlockSize(p^.Size) < AllocSize) do
  81. begin
  82. prev := p;
  83. p := p^.Next;
  84. end;
  85. if assigned(p) then
  86. begin
  87. result := @PTinyHeapMemBlockSize(p)[1];
  88. if DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize >= TinyHeapMinBlock then
  89. RestSize := DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize
  90. else
  91. begin
  92. AllocSize := DecodeTinyHeapFreeBlockSize(p^.Size);
  93. RestSize := 0;
  94. end;
  95. if RestSize > 0 then
  96. begin
  97. p2 := pointer(TTinyHeapPointerArithmeticType(p)+AllocSize);
  98. p2^.Next := p^.Next;
  99. p2^.Size := EncodeTinyHeapFreeBlockSize(RestSize);
  100. if prev = nil then
  101. FreeList := p2
  102. else
  103. prev^.next := p2;
  104. end
  105. else
  106. begin
  107. if prev = nil then
  108. FreeList := p^.Next
  109. else
  110. prev^.next := p^.next;
  111. end;
  112. PTinyHeapMemBlockSize(p)^ := size;
  113. end
  114. else
  115. if ReturnNilIfGrowHeapFails then
  116. Result := nil
  117. else
  118. HandleError(203);
  119. {$ifdef DEBUG_TINY_HEAP}
  120. Writeln(ptruint(Result));
  121. {$endif DEBUG_TINY_HEAP}
  122. end;
  123. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  124. var
  125. mem: Pointer;
  126. memp: ptruint;
  127. begin
  128. if alignment <= sizeof(pointer) then
  129. result := GetMem(size)
  130. else
  131. begin
  132. mem := GetMem(Size+Alignment-1);
  133. memp := align(ptruint(mem), Alignment);
  134. InternalTinyFreeMem(mem, TTinyHeapPointerArithmeticType(memp)-TTinyHeapPointerArithmeticType(mem));
  135. result := pointer(memp);
  136. end;
  137. end;
  138. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt);
  139. var
  140. b, p, prev: PTinyHeapBlock;
  141. EndAddr: Pointer;
  142. concatenated: boolean;
  143. begin
  144. repeat
  145. concatenated := false;
  146. b := addr;
  147. b^.Next := FreeList;
  148. b^.Size := EncodeTinyHeapFreeBlockSize(Size);
  149. EndAddr := pointer(TTinyHeapPointerArithmeticType(addr)+size);
  150. if FreeList = nil then
  151. FreeList := b
  152. else
  153. begin
  154. p := FreeList;
  155. prev := nil;
  156. while assigned(p) do
  157. begin
  158. if (TTinyHeapPointerArithmeticType(p)+DecodeTinyHeapFreeBlockSize(p^.Size)) = TTinyHeapPointerArithmeticType(Addr) then
  159. begin
  160. addr:=p;
  161. size:=DecodeTinyHeapFreeBlockSize(p^.size)+size;
  162. if prev = nil then
  163. FreeList:=p^.next
  164. else
  165. prev^.next:=p^.next;
  166. concatenated:=true;
  167. break;
  168. end
  169. else if p = EndAddr then
  170. begin
  171. size:=DecodeTinyHeapFreeBlockSize(p^.size)+size;
  172. if prev = nil then
  173. FreeList:=p^.next
  174. else
  175. prev^.next:=p^.next;
  176. concatenated:=true;
  177. break;
  178. end;
  179. prev := p;
  180. p := p^.next;
  181. end;
  182. if not concatenated then
  183. begin
  184. p := FreeList;
  185. prev := nil;
  186. while assigned(p) and (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(b)) do
  187. begin
  188. prev := p;
  189. p := p^.Next;
  190. end;
  191. if assigned(prev) then
  192. begin
  193. b^.Next := p;
  194. prev^.Next := b;
  195. end
  196. else
  197. FreeList := b;
  198. end;
  199. end;
  200. until not concatenated;
  201. end;
  202. function SysTinyFreeMem(Addr: Pointer): ptruint;
  203. var
  204. sz: ptruint;
  205. begin
  206. {$ifdef DEBUG_TINY_HEAP}
  207. Writeln('SysTinyFreeMem(', ptruint(Addr), ')');
  208. {$endif DEBUG_TINY_HEAP}
  209. if addr=nil then
  210. begin
  211. result:=0;
  212. exit;
  213. end;
  214. if (TTinyHeapPointerArithmeticType(addr) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  215. (TTinyHeapPointerArithmeticType(addr) >= TTinyHeapPointerArithmeticType(HeapEnd)) then
  216. HandleError(204);
  217. sz := Align(FindSize(addr)+SizeOf(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  218. InternalTinyFreeMem(@PTinyHeapMemBlockSize(addr)[-1], sz);
  219. result := sz;
  220. end;
  221. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  222. begin
  223. result := SysTinyFreeMem(addr);
  224. end;
  225. function SysTinyMemSize(p: pointer): ptruint;
  226. begin
  227. result := findsize(p);
  228. end;
  229. function SysTinyAllocMem(size: ptruint): pointer;
  230. begin
  231. result := SysTinyGetMem(size);
  232. if result<>nil then
  233. FillChar(result^,SysTinyMemSize(result),0);
  234. end;
  235. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  236. var
  237. sz: ptruint;
  238. begin
  239. {$ifdef DEBUG_TINY_HEAP}
  240. Write('SysTinyReAllocMem(', ptruint(p), ',', size, ')=');
  241. {$endif DEBUG_TINY_HEAP}
  242. if size=0 then
  243. result := nil
  244. else
  245. result := AllocMem(size);
  246. if result <> nil then
  247. begin
  248. if p <> nil then
  249. begin
  250. sz := FindSize(p);
  251. if sz > size then
  252. sz := size;
  253. move(pbyte(p)^, pbyte(result)^, sz);
  254. end;
  255. end;
  256. SysTinyFreeMem(p);
  257. p := result;
  258. {$ifdef DEBUG_TINY_HEAP}
  259. Writeln(ptruint(result));
  260. {$endif DEBUG_TINY_HEAP}
  261. end;
  262. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  263. var
  264. alignment_inc: smallint;
  265. begin
  266. {$ifdef DEBUG_TINY_HEAP}
  267. Writeln('RegisterTinyHeapBlock(', ptruint(AAddress), ',', ASize, ')');
  268. {$endif DEBUG_TINY_HEAP}
  269. alignment_inc := TTinyHeapPointerArithmeticType(align(AAddress,TinyHeapAllocGranularity))-TTinyHeapPointerArithmeticType(AAddress);
  270. Inc(AAddress,alignment_inc);
  271. Dec(ASize,alignment_inc);
  272. Dec(ASize,ASize mod TinyHeapAllocGranularity);
  273. if (HeapOrg=nil) or (TTinyHeapPointerArithmeticType(HeapOrg) > TTinyHeapPointerArithmeticType(AAddress)) then
  274. HeapOrg:=AAddress;
  275. if (HeapEnd=nil) or (TTinyHeapPointerArithmeticType(HeapEnd) < (TTinyHeapPointerArithmeticType(AAddress)+ASize)) then
  276. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  277. InternalTinyFreeMem(AAddress, ASize);
  278. end;
  279. const
  280. TinyHeapMemoryManager: TMemoryManager = (
  281. NeedLock: false; // Obsolete
  282. GetMem: @SysTinyGetMem;
  283. FreeMem: @SysTinyFreeMem;
  284. FreeMemSize: @SysTinyFreeMemSize;
  285. AllocMem: @SysTinyAllocMem;
  286. ReAllocMem: @SysTinyReAllocMem;
  287. MemSize: @SysTinyMemSize;
  288. InitThread: nil;
  289. DoneThread: nil;
  290. RelocateHeap: nil;
  291. GetHeapStatus: nil;
  292. GetFPCHeapStatus: nil;
  293. );