heap.inc 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993-98 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. Supported conditionnals:
  14. ------------------------
  15. TEMPHEAP to allow to split the heap in two parts for easier release
  16. started for the compiler
  17. CHECKHEAP if you want to test the heap integrity
  18. }
  19. { Memory manager }
  20. const
  21. MemoryManager: TMemoryManager = (
  22. GetMem: SysGetMem;
  23. FreeMem: SysFreeMem
  24. );
  25. { Default Heap }
  26. const
  27. max_size = 256;
  28. maxblock = max_size div 8;
  29. type
  30. ppointer = ^pointer;
  31. pfreerecord = ^tfreerecord;
  32. tfreerecord = record
  33. next : pfreerecord;
  34. size : longint;
  35. end;
  36. tblocks = array[1..maxblock] of pointer;
  37. pblocks = ^tblocks;
  38. tnblocks = array[1..maxblock] of longint;
  39. pnblocks = ^tnblocks;
  40. var
  41. internal_memavail : longint;
  42. internal_heapsize : longint;
  43. baseblocks : tblocks;
  44. basenblocks : tnblocks;
  45. const
  46. blocks : pblocks = @baseblocks;
  47. nblocks : pnblocks = @basenblocks;
  48. { Check Heap }
  49. {$IfDef CHECKHEAP}
  50. { 4 levels of tracing }
  51. const
  52. tracesize = 4;
  53. freerecord_list_length : longint = 0;
  54. type
  55. pheap_mem_info = ^heap_mem_info;
  56. heap_mem_info = record
  57. next,
  58. previous : pheap_mem_info;
  59. size : longint;
  60. sig : longint; {dummy number for test }
  61. calls : array [1..tracesize] of longint;
  62. end;
  63. { size 8*4 = 32 }
  64. const
  65. { help variables for debugging with GDB }
  66. check : boolean = false;
  67. growheapstop : boolean = false;
  68. free_nothing : boolean = false;
  69. trace : boolean = true;
  70. var
  71. last_assigned : pheap_mem_info;
  72. getmem_nb : longint;
  73. freemem_nb : longint;
  74. {$EndIf CHECKHEAP}
  75. { Temp Heap }
  76. {$ifdef TEMPHEAP}
  77. const
  78. heap_split : boolean = false;
  79. type
  80. pheapinfo = ^theapinfo;
  81. theapinfo = record
  82. heaporg,heapptr,
  83. heapend,freelist : pointer;
  84. memavail,heapsize : longint;
  85. block : pblocks;
  86. nblock : pnblocks;
  87. {$IfDef CHECKHEAP}
  88. last_mem : pheap_mem_info;
  89. nb_get,
  90. nb_free : longint;
  91. {$EndIf CHECKHEAP}
  92. end;
  93. var
  94. baseheap : theapinfo;
  95. curheap : pheapinfo;
  96. tempheap : theapinfo;
  97. otherheap : pheapinfo;
  98. {$endif TEMPHEAP}
  99. {*****************************************************************************
  100. Memory Manager
  101. *****************************************************************************}
  102. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  103. begin
  104. MemMgr:=MemoryManager;
  105. end;
  106. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  107. begin
  108. MemoryManager:=MemMgr;
  109. end;
  110. function IsMemoryManagerSet:Boolean;
  111. begin
  112. IsMemoryManagerSet:=(MemoryManager.GetMem<>@SysGetMem) or
  113. (MemoryManager.FreeMem<>@SysFreeMem);
  114. end;
  115. procedure GetMem(Var p:pointer;Size:Longint);[public,alias:{$ifdef FPCNAMES}'FPC_'+{$endif}'GETMEM'];
  116. begin
  117. MemoryManager.GetMem(p,Size);
  118. end;
  119. procedure FreeMem(Var p:pointer;Size:Longint);[public,alias:{$ifdef FPCNAMES}'FPC_'+{$endif}'FREEMEM'];
  120. begin
  121. MemoryManager.FreeMem(p,Size);
  122. end;
  123. {*****************************************************************************
  124. Heapsize,Memavail,MaxAvail
  125. *****************************************************************************}
  126. function heapsize : longint;
  127. begin
  128. heapsize:=internal_heapsize;
  129. end;
  130. function memavail : longint;
  131. begin
  132. memavail:=internal_memavail;
  133. end;
  134. function maxavail : longint;
  135. var
  136. hp : pfreerecord;
  137. begin
  138. maxavail:=heapend-heapptr;
  139. hp:=freelist;
  140. while assigned(hp) do
  141. begin
  142. if hp^.size>maxavail then
  143. maxavail:=hp^.size;
  144. hp:=hp^.next;
  145. end;
  146. end;
  147. function calc_memavail : longint;
  148. var
  149. hp : pfreerecord;
  150. ma : longint;
  151. i : longint;
  152. begin
  153. ma:=heapend-heapptr;
  154. { count blocks }
  155. if heapblocks then
  156. for i:=1 to maxblock do
  157. inc(ma,i*8*nblocks^[i]);
  158. { walk freelist }
  159. hp:=freelist;
  160. while assigned(hp) do
  161. begin
  162. inc(ma,hp^.size);
  163. {$IfDef CHECKHEAP}
  164. if (longint(hp^.next)=0) then
  165. begin
  166. if ((longint(hp)+hp^.size)>longint(heapptr)) then
  167. writeln('freerecordlist bad at end ')
  168. end
  169. else
  170. if ((longint(hp^.next)<=(longint(hp)+hp^.size)) or
  171. ((hp^.size and 7) <> 0)) then
  172. writeln('error in freerecord list ');
  173. {$EndIf CHECKHEAP}
  174. hp:=hp^.next;
  175. end;
  176. calc_memavail:=ma;
  177. end;
  178. {*****************************************************************************
  179. Check Heap helpers
  180. *****************************************************************************}
  181. {$IfDef CHECKHEAP}
  182. procedure call_stack(p : pointer);
  183. var
  184. i : longint;
  185. pp : pheap_mem_info;
  186. begin
  187. if trace then
  188. begin
  189. pp:=pheap_mem_info(p-sizeof(heap_mem_info));
  190. writeln('Call trace of 0x',hexstr(longint(p),8));
  191. writeln('of size ',pp^.size);
  192. for i:=1 to tracesize do
  193. writeln(i,' 0x',hexstr(pp^.calls[i],8));
  194. end
  195. else
  196. writeln('tracing not enabled, sorry !!');
  197. end;
  198. procedure dump_heap(mark : boolean);
  199. var
  200. pp : pheap_mem_info;
  201. begin
  202. pp:=last_assigned;
  203. while pp<>nil do
  204. begin
  205. call_stack(pp+sizeof(heap_mem_info));
  206. if mark then
  207. pp^.sig:=$AAAAAAAA;
  208. pp:=pp^.previous;
  209. end;
  210. end;
  211. procedure dump_free(p : pheap_mem_info);
  212. var
  213. ebp : longint;
  214. begin
  215. Writeln('Marked memory at ',HexStr(longint(p),8),' released');
  216. call_stack(p+sizeof(heap_mem_info));
  217. dump_stack(get_caller_frame(get_frame));
  218. end;
  219. function is_in_getmem_list (p : pointer) : boolean;
  220. var
  221. i : longint;
  222. pp : pheap_mem_info;
  223. begin
  224. is_in_getmem_list:=false;
  225. pp:=last_assigned;
  226. i:=0;
  227. while pp<>nil do
  228. begin
  229. if (pp^.sig<>$DEADBEEF) and (pp^.sig <> $AAAAAAAA) then
  230. begin
  231. writeln('error in linked list of heap_mem_info');
  232. HandleError(204);
  233. end
  234. if pp=p then
  235. is_in_getmem_list:=true;
  236. pp:=pp^.previous;
  237. inc(i);
  238. if i > getmem_nb - freemem_nb then
  239. writeln('error in linked list of heap_mem_info');
  240. end;
  241. end;
  242. function is_in_free(p : pointer) : boolean;
  243. var
  244. hp : pfreerecord;
  245. begin
  246. if p>heapptr then
  247. begin
  248. is_in_free:=true;
  249. exit;
  250. end
  251. else
  252. begin
  253. hp:=freelist;
  254. while assigned(hp) do
  255. begin
  256. if (p>=hp) and (p<hp+hp^.size) then
  257. begin
  258. is_in_free:=true;
  259. exit;
  260. end;
  261. hp:=hp^.next;
  262. end;
  263. is_in_free:=false;
  264. end;
  265. end;
  266. procedure test_memavail;
  267. begin
  268. if check and (internal_memavail<>calc_memavail) then
  269. writeln('Memavail error in getmem/freemem');
  270. end;
  271. {$EndIf CHECKHEAP}
  272. {*****************************************************************************
  273. Temp Heap support
  274. *****************************************************************************}
  275. {$ifdef TEMPHEAP}
  276. procedure split_heap;
  277. begin
  278. if not heap_split then
  279. begin
  280. baseheap.heaporg:=heaporg;
  281. baseheap.heapptr:=heapptr;
  282. baseheap.freelist:=freelist;
  283. baseheap.block:=blocks;
  284. baseheap.nblock:=nblocks;
  285. longint(baseheap.heapend):=((longint(heapend)+longint(heapptr)) div 16)*8;
  286. tempheap.heaporg:=baseheap.heapend;
  287. tempheap.freelist:=nil;
  288. tempheap.heapptr:=tempheap.heaporg;
  289. {$IfDef CHECKHEAP}
  290. tempheap.last_mem:=nil;
  291. tempheap.nb_get:=0;
  292. tempheap.nb_free:=0;
  293. {$EndIf CHECKHEAP}
  294. tempheap.heapend:=heapend;
  295. tempheap.memavail:=longint(tempheap.heapend) - longint(tempheap.heaporg);
  296. tempheap.heapsize:=tempheap.memavail;
  297. getmem(tempheap.block,sizeof(tblocks));
  298. getmem(tempheap.nblock,sizeof(tnblocks));
  299. fillchar(tempheap.block^,sizeof(tblocks),0);
  300. fillchar(tempheap.nblock^,sizeof(tnblocks),0);
  301. heapend:=baseheap.heapend;
  302. internal_memavail:=calc_memavail;
  303. baseheap.memavail:=internal_memavail;
  304. baseheap.heapsize:=longint(baseheap.heapend)-longint(baseheap.heaporg);
  305. curheap:=@baseheap;
  306. otherheap:=@tempheap;
  307. heap_split:=true;
  308. end;
  309. end;
  310. procedure switch_to_temp_heap;
  311. begin
  312. if curheap = @baseheap then
  313. begin
  314. baseheap.heaporg:=heaporg;
  315. baseheap.heapend:=heapend;
  316. baseheap.heapptr:=heapptr;
  317. baseheap.freelist:=freelist;
  318. baseheap.memavail:=internal_memavail;
  319. baseheap.block:=blocks;
  320. baseheap.nblock:=nblocks;
  321. {$IfDef CHECKHEAP}
  322. baseheap.last_mem:=last_assigned;
  323. last_assigned:=tempheap.last_mem;
  324. baseheap.nb_get:=getmem_nb;
  325. baseheap.nb_free:=freemem_nb;
  326. getmem_nb:=tempheap.nb_get;
  327. freemem_nb:=tempheap.nb_free;
  328. {$EndIf CHECKHEAP}
  329. heaporg:=tempheap.heaporg;
  330. heapptr:=tempheap.heapptr;
  331. freelist:=tempheap.freelist;
  332. heapend:=tempheap.heapend;
  333. blocks:=tempheap.block;
  334. nblocks:=tempheap.nblock;
  335. internal_memavail:=calc_memavail;
  336. curheap:=@tempheap;
  337. otherheap:=@baseheap;
  338. end;
  339. end;
  340. procedure switch_to_base_heap;
  341. begin
  342. if curheap = @tempheap then
  343. begin
  344. tempheap.heaporg:=heaporg;
  345. tempheap.heapend:=heapend;
  346. tempheap.heapptr:=heapptr;
  347. tempheap.freelist:=freelist;
  348. tempheap.memavail:=internal_memavail;
  349. {$IfDef CHECKHEAP}
  350. tempheap.last_mem:=last_assigned;
  351. last_assigned:=baseheap.last_mem;
  352. tempheap.nb_get:=getmem_nb;
  353. tempheap.nb_free:=freemem_nb;
  354. getmem_nb:=baseheap.nb_get;
  355. freemem_nb:=baseheap.nb_free;
  356. {$EndIf CHECKHEAP}
  357. heaporg:=baseheap.heaporg;
  358. heapptr:=baseheap.heapptr;
  359. freelist:=baseheap.freelist;
  360. heapend:=baseheap.heapend;
  361. blocks:=baseheap.block;
  362. nblocks:=baseheap.nblock;
  363. internal_memavail:=calc_memavail;
  364. curheap:=@baseheap;
  365. otherheap:=@tempheap;
  366. end;
  367. end;
  368. procedure switch_heap;
  369. begin
  370. if not heap_split then
  371. split_heap;
  372. if curheap = @tempheap then
  373. switch_to_base_heap
  374. else
  375. switch_to_temp_heap;
  376. end;
  377. procedure gettempmem(var p : pointer;size : longint);
  378. begin
  379. split_heap;
  380. switch_to_temp_heap;
  381. allow_special:=true;
  382. getmem(p,size);
  383. allow_special:=false;
  384. end;
  385. procedure unsplit_heap;
  386. var
  387. hp,hp2,thp : pfreerecord;
  388. begin
  389. {heapend can be modified by HeapError }
  390. if not heap_split then
  391. exit;
  392. if baseheap.heapend = tempheap.heaporg then
  393. begin
  394. switch_to_base_heap;
  395. hp:=pfreerecord(freelist);
  396. if assigned(hp) then
  397. begin
  398. while assigned(hp^.next) do
  399. hp:=hp^.next;
  400. end;
  401. if tempheap.heapptr<>tempheap.heaporg then
  402. begin
  403. if hp<>nil then
  404. hp^.next:=heapptr;
  405. hp:=pfreerecord(heapptr);
  406. hp^.size:=heapend-heapptr;
  407. hp^.next:=tempheap.freelist;
  408. heapptr:=tempheap.heapptr;
  409. end;
  410. heapend:=tempheap.heapend;
  411. internal_memavail:=calc_memavail;
  412. heap_split:=false;
  413. end
  414. else
  415. begin
  416. hp:=pfreerecord(baseheap.freelist);
  417. hp2:=pfreerecord(tempheap.freelist);
  418. while assigned(hp) and assigned(hp2) do
  419. begin
  420. if hp=hp2 then
  421. break;
  422. if hp>hp2 then
  423. begin
  424. thp:=hp2;
  425. hp2:=hp;
  426. hp:=thp;
  427. end;
  428. while assigned(hp^.next) and (hp^.next<hp2) do
  429. hp:=hp^.next;
  430. if assigned(hp^.next) then
  431. begin
  432. thp:=hp^.next;
  433. hp^.next:=hp2;
  434. hp:=thp;
  435. end
  436. else
  437. begin
  438. hp^.next:=hp2;
  439. hp:=nil;
  440. end;
  441. end;
  442. if heapend < tempheap.heapend then
  443. heapend:=tempheap.heapend;
  444. if heapptr < tempheap.heapptr then
  445. heapptr:=tempheap.heapptr;
  446. freemem(tempheap.block,sizeof(tblocks));
  447. freemem(tempheap.nblock,sizeof(tnblocks));
  448. internal_memavail:=calc_memavail;
  449. heap_split:=false;
  450. end;
  451. end;
  452. procedure releasetempheap;
  453. begin
  454. switch_to_temp_heap;
  455. {$ifdef CHECKHEAP}
  456. if heapptr<>heaporg then
  457. writeln('Warning in releasetempheap : ',longint(tempheap.heapsize)-longint(tempheap.memavail),' bytes used !');
  458. dump_heap(true);
  459. { release(heaporg);
  460. fillchar(heaporg^,longint(heapend)-longint(heaporg),#0); }
  461. {$endif CHECKHEAP }
  462. unsplit_heap;
  463. split_heap;
  464. end;
  465. {$endif TEMPHEAP}
  466. {*****************************************************************************
  467. SysGetMem
  468. *****************************************************************************}
  469. procedure SysGetMem(var p : pointer;size : longint);
  470. type
  471. heaperrorproc=function(size:longint):integer;
  472. var
  473. proc : heaperrorproc;
  474. last,hp : pfreerecord;
  475. again : boolean;
  476. s,hpsize : longint;
  477. {$IfDef CHECKHEAP}
  478. i,bp,orsize : longint;
  479. label
  480. check_new;
  481. {$endif CHECKHEAP}
  482. begin
  483. {$ifdef CHECKHEAP}
  484. if trace then
  485. begin
  486. orsize:=size;
  487. inc(size,sizeof(heap_mem_info));
  488. end;
  489. {$endif CHECKHEAP}
  490. if size=0 then
  491. begin
  492. p:=heapend;
  493. {$ifdef CHECKHEAP}
  494. goto check_new;
  495. {$else CHECKHEAP}
  496. exit;
  497. {$endif CHECKHEAP}
  498. end;
  499. { temp heap checking }
  500. {$ifdef TEMPHEAP}
  501. if heap_split and not allow_special then
  502. begin
  503. if (@p < otherheap^.heapend) and (@p > otherheap^.heaporg) then
  504. { useful line for the debugger }
  505. writeln('warning : p and @p are in different heaps !');
  506. end;
  507. {$endif TEMPHEAP}
  508. { calc to multiply of 8 }
  509. size:=(size+7) and (not 7);
  510. dec(internal_memavail,size);
  511. { first try heap blocks }
  512. if heapblocks then
  513. begin
  514. { search cache }
  515. if size<=max_size then
  516. begin
  517. s:=size shr 3;
  518. p:=blocks^[s];
  519. if assigned(p) then
  520. begin
  521. blocks^[s]:=pointer(p^);
  522. dec(nblocks^[s]);
  523. {$ifdef CHECKHEAP}
  524. goto check_new;
  525. {$else CHECKHEAP}
  526. exit;
  527. {$endif CHECKHEAP}
  528. end;
  529. end;
  530. end;
  531. { walk free list }
  532. repeat
  533. again:=false;
  534. { search the freelist }
  535. if assigned(freelist) then
  536. begin
  537. last:=nil;
  538. hp:=freelist;
  539. while assigned(hp) do
  540. begin
  541. hpsize:=hp^.size;
  542. { take the first fitting block }
  543. if hpsize>=size then
  544. begin
  545. p:=hp;
  546. { need we the whole block ? }
  547. if (hpsize>size) and heapblocks then
  548. begin
  549. { we must check if we are still below the limit !! }
  550. if hpsize-size<=max_size then
  551. begin
  552. { adjust the list }
  553. if assigned(last) then
  554. last^.next:=hp^.next
  555. else
  556. freelist:=hp^.next;
  557. { insert in chain }
  558. s:=(hpsize-size) div 8;
  559. ppointer(hp+size)^:=blocks^[s];
  560. blocks^[s]:=hp+size;
  561. inc(nblocks^[s]);
  562. end
  563. else
  564. begin
  565. (hp+size)^.size:=hpsize-size;
  566. (hp+size)^.next:=hp^.next;
  567. if assigned(last) then
  568. last^.next:=hp+size
  569. else
  570. freelist:=hp+size;
  571. end;
  572. end
  573. else
  574. begin
  575. {$IfDef CHECKHEAP}
  576. dec(freerecord_list_length);
  577. {$endif CHECKHEAP}
  578. if assigned(last) then
  579. last^.next:=hp^.next
  580. else
  581. freelist:=hp^.next;
  582. end;
  583. {$ifdef CHECKHEAP}
  584. goto check_new;
  585. {$else CHECKHEAP}
  586. exit;
  587. {$endif CHECKHEAP}
  588. end;
  589. last:=hp;
  590. hp:=hp^.next;
  591. end;
  592. end;
  593. { Latly, the top of the heap is checked, to see if there is }
  594. { still memory available. }
  595. if heapend-heapptr<size then
  596. begin
  597. if assigned(heaperror) then
  598. begin
  599. proc:=heaperrorproc(heaperror);
  600. case proc(size) of
  601. 0 : HandleError(203);
  602. 1 : p:=nil;
  603. 2 : again:=true;
  604. end;
  605. end
  606. else
  607. HandleError(203);
  608. end
  609. else
  610. begin
  611. p:=heapptr;
  612. inc(heapptr,size);
  613. end;
  614. until not again;
  615. {$ifdef CHECKHEAP}
  616. check_new:
  617. inc(getmem_nb);
  618. test_memavail;
  619. if trace then
  620. begin
  621. pheap_mem_info(p)^.sig:=$DEADBEEF;
  622. pheap_mem_info(p)^.previous:=last_assigned;
  623. if last_assigned<>nil then
  624. last_assigned^.next:=pheap_mem_info(p);
  625. last_assigned:=p;
  626. pheap_mem_info(p)^.next:=nil;
  627. pheap_mem_info(p)^.size:=orsize;
  628. bp:=get_caller_frame(get_frame);
  629. for i:=1 to tracesize do
  630. begin
  631. pheap_mem_info(p)^.calls[i]:=get_caller_addr(bp);
  632. bp:=get_caller_frame(bp);
  633. end;
  634. inc(p,sizeof(heap_mem_info));
  635. end;
  636. {$endif CHECKHEAP}
  637. end;
  638. {*****************************************************************************
  639. SysFreeMem
  640. *****************************************************************************}
  641. procedure SysFreeMem(var p : pointer;size : longint);
  642. var
  643. hp : pfreerecord;
  644. {$ifdef TEMPHEAP}
  645. heap_switched : boolean;
  646. {$endif TEMPHEAP}
  647. s : longint;
  648. label
  649. freemem_exit;
  650. begin
  651. if size=0 then
  652. begin
  653. p:=nil;
  654. exit;
  655. end;
  656. if p=nil then
  657. HandleError(204);
  658. {$ifdef CHECKHEAP}
  659. if free_nothing then
  660. begin
  661. p:=nil;
  662. exit;
  663. end;
  664. if trace then
  665. begin
  666. inc(size,sizeof(heap_mem_info));
  667. dec(p,sizeof(heap_mem_info));
  668. end;
  669. {$endif CHECKHEAP}
  670. {$ifdef TEMPHEAP}
  671. heap_switched:=false;
  672. if heap_split and not allow_special then
  673. begin
  674. if (p<=heapptr) and (p>=heaporg) and
  675. (@p<=otherheap^.heapend) and (@p>=otherheap^.heaporg) then
  676. writeln('warning : p and @p are in different heaps !');
  677. end;
  678. if (p<heaporg) or (p>heapptr) then
  679. begin
  680. if heap_split and (p<otherheap^.heapend) and (p>otherheap^.heaporg) then
  681. begin
  682. if (@p>=heaporg) and (@p<=heapptr) and not allow_special then
  683. writeln('warning : p and @p are in different heaps !');
  684. switch_heap;
  685. heap_switched:=true;
  686. end
  687. else
  688. begin
  689. writeln('pointer ',hexstr(longint(@p),8),' at ',hexstr(longint(p),8),' doesn''t points to the heap');
  690. HandleError(204);
  691. end;
  692. end;
  693. {$endif TEMPHEAP}
  694. {$ifdef CHECKHEAP}
  695. if trace then
  696. begin
  697. if not (is_in_getmem_list(p)) then
  698. HandleError(204);
  699. if pheap_mem_info(p)^.sig=$AAAAAAAA then
  700. dump_free(p);
  701. if pheap_mem_info(p)^.next<>nil then
  702. pheap_mem_info(p)^.next^.previous:=pheap_mem_info(p)^.previous;
  703. if pheap_mem_info(p)^.previous<>nil then
  704. pheap_mem_info(p)^.previous^.next:=pheap_mem_info(p)^.next;
  705. if pheap_mem_info(p)=last_assigned then
  706. last_assigned:=last_assigned^.previous;
  707. end;
  708. {$endif CHECKHEAP}
  709. { calc to multiple of 8 }
  710. size:=(size+7) and (not 7);
  711. inc(internal_memavail,size);
  712. { end of the heap ? }
  713. if p+size>=heapptr then
  714. begin
  715. heapptr:=p;
  716. goto freemem_exit;
  717. end;
  718. { heap block? }
  719. if heapblocks and (size<=max_size) then
  720. begin
  721. s:=size shr 3;
  722. ppointer(p)^:=blocks^[s];
  723. blocks^[s]:=p;
  724. inc(nblocks^[s]);
  725. end
  726. else
  727. begin
  728. { size can be allways set }
  729. pfreerecord(p)^.size:=size;
  730. { if there is no free list }
  731. if not assigned(freelist) then
  732. begin
  733. { then generate one }
  734. freelist:=p;
  735. pfreerecord(p)^.next:=nil;
  736. {$ifdef CHECKHEAP}
  737. inc(freerecord_list_length);
  738. {$endif CHECKHEAP}
  739. goto freemem_exit;
  740. end;
  741. if p+size<freelist then
  742. begin
  743. pfreerecord(p)^.next:=freelist;
  744. freelist:=p;
  745. {$ifdef CHECKHEAP}
  746. inc(freerecord_list_length);
  747. {$endif CHECKHEAP}
  748. goto freemem_exit;
  749. end
  750. else
  751. if p+size=freelist then
  752. begin
  753. pfreerecord(p)^.size:=Pfreerecord(p)^.size+pfreerecord(freelist)^.size;
  754. pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
  755. freelist:=p;
  756. { but now it can also connect the next block !!}
  757. if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
  758. begin
  759. pfreerecord(p)^.size:=pfreerecord(p)^.size+pfreerecord(p)^.next^.size;
  760. {$ifdef CHECKHEAP}
  761. dec(freerecord_list_length);
  762. {$endif CHECKHEAP}
  763. pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
  764. end;
  765. goto freemem_exit;
  766. end;
  767. { insert block in freelist }
  768. hp:=freelist;
  769. while assigned(hp) do
  770. begin
  771. if p<hp+hp^.size then
  772. begin
  773. {$ifdef CHECKHEAP}
  774. writeln('pointer to dispose at ',hexstr(longint(p),8),' has already been disposed');
  775. {$endif CHECKHEAP}
  776. HandleError(204);
  777. end;
  778. { connecting two blocks ? }
  779. if hp+hp^.size=p then
  780. begin
  781. inc(hp^.size,size);
  782. { connecting also to next block ? }
  783. if hp+hp^.size=hp^.next then
  784. begin
  785. inc(hp^.size,hp^.next^.size);
  786. {$ifdef CHECKHEAP}
  787. dec(freerecord_list_length);
  788. {$endif CHECKHEAP}
  789. hp^.next:=hp^.next^.next;
  790. end
  791. else
  792. if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
  793. begin
  794. {$ifdef CHECKHEAP}
  795. writeln('pointer to dispose at ',hexstr(longint(p),8),' is too big !!');
  796. {$endif CHECKHEAP}
  797. HandleError(204);
  798. end;
  799. break;
  800. end
  801. { if the end is reached, then concat }
  802. else
  803. if hp^.next=nil then
  804. begin
  805. hp^.next:=p;
  806. {$ifdef CHECKHEAP}
  807. inc(freerecord_list_length);
  808. {$endif CHECKHEAP}
  809. pfreerecord(p)^.next:=nil;
  810. break;
  811. end
  812. { if next pointer is greater, then insert }
  813. else
  814. if hp^.next>p then
  815. begin
  816. { connect to blocks }
  817. if p+size=hp^.next then
  818. begin
  819. pfreerecord(p)^.next:=hp^.next^.next;
  820. pfreerecord(p)^.size:=pfreerecord(p)^.size+hp^.next^.size;
  821. { we have to reset the right position }
  822. hp^.next:=pfreerecord(p);
  823. end
  824. else
  825. begin
  826. pfreerecord(p)^.next:=hp^.next;
  827. hp^.next:=p;
  828. {$ifdef CHECKHEAP}
  829. inc(freerecord_list_length);
  830. {$endif CHECKHEAP}
  831. end;
  832. break;
  833. end;
  834. hp:=hp^.next;
  835. end;
  836. end;
  837. freemem_exit:
  838. {$ifdef CHECKHEAP}
  839. inc(freemem_nb);
  840. test_memavail;
  841. {$endif CHECKHEAP}
  842. {$ifdef TEMPHEAP}
  843. if heap_switched then
  844. switch_heap;
  845. {$endif TEMPHEAP}
  846. p:=nil;
  847. end;
  848. {*****************************************************************************
  849. Mark/Release
  850. *****************************************************************************}
  851. procedure release(var p : pointer);
  852. begin
  853. heapptr:=p;
  854. freelist:=nil;
  855. internal_memavail:=calc_memavail;
  856. end;
  857. procedure mark(var p : pointer);
  858. begin
  859. p:=heapptr;
  860. end;
  861. procedure markheap(var oldfreelist,oldheapptr : pointer);
  862. begin
  863. oldheapptr:=heapptr;
  864. oldfreelist:=freelist;
  865. freelist:=nil;
  866. internal_memavail:=calc_memavail;
  867. end;
  868. procedure releaseheap(oldfreelist,oldheapptr : pointer);
  869. begin
  870. heapptr:=oldheapptr;
  871. if longint(freelist) < longint(heapptr) then
  872. begin
  873. { here we should reget the freed blocks }
  874. end;
  875. freelist:=oldfreelist;
  876. internal_memavail:=calc_memavail;
  877. end;
  878. {*****************************************************************************
  879. Grow Heap
  880. *****************************************************************************}
  881. function growheap(size :longint) : integer;
  882. var
  883. {$ifdef CHECKHEAP}
  884. NewLimit,
  885. {$endif CHECKHEAP}
  886. NewPos,
  887. wantedsize : longint;
  888. hp : pfreerecord;
  889. begin
  890. wantedsize:=size;
  891. { Allocate by 64K size }
  892. size:=(size+$fffff) and $ffff0000;
  893. { first try 1Meg }
  894. if size<GrowHeapSize then
  895. begin
  896. NewPos:=Sbrk(GrowHeapSize);
  897. if NewPos>0 then
  898. size:=GrowHeapSize;
  899. end
  900. else
  901. NewPos:=SBrk(size);
  902. { try again }
  903. if NewPos=-1 then
  904. begin
  905. NewPos:=Sbrk(size);
  906. if NewPos=-1 then
  907. begin
  908. GrowHeap:=0;
  909. {$IfDef CHECKHEAP}
  910. writeln('Call to GrowHeap failed');
  911. readln;
  912. {$EndIf CHECKHEAP}
  913. Exit;
  914. end;
  915. end;
  916. { make the room clean }
  917. {$ifdef CHECKHEAP}
  918. Fillword(pointer(NewPos)^,size div 2,$ABCD);
  919. Newlimit:=(newpos+size) or $3fff;
  920. {$endif CHECKHEAP}
  921. hp:=pfreerecord(freelist);
  922. if not assigned(hp) then
  923. begin
  924. if pointer(newpos) = heapend then
  925. heapend:=pointer(newpos+size)
  926. else
  927. begin
  928. if heapend - heapptr > 0 then
  929. begin
  930. freelist:=heapptr;
  931. hp:=pfreerecord(freelist);
  932. hp^.size:=heapend-heapptr;
  933. hp^.next:=nil;
  934. end;
  935. heapptr:=pointer(newpos);
  936. heapend:=pointer(newpos+size);
  937. end;
  938. end
  939. else
  940. begin
  941. if pointer(newpos) = heapend then
  942. heapend:=pointer(newpos+size)
  943. else
  944. begin
  945. while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
  946. hp:=hp^.next;
  947. if hp^.next = nil then
  948. begin
  949. hp^.next:=pfreerecord(heapptr);
  950. hp:=pfreerecord(heapptr);
  951. hp^.size:=heapend-heapptr;
  952. hp^.next:=nil;
  953. heapptr:=pointer(NewPos);
  954. heapend:=pointer(NewPos+Size);
  955. end
  956. else
  957. begin
  958. pfreerecord(NewPos)^.Size:=Size;
  959. pfreerecord(NewPos)^.Next:=hp^.next;
  960. hp^.next:=pfreerecord(NewPos);
  961. end;
  962. end;
  963. end;
  964. { the wanted size has to be substracted
  965. why it will be substracted in the second try
  966. to get the memory PM }
  967. internal_memavail:=calc_memavail;
  968. { set the total new heap size }
  969. inc(internal_heapsize,size);
  970. { try again }
  971. GrowHeap:=2;
  972. {$IfDef CHECKHEAP}
  973. writeln('Call to GrowHeap succedeed : HeapSize = ',internal_heapsize,' MemAvail = ',memavail);
  974. writeln('New heap part begins at ',Newpos,' with size ',size);
  975. if growheapstop then
  976. readln;
  977. {$EndIf CHECKHEAP}
  978. end;
  979. {*****************************************************************************
  980. InitHeap
  981. *****************************************************************************}
  982. { This function will initialize the Heap manager and need to be called from
  983. the initialization of the system unit }
  984. procedure InitHeap;
  985. begin
  986. FillChar(Blocks^,sizeof(Blocks^),0);
  987. FillChar(NBlocks^,sizeof(NBlocks^),0);
  988. {$ifdef TEMPHEAP}
  989. Curheap:=@baseheap;
  990. Otherheap:=@tempheap;
  991. {$endif TEMPHEAP}
  992. internal_heapsize:=GetHeapSize;
  993. internal_memavail:=internal_heapsize;
  994. HeapOrg:=GetHeapStart;
  995. HeapPtr:=HeapOrg;
  996. HeapEnd:=HeapOrg+internal_memavail;
  997. HeapError:=@GrowHeap;
  998. Freelist:=nil;
  999. end;
  1000. {
  1001. $Log$
  1002. Revision 1.2 1998-10-01 14:55:17 peter
  1003. + memorymanager like delphi
  1004. Revision 1.1 1998/09/14 10:48:17 peter
  1005. * FPC_ names
  1006. * Heap manager is now system independent
  1007. Revision 1.18 1998/09/08 15:02:48 peter
  1008. * much more readable :)
  1009. Revision 1.17 1998/09/04 17:27:48 pierre
  1010. * small corrections
  1011. Revision 1.16 1998/08/25 14:15:51 pierre
  1012. * corrected a bug introduced by my last change
  1013. (allocating 1Mb but only using a small part !!)
  1014. Revision 1.15 1998/08/24 14:44:04 pierre
  1015. * bug allocation of more than 1 MB failed corrected
  1016. Revision 1.14 1998/07/30 13:26:21 michael
  1017. + Added support for ErrorProc variable. All internal functions are required
  1018. to call HandleError instead of runerror from now on.
  1019. This is necessary for exception support.
  1020. Revision 1.13 1998/07/02 14:24:09 michael
  1021. Undid carls changes, but renamed _heapsize to internal_heapsize. Make cycle now works
  1022. Revision 1.11 1998/06/25 09:26:10 daniel
  1023. * Removed some more tabs
  1024. Revision 1.10 1998/06/24 11:53:26 daniel
  1025. * Removed some tabs.
  1026. Revision 1.9 1998/06/16 14:55:49 daniel
  1027. * Optimizations
  1028. Revision 1.8 1998/06/15 15:15:13 daniel
  1029. * Brought my policy into practive that the RTL should output only runtime
  1030. errors and no other texts when things go wrong.
  1031. Revision 1.7 1998/05/30 15:01:28 peter
  1032. * this needs also direct mode :(
  1033. Revision 1.6 1998/05/25 10:40:48 peter
  1034. * remake3 works again on tflily
  1035. Revision 1.4 1998/04/21 10:22:48 peter
  1036. + heapblocks
  1037. Revision 1.3 1998/04/09 08:32:14 daniel
  1038. * Optimized some code.
  1039. }