heap.inc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1993,97 by the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************
  12. functions for heap management in the data segment
  13. ****************************************************************************}
  14. {**** 10/06/97 added checkings and corrected some bugs in getmem/freemem ****}
  15. {**** Pierre Muller *********************************************************}
  16. { three conditionnals here }
  17. { TEMPHEAP to allow to split the heap in two parts for easier release}
  18. { started for the compiler }
  19. { USEBLOCKS if you want special allocation for small blocks }
  20. { CHECKHEAP if you want to test the heap integrity }
  21. {$IfDef CHECKHEAP}
  22. { 4 levels of tracing }
  23. const tracesize = 4;
  24. type pheap_mem_info = ^heap_mem_info;
  25. heap_mem_info = record
  26. next,previous : pheap_mem_info;
  27. size : longint;
  28. sig : longint; {dummy number for test }
  29. calls : array [1..tracesize] of longint;
  30. end;
  31. { size 8*4 = 32 }
  32. { help variables for debugging with GDB }
  33. const check : boolean = false;
  34. const last_assigned : pheap_mem_info = nil;
  35. const growheapstop : boolean = false;
  36. const free_nothing : boolean = false;
  37. const trace : boolean = true;
  38. const getmem_nb : longint = 0;
  39. const freemem_nb : longint = 0;
  40. {$EndIf CHECKHEAP}
  41. const
  42. heap_split : boolean = false;
  43. max_size = 256;
  44. maxblock = max_size div 8;
  45. freerecord_list_length : longint = 0;
  46. var
  47. _memavail : longint;
  48. _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. move.l size,-(sp)
  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. size:=(size+7) and not 7;
  710. _memavail:=_memavail+size;
  711. if p+size>=heapptr then
  712. heapptr:=p
  713. {$ifdef UseBlocks}
  714. { insert into cache }
  715. else if size<=max_size then
  716. begin
  717. s:=size div 8;
  718. ppointer(p)^:=blocks^[s];
  719. blocks^[s]:=p;
  720. inc(nblocks^[s]);
  721. end
  722. {$endif UseBlocks}
  723. else
  724. begin
  725. { size can be allways set }
  726. pfreerecord(p)^.size:=size;
  727. { if there is no free list }
  728. if not assigned(freelist) then
  729. begin
  730. { then generate one }
  731. freelist:=p;
  732. pfreerecord(p)^.next:=nil;
  733. {$ifdef CHECKHEAP}
  734. inc(freerecord_list_length);
  735. {$endif CHECKHEAP}
  736. goto freemem_exit;
  737. end;
  738. if p+size<freelist then
  739. begin
  740. pfreerecord(p)^.next:=freelist;
  741. freelist:=p;
  742. {$ifdef CHECKHEAP}
  743. inc(freerecord_list_length);
  744. {$endif CHECKHEAP}
  745. goto freemem_exit;
  746. end
  747. else
  748. if p+size=freelist then
  749. begin
  750. inc(pfreerecord(p)^.size,pfreerecord(freelist)^.size);
  751. pfreerecord(p)^.next:=pfreerecord(freelist)^.next;
  752. freelist:=p;
  753. { but now it can also connect the next block !!}
  754. if p+pfreerecord(p)^.size=pfreerecord(p)^.next then
  755. begin
  756. inc(pfreerecord(p)^.size,pfreerecord(p)^.next^.size);
  757. {$ifdef CHECKHEAP}
  758. dec(freerecord_list_length);
  759. {$endif CHECKHEAP}
  760. pfreerecord(p)^.next:=pfreerecord(freelist)^.next^.next;
  761. end;
  762. goto freemem_exit;
  763. end;
  764. { search the insert position }
  765. hp:=freelist;
  766. while assigned(hp) do
  767. begin
  768. if p<hp+hp^.size then
  769. begin
  770. writeln('pointer to dispose at ',hexstr(longint(p),8),
  771. ' has already been disposed');
  772. runerror(204);
  773. end;
  774. { connecting two blocks ? }
  775. if hp+hp^.size=p then
  776. begin
  777. inc(hp^.size,size);
  778. { connecting also to next block ? }
  779. if hp+hp^.size=hp^.next then
  780. begin
  781. inc(hp^.size,hp^.next^.size);
  782. {$ifdef CHECKHEAP}
  783. dec(freerecord_list_length);
  784. {$endif CHECKHEAP}
  785. hp^.next:=hp^.next^.next;
  786. end
  787. else
  788. if (hp^.next<>nil) and (hp+hp^.size>hp^.next) then
  789. begin
  790. writeln('pointer to dispose at ',hexstr(longint(p),8),
  791. ' is too big !!');
  792. runerror(204);
  793. end;
  794. break;
  795. end
  796. { if the end is reached, then concat }
  797. else if hp^.next=nil then
  798. begin
  799. hp^.next:=p;
  800. {$ifdef CHECKHEAP}
  801. inc(freerecord_list_length);
  802. {$endif CHECKHEAP}
  803. pfreerecord(p)^.next:=nil;
  804. break;
  805. end
  806. { falls der n„chste Zeiger gr”áer ist, dann }
  807. { Einh„ngen }
  808. else if hp^.next>p then
  809. begin
  810. { connect to blocks }
  811. if p+size=hp^.next then
  812. begin
  813. pfreerecord(p)^.next:=hp^.next^.next;
  814. inc(pfreerecord(p)^.size,hp^.next^.size);
  815. { we have to reset the right position }
  816. hp^.next:=pfreerecord(p);
  817. end
  818. else
  819. begin
  820. pfreerecord(p)^.next:=hp^.next;
  821. hp^.next:=p;
  822. {$ifdef CHECKHEAP}
  823. inc(freerecord_list_length);
  824. {$endif CHECKHEAP}
  825. end;
  826. break;
  827. end;
  828. hp:=hp^.next;
  829. end;
  830. end;
  831. freemem_exit:
  832. {$ifdef CHECKHEAP}
  833. inc(freemem_nb);
  834. test_memavail;
  835. {$endif CHECKHEAP}
  836. p:=nil;
  837. {$ifdef TEMPHEAP}
  838. if heap_switched then switch_heap;
  839. {$endif TEMPHEAP}
  840. end;
  841. procedure release(var p : pointer);
  842. begin
  843. heapptr:=p;
  844. freelist:=nil;
  845. _memavail:=cal_memavail;
  846. end;
  847. procedure mark(var p : pointer);
  848. begin
  849. p:=heapptr;
  850. end;
  851. procedure markheap(var oldfreelist,oldheapptr : pointer);
  852. begin
  853. oldheapptr:=heapptr;
  854. oldfreelist:=freelist;
  855. freelist:=nil;
  856. _memavail:=cal_memavail;
  857. end;
  858. procedure releaseheap(oldfreelist,oldheapptr : pointer);
  859. begin
  860. heapptr:=oldheapptr;
  861. if longint(freelist) < longint(heapptr) then
  862. begin
  863. {here we should reget the freed blocks}
  864. end;
  865. freelist:=oldfreelist;
  866. _memavail:=cal_memavail;
  867. end;
  868. { the sbrk function is moved to the system.pp }
  869. { as it is system dependent !! }
  870. function growheap(size :longint) : integer;
  871. var NewPos,wantedsize : longint;
  872. hp : pfreerecord;
  873. Newlimit : longint;
  874. begin
  875. wantedsize:=size;
  876. size:=size+$ffff;
  877. size:=size and $ffff0000;
  878. { Allocate by 64K size }
  879. { first try 1Meg }
  880. if Size<$100000 then
  881. begin
  882. NewPos:=Sbrk($100000);
  883. if NewPos > 0 then
  884. Size:=$100000;
  885. end
  886. else
  887. NewPos:=Sbrk(size);
  888. if NewPos=-1 then
  889. NewPos:=Sbrk(size);
  890. if (NewPos = -1) then
  891. begin
  892. GrowHeap:=0;
  893. {$IfDef CHECKHEAP}
  894. writeln('Call to GrowHeap failed');
  895. readln;
  896. {$EndIf CHECKHEAP}
  897. Exit;
  898. end
  899. else
  900. begin
  901. { make the room clean }
  902. {$ifdef CHECKHEAP}
  903. Fillword(pointer(NewPos)^,size div 2,$ABCD);
  904. Newlimit:= (newpos+size) or $3fff;
  905. {$else }
  906. Fillchar(pointer(NewPos)^,size,#0);
  907. {$endif }
  908. hp:=pfreerecord(freelist);
  909. if not assigned(hp) then
  910. begin
  911. if pointer(newpos) = heapend then
  912. heapend:=pointer(newpos+size)
  913. else
  914. begin
  915. if heapend - heapptr > 0 then
  916. begin
  917. freelist:=heapptr;
  918. hp:=pfreerecord(freelist);
  919. hp^.size:=heapend-heapptr;
  920. hp^.next:=nil;
  921. end;
  922. heapptr:=pointer(newpos);
  923. heapend:=pointer(newpos+size);
  924. end;
  925. end
  926. else
  927. begin
  928. if pointer(newpos) = heapend then
  929. heapend:=pointer(newpos+size)
  930. else
  931. begin
  932. while assigned(hp^.next) and (longint(hp^.next) < longint(NewPos)) do
  933. hp:=hp^.next;
  934. if hp^.next = nil then
  935. begin
  936. hp^.next:=pfreerecord(heapptr);
  937. hp:=pfreerecord(heapptr);
  938. hp^.size:=heapend-heapptr;
  939. hp^.next:=nil;
  940. heapptr:=pointer(NewPos);
  941. heapend:=pointer(NewPos+Size);
  942. end
  943. else
  944. begin
  945. pfreerecord(NewPos)^.Size:=Size;
  946. pfreerecord(NewPos)^.Next:=hp^.next;
  947. hp^.next:=pfreerecord(NewPos);
  948. end;
  949. end;
  950. end;
  951. { the wanted size has to be substracted
  952. why it will be substracted in the second try
  953. to get the memory PM }
  954. _memavail:=cal_memavail;
  955. { set the total new heap size }
  956. asm
  957. move.l Size,d0
  958. move.l HEAP_SIZE,d1
  959. add.l d0,d1
  960. move.l d1,HEAP_SIZE
  961. end;
  962. GrowHeap:=2;{ try again }
  963. _internal_heapsize:=size+_internal_heapsize;
  964. {$IfDef CHECKHEAP}
  965. writeln('Call to GrowHeap succedeed : HeapSize = ',_internal_heapsize,' MemAvail = ',memavail);
  966. writeln('New heap part begins at ',Newpos,' with size ',size);
  967. if growheapstop then
  968. readln;
  969. {$EndIf CHECKHEAP}
  970. exit;
  971. end;
  972. end;
  973. { This function will initialize the Heap manager and need to be called from
  974. the initialization of the system unit }
  975. procedure InitHeap;
  976. {$ifdef UseBlocks}
  977. var
  978. i : longint;
  979. {$endif UseBlocks}
  980. begin
  981. {$ifdef UseBlocks}
  982. Blocks:=@baseblocks;
  983. Nblocks:=@basenblocks;
  984. for i:=1 to maxblock do
  985. begin
  986. Blocks^[i]:=nil;
  987. Nblocks^[i]:=0;
  988. end;
  989. {$endif UseBlocks}
  990. Curheap := @baseheap;
  991. {$ifdef TEMPHEAP}
  992. Otherheap := @tempheap;
  993. {$endif TEMPHEAP}
  994. HeapOrg := GetHeapStart;
  995. HeapPtr := HeapOrg;
  996. _memavail := GetHeapSize;
  997. HeapEnd := HeapOrg + _memavail;
  998. HeapError := @GrowHeap;
  999. _internal_heapsize:=longint(heapend)-longint(heaporg);
  1000. Freelist := nil;
  1001. end;
  1002. {
  1003. $Log$
  1004. Revision 1.8 1998-09-04 17:27:09 pierre
  1005. * small modifications
  1006. Revision 1.7 1998/08/25 14:15:53 pierre
  1007. * corrected a bug introduced by my last change
  1008. (allocating 1Mb but only using a small part !!)
  1009. Revision 1.6 1998/08/24 14:44:05 pierre
  1010. * bug allocation of more than 1 MB failed corrected
  1011. Revision 1.5 1998/08/17 12:27:17 carl
  1012. * bugfix of heaperror, was pushing wrong parameter
  1013. Revision 1.4 1998/07/08 11:54:40 carl
  1014. + reinstated hepasize function
  1015. * renamed HEAPSIZE global var to HEAP_SIZE to remove conflicts
  1016. Revision 1.3 1998/07/02 14:24:08 michael
  1017. Undid carls changes, but renamed _heapsize to _internal_heapsize. Make cycle now works
  1018. Revision 1.2 1998/07/02 12:22:38 carl
  1019. - removed heapsize function, would cause conflicts with HEAPSIZE var
  1020. * GetHeapstart was misplaced
  1021. Revision 1.1.1.1 1998/03/25 11:18:44 root
  1022. * Restored version
  1023. Revision 1.3 1998/01/26 12:01:52 michael
  1024. + Added log at the end
  1025. Working file: rtl/m68k/heap.inc
  1026. description:
  1027. ----------------------------
  1028. revision 1.2
  1029. date: 1998/01/05 16:51:24; author: michael; state: Exp; lines: +31 -1
  1030. + Moved init of heap to heap.inc: INITheap() (From Peter Vreman)
  1031. ----------------------------
  1032. revision 1.1
  1033. date: 1998/01/05 00:32:44; author: carl; state: Exp;
  1034. + First Version of m68k heap handler (handles amiga/macos/atari)
  1035. =============================================================================
  1036. }