tinyheap.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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. TinyHeapAllocGranularity = sizeof(TTinyHeapBlock);
  50. function EncodeTinyHeapFreeBlockSize(Size: PtrUInt): TTinyHeapFreeBlockSize; inline;
  51. begin
  52. {$ifdef FPC_TINYHEAP_HUGE}
  53. EncodeTinyHeapFreeBlockSize.OfsSize := Size and 15;
  54. EncodeTinyHeapFreeBlockSize.SegSize := Size shr 4;
  55. {$else FPC_TINYHEAP_HUGE}
  56. EncodeTinyHeapFreeBlockSize := Size;
  57. {$endif FPC_TINYHEAP_HUGE}
  58. end;
  59. function DecodeTinyHeapFreeBlockSize(Size: TTinyHeapFreeBlockSize): PtrUInt; inline;
  60. begin
  61. {$ifdef FPC_TINYHEAP_HUGE}
  62. DecodeTinyHeapFreeBlockSize := (PtrUInt(Size.SegSize) shl 4) + Size.OfsSize;
  63. {$else FPC_TINYHEAP_HUGE}
  64. DecodeTinyHeapFreeBlockSize := Size;
  65. {$endif FPC_TINYHEAP_HUGE}
  66. end;
  67. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt); forward;
  68. function FindSize(p: pointer): TTinyHeapMemBlockSize;
  69. begin
  70. FindSize := PTinyHeapMemBlockSize(p)[-1];
  71. end;
  72. function SysTinyGetMem(Size: ptruint): pointer;
  73. var
  74. p, prev, p2: PTinyHeapBlock;
  75. AllocSize, RestSize: ptruint;
  76. begin
  77. {$ifdef DEBUG_TINY_HEAP}
  78. Write('SysTinyGetMem(', Size, ')=');
  79. {$endif DEBUG_TINY_HEAP}
  80. AllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  81. p := FreeList;
  82. prev := nil;
  83. while (p<>HeapPtr) and (DecodeTinyHeapFreeBlockSize(p^.Size) < AllocSize) do
  84. begin
  85. prev := p;
  86. p := p^.Next;
  87. end;
  88. if p<>HeapPtr then
  89. begin
  90. result := @PTinyHeapMemBlockSize(p)[1];
  91. if DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize >= TinyHeapMinBlock then
  92. RestSize := DecodeTinyHeapFreeBlockSize(p^.Size)-AllocSize
  93. else
  94. begin
  95. AllocSize := DecodeTinyHeapFreeBlockSize(p^.Size);
  96. RestSize := 0;
  97. end;
  98. if RestSize > 0 then
  99. begin
  100. p2 := pointer(TTinyHeapPointerArithmeticType(p)+AllocSize);
  101. p2^.Next := p^.Next;
  102. p2^.Size := EncodeTinyHeapFreeBlockSize(RestSize);
  103. if prev = nil then
  104. FreeList := p2
  105. else
  106. prev^.next := p2;
  107. end
  108. else
  109. begin
  110. if prev = nil then
  111. FreeList := p^.Next
  112. else
  113. prev^.next := p^.next;
  114. end;
  115. PTinyHeapMemBlockSize(p)^ := size;
  116. end
  117. else
  118. begin
  119. { p=HeapPtr }
  120. if PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr))<AllocSize then
  121. if ReturnNilIfGrowHeapFails then
  122. Result := nil
  123. else
  124. HandleError(203);
  125. result := @PTinyHeapMemBlockSize(HeapPtr)[1];
  126. PTinyHeapMemBlockSize(HeapPtr)^ := size;
  127. HeapPtr := pointer(TTinyHeapPointerArithmeticType(HeapPtr)+AllocSize);
  128. if prev = nil then
  129. FreeList := HeapPtr
  130. else
  131. prev^.next := HeapPtr;
  132. end;
  133. {$ifdef DEBUG_TINY_HEAP}
  134. Writeln(HexStr(Result));
  135. {$endif DEBUG_TINY_HEAP}
  136. end;
  137. function TinyGetAlignedMem(Size, Alignment: ptruint): pointer;
  138. var
  139. mem: Pointer;
  140. memp: ptruint;
  141. begin
  142. if alignment <= sizeof(pointer) then
  143. result := GetMem(size)
  144. else
  145. begin
  146. mem := GetMem(Size+Alignment-1);
  147. memp := align(ptruint(mem), Alignment);
  148. InternalTinyFreeMem(mem, TTinyHeapPointerArithmeticType(memp)-TTinyHeapPointerArithmeticType(mem));
  149. result := pointer(memp);
  150. end;
  151. end;
  152. procedure InternalTinyFreeMem(Addr: Pointer; Size: PtrUInt);
  153. var
  154. p, prev: PTinyHeapBlock;
  155. begin
  156. p := FreeList;
  157. prev := nil;
  158. while (p<>HeapPtr) and (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(Addr)) do
  159. begin
  160. prev := p;
  161. p := p^.Next;
  162. end;
  163. { join with previous block? }
  164. if assigned(prev) and ((TTinyHeapPointerArithmeticType(prev)+DecodeTinyHeapFreeBlockSize(prev^.Size)) = TTinyHeapPointerArithmeticType(Addr)) then
  165. begin
  166. Addr:=prev;
  167. Size:=DecodeTinyHeapFreeBlockSize(prev^.size)+Size;
  168. end
  169. else
  170. if assigned(prev) then
  171. prev^.Next := Addr
  172. else
  173. FreeList := Addr;
  174. { join with next block? }
  175. if TTinyHeapPointerArithmeticType(p)=(TTinyHeapPointerArithmeticType(Addr)+Size) then
  176. begin
  177. if p=HeapPtr then
  178. HeapPtr:=Addr
  179. else
  180. begin
  181. PTinyHeapBlock(Addr)^.Next:=p^.Next;
  182. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size+DecodeTinyHeapFreeBlockSize(p^.Size));
  183. end;
  184. end
  185. else
  186. begin
  187. PTinyHeapBlock(Addr)^.Next:=p;
  188. PTinyHeapBlock(Addr)^.Size:=EncodeTinyHeapFreeBlockSize(Size);
  189. end;
  190. end;
  191. function SysTinyFreeMem(Addr: Pointer): ptruint;
  192. var
  193. sz: ptruint;
  194. begin
  195. {$ifdef DEBUG_TINY_HEAP}
  196. Writeln('SysTinyFreeMem(', HexStr(Addr), ')');
  197. {$endif DEBUG_TINY_HEAP}
  198. if addr=nil then
  199. begin
  200. result:=0;
  201. exit;
  202. end;
  203. if (TTinyHeapPointerArithmeticType(addr) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  204. (TTinyHeapPointerArithmeticType(addr) >= TTinyHeapPointerArithmeticType(HeapPtr)) then
  205. HandleError(204);
  206. sz := Align(FindSize(addr)+SizeOf(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  207. InternalTinyFreeMem(@PTinyHeapMemBlockSize(addr)[-1], sz);
  208. result := sz;
  209. end;
  210. function SysTinyFreeMemSize(Addr: Pointer; Size: Ptruint): ptruint;
  211. begin
  212. result := SysTinyFreeMem(addr);
  213. end;
  214. function SysTinyMemSize(p: pointer): ptruint;
  215. begin
  216. result := findsize(p);
  217. end;
  218. function SysTinyAllocMem(size: ptruint): pointer;
  219. begin
  220. result := SysTinyGetMem(size);
  221. if result<>nil then
  222. FillChar(result^,SysTinyMemSize(result),0);
  223. end;
  224. function SysTinyReAllocMem(var p: pointer; size: ptruint):pointer;
  225. var
  226. oldsize, OldAllocSize, NewAllocSize: ptruint;
  227. after_block, before_block, before_before_block: PTinyHeapBlock;
  228. after_block_size, before_block_size: PtrUInt;
  229. new_after_block: PTinyHeapBlock;
  230. begin
  231. {$ifdef DEBUG_TINY_HEAP}
  232. Write('SysTinyReAllocMem(', HexStr(p), ',', size, ')=');
  233. {$endif DEBUG_TINY_HEAP}
  234. if size=0 then
  235. begin
  236. SysTinyFreeMem(p);
  237. result := nil;
  238. p := nil;
  239. end
  240. else if p=nil then
  241. begin
  242. result := AllocMem(size);
  243. p := result;
  244. end
  245. else
  246. begin
  247. if (TTinyHeapPointerArithmeticType(p) < TTinyHeapPointerArithmeticType(HeapOrg)) or
  248. (TTinyHeapPointerArithmeticType(p) >= TTinyHeapPointerArithmeticType(HeapPtr)) then
  249. HandleError(204);
  250. oldsize := FindSize(p);
  251. OldAllocSize := align(oldsize+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  252. NewAllocSize := align(size+sizeof(TTinyHeapMemBlockSize), TinyHeapAllocGranularity);
  253. if OldAllocSize = NewAllocSize then
  254. begin
  255. { old and new size are the same after alignment, so the memory block is already allocated }
  256. { we just need to update the size }
  257. PTinyHeapMemBlockSize(p)[-1] := size;
  258. if size > oldsize then
  259. FillChar((TTinyHeapPointerArithmeticType(p)+oldsize)^, size-oldsize, 0);
  260. end
  261. else if OldAllocSize > NewAllocSize then
  262. begin
  263. { we're decreasing the memory block size, so we can just free the remaining memory at the end }
  264. PTinyHeapMemBlockSize(p)[-1] := size;
  265. InternalTinyFreeMem(Pointer(TTinyHeapPointerArithmeticType(p)+(NewAllocSize-PtrUInt(SizeOf(TTinyHeapMemBlockSize)))), OldAllocSize-NewAllocSize);
  266. end
  267. else
  268. begin
  269. { we're increasing the memory block size. First, find if there are free memory blocks immediately
  270. before and after our memory block. }
  271. after_block := FreeList;
  272. before_block := nil;
  273. before_before_block := nil;
  274. while (after_block<>HeapPtr) and (TTinyHeapPointerArithmeticType(after_block) < TTinyHeapPointerArithmeticType(p)) do
  275. begin
  276. before_before_block := before_block;
  277. before_block := after_block;
  278. after_block := after_block^.Next;
  279. end;
  280. { is after_block immediately after our block? }
  281. if after_block=Pointer(TTinyHeapPointerArithmeticType(p)+(OldAllocSize-PtrUInt(SizeOf(TTinyHeapMemBlockSize)))) then
  282. begin
  283. if after_block = HeapPtr then
  284. after_block_size := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr))
  285. else
  286. after_block_size := DecodeTinyHeapFreeBlockSize(after_block^.size);
  287. end
  288. else
  289. after_block_size := 0;
  290. { is there enough room after the block? }
  291. if (OldAllocSize+after_block_size)>=NewAllocSize then
  292. begin
  293. if after_block = HeapPtr then
  294. begin
  295. HeapPtr:=Pointer(TTinyHeapPointerArithmeticType(HeapPtr)+(NewAllocSize-OldAllocSize));
  296. if assigned(before_block) then
  297. before_block^.Next := HeapPtr
  298. else
  299. FreeList := HeapPtr;
  300. end
  301. else
  302. begin
  303. if (NewAllocSize-OldAllocSize)=after_block_size then
  304. begin
  305. if assigned(before_block) then
  306. before_block^.Next := after_block^.Next
  307. else
  308. FreeList := after_block^.Next;
  309. end
  310. else
  311. begin
  312. new_after_block := PTinyHeapBlock(TTinyHeapPointerArithmeticType(after_block)+(NewAllocSize-OldAllocSize));
  313. new_after_block^.Next:=after_block^.Next;
  314. new_after_block^.Size:=EncodeTinyHeapFreeBlockSize(after_block_size-(NewAllocSize-OldAllocSize));
  315. if assigned(before_block) then
  316. before_block^.Next := new_after_block
  317. else
  318. FreeList := new_after_block;
  319. end;
  320. end;
  321. PTinyHeapMemBlockSize(p)[-1] := size;
  322. FillChar((TTinyHeapPointerArithmeticType(p)+oldsize)^, size-oldsize, 0);
  323. end
  324. else
  325. begin
  326. { is before_block immediately before our block? }
  327. if assigned(before_block) and (Pointer(TTinyHeapPointerArithmeticType(before_block)+DecodeTinyHeapFreeBlockSize(before_block^.Size))=Pointer(TTinyHeapPointerArithmeticType(p)-SizeOf(TTinyHeapMemBlockSize))) then
  328. before_block_size := DecodeTinyHeapFreeBlockSize(before_block^.Size)
  329. else
  330. before_block_size := 0;
  331. { if there's enough space, we can slide our current block back and reclaim before_block }
  332. if (before_block_size<NewAllocSize) and ((before_block_size+OldAllocSize+after_block_size)>=NewAllocSize) and
  333. { todo: implement this also for after_block_size>0 }
  334. (after_block_size>0) then
  335. begin
  336. if (before_block_size+OldAllocSize+after_block_size)=NewAllocSize then
  337. begin
  338. if after_block=HeapPtr then
  339. begin
  340. HeapPtr := HeapEnd;
  341. if assigned(before_before_block) then
  342. before_before_block^.Next := HeapPtr
  343. else
  344. FreeList := HeapPtr;
  345. end
  346. else
  347. if assigned(before_before_block) then
  348. before_before_block^.Next := after_block^.Next
  349. else
  350. FreeList := after_block^.Next;
  351. end;
  352. Result := Pointer(TTinyHeapPointerArithmeticType(before_block)+SizeOf(TTinyHeapMemBlockSize));
  353. Move(p^, Result^, oldsize);
  354. PTinyHeapMemBlockSize(before_block)^ := size;
  355. if (before_block_size+OldAllocSize+after_block_size)>NewAllocSize then
  356. begin
  357. new_after_block := PTinyHeapBlock(TTinyHeapPointerArithmeticType(before_block)+NewAllocSize);
  358. new_after_block^.Next:=after_block^.Next;
  359. new_after_block^.Size:=EncodeTinyHeapFreeBlockSize(before_block_size+after_block_size-(NewAllocSize-OldAllocSize));
  360. if assigned(before_before_block) then
  361. before_before_block^.Next := new_after_block
  362. else
  363. FreeList := new_after_block;
  364. end;
  365. FillChar((TTinyHeapPointerArithmeticType(Result)+oldsize)^, size-oldsize, 0);
  366. p := Result;
  367. end
  368. else
  369. begin
  370. result := AllocMem(size);
  371. if result <> nil then
  372. begin
  373. if oldsize > size then
  374. oldsize := size;
  375. move(pbyte(p)^, pbyte(result)^, oldsize);
  376. end;
  377. SysTinyFreeMem(p);
  378. p := result;
  379. end;
  380. end;
  381. end;
  382. end;
  383. {$ifdef DEBUG_TINY_HEAP}
  384. Writeln(HexStr(result));
  385. {$endif DEBUG_TINY_HEAP}
  386. end;
  387. function MemAvail: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif};
  388. var
  389. p: PTinyHeapBlock;
  390. begin
  391. MemAvail := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  392. if MemAvail > 0 then
  393. Dec(MemAvail, SizeOf(TTinyHeapMemBlockSize));
  394. p := FreeList;
  395. while p <> HeapPtr do
  396. begin
  397. Inc(MemAvail, DecodeTinyHeapFreeBlockSize(p^.Size)-SizeOf(TTinyHeapMemBlockSize));
  398. p := p^.Next;
  399. end;
  400. end;
  401. function MaxAvail: {$ifdef FPC_TINYHEAP_HUGE}LongInt{$else}PtrUInt{$endif};
  402. var
  403. p: PTinyHeapBlock;
  404. begin
  405. MaxAvail := PtrUInt(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  406. p := FreeList;
  407. while p <> HeapPtr do
  408. begin
  409. if DecodeTinyHeapFreeBlockSize(p^.Size) > MaxAvail then
  410. MaxAvail := DecodeTinyHeapFreeBlockSize(p^.Size);
  411. p := p^.Next;
  412. end;
  413. if MaxAvail > 0 then
  414. Dec(MaxAvail, SizeOf(TTinyHeapMemBlockSize));
  415. end;
  416. procedure Mark(var p: Pointer);
  417. begin
  418. p := HeapPtr;
  419. end;
  420. procedure Release(var p: Pointer);
  421. begin
  422. HeapPtr := p;
  423. FreeList := p;
  424. end;
  425. procedure InternalTinyAlign(var AAddress: Pointer; ASize: PtrUInt);
  426. var
  427. alignment_inc: smallint;
  428. begin
  429. alignment_inc := TTinyHeapPointerArithmeticType(align(AAddress,TinyHeapAllocGranularity))-TTinyHeapPointerArithmeticType(AAddress);
  430. Inc(AAddress,alignment_inc);
  431. Dec(ASize,alignment_inc);
  432. Dec(ASize,ASize mod TinyHeapAllocGranularity);
  433. end;
  434. { Strongly simplified version of RegisterTinyHeapBlock, which can be used when
  435. the heap is only a single contiguous memory block. If you want to add
  436. multiple blocks to the heap, you should use RegisterTinyHeapBlock instead. }
  437. procedure RegisterTinyHeapBlock_Simple(AAddress: Pointer; ASize: PtrUInt);
  438. begin
  439. {$ifdef DEBUG_TINY_HEAP}
  440. Writeln('RegisterTinyHeapBlock_Simple(', HexStr(AAddress), ',', ASize, ')');
  441. {$endif DEBUG_TINY_HEAP}
  442. InternalTinyAlign(AAddress, ASize);
  443. HeapOrg:=AAddress;
  444. HeapPtr:=AAddress;
  445. FreeList:=AAddress;
  446. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  447. end;
  448. { Strongly simplified version of RegisterTinyHeapBlock, which can be used when
  449. the heap is only a single contiguous memory block and the address and size
  450. are already aligned on a TinyHeapAllocGranularity boundary. }
  451. procedure RegisterTinyHeapBlock_Simple_Prealigned(AAddress: Pointer; ASize: PtrUInt);
  452. begin
  453. {$ifdef DEBUG_TINY_HEAP}
  454. Writeln('RegisterTinyHeapBlock_Simple_Prealigned(', HexStr(AAddress), ',', ASize, ')');
  455. {$endif DEBUG_TINY_HEAP}
  456. HeapOrg:=AAddress;
  457. HeapPtr:=AAddress;
  458. FreeList:=AAddress;
  459. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  460. end;
  461. procedure RegisterTinyHeapBlock(AAddress: pointer; ASize: ptruint);
  462. var
  463. alignment_inc: smallint;
  464. p: PTinyHeapBlock;
  465. begin
  466. {$ifdef DEBUG_TINY_HEAP}
  467. Writeln('RegisterTinyHeapBlock(', HexStr(AAddress), ',', ASize, ')');
  468. {$endif DEBUG_TINY_HEAP}
  469. InternalTinyAlign(AAddress, ASize);
  470. if HeapOrg=nil then
  471. begin
  472. HeapOrg:=AAddress;
  473. HeapPtr:=AAddress;
  474. FreeList:=AAddress;
  475. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  476. end
  477. else
  478. begin
  479. if (TTinyHeapPointerArithmeticType(HeapOrg) > TTinyHeapPointerArithmeticType(AAddress)) then
  480. HeapOrg:=AAddress;
  481. if TTinyHeapPointerArithmeticType(AAddress) > TTinyHeapPointerArithmeticType(HeapEnd) then
  482. begin
  483. if TTinyHeapPointerArithmeticType(HeapPtr) = TTinyHeapPointerArithmeticType(HeapEnd) then
  484. begin
  485. if FreeList=HeapPtr then
  486. FreeList:=AAddress
  487. else
  488. begin
  489. p:=FreeList;
  490. while p^.Next<>HeapPtr do
  491. p:=p^.Next;
  492. PTinyHeapBlock(HeapPtr)^.Next:=AAddress;
  493. end;
  494. end
  495. else
  496. begin
  497. PTinyHeapBlock(HeapPtr)^.Size:=EncodeTinyHeapFreeBlockSize(TTinyHeapPointerArithmeticType(HeapEnd)-TTinyHeapPointerArithmeticType(HeapPtr));
  498. PTinyHeapBlock(HeapPtr)^.Next:=AAddress;
  499. end;
  500. HeapPtr:=AAddress;
  501. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize);
  502. end
  503. else if TTinyHeapPointerArithmeticType(AAddress) = TTinyHeapPointerArithmeticType(HeapEnd) then
  504. HeapEnd:=Pointer(TTinyHeapPointerArithmeticType(AAddress)+ASize)
  505. else
  506. InternalTinyFreeMem(AAddress, ASize);
  507. end;
  508. end;
  509. const
  510. TinyHeapMemoryManager: TMemoryManager = (
  511. NeedLock: false; // Obsolete
  512. GetMem: @SysTinyGetMem;
  513. FreeMem: @SysTinyFreeMem;
  514. FreeMemSize: @SysTinyFreeMemSize;
  515. AllocMem: @SysTinyAllocMem;
  516. ReAllocMem: @SysTinyReAllocMem;
  517. MemSize: @SysTinyMemSize;
  518. InitThread: nil;
  519. DoneThread: nil;
  520. RelocateHeap: nil;
  521. GetHeapStatus: nil;
  522. GetFPCHeapStatus: nil;
  523. );