ncgflw.pas 50 KB

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