ncgflw.pas 52 KB

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