heap.inc 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. functions for heap management in the data segment
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {****************************************************************************}
  13. { Reuse bigger blocks instead of allocating a new block at freelist/heapptr.
  14. the tried bigger blocks are always multiple sizes of the current block }
  15. {$define REUSEBIGGER}
  16. { Allocate small blocks at heapptr instead of walking the freelist }
  17. {$define SMALLATHEAPPTR}
  18. { Try to find the best matching block in general freelist }
  19. {$define BESTMATCH}
  20. { DEBUG: Dump info when the heap needs to grow }
  21. { define DUMPGROW}
  22. { Default heap settings }
  23. const
  24. blocksize = 16; { at least size of freerecord }
  25. blockshr = 4; { shr value for blocksize=2^blockshr}
  26. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  27. maxblock = maxblocksize div blocksize;
  28. maxreusebigger = 8; { max reuse bigger tries }
  29. usedmask = 1; { flag if the block is used or not }
  30. beforeheapendmask = 2; { flag if the block is just before a heapptr }
  31. sizemask = not(blocksize-1);
  32. {****************************************************************************}
  33. {$ifdef DUMPGROW}
  34. {$define DUMPBLOCKS}
  35. {$endif}
  36. { Memory manager }
  37. const
  38. MemoryManager: TMemoryManager = (
  39. GetMem: SysGetMem;
  40. FreeMem: SysFreeMem;
  41. FreeMemSize: SysFreeMemSize;
  42. AllocMem: SysAllocMem;
  43. ReAllocMem: SysReAllocMem;
  44. MemSize: SysMemSize;
  45. MemAvail: SysMemAvail;
  46. MaxAvail: SysMaxAvail;
  47. HeapSize: SysHeapSize;
  48. );
  49. type
  50. ppfreerecord = ^pfreerecord;
  51. pfreerecord = ^tfreerecord;
  52. tfreerecord = record
  53. size : longint;
  54. next,
  55. prev : pfreerecord;
  56. end; { 12 bytes }
  57. pheaprecord = ^theaprecord;
  58. theaprecord = record
  59. { this should overlap with tfreerecord }
  60. size : longint;
  61. end; { 4 bytes }
  62. tfreelists = array[0..maxblock] of pfreerecord;
  63. pfreelists = ^tfreelists;
  64. var
  65. internal_memavail : longint;
  66. internal_heapsize : longint;
  67. freelists : tfreelists;
  68. {*****************************************************************************
  69. Memory Manager
  70. *****************************************************************************}
  71. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  72. begin
  73. MemMgr:=MemoryManager;
  74. end;
  75. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  76. begin
  77. MemoryManager:=MemMgr;
  78. end;
  79. function IsMemoryManagerSet:Boolean;
  80. begin
  81. IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
  82. (MemoryManager.FreeMem<>@SysFreeMem);
  83. end;
  84. procedure GetMem(Var p:pointer;Size:Longint);{$ifndef NEWMM}[public,alias:'FPC_GETMEM'];{$endif}
  85. begin
  86. p:=MemoryManager.GetMem(Size);
  87. end;
  88. procedure FreeMem(Var p:pointer;Size:Longint);{$ifndef NEWMM}[public,alias:'FPC_FREEMEM'];{$endif}
  89. begin
  90. MemoryManager.FreeMemSize(p,Size);
  91. p:=nil;
  92. end;
  93. function MaxAvail:Longint;
  94. begin
  95. MaxAvail:=MemoryManager.MaxAvail();
  96. end;
  97. function MemAvail:Longint;
  98. begin
  99. MemAvail:=MemoryManager.MemAvail();
  100. end;
  101. { FPC Additions }
  102. function HeapSize:Longint;
  103. begin
  104. HeapSize:=MemoryManager.HeapSize();
  105. end;
  106. function MemSize(p:pointer):Longint;
  107. begin
  108. MemSize:=MemoryManager.MemSize(p);
  109. end;
  110. { Delphi style }
  111. function FreeMem(var p:pointer):Longint;
  112. begin
  113. Freemem:=MemoryManager.FreeMem(p);
  114. end;
  115. function GetMem(size:longint):pointer;
  116. begin
  117. GetMem:=MemoryManager.GetMem(Size);
  118. end;
  119. function AllocMem(Size:Longint):pointer;
  120. begin
  121. AllocMem:=MemoryManager.AllocMem(size);
  122. end;
  123. function ReAllocMem(var p:pointer;Size:Longint):pointer;
  124. begin
  125. ReAllocMem:=MemoryManager.ReAllocMem(p,size);
  126. end;
  127. { Needed for calls from Assembler }
  128. procedure AsmGetMem(var p:pointer;size:longint);{$ifdef NEWMM}[public,alias:'FPC_GETMEM'];{$endif}
  129. begin
  130. p:=MemoryManager.GetMem(size);
  131. end;
  132. procedure AsmFreeMem(var p:pointer);{$ifdef NEWMM}[public,alias:'FPC_FREEMEM'];{$endif}
  133. begin
  134. if p <> nil then
  135. begin
  136. MemoryManager.FreeMem(p);
  137. p:=nil;
  138. end;
  139. end;
  140. {*****************************************************************************
  141. Heapsize,Memavail,MaxAvail
  142. *****************************************************************************}
  143. function SysHeapsize : longint;
  144. begin
  145. Sysheapsize:=internal_heapsize;
  146. end;
  147. function SysMemavail : longint;
  148. begin
  149. Sysmemavail:=internal_memavail;
  150. end;
  151. function SysMaxavail : longint;
  152. var
  153. hp : pfreerecord;
  154. begin
  155. Sysmaxavail:=heapend-heapptr;
  156. hp:=freelists[0];
  157. while assigned(hp) do
  158. begin
  159. if hp^.size>Sysmaxavail then
  160. Sysmaxavail:=hp^.size;
  161. hp:=hp^.next;
  162. end;
  163. end;
  164. {$ifdef DUMPBLOCKS}
  165. procedure DumpBlocks;
  166. var
  167. s,i,j : longint;
  168. hp : pfreerecord;
  169. begin
  170. for i:=1 to maxblock do
  171. begin
  172. hp:=freelists[i];
  173. j:=0;
  174. while assigned(hp) do
  175. begin
  176. inc(j);
  177. hp:=hp^.next;
  178. end;
  179. writeln('Block ',i*blocksize,': ',j);
  180. end;
  181. { freelist 0 }
  182. hp:=freelists[0];
  183. j:=0;
  184. s:=0;
  185. while assigned(hp) do
  186. begin
  187. inc(j);
  188. if hp^.size>s then
  189. s:=hp^.size;
  190. hp:=hp^.next;
  191. end;
  192. writeln('Main: ',j,' maxsize: ',s);
  193. end;
  194. {$endif}
  195. {*****************************************************************************
  196. SysGetMem
  197. *****************************************************************************}
  198. function SysGetMem(size : longint):pointer;
  199. type
  200. heaperrorproc=function(size:longint):integer;
  201. var
  202. proc : heaperrorproc;
  203. pcurr : pfreerecord;
  204. again : boolean;
  205. s,s1,i,
  206. sizeleft : longint;
  207. {$ifdef BESTMATCH}
  208. pbest : pfreerecord;
  209. {$endif}
  210. begin
  211. { Something to allocate ? }
  212. if size<=0 then
  213. begin
  214. { give an error for < 0 }
  215. if size<0 then
  216. HandleError(204);
  217. { we always need to allocate something, using heapend is not possible,
  218. because heappend can be changed by growheap (PFV) }
  219. size:=1;
  220. end;
  221. { calc to multiply of 16 after adding the needed 8 bytes heaprecord }
  222. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  223. dec(internal_memavail,size);
  224. { try to find a block in one of the freelists per size }
  225. s:=size shr blockshr;
  226. if s<=maxblock then
  227. begin
  228. pcurr:=freelists[s];
  229. { correct size match ? }
  230. if assigned(pcurr) then
  231. begin
  232. { create the block we should return }
  233. sysgetmem:=pointer(pcurr)+sizeof(theaprecord);
  234. { fix size }
  235. pcurr^.size:=pcurr^.size or usedmask;
  236. { update freelist }
  237. freelists[s]:=pcurr^.next;
  238. if assigned(freelists[s]) then
  239. freelists[s]^.prev:=nil;
  240. exit;
  241. end;
  242. {$ifdef SMALLATHEAPPTR}
  243. if heapend-heapptr>size then
  244. begin
  245. sysgetmem:=heapptr;
  246. if (heapptr+size=heapend) then
  247. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  248. else
  249. pheaprecord(sysgetmem)^.size:=size or usedmask;
  250. inc(sysgetmem,sizeof(theaprecord));
  251. inc(heapptr,size);
  252. exit;
  253. end;
  254. {$endif}
  255. {$ifdef REUSEBIGGER}
  256. { try a bigger block }
  257. s1:=s+s;
  258. i:=0;
  259. while (s1<=maxblock) and (i<maxreusebigger) do
  260. begin
  261. pcurr:=freelists[s1];
  262. if assigned(pcurr) then
  263. begin
  264. s:=s1;
  265. break;
  266. end;
  267. inc(s1);
  268. inc(i);
  269. end;
  270. {$endif}
  271. end
  272. else
  273. pcurr:=nil;
  274. { not found, then check the main freelist for the first match }
  275. if not(assigned(pcurr)) then
  276. begin
  277. s:=0;
  278. {$ifdef BESTMATCH}
  279. pbest:=nil;
  280. {$endif}
  281. pcurr:=freelists[0];
  282. while assigned(pcurr) do
  283. begin
  284. {$ifdef BESTMATCH}
  285. if pcurr^.size=size then
  286. break
  287. else
  288. begin
  289. if (pcurr^.size>size) then
  290. begin
  291. if (not assigned(pbest)) or
  292. (pcurr^.size<pbest^.size) then
  293. pbest:=pcurr;
  294. end;
  295. end;
  296. {$else}
  297. if pcurr^.size>=size then
  298. break;
  299. {$endif}
  300. pcurr:=pcurr^.next;
  301. end;
  302. {$ifdef BESTMATCH}
  303. if not assigned(pcurr) then
  304. pcurr:=pbest;
  305. {$endif}
  306. end;
  307. { have we found a block, then get it and free up the other left part,
  308. if no blocks are found then allocated at the heapptr or grow the heap }
  309. if assigned(pcurr) then
  310. begin
  311. { get pointer of the block we should return }
  312. sysgetmem:=pointer(pcurr);
  313. { remove the current block from the freelist }
  314. if assigned(pcurr^.next) then
  315. pcurr^.next^.prev:=pcurr^.prev;
  316. if assigned(pcurr^.prev) then
  317. pcurr^.prev^.next:=pcurr^.next
  318. else
  319. freelists[s]:=pcurr^.next;
  320. { create the left over freelist block, if at least 16 bytes are free }
  321. sizeleft:=pcurr^.size-size;
  322. if sizeleft>sizeof(tfreerecord) then
  323. begin
  324. pcurr:=pfreerecord(pointer(pcurr)+size);
  325. { inherit the beforeheapendmask }
  326. pcurr^.size:=sizeleft or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  327. { insert the block in the freelist }
  328. pcurr^.prev:=nil;
  329. s1:=sizeleft shr blockshr;
  330. if s1>maxblock then
  331. s1:=0;
  332. pcurr^.next:=freelists[s1];
  333. if assigned(freelists[s1]) then
  334. freelists[s1]^.prev:=pcurr;
  335. freelists[s1]:=pcurr;
  336. { create the block we need to return }
  337. pheaprecord(sysgetmem)^.size:=size or usedmask;
  338. end
  339. else
  340. begin
  341. { create the block we need to return }
  342. pheaprecord(sysgetmem)^.size:=size or usedmask or (pheaprecord(sysgetmem)^.size and beforeheapendmask);
  343. end;
  344. inc(sysgetmem,sizeof(theaprecord));
  345. exit;
  346. end;
  347. { Lastly, the top of the heap is checked, to see if there is }
  348. { still memory available. }
  349. repeat
  350. again:=false;
  351. if heapend-heapptr>size then
  352. begin
  353. sysgetmem:=heapptr;
  354. if (heapptr+size=heapend) then
  355. pheaprecord(sysgetmem)^.size:=size or (usedmask or beforeheapendmask)
  356. else
  357. pheaprecord(sysgetmem)^.size:=size or usedmask;
  358. inc(sysgetmem,sizeof(theaprecord));
  359. inc(heapptr,size);
  360. exit;
  361. end;
  362. { Call the heaperror proc }
  363. if assigned(heaperror) then
  364. begin
  365. proc:=heaperrorproc(heaperror);
  366. case proc(size) of
  367. 0 : HandleError(203);
  368. 1 : sysgetmem:=nil;
  369. 2 : again:=true;
  370. end;
  371. end
  372. else
  373. HandleError(203);
  374. until not again;
  375. end;
  376. {*****************************************************************************
  377. SysFreeMem
  378. *****************************************************************************}
  379. Function SysFreeMem(var p : pointer):Longint;
  380. var
  381. pcurrsize,s : longint;
  382. pcurr : pfreerecord;
  383. begin
  384. if p=nil then
  385. HandleError(204);
  386. { fix p to point to the heaprecord }
  387. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  388. pcurrsize:=pcurr^.size and sizemask;
  389. inc(internal_memavail,pcurrsize);
  390. { insert the block in it's freelist }
  391. pcurr^.size:=pcurr^.size and (not usedmask);
  392. pcurr^.prev:=nil;
  393. s:=pcurrsize shr blockshr;
  394. if s>maxblock then
  395. s:=0;
  396. pcurr^.next:=freelists[s];
  397. if assigned(pcurr^.next) then
  398. pcurr^.next^.prev:=pcurr;
  399. freelists[s]:=pcurr;
  400. p:=nil;
  401. SysFreeMem:=pcurrsize;
  402. end;
  403. {*****************************************************************************
  404. SysFreeMemSize
  405. *****************************************************************************}
  406. Function SysFreeMemSize(var p : pointer;size : longint):longint;
  407. var
  408. pcurrsize,s : longint;
  409. pcurr : pfreerecord;
  410. begin
  411. SysFreeMemSize:=0;
  412. if size<=0 then
  413. begin
  414. if size<0 then
  415. HandleError(204);
  416. p:=nil;
  417. exit;
  418. end;
  419. if p=nil then
  420. HandleError(204);
  421. { fix p to point to the heaprecord }
  422. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  423. pcurrsize:=pcurr^.size and sizemask;
  424. inc(internal_memavail,pcurrsize);
  425. { size check }
  426. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  427. if size<>pcurrsize then
  428. HandleError(204);
  429. { insert the block in it's freelist }
  430. pcurr^.size:=pcurr^.size and (not usedmask);
  431. pcurr^.prev:=nil;
  432. s:=pcurrsize shr blockshr;
  433. if s>maxblock then
  434. s:=0;
  435. pcurr^.next:=freelists[s];
  436. if assigned(pcurr^.next) then
  437. pcurr^.next^.prev:=pcurr;
  438. freelists[s]:=pcurr;
  439. p:=nil;
  440. SysFreeMemSize:=pcurrsize;
  441. end;
  442. {*****************************************************************************
  443. SysMemSize
  444. *****************************************************************************}
  445. function SysMemSize(p:pointer):longint;
  446. begin
  447. SysMemSize:=(pheaprecord(pointer(p)-sizeof(theaprecord))^.size and sizemask)-sizeof(theaprecord);
  448. end;
  449. {*****************************************************************************
  450. SysAllocMem
  451. *****************************************************************************}
  452. function SysAllocMem(size : longint):pointer;
  453. begin
  454. sysallocmem:=MemoryManager.GetMem(size);
  455. if sysallocmem<>nil then
  456. FillChar(sysallocmem^,size,0);
  457. end;
  458. {*****************************************************************************
  459. SysResizeMem
  460. *****************************************************************************}
  461. function SysTryResizeMem(var p:pointer;size : longint):boolean;
  462. var
  463. oldsize,
  464. currsize,
  465. foundsize,
  466. sizeleft,
  467. s : longint;
  468. wasbeforeheapend : boolean;
  469. hp,
  470. pnew,
  471. pcurr : pfreerecord;
  472. begin
  473. { fix needed size }
  474. size:=(size+sizeof(theaprecord)+(blocksize-1)) and (not (blocksize-1));
  475. { fix p to point to the heaprecord }
  476. pcurr:=pfreerecord(pointer(p)-sizeof(theaprecord));
  477. currsize:=pcurr^.size and sizemask;
  478. oldsize:=currsize;
  479. wasbeforeheapend:=(pcurr^.size and beforeheapendmask)<>0;
  480. { is the allocated block still correct? }
  481. if currsize=size then
  482. begin
  483. SysTryResizeMem:=true;
  484. exit;
  485. end;
  486. { do we need to allocate more memory ? }
  487. if size>currsize then
  488. begin
  489. { the size is bigger than the previous size, we need to allocated more mem.
  490. We first check if the blocks after the current block are free. If not we
  491. simply call getmem/freemem to get the new block }
  492. foundsize:=0;
  493. hp:=pcurr;
  494. repeat
  495. inc(foundsize,hp^.size and sizemask);
  496. { block used or before a heapptr ? }
  497. if (hp^.size and beforeheapendmask)<>0 then
  498. begin
  499. wasbeforeheapend:=true;
  500. break;
  501. end;
  502. { get next block }
  503. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  504. { when we're at heapptr then we can stop }
  505. if (hp=heapptr) then
  506. begin
  507. inc(foundsize,heapend-heapptr);
  508. break;
  509. end;
  510. if (hp^.size and usedmask)<>0 then
  511. break;
  512. until (foundsize>=size);
  513. { found enough free blocks? }
  514. if foundsize>=size then
  515. begin
  516. { we walk the list again and remove all blocks }
  517. foundsize:=pcurr^.size and sizemask;
  518. hp:=pcurr;
  519. repeat
  520. { get next block }
  521. hp:=pfreerecord(pointer(hp)+(hp^.size and sizemask));
  522. { when we're at heapptr then we can increase it, if there is enough
  523. room is already checked }
  524. if (hp=heapptr) then
  525. begin
  526. inc(heapptr,size-foundsize);
  527. foundsize:=size;
  528. break;
  529. end;
  530. s:=hp^.size and sizemask;
  531. inc(foundsize,s);
  532. { remove block from freelist }
  533. s:=s shr blockshr;
  534. if s>maxblock then
  535. s:=0;
  536. if assigned(hp^.next) then
  537. hp^.next^.prev:=hp^.prev;
  538. if assigned(hp^.prev) then
  539. hp^.prev^.next:=hp^.next
  540. else
  541. freelists[s]:=hp^.next;
  542. until (foundsize>=size);
  543. if wasbeforeheapend then
  544. pcurr^.size:=foundsize or usedmask or beforeheapendmask
  545. else
  546. pcurr^.size:=foundsize or usedmask;
  547. end
  548. else
  549. begin
  550. { we need to call getmem/move/freemem }
  551. SysTryResizeMem:=false;
  552. exit;
  553. end;
  554. currsize:=pcurr^.size and sizemask;
  555. end;
  556. { is the size smaller then we can adjust the block to that size and insert
  557. the other part into the freelist }
  558. if size<currsize then
  559. begin
  560. { create the left over freelist block, if at least 16 bytes are free }
  561. sizeleft:=currsize-size;
  562. if sizeleft>sizeof(tfreerecord) then
  563. begin
  564. pnew:=pfreerecord(pointer(pcurr)+size);
  565. pnew^.size:=sizeleft or (pcurr^.size and beforeheapendmask);
  566. { insert the block in the freelist }
  567. pnew^.prev:=nil;
  568. s:=sizeleft shr blockshr;
  569. if s>maxblock then
  570. s:=0;
  571. pnew^.next:=freelists[s];
  572. if assigned(freelists[s]) then
  573. freelists[s]^.prev:=pnew;
  574. freelists[s]:=pnew;
  575. { fix the size of the current block and leave }
  576. pcurr^.size:=size or usedmask;
  577. end
  578. else
  579. begin
  580. { fix the size of the current block and leave }
  581. pcurr^.size:=size or usedmask or (pcurr^.size and beforeheapendmask);
  582. end;
  583. end;
  584. dec(internal_memavail,size-oldsize);
  585. SysTryResizeMem:=true;
  586. end;
  587. {*****************************************************************************
  588. SysResizeMem
  589. *****************************************************************************}
  590. function SysReAllocMem(var p:pointer;size : longint):pointer;
  591. var
  592. oldsize : longint;
  593. p2 : pointer;
  594. begin
  595. { Free block? }
  596. if size=0 then
  597. begin
  598. if p<>nil then
  599. MemoryManager.FreeMem(p);
  600. end
  601. else
  602. { Allocate a new block? }
  603. if p=nil then
  604. begin
  605. p:=MemoryManager.GetMem(size);
  606. end
  607. else
  608. { Resize block }
  609. if not SysTryResizeMem(p,size) then
  610. begin
  611. oldsize:=MemoryManager.MemSize(p);
  612. p2:=MemoryManager.GetMem(size);
  613. if p2<>nil then
  614. Move(p^,p2^,oldsize);
  615. MemoryManager.FreeMem(p);
  616. p:=p2;
  617. end;
  618. SysReAllocMem:=p;
  619. end;
  620. {*****************************************************************************
  621. Mark/Release
  622. *****************************************************************************}
  623. procedure release(var p : pointer);
  624. begin
  625. end;
  626. procedure mark(var p : pointer);
  627. begin
  628. end;
  629. {*****************************************************************************
  630. Grow Heap
  631. *****************************************************************************}
  632. function growheap(size :longint) : integer;
  633. var
  634. sizeleft,
  635. NewPos : longint;
  636. pcurr : pfreerecord;
  637. begin
  638. {$ifdef DUMPGROW}
  639. writeln('grow ',size);
  640. DumpBlocks;
  641. {$endif}
  642. { Allocate by 64K size }
  643. size:=(size+$ffff) and $ffff0000;
  644. { first try 256K (default) }
  645. if size<=GrowHeapSize1 then
  646. begin
  647. NewPos:=Sbrk(GrowHeapSize1);
  648. if NewPos>0 then
  649. size:=GrowHeapSize1;
  650. end
  651. else
  652. { second try 1024K (default) }
  653. if size<=GrowHeapSize2 then
  654. begin
  655. NewPos:=Sbrk(GrowHeapSize2);
  656. if NewPos>0 then
  657. size:=GrowHeapSize2;
  658. end
  659. { else alloate the needed bytes }
  660. else
  661. NewPos:=SBrk(size);
  662. { try again }
  663. if NewPos=-1 then
  664. begin
  665. NewPos:=Sbrk(size);
  666. if NewPos=-1 then
  667. begin
  668. GrowHeap:=0;
  669. Exit;
  670. end;
  671. end;
  672. { increase heapend or add to freelist }
  673. if heapend=pointer(newpos) then
  674. begin
  675. heapend:=pointer(newpos+size);
  676. end
  677. else
  678. begin
  679. { create freelist entry for old heapptr-heapend }
  680. sizeleft:=heapend-heapptr;
  681. if sizeleft>sizeof(tfreerecord) then
  682. begin
  683. pcurr:=pfreerecord(heapptr);
  684. pcurr^.size:=sizeleft or beforeheapendmask;
  685. { insert the block in the freelist }
  686. pcurr^.next:=freelists[0];
  687. pcurr^.prev:=nil;
  688. if assigned(freelists[0]) then
  689. freelists[0]^.prev:=pcurr;
  690. freelists[0]:=pcurr;
  691. end;
  692. { now set the new heapptr,heapend to the new block }
  693. heapptr:=pointer(newpos);
  694. heapend:=pointer(newpos+size);
  695. end;
  696. { set the total new heap size }
  697. inc(internal_memavail,size);
  698. inc(internal_heapsize,size);
  699. { try again }
  700. GrowHeap:=2;
  701. end;
  702. {*****************************************************************************
  703. InitHeap
  704. *****************************************************************************}
  705. { This function will initialize the Heap manager and need to be called from
  706. the initialization of the system unit }
  707. procedure InitHeap;
  708. begin
  709. FillChar(FreeLists,sizeof(TFreeLists),0);
  710. internal_heapsize:=GetHeapSize;
  711. internal_memavail:=internal_heapsize;
  712. HeapOrg:=GetHeapStart;
  713. HeapPtr:=HeapOrg;
  714. HeapEnd:=HeapOrg+internal_memavail;
  715. HeapError:=@GrowHeap;
  716. end;
  717. {
  718. $Log$
  719. Revision 1.34 2000-02-10 13:59:35 peter
  720. * fixed bug with reallocmem to use the wrong size when copying the
  721. data to the new allocated pointer
  722. Revision 1.33 2000/02/02 11:12:29 peter
  723. * fixed internal_memavail counting for tryresizemem
  724. Revision 1.32 2000/01/31 23:41:30 peter
  725. * reallocmem fixed for freemem() call when size=0
  726. Revision 1.31 2000/01/24 23:56:10 peter
  727. * fixed reallocmem which didn't work anymore and thus broke a lot
  728. of objfpc/delphi code
  729. Revision 1.30 2000/01/20 12:35:35 jonas
  730. * fixed problem with reallocmem and heaptrc
  731. Revision 1.29 2000/01/07 16:41:34 daniel
  732. * copyright 2000
  733. Revision 1.28 2000/01/07 16:32:24 daniel
  734. * copyright 2000 added
  735. Revision 1.27 1999/12/16 19:11:49 peter
  736. * fixed sysmemsize which did the and sizemask wrong
  737. Revision 1.26 1999/12/13 21:04:46 peter
  738. * fixed getmem call with wrong size from reallocmem
  739. Revision 1.25 1999/12/01 22:57:31 peter
  740. * cmdline support
  741. Revision 1.24 1999/11/14 21:34:21 peter
  742. * fixed reallocmem with a block at the end of an allocated memoryblock,
  743. had to introduce a flag for such blocks.
  744. * flags are now stored in the first 4 bits instead of the highest bit,
  745. this could be done because the sizes of block are always >= 16
  746. Revision 1.23 1999/11/10 22:29:51 michael
  747. + Fixed sysreallocmem
  748. Revision 1.22 1999/11/01 13:56:50 peter
  749. * freemem,reallocmem now get var argument
  750. Revision 1.21 1999/10/30 17:39:05 peter
  751. * memorymanager expanded with allocmem/reallocmem
  752. Revision 1.20 1999/10/22 22:03:07 sg
  753. * FreeMem(p) is ignored if p is NIL, instead of throwing an
  754. runtime error 204. (Delphi ignores NIL FreeMem's, too)
  755. Revision 1.19 1999/10/01 07:55:54 peter
  756. * fixed memsize which forgot the sizemask
  757. Revision 1.18 1999/09/22 21:59:02 peter
  758. * best match for main freelist
  759. * removed root field, saves 4 bytes per block
  760. * fixed crash in dumpblocks
  761. Revision 1.17 1999/09/20 14:17:37 peter
  762. * fixed growheap freelist addition when heapend-heapptr<blocksize
  763. Revision 1.16 1999/09/17 17:14:12 peter
  764. + new heap manager supporting delphi freemem(pointer)
  765. }