heap.inc 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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. _internal_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. { Get start address of HEAP, this works well }
  97. { with AMIGA, ATARI, but for the MAC, the }
  98. { HEAP is a pointer!!! }
  99. {$IFNDEF MACOS}
  100. function getheapstart : pointer; assembler;
  101. asm
  102. lea.l HEAP,a0
  103. move.l a0,d0
  104. end;
  105. {$ELSE}
  106. function getheapstart : pointer; assembler;
  107. asm
  108. move.l HEAP,d0
  109. end;
  110. {$ENDIF MACOS}
  111. function getheapsize : longint; assembler;
  112. asm
  113. move.l HEAP_SIZE,d0
  114. end ['d0'];
  115. function heapsize : longint;
  116. begin
  117. heapsize:=_internal_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 bp : longint;
  151. begin
  152. Writeln('Marked memory at ',HexStr(longint(p),8),' released');
  153. call_stack(p+sizeof(heap_mem_info));
  154. asm
  155. move.l (a6),a0
  156. move.l (a0),d0
  157. move.l d0,bp
  158. end;
  159. dump_stack(bp);
  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. i,ma : longint;
  214. begin
  215. ma:=heapend-heapptr;
  216. {$ifdef UseBlocks}
  217. for i:=1 to maxblock do
  218. ma:=ma+i*8*nblocks^[i];
  219. {$endif UseBlocks}
  220. hp:=freelist;
  221. while assigned(hp) do
  222. begin
  223. ma:=ma+hp^.size;
  224. {$IfDef CHECKHEAP}
  225. if (longint(hp^.next)=0) then
  226. begin
  227. if ((longint(hp)+hp^.size)>longint(heapptr)) then
  228. writeln('freerecordlist bad at end ')
  229. end
  230. else
  231. if ((longint(hp^.next)<=(longint(hp)+hp^.size)) or
  232. ((hp^.size mod 8) <> 0)) then
  233. writeln('error in freerecord list ');
  234. {$EndIf CHECKHEAP}
  235. hp:=hp^.next;
  236. end;
  237. cal_memavail:=ma;
  238. end;
  239. {$ifdef TEMPHEAP}
  240. procedure split_heap;
  241. var i :longint;
  242. begin
  243. if not heap_split then
  244. begin
  245. baseheap.heaporg:=heaporg;
  246. baseheap.heapptr:=heapptr;
  247. baseheap.freelist:=freelist;
  248. baseheap.block:=blocks;
  249. baseheap.nblock:=nblocks;
  250. longint(baseheap.heapend):=((longint(heapend)+longint(heapptr)) div 16)*8;
  251. tempheap.heaporg:=baseheap.heapend;
  252. tempheap.freelist:=nil;
  253. tempheap.heapptr:=tempheap.heaporg;
  254. {$IfDef CHECKHEAP}
  255. tempheap.last_mem:=nil;
  256. tempheap.nb_get:=0;
  257. tempheap.nb_free:=0;
  258. {$EndIf CHECKHEAP}
  259. tempheap.heapend:=heapend;
  260. tempheap.memavail:=longint(tempheap.heapend) - longint(tempheap.heaporg);
  261. tempheap.heapsize:=tempheap.memavail;
  262. getmem(tempheap.block,sizeof(tblocks));
  263. getmem(tempheap.nblock,sizeof(tnblocks));
  264. for i:=1 to maxblock do
  265. begin
  266. tempheap.block^[i]:=nil;
  267. tempheap.nblock^[i]:=0;
  268. end;
  269. heapend:=baseheap.heapend;
  270. _memavail:=cal_memavail;
  271. baseheap.memavail:=_memavail;
  272. baseheap.heapsize:=longint(baseheap.heapend)-longint(baseheap.heaporg);
  273. curheap:=@baseheap;
  274. otherheap:=@tempheap;
  275. heap_split:=true;
  276. end;
  277. end;
  278. procedure switch_to_temp_heap;
  279. begin
  280. if curheap = @baseheap then
  281. begin
  282. baseheap.heaporg:=heaporg;
  283. baseheap.heapend:=heapend;
  284. baseheap.heapptr:=heapptr;
  285. baseheap.freelist:=freelist;
  286. baseheap.memavail:=_memavail;
  287. baseheap.block:=blocks;
  288. baseheap.nblock:=nblocks;
  289. {$IfDef CHECKHEAP}
  290. baseheap.last_mem:=last_assigned;
  291. last_assigned:=tempheap.last_mem;
  292. baseheap.nb_get:=getmem_nb;
  293. baseheap.nb_free:=freemem_nb;
  294. getmem_nb:=tempheap.nb_get;
  295. freemem_nb:=tempheap.nb_free;
  296. {$EndIf CHECKHEAP}
  297. heaporg:=tempheap.heaporg;
  298. heapptr:=tempheap.heapptr;
  299. freelist:=tempheap.freelist;
  300. heapend:=tempheap.heapend;
  301. blocks:=tempheap.block;
  302. nblocks:=tempheap.nblock;
  303. _memavail:=cal_memavail;
  304. curheap:=@tempheap;
  305. otherheap:=@baseheap;
  306. end;
  307. end;
  308. procedure switch_to_base_heap;
  309. begin
  310. if curheap = @tempheap then
  311. begin
  312. tempheap.heaporg:=heaporg;
  313. tempheap.heapend:=heapend;
  314. tempheap.heapptr:=heapptr;
  315. tempheap.freelist:=freelist;
  316. tempheap.memavail:=_memavail;
  317. {$IfDef CHECKHEAP}
  318. tempheap.last_mem:=last_assigned;
  319. last_assigned:=baseheap.last_mem;
  320. tempheap.nb_get:=getmem_nb;
  321. tempheap.nb_free:=freemem_nb;
  322. getmem_nb:=baseheap.nb_get;
  323. freemem_nb:=baseheap.nb_free;
  324. {$EndIf CHECKHEAP}
  325. heaporg:=baseheap.heaporg;
  326. heapptr:=baseheap.heapptr;
  327. freelist:=baseheap.freelist;
  328. heapend:=baseheap.heapend;
  329. blocks:=baseheap.block;
  330. nblocks:=baseheap.nblock;
  331. _memavail:=cal_memavail;
  332. curheap:=@baseheap;
  333. otherheap:=@tempheap;
  334. end;
  335. end;
  336. procedure switch_heap;
  337. begin
  338. if not heap_split then split_heap;
  339. if curheap = @tempheap then
  340. switch_to_base_heap
  341. else
  342. switch_to_temp_heap;
  343. end;
  344. procedure gettempmem(var p : pointer;size : longint);
  345. begin
  346. split_heap;
  347. switch_to_temp_heap;
  348. allow_special:=true;
  349. getmem(p,size);
  350. allow_special:=false;
  351. end;
  352. {$endif TEMPHEAP}
  353. function memavail : longint;
  354. begin
  355. memavail:=_memavail;
  356. end;
  357. {$ifdef TEMPHEAP}
  358. procedure unsplit_heap;
  359. var hp,hp2,thp : pfreerecord;
  360. begin
  361. {heapend can be modified by HeapError }
  362. if not heap_split then exit;
  363. if baseheap.heapend = tempheap.heaporg then
  364. begin
  365. switch_to_base_heap;
  366. hp:=pfreerecord(freelist);
  367. if assigned(hp) then
  368. while assigned(hp^.next) do hp:=hp^.next;
  369. if tempheap.heapptr<>tempheap.heaporg then
  370. begin
  371. if hp<>nil then
  372. hp^.next:=heapptr;
  373. hp:=pfreerecord(heapptr);
  374. hp^.size:=heapend-heapptr;
  375. hp^.next:=tempheap.freelist;
  376. heapptr:=tempheap.heapptr;
  377. end;
  378. heapend:=tempheap.heapend;
  379. _memavail:=cal_memavail;
  380. heap_split:=false;
  381. end else
  382. begin
  383. hp:=pfreerecord(baseheap.freelist);
  384. hp2:=pfreerecord(tempheap.freelist);
  385. while assigned(hp) and assigned(hp2) do
  386. begin
  387. if hp=hp2 then break;
  388. if hp>hp2 then
  389. begin
  390. thp:=hp2;
  391. hp2:=hp;
  392. hp:=thp;
  393. end;
  394. while assigned(hp^.next) and (hp^.next<hp2) do
  395. hp:=hp^.next;
  396. if assigned(hp^.next) then
  397. begin
  398. thp:=hp^.next;
  399. hp^.next:=hp2;
  400. hp:=thp;
  401. end else
  402. begin
  403. hp^.next:=hp2;
  404. hp:=nil;
  405. end;
  406. end ;
  407. if heapend < tempheap.heapend then
  408. heapend:=tempheap.heapend;
  409. if heapptr < tempheap.heapptr then
  410. heapptr:=tempheap.heapptr;
  411. freemem(tempheap.block,sizeof(tblocks));
  412. freemem(tempheap.nblock,sizeof(tnblocks));
  413. _memavail:=cal_memavail;
  414. heap_split:=false;
  415. end;
  416. end;
  417. procedure releasetempheap;
  418. begin
  419. switch_to_temp_heap;
  420. {$ifdef CHECKHEAP}
  421. if heapptr<>heaporg then
  422. writeln('Warning in releasetempheap : ',longint(tempheap.heapsize)-longint(tempheap.memavail),' bytes used !');
  423. dump_heap(true);
  424. { release(heaporg);
  425. fillchar(heaporg^,longint(heapend)-longint(heaporg),#0);}
  426. {$endif CHECKHEAP }
  427. unsplit_heap;
  428. split_heap;
  429. end;
  430. {$endif TEMPHEAP}
  431. function maxavail : longint;
  432. var
  433. hp : pfreerecord;
  434. begin
  435. maxavail:=heapend-heapptr;
  436. hp:=freelist;
  437. while assigned(hp) do
  438. begin
  439. if hp^.size>maxavail then
  440. maxavail:=hp^.size;
  441. hp:=hp^.next;
  442. end;
  443. end;
  444. {$ifdef CHECKHEAP}
  445. procedure test_memavail;
  446. begin
  447. if check and (_memavail<>cal_memavail) then
  448. begin
  449. writeln('Memavail error in getmem/freemem');
  450. end;
  451. end;
  452. {$endif CHECKHEAP}
  453. procedure getmem(var p : pointer;size : longint);[public,alias: 'GETMEM'];
  454. {$IfDef CHECKHEAP}
  455. var i,bp,orsize : longint;
  456. label check_new;
  457. {$endif CHECKHEAP}
  458. { changed to removed the OS conditionnals }
  459. function call_heaperror(addr : pointer; size : longint) : integer;
  460. begin
  461. asm
  462. pea.l size
  463. move.l addr,a0
  464. jsr (a0)
  465. move.w d0,@Result
  466. end;
  467. end;
  468. var
  469. last,hp : pfreerecord;
  470. nochmal : boolean;
  471. s : longint;
  472. begin
  473. {$ifdef CHECKHEAP}
  474. if trace then
  475. begin
  476. orsize:=size;
  477. size:=size+sizeof(heap_mem_info);
  478. end;
  479. {$endif CHECKHEAP}
  480. if size=0 then
  481. begin
  482. p:=heapend;
  483. {$ifdef CHECKHEAP}
  484. goto check_new;
  485. {$else CHECKHEAP}
  486. exit;
  487. {$endif CHECKHEAP}
  488. end;
  489. {$ifdef TEMPHEAP}
  490. if heap_split and not allow_special then
  491. begin
  492. if (@p < otherheap^.heapend) and
  493. (@p > otherheap^.heaporg) then
  494. { useful line for the debugger }
  495. writeln('warning : p and @p are in different heaps !');
  496. end;
  497. {$endif TEMPHEAP}
  498. { calc to multiply of 8 }
  499. if (size mod 8)<>0 then
  500. size:=size+(8-(size mod 8));
  501. dec(_memavail,size);
  502. {$ifdef UseBlocks}
  503. { search cache }
  504. if size<=max_size then
  505. begin
  506. s:=size div 8;
  507. if assigned(blocks^[s]) then
  508. begin
  509. p:=blocks^[s];
  510. blocks^[s]:=pointer(blocks^[s]^);
  511. dec(nblocks^[s]);
  512. {$ifdef CHECKHEAP}
  513. goto check_new;
  514. {$else CHECKHEAP}
  515. exit;
  516. {$endif CHECKHEAP}
  517. end;
  518. end;
  519. {$endif UseBlocks}
  520. repeat
  521. nochmal:=false;
  522. { search the freelist }
  523. if assigned(freelist) then
  524. begin
  525. last:=nil;
  526. hp:=freelist;
  527. while assigned(hp) do
  528. begin
  529. { take the first fitting block }
  530. if hp^.size>=size then
  531. begin
  532. p:=hp;
  533. { need we the whole block ? }
  534. if hp^.size>size then
  535. begin
  536. {$ifdef UseBlocks}
  537. { we must check if we are still below the limit !! }
  538. if hp^.size-size<=max_size then
  539. begin
  540. { adjust the list }
  541. if assigned(last) then
  542. last^.next:=hp^.next
  543. else
  544. freelist:=hp^.next;
  545. { insert in chain }
  546. s:=(hp^.size-size) div 8;
  547. ppointer(hp+size)^:=blocks^[s];
  548. blocks^[s]:=hp+size;
  549. inc(nblocks^[s]);
  550. end
  551. else
  552. {$endif UseBlocks}
  553. begin
  554. (hp+size)^.size:=hp^.size-size;
  555. (hp+size)^.next:=hp^.next;
  556. if assigned(last) then
  557. last^.next:=hp+size
  558. else
  559. freelist:=hp+size;
  560. end;
  561. end
  562. else
  563. begin
  564. {$IfDef CHECKHEAP}
  565. dec(freerecord_list_length);
  566. {$endif CHECKHEAP}
  567. if assigned(last) then
  568. last^.next:=hp^.next
  569. else
  570. {this was wrong !!}
  571. {freelist:=nil;}
  572. freelist:=hp^.next;
  573. end;
  574. {$ifdef CHECKHEAP}
  575. goto check_new;
  576. {$else CHECKHEAP}
  577. exit;
  578. {$endif CHECKHEAP}
  579. end;
  580. last:=hp;
  581. hp:=hp^.next;
  582. end;
  583. end;
  584. { Latly, the top of the heap is checked, to see if there is }
  585. { still memory available. }
  586. if heapend-heapptr<size then
  587. begin
  588. if assigned(heaperror) then
  589. begin
  590. case call_heaperror(heaperror,size) of
  591. 0 : runerror(203);
  592. 1 : p:=nil;
  593. 2 : nochmal:=true;
  594. end;
  595. end
  596. else
  597. runerror(203);
  598. end
  599. else
  600. begin
  601. p:=heapptr;
  602. heapptr:=heapptr+size;
  603. end;
  604. until not nochmal;
  605. {$ifdef CHECKHEAP}
  606. check_new:
  607. inc(getmem_nb);
  608. test_memavail;
  609. if trace then
  610. begin
  611. asm
  612. move.l (a6),d0
  613. move.l d0,bp
  614. end;
  615. pheap_mem_info(p)^.sig:=$DEADBEEF;
  616. pheap_mem_info(p)^.previous:=last_assigned;
  617. if last_assigned<>nil then
  618. last_assigned^.next:=pheap_mem_info(p);
  619. last_assigned:=p;
  620. pheap_mem_info(p)^.next:=nil;
  621. pheap_mem_info(p)^.size:=orsize;
  622. for i:=1 to tracesize do
  623. begin
  624. pheap_mem_info(p)^.calls[i]:=get_addr(bp);
  625. bp:=get_next_frame(bp);
  626. end;
  627. p:=p+sizeof(heap_mem_info);
  628. end;
  629. {$endif CHECKHEAP}
  630. end;
  631. procedure freemem(var p : pointer;size : longint);[public,alias: 'FREEMEM'];
  632. var
  633. hp : pfreerecord;
  634. {$ifdef TEMPHEAP}
  635. heap_switched : boolean;
  636. {$endif TEMPHEAP}
  637. s : longint;
  638. label freemem_exit;
  639. begin
  640. {$ifdef CHECKHEAP}
  641. if free_nothing then
  642. begin
  643. p:=nil;
  644. exit;
  645. end;
  646. if trace then
  647. begin
  648. size:=size+sizeof(heap_mem_info);
  649. p:=p-sizeof(heap_mem_info);
  650. { made after heap_switch
  651. if not (is_in_getmem_list(p)) then
  652. runerror(204); }
  653. end;
  654. {$endif CHECKHEAP}
  655. if size=0 then
  656. begin
  657. p:=nil;
  658. exit;
  659. end;
  660. if p=nil then RunError (204);
  661. {$ifdef TEMPHEAP}
  662. heap_switched:=false;
  663. if heap_split and not allow_special then
  664. begin
  665. if (p <= heapptr) and
  666. ( p >= heaporg) and
  667. (@p <= otherheap^.heapend) and
  668. (@p >= otherheap^.heaporg) then
  669. begin
  670. writeln('warning : p and @p are in different heaps !');
  671. end;
  672. end;
  673. if (p<heaporg) or (p>heapptr) then
  674. begin
  675. if heap_split and (p<otherheap^.heapend) and
  676. (p>otherheap^.heaporg) then
  677. begin
  678. if (@p >= heaporg) and
  679. (@p <= heapptr) and
  680. not allow_special then
  681. writeln('warning : p and @p are in different heaps !');
  682. switch_heap;
  683. heap_switched:=true;
  684. end
  685. else
  686. begin
  687. writeln('pointer ',hexstr(longint(@p),8),' at ',
  688. hexstr(longint(p),8),' doesn''t points to the heap');
  689. runerror(204);
  690. end;
  691. end;
  692. {$endif TEMPHEAP}
  693. {$ifdef CHECKHEAP}
  694. if trace then
  695. begin
  696. if not (is_in_getmem_list(p)) then
  697. runerror(204);
  698. if pheap_mem_info(p)^.sig=$AAAAAAAA then
  699. dump_free(p);
  700. if pheap_mem_info(p)^.next<>nil then
  701. pheap_mem_info(p)^.next^.previous:=pheap_mem_info(p)^.previous;
  702. if pheap_mem_info(p)^.previous<>nil then
  703. pheap_mem_info(p)^.previous^.next:=pheap_mem_info(p)^.next;
  704. if pheap_mem_info(p)=last_assigned then
  705. last_assigned:=last_assigned^.previous;
  706. end;
  707. {$endif CHECKHEAP}
  708. { calc to multiple of 8 }
  709. if (size mod 8)<>0 then
  710. size:=size+(8-(size mod 8));
  711. inc(_memavail,size);
  712. if p+size>=heapptr then
  713. heapptr:=p
  714. {$ifdef UseBlocks}
  715. { insert into cache }
  716. else if size<=max_size then
  717. begin
  718. s:=size div 8;
  719. ppointer(p)^:=blocks^[s];
  720. blocks^[s]:=p;
  721. inc(nblocks^[s]);
  722. end
  723. {$endif UseBlocks}
  724. else
  725. begin
  726. { size can be allways set }
  727. pfreerecord(p)^.size:=size;
  728. { if there is no free list }
  729. if not assigned(freelist) then
  730. begin
  731. { then generate one }
  732. freelist:=p;
  733. pfreerecord(p)^.next:=nil;
  734. {$ifdef CHECKHEAP}
  735. inc(freerecord_list_length);
  736. {$endif CHECKHEAP}
  737. goto freemem_exit;
  738. end;
  739. if p+size<freelist then
  740. begin
  741. pfreerecord(p)^.next:=freelist;
  742. freelist:=p;
  743. {$ifdef CHECKHEAP}
  744. inc(freerecord_list_length);
  745. {$endif CHECKHEAP}
  746. goto freemem_exit;
  747. end
  748. else
  749. if p+size=freelist then
  750. begin
  751. inc(pfreerecord(p)^.size,pfreerecord(freelist)^.size);
  752. pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
  753. freelist:=p;
  754. { but now it can also connect the next block !!}
  755. if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
  756. begin
  757. inc(pfreerecord(p)^.size,pfreerecord(p)^.next^.size);
  758. {$ifdef CHECKHEAP}
  759. dec(freerecord_list_length);
  760. {$endif CHECKHEAP}
  761. pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
  762. end;
  763. goto freemem_exit;
  764. end;
  765. { search the insert position }
  766. hp:=freelist;
  767. while assigned(hp) do
  768. begin
  769. if p<hp+hp^.size then
  770. begin
  771. writeln('pointer to dispose at ',hexstr(longint(p),8),
  772. ' has already been disposed');
  773. runerror(204);
  774. end;
  775. { connecting two blocks ? }
  776. if hp+hp^.size=p then
  777. begin
  778. inc(hp^.size,size);
  779. { connecting also to next block ? }
  780. if hp+hp^.size=hp^.next then
  781. begin
  782. inc(hp^.size,hp^.next^.size);
  783. {$ifdef CHECKHEAP}
  784. dec(freerecord_list_length);
  785. {$endif CHECKHEAP}
  786. hp^.next:=hp^.next^.next;
  787. end
  788. else
  789. if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
  790. begin
  791. writeln('pointer to dispose at ',hexstr(longint(p),8),
  792. ' is too big !!');
  793. runerror(204);
  794. end;
  795. break;
  796. end
  797. { if the end is reached, then concat }
  798. else if hp^.next=nil then
  799. begin
  800. hp^.next:=p;
  801. {$ifdef CHECKHEAP}
  802. inc(freerecord_list_length);
  803. {$endif CHECKHEAP}
  804. pfreerecord(p)^.next:=nil;
  805. break;
  806. end
  807. { falls der n„chste Zeiger gr”áer ist, dann }
  808. { Einh„ngen }
  809. else if hp^.next>p then
  810. begin
  811. { connect to blocks }
  812. if p+size=hp^.next then
  813. begin
  814. pfreerecord(p)^.next:=hp^.next^.next;
  815. inc(pfreerecord(p)^.size,hp^.next^.size);
  816. { we have to reset the right position }
  817. hp^.next:=pfreerecord(p);
  818. end
  819. else
  820. begin
  821. pfreerecord(p)^.next:=hp^.next;
  822. hp^.next:=p;
  823. {$ifdef CHECKHEAP}
  824. inc(freerecord_list_length);
  825. {$endif CHECKHEAP}
  826. end;
  827. break;
  828. end;
  829. hp:=hp^.next;
  830. end;
  831. end;
  832. freemem_exit:
  833. {$ifdef CHECKHEAP}
  834. inc(freemem_nb);
  835. test_memavail;
  836. {$endif CHECKHEAP}
  837. p:=nil;
  838. {$ifdef TEMPHEAP}
  839. if heap_switched then switch_heap;
  840. {$endif TEMPHEAP}
  841. end;
  842. procedure release(var p : pointer);
  843. begin
  844. heapptr:=p;
  845. freelist:=nil;
  846. _memavail:=cal_memavail;
  847. end;
  848. procedure mark(var p : pointer);
  849. begin
  850. p:=heapptr;
  851. end;
  852. procedure markheap(var oldfreelist,oldheapptr : pointer);
  853. begin
  854. oldheapptr:=heapptr;
  855. oldfreelist:=freelist;
  856. freelist:=nil;
  857. _memavail:=cal_memavail;
  858. end;
  859. procedure releaseheap(oldfreelist,oldheapptr : pointer);
  860. begin
  861. heapptr:=oldheapptr;
  862. if longint(freelist) < longint(heapptr) then
  863. begin
  864. {here we should reget the freed blocks}
  865. end;
  866. freelist:=oldfreelist;
  867. _memavail:=cal_memavail;
  868. end;
  869. { the sbrk function is moved to the system.pp }
  870. { as it is system dependent !! }
  871. function growheap(size :longint) : integer;
  872. var NewPos,wantedsize : longint;
  873. hp : pfreerecord;
  874. Newlimit : longint;
  875. begin
  876. wantedsize:=size;
  877. size:=size+$ffff;
  878. size:=size and $ffff0000;
  879. { Allocate by 64K size }
  880. { first try 1Meg }
  881. NewPos:=Sbrk($100000);
  882. if NewPos=-1 then
  883. NewPos:=Sbrk(size)
  884. else
  885. size:=$100000;
  886. if (NewPos = -1) then
  887. begin
  888. GrowHeap:=0;
  889. {$IfDef CHECKHEAP}
  890. writeln('Call to GrowHeap failed');
  891. readln;
  892. {$EndIf CHECKHEAP}
  893. Exit;
  894. end
  895. else
  896. begin
  897. { make the room clean }
  898. {$ifdef CHECKHEAP}
  899. Fillword(pointer(NewPos)^,size div 2,$ABCD);
  900. Newlimit:= (newpos+size) or $3fff;
  901. {$else }
  902. Fillchar(pointer(NewPos)^,size,#0);
  903. {$endif }
  904. hp:=pfreerecord(freelist);
  905. if not assigned(hp) then
  906. begin
  907. if pointer(newpos) = heapend then
  908. heapend:=pointer(newpos+size)
  909. else
  910. begin
  911. if heapend - heapptr > 0 then
  912. begin
  913. freelist:=heapptr;
  914. hp:=pfreerecord(freelist);
  915. hp^.size:=heapend-heapptr;
  916. hp^.next:=nil;
  917. end;
  918. heapptr:=pointer(newpos);
  919. heapend:=pointer(newpos+size);
  920. end;
  921. end
  922. else
  923. begin
  924. if pointer(newpos) = heapend then
  925. heapend:=pointer(newpos+size)
  926. else
  927. begin
  928. while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
  929. hp:=hp^.next;
  930. if hp^.next = nil then
  931. begin
  932. hp^.next:=pfreerecord(heapptr);
  933. hp:=pfreerecord(heapptr);
  934. hp^.size:=heapend-heapptr;
  935. hp^.next:=nil;
  936. heapptr:=pointer(NewPos);
  937. heapend:=pointer(NewPos+Size);
  938. end
  939. else
  940. begin
  941. pfreerecord(NewPos)^.Size:=Size;
  942. pfreerecord(NewPos)^.Next:=hp^.next;
  943. hp^.next:=pfreerecord(NewPos);
  944. end;
  945. end;
  946. end;
  947. { the wanted size has to be substracted }
  948. _memavail:=cal_memavail-wantedsize;
  949. { set the total new heap size }
  950. asm
  951. move.l Size,d0
  952. move.l HEAP_SIZE,d1
  953. add.l d0,d1
  954. move.l d1,HEAP_SIZE
  955. end;
  956. GrowHeap:=2;{ try again }
  957. _internal_heapsize:=size+_internal_heapsize;
  958. {$IfDef CHECKHEAP}
  959. writeln('Call to GrowHeap succedeed : HeapSize = ',_internal_heapsize,' MemAvail = ',memavail);
  960. writeln('New heap part begins at ',Newpos,' with size ',size);
  961. if growheapstop then
  962. readln;
  963. {$EndIf CHECKHEAP}
  964. exit;
  965. end;
  966. end;
  967. { This function will initialize the Heap manager and need to be called from
  968. the initialization of the system unit }
  969. procedure InitHeap;
  970. {$ifdef UseBlocks}
  971. var
  972. i : longint;
  973. {$endif UseBlocks}
  974. begin
  975. {$ifdef UseBlocks}
  976. Blocks:=@baseblocks;
  977. Nblocks:=@basenblocks;
  978. for i:=1 to maxblock do
  979. begin
  980. Blocks^[i]:=nil;
  981. Nblocks^[i]:=0;
  982. end;
  983. {$endif UseBlocks}
  984. Curheap := @baseheap;
  985. {$ifdef TEMPHEAP}
  986. Otherheap := @tempheap;
  987. {$endif TEMPHEAP}
  988. HeapOrg := GetHeapStart;
  989. HeapPtr := HeapOrg;
  990. _memavail := GetHeapSize;
  991. HeapEnd := HeapOrg + _memavail;
  992. HeapError := @GrowHeap;
  993. _internal_heapsize:=longint(heapend)-longint(heaporg);
  994. Freelist := nil;
  995. end;
  996. {
  997. $Log$
  998. Revision 1.4 1998-07-08 11:54:40 carl
  999. + reinstated hepasize function
  1000. * renamed HEAPSIZE global var to HEAP_SIZE to remove conflicts
  1001. Revision 1.3 1998/07/02 14:24:08 michael
  1002. Undid carls changes, but renamed _heapsize to _internal_heapsize. Make cycle now works
  1003. Revision 1.2 1998/07/02 12:22:38 carl
  1004. - removed heapsize function, would cause conflicts with HEAPSIZE var
  1005. * GetHeapstart was misplaced
  1006. Revision 1.1.1.1 1998/03/25 11:18:44 root
  1007. * Restored version
  1008. Revision 1.3 1998/01/26 12:01:52 michael
  1009. + Added log at the end
  1010. Working file: rtl/m68k/heap.inc
  1011. description:
  1012. ----------------------------
  1013. revision 1.2
  1014. date: 1998/01/05 16:51:24; author: michael; state: Exp; lines: +31 -1
  1015. + Moved init of heap to heap.inc: INITheap() (From Peter Vreman)
  1016. ----------------------------
  1017. revision 1.1
  1018. date: 1998/01/05 00:32:44; author: carl; state: Exp;
  1019. + First Version of m68k heap handler (handles amiga/macos/atari)
  1020. =============================================================================
  1021. }