ncgflw.pas 52 KB

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