temp_gen.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. {
  2. $Id$
  3. Copyright (C) 1993-98 by Florian Klaempfl
  4. This unit handles the temporary variables stuff for i386
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit temp_gen;
  19. interface
  20. uses
  21. {$ifdef i386}
  22. {$ifdef ag386bin}
  23. i386base,
  24. {$else}
  25. i386,
  26. {$endif}
  27. {$endif i386}
  28. {$ifdef m68k}
  29. m68k,
  30. {$endif m68k}
  31. cobjects,globals,tree,hcodegen,verbose,files,aasm;
  32. type
  33. { this saves some memory }
  34. {$ifdef FPC}
  35. {$minenumsize 1}
  36. {$endif FPC}
  37. ttemptype = (tt_normal,tt_ansistring,tt_widestring);
  38. {$ifdef FPC}
  39. {$minenumsize default}
  40. {$endif FPC}
  41. { generates temporary variables }
  42. procedure resettempgen;
  43. procedure setfirsttemp(l : longint);
  44. function gettempsize : longint;
  45. function gettempofsize(size : longint) : longint;
  46. { special call for inlined procedures }
  47. function gettempofsizepersistant(size : longint) : longint;
  48. { for parameter func returns }
  49. procedure persistanttemptonormal(pos : longint);
  50. procedure ungettemp(pos : longint;size : longint);
  51. procedure ungetpersistanttemp(pos : longint;size : longint);
  52. procedure gettempofsizereference(l : longint;var ref : treference);
  53. procedure gettempslotreference(slottype : ttemptype;var ref : treference);
  54. function istemp(const ref : treference) : boolean;
  55. procedure ungetiftemp(const ref : treference);
  56. procedure gettempansistringreference(var ref : treference);
  57. implementation
  58. uses
  59. scanner
  60. {$ifdef i386}
  61. ,cgai386
  62. {$endif i386}
  63. {$ifdef m68k}
  64. ,cga68k
  65. {$endif m68k}
  66. ;
  67. type
  68. pfreerecord = ^tfreerecord;
  69. tfreerecord = record
  70. next : pfreerecord;
  71. pos : longint;
  72. size : longint;
  73. persistant : boolean; { used for inlined procedures }
  74. temptype : ttemptype;
  75. {$ifdef EXTDEBUG}
  76. posinfo,releaseposinfo : tfileposinfo;
  77. {$endif}
  78. end;
  79. var
  80. { contains all free temps }
  81. tmpfreelist : pfreerecord;
  82. { contains all used temps }
  83. templist : pfreerecord;
  84. { contains the slots for ansi/wide string temps }
  85. reftempslots : pfreerecord;
  86. {$ifdef EXTDEBUG}
  87. tempfreedlist : pfreerecord;
  88. {$endif}
  89. lastoccupied : longint;
  90. firsttemp, maxtemp : longint;
  91. procedure resettempgen;
  92. var
  93. hp : pfreerecord;
  94. begin
  95. while assigned(tmpfreelist) do
  96. begin
  97. hp:=tmpfreelist;
  98. tmpfreelist:=hp^.next;
  99. dispose(hp);
  100. end;
  101. while assigned(templist) do
  102. begin
  103. {$ifdef EXTDEBUG}
  104. Comment(V_Warning,'temporary assignment of size '
  105. +tostr(templist^.size)+' from pos '+tostr(templist^.posinfo.line)
  106. +':'+tostr(templist^.posinfo.column)
  107. +' at pos '+tostr(templist^.pos)+
  108. ' not freed at the end of the procedure');
  109. {$endif}
  110. hp:=templist;
  111. templist:=hp^.next;
  112. dispose(hp);
  113. end;
  114. {$ifdef EXTDEBUG}
  115. while assigned(tempfreedlist) do
  116. begin
  117. hp:=tempfreedlist;
  118. tempfreedlist:=hp^.next;
  119. dispose(hp);
  120. end;
  121. {$endif}
  122. firsttemp:=0;
  123. maxtemp:=0;
  124. lastoccupied:=0;
  125. end;
  126. procedure setfirsttemp(l : longint);
  127. begin
  128. { this is a negative value normally }
  129. if l < 0 then
  130. Begin
  131. if odd(l) then
  132. Dec(l);
  133. end
  134. else
  135. Begin
  136. if odd(l) then
  137. Inc(l);
  138. end;
  139. firsttemp:=l;
  140. maxtemp:=l;
  141. lastoccupied:=l;
  142. end;
  143. function gettempofsize(size : longint) : longint;
  144. var
  145. tl,last,hp : pfreerecord;
  146. ofs : longint;
  147. begin
  148. { this code comes from the heap management of FPC ... }
  149. if (size mod 4)<>0 then
  150. size:=size+(4-(size mod 4));
  151. ofs:=0;
  152. if assigned(tmpfreelist) then
  153. begin
  154. last:=nil;
  155. hp:=tmpfreelist;
  156. while assigned(hp) do
  157. begin
  158. { first fit }
  159. if hp^.size>=size then
  160. begin
  161. ofs:=hp^.pos;
  162. { the whole block is needed ? }
  163. if hp^.size>size then
  164. begin
  165. hp^.size:=hp^.size-size;
  166. hp^.pos:=hp^.pos-size;
  167. end
  168. else
  169. begin
  170. if assigned(last) then
  171. last^.next:=hp^.next
  172. else
  173. tmpfreelist:=nil;
  174. dispose(hp);
  175. end;
  176. break;
  177. end;
  178. last:=hp;
  179. hp:=hp^.next;
  180. end;
  181. end;
  182. { nothing free is big enough : expand temp }
  183. if ofs=0 then
  184. begin
  185. ofs:=lastoccupied-size;
  186. lastoccupied:=lastoccupied-size;
  187. if lastoccupied < maxtemp then
  188. maxtemp := lastoccupied;
  189. end;
  190. new(tl);
  191. tl^.pos:=ofs;
  192. tl^.size:=size;
  193. tl^.next:=templist;
  194. tl^.persistant:=false;
  195. templist:=tl;
  196. {$ifdef EXTDEBUG}
  197. tl^.posinfo:=aktfilepos;
  198. {$endif}
  199. gettempofsize:=ofs;
  200. end;
  201. function gettempofsizepersistant(size : longint) : longint;
  202. var
  203. l : longint;
  204. begin
  205. l:=gettempofsize(size);
  206. templist^.persistant:=true;
  207. {$ifdef EXTDEBUG}
  208. Comment(V_Debug,'temp managment : call to gettempofsizepersistant()'+
  209. ' with size '+tostr(size)+' returned '+tostr(l));
  210. {$endif}
  211. gettempofsizepersistant:=l;
  212. end;
  213. function gettempsize : longint;
  214. begin
  215. {$ifdef i386}
  216. { align local data to dwords }
  217. if (maxtemp mod 4)<>0 then
  218. dec(maxtemp,4+(maxtemp mod 4));
  219. {$endif}
  220. {$ifdef m68k}
  221. { we only push words and we want to stay on }
  222. { even stack addresses }
  223. { maxtemp is negative }
  224. if (maxtemp mod 2)<>0 then
  225. dec(maxtemp);
  226. {$endif}
  227. gettempsize:=-maxtemp;
  228. end;
  229. procedure gettempofsizereference(l : longint;var ref : treference);
  230. begin
  231. { do a reset, because the reference isn't used }
  232. reset_reference(ref);
  233. ref.offset:=gettempofsize(l);
  234. ref.base:=procinfo.framepointer;
  235. end;
  236. procedure gettempansistringreference(var ref : treference);
  237. begin
  238. { do a reset, because the reference isn't used }
  239. reset_reference(ref);
  240. ref.offset:=gettempofsize(4);
  241. ref.base:=procinfo.framepointer;
  242. end;
  243. procedure gettempslotreference(slottype : ttemptype;var ref : treference);
  244. begin
  245. { do a reset, because the reference isn't used }
  246. reset_reference(ref);
  247. ref.offset:=gettempofsize(4);
  248. ref.base:=procinfo.framepointer;
  249. templist^.temptype:=slottype;
  250. end;
  251. function istemp(const ref : treference) : boolean;
  252. begin
  253. { ref.index = R_NO was missing
  254. led to problems with local arrays
  255. with lower bound > 0 (PM) }
  256. istemp:=((ref.base=procinfo.framepointer) and
  257. (ref.offset<firsttemp) and (ref.index=R_NO));
  258. end;
  259. procedure persistanttemptonormal(pos : longint);
  260. var hp : pfreerecord;
  261. begin
  262. hp:=templist;
  263. while assigned(hp) do
  264. if (hp^.persistant) and (hp^.pos=pos) then
  265. begin
  266. {$ifdef EXTDEBUG}
  267. Comment(V_Debug,'temp managment : persistanttemptonormal()'+
  268. ' at pos '+tostr(pos)+ ' found !');
  269. {$endif}
  270. hp^.persistant:=false;
  271. exit;
  272. end
  273. else
  274. hp:=hp^.next;
  275. {$ifdef EXTDEBUG}
  276. Comment(V_Debug,'temp managment problem : persistanttemptonormal()'+
  277. ' at pos '+tostr(pos)+ ' not found !');
  278. {$endif}
  279. end;
  280. procedure ungetpersistanttemp(pos : longint;size : longint);
  281. var
  282. prev,hp : pfreerecord;
  283. begin
  284. ungettemp(pos,size);
  285. prev:=nil;
  286. hp:=templist;
  287. while assigned(hp) do
  288. begin
  289. if (hp^.persistant) and (hp^.pos=pos) and (hp^.size=size) then
  290. begin
  291. if assigned(prev) then
  292. prev^.next:=hp^.next
  293. else
  294. templist:=hp^.next;
  295. {$ifdef EXTDEBUG}
  296. Comment(V_Debug,'temp managment : ungetpersistanttemp()'+
  297. ' at pos '+tostr(pos)+ ' found !');
  298. hp^.next:=tempfreedlist;
  299. tempfreedlist:=hp;
  300. hp^.releaseposinfo:=aktfilepos;
  301. {$else}
  302. dispose(hp);
  303. {$endif}
  304. exit;
  305. end;
  306. prev:=hp;
  307. hp:=hp^.next;
  308. end;
  309. {$ifdef EXTDEBUG}
  310. Comment(V_Warning,'temp managment problem : ungetpersistanttemp()'+
  311. ' at pos '+tostr(pos)+ ' not found !');
  312. {$endif}
  313. end;
  314. procedure ungettemp(pos : longint;size : longint);
  315. var
  316. hp,newhp : pfreerecord;
  317. begin
  318. if (size mod 4)<>0 then
  319. size:=size+(4-(size mod 4));
  320. if size = 0 then
  321. exit;
  322. if pos<=lastoccupied then
  323. if pos=lastoccupied then
  324. begin
  325. lastoccupied:=pos+size;
  326. hp:=tmpfreelist;
  327. newhp:=nil;
  328. while assigned(hp) do
  329. begin
  330. { conneting a free block }
  331. if hp^.pos=lastoccupied then
  332. begin
  333. if assigned(newhp) then newhp^.next:=nil
  334. else tmpfreelist:=nil;
  335. lastoccupied:=lastoccupied+hp^.size;
  336. dispose(hp);
  337. break;
  338. end;
  339. newhp:=hp;
  340. hp:=hp^.next;
  341. end;
  342. end
  343. else
  344. begin
  345. {$ifdef EXTDEBUG}
  346. Comment(V_Warning,'temp managment problem : ungettemp()'+
  347. 'pos '+tostr(pos)+ '< lastoccupied '+tostr(lastoccupied)+' !');
  348. {$endif}
  349. end
  350. else
  351. begin
  352. new(newhp);
  353. { size can be allways set }
  354. newhp^.size:=size;
  355. newhp^.pos := pos;
  356. { if there is no free list }
  357. if not assigned(tmpfreelist) then
  358. begin
  359. { then generate one }
  360. tmpfreelist:=newhp;
  361. newhp^.next:=nil;
  362. exit;
  363. end;
  364. { search the position to insert }
  365. hp:=tmpfreelist;
  366. while assigned(hp) do
  367. begin
  368. { conneting two blocks ? }
  369. if hp^.pos+hp^.size=pos then
  370. begin
  371. inc(hp^.size,size);
  372. dispose(newhp);
  373. break;
  374. end
  375. { if the end is reached, then concat }
  376. else if hp^.next=nil then
  377. begin
  378. hp^.next:=newhp;
  379. newhp^.next:=nil;
  380. break;
  381. end
  382. { falls der n„chste Zeiger gr”áer ist, dann }
  383. { Einh„ngen }
  384. else if hp^.next^.pos<=pos+size then
  385. begin
  386. { concat two blocks ? }
  387. if pos+size=hp^.next^.pos then
  388. begin
  389. newhp^.next:=hp^.next^.next;
  390. inc(newhp^.size,hp^.next^.size);
  391. dispose(hp^.next);
  392. hp^.next:=newhp;
  393. end
  394. else
  395. begin
  396. newhp^.next:=hp^.next;
  397. hp^.next:=newhp;
  398. end;
  399. break;
  400. end;
  401. hp:=hp^.next;
  402. end;
  403. end;
  404. end;
  405. procedure ungetiftemp(const ref : treference);
  406. var
  407. tl,prev : pfreerecord;
  408. begin
  409. if istemp(ref) then
  410. begin
  411. prev:=nil;
  412. tl:=templist;
  413. while assigned(tl) do
  414. begin
  415. { no release of persistant blocks this way!! }
  416. if (tl^.persistant) or (tl^.temptype<>tt_normal) then
  417. if (ref.offset>=tl^.pos) and
  418. (ref.offset<tl^.pos+tl^.size) then
  419. begin
  420. {$ifdef EXTDEBUG}
  421. Comment(V_Debug,'temp '+
  422. ' at pos '+tostr(ref.offset)+ ' not released because persistant or slot!');
  423. {$endif}
  424. exit;
  425. end;
  426. if (ref.offset=tl^.pos) then
  427. begin
  428. ungettemp(ref.offset,tl^.size);
  429. {$ifdef TEMPDEBUG}
  430. Comment(V_Debug,'temp managment : ungettemp()'+
  431. ' at pos '+tostr(tl^.pos)+ ' found !');
  432. {$endif}
  433. if assigned(prev) then
  434. prev^.next:=tl^.next
  435. else
  436. templist:=tl^.next;
  437. {$ifdef EXTDEBUG}
  438. tl^.next:=tempfreedlist;
  439. tempfreedlist:=tl;
  440. tl^.releaseposinfo:=aktfilepos;
  441. {$else}
  442. dispose(tl);
  443. {$endif}
  444. exit;
  445. end
  446. else
  447. begin
  448. prev:=tl;
  449. tl:=tl^.next;
  450. end;
  451. end;
  452. {$ifdef EXTDEBUG}
  453. Comment(V_Warning,'Internal: temp managment problem : '+
  454. 'temp not found for release at offset '+tostr(ref.offset));
  455. tl:=tempfreedlist;
  456. while assigned(tl) do
  457. begin
  458. if (ref.offset=tl^.pos) then
  459. begin
  460. Comment(V_Warning,'Last temporary assignment of size '
  461. +tostr(tl^.size)+' from pos '+tostr(tl^.posinfo.line)
  462. +':'+tostr(tl^.posinfo.column)
  463. +' at pos '+tostr(tl^.pos)+
  464. ' has been already freed at '
  465. +tostr(tl^.releaseposinfo.line)
  466. +':'+tostr(tl^.releaseposinfo.column)
  467. );
  468. Exit;
  469. end;
  470. tl:=tl^.next;
  471. end;
  472. {$endIf}
  473. end;
  474. end;
  475. procedure inittemps;
  476. begin
  477. { hp:=temp }
  478. end;
  479. begin
  480. tmpfreelist:=nil;
  481. templist:=nil;
  482. reftempslots:=nil;
  483. end.
  484. {
  485. $Log$
  486. Revision 1.11 1999-04-08 20:59:44 florian
  487. * fixed problem with default properties which are a class
  488. * case bug (from the mailing list with -O2) fixed, the
  489. distance of the case labels can be greater than the positive
  490. range of a longint => it is now a dword for fpc
  491. Revision 1.10 1999/04/06 11:19:49 peter
  492. * fixed temp reuse
  493. Revision 1.9 1999/02/22 02:15:56 peter
  494. * updates for ag386bin
  495. Revision 1.8 1999/02/11 09:35:19 pierre
  496. * ExtDebug conditionnal infinite loop on temp problem removed
  497. Revision 1.7 1999/02/02 23:52:33 florian
  498. * problem with calls to method pointers in methods fixed
  499. - double ansistrings temp management removed
  500. Revision 1.6 1999/01/15 11:34:23 pierre
  501. + better info for temp allocation debugging
  502. Revision 1.5 1998/11/30 09:43:24 pierre
  503. * some range check bugs fixed (still not working !)
  504. + added DLL writing support for win32 (also accepts variables)
  505. + TempAnsi for code that could be used for Temporary ansi strings
  506. handling
  507. Revision 1.4 1998/10/09 08:56:32 pierre
  508. * several memory leaks fixed
  509. Revision 1.3 1998/07/16 08:01:42 pierre
  510. * small bug correction due to newinput
  511. (only with tempdebug conditionnal)
  512. Revision 1.2 1998/07/10 10:51:05 peter
  513. * m68k updates
  514. Revision 1.1 1998/06/08 16:07:41 pierre
  515. * temp_gen contains all temporary var functions
  516. (processor independent)
  517. }