heap.inc 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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:'FPC_GETMEM'];
  116. begin
  117. MemoryManager.GetMem(p,Size);
  118. end;
  119. procedure FreeMem(Var p:pointer;Size:Longint);[public,alias:'FPC_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(output,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. getmem(tempheap.block,sizeof(tblocks));
  281. getmem(tempheap.nblock,sizeof(tnblocks));
  282. fillchar(tempheap.block^,sizeof(tblocks),0);
  283. fillchar(tempheap.nblock^,sizeof(tnblocks),0);
  284. baseheap.heaporg:=heaporg;
  285. baseheap.heapptr:=heapptr;
  286. baseheap.freelist:=freelist;
  287. baseheap.block:=blocks;
  288. baseheap.nblock:=nblocks;
  289. longint(baseheap.heapend):=((longint(heapend)+longint(heapptr)) div 16)*8;
  290. tempheap.heaporg:=baseheap.heapend;
  291. tempheap.freelist:=nil;
  292. tempheap.heapptr:=tempheap.heaporg;
  293. {$IfDef CHECKHEAP}
  294. tempheap.last_mem:=nil;
  295. tempheap.nb_get:=0;
  296. tempheap.nb_free:=0;
  297. {$EndIf CHECKHEAP}
  298. tempheap.heapend:=heapend;
  299. tempheap.memavail:=longint(tempheap.heapend) - longint(tempheap.heaporg);
  300. tempheap.heapsize:=tempheap.memavail;
  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. { Something to allocate ? }
  491. if size<=0 then
  492. begin
  493. { give an error for < 0 }
  494. if size<0 then
  495. HandleError(204);
  496. p:=heapend;
  497. {$ifdef CHECKHEAP}
  498. goto check_new;
  499. {$else CHECKHEAP}
  500. exit;
  501. {$endif CHECKHEAP}
  502. end;
  503. { temp heap checking }
  504. {$ifdef TEMPHEAP}
  505. if heap_split and not allow_special then
  506. begin
  507. if (@p < otherheap^.heapend) and (@p > otherheap^.heaporg) then
  508. { useful line for the debugger }
  509. writeln('warning : p and @p are in different heaps !');
  510. end;
  511. {$endif TEMPHEAP}
  512. { calc to multiply of 8 }
  513. size:=(size+7) and (not 7);
  514. dec(internal_memavail,size);
  515. { first try heap blocks }
  516. if heapblocks then
  517. begin
  518. { search cache }
  519. if size<=max_size then
  520. begin
  521. s:=size shr 3;
  522. p:=blocks^[s];
  523. if assigned(p) then
  524. begin
  525. blocks^[s]:=pointer(p^);
  526. dec(nblocks^[s]);
  527. {$ifdef CHECKHEAP}
  528. goto check_new;
  529. {$else CHECKHEAP}
  530. exit;
  531. {$endif CHECKHEAP}
  532. end;
  533. end;
  534. end;
  535. { walk free list }
  536. repeat
  537. again:=false;
  538. { search the freelist }
  539. if assigned(freelist) then
  540. begin
  541. last:=nil;
  542. hp:=freelist;
  543. while assigned(hp) do
  544. begin
  545. hpsize:=hp^.size;
  546. { take the first fitting block }
  547. if hpsize>=size then
  548. begin
  549. p:=hp;
  550. { need we the whole block ? }
  551. if (hpsize>size) and heapblocks then
  552. begin
  553. { we must check if we are still below the limit !! }
  554. if hpsize-size<=max_size then
  555. begin
  556. { adjust the list }
  557. if assigned(last) then
  558. last^.next:=hp^.next
  559. else
  560. freelist:=hp^.next;
  561. { insert in chain }
  562. s:=(hpsize-size) div 8;
  563. ppointer(hp+size)^:=blocks^[s];
  564. blocks^[s]:=hp+size;
  565. inc(nblocks^[s]);
  566. end
  567. else
  568. begin
  569. (hp+size)^.size:=hpsize-size;
  570. (hp+size)^.next:=hp^.next;
  571. if assigned(last) then
  572. last^.next:=hp+size
  573. else
  574. freelist:=hp+size;
  575. end;
  576. end
  577. else
  578. begin
  579. {$IfDef CHECKHEAP}
  580. dec(freerecord_list_length);
  581. {$endif CHECKHEAP}
  582. if assigned(last) then
  583. last^.next:=hp^.next
  584. else
  585. freelist:=hp^.next;
  586. end;
  587. {$ifdef CHECKHEAP}
  588. goto check_new;
  589. {$else CHECKHEAP}
  590. exit;
  591. {$endif CHECKHEAP}
  592. end;
  593. last:=hp;
  594. hp:=hp^.next;
  595. end;
  596. end;
  597. { Latly, the top of the heap is checked, to see if there is }
  598. { still memory available. }
  599. if heapend-heapptr<size then
  600. begin
  601. if assigned(heaperror) then
  602. begin
  603. proc:=heaperrorproc(heaperror);
  604. case proc(size) of
  605. 0 : HandleError(203);
  606. 1 : p:=nil;
  607. 2 : again:=true;
  608. end;
  609. end
  610. else
  611. HandleError(203);
  612. end
  613. else
  614. begin
  615. p:=heapptr;
  616. inc(heapptr,size);
  617. end;
  618. until not again;
  619. {$ifdef CHECKHEAP}
  620. check_new:
  621. inc(getmem_nb);
  622. test_memavail;
  623. if trace then
  624. begin
  625. pheap_mem_info(p)^.sig:=$DEADBEEF;
  626. pheap_mem_info(p)^.previous:=last_assigned;
  627. if last_assigned<>nil then
  628. last_assigned^.next:=pheap_mem_info(p);
  629. last_assigned:=p;
  630. pheap_mem_info(p)^.next:=nil;
  631. pheap_mem_info(p)^.size:=orsize;
  632. bp:=get_caller_frame(get_frame);
  633. for i:=1 to tracesize do
  634. begin
  635. pheap_mem_info(p)^.calls[i]:=get_caller_addr(bp);
  636. bp:=get_caller_frame(bp);
  637. end;
  638. inc(p,sizeof(heap_mem_info));
  639. end;
  640. {$endif CHECKHEAP}
  641. end;
  642. {*****************************************************************************
  643. SysFreeMem
  644. *****************************************************************************}
  645. procedure SysFreeMem(var p : pointer;size : longint);
  646. var
  647. hp : pfreerecord;
  648. {$ifdef TEMPHEAP}
  649. heap_switched : boolean;
  650. {$endif TEMPHEAP}
  651. s : longint;
  652. label
  653. freemem_exit;
  654. begin
  655. if size<=0 then
  656. begin
  657. if size<0 then
  658. HandleError(204);
  659. p:=nil;
  660. exit;
  661. end;
  662. if p=nil then
  663. HandleError(204);
  664. {$ifdef CHECKHEAP}
  665. if free_nothing then
  666. begin
  667. p:=nil;
  668. exit;
  669. end;
  670. if trace then
  671. begin
  672. inc(size,sizeof(heap_mem_info));
  673. dec(p,sizeof(heap_mem_info));
  674. end;
  675. {$endif CHECKHEAP}
  676. {$ifdef TEMPHEAP}
  677. heap_switched:=false;
  678. if heap_split and not allow_special then
  679. begin
  680. if (p<=heapptr) and (p>=heaporg) and
  681. (@p<=otherheap^.heapend) and (@p>=otherheap^.heaporg) then
  682. writeln('warning : p and @p are in different heaps !');
  683. end;
  684. if (p<heaporg) or (p>heapptr) then
  685. begin
  686. if heap_split and (p<otherheap^.heapend) and (p>otherheap^.heaporg) then
  687. begin
  688. if (@p>=heaporg) and (@p<=heapptr) and not allow_special then
  689. writeln('warning : p and @p are in different heaps !');
  690. switch_heap;
  691. heap_switched:=true;
  692. end
  693. else
  694. begin
  695. writeln('pointer ',hexstr(longint(@p),8),' at ',hexstr(longint(p),8),' doesn''t points to the heap');
  696. HandleError(204);
  697. end;
  698. end;
  699. {$endif TEMPHEAP}
  700. {$ifdef CHECKHEAP}
  701. if trace then
  702. begin
  703. if not (is_in_getmem_list(p)) then
  704. HandleError(204);
  705. if pheap_mem_info(p)^.sig=$AAAAAAAA then
  706. dump_free(p);
  707. if pheap_mem_info(p)^.next<>nil then
  708. pheap_mem_info(p)^.next^.previous:=pheap_mem_info(p)^.previous;
  709. if pheap_mem_info(p)^.previous<>nil then
  710. pheap_mem_info(p)^.previous^.next:=pheap_mem_info(p)^.next;
  711. if pheap_mem_info(p)=last_assigned then
  712. last_assigned:=last_assigned^.previous;
  713. end;
  714. {$endif CHECKHEAP}
  715. { calc to multiple of 8 }
  716. size:=(size+7) and (not 7);
  717. inc(internal_memavail,size);
  718. { end of the heap ? }
  719. if p+size>=heapptr then
  720. begin
  721. heapptr:=p;
  722. internal_memavail:=internal_heapsize;
  723. goto freemem_exit;
  724. end;
  725. { heap block? }
  726. if heapblocks and (size<=max_size) then
  727. begin
  728. s:=size shr 3;
  729. ppointer(p)^:=blocks^[s];
  730. blocks^[s]:=p;
  731. inc(nblocks^[s]);
  732. end
  733. else
  734. begin
  735. { size can be allways set }
  736. pfreerecord(p)^.size:=size;
  737. { if there is no free list }
  738. if not assigned(freelist) then
  739. begin
  740. { then generate one }
  741. freelist:=p;
  742. pfreerecord(p)^.next:=nil;
  743. {$ifdef CHECKHEAP}
  744. inc(freerecord_list_length);
  745. {$endif CHECKHEAP}
  746. goto freemem_exit;
  747. end;
  748. if p+size<freelist then
  749. begin
  750. pfreerecord(p)^.next:=freelist;
  751. freelist:=p;
  752. {$ifdef CHECKHEAP}
  753. inc(freerecord_list_length);
  754. {$endif CHECKHEAP}
  755. goto freemem_exit;
  756. end
  757. else
  758. if p+size=freelist then
  759. begin
  760. pfreerecord(p)^.size:=Pfreerecord(p)^.size+pfreerecord(freelist)^.size;
  761. pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
  762. freelist:=p;
  763. { but now it can also connect the next block !!}
  764. if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
  765. begin
  766. pfreerecord(p)^.size:=pfreerecord(p)^.size+pfreerecord(p)^.next^.size;
  767. {$ifdef CHECKHEAP}
  768. dec(freerecord_list_length);
  769. {$endif CHECKHEAP}
  770. pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
  771. end;
  772. goto freemem_exit;
  773. end;
  774. { insert block in freelist }
  775. hp:=freelist;
  776. while assigned(hp) do
  777. begin
  778. if p<hp+hp^.size then
  779. begin
  780. {$ifdef CHECKHEAP}
  781. writeln('pointer to dispose at ',hexstr(longint(p),8),' has already been disposed');
  782. {$endif CHECKHEAP}
  783. HandleError(204);
  784. end;
  785. { connecting two blocks ? }
  786. if hp+hp^.size=p then
  787. begin
  788. inc(hp^.size,size);
  789. { connecting also to next block ? }
  790. if hp+hp^.size=hp^.next then
  791. begin
  792. inc(hp^.size,hp^.next^.size);
  793. {$ifdef CHECKHEAP}
  794. dec(freerecord_list_length);
  795. {$endif CHECKHEAP}
  796. hp^.next:=hp^.next^.next;
  797. end
  798. else
  799. if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
  800. begin
  801. {$ifdef CHECKHEAP}
  802. writeln('pointer to dispose at ',hexstr(longint(p),8),' is too big !!');
  803. {$endif CHECKHEAP}
  804. HandleError(204);
  805. end;
  806. break;
  807. end
  808. { if the end is reached, then concat }
  809. else
  810. if hp^.next=nil then
  811. begin
  812. hp^.next:=p;
  813. {$ifdef CHECKHEAP}
  814. inc(freerecord_list_length);
  815. {$endif CHECKHEAP}
  816. pfreerecord(p)^.next:=nil;
  817. break;
  818. end
  819. { if next pointer is greater, then insert }
  820. else
  821. if hp^.next>p then
  822. begin
  823. { connect to blocks }
  824. if p+size=hp^.next then
  825. begin
  826. pfreerecord(p)^.next:=hp^.next^.next;
  827. pfreerecord(p)^.size:=pfreerecord(p)^.size+hp^.next^.size;
  828. { we have to reset the right position }
  829. hp^.next:=pfreerecord(p);
  830. end
  831. else
  832. begin
  833. pfreerecord(p)^.next:=hp^.next;
  834. hp^.next:=p;
  835. {$ifdef CHECKHEAP}
  836. inc(freerecord_list_length);
  837. {$endif CHECKHEAP}
  838. end;
  839. break;
  840. end;
  841. hp:=hp^.next;
  842. end;
  843. end;
  844. freemem_exit:
  845. {$ifdef CHECKHEAP}
  846. inc(freemem_nb);
  847. test_memavail;
  848. {$endif CHECKHEAP}
  849. {$ifdef TEMPHEAP}
  850. if heap_switched then
  851. switch_heap;
  852. {$endif TEMPHEAP}
  853. p:=nil;
  854. end;
  855. {*****************************************************************************
  856. Mark/Release
  857. *****************************************************************************}
  858. procedure release(var p : pointer);
  859. begin
  860. heapptr:=p;
  861. freelist:=nil;
  862. internal_memavail:=calc_memavail;
  863. end;
  864. procedure mark(var p : pointer);
  865. begin
  866. p:=heapptr;
  867. end;
  868. procedure markheap(var oldfreelist,oldheapptr : pointer);
  869. begin
  870. oldheapptr:=heapptr;
  871. oldfreelist:=freelist;
  872. freelist:=nil;
  873. internal_memavail:=calc_memavail;
  874. end;
  875. procedure releaseheap(oldfreelist,oldheapptr : pointer);
  876. begin
  877. heapptr:=oldheapptr;
  878. if longint(freelist) < longint(heapptr) then
  879. begin
  880. { here we should reget the freed blocks }
  881. end;
  882. freelist:=oldfreelist;
  883. internal_memavail:=calc_memavail;
  884. end;
  885. {*****************************************************************************
  886. Grow Heap
  887. *****************************************************************************}
  888. function growheap(size :longint) : integer;
  889. var
  890. {$ifdef CHECKHEAP}
  891. NewLimit,
  892. {$endif CHECKHEAP}
  893. NewPos,
  894. wantedsize : longint;
  895. hp : pfreerecord;
  896. begin
  897. wantedsize:=size;
  898. { Allocate by 64K size }
  899. size:=(size+$fffff) and $ffff0000;
  900. { first try 1Meg }
  901. if size<GrowHeapSize then
  902. begin
  903. NewPos:=Sbrk(GrowHeapSize);
  904. if NewPos>0 then
  905. size:=GrowHeapSize;
  906. end
  907. else
  908. NewPos:=SBrk(size);
  909. { try again }
  910. if NewPos=-1 then
  911. begin
  912. NewPos:=Sbrk(size);
  913. if NewPos=-1 then
  914. begin
  915. GrowHeap:=0;
  916. {$IfDef CHECKHEAP}
  917. writeln('Call to GrowHeap failed');
  918. readln;
  919. {$EndIf CHECKHEAP}
  920. Exit;
  921. end;
  922. end;
  923. { make the room clean }
  924. {$ifdef CHECKHEAP}
  925. Fillword(pointer(NewPos)^,size div 2,$ABCD);
  926. Newlimit:=(newpos+size) or $3fff;
  927. {$endif CHECKHEAP}
  928. hp:=pfreerecord(freelist);
  929. if not assigned(hp) then
  930. begin
  931. if pointer(newpos) = heapend then
  932. heapend:=pointer(newpos+size)
  933. else
  934. begin
  935. if heapend - heapptr > 0 then
  936. begin
  937. freelist:=heapptr;
  938. hp:=pfreerecord(freelist);
  939. hp^.size:=heapend-heapptr;
  940. hp^.next:=nil;
  941. end;
  942. heapptr:=pointer(newpos);
  943. heapend:=pointer(newpos+size);
  944. end;
  945. end
  946. else
  947. begin
  948. if pointer(newpos) = heapend then
  949. heapend:=pointer(newpos+size)
  950. else
  951. begin
  952. while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
  953. hp:=hp^.next;
  954. if hp^.next = nil then
  955. begin
  956. hp^.next:=pfreerecord(heapptr);
  957. hp:=pfreerecord(heapptr);
  958. hp^.size:=heapend-heapptr;
  959. hp^.next:=nil;
  960. heapptr:=pointer(NewPos);
  961. heapend:=pointer(NewPos+Size);
  962. end
  963. else
  964. begin
  965. pfreerecord(NewPos)^.Size:=Size;
  966. pfreerecord(NewPos)^.Next:=hp^.next;
  967. hp^.next:=pfreerecord(NewPos);
  968. end;
  969. end;
  970. end;
  971. { the wanted size has to be substracted
  972. why it will be substracted in the second try
  973. to get the memory PM }
  974. internal_memavail:=calc_memavail;
  975. { set the total new heap size }
  976. inc(internal_heapsize,size);
  977. { try again }
  978. GrowHeap:=2;
  979. {$IfDef CHECKHEAP}
  980. writeln('Call to GrowHeap succedeed : HeapSize = ',internal_heapsize,' MemAvail = ',memavail);
  981. writeln('New heap part begins at ',Newpos,' with size ',size);
  982. if growheapstop then
  983. readln;
  984. {$EndIf CHECKHEAP}
  985. end;
  986. {*****************************************************************************
  987. InitHeap
  988. *****************************************************************************}
  989. { This function will initialize the Heap manager and need to be called from
  990. the initialization of the system unit }
  991. procedure InitHeap;
  992. begin
  993. FillChar(Blocks^,sizeof(Blocks^),0);
  994. FillChar(NBlocks^,sizeof(NBlocks^),0);
  995. {$ifdef TEMPHEAP}
  996. Curheap:=@baseheap;
  997. Otherheap:=@tempheap;
  998. {$endif TEMPHEAP}
  999. internal_heapsize:=GetHeapSize;
  1000. internal_memavail:=internal_heapsize;
  1001. HeapOrg:=GetHeapStart;
  1002. HeapPtr:=HeapOrg;
  1003. HeapEnd:=HeapOrg+internal_memavail;
  1004. HeapError:=@GrowHeap;
  1005. Freelist:=nil;
  1006. end;
  1007. {
  1008. $Log$
  1009. Revision 1.7 1999-03-18 11:21:16 peter
  1010. * memavail fixed for too big freemem calls
  1011. Revision 1.6 1999/02/08 09:31:39 florian
  1012. * fixed small things regarding TEMPHEAP
  1013. Revision 1.5 1999/01/22 12:39:21 pierre
  1014. + added text arg for dump_stack
  1015. Revision 1.4 1998/12/16 00:22:24 peter
  1016. * more temp symbols removed
  1017. Revision 1.3 1998/10/22 23:50:45 peter
  1018. + check for < 0 which otherwise segfaulted
  1019. Revision 1.2 1998/10/01 14:55:17 peter
  1020. + memorymanager like delphi
  1021. Revision 1.1 1998/09/14 10:48:17 peter
  1022. * FPC_ names
  1023. * Heap manager is now system independent
  1024. Revision 1.18 1998/09/08 15:02:48 peter
  1025. * much more readable :)
  1026. Revision 1.17 1998/09/04 17:27:48 pierre
  1027. * small corrections
  1028. Revision 1.16 1998/08/25 14:15:51 pierre
  1029. * corrected a bug introduced by my last change
  1030. (allocating 1Mb but only using a small part !!)
  1031. Revision 1.15 1998/08/24 14:44:04 pierre
  1032. * bug allocation of more than 1 MB failed corrected
  1033. Revision 1.14 1998/07/30 13:26:21 michael
  1034. + Added support for ErrorProc variable. All internal functions are required
  1035. to call HandleError instead of runerror from now on.
  1036. This is necessary for exception support.
  1037. Revision 1.13 1998/07/02 14:24:09 michael
  1038. Undid carls changes, but renamed _heapsize to internal_heapsize. Make cycle now works
  1039. Revision 1.11 1998/06/25 09:26:10 daniel
  1040. * Removed some more tabs
  1041. Revision 1.10 1998/06/24 11:53:26 daniel
  1042. * Removed some tabs.
  1043. Revision 1.9 1998/06/16 14:55:49 daniel
  1044. * Optimizations
  1045. Revision 1.8 1998/06/15 15:15:13 daniel
  1046. * Brought my policy into practive that the RTL should output only runtime
  1047. errors and no other texts when things go wrong.
  1048. Revision 1.7 1998/05/30 15:01:28 peter
  1049. * this needs also direct mode :(
  1050. Revision 1.6 1998/05/25 10:40:48 peter
  1051. * remake3 works again on tflily
  1052. Revision 1.4 1998/04/21 10:22:48 peter
  1053. + heapblocks
  1054. Revision 1.3 1998/04/09 08:32:14 daniel
  1055. * Optimized some code.
  1056. }