ncgflw.pas 50 KB

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