ncgflw.pas 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  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,cgexcept;
  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. tcgtryexceptnode = class(ttryexceptnode)
  65. protected
  66. type
  67. tframetype = (ft_try,ft_except);
  68. procedure emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel); virtual;
  69. public
  70. procedure pass_generate_code;override;
  71. end;
  72. tcgtryfinallynode = class(ttryfinallynode)
  73. protected
  74. procedure emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
  75. function get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
  76. public
  77. procedure handle_safecall_exception;
  78. procedure pass_generate_code;override;
  79. end;
  80. tcgonnode = class(tonnode)
  81. procedure pass_generate_code;override;
  82. end;
  83. implementation
  84. uses
  85. cutils,
  86. verbose,globals,systems,
  87. symconst,symsym,symtable,aasmtai,aasmcpu,defutil,
  88. procinfo,parabase,
  89. fmodule,
  90. cpubase,
  91. tgobj,paramgr,
  92. cgobj,hlcgobj,nutils
  93. {$ifndef jvm}
  94. ,psabiehpi
  95. {$endif jvm}
  96. ;
  97. {*****************************************************************************
  98. Second_While_RepeatN
  99. *****************************************************************************}
  100. procedure tcgwhilerepeatnode.sync_regvars(checkusedregvars: boolean);
  101. begin
  102. if (cs_opt_regvar in current_settings.optimizerswitches) and
  103. not(pi_has_label in current_procinfo.flags) then
  104. begin
  105. if checkusedregvars then
  106. begin
  107. usedregvars.intregvars.init;
  108. usedregvars.addrregvars.init;
  109. usedregvars.fpuregvars.init;
  110. usedregvars.mmregvars.init;
  111. { we have to synchronise both the regvars used in the loop }
  112. { and the ones in the while/until condition }
  113. get_used_regvars(self,usedregvars);
  114. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  115. end
  116. else
  117. begin
  118. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  119. usedregvars.intregvars.done;
  120. usedregvars.addrregvars.done;
  121. usedregvars.fpuregvars.done;
  122. usedregvars.mmregvars.done;
  123. end;
  124. end;
  125. end;
  126. procedure tcgwhilerepeatnode.pass_generate_code;
  127. var
  128. lcont,lbreak,lloop,
  129. oldclabel,oldblabel : tasmlabel;
  130. truelabel,falselabel : tasmlabel;
  131. oldflowcontrol : tflowcontrol;
  132. begin
  133. location_reset(location,LOC_VOID,OS_NO);
  134. current_asmdata.getjumplabel(lloop);
  135. current_asmdata.getjumplabel(lcont);
  136. current_asmdata.getjumplabel(lbreak);
  137. { arrange continue and breaklabels: }
  138. oldflowcontrol:=flowcontrol;
  139. oldclabel:=current_procinfo.CurrContinueLabel;
  140. oldblabel:=current_procinfo.CurrBreakLabel;
  141. include(flowcontrol,fc_inflowcontrol);
  142. exclude(flowcontrol,fc_unwind_loop);
  143. sync_regvars(true);
  144. {$ifdef OLDREGVARS}
  145. load_all_regvars(current_asmdata.CurrAsmList);
  146. {$endif OLDREGVARS}
  147. { handling code at the end as it is much more efficient, and makes
  148. while equal to repeat loop, only the end true/false is swapped (PFV) }
  149. if lnf_testatbegin in loopflags then
  150. hlcg.a_jmp_always(current_asmdata.CurrAsmList,lcont);
  151. if not(cs_opt_size in current_settings.optimizerswitches) then
  152. { align loop target, as an unconditional jump is done before,
  153. use jump align which assume that the instructions inserted as alignment are never executed }
  154. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  155. hlcg.a_label(current_asmdata.CurrAsmList,lloop);
  156. current_procinfo.CurrContinueLabel:=lcont;
  157. current_procinfo.CurrBreakLabel:=lbreak;
  158. if assigned(right) then
  159. secondpass(right);
  160. {$ifdef OLDREGVARS}
  161. load_all_regvars(current_asmdata.CurrAsmList);
  162. {$endif OLDREGVARS}
  163. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  164. if lnf_checknegate in loopflags then
  165. begin
  166. truelabel:=lbreak;
  167. falselabel:=lloop;
  168. end
  169. else
  170. begin
  171. truelabel:=lloop;
  172. falselabel:=lbreak;
  173. end;
  174. secondpass(left);
  175. hlcg.maketojumpboollabels(current_asmdata.CurrAsmList,left,truelabel,falselabel);
  176. hlcg.a_label(current_asmdata.CurrAsmList,lbreak);
  177. sync_regvars(false);
  178. current_procinfo.CurrContinueLabel:=oldclabel;
  179. current_procinfo.CurrBreakLabel:=oldblabel;
  180. { a break/continue in a while/repeat block can't be seen outside }
  181. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  182. end;
  183. {*****************************************************************************
  184. tcgIFNODE
  185. *****************************************************************************}
  186. procedure tcgifnode.pass_generate_code;
  187. var
  188. hl : tasmlabel;
  189. oldflowcontrol: tflowcontrol;
  190. (*
  191. org_regvar_loaded_other,
  192. then_regvar_loaded_other,
  193. else_regvar_loaded_other : regvarother_booleanarray;
  194. org_regvar_loaded_int,
  195. then_regvar_loaded_int,
  196. else_regvar_loaded_int : Tsuperregisterset;
  197. org_list,
  198. then_list,
  199. else_list : TAsmList;
  200. *)
  201. begin
  202. location_reset(location,LOC_VOID,OS_NO);
  203. hl:=nil;
  204. oldflowcontrol := flowcontrol;
  205. include(flowcontrol,fc_inflowcontrol);
  206. secondpass(left);
  207. (*
  208. { save regvars loaded in the beginning so that we can restore them }
  209. { when processing the else-block }
  210. if cs_opt_regvar in current_settings.optimizerswitches then
  211. begin
  212. org_list := current_asmdata.CurrAsmList;
  213. current_asmdata.CurrAsmList := TAsmList.create;
  214. end;
  215. *)
  216. hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
  217. (*
  218. if cs_opt_regvar in current_settings.optimizerswitches then
  219. begin
  220. org_regvar_loaded_int := rg.regvar_loaded_int;
  221. org_regvar_loaded_other := rg.regvar_loaded_other;
  222. end;
  223. *)
  224. if assigned(right) then
  225. begin
  226. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  227. secondpass(right);
  228. end;
  229. { save current asmlist (previous instructions + then-block) and }
  230. { loaded regvar state and create new clean ones }
  231. {
  232. if cs_opt_regvar in current_settings.optimizerswitches then
  233. begin
  234. then_regvar_loaded_int := rg.regvar_loaded_int;
  235. then_regvar_loaded_other := rg.regvar_loaded_other;
  236. rg.regvar_loaded_int := org_regvar_loaded_int;
  237. rg.regvar_loaded_other := org_regvar_loaded_other;
  238. then_list := current_asmdata.CurrAsmList;
  239. current_asmdata.CurrAsmList := TAsmList.create;
  240. end;
  241. }
  242. if assigned(t1) then
  243. begin
  244. if assigned(right) then
  245. begin
  246. current_asmdata.getjumplabel(hl);
  247. { do go back to if line !! }
  248. (*
  249. if not(cs_opt_regvar in current_settings.optimizerswitches) then
  250. *)
  251. current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^
  252. (*
  253. else
  254. current_filepos:=then_list.getlasttaifilepos^
  255. *)
  256. ;
  257. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hl);
  258. if not(cs_opt_size in current_settings.optimizerswitches) then
  259. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  260. end;
  261. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  262. secondpass(t1);
  263. (*
  264. { save current asmlist (previous instructions + else-block) }
  265. { and loaded regvar state and create a new clean list }
  266. if cs_opt_regvar in current_settings.optimizerswitches then
  267. begin
  268. { else_regvar_loaded_int := rg.regvar_loaded_int;
  269. else_regvar_loaded_other := rg.regvar_loaded_other;}
  270. else_list := current_asmdata.CurrAsmList;
  271. current_asmdata.CurrAsmList := TAsmList.create;
  272. end;
  273. *)
  274. if assigned(right) then
  275. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  276. end
  277. else
  278. begin
  279. (*
  280. if cs_opt_regvar in current_settings.optimizerswitches then
  281. begin
  282. { else_regvar_loaded_int := rg.regvar_loaded_int;
  283. else_regvar_loaded_other := rg.regvar_loaded_other;}
  284. else_list := current_asmdata.CurrAsmList;
  285. current_asmdata.CurrAsmList := TAsmList.create;
  286. end;
  287. *)
  288. if not(cs_opt_size in current_settings.optimizerswitches) then
  289. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.coalescealign,current_settings.alignment.coalescealignskipmax));
  290. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  291. end;
  292. if not(assigned(right)) then
  293. begin
  294. if not(cs_opt_size in current_settings.optimizerswitches) then
  295. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.coalescealign,current_settings.alignment.coalescealignskipmax));
  296. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  297. end;
  298. (*
  299. if cs_opt_regvar in current_settings.optimizerswitches then
  300. begin
  301. { add loads of regvars at the end of the then- and else-blocks }
  302. { so that at the end of both blocks the same regvars are loaded }
  303. { no else block? }
  304. if not assigned(t1) then
  305. begin
  306. sync_regvars_int(org_list,then_list,org_regvar_loaded_int,then_regvar_loaded_int);
  307. sync_regvars_other(org_list,then_list,org_regvar_loaded_other,then_regvar_loaded_other);
  308. end
  309. { no then block? }
  310. else if not assigned(right) then
  311. begin
  312. sync_regvars_int(org_list,else_list,org_regvar_loaded_int,else_regvar_loaded_int);
  313. sync_regvars_other(org_list,else_list,org_regvar_loaded_other,else_regvar_loaded_other);
  314. end
  315. { both else and then blocks }
  316. else
  317. begin
  318. sync_regvars_int(then_list,else_list,then_regvar_loaded_int,else_regvar_loaded_int);
  319. sync_regvars_other(then_list,else_list,then_regvar_loaded_other,else_regvar_loaded_other);
  320. end;
  321. { add all lists together }
  322. org_list.concatlist(then_list);
  323. then_list.free;
  324. org_list.concatlist(else_list);
  325. else_list.free;
  326. org_list.concatlist(current_asmdata.CurrAsmList);
  327. current_asmdata.CurrAsmList.free;
  328. current_asmdata.CurrAsmList := org_list;
  329. end;
  330. *)
  331. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  332. end;
  333. {*****************************************************************************
  334. SecondFor
  335. *****************************************************************************}
  336. procedure tcgfornode.pass_generate_code;
  337. begin
  338. { for nodes are converted in pass_1 in a while loop }
  339. internalerror(2015082501);
  340. end;
  341. {*****************************************************************************
  342. SecondExitN
  343. *****************************************************************************}
  344. procedure tcgexitnode.pass_generate_code;
  345. begin
  346. location_reset(location,LOC_VOID,OS_NO);
  347. if fc_no_direct_exit in flowcontrol then
  348. include(flowcontrol,fc_gotolabel);
  349. include(flowcontrol,fc_exit);
  350. if assigned(left) then
  351. secondpass(left);
  352. if (fc_unwind_exit in flowcontrol) then
  353. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel)
  354. else
  355. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  356. if not(cs_opt_size in current_settings.optimizerswitches) then
  357. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  358. end;
  359. {*****************************************************************************
  360. SecondBreakN
  361. *****************************************************************************}
  362. procedure tcgbreaknode.pass_generate_code;
  363. begin
  364. location_reset(location,LOC_VOID,OS_NO);
  365. include(flowcontrol,fc_break);
  366. if current_procinfo.CurrBreakLabel<>nil then
  367. begin
  368. {$ifdef OLDREGVARS}
  369. load_all_regvars(current_asmdata.CurrAsmList);
  370. {$endif OLDREGVARS}
  371. if (fc_unwind_loop in flowcontrol) then
  372. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  373. else
  374. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel);
  375. if not(cs_opt_size in current_settings.optimizerswitches) then
  376. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  377. end
  378. else
  379. CGMessage(cg_e_break_not_allowed);
  380. end;
  381. {*****************************************************************************
  382. SecondContinueN
  383. *****************************************************************************}
  384. procedure tcgcontinuenode.pass_generate_code;
  385. begin
  386. location_reset(location,LOC_VOID,OS_NO);
  387. include(flowcontrol,fc_continue);
  388. if current_procinfo.CurrContinueLabel<>nil then
  389. begin
  390. {$ifdef OLDREGVARS}
  391. load_all_regvars(current_asmdata.CurrAsmList);
  392. {$endif OLDREGVARS}
  393. if (fc_unwind_loop in flowcontrol) then
  394. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  395. else
  396. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel);
  397. if not(cs_opt_size in current_settings.optimizerswitches) then
  398. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  399. end
  400. else
  401. CGMessage(cg_e_continue_not_allowed);
  402. end;
  403. {*****************************************************************************
  404. SecondGoto
  405. *****************************************************************************}
  406. procedure tcggotonode.pass_generate_code;
  407. begin
  408. location_reset(location,LOC_VOID,OS_NO);
  409. include(flowcontrol,fc_gotolabel);
  410. {$ifdef OLDREGVARS}
  411. load_all_regvars(current_asmdata.CurrAsmList);
  412. {$endif OLDREGVARS}
  413. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(labelnode).getasmlabel);
  414. if not(cs_opt_size in current_settings.optimizerswitches) then
  415. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  416. end;
  417. {*****************************************************************************
  418. SecondLabel
  419. *****************************************************************************}
  420. function tcglabelnode.getasmlabel : tasmlabel;
  421. begin
  422. if not(assigned(asmlabel)) then
  423. { labsym is not set in inlined procedures, but since assembler }
  424. { routines can't be inlined, that shouldn't matter }
  425. if assigned(labsym) and
  426. labsym.nonlocal then
  427. current_asmdata.getglobaljumplabel(asmlabel)
  428. else
  429. current_asmdata.getjumplabel(asmlabel);
  430. result:=asmlabel
  431. end;
  432. procedure tcglabelnode.pass_generate_code;
  433. begin
  434. location_reset(location,LOC_VOID,OS_NO);
  435. include(flowcontrol,fc_gotolabel);
  436. {$ifdef OLDREGVARS}
  437. load_all_regvars(current_asmdata.CurrAsmList);
  438. {$endif OLDREGVARS}
  439. hlcg.a_label(current_asmdata.CurrAsmList,getasmlabel);
  440. { Write also extra label if this label was referenced from
  441. assembler block }
  442. if assigned(labsym) and
  443. assigned(labsym.asmblocklabel) then
  444. hlcg.a_label(current_asmdata.CurrAsmList,labsym.asmblocklabel);
  445. secondpass(left);
  446. end;
  447. {*****************************************************************************
  448. SecondTryExcept
  449. *****************************************************************************}
  450. var
  451. endexceptlabel : tasmlabel;
  452. { jump out of an try/except block }
  453. procedure tcgtryexceptnode.emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel);
  454. begin
  455. hlcg.a_label(list,framelabel);
  456. { we must also destroy the address frame which guards
  457. the exception object }
  458. cexceptionstatehandler.popaddrstack(list);
  459. hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
  460. if frametype=ft_except then
  461. begin
  462. cexceptionstatehandler.cleanupobjectstack(list);
  463. cexceptionstatehandler.end_catch(list);
  464. end;
  465. hlcg.a_jmp_always(list,outerlabel);
  466. end;
  467. procedure tcgtryexceptnode.pass_generate_code;
  468. var
  469. oldendexceptlabel,
  470. lastonlabel,
  471. exitexceptlabel,
  472. continueexceptlabel,
  473. breakexceptlabel,
  474. exittrylabel,
  475. continuetrylabel,
  476. breaktrylabel,
  477. oldCurrExitLabel,
  478. oldContinueLabel,
  479. oldBreakLabel : tasmlabel;
  480. destroytemps,
  481. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  482. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  483. afteronflowcontrol: tflowcontrol;
  484. label
  485. errorexit;
  486. begin
  487. location_reset(location,LOC_VOID,OS_NO);
  488. continuetrylabel:=nil;
  489. breaktrylabel:=nil;
  490. continueexceptlabel:=nil;
  491. breakexceptlabel:=nil;
  492. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  493. { this can be called recursivly }
  494. oldBreakLabel:=nil;
  495. oldContinueLabel:=nil;
  496. oldendexceptlabel:=endexceptlabel;
  497. { save the old labels for control flow statements }
  498. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  499. if assigned(current_procinfo.CurrBreakLabel) then
  500. begin
  501. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  502. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  503. end;
  504. { get new labels for the control flow statements }
  505. current_asmdata.getjumplabel(exittrylabel);
  506. current_asmdata.getjumplabel(exitexceptlabel);
  507. if assigned(current_procinfo.CurrBreakLabel) then
  508. begin
  509. current_asmdata.getjumplabel(breaktrylabel);
  510. current_asmdata.getjumplabel(continuetrylabel);
  511. current_asmdata.getjumplabel(breakexceptlabel);
  512. current_asmdata.getjumplabel(continueexceptlabel);
  513. end;
  514. current_asmdata.getjumplabel(endexceptlabel);
  515. current_asmdata.getjumplabel(lastonlabel);
  516. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  517. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  518. { try block }
  519. { set control flow labels for the try block }
  520. current_procinfo.CurrExitLabel:=exittrylabel;
  521. if assigned(oldBreakLabel) then
  522. begin
  523. current_procinfo.CurrContinueLabel:=continuetrylabel;
  524. current_procinfo.CurrBreakLabel:=breaktrylabel;
  525. end;
  526. secondpass(left);
  527. if codegenerror then
  528. goto errorexit;
  529. { don't generate line info for internal cleanup }
  530. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  531. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,endexceptlabel);
  532. cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,tek_except,trystate,excepttemps);
  533. cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList, excepttemps, trystate, 0, endexceptlabel, false);
  534. { end cleanup }
  535. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  536. { set control flow labels for the except block }
  537. { and the on statements }
  538. current_procinfo.CurrExitLabel:=exitexceptlabel;
  539. if assigned(oldBreakLabel) then
  540. begin
  541. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  542. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  543. end;
  544. flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
  545. { on statements }
  546. if assigned(right) then
  547. secondpass(right);
  548. afteronflowcontrol:=flowcontrol;
  549. { don't generate line info for internal cleanup }
  550. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  551. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  552. { default handling except handling }
  553. if assigned(t1) then
  554. begin
  555. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  556. it doesn't change any state and its return value is ignored (Sergei)
  557. }
  558. { the destruction of the exception object must be also }
  559. { guarded by an exception frame, but it can be omitted }
  560. { if there's no user code in 'except' block }
  561. cexceptionstatehandler.catch_all_start(current_asmdata.CurrAsmList);
  562. if not (has_no_code(t1)) then
  563. begin
  564. { if there is an outer frame that catches exceptions, remember this for the "except"
  565. part of this try/except }
  566. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  567. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  568. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  569. cexceptionstatehandler.catch_all_add(current_asmdata.CurrAsmList);
  570. { the flowcontrol from the default except-block must be merged
  571. with the flowcontrol flags potentially set by the
  572. on-statements handled above (secondpass(right)), as they are
  573. at the same program level }
  574. flowcontrol:=
  575. flowcontrol+
  576. afteronflowcontrol;
  577. { except block needs line info }
  578. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  579. secondpass(t1);
  580. cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
  581. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  582. cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
  583. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  584. end
  585. else
  586. begin
  587. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  588. cexceptionstatehandler.cleanupobjectstack(current_asmdata.CurrAsmList);
  589. cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
  590. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  591. end;
  592. end
  593. else
  594. begin
  595. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,trystate,tek_except);
  596. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  597. end;
  598. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  599. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,exitexceptlabel,oldCurrExitLabel);
  600. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  601. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,breakexceptlabel,oldBreakLabel);
  602. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  603. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,continueexceptlabel,oldContinueLabel);
  604. if fc_exit in trystate.newflowcontrol then
  605. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,exittrylabel,oldCurrExitLabel);
  606. if fc_break in trystate.newflowcontrol then
  607. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,breaktrylabel,oldBreakLabel);
  608. if fc_continue in trystate.newflowcontrol then
  609. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,continuetrylabel,oldContinueLabel);
  610. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  611. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  612. { end cleanup }
  613. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  614. errorexit:
  615. { restore all saved labels }
  616. endexceptlabel:=oldendexceptlabel;
  617. { restore the control flow labels }
  618. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  619. if assigned(oldBreakLabel) then
  620. begin
  621. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  622. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  623. end;
  624. { return all used control flow statements }
  625. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  626. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  627. end;
  628. procedure tcgonnode.pass_generate_code;
  629. var
  630. nextonlabel,
  631. exitonlabel,
  632. continueonlabel,
  633. breakonlabel,
  634. oldCurrExitLabel,
  635. oldContinueLabel,
  636. oldBreakLabel : tasmlabel;
  637. doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  638. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  639. exceptvarsym : tlocalvarsym;
  640. exceptlocdef: tdef;
  641. exceptlocreg: tregister;
  642. begin
  643. location_reset(location,LOC_VOID,OS_NO);
  644. oldCurrExitLabel:=nil;
  645. continueonlabel:=nil;
  646. breakonlabel:=nil;
  647. exitonlabel:=nil;
  648. current_asmdata.getjumplabel(nextonlabel);
  649. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nextonlabel,exceptlocdef,exceptlocreg);
  650. { Retrieve exception variable }
  651. if assigned(excepTSymtable) then
  652. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  653. else
  654. internalerror(2011020401);
  655. if assigned(exceptvarsym) then
  656. begin
  657. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  658. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  659. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  660. end;
  661. { in the case that another exception is risen
  662. we've to destroy the old one, so create a new
  663. exception frame for the catch-handler }
  664. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  665. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,doobjectdestroyandreraisestate);
  666. oldBreakLabel:=nil;
  667. oldContinueLabel:=nil;
  668. if assigned(right) then
  669. begin
  670. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  671. current_asmdata.getjumplabel(exitonlabel);
  672. current_procinfo.CurrExitLabel:=exitonlabel;
  673. if assigned(current_procinfo.CurrBreakLabel) then
  674. begin
  675. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  676. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  677. current_asmdata.getjumplabel(breakonlabel);
  678. current_asmdata.getjumplabel(continueonlabel);
  679. current_procinfo.CurrContinueLabel:=continueonlabel;
  680. current_procinfo.CurrBreakLabel:=breakonlabel;
  681. end;
  682. secondpass(right);
  683. end;
  684. cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
  685. { clear some stuff }
  686. if assigned(exceptvarsym) then
  687. begin
  688. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  689. exceptvarsym.localloc.loc:=LOC_INVALID;
  690. end;
  691. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  692. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  693. if assigned(right) then
  694. begin
  695. { special handling for control flow instructions }
  696. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  697. begin
  698. { the address and object pop does secondtryexcept }
  699. hlcg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  700. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  701. end;
  702. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  703. begin
  704. { the address and object pop does secondtryexcept }
  705. hlcg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  706. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  707. end;
  708. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  709. begin
  710. { the address and object pop does secondtryexcept }
  711. hlcg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  712. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  713. end;
  714. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  715. if assigned(oldBreakLabel) then
  716. begin
  717. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  718. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  719. end;
  720. end;
  721. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  722. hlcg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  723. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  724. { propagate exit/break/continue }
  725. flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  726. { next on node }
  727. if assigned(left) then
  728. secondpass(left);
  729. end;
  730. {*****************************************************************************
  731. SecondTryFinally
  732. *****************************************************************************}
  733. { jump out of a finally block }
  734. procedure tcgtryfinallynode.emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
  735. begin
  736. hlcg.a_label(list,framelabel);
  737. hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
  738. hlcg.g_exception_reason_save_const(list,osuinttype,reason,excepttemps.reasonbuf);
  739. hlcg.a_jmp_always(list,finallycodelabel);
  740. end;
  741. function tcgtryfinallynode.get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
  742. begin
  743. current_asmdata.getjumplabel(result);
  744. end;
  745. procedure tcgtryfinallynode.handle_safecall_exception;
  746. var
  747. cgpara, resultpara: tcgpara;
  748. selfsym: tparavarsym;
  749. pd: tprocdef;
  750. safecallresult: tlocalvarsym;
  751. begin
  752. { call fpc_safecallhandler, passing self for methods of classes,
  753. nil otherwise. }
  754. pd:=search_system_proc('fpc_safecallhandler');
  755. cgpara.init;
  756. paramanager.getcgtempparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  757. if is_class(current_procinfo.procdef.struct) then
  758. begin
  759. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  760. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  761. InternalError(2011123101);
  762. hlcg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.vardef,selfsym.localloc,cgpara);
  763. end
  764. else
  765. hlcg.a_load_const_cgpara(current_asmdata.CurrAsmList,voidpointertype,0,cgpara);
  766. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  767. resultpara:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@cgpara],nil);
  768. cgpara.done;
  769. safecallresult:=tlocalvarsym(current_procinfo.procdef.localst.Find('safecallresult'));
  770. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,resultpara.def,resultpara,safecallresult.localloc,false);
  771. resultpara.resetiftemp;
  772. end;
  773. procedure tcgtryfinallynode.pass_generate_code;
  774. var
  775. endfinallylabel,
  776. exitfinallylabel,
  777. continuefinallylabel,
  778. breakfinallylabel,
  779. oldCurrExitLabel,
  780. oldContinueLabel,
  781. oldBreakLabel,
  782. finallyNoExceptionLabel: tasmlabel;
  783. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  784. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  785. reasonreg : tregister;
  786. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  787. tmplist: TAsmList;
  788. procedure handle_breakcontinueexit(const finallycode: tasmlabel; doreraise: boolean);
  789. begin
  790. { no exception happened, but maybe break/continue/exit }
  791. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  792. if fc_exit in finallyexceptionstate.newflowcontrol then
  793. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  794. if fc_break in finallyexceptionstate.newflowcontrol then
  795. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  796. if fc_continue in finallyexceptionstate.newflowcontrol then
  797. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  798. if doreraise then
  799. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,tek_normalfinally)
  800. else
  801. hlcg.g_unreachable(current_asmdata.CurrAsmList);
  802. { redirect break/continue/exit to the label above, with the reasonbuf set appropriately }
  803. if fc_exit in finallyexceptionstate.newflowcontrol then
  804. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,2,finallycode,excepttemps,exitfinallylabel);
  805. if fc_break in finallyexceptionstate.newflowcontrol then
  806. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,3,finallycode,excepttemps,breakfinallylabel);
  807. if fc_continue in finallyexceptionstate.newflowcontrol then
  808. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,4,finallycode,excepttemps,continuefinallylabel);
  809. end;
  810. begin
  811. location_reset(location,LOC_VOID,OS_NO);
  812. oldBreakLabel:=nil;
  813. oldContinueLabel:=nil;
  814. continuefinallylabel:=nil;
  815. breakfinallylabel:=nil;
  816. if not implicitframe then
  817. exceptframekind:=tek_normalfinally
  818. else
  819. exceptframekind:=tek_implicitfinally;
  820. current_asmdata.getjumplabel(endfinallylabel);
  821. { call setjmp, and jump to finally label on non-zero result }
  822. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  823. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  824. { the finally block must catch break, continue and exit }
  825. { statements }
  826. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  827. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  828. current_procinfo.CurrExitLabel:=exitfinallylabel;
  829. if assigned(current_procinfo.CurrBreakLabel) then
  830. begin
  831. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  832. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  833. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  834. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  835. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  836. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  837. end;
  838. { try code }
  839. if assigned(left) then
  840. begin
  841. secondpass(left);
  842. if codegenerror then
  843. exit;
  844. end;
  845. { don't generate line info for internal cleanup }
  846. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  847. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,finallyexceptionstate.finallycodelabel);
  848. if assigned(third) then
  849. begin
  850. tmplist:=TAsmList.create;
  851. { emit the except label already (to a temporary list) to ensure that any calls in the
  852. finally block refer to the outer exception frame rather than to the exception frame
  853. that emits this same finally code in case an exception does happen }
  854. cexceptionstatehandler.emit_except_label(tmplist,exceptframekind,finallyexceptionstate,excepttemps);
  855. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  856. current_asmdata.getjumplabel(finallyNoExceptionLabel);
  857. hlcg.a_label(current_asmdata.CurrAsmList,finallyNoExceptionLabel);
  858. if not implicitframe then
  859. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  860. secondpass(third);
  861. if codegenerror then
  862. exit;
  863. if not implicitframe then
  864. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  865. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  866. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  867. handle_breakcontinueexit(finallyNoExceptionLabel,false);
  868. current_asmdata.CurrAsmList.concatList(tmplist);
  869. tmplist.free;
  870. end
  871. else
  872. cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,exceptframekind,finallyexceptionstate,excepttemps);
  873. { just free the frame information }
  874. cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,1,finallyexceptionstate.exceptionlabel,true);
  875. { end cleanup }
  876. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  877. { finally code (don't unconditionally set fc_inflowcontrol, since the
  878. finally code is unconditionally executed; we do have to filter out
  879. flags regarding break/contrinue/etc. because we have to give an
  880. error in case one of those is used in the finally-code }
  881. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  882. secondpass(right);
  883. { goto is allowed if it stays inside the finally block,
  884. this is checked using the exception block number }
  885. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  886. CGMessage(cg_e_control_flow_outside_finally);
  887. if codegenerror then
  888. exit;
  889. { don't generate line info for internal cleanup }
  890. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  891. { same level as before try, but this part is only executed if an exception occcurred
  892. -> always fc_in_flowcontrol }
  893. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_catching_exceptions];
  894. include(flowcontrol,fc_inflowcontrol);
  895. if not assigned(third) then
  896. begin
  897. { the value should now be in the exception handler }
  898. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  899. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  900. if implicitframe then
  901. begin
  902. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  903. { finally code only needed to be executed on exception (-> in
  904. if-branch -> fc_inflowcontrol) }
  905. if current_procinfo.procdef.generate_safecall_wrapper then
  906. begin
  907. handle_safecall_exception;
  908. { we have to jump immediatly as we have to return the value of FPC_SAFECALL }
  909. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  910. end
  911. else
  912. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  913. { we have to load 0 into the execepttemp, else the program thinks an exception happended }
  914. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,0,finallyexceptionstate.exceptionlabel,excepttemps,exitfinallylabel);
  915. end
  916. else
  917. begin
  918. handle_breakcontinueexit(finallyexceptionstate.exceptionlabel,true);
  919. end;
  920. end
  921. else
  922. begin
  923. if implicitframe then
  924. begin
  925. if current_procinfo.procdef.generate_safecall_wrapper then
  926. handle_safecall_exception
  927. else
  928. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  929. end
  930. else
  931. begin
  932. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  933. end;
  934. end;
  935. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  936. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  937. { end cleanup }
  938. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  939. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  940. if assigned(current_procinfo.CurrBreakLabel) then
  941. begin
  942. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  943. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  944. end;
  945. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  946. end;
  947. function tcgraisenode.pass_1: tnode;
  948. begin
  949. if not(tf_use_psabieh in target_info.flags) or assigned(left) then
  950. result:=inherited
  951. else
  952. begin
  953. expectloc:=LOC_VOID;
  954. result:=nil;
  955. end;
  956. end;
  957. {$ifndef jvm}
  958. { has to be factored out as well }
  959. procedure tcgraisenode.pass_generate_code;
  960. var
  961. CurrentLandingPad, CurrentAction, ReRaiseLandingPad: TPSABIEHAction;
  962. psabiehprocinfo: tpsabiehprocinfo;
  963. begin
  964. if not(tf_use_psabieh in target_info.flags) then
  965. Internalerror(2019021701);
  966. location_reset(location,LOC_VOID,OS_NO);
  967. CurrentLandingPad:=nil;
  968. CurrentAction:=nil;
  969. ReRaiseLandingPad:=nil;
  970. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  971. { a reraise must raise the exception to the parent exception frame }
  972. if fc_catching_exceptions in flowcontrol then
  973. begin
  974. psabiehprocinfo.CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
  975. CurrentLandingPad:=psabiehprocinfo.CurrentLandingPad;
  976. if psabiehprocinfo.PopLandingPad(CurrentLandingPad) then
  977. exclude(flowcontrol,fc_catching_exceptions);
  978. CurrentAction:=psabiehprocinfo.CurrentAction;
  979. psabiehprocinfo.FinalizeAndPopAction(CurrentAction);
  980. if not(fc_catching_exceptions in flowcontrol) then
  981. begin
  982. ReRaiseLandingPad:=psabiehprocinfo.NoAction;
  983. psabiehprocinfo.PushAction(ReRaiseLandingPad);
  984. psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
  985. end;
  986. end;
  987. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  988. if assigned(CurrentLandingPad) then
  989. begin
  990. psabiehprocinfo.CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
  991. if not(fc_catching_exceptions in flowcontrol) then
  992. begin
  993. psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
  994. psabiehprocinfo.PopAction(ReRaiseLandingPad);
  995. end;
  996. psabiehprocinfo.PushAction(CurrentAction);
  997. psabiehprocinfo.PushLandingPad(CurrentLandingPad);
  998. include(flowcontrol,fc_catching_exceptions);
  999. end;
  1000. end;
  1001. {$endif jvm}
  1002. begin
  1003. cwhilerepeatnode:=tcgwhilerepeatnode;
  1004. cifnode:=tcgifnode;
  1005. cfornode:=tcgfornode;
  1006. cexitnode:=tcgexitnode;
  1007. cbreaknode:=tcgbreaknode;
  1008. ccontinuenode:=tcgcontinuenode;
  1009. cgotonode:=tcggotonode;
  1010. clabelnode:=tcglabelnode;
  1011. craisenode:=tcgraisenode;
  1012. ctryexceptnode:=tcgtryexceptnode;
  1013. ctryfinallynode:=tcgtryfinallynode;
  1014. connode:=tcgonnode;
  1015. cexceptionstatehandler:=tcgexceptionstatehandler;
  1016. end.