heap.inc 29 KB

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