heap.inc 32 KB

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