ncgflw.pas 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for nodes that influence the flow which are
  4. the same for all (most?) processors
  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 ncgflw;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmbase,node,nflw,ncgutil;
  23. type
  24. tcgwhilerepeatnode = class(twhilerepeatnode)
  25. usedregvars: tusedregvars;
  26. procedure pass_generate_code;override;
  27. procedure sync_regvars(checkusedregvars: boolean);
  28. end;
  29. tcgifnode = class(tifnode)
  30. procedure pass_generate_code;override;
  31. end;
  32. tcgfornode = class(tfornode)
  33. procedure pass_generate_code;override;
  34. end;
  35. tcgexitnode = class(texitnode)
  36. procedure pass_generate_code;override;
  37. end;
  38. tcgbreaknode = class(tbreaknode)
  39. procedure pass_generate_code;override;
  40. end;
  41. tcgcontinuenode = class(tcontinuenode)
  42. procedure pass_generate_code;override;
  43. end;
  44. tcggotonode = class(tgotonode)
  45. procedure pass_generate_code;override;
  46. end;
  47. tcglabelnode = class(tlabelnode)
  48. protected
  49. asmlabel : tasmlabel;
  50. public
  51. function getasmlabel : tasmlabel; virtual;
  52. procedure pass_generate_code;override;
  53. end;
  54. tcgraisenode = class(traisenode)
  55. end;
  56. tcgtryexceptnode = class(ttryexceptnode)
  57. procedure pass_generate_code;override;
  58. end;
  59. tcgtryfinallynode = class(ttryfinallynode)
  60. procedure handle_safecall_exception;
  61. procedure pass_generate_code;override;
  62. end;
  63. tcgonnode = class(tonnode)
  64. procedure pass_generate_code;override;
  65. end;
  66. implementation
  67. uses
  68. cutils,
  69. verbose,globals,systems,globtype,constexp,
  70. symconst,symdef,symsym,symtable,symtype,aasmtai,aasmdata,aasmcpu,defutil,
  71. procinfo,cgbase,pass_2,parabase,
  72. fmodule,
  73. cpubase,ncon,
  74. tgobj,paramgr,
  75. cgutils,cgobj,hlcgobj,nutils
  76. ;
  77. {*****************************************************************************
  78. Second_While_RepeatN
  79. *****************************************************************************}
  80. procedure tcgwhilerepeatnode.sync_regvars(checkusedregvars: boolean);
  81. begin
  82. if (cs_opt_regvar in current_settings.optimizerswitches) and
  83. not(pi_has_label in current_procinfo.flags) then
  84. begin
  85. if checkusedregvars then
  86. begin
  87. usedregvars.intregvars.init;
  88. usedregvars.addrregvars.init;
  89. usedregvars.fpuregvars.init;
  90. usedregvars.mmregvars.init;
  91. { we have to synchronise both the regvars used in the loop }
  92. { and the ones in the while/until condition }
  93. get_used_regvars(self,usedregvars);
  94. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  95. end
  96. else
  97. begin
  98. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  99. usedregvars.intregvars.done;
  100. usedregvars.addrregvars.done;
  101. usedregvars.fpuregvars.done;
  102. usedregvars.mmregvars.done;
  103. end;
  104. end;
  105. end;
  106. procedure tcgwhilerepeatnode.pass_generate_code;
  107. var
  108. lcont,lbreak,lloop,
  109. oldclabel,oldblabel : tasmlabel;
  110. truelabel,falselabel : tasmlabel;
  111. oldflowcontrol : tflowcontrol;
  112. oldexecutionweight : longint;
  113. begin
  114. location_reset(location,LOC_VOID,OS_NO);
  115. current_asmdata.getjumplabel(lloop);
  116. current_asmdata.getjumplabel(lcont);
  117. current_asmdata.getjumplabel(lbreak);
  118. { arrange continue and breaklabels: }
  119. oldflowcontrol:=flowcontrol;
  120. oldclabel:=current_procinfo.CurrContinueLabel;
  121. oldblabel:=current_procinfo.CurrBreakLabel;
  122. include(flowcontrol,fc_inflowcontrol);
  123. exclude(flowcontrol,fc_unwind_loop);
  124. sync_regvars(true);
  125. {$ifdef OLDREGVARS}
  126. load_all_regvars(current_asmdata.CurrAsmList);
  127. {$endif OLDREGVARS}
  128. { handling code at the end as it is much more efficient, and makes
  129. while equal to repeat loop, only the end true/false is swapped (PFV) }
  130. if lnf_testatbegin in loopflags then
  131. hlcg.a_jmp_always(current_asmdata.CurrAsmList,lcont);
  132. if not(cs_opt_size in current_settings.optimizerswitches) then
  133. { align loop target }
  134. current_asmdata.CurrAsmList.concat(Tai_align.Create(current_settings.alignment.loopalign));
  135. hlcg.a_label(current_asmdata.CurrAsmList,lloop);
  136. current_procinfo.CurrContinueLabel:=lcont;
  137. current_procinfo.CurrBreakLabel:=lbreak;
  138. { calc register weight }
  139. oldexecutionweight:=cg.executionweight;
  140. cg.executionweight:=max(cg.executionweight,1)*8;
  141. if assigned(right) then
  142. secondpass(right);
  143. {$ifdef OLDREGVARS}
  144. load_all_regvars(current_asmdata.CurrAsmList);
  145. {$endif OLDREGVARS}
  146. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  147. if lnf_checknegate in loopflags then
  148. begin
  149. truelabel:=lbreak;
  150. falselabel:=lloop;
  151. end
  152. else
  153. begin
  154. truelabel:=lloop;
  155. falselabel:=lbreak;
  156. end;
  157. secondpass(left);
  158. hlcg.maketojumpboollabels(current_asmdata.CurrAsmList,left,truelabel,falselabel);
  159. cg.executionweight:=oldexecutionweight;
  160. hlcg.a_label(current_asmdata.CurrAsmList,lbreak);
  161. sync_regvars(false);
  162. current_procinfo.CurrContinueLabel:=oldclabel;
  163. current_procinfo.CurrBreakLabel:=oldblabel;
  164. { a break/continue in a while/repeat block can't be seen outside }
  165. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  166. end;
  167. {*****************************************************************************
  168. tcgIFNODE
  169. *****************************************************************************}
  170. procedure tcgifnode.pass_generate_code;
  171. var
  172. hl : tasmlabel;
  173. oldflowcontrol: tflowcontrol;
  174. oldexecutionweight : longint;
  175. (*
  176. org_regvar_loaded_other,
  177. then_regvar_loaded_other,
  178. else_regvar_loaded_other : regvarother_booleanarray;
  179. org_regvar_loaded_int,
  180. then_regvar_loaded_int,
  181. else_regvar_loaded_int : Tsuperregisterset;
  182. org_list,
  183. then_list,
  184. else_list : TAsmList;
  185. *)
  186. begin
  187. location_reset(location,LOC_VOID,OS_NO);
  188. hl:=nil;
  189. oldflowcontrol := flowcontrol;
  190. include(flowcontrol,fc_inflowcontrol);
  191. secondpass(left);
  192. (*
  193. { save regvars loaded in the beginning so that we can restore them }
  194. { when processing the else-block }
  195. if cs_opt_regvar in current_settings.optimizerswitches then
  196. begin
  197. org_list := current_asmdata.CurrAsmList;
  198. current_asmdata.CurrAsmList := TAsmList.create;
  199. end;
  200. *)
  201. hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
  202. (*
  203. if cs_opt_regvar in current_settings.optimizerswitches then
  204. begin
  205. org_regvar_loaded_int := rg.regvar_loaded_int;
  206. org_regvar_loaded_other := rg.regvar_loaded_other;
  207. end;
  208. *)
  209. { determines registers weigths }
  210. oldexecutionweight:=cg.executionweight;
  211. cg.executionweight:=cg.executionweight div 2;
  212. if cg.executionweight<1 then
  213. cg.executionweight:=1;
  214. if assigned(right) then
  215. begin
  216. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  217. secondpass(right);
  218. end;
  219. { save current asmlist (previous instructions + then-block) and }
  220. { loaded regvar state and create new clean ones }
  221. {
  222. if cs_opt_regvar in current_settings.optimizerswitches then
  223. begin
  224. then_regvar_loaded_int := rg.regvar_loaded_int;
  225. then_regvar_loaded_other := rg.regvar_loaded_other;
  226. rg.regvar_loaded_int := org_regvar_loaded_int;
  227. rg.regvar_loaded_other := org_regvar_loaded_other;
  228. then_list := current_asmdata.CurrAsmList;
  229. current_asmdata.CurrAsmList := TAsmList.create;
  230. end;
  231. }
  232. if assigned(t1) then
  233. begin
  234. if assigned(right) then
  235. begin
  236. current_asmdata.getjumplabel(hl);
  237. { do go back to if line !! }
  238. (*
  239. if not(cs_opt_regvar in current_settings.optimizerswitches) then
  240. *)
  241. current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^
  242. (*
  243. else
  244. current_filepos:=then_list.getlasttaifilepos^
  245. *)
  246. ;
  247. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hl);
  248. end;
  249. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  250. secondpass(t1);
  251. (*
  252. { save current asmlist (previous instructions + else-block) }
  253. { and loaded regvar state and create a new clean list }
  254. if cs_opt_regvar in current_settings.optimizerswitches then
  255. begin
  256. { else_regvar_loaded_int := rg.regvar_loaded_int;
  257. else_regvar_loaded_other := rg.regvar_loaded_other;}
  258. else_list := current_asmdata.CurrAsmList;
  259. current_asmdata.CurrAsmList := TAsmList.create;
  260. end;
  261. *)
  262. if assigned(right) then
  263. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  264. end
  265. else
  266. begin
  267. (*
  268. if cs_opt_regvar in current_settings.optimizerswitches then
  269. begin
  270. { else_regvar_loaded_int := rg.regvar_loaded_int;
  271. else_regvar_loaded_other := rg.regvar_loaded_other;}
  272. else_list := current_asmdata.CurrAsmList;
  273. current_asmdata.CurrAsmList := TAsmList.create;
  274. end;
  275. *)
  276. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  277. end;
  278. if not(assigned(right)) then
  279. begin
  280. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  281. end;
  282. (*
  283. if cs_opt_regvar in current_settings.optimizerswitches then
  284. begin
  285. { add loads of regvars at the end of the then- and else-blocks }
  286. { so that at the end of both blocks the same regvars are loaded }
  287. { no else block? }
  288. if not assigned(t1) then
  289. begin
  290. sync_regvars_int(org_list,then_list,org_regvar_loaded_int,then_regvar_loaded_int);
  291. sync_regvars_other(org_list,then_list,org_regvar_loaded_other,then_regvar_loaded_other);
  292. end
  293. { no then block? }
  294. else if not assigned(right) then
  295. begin
  296. sync_regvars_int(org_list,else_list,org_regvar_loaded_int,else_regvar_loaded_int);
  297. sync_regvars_other(org_list,else_list,org_regvar_loaded_other,else_regvar_loaded_other);
  298. end
  299. { both else and then blocks }
  300. else
  301. begin
  302. sync_regvars_int(then_list,else_list,then_regvar_loaded_int,else_regvar_loaded_int);
  303. sync_regvars_other(then_list,else_list,then_regvar_loaded_other,else_regvar_loaded_other);
  304. end;
  305. { add all lists together }
  306. org_list.concatlist(then_list);
  307. then_list.free;
  308. org_list.concatlist(else_list);
  309. else_list.free;
  310. org_list.concatlist(current_asmdata.CurrAsmList);
  311. current_asmdata.CurrAsmList.free;
  312. current_asmdata.CurrAsmList := org_list;
  313. end;
  314. *)
  315. cg.executionweight:=oldexecutionweight;
  316. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  317. end;
  318. {*****************************************************************************
  319. SecondFor
  320. *****************************************************************************}
  321. procedure tcgfornode.pass_generate_code;
  322. begin
  323. { for nodes are converted in pass_1 in a while loop }
  324. internalerror(2015082501);
  325. end;
  326. {*****************************************************************************
  327. SecondExitN
  328. *****************************************************************************}
  329. procedure tcgexitnode.pass_generate_code;
  330. begin
  331. location_reset(location,LOC_VOID,OS_NO);
  332. include(flowcontrol,fc_exit);
  333. if assigned(left) then
  334. secondpass(left);
  335. if (fc_unwind_exit in flowcontrol) then
  336. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel)
  337. else
  338. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  339. end;
  340. {*****************************************************************************
  341. SecondBreakN
  342. *****************************************************************************}
  343. procedure tcgbreaknode.pass_generate_code;
  344. begin
  345. location_reset(location,LOC_VOID,OS_NO);
  346. include(flowcontrol,fc_break);
  347. if current_procinfo.CurrBreakLabel<>nil then
  348. begin
  349. {$ifdef OLDREGVARS}
  350. load_all_regvars(current_asmdata.CurrAsmList);
  351. {$endif OLDREGVARS}
  352. if (fc_unwind_loop in flowcontrol) then
  353. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  354. else
  355. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  356. end
  357. else
  358. CGMessage(cg_e_break_not_allowed);
  359. end;
  360. {*****************************************************************************
  361. SecondContinueN
  362. *****************************************************************************}
  363. procedure tcgcontinuenode.pass_generate_code;
  364. begin
  365. location_reset(location,LOC_VOID,OS_NO);
  366. include(flowcontrol,fc_continue);
  367. if current_procinfo.CurrContinueLabel<>nil then
  368. begin
  369. {$ifdef OLDREGVARS}
  370. load_all_regvars(current_asmdata.CurrAsmList);
  371. {$endif OLDREGVARS}
  372. if (fc_unwind_loop in flowcontrol) then
  373. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  374. else
  375. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  376. end
  377. else
  378. CGMessage(cg_e_continue_not_allowed);
  379. end;
  380. {*****************************************************************************
  381. SecondGoto
  382. *****************************************************************************}
  383. procedure tcggotonode.pass_generate_code;
  384. begin
  385. location_reset(location,LOC_VOID,OS_NO);
  386. include(flowcontrol,fc_gotolabel);
  387. {$ifdef OLDREGVARS}
  388. load_all_regvars(current_asmdata.CurrAsmList);
  389. {$endif OLDREGVARS}
  390. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(labelnode).getasmlabel)
  391. end;
  392. {*****************************************************************************
  393. SecondLabel
  394. *****************************************************************************}
  395. function tcglabelnode.getasmlabel : tasmlabel;
  396. begin
  397. if not(assigned(asmlabel)) then
  398. { labsym is not set in inlined procedures, but since assembler }
  399. { routines can't be inlined, that shouldn't matter }
  400. if assigned(labsym) and
  401. labsym.nonlocal then
  402. current_asmdata.getglobaljumplabel(asmlabel)
  403. else
  404. current_asmdata.getjumplabel(asmlabel);
  405. result:=asmlabel
  406. end;
  407. procedure tcglabelnode.pass_generate_code;
  408. begin
  409. location_reset(location,LOC_VOID,OS_NO);
  410. include(flowcontrol,fc_gotolabel);
  411. {$ifdef OLDREGVARS}
  412. load_all_regvars(current_asmdata.CurrAsmList);
  413. {$endif OLDREGVARS}
  414. hlcg.a_label(current_asmdata.CurrAsmList,getasmlabel);
  415. { Write also extra label if this label was referenced from
  416. assembler block }
  417. if assigned(labsym) and
  418. assigned(labsym.asmblocklabel) then
  419. hlcg.a_label(current_asmdata.CurrAsmList,labsym.asmblocklabel);
  420. secondpass(left);
  421. end;
  422. {*****************************************************************************
  423. Exception management
  424. *****************************************************************************}
  425. { Allocate the buffers for exception management and setjmp environment.
  426. Return a pointer to these buffers, send them to the utility routine
  427. so they are registered, and then call setjmp.
  428. Then compare the result of setjmp with 0, and if not equal
  429. to zero, then jump to exceptlabel.
  430. Also store the result of setjmp to a temporary space by calling g_save_exception_reason
  431. It is to note that this routine may be called *after* the stackframe of a
  432. routine has been called, therefore on machines where the stack cannot
  433. be modified, all temps should be allocated on the heap instead of the
  434. stack. }
  435. type
  436. texceptiontemps=record
  437. jmpbuf,
  438. envbuf,
  439. reasonbuf : treference;
  440. end;
  441. texceptionstate = record
  442. exceptionlabel: TAsmLabel;
  443. oldflowcontrol,
  444. newflowcontrol: tflowcontrol;
  445. end;
  446. procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
  447. begin
  448. tg.gethltemp(list,rec_exceptaddr,rec_exceptaddr.size,tt_persistent,t.envbuf);
  449. tg.gethltemp(list,rec_jmp_buf,rec_jmp_buf.size,tt_persistent,t.jmpbuf);
  450. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  451. end;
  452. procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  453. begin
  454. tg.Ungettemp(list,t.jmpbuf);
  455. tg.ungettemp(list,t.envbuf);
  456. tg.ungettemp(list,t.reasonbuf);
  457. end;
  458. procedure new_exception(list:TAsmList;const t:texceptiontemps; out exceptstate: texceptionstate);
  459. var
  460. paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
  461. pd: tprocdef;
  462. tmpresloc: tlocation;
  463. begin
  464. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  465. exceptstate.oldflowcontrol:=flowcontrol;
  466. flowcontrol:=[fc_inflowcontrol];
  467. paraloc1.init;
  468. paraloc2.init;
  469. paraloc3.init;
  470. { fpc_pushexceptaddr(exceptionframetype, setjmp_buffer, exception_address_chain_entry) }
  471. pd:=search_system_proc('fpc_pushexceptaddr');
  472. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  473. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,2,paraloc2);
  474. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,3,paraloc3);
  475. if pd.is_pushleftright then
  476. begin
  477. { type of exceptionframe }
  478. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  479. { setjmp buffer }
  480. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  481. { exception address chain entry }
  482. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  483. end
  484. else
  485. begin
  486. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  487. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  488. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  489. end;
  490. paramanager.freecgpara(list,paraloc3);
  491. paramanager.freecgpara(list,paraloc2);
  492. paramanager.freecgpara(list,paraloc1);
  493. { perform the fpc_pushexceptaddr call }
  494. pushexceptres:=hlcg.g_call_system_proc(list,pd,[@paraloc1,@paraloc2,@paraloc3],nil);
  495. paraloc1.done;
  496. paraloc2.done;
  497. paraloc3.done;
  498. { get the result }
  499. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(pushexceptres.def));
  500. tmpresloc.register:=hlcg.getaddressregister(list,pushexceptres.def);
  501. hlcg.gen_load_cgpara_loc(list,pushexceptres.def,pushexceptres,tmpresloc,true);
  502. pushexceptres.resetiftemp;
  503. { fpc_setjmp(result_of_pushexceptaddr_call) }
  504. pd:=search_system_proc('fpc_setjmp');
  505. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  506. hlcg.a_load_reg_cgpara(list,pushexceptres.def,tmpresloc.register,paraloc1);
  507. paramanager.freecgpara(list,paraloc1);
  508. { perform the fpc_setjmp call }
  509. setjmpres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  510. paraloc1.done;
  511. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(setjmpres.def));
  512. tmpresloc.register:=hlcg.getintregister(list,setjmpres.def);
  513. hlcg.gen_load_cgpara_loc(list,setjmpres.def,setjmpres,tmpresloc,true);
  514. hlcg.g_exception_reason_save(list,setjmpres.def,ossinttype,tmpresloc.register,t.reasonbuf);
  515. { if we get 0 here in the function result register, it means that we
  516. longjmp'd back here }
  517. hlcg.a_cmp_const_reg_label(list,setjmpres.def,OC_NE,0,tmpresloc.register,exceptstate.exceptionlabel);
  518. setjmpres.resetiftemp;
  519. end;
  520. procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
  521. begin
  522. hlcg.a_label(list,exceptionstate.exceptionlabel);
  523. exceptionstate.newflowcontrol:=flowcontrol;
  524. flowcontrol:=exceptionstate.oldflowcontrol;
  525. end;
  526. procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
  527. var
  528. reasonreg: tregister;
  529. begin
  530. hlcg.g_call_system_proc(list,'fpc_popaddrstack',[],nil);
  531. if not onlyfree then
  532. begin
  533. reasonreg:=hlcg.getintregister(list,osuinttype);
  534. hlcg.g_exception_reason_load(list,osuinttype,osuinttype,t.reasonbuf,reasonreg);
  535. hlcg.a_cmp_const_reg_label(list,osuinttype,OC_EQ,a,reasonreg,endexceptlabel);
  536. end;
  537. end;
  538. {*****************************************************************************
  539. SecondTryExcept
  540. *****************************************************************************}
  541. var
  542. endexceptlabel : tasmlabel;
  543. { does the necessary things to clean up the object stack }
  544. { in the except block }
  545. procedure cleanupobjectstack;
  546. begin
  547. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
  548. end;
  549. { generates code to be executed when another exeception is raised while
  550. control is inside except block }
  551. procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;var entrystate: texceptionstate);
  552. var
  553. exitlabel: tasmlabel;
  554. begin
  555. { don't generate line info for internal cleanup }
  556. list.concat(tai_marker.create(mark_NoLineInfoStart));
  557. current_asmdata.getjumplabel(exitlabel);
  558. emit_except_label(current_asmdata.CurrAsmList,entrystate);
  559. free_exception(list,t,0,exitlabel,false);
  560. { we don't need to save/restore registers here because reraise never }
  561. { returns }
  562. hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil);
  563. hlcg.a_label(list,exitlabel);
  564. cleanupobjectstack;
  565. end;
  566. procedure tcgtryexceptnode.pass_generate_code;
  567. var
  568. exceptlabel,oldendexceptlabel,
  569. lastonlabel,
  570. exitexceptlabel,
  571. continueexceptlabel,
  572. breakexceptlabel,
  573. exittrylabel,
  574. continuetrylabel,
  575. breaktrylabel,
  576. oldCurrExitLabel,
  577. oldContinueLabel,
  578. oldBreakLabel : tasmlabel;
  579. destroytemps,
  580. excepttemps : texceptiontemps;
  581. trystate,doobjectdestroyandreraisestate: texceptionstate;
  582. label
  583. errorexit;
  584. begin
  585. location_reset(location,LOC_VOID,OS_NO);
  586. continuetrylabel:=nil;
  587. breaktrylabel:=nil;
  588. continueexceptlabel:=nil;
  589. breakexceptlabel:=nil;
  590. { this can be called recursivly }
  591. oldBreakLabel:=nil;
  592. oldContinueLabel:=nil;
  593. oldendexceptlabel:=endexceptlabel;
  594. { save the old labels for control flow statements }
  595. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  596. if assigned(current_procinfo.CurrBreakLabel) then
  597. begin
  598. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  599. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  600. end;
  601. { get new labels for the control flow statements }
  602. current_asmdata.getjumplabel(exittrylabel);
  603. current_asmdata.getjumplabel(exitexceptlabel);
  604. if assigned(current_procinfo.CurrBreakLabel) then
  605. begin
  606. current_asmdata.getjumplabel(breaktrylabel);
  607. current_asmdata.getjumplabel(continuetrylabel);
  608. current_asmdata.getjumplabel(breakexceptlabel);
  609. current_asmdata.getjumplabel(continueexceptlabel);
  610. end;
  611. current_asmdata.getjumplabel(endexceptlabel);
  612. current_asmdata.getjumplabel(lastonlabel);
  613. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  614. new_exception(current_asmdata.CurrAsmList,excepttemps,trystate);
  615. { try block }
  616. { set control flow labels for the try block }
  617. current_procinfo.CurrExitLabel:=exittrylabel;
  618. if assigned(oldBreakLabel) then
  619. begin
  620. current_procinfo.CurrContinueLabel:=continuetrylabel;
  621. current_procinfo.CurrBreakLabel:=breaktrylabel;
  622. end;
  623. secondpass(left);
  624. if codegenerror then
  625. goto errorexit;
  626. { don't generate line info for internal cleanup }
  627. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  628. emit_except_label(current_asmdata.CurrAsmList,trystate);
  629. free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
  630. { end cleanup }
  631. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  632. { set control flow labels for the except block }
  633. { and the on statements }
  634. current_procinfo.CurrExitLabel:=exitexceptlabel;
  635. if assigned(oldBreakLabel) then
  636. begin
  637. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  638. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  639. end;
  640. flowcontrol:=[fc_inflowcontrol];
  641. { on statements }
  642. if assigned(right) then
  643. secondpass(right);
  644. { don't generate line info for internal cleanup }
  645. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  646. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  647. { default handling except handling }
  648. if assigned(t1) then
  649. begin
  650. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  651. it doesn't change any state and its return value is ignored (Sergei)
  652. }
  653. { the destruction of the exception object must be also }
  654. { guarded by an exception frame, but it can be omitted }
  655. { if there's no user code in 'except' block }
  656. if not (has_no_code(t1)) then
  657. begin
  658. get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  659. new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
  660. { the flowcontrol from the default except-block must be merged
  661. with the flowcontrol flags potentially set by the
  662. on-statements handled above (secondpass(right)), as they are
  663. at the same program level }
  664. flowcontrol:=
  665. flowcontrol+
  666. doobjectdestroyandreraisestate.oldflowcontrol;
  667. { except block needs line info }
  668. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  669. secondpass(t1);
  670. handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
  671. unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  672. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  673. end
  674. else
  675. begin
  676. doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
  677. cleanupobjectstack;
  678. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  679. end;
  680. end
  681. else
  682. begin
  683. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  684. doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
  685. end;
  686. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  687. begin
  688. { do some magic for exit in the try block }
  689. hlcg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
  690. { we must also destroy the address frame which guards }
  691. { exception object }
  692. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  693. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  694. cleanupobjectstack;
  695. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  696. end;
  697. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  698. begin
  699. hlcg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
  700. { we must also destroy the address frame which guards }
  701. { exception object }
  702. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  703. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  704. cleanupobjectstack;
  705. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  706. end;
  707. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  708. begin
  709. hlcg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
  710. { we must also destroy the address frame which guards }
  711. { exception object }
  712. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  713. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  714. cleanupobjectstack;
  715. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  716. end;
  717. if fc_exit in trystate.newflowcontrol then
  718. begin
  719. { do some magic for exit in the try block }
  720. hlcg.a_label(current_asmdata.CurrAsmList,exittrylabel);
  721. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  722. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  723. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  724. end;
  725. if fc_break in trystate.newflowcontrol then
  726. begin
  727. hlcg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
  728. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  729. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  730. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  731. end;
  732. if fc_continue in trystate.newflowcontrol then
  733. begin
  734. hlcg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
  735. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  736. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  737. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  738. end;
  739. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  740. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  741. { end cleanup }
  742. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  743. errorexit:
  744. { restore all saved labels }
  745. endexceptlabel:=oldendexceptlabel;
  746. { restore the control flow labels }
  747. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  748. if assigned(oldBreakLabel) then
  749. begin
  750. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  751. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  752. end;
  753. { return all used control flow statements }
  754. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  755. trystate.newflowcontrol - [fc_inflowcontrol]);
  756. end;
  757. procedure tcgonnode.pass_generate_code;
  758. var
  759. nextonlabel,
  760. exitonlabel,
  761. continueonlabel,
  762. breakonlabel,
  763. oldCurrExitLabel,
  764. oldContinueLabel,
  765. oldBreakLabel : tasmlabel;
  766. doobjectdestroyandreraisestate: texceptionstate;
  767. excepttemps : texceptiontemps;
  768. href2: treference;
  769. paraloc1 : tcgpara;
  770. exceptvarsym : tlocalvarsym;
  771. pd : tprocdef;
  772. fpc_catches_res: TCGPara;
  773. fpc_catches_resloc: tlocation;
  774. otherunit,
  775. indirect : boolean;
  776. begin
  777. paraloc1.init;
  778. location_reset(location,LOC_VOID,OS_NO);
  779. oldCurrExitLabel:=nil;
  780. continueonlabel:=nil;
  781. breakonlabel:=nil;
  782. exitonlabel:=nil;
  783. current_asmdata.getjumplabel(nextonlabel);
  784. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  785. indirect:=(tf_supports_packages in target_info.flags) and
  786. (target_info.system in systems_indirect_var_imports) and
  787. (cs_imported_data in current_settings.localswitches) and
  788. otherunit;
  789. { send the vmt parameter }
  790. pd:=search_system_proc('fpc_catches');
  791. reference_reset_symbol(href2,current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname,AT_DATA,indirect),0,sizeof(pint),[]);
  792. if otherunit then
  793. current_module.add_extern_asmsym(excepttype.vmt_mangledname,AB_EXTERNAL,AT_DATA);
  794. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  795. hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,excepttype.vmt_def,href2,paraloc1);
  796. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  797. fpc_catches_res:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@paraloc1],nil);
  798. location_reset(fpc_catches_resloc,LOC_REGISTER,def_cgsize(fpc_catches_res.def));
  799. fpc_catches_resloc.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fpc_catches_res.def);
  800. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fpc_catches_res.def,fpc_catches_res,fpc_catches_resloc,true);
  801. { is it this catch? No. go to next onlabel }
  802. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,fpc_catches_res.def,OC_EQ,0,fpc_catches_resloc.register,nextonlabel);
  803. { Retrieve exception variable }
  804. if assigned(excepTSymtable) then
  805. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  806. else
  807. internalerror(2011020401);
  808. if assigned(exceptvarsym) then
  809. begin
  810. location_reset_ref(exceptvarsym.localloc,LOC_REFERENCE,def_cgsize(voidpointertype),voidpointertype.alignment,[]);
  811. tg.GetLocal(current_asmdata.CurrAsmList,exceptvarsym.vardef.size,exceptvarsym.vardef,exceptvarsym.localloc.reference);
  812. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,fpc_catches_res.def,exceptvarsym.vardef,fpc_catches_resloc.register,exceptvarsym.localloc.reference);
  813. end;
  814. { in the case that another exception is risen
  815. we've to destroy the old one:
  816. call setjmp, and jump to finally label on non-zero result }
  817. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  818. new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
  819. oldBreakLabel:=nil;
  820. oldContinueLabel:=nil;
  821. if assigned(right) then
  822. begin
  823. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  824. current_asmdata.getjumplabel(exitonlabel);
  825. current_procinfo.CurrExitLabel:=exitonlabel;
  826. if assigned(current_procinfo.CurrBreakLabel) then
  827. begin
  828. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  829. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  830. current_asmdata.getjumplabel(breakonlabel);
  831. current_asmdata.getjumplabel(continueonlabel);
  832. current_procinfo.CurrContinueLabel:=continueonlabel;
  833. current_procinfo.CurrBreakLabel:=breakonlabel;
  834. end;
  835. secondpass(right);
  836. end;
  837. handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
  838. { clear some stuff }
  839. if assigned(exceptvarsym) then
  840. begin
  841. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  842. exceptvarsym.localloc.loc:=LOC_INVALID;
  843. end;
  844. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  845. if assigned(right) then
  846. begin
  847. { special handling for control flow instructions }
  848. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  849. begin
  850. { the address and object pop does secondtryexcept }
  851. cg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  852. cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  853. end;
  854. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  855. begin
  856. { the address and object pop does secondtryexcept }
  857. cg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  858. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  859. end;
  860. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  861. begin
  862. { the address and object pop does secondtryexcept }
  863. cg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  864. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  865. end;
  866. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  867. if assigned(oldBreakLabel) then
  868. begin
  869. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  870. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  871. end;
  872. end;
  873. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  874. cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  875. flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol]);
  876. paraloc1.done;
  877. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  878. { next on node }
  879. if assigned(left) then
  880. secondpass(left);
  881. end;
  882. {*****************************************************************************
  883. SecondTryFinally
  884. *****************************************************************************}
  885. procedure tcgtryfinallynode.handle_safecall_exception;
  886. var
  887. cgpara: tcgpara;
  888. selfsym: tparavarsym;
  889. pd: tprocdef;
  890. begin
  891. { call fpc_safecallhandler, passing self for methods of classes,
  892. nil otherwise. }
  893. pd:=search_system_proc('fpc_safecallhandler');
  894. cgpara.init;
  895. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  896. if is_class(current_procinfo.procdef.struct) then
  897. begin
  898. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  899. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  900. InternalError(2011123101);
  901. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.localloc,cgpara);
  902. end
  903. else
  904. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_ADDR,0,cgpara);
  905. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  906. cgpara.done;
  907. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLHANDLER');
  908. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
  909. end;
  910. procedure tcgtryfinallynode.pass_generate_code;
  911. var
  912. endfinallylabel,
  913. exitfinallylabel,
  914. continuefinallylabel,
  915. breakfinallylabel,
  916. oldCurrExitLabel,
  917. oldContinueLabel,
  918. oldBreakLabel : tasmlabel;
  919. finallyexceptionstate: texceptionstate;
  920. prefinallyflowcontrol : tflowcontrol;
  921. excepttemps : texceptiontemps;
  922. reasonreg : tregister;
  923. begin
  924. location_reset(location,LOC_VOID,OS_NO);
  925. oldBreakLabel:=nil;
  926. oldContinueLabel:=nil;
  927. continuefinallylabel:=nil;
  928. breakfinallylabel:=nil;
  929. current_asmdata.getjumplabel(endfinallylabel);
  930. { call setjmp, and jump to finally label on non-zero result }
  931. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  932. new_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate);
  933. { the finally block must catch break, continue and exit }
  934. { statements }
  935. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  936. if implicitframe then
  937. exitfinallylabel:=finallyexceptionstate.exceptionlabel
  938. else
  939. current_asmdata.getjumplabel(exitfinallylabel);
  940. current_procinfo.CurrExitLabel:=exitfinallylabel;
  941. if assigned(current_procinfo.CurrBreakLabel) then
  942. begin
  943. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  944. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  945. if implicitframe then
  946. begin
  947. breakfinallylabel:=finallyexceptionstate.exceptionlabel;
  948. continuefinallylabel:=finallyexceptionstate.exceptionlabel;
  949. end
  950. else
  951. begin
  952. current_asmdata.getjumplabel(breakfinallylabel);
  953. current_asmdata.getjumplabel(continuefinallylabel);
  954. end;
  955. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  956. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  957. end;
  958. { try code }
  959. if assigned(left) then
  960. begin
  961. secondpass(left);
  962. if codegenerror then
  963. exit;
  964. end;
  965. { don't generate line info for internal cleanup }
  966. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  967. emit_except_label(current_asmdata.CurrAsmList,finallyexceptionstate);
  968. { just free the frame information }
  969. free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallyexceptionstate.exceptionlabel,true);
  970. { end cleanup }
  971. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  972. { finally code (don't unconditionally set fc_inflowcontrol, since the
  973. finally code is unconditionally executed; we do have to filter out
  974. flags regarding break/contrinue/etc. because we have to give an
  975. error in case one of those is used in the finally-code }
  976. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol];
  977. secondpass(right);
  978. { goto is allowed if it stays inside the finally block,
  979. this is checked using the exception block number }
  980. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol]) then
  981. CGMessage(cg_e_control_flow_outside_finally);
  982. if codegenerror then
  983. exit;
  984. { don't generate line info for internal cleanup }
  985. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  986. { the value should now be in the exception handler }
  987. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  988. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  989. if implicitframe then
  990. begin
  991. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  992. { finally code only needed to be executed on exception (-> in
  993. if-branch -> fc_inflowcontrol) }
  994. flowcontrol:=[fc_inflowcontrol];
  995. secondpass(t1);
  996. if flowcontrol<>[fc_inflowcontrol] then
  997. CGMessage(cg_e_control_flow_outside_finally);
  998. if codegenerror then
  999. exit;
  1000. if (tf_safecall_exceptions in target_info.flags) and
  1001. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  1002. handle_safecall_exception
  1003. else
  1004. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1005. end
  1006. else
  1007. begin
  1008. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1009. if fc_exit in finallyexceptionstate.newflowcontrol then
  1010. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  1011. if fc_break in finallyexceptionstate.newflowcontrol then
  1012. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  1013. if fc_continue in finallyexceptionstate.newflowcontrol then
  1014. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  1015. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1016. { do some magic for exit,break,continue in the try block }
  1017. if fc_exit in finallyexceptionstate.newflowcontrol then
  1018. begin
  1019. hlcg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
  1020. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1021. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,2,excepttemps.reasonbuf);
  1022. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
  1023. end;
  1024. if fc_break in finallyexceptionstate.newflowcontrol then
  1025. begin
  1026. hlcg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
  1027. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1028. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,3,excepttemps.reasonbuf);
  1029. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
  1030. end;
  1031. if fc_continue in finallyexceptionstate.newflowcontrol then
  1032. begin
  1033. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  1034. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1035. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,4,excepttemps.reasonbuf);
  1036. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
  1037. end;
  1038. end;
  1039. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1040. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  1041. { end cleanup }
  1042. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1043. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1044. if assigned(current_procinfo.CurrBreakLabel) then
  1045. begin
  1046. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1047. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1048. end;
  1049. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol]);
  1050. end;
  1051. begin
  1052. cwhilerepeatnode:=tcgwhilerepeatnode;
  1053. cifnode:=tcgifnode;
  1054. cfornode:=tcgfornode;
  1055. cexitnode:=tcgexitnode;
  1056. cbreaknode:=tcgbreaknode;
  1057. ccontinuenode:=tcgcontinuenode;
  1058. cgotonode:=tcggotonode;
  1059. clabelnode:=tcglabelnode;
  1060. craisenode:=tcgraisenode;
  1061. ctryexceptnode:=tcgtryexceptnode;
  1062. ctryfinallynode:=tcgtryfinallynode;
  1063. connode:=tcgonnode;
  1064. end.