ncgflw.pas 62 KB

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