ncgflw.pas 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243
  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. procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
  442. begin
  443. tg.gethltemp(list,rec_exceptaddr,rec_exceptaddr.size,tt_persistent,t.envbuf);
  444. tg.gethltemp(list,rec_jmp_buf,rec_jmp_buf.size,tt_persistent,t.jmpbuf);
  445. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  446. end;
  447. procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  448. begin
  449. tg.Ungettemp(list,t.jmpbuf);
  450. tg.ungettemp(list,t.envbuf);
  451. tg.ungettemp(list,t.reasonbuf);
  452. end;
  453. procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);
  454. var
  455. paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
  456. pd: tprocdef;
  457. tmpresloc: tlocation;
  458. begin
  459. paraloc1.init;
  460. paraloc2.init;
  461. paraloc3.init;
  462. { fpc_pushexceptaddr(exceptionframetype, setjmp_buffer, exception_address_chain_entry) }
  463. pd:=search_system_proc('fpc_pushexceptaddr');
  464. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  465. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,2,paraloc2);
  466. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,3,paraloc3);
  467. if pd.is_pushleftright then
  468. begin
  469. { type of exceptionframe }
  470. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  471. { setjmp buffer }
  472. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  473. { exception address chain entry }
  474. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  475. end
  476. else
  477. begin
  478. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  479. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  480. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  481. end;
  482. paramanager.freecgpara(list,paraloc3);
  483. paramanager.freecgpara(list,paraloc2);
  484. paramanager.freecgpara(list,paraloc1);
  485. { perform the fpc_pushexceptaddr call }
  486. pushexceptres:=hlcg.g_call_system_proc(list,pd,[@paraloc1,@paraloc2,@paraloc3],nil);
  487. paraloc1.done;
  488. paraloc2.done;
  489. paraloc3.done;
  490. { get the result }
  491. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(pushexceptres.def));
  492. tmpresloc.register:=hlcg.getaddressregister(list,pushexceptres.def);
  493. hlcg.gen_load_cgpara_loc(list,pushexceptres.def,pushexceptres,tmpresloc,true);
  494. pushexceptres.resetiftemp;
  495. { fpc_setjmp(result_of_pushexceptaddr_call) }
  496. pd:=search_system_proc('fpc_setjmp');
  497. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  498. hlcg.a_load_reg_cgpara(list,pushexceptres.def,tmpresloc.register,paraloc1);
  499. paramanager.freecgpara(list,paraloc1);
  500. { perform the fpc_setjmp call }
  501. setjmpres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  502. paraloc1.done;
  503. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(setjmpres.def));
  504. tmpresloc.register:=hlcg.getintregister(list,setjmpres.def);
  505. hlcg.gen_load_cgpara_loc(list,setjmpres.def,setjmpres,tmpresloc,true);
  506. hlcg.g_exception_reason_save(list,setjmpres.def,ossinttype,tmpresloc.register,t.reasonbuf);
  507. { if we get 0 here in the function result register, it means that we
  508. longjmp'd back here }
  509. hlcg.a_cmp_const_reg_label(list,setjmpres.def,OC_NE,0,tmpresloc.register,exceptlabel);
  510. setjmpres.resetiftemp;
  511. end;
  512. procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
  513. var
  514. reasonreg: tregister;
  515. begin
  516. hlcg.g_call_system_proc(list,'fpc_popaddrstack',[],nil);
  517. if not onlyfree then
  518. begin
  519. reasonreg:=hlcg.getintregister(list,osuinttype);
  520. hlcg.g_exception_reason_load(list,osuinttype,osuinttype,t.reasonbuf,reasonreg);
  521. hlcg.a_cmp_const_reg_label(list,osuinttype,OC_EQ,a,reasonreg,endexceptlabel);
  522. end;
  523. end;
  524. {*****************************************************************************
  525. SecondTryExcept
  526. *****************************************************************************}
  527. var
  528. endexceptlabel : tasmlabel;
  529. { does the necessary things to clean up the object stack }
  530. { in the except block }
  531. procedure cleanupobjectstack;
  532. begin
  533. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
  534. end;
  535. { generates code to be executed when another exeception is raised while
  536. control is inside except block }
  537. procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;entrylabel:TAsmLabel);
  538. var
  539. exitlabel: tasmlabel;
  540. begin
  541. { don't generate line info for internal cleanup }
  542. list.concat(tai_marker.create(mark_NoLineInfoStart));
  543. current_asmdata.getjumplabel(exitlabel);
  544. hlcg.a_label(list,entrylabel);
  545. free_exception(list,t,0,exitlabel,false);
  546. { we don't need to save/restore registers here because reraise never }
  547. { returns }
  548. hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil);
  549. hlcg.a_label(list,exitlabel);
  550. cleanupobjectstack;
  551. end;
  552. procedure tcgtryexceptnode.pass_generate_code;
  553. var
  554. exceptlabel,oldendexceptlabel,
  555. lastonlabel,
  556. exitexceptlabel,
  557. continueexceptlabel,
  558. breakexceptlabel,
  559. exittrylabel,
  560. continuetrylabel,
  561. breaktrylabel,
  562. doobjectdestroyandreraise,
  563. oldCurrExitLabel,
  564. oldContinueLabel,
  565. oldBreakLabel : tasmlabel;
  566. oldflowcontrol,tryflowcontrol,
  567. exceptflowcontrol : tflowcontrol;
  568. destroytemps,
  569. excepttemps : texceptiontemps;
  570. label
  571. errorexit;
  572. begin
  573. location_reset(location,LOC_VOID,OS_NO);
  574. exceptflowcontrol:=[];
  575. continuetrylabel:=nil;
  576. breaktrylabel:=nil;
  577. continueexceptlabel:=nil;
  578. breakexceptlabel:=nil;
  579. oldflowcontrol:=flowcontrol;
  580. flowcontrol:=[fc_inflowcontrol];
  581. { this can be called recursivly }
  582. oldBreakLabel:=nil;
  583. oldContinueLabel:=nil;
  584. oldendexceptlabel:=endexceptlabel;
  585. { save the old labels for control flow statements }
  586. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  587. if assigned(current_procinfo.CurrBreakLabel) then
  588. begin
  589. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  590. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  591. end;
  592. { get new labels for the control flow statements }
  593. current_asmdata.getjumplabel(exittrylabel);
  594. current_asmdata.getjumplabel(exitexceptlabel);
  595. if assigned(current_procinfo.CurrBreakLabel) then
  596. begin
  597. current_asmdata.getjumplabel(breaktrylabel);
  598. current_asmdata.getjumplabel(continuetrylabel);
  599. current_asmdata.getjumplabel(breakexceptlabel);
  600. current_asmdata.getjumplabel(continueexceptlabel);
  601. end;
  602. current_asmdata.getjumplabel(exceptlabel);
  603. current_asmdata.getjumplabel(endexceptlabel);
  604. current_asmdata.getjumplabel(lastonlabel);
  605. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  606. new_exception(current_asmdata.CurrAsmList,excepttemps,exceptlabel);
  607. { try block }
  608. { set control flow labels for the try block }
  609. current_procinfo.CurrExitLabel:=exittrylabel;
  610. if assigned(oldBreakLabel) then
  611. begin
  612. current_procinfo.CurrContinueLabel:=continuetrylabel;
  613. current_procinfo.CurrBreakLabel:=breaktrylabel;
  614. end;
  615. flowcontrol:=[fc_inflowcontrol];
  616. secondpass(left);
  617. tryflowcontrol:=flowcontrol;
  618. if codegenerror then
  619. goto errorexit;
  620. { don't generate line info for internal cleanup }
  621. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  622. hlcg.a_label(current_asmdata.CurrAsmList,exceptlabel);
  623. free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
  624. { end cleanup }
  625. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  626. { set control flow labels for the except block }
  627. { and the on statements }
  628. current_procinfo.CurrExitLabel:=exitexceptlabel;
  629. if assigned(oldBreakLabel) then
  630. begin
  631. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  632. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  633. end;
  634. flowcontrol:=[fc_inflowcontrol];
  635. { on statements }
  636. if assigned(right) then
  637. secondpass(right);
  638. { don't generate line info for internal cleanup }
  639. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  640. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  641. { default handling except handling }
  642. if assigned(t1) then
  643. begin
  644. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  645. it doesn't change any state and its return value is ignored (Sergei)
  646. }
  647. { the destruction of the exception object must be also }
  648. { guarded by an exception frame, but it can be omitted }
  649. { if there's no user code in 'except' block }
  650. if not (has_no_code(t1)) then
  651. begin
  652. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  653. get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  654. new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  655. { except block needs line info }
  656. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  657. { here we don't have to reset flowcontrol }
  658. { the default and on flowcontrols are handled equal }
  659. secondpass(t1);
  660. exceptflowcontrol:=flowcontrol;
  661. handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  662. unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  663. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  664. end
  665. else
  666. begin
  667. exceptflowcontrol:=flowcontrol;
  668. cleanupobjectstack;
  669. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  670. end;
  671. end
  672. else
  673. begin
  674. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  675. exceptflowcontrol:=flowcontrol;
  676. end;
  677. if fc_exit in exceptflowcontrol then
  678. begin
  679. { do some magic for exit in the try block }
  680. hlcg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
  681. { we must also destroy the address frame which guards }
  682. { exception object }
  683. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  684. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  685. cleanupobjectstack;
  686. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  687. end;
  688. if fc_break in exceptflowcontrol then
  689. begin
  690. hlcg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
  691. { we must also destroy the address frame which guards }
  692. { exception object }
  693. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  694. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  695. cleanupobjectstack;
  696. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  697. end;
  698. if fc_continue in exceptflowcontrol then
  699. begin
  700. hlcg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
  701. { we must also destroy the address frame which guards }
  702. { exception object }
  703. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  704. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  705. cleanupobjectstack;
  706. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  707. end;
  708. if fc_exit in tryflowcontrol then
  709. begin
  710. { do some magic for exit in the try block }
  711. hlcg.a_label(current_asmdata.CurrAsmList,exittrylabel);
  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. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  715. end;
  716. if fc_break in tryflowcontrol then
  717. begin
  718. hlcg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
  719. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  720. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  721. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  722. end;
  723. if fc_continue in tryflowcontrol then
  724. begin
  725. hlcg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
  726. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  727. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  728. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  729. end;
  730. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  731. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  732. { end cleanup }
  733. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  734. errorexit:
  735. { restore all saved labels }
  736. endexceptlabel:=oldendexceptlabel;
  737. { restore the control flow labels }
  738. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  739. if assigned(oldBreakLabel) then
  740. begin
  741. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  742. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  743. end;
  744. { return all used control flow statements }
  745. flowcontrol:=oldflowcontrol+(exceptflowcontrol +
  746. tryflowcontrol - [fc_inflowcontrol]);
  747. end;
  748. procedure tcgonnode.pass_generate_code;
  749. var
  750. nextonlabel,
  751. exitonlabel,
  752. continueonlabel,
  753. breakonlabel,
  754. oldCurrExitLabel,
  755. oldContinueLabel,
  756. doobjectdestroyandreraise,
  757. oldBreakLabel : tasmlabel;
  758. oldflowcontrol : tflowcontrol;
  759. excepttemps : texceptiontemps;
  760. href2: treference;
  761. paraloc1 : tcgpara;
  762. exceptvarsym : tlocalvarsym;
  763. pd : tprocdef;
  764. fpc_catches_res: TCGPara;
  765. fpc_catches_resloc: tlocation;
  766. otherunit,
  767. indirect : boolean;
  768. begin
  769. paraloc1.init;
  770. location_reset(location,LOC_VOID,OS_NO);
  771. oldCurrExitLabel:=nil;
  772. continueonlabel:=nil;
  773. breakonlabel:=nil;
  774. exitonlabel:=nil;
  775. oldflowcontrol:=flowcontrol;
  776. flowcontrol:=[fc_inflowcontrol];
  777. current_asmdata.getjumplabel(nextonlabel);
  778. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  779. indirect:=(tf_supports_packages in target_info.flags) and
  780. (target_info.system in systems_indirect_var_imports) and
  781. (cs_imported_data in current_settings.localswitches) and
  782. otherunit;
  783. { send the vmt parameter }
  784. pd:=search_system_proc('fpc_catches');
  785. reference_reset_symbol(href2,current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname,AT_DATA,indirect),0,sizeof(pint),[]);
  786. if otherunit then
  787. current_module.add_extern_asmsym(excepttype.vmt_mangledname,AB_EXTERNAL,AT_DATA);
  788. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  789. hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,excepttype.vmt_def,href2,paraloc1);
  790. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  791. fpc_catches_res:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@paraloc1],nil);
  792. location_reset(fpc_catches_resloc,LOC_REGISTER,def_cgsize(fpc_catches_res.def));
  793. fpc_catches_resloc.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fpc_catches_res.def);
  794. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fpc_catches_res.def,fpc_catches_res,fpc_catches_resloc,true);
  795. { is it this catch? No. go to next onlabel }
  796. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,fpc_catches_res.def,OC_EQ,0,fpc_catches_resloc.register,nextonlabel);
  797. { Retrieve exception variable }
  798. if assigned(excepTSymtable) then
  799. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  800. else
  801. internalerror(2011020401);
  802. if assigned(exceptvarsym) then
  803. begin
  804. location_reset_ref(exceptvarsym.localloc,LOC_REFERENCE,def_cgsize(voidpointertype),voidpointertype.alignment,[]);
  805. tg.GetLocal(current_asmdata.CurrAsmList,exceptvarsym.vardef.size,exceptvarsym.vardef,exceptvarsym.localloc.reference);
  806. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,fpc_catches_res.def,exceptvarsym.vardef,fpc_catches_resloc.register,exceptvarsym.localloc.reference);
  807. end;
  808. { in the case that another exception is risen
  809. we've to destroy the old one }
  810. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  811. { call setjmp, and jump to finally label on non-zero result }
  812. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  813. new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  814. oldBreakLabel:=nil;
  815. oldContinueLabel:=nil;
  816. if assigned(right) then
  817. begin
  818. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  819. current_asmdata.getjumplabel(exitonlabel);
  820. current_procinfo.CurrExitLabel:=exitonlabel;
  821. if assigned(current_procinfo.CurrBreakLabel) then
  822. begin
  823. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  824. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  825. current_asmdata.getjumplabel(breakonlabel);
  826. current_asmdata.getjumplabel(continueonlabel);
  827. current_procinfo.CurrContinueLabel:=continueonlabel;
  828. current_procinfo.CurrBreakLabel:=breakonlabel;
  829. end;
  830. secondpass(right);
  831. end;
  832. handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  833. { clear some stuff }
  834. if assigned(exceptvarsym) then
  835. begin
  836. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  837. exceptvarsym.localloc.loc:=LOC_INVALID;
  838. end;
  839. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  840. if assigned(right) then
  841. begin
  842. { special handling for control flow instructions }
  843. if fc_exit in flowcontrol then
  844. begin
  845. { the address and object pop does secondtryexcept }
  846. cg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  847. cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  848. end;
  849. if fc_break in flowcontrol then
  850. begin
  851. { the address and object pop does secondtryexcept }
  852. cg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  853. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  854. end;
  855. if fc_continue in flowcontrol then
  856. begin
  857. { the address and object pop does secondtryexcept }
  858. cg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  859. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  860. end;
  861. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  862. if assigned(oldBreakLabel) then
  863. begin
  864. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  865. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  866. end;
  867. end;
  868. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  869. cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  870. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
  871. paraloc1.done;
  872. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  873. { next on node }
  874. if assigned(left) then
  875. secondpass(left);
  876. end;
  877. {*****************************************************************************
  878. SecondTryFinally
  879. *****************************************************************************}
  880. procedure tcgtryfinallynode.handle_safecall_exception;
  881. var
  882. cgpara: tcgpara;
  883. selfsym: tparavarsym;
  884. pd: tprocdef;
  885. begin
  886. { call fpc_safecallhandler, passing self for methods of classes,
  887. nil otherwise. }
  888. pd:=search_system_proc('fpc_safecallhandler');
  889. cgpara.init;
  890. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  891. if is_class(current_procinfo.procdef.struct) then
  892. begin
  893. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  894. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  895. InternalError(2011123101);
  896. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.localloc,cgpara);
  897. end
  898. else
  899. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_ADDR,0,cgpara);
  900. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  901. cgpara.done;
  902. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLHANDLER');
  903. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
  904. end;
  905. procedure tcgtryfinallynode.pass_generate_code;
  906. var
  907. finallylabel,
  908. endfinallylabel,
  909. exitfinallylabel,
  910. continuefinallylabel,
  911. breakfinallylabel,
  912. oldCurrExitLabel,
  913. oldContinueLabel,
  914. oldBreakLabel : tasmlabel;
  915. oldflowcontrol,tryflowcontrol : tflowcontrol;
  916. excepttemps : texceptiontemps;
  917. reasonreg : tregister;
  918. begin
  919. location_reset(location,LOC_VOID,OS_NO);
  920. tryflowcontrol:=[];
  921. oldBreakLabel:=nil;
  922. oldContinueLabel:=nil;
  923. continuefinallylabel:=nil;
  924. breakfinallylabel:=nil;
  925. { check if child nodes do a break/continue/exit }
  926. oldflowcontrol:=flowcontrol;
  927. flowcontrol:=[fc_inflowcontrol];
  928. current_asmdata.getjumplabel(finallylabel);
  929. current_asmdata.getjumplabel(endfinallylabel);
  930. { the finally block must catch break, continue and exit }
  931. { statements }
  932. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  933. if implicitframe then
  934. exitfinallylabel:=finallylabel
  935. else
  936. current_asmdata.getjumplabel(exitfinallylabel);
  937. current_procinfo.CurrExitLabel:=exitfinallylabel;
  938. if assigned(current_procinfo.CurrBreakLabel) then
  939. begin
  940. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  941. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  942. if implicitframe then
  943. begin
  944. breakfinallylabel:=finallylabel;
  945. continuefinallylabel:=finallylabel;
  946. end
  947. else
  948. begin
  949. current_asmdata.getjumplabel(breakfinallylabel);
  950. current_asmdata.getjumplabel(continuefinallylabel);
  951. end;
  952. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  953. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  954. end;
  955. { call setjmp, and jump to finally label on non-zero result }
  956. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  957. new_exception(current_asmdata.CurrAsmList,excepttemps,finallylabel);
  958. { try code }
  959. if assigned(left) then
  960. begin
  961. secondpass(left);
  962. tryflowcontrol:=flowcontrol;
  963. if codegenerror then
  964. exit;
  965. end;
  966. { don't generate line info for internal cleanup }
  967. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  968. hlcg.a_label(current_asmdata.CurrAsmList,finallylabel);
  969. { just free the frame information }
  970. free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallylabel,true);
  971. { end cleanup }
  972. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  973. { finally code }
  974. flowcontrol:=[fc_inflowcontrol];
  975. secondpass(right);
  976. { goto is allowed if it stays inside the finally block,
  977. this is checked using the exception block number }
  978. if (flowcontrol-[fc_gotolabel])<>[fc_inflowcontrol] then
  979. CGMessage(cg_e_control_flow_outside_finally);
  980. if codegenerror then
  981. exit;
  982. { don't generate line info for internal cleanup }
  983. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  984. { the value should now be in the exception handler }
  985. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  986. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  987. if implicitframe then
  988. begin
  989. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  990. { finally code only needed to be executed on exception }
  991. flowcontrol:=[fc_inflowcontrol];
  992. secondpass(t1);
  993. if flowcontrol<>[fc_inflowcontrol] then
  994. CGMessage(cg_e_control_flow_outside_finally);
  995. if codegenerror then
  996. exit;
  997. if (tf_safecall_exceptions in target_info.flags) and
  998. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  999. handle_safecall_exception
  1000. else
  1001. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1002. end
  1003. else
  1004. begin
  1005. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1006. if fc_exit in tryflowcontrol then
  1007. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  1008. if fc_break in tryflowcontrol then
  1009. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  1010. if fc_continue in tryflowcontrol then
  1011. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  1012. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1013. { do some magic for exit,break,continue in the try block }
  1014. if fc_exit in tryflowcontrol then
  1015. begin
  1016. hlcg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
  1017. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1018. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,2,excepttemps.reasonbuf);
  1019. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1020. end;
  1021. if fc_break in tryflowcontrol then
  1022. begin
  1023. hlcg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
  1024. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1025. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,3,excepttemps.reasonbuf);
  1026. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1027. end;
  1028. if fc_continue in tryflowcontrol then
  1029. begin
  1030. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  1031. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1032. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,4,excepttemps.reasonbuf);
  1033. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1034. end;
  1035. end;
  1036. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1037. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  1038. { end cleanup }
  1039. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1040. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1041. if assigned(current_procinfo.CurrBreakLabel) then
  1042. begin
  1043. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1044. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1045. end;
  1046. flowcontrol:=oldflowcontrol+(tryflowcontrol-[fc_inflowcontrol]);
  1047. end;
  1048. begin
  1049. cwhilerepeatnode:=tcgwhilerepeatnode;
  1050. cifnode:=tcgifnode;
  1051. cfornode:=tcgfornode;
  1052. cexitnode:=tcgexitnode;
  1053. cbreaknode:=tcgbreaknode;
  1054. ccontinuenode:=tcgcontinuenode;
  1055. cgotonode:=tcggotonode;
  1056. clabelnode:=tcglabelnode;
  1057. craisenode:=tcgraisenode;
  1058. ctryexceptnode:=tcgtryexceptnode;
  1059. ctryfinallynode:=tcgtryfinallynode;
  1060. connode:=tcgonnode;
  1061. end.