ncgflw.pas 62 KB

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