heap.inc 25 KB

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