heap.inc 28 KB

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