tinyheap.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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. { The heap, implemented here is TP7-compatible in the i8086 far data memory
  12. models. It's basically a linked list of free blocks, which are kept ordered by
  13. start address. The FreeList variable points to the start of the list. Each
  14. free block, except the last one, contains a TTinyHeapBlock structure, which
  15. holds the block size and a pointer to the next free block. The HeapPtr
  16. variable points to the last free block, indicating the end of the list. The
  17. last block is special in that it doesn't contain a TTinyHeapBlock structure.
  18. Instead its size is determined by the pointer difference (HeapEnd-HeapPtr).
  19. It *can* become zero sized, when all the memory inside of it is allocated, in
  20. which case, HeapPtr will become equal to HeapEnd. }
  21. {$ifdef FPC_TINYHEAP_HUGE}
  22. {$HugePointerArithmeticNormalization On}
  23. {$HugePointerComparisonNormalization On}
  24. {$endif FPC_TINYHEAP_HUGE}
  25. type
  26. { TTinyHeapMemBlockSize holds the size of an *allocated* memory block,
  27. and is written at position:
  28. memblockstart-sizeof(TTinyHeapMemBlockSize) }
  29. PTinyHeapMemBlockSize = ^TTinyHeapMemBlockSize; {$ifdef FPC_TINYHEAP_HUGE}huge;{$endif}
  30. TTinyHeapMemBlockSize = PtrUInt;
  31. { TTinyHeapFreeBlockSize holds the size of a *free* memory block, as a
  32. part of the TTinyHeapBlock structure }
  33. {$ifdef FPC_TINYHEAP_HUGE}
  34. TTinyHeapFreeBlockSize = record
  35. OfsSize: Word;
  36. SegSize: Word;
  37. end;
  38. {$else FPC_TINYHEAP_HUGE}
  39. TTinyHeapFreeBlockSize = PtrUInt;
  40. {$endif FPC_TINYHEAP_HUGE}
  41. TTinyHeapPointerArithmeticType = ^Byte; {$ifdef FPC_TINYHEAP_HUGE}huge;{$endif}
  42. PTinyHeapBlock = ^TTinyHeapBlock;
  43. TTinyHeapBlock = record
  44. Next: PTinyHeapBlock;
  45. Size: TTinyHeapFreeBlockSize;
  46. end;
  47. const
  48. TinyHeapMinBlock = sizeof(TTinyHeapBlock);
  49. TinyHeapMaxBlock = High(ptruint) - sizeof(TTinyHeapBlock) - sizeof(TTinyHeapMemBlockSize);
  50. TinyHeapAllocGranularity = sizeof(TTinyHeapBlock);
  51. procedure RegisterTinyHeapBlock(AAddress: Pointer; ASize:{$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif}); forward;
  52. function EncodeTinyHeapFreeBlockSize(Size: PtrUInt): TTinyHeapFreeBlockSize; {$ifndef FPC_TINYHEAP_HUGE} inline; {$endif}
  53. begin
  54. {$ifdef FPC_TINYHEAP_HUGE}
  55. EncodeTinyHeapFreeBlockSize.OfsSize := Size and 15;
  56. EncodeTinyHeapFreeBlockSize.SegSize := Size shr 4;
  57. {$else FPC_TINYHEAP_HUGE}
  58. EncodeTinyHeapFreeBlockSize := Size;
  59. {$endif FPC_TINYHEAP_HUGE}
  60. end;
  61. function DecodeTinyHeapFreeBlockSize(Size: TTinyHeapFreeBlockSize): PtrUInt; {$ifndef FPC_TINYHEAP_HUGE} inline; {$endif}
  62. begin
  63. {$ifdef FPC_TINYHEAP_HUGE}
  64. DecodeTinyHeapFreeBlockSize := (PtrUInt(Size.SegSize) shl 4) + Size.OfsSize;
  65. {$else FPC_TINYHEAP_HUGE}
  66. DecodeTinyHeapFreeBlockSize := Size;
  67. {$endif FPC_TINYHEAP_HUGE}
  68. end;
  69. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt); forward;
  70. function FindSize(p: pointer): TTinyHeapMemBlockSize;
  71. begin
  72. FindSize := PTinyHeapMemBlockSize(p)[-1];
  73. end;
  74. function SysGetMem(Size: ptruint): pointer;
  75. var
  76. p, prev, p2: PTinyHeapBlock;
  77. AllocSize, RestSize: ptruint;
  78. begin
  79. {$ifdef DEBUG_TINY_HEAP}
  80. Write('SysGetMem(', Size, ')=');
  81. {$endif DEBUG_TINY_HEAP}
  82. if size>TinyHeapMaxBlock then
  83. HandleError(203);
  84. AllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  85. p := FreeList;
  86. prev := nil;
  87. while (p<>HeapPtr) and (DecodeTinyHeapFreeBlockSize(p^.Size) < AllocSize) do
  88. begin
  89. prev := p;
  90. p := p^.Next;
  91. end;
  92. if p<>HeapPtr then
  93. begin
  94. result := @PTinyHeapMemBlockSize(p)[1];
  95. if DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize >= TinyHeapMinBlock then
  96. RestSize := DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize
  97. else
  98. begin
  99. AllocSize := DecodeTinyHeapFreeBlockSize(p^.Size);
  100. RestSize := 0;
  101. end;
  102. if RestSize > 0 then
  103. begin
  104. p2 := pointer(TTinyHeapPointerArithmeticType(p)+AllocSize);
  105. p2^.Next := p^.Next;
  106. p2^.Size := EncodeTinyHeapFreeBlockSize(RestSize);
  107. if prev = nil then
  108. FreeList := p2
  109. else
  110. prev^.next := p2;
  111. end
  112. else
  113. begin
  114. if prev = nil then
  115. FreeList := p^.Next
  116. else
  117. prev^.next := p^.next;
  118. end;
  119. PTinyHeapMemBlockSize(p)^ := size;
  120. end
  121. else
  122. begin
  123. { p=HeapPtr }
  124. if PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr))<AllocSize then
  125. begin
  126. { align to 16 bytes }
  127. AllocSize:= (AllocSize + $f) and (not $f);
  128. p:=SysOSAlloc(AllocSize);
  129. if assigned(p) then
  130. begin
  131. { This needs toi be fixed because
  132. HeapEnd and HeapSize are not updated correctly
  133. if p > HeapPtr then
  134. begin
  135. prev:=HeapPtr;
  136. HeapPtr:=p;
  137. end
  138. else }
  139. begin
  140. {$ifdef DEBUG_TINY_HEAP}
  141. Writeln('SysAlloc returned: ',HexStr(p));
  142. {$endif DEBUG_TINY_HEAP}
  143. RegisterTinyHeapBlock(p,AllocSize);
  144. { Recursive call }
  145. SysGetMem:=SysGetMem(Size);
  146. exit;
  147. end;
  148. end
  149. else
  150. begin
  151. if ReturnNilIfGrowHeapFails then
  152. begin
  153. Result := nil;
  154. exit;
  155. end
  156. else
  157. HandleError(203);
  158. end;
  159. end;
  160. result := @PTinyHeapMemBlockSize(HeapPtr)[1];
  161. PTinyHeapMemBlockSize(HeapPtr)^ := size;
  162. HeapPtr := pointer(TTinyHeapPointerArithmeticType(HeapPtr)+AllocSize);
  163. if prev = nil then
  164. FreeList := HeapPtr
  165. else
  166. prev^.next := HeapPtr;
  167. end;
  168. {$ifdef DEBUG_TINY_HEAP}
  169. Writeln(HexStr(Result));
  170. {$endif DEBUG_TINY_HEAP}
  171. end;
  172. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  173. var
  174. mem: Pointer;
  175. memp: ptruint;
  176. begin
  177. if alignment <= sizeof(pointer) then
  178. result := GetMem(size)
  179. else
  180. begin
  181. mem := GetMem(Size+Alignment-1);
  182. memp := align(ptruint(mem), Alignment);
  183. InternalTinyFreeMem(mem, TTinyHeapPointerArithmeticType(memp)-TTinyHeapPointerArithmeticType(mem));
  184. result := pointer(memp);
  185. end;
  186. end;
  187. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt);
  188. var
  189. p, prev: PTinyHeapBlock;
  190. begin
  191. p := FreeList;
  192. prev := nil;
  193. while (p<>HeapPtr) and (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(Addr)) do
  194. begin
  195. prev := p;
  196. p := p^.Next;
  197. end;
  198. { join with previous block? }
  199. if assigned(prev) and ((TTinyHeapPointerArithmeticType(prev)+DecodeTinyHeapFreeBlockSize(prev^.Size)) = TTinyHeapPointerArithmeticType(Addr)) then
  200. begin
  201. Addr:=prev;
  202. Size:=DecodeTinyHeapFreeBlockSize(prev^.size)+Size;
  203. end
  204. else
  205. if assigned(prev) then
  206. prev^.Next := Addr
  207. else
  208. FreeList := Addr;
  209. { join with next block? }
  210. if TTinyHeapPointerArithmeticType(p)=(TTinyHeapPointerArithmeticType(Addr)+Size) then
  211. begin
  212. if p=HeapPtr then
  213. HeapPtr:=Addr
  214. else
  215. begin
  216. PTinyHeapBlock(Addr)^.Next:=p^.Next;
  217. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size+DecodeTinyHeapFreeBlockSize(p^.Size));
  218. end;
  219. end
  220. else
  221. begin
  222. PTinyHeapBlock(Addr)^.Next:=p;
  223. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size);
  224. end;
  225. end;
  226. function SysFreeMem(p: Pointer): ptruint;
  227. var
  228. sz: ptruint;
  229. begin
  230. {$ifdef DEBUG_TINY_HEAP}
  231. Writeln('SysFreeMem(', HexStr(p), ')');
  232. {$endif DEBUG_TINY_HEAP}
  233. if p=nil then
  234. begin
  235. result:=0;
  236. exit;
  237. end;
  238. if (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  239. (TTinyHeapPointerArithmeticType(p) >= TTinyHeapPointerArithmeticType(HeapPtr)) then
  240. HandleError(204);
  241. sz := Align(FindSize(p)+SizeOf(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  242. InternalTinyFreeMem(@PTinyHeapMemBlockSize(p)[-1], sz);
  243. result := sz;
  244. end;
  245. function SysFreeMemSize(p: Pointer; Size: Ptruint): ptruint;
  246. begin
  247. result := SysFreeMem(p);
  248. end;
  249. function SysMemSize(p: pointer): ptruint;
  250. begin
  251. result := findsize(p);
  252. end;
  253. function SysTryResizeMem(var p: pointer; size: ptruint) : boolean;
  254. begin
  255. result := false;
  256. end;
  257. function SysAllocMem(size: ptruint): pointer;
  258. begin
  259. result := SysGetMem(size);
  260. if result<>nil then
  261. FillChar(result^,SysMemSize(result),0);
  262. end;
  263. function SysReAllocMem(var p: pointer; size: ptruint):pointer;
  264. var
  265. oldsize, OldAllocSize, NewAllocSize: ptruint;
  266. after_block, before_block, before_before_block: PTinyHeapBlock;
  267. after_block_size, before_block_size: PtrUInt;
  268. new_after_block: PTinyHeapBlock;
  269. begin
  270. {$ifdef DEBUG_TINY_HEAP}
  271. Write('SysReAllocMem(', HexStr(p), ',', size, ')=');
  272. {$endif DEBUG_TINY_HEAP}
  273. if size=0 then
  274. begin
  275. SysFreeMem(p);
  276. result := nil;
  277. p := nil;
  278. end
  279. else if p=nil then
  280. begin
  281. result := AllocMem(size);
  282. p := result;
  283. end
  284. else
  285. begin
  286. if (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  287. (TTinyHeapPointerArithmeticType(p) >= TTinyHeapPointerArithmeticType(HeapPtr)) then
  288. HandleError(204);
  289. if size>TinyHeapMaxBlock then
  290. HandleError(203);
  291. oldsize := FindSize(p);
  292. OldAllocSize := align(oldsize+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  293. NewAllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  294. if OldAllocSize = NewAllocSize then
  295. begin
  296. { old and new size are the same after alignment, so the memory block is already allocated }
  297. { we just need to update the size }
  298. PTinyHeapMemBlockSize(p)[-1] := size;
  299. if size > oldsize then
  300. FillChar((TTinyHeapPointerArithmeticType(p)+oldsize)^, size-oldsize, 0);
  301. end
  302. else if OldAllocSize > NewAllocSize then
  303. begin
  304. { we're decreasing the memory block size, so we can just free the remaining memory at the end }
  305. PTinyHeapMemBlockSize(p)[-1] := size;
  306. InternalTinyFreeMem(Pointer(TTinyHeapPointerArithmeticType(p)+(NewAllocSize-PtrUInt(SizeOf(TTinyHeapMemBlockSize)))), OldAllocSize-NewAllocSize);
  307. end
  308. else
  309. begin
  310. { we're increasing the memory block size. First, find if there are free memory blocks immediately
  311. before and after our memory block. }
  312. after_block := FreeList;
  313. before_block := nil;
  314. before_before_block := nil;
  315. while (after_block<>HeapPtr) and (TTinyHeapPointerArithmeticType(after_block) < TTinyHeapPointerArithmeticType(p)) do
  316. begin
  317. before_before_block := before_block;
  318. before_block := after_block;
  319. after_block := after_block^.Next;
  320. end;
  321. { is after_block immediately after our block? }
  322. if after_block=Pointer(TTinyHeapPointerArithmeticType(p)+(OldAllocSize-PtrUInt(SizeOf(TTinyHeapMemBlockSize)))) then
  323. begin
  324. if after_block = HeapPtr then
  325. after_block_size := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr))
  326. else
  327. after_block_size := DecodeTinyHeapFreeBlockSize(after_block^.size);
  328. end
  329. else
  330. after_block_size := 0;
  331. { is there enough room after the block? }
  332. if (OldAllocSize+after_block_size)>=NewAllocSize then
  333. begin
  334. if after_block = HeapPtr then
  335. begin
  336. HeapPtr:=Pointer(TTinyHeapPointerArithmeticType(HeapPtr)+(NewAllocSize-OldAllocSize));
  337. if assigned(before_block) then
  338. before_block^.Next := HeapPtr
  339. else
  340. FreeList := HeapPtr;
  341. end
  342. else
  343. begin
  344. if (NewAllocSize-OldAllocSize)=after_block_size then
  345. begin
  346. if assigned(before_block) then
  347. before_block^.Next := after_block^.Next
  348. else
  349. FreeList := after_block^.Next;
  350. end
  351. else
  352. begin
  353. new_after_block := PTinyHeapBlock(TTinyHeapPointerArithmeticType(after_block)+(NewAllocSize-OldAllocSize));
  354. new_after_block^.Next:=after_block^.Next;
  355. new_after_block^.Size:=EncodeTinyHeapFreeBlockSize(after_block_size-(NewAllocSize-OldAllocSize));
  356. if assigned(before_block) then
  357. before_block^.Next := new_after_block
  358. else
  359. FreeList := new_after_block;
  360. end;
  361. end;
  362. PTinyHeapMemBlockSize(p)[-1] := size;
  363. FillChar((TTinyHeapPointerArithmeticType(p)+oldsize)^, size-oldsize, 0);
  364. end
  365. else
  366. begin
  367. { is before_block immediately before our block? }
  368. if assigned(before_block) and (Pointer(TTinyHeapPointerArithmeticType(before_block)+DecodeTinyHeapFreeBlockSize(before_block^.Size))=Pointer(TTinyHeapPointerArithmeticType(p)-SizeOf(TTinyHeapMemBlockSize))) then
  369. before_block_size := DecodeTinyHeapFreeBlockSize(before_block^.Size)
  370. else
  371. before_block_size := 0;
  372. { if there's enough space, we can slide our current block back and reclaim before_block }
  373. if (before_block_size<NewAllocSize) and ((before_block_size+OldAllocSize+after_block_size)>=NewAllocSize) and
  374. { todo: implement this also for after_block_size>0 }
  375. (after_block_size>0) then
  376. begin
  377. if (before_block_size+OldAllocSize+after_block_size)=NewAllocSize then
  378. begin
  379. if after_block=HeapPtr then
  380. begin
  381. HeapPtr := HeapEnd;
  382. if assigned(before_before_block) then
  383. before_before_block^.Next := HeapPtr
  384. else
  385. FreeList := HeapPtr;
  386. end
  387. else
  388. if assigned(before_before_block) then
  389. before_before_block^.Next := after_block^.Next
  390. else
  391. FreeList := after_block^.Next;
  392. end;
  393. Result := Pointer(TTinyHeapPointerArithmeticType(before_block)+SizeOf(TTinyHeapMemBlockSize));
  394. Move(p^, Result^, oldsize);
  395. PTinyHeapMemBlockSize(before_block)^ := size;
  396. if (before_block_size+OldAllocSize+after_block_size)>NewAllocSize then
  397. begin
  398. new_after_block := PTinyHeapBlock(TTinyHeapPointerArithmeticType(before_block)+NewAllocSize);
  399. new_after_block^.Next:=after_block^.Next;
  400. new_after_block^.Size:=EncodeTinyHeapFreeBlockSize(before_block_size+after_block_size-(NewAllocSize-OldAllocSize));
  401. if assigned(before_before_block) then
  402. before_before_block^.Next := new_after_block
  403. else
  404. FreeList := new_after_block;
  405. end;
  406. FillChar((TTinyHeapPointerArithmeticType(Result)+oldsize)^, size-oldsize, 0);
  407. p := Result;
  408. end
  409. else
  410. begin
  411. result := AllocMem(size);
  412. if result <> nil then
  413. begin
  414. if oldsize > size then
  415. oldsize := size;
  416. move(pbyte(p)^, pbyte(result)^, oldsize);
  417. end;
  418. SysFreeMem(p);
  419. p := result;
  420. end;
  421. end;
  422. end;
  423. end;
  424. {$ifdef DEBUG_TINY_HEAP}
  425. Writeln(HexStr(result));
  426. {$endif DEBUG_TINY_HEAP}
  427. end;
  428. function MemAvail: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif};
  429. var
  430. p: PTinyHeapBlock;
  431. begin
  432. MemAvail := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  433. if MemAvail > 0 then
  434. Dec(MemAvail, SizeOf(TTinyHeapMemBlockSize));
  435. p := FreeList;
  436. while p <> HeapPtr do
  437. begin
  438. Inc(MemAvail, DecodeTinyHeapFreeBlockSize(p^.Size)-SizeOf(TTinyHeapMemBlockSize));
  439. p := p^.Next;
  440. end;
  441. end;
  442. function MaxAvail: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif};
  443. var
  444. p: PTinyHeapBlock;
  445. begin
  446. MaxAvail := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  447. p := FreeList;
  448. while p <> HeapPtr do
  449. begin
  450. if DecodeTinyHeapFreeBlockSize(p^.Size) > MaxAvail then
  451. MaxAvail := DecodeTinyHeapFreeBlockSize(p^.Size);
  452. p := p^.Next;
  453. end;
  454. if MaxAvail > 0 then
  455. Dec(MaxAvail, SizeOf(TTinyHeapMemBlockSize));
  456. end;
  457. procedure Mark(var p: Pointer);
  458. begin
  459. p := HeapPtr;
  460. end;
  461. procedure Release(var p: Pointer);
  462. begin
  463. HeapPtr := p;
  464. FreeList := p;
  465. end;
  466. procedure InternalTinyAlign(var AAddress: Pointer; var ASize: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif});
  467. var
  468. alignment_inc: smallint;
  469. begin
  470. alignment_inc := TTinyHeapPointerArithmeticType(align(AAddress,TinyHeapAllocGranularity))-TTinyHeapPointerArithmeticType(AAddress);
  471. Inc(AAddress,alignment_inc);
  472. Dec(ASize,alignment_inc);
  473. Dec(ASize,ASize mod TinyHeapAllocGranularity);
  474. end;
  475. { Strongly simplified version of RegisterTinyHeapBlock, which can be used when
  476. the heap is only a single contiguous memory block. If you want to add
  477. multiple blocks to the heap, you should use RegisterTinyHeapBlock instead. }
  478. procedure RegisterTinyHeapBlock_Simple(AAddress: Pointer; ASize:{$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif});
  479. begin
  480. {$ifdef DEBUG_TINY_HEAP}
  481. Writeln('RegisterTinyHeapBlock_Simple(', HexStr(AAddress), ',', ASize, ')');
  482. {$endif DEBUG_TINY_HEAP}
  483. InternalTinyAlign(AAddress, ASize);
  484. HeapSize:=HeapSize + ASize;
  485. HeapOrg:=AAddress;
  486. HeapPtr:=AAddress;
  487. FreeList:=AAddress;
  488. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  489. end;
  490. { Strongly simplified version of RegisterTinyHeapBlock, which can be used when
  491. the heap is only a single contiguous memory block and the address and size
  492. are already aligned on a TinyHeapAllocGranularity boundary. }
  493. procedure RegisterTinyHeapBlock_Simple_Prealigned(AAddress: Pointer; ASize: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif});
  494. begin
  495. {$ifdef DEBUG_TINY_HEAP}
  496. Writeln('RegisterTinyHeapBlock_Simple_Prealigned(', HexStr(AAddress), ',', ASize, ')');
  497. {$endif DEBUG_TINY_HEAP}
  498. HeapOrg:=AAddress;
  499. HeapPtr:=AAddress;
  500. FreeList:=AAddress;
  501. HeapSize:=HeapSize + ASize;
  502. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  503. end;
  504. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif});
  505. var
  506. alignment_inc: smallint;
  507. p: PTinyHeapBlock;
  508. begin
  509. {$ifdef DEBUG_TINY_HEAP}
  510. Writeln('RegisterTinyHeapBlock(', HexStr(AAddress), ',', ASize, ')');
  511. {$endif DEBUG_TINY_HEAP}
  512. InternalTinyAlign(AAddress, ASize);
  513. HeapSize:=HeapSize + ASize;
  514. if HeapOrg=nil then
  515. begin
  516. HeapOrg:=AAddress;
  517. HeapPtr:=AAddress;
  518. FreeList:=AAddress;
  519. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  520. end
  521. else
  522. begin
  523. if (TTinyHeapPointerArithmeticType(HeapOrg) > TTinyHeapPointerArithmeticType(AAddress)) then
  524. HeapOrg:=AAddress;
  525. if TTinyHeapPointerArithmeticType(AAddress) > TTinyHeapPointerArithmeticType(HeapEnd) then
  526. begin
  527. if TTinyHeapPointerArithmeticType(HeapPtr) = TTinyHeapPointerArithmeticType(HeapEnd) then
  528. begin
  529. if FreeList=HeapPtr then
  530. FreeList:=AAddress
  531. else
  532. begin
  533. p:=FreeList;
  534. while p^.Next<>HeapPtr do
  535. p:=p^.Next;
  536. PTinyHeapBlock(p)^.Next:=AAddress;
  537. end;
  538. end
  539. else
  540. begin
  541. PTinyHeapBlock(HeapPtr)^.Size:=EncodeTinyHeapFreeBlockSize(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  542. PTinyHeapBlock(HeapPtr)^.Next:=AAddress;
  543. end;
  544. HeapPtr:=AAddress;
  545. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  546. end
  547. else if TTinyHeapPointerArithmeticType(AAddress) = TTinyHeapPointerArithmeticType(HeapEnd) then
  548. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize)
  549. else
  550. InternalTinyFreeMem(AAddress, ASize);
  551. end;
  552. end;
  553. function SysGetFPCHeapStatus : TFPCHeapStatus;
  554. {
  555. TFPCHeapStatus = record
  556. MaxHeapSize,
  557. MaxHeapUsed,
  558. CurrHeapSize,
  559. CurrHeapUsed,
  560. CurrHeapFree : ptruint;
  561. end;
  562. }
  563. begin
  564. SysGetFPCHeapStatus.MaxHeapSize:=MaxAvail;
  565. { How can we compute this? }
  566. SysGetFPCHeapStatus.MaxHeapUsed:=0;
  567. SysGetFPCHeapStatus.CurrHeapFree:=MemAvail;
  568. SysGetFPCHeapStatus.CurrHeapUsed:=HeapSize-SysGetFPCHeapStatus.CurrHeapFree;
  569. SysGetFPCHeapStatus.CurrHeapSize:=HeapSize;
  570. end;
  571. function SysGetHeapStatus : THeapStatus;
  572. begin
  573. SysGetHeapStatus.TotalAddrSpace:= HeapSize;
  574. SysGetHeapStatus.TotalUncommitted:= 0;
  575. SysGetHeapStatus.TotalCommitted:= 0;
  576. SysGetHeapStatus.TotalAllocated:= HeapSize-MemAvail;
  577. SysGetHeapStatus.TotalFree:= MemAvail;
  578. SysGetHeapStatus.FreeSmall:= 0;
  579. SysGetHeapStatus.FreeBig:= 0;
  580. SysGetHeapStatus.Unused:= 0;
  581. SysGetHeapStatus.Overhead:= 0;
  582. SysGetHeapStatus.HeapErrorCode:= 0;
  583. end;
  584. procedure FinalizeHeap;
  585. begin
  586. end;