heap.inc 31 KB

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