ncgflw.pas 58 KB

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