ncgflw.pas 51 KB

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