heap.inc 32 KB

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