heap.inc 26 KB

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