ncgflw.pas 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for nodes that influence the flow which are
  4. the same for all (most?) processors
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ncgflw;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. globtype,
  23. symtype,symdef,
  24. aasmbase,aasmdata,
  25. node,nflw,
  26. pass_2,cgbase,cgutils,ncgutil;
  27. type
  28. tcgwhilerepeatnode = class(twhilerepeatnode)
  29. usedregvars: tusedregvars;
  30. procedure pass_generate_code;override;
  31. procedure sync_regvars(checkusedregvars: boolean);
  32. end;
  33. tcgifnode = class(tifnode)
  34. procedure pass_generate_code;override;
  35. end;
  36. tcgfornode = class(tfornode)
  37. procedure pass_generate_code;override;
  38. end;
  39. tcgexitnode = class(texitnode)
  40. procedure pass_generate_code;override;
  41. end;
  42. tcgbreaknode = class(tbreaknode)
  43. procedure pass_generate_code;override;
  44. end;
  45. tcgcontinuenode = class(tcontinuenode)
  46. procedure pass_generate_code;override;
  47. end;
  48. tcggotonode = class(tgotonode)
  49. procedure pass_generate_code;override;
  50. end;
  51. tcglabelnode = class(tlabelnode)
  52. protected
  53. asmlabel : tasmlabel;
  54. public
  55. function getasmlabel : tasmlabel; virtual;
  56. procedure pass_generate_code;override;
  57. end;
  58. tcgraisenode = class(traisenode)
  59. function pass_1: tnode;override;
  60. procedure pass_generate_code;override;
  61. end;
  62. { Utility class for exception handling state management that is used
  63. by tryexcept/tryfinally/on nodes (in a separate class so it can both
  64. be shared and overridden)
  65. Never instantiated. }
  66. tcgexceptionstatehandler = class
  67. type
  68. texceptiontemps=record
  69. jmpbuf,
  70. envbuf,
  71. reasonbuf : treference;
  72. { when using dwarf based eh handling, the landing pads get the unwind info passed, it is
  73. stored in the given register so it can be passed to unwind_resume }
  74. unwind_info : TRegister;
  75. end;
  76. texceptionstate = record
  77. exceptionlabel: TAsmLabel;
  78. oldflowcontrol,
  79. newflowcontrol: tflowcontrol;
  80. finallycodelabel : TAsmLabel;
  81. end;
  82. texceptframekind = (tek_except, tek_implicitfinally, tek_normalfinally);
  83. class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); virtual;
  84. class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); virtual;
  85. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); virtual;
  86. { start of "except/finally" block }
  87. class procedure emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptstate: texceptionstate;var exceptiontemps:texceptiontemps); virtual;
  88. { end of a try-block, label comes after the end of try/except or
  89. try/finally }
  90. class procedure end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel); virtual;
  91. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); virtual;
  92. class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); virtual;
  93. class procedure handle_reraise(list:TAsmList;const t:texceptiontemps;const entrystate: texceptionstate; const exceptframekind: texceptframekind); virtual;
  94. { start of an "on" (catch) block }
  95. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); virtual;
  96. { end of an "on" (catch) block }
  97. class procedure end_catch(list: TAsmList); virtual;
  98. { called for a catch all exception }
  99. class procedure catch_all_start(list: TAsmList); virtual;
  100. class procedure catch_all_end(list: TAsmList); virtual;
  101. class procedure cleanupobjectstack(list: TAsmList); virtual;
  102. class procedure popaddrstack(list: TAsmList); virtual;
  103. class function use_cleanup(const exceptframekind: texceptframekind): boolean;
  104. end;
  105. tcgexceptionstatehandlerclass = class of tcgexceptionstatehandler;
  106. { Utility class for exception handling state management that is used
  107. by tryexcept/tryfinally/on nodes (in a separate class so it can both
  108. be shared and overridden)
  109. Never instantiated. }
  110. tpsabiehexceptionstatehandler = class(tcgexceptionstatehandler)
  111. protected
  112. class procedure begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; add_catch: boolean; out exceptlocdef: tdef; out
  113. exceptlocreg: tregister);
  114. class procedure catch_all_start_internal(list: TAsmList; add_catch: boolean);
  115. public
  116. class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
  117. class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
  118. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  119. { start of "except/finally" block }
  120. class procedure emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps); override;
  121. { end of a try-block, label comes after the end of try/except or
  122. try/finally }
  123. class procedure end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel); override;
  124. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  125. class procedure handle_reraise(list:TAsmList;const t:texceptiontemps;const entrystate: texceptionstate; const exceptframekind: texceptframekind); override;
  126. { start of an "on" (catch) block }
  127. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  128. { end of an "on" (catch) block }
  129. class procedure end_catch(list: TAsmList); override;
  130. { called for a catch all exception }
  131. class procedure catch_all_start(list: TAsmList); override;
  132. class procedure catch_all_end(list: TAsmList); override;
  133. class procedure cleanupobjectstack(list: TAsmList); override;
  134. class procedure popaddrstack(list: TAsmList); override;
  135. end;
  136. tcgtryexceptnode = class(ttryexceptnode)
  137. protected
  138. type
  139. tframetype = (ft_try,ft_except);
  140. procedure emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel); virtual;
  141. public
  142. procedure pass_generate_code;override;
  143. end;
  144. tcgtryfinallynode = class(ttryfinallynode)
  145. protected
  146. procedure emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
  147. function get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
  148. public
  149. procedure handle_safecall_exception;
  150. procedure pass_generate_code;override;
  151. end;
  152. tcgonnode = class(tonnode)
  153. procedure pass_generate_code;override;
  154. end;
  155. var
  156. cexceptionstatehandler: tcgexceptionstatehandlerclass;
  157. implementation
  158. uses
  159. cutils,
  160. verbose,globals,systems,
  161. symconst,symsym,symtable,aasmtai,aasmcpu,defutil,
  162. procinfo,parabase,
  163. fmodule,
  164. cpubase,
  165. tgobj,paramgr,
  166. cgobj,hlcgobj,nutils
  167. ;
  168. class procedure tpsabiehexceptionstatehandler.get_exception_temps(list: TAsmList; var t: texceptiontemps);
  169. begin
  170. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  171. end;
  172. class procedure tpsabiehexceptionstatehandler.unget_exception_temps(list: TAsmList; const t: texceptiontemps);
  173. begin
  174. tg.ungettemp(list,t.reasonbuf);
  175. current_procinfo.PopAction(current_procinfo.CurrentAction);
  176. end;
  177. class procedure tpsabiehexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps;
  178. const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  179. var
  180. reg: tregister;
  181. action: TPSABIEHAction;
  182. begin
  183. exceptstate.oldflowcontrol:=flowcontrol;
  184. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  185. if exceptframekind<>tek_except then
  186. begin
  187. current_asmdata.getjumplabel(exceptstate.finallycodelabel);
  188. action:=TPSABIEHAction.Create(exceptstate.finallycodelabel);
  189. end
  190. else
  191. begin
  192. exceptstate.finallycodelabel:=nil;
  193. action:=TPSABIEHAction.Create(exceptstate.exceptionlabel);
  194. end;
  195. current_procinfo.CreateNewPSABIEHCallsite;
  196. current_procinfo.PushAction(action);
  197. current_procinfo.PushLandingPad(action);
  198. if exceptframekind<>tek_except then
  199. current_procinfo.CurrentAction.AddAction(nil);
  200. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  201. if exceptframekind<>tek_except then
  202. begin
  203. reg:=hlcg.getintregister(list,ossinttype);
  204. hlcg.a_load_const_reg(list,ossinttype,1,reg);
  205. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  206. end;
  207. end;
  208. class procedure tpsabiehexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind;
  209. var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps);
  210. begin
  211. hlcg.g_unreachable(list);
  212. hlcg.a_label(list,exceptionstate.exceptionlabel);
  213. if exceptframekind<>tek_except then
  214. begin
  215. if not assigned(exceptionstate.finallycodelabel) then
  216. internalerror(2019021002);
  217. hlcg.a_label(list,exceptionstate.finallycodelabel);
  218. exceptionstate.finallycodelabel:=nil;
  219. exceptiontemps.unwind_info:=cg.getaddressregister(list);
  220. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,exceptiontemps.unwind_info);
  221. end;
  222. end;
  223. class procedure tpsabiehexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps;
  224. var exceptionstate: texceptionstate; endlabel: TAsmLabel);
  225. var
  226. reg: TRegister;
  227. begin
  228. current_procinfo.CreateNewPSABIEHCallsite;
  229. current_procinfo.PopLandingPad(current_procinfo.CurrentLandingPad);
  230. if exceptframekind<>tek_except then
  231. begin
  232. { record that no exception happened in the reason buf, in case we are in a try block of a finally statement }
  233. reg:=hlcg.getintregister(list,ossinttype);
  234. hlcg.a_load_const_reg(list,ossinttype,0,reg);
  235. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  236. end;
  237. inherited;
  238. if exceptframekind=tek_except then
  239. hlcg.a_jmp_always(list,endlabel);
  240. end;
  241. class procedure tpsabiehexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint;
  242. endexceptlabel: tasmlabel; onlyfree: boolean);
  243. begin
  244. current_procinfo.CreateNewPSABIEHCallsite;
  245. // inherited free_exception(list, t, s, a, endexceptlabel, onlyfree);
  246. end;
  247. class procedure tpsabiehexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate;
  248. const exceptframekind: texceptframekind);
  249. var
  250. cgpara1: tcgpara;
  251. pd: tprocdef;
  252. action: TPSABIEHAction;
  253. begin
  254. cgpara1.init;
  255. if not(fc_catching_exceptions in flowcontrol) and
  256. use_cleanup(exceptframekind) then
  257. begin
  258. pd:=search_system_proc('fpc_resume');
  259. paramanager.getintparaloc(list,pd,1,cgpara1);
  260. hlcg.a_load_reg_cgpara(list,voidpointertype,t.unwind_info,cgpara1);
  261. paramanager.freecgpara(list,cgpara1);
  262. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_resume',[@cgpara1],nil).resetiftemp
  263. end
  264. else
  265. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  266. cgpara1.done;
  267. end;
  268. class procedure tpsabiehexceptionstatehandler.begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel;
  269. add_catch: boolean; out exceptlocdef: tdef; out exceptlocreg: tregister);
  270. var
  271. catchstartlab : tasmlabel;
  272. begincatchres,
  273. typeidres,
  274. paraloc1: tcgpara;
  275. pd: tprocdef;
  276. landingpadstructdef,
  277. landingpadtypeiddef: tdef;
  278. rttisym: TAsmSymbol;
  279. rttidef: tdef;
  280. rttiref: treference;
  281. wrappedexception,
  282. exceptiontypeidreg,
  283. landingpadres: tregister;
  284. exceptloc: tlocation;
  285. indirect: boolean;
  286. otherunit: boolean;
  287. typeindex : aint;
  288. begin
  289. paraloc1.init;
  290. rttidef:=nil;
  291. rttisym:=nil;
  292. if add_catch then
  293. begin
  294. if assigned(excepttype) then
  295. begin
  296. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  297. indirect:=(tf_supports_packages in target_info.flags) and
  298. (target_info.system in systems_indirect_var_imports) and
  299. (cs_imported_data in current_settings.localswitches) and
  300. otherunit;
  301. { add "catch exceptiontype" clause to the landing pad }
  302. rttidef:=cpointerdef.getreusable(excepttype.vmt_def);
  303. rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect);
  304. end;
  305. end;
  306. { check if the exception is handled by this node }
  307. if assigned(excepttype) then
  308. begin
  309. typeindex:=current_procinfo.CurrentAction.AddAction(excepttype);
  310. current_asmdata.getjumplabel(catchstartlab);
  311. {$ifdef i386}
  312. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab);
  313. {$else i386}
  314. { we need to find a way to fix this in a generic way }
  315. Internalerror(2019021008);
  316. {$endif i386}
  317. hlcg.a_jmp_always(list,nextonlabel);
  318. hlcg.a_label(list,catchstartlab);
  319. end
  320. else
  321. current_procinfo.CurrentAction.AddAction(tobjectdef(-1));
  322. wrappedexception:=hlcg.getaddressregister(list,voidpointertype);
  323. pd:=search_system_proc('fpc_psabi_begin_catch');
  324. paramanager.getintparaloc(list, pd, 1, paraloc1);
  325. hlcg.a_load_reg_cgpara(list,voidpointertype,wrappedexception,paraloc1);
  326. begincatchres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  327. location_reset(exceptloc, LOC_REGISTER, def_cgsize(begincatchres.def));
  328. exceptloc.register:=hlcg.getaddressregister(list, begincatchres.def);
  329. hlcg.gen_load_cgpara_loc(list, begincatchres.def, begincatchres, exceptloc, true);
  330. begincatchres.resetiftemp;
  331. paraloc1.done;
  332. exceptlocdef:=begincatchres.def;
  333. exceptlocreg:=exceptloc.register;
  334. end;
  335. class procedure tpsabiehexceptionstatehandler.catch_all_start_internal(list: TAsmList; add_catch: boolean);
  336. var
  337. exceptlocdef: tdef;
  338. exceptlocreg: tregister;
  339. begin
  340. begin_catch_internal(list,nil,nil,add_catch,exceptlocdef,exceptlocreg);
  341. end;
  342. class procedure tpsabiehexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out
  343. exceptlocreg: tregister);
  344. begin
  345. begin_catch_internal(list,excepttype,nextonlabel,true,exceptlocdef,exceptlocreg);
  346. end;
  347. class procedure tpsabiehexceptionstatehandler.end_catch(list: TAsmList);
  348. begin
  349. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  350. inherited;
  351. end;
  352. class procedure tpsabiehexceptionstatehandler.catch_all_start(list: TAsmList);
  353. begin
  354. catch_all_start_internal(list,true);
  355. end;
  356. class procedure tpsabiehexceptionstatehandler.catch_all_end(list: TAsmList);
  357. begin
  358. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  359. end;
  360. class procedure tpsabiehexceptionstatehandler.cleanupobjectstack(list: TAsmList);
  361. begin
  362. // inherited cleanupobjectstack(list);
  363. //!!! some catch all clause needed?
  364. //!!! internalerror(2019021004)
  365. end;
  366. class procedure tpsabiehexceptionstatehandler.popaddrstack(list: TAsmList);
  367. begin
  368. { there is no addr stack, so do nothing }
  369. end;
  370. {*****************************************************************************
  371. Second_While_RepeatN
  372. *****************************************************************************}
  373. procedure tcgwhilerepeatnode.sync_regvars(checkusedregvars: boolean);
  374. begin
  375. if (cs_opt_regvar in current_settings.optimizerswitches) and
  376. not(pi_has_label in current_procinfo.flags) then
  377. begin
  378. if checkusedregvars then
  379. begin
  380. usedregvars.intregvars.init;
  381. usedregvars.addrregvars.init;
  382. usedregvars.fpuregvars.init;
  383. usedregvars.mmregvars.init;
  384. { we have to synchronise both the regvars used in the loop }
  385. { and the ones in the while/until condition }
  386. get_used_regvars(self,usedregvars);
  387. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  388. end
  389. else
  390. begin
  391. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  392. usedregvars.intregvars.done;
  393. usedregvars.addrregvars.done;
  394. usedregvars.fpuregvars.done;
  395. usedregvars.mmregvars.done;
  396. end;
  397. end;
  398. end;
  399. procedure tcgwhilerepeatnode.pass_generate_code;
  400. var
  401. lcont,lbreak,lloop,
  402. oldclabel,oldblabel : tasmlabel;
  403. truelabel,falselabel : tasmlabel;
  404. oldflowcontrol : tflowcontrol;
  405. begin
  406. location_reset(location,LOC_VOID,OS_NO);
  407. current_asmdata.getjumplabel(lloop);
  408. current_asmdata.getjumplabel(lcont);
  409. current_asmdata.getjumplabel(lbreak);
  410. { arrange continue and breaklabels: }
  411. oldflowcontrol:=flowcontrol;
  412. oldclabel:=current_procinfo.CurrContinueLabel;
  413. oldblabel:=current_procinfo.CurrBreakLabel;
  414. include(flowcontrol,fc_inflowcontrol);
  415. exclude(flowcontrol,fc_unwind_loop);
  416. sync_regvars(true);
  417. {$ifdef OLDREGVARS}
  418. load_all_regvars(current_asmdata.CurrAsmList);
  419. {$endif OLDREGVARS}
  420. { handling code at the end as it is much more efficient, and makes
  421. while equal to repeat loop, only the end true/false is swapped (PFV) }
  422. if lnf_testatbegin in loopflags then
  423. hlcg.a_jmp_always(current_asmdata.CurrAsmList,lcont);
  424. if not(cs_opt_size in current_settings.optimizerswitches) then
  425. { align loop target, as an unconditional jump is done before,
  426. use jump align which assume that the instructions inserted as alignment are never executed }
  427. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  428. hlcg.a_label(current_asmdata.CurrAsmList,lloop);
  429. current_procinfo.CurrContinueLabel:=lcont;
  430. current_procinfo.CurrBreakLabel:=lbreak;
  431. if assigned(right) then
  432. secondpass(right);
  433. {$ifdef OLDREGVARS}
  434. load_all_regvars(current_asmdata.CurrAsmList);
  435. {$endif OLDREGVARS}
  436. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  437. if lnf_checknegate in loopflags then
  438. begin
  439. truelabel:=lbreak;
  440. falselabel:=lloop;
  441. end
  442. else
  443. begin
  444. truelabel:=lloop;
  445. falselabel:=lbreak;
  446. end;
  447. secondpass(left);
  448. hlcg.maketojumpboollabels(current_asmdata.CurrAsmList,left,truelabel,falselabel);
  449. hlcg.a_label(current_asmdata.CurrAsmList,lbreak);
  450. sync_regvars(false);
  451. current_procinfo.CurrContinueLabel:=oldclabel;
  452. current_procinfo.CurrBreakLabel:=oldblabel;
  453. { a break/continue in a while/repeat block can't be seen outside }
  454. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  455. end;
  456. {*****************************************************************************
  457. tcgIFNODE
  458. *****************************************************************************}
  459. procedure tcgifnode.pass_generate_code;
  460. var
  461. hl : tasmlabel;
  462. oldflowcontrol: tflowcontrol;
  463. (*
  464. org_regvar_loaded_other,
  465. then_regvar_loaded_other,
  466. else_regvar_loaded_other : regvarother_booleanarray;
  467. org_regvar_loaded_int,
  468. then_regvar_loaded_int,
  469. else_regvar_loaded_int : Tsuperregisterset;
  470. org_list,
  471. then_list,
  472. else_list : TAsmList;
  473. *)
  474. begin
  475. location_reset(location,LOC_VOID,OS_NO);
  476. hl:=nil;
  477. oldflowcontrol := flowcontrol;
  478. include(flowcontrol,fc_inflowcontrol);
  479. secondpass(left);
  480. (*
  481. { save regvars loaded in the beginning so that we can restore them }
  482. { when processing the else-block }
  483. if cs_opt_regvar in current_settings.optimizerswitches then
  484. begin
  485. org_list := current_asmdata.CurrAsmList;
  486. current_asmdata.CurrAsmList := TAsmList.create;
  487. end;
  488. *)
  489. hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
  490. (*
  491. if cs_opt_regvar in current_settings.optimizerswitches then
  492. begin
  493. org_regvar_loaded_int := rg.regvar_loaded_int;
  494. org_regvar_loaded_other := rg.regvar_loaded_other;
  495. end;
  496. *)
  497. if assigned(right) then
  498. begin
  499. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  500. secondpass(right);
  501. end;
  502. { save current asmlist (previous instructions + then-block) and }
  503. { loaded regvar state and create new clean ones }
  504. {
  505. if cs_opt_regvar in current_settings.optimizerswitches then
  506. begin
  507. then_regvar_loaded_int := rg.regvar_loaded_int;
  508. then_regvar_loaded_other := rg.regvar_loaded_other;
  509. rg.regvar_loaded_int := org_regvar_loaded_int;
  510. rg.regvar_loaded_other := org_regvar_loaded_other;
  511. then_list := current_asmdata.CurrAsmList;
  512. current_asmdata.CurrAsmList := TAsmList.create;
  513. end;
  514. }
  515. if assigned(t1) then
  516. begin
  517. if assigned(right) then
  518. begin
  519. current_asmdata.getjumplabel(hl);
  520. { do go back to if line !! }
  521. (*
  522. if not(cs_opt_regvar in current_settings.optimizerswitches) then
  523. *)
  524. current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^
  525. (*
  526. else
  527. current_filepos:=then_list.getlasttaifilepos^
  528. *)
  529. ;
  530. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hl);
  531. if not(cs_opt_size in current_settings.optimizerswitches) then
  532. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.jumpalign,current_settings.alignment.jumpalignskipmax));
  533. end;
  534. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  535. secondpass(t1);
  536. (*
  537. { save current asmlist (previous instructions + else-block) }
  538. { and loaded regvar state and create a new clean list }
  539. if cs_opt_regvar in current_settings.optimizerswitches then
  540. begin
  541. { else_regvar_loaded_int := rg.regvar_loaded_int;
  542. else_regvar_loaded_other := rg.regvar_loaded_other;}
  543. else_list := current_asmdata.CurrAsmList;
  544. current_asmdata.CurrAsmList := TAsmList.create;
  545. end;
  546. *)
  547. if assigned(right) then
  548. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  549. end
  550. else
  551. begin
  552. (*
  553. if cs_opt_regvar in current_settings.optimizerswitches then
  554. begin
  555. { else_regvar_loaded_int := rg.regvar_loaded_int;
  556. else_regvar_loaded_other := rg.regvar_loaded_other;}
  557. else_list := current_asmdata.CurrAsmList;
  558. current_asmdata.CurrAsmList := TAsmList.create;
  559. end;
  560. *)
  561. if not(cs_opt_size in current_settings.optimizerswitches) then
  562. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.coalescealign,current_settings.alignment.coalescealignskipmax));
  563. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  564. end;
  565. if not(assigned(right)) then
  566. begin
  567. if not(cs_opt_size in current_settings.optimizerswitches) then
  568. current_asmdata.CurrAsmList.concat(cai_align.create_max(current_settings.alignment.coalescealign,current_settings.alignment.coalescealignskipmax));
  569. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  570. end;
  571. (*
  572. if cs_opt_regvar in current_settings.optimizerswitches then
  573. begin
  574. { add loads of regvars at the end of the then- and else-blocks }
  575. { so that at the end of both blocks the same regvars are loaded }
  576. { no else block? }
  577. if not assigned(t1) then
  578. begin
  579. sync_regvars_int(org_list,then_list,org_regvar_loaded_int,then_regvar_loaded_int);
  580. sync_regvars_other(org_list,then_list,org_regvar_loaded_other,then_regvar_loaded_other);
  581. end
  582. { no then block? }
  583. else if not assigned(right) then
  584. begin
  585. sync_regvars_int(org_list,else_list,org_regvar_loaded_int,else_regvar_loaded_int);
  586. sync_regvars_other(org_list,else_list,org_regvar_loaded_other,else_regvar_loaded_other);
  587. end
  588. { both else and then blocks }
  589. else
  590. begin
  591. sync_regvars_int(then_list,else_list,then_regvar_loaded_int,else_regvar_loaded_int);
  592. sync_regvars_other(then_list,else_list,then_regvar_loaded_other,else_regvar_loaded_other);
  593. end;
  594. { add all lists together }
  595. org_list.concatlist(then_list);
  596. then_list.free;
  597. org_list.concatlist(else_list);
  598. else_list.free;
  599. org_list.concatlist(current_asmdata.CurrAsmList);
  600. current_asmdata.CurrAsmList.free;
  601. current_asmdata.CurrAsmList := org_list;
  602. end;
  603. *)
  604. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  605. end;
  606. {*****************************************************************************
  607. SecondFor
  608. *****************************************************************************}
  609. procedure tcgfornode.pass_generate_code;
  610. begin
  611. { for nodes are converted in pass_1 in a while loop }
  612. internalerror(2015082501);
  613. end;
  614. {*****************************************************************************
  615. SecondExitN
  616. *****************************************************************************}
  617. procedure tcgexitnode.pass_generate_code;
  618. begin
  619. location_reset(location,LOC_VOID,OS_NO);
  620. include(flowcontrol,fc_exit);
  621. if assigned(left) then
  622. secondpass(left);
  623. if (fc_unwind_exit in flowcontrol) then
  624. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel)
  625. else
  626. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  627. end;
  628. {*****************************************************************************
  629. SecondBreakN
  630. *****************************************************************************}
  631. procedure tcgbreaknode.pass_generate_code;
  632. begin
  633. location_reset(location,LOC_VOID,OS_NO);
  634. include(flowcontrol,fc_break);
  635. if current_procinfo.CurrBreakLabel<>nil then
  636. begin
  637. {$ifdef OLDREGVARS}
  638. load_all_regvars(current_asmdata.CurrAsmList);
  639. {$endif OLDREGVARS}
  640. if (fc_unwind_loop in flowcontrol) then
  641. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  642. else
  643. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  644. end
  645. else
  646. CGMessage(cg_e_break_not_allowed);
  647. end;
  648. {*****************************************************************************
  649. SecondContinueN
  650. *****************************************************************************}
  651. procedure tcgcontinuenode.pass_generate_code;
  652. begin
  653. location_reset(location,LOC_VOID,OS_NO);
  654. include(flowcontrol,fc_continue);
  655. if current_procinfo.CurrContinueLabel<>nil then
  656. begin
  657. {$ifdef OLDREGVARS}
  658. load_all_regvars(current_asmdata.CurrAsmList);
  659. {$endif OLDREGVARS}
  660. if (fc_unwind_loop in flowcontrol) then
  661. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  662. else
  663. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  664. end
  665. else
  666. CGMessage(cg_e_continue_not_allowed);
  667. end;
  668. {*****************************************************************************
  669. SecondGoto
  670. *****************************************************************************}
  671. procedure tcggotonode.pass_generate_code;
  672. begin
  673. location_reset(location,LOC_VOID,OS_NO);
  674. include(flowcontrol,fc_gotolabel);
  675. {$ifdef OLDREGVARS}
  676. load_all_regvars(current_asmdata.CurrAsmList);
  677. {$endif OLDREGVARS}
  678. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(labelnode).getasmlabel)
  679. end;
  680. {*****************************************************************************
  681. SecondLabel
  682. *****************************************************************************}
  683. function tcglabelnode.getasmlabel : tasmlabel;
  684. begin
  685. if not(assigned(asmlabel)) then
  686. { labsym is not set in inlined procedures, but since assembler }
  687. { routines can't be inlined, that shouldn't matter }
  688. if assigned(labsym) and
  689. labsym.nonlocal then
  690. current_asmdata.getglobaljumplabel(asmlabel)
  691. else
  692. current_asmdata.getjumplabel(asmlabel);
  693. result:=asmlabel
  694. end;
  695. procedure tcglabelnode.pass_generate_code;
  696. begin
  697. location_reset(location,LOC_VOID,OS_NO);
  698. include(flowcontrol,fc_gotolabel);
  699. {$ifdef OLDREGVARS}
  700. load_all_regvars(current_asmdata.CurrAsmList);
  701. {$endif OLDREGVARS}
  702. hlcg.a_label(current_asmdata.CurrAsmList,getasmlabel);
  703. { Write also extra label if this label was referenced from
  704. assembler block }
  705. if assigned(labsym) and
  706. assigned(labsym.asmblocklabel) then
  707. hlcg.a_label(current_asmdata.CurrAsmList,labsym.asmblocklabel);
  708. secondpass(left);
  709. end;
  710. {*****************************************************************************
  711. tcgexceptionstatehandler
  712. *****************************************************************************}
  713. class function tcgexceptionstatehandler.use_cleanup(const exceptframekind: texceptframekind): boolean;
  714. begin
  715. { in case of an exception caught by the implicit exception frame of
  716. a safecall routine, this is not a cleanup frame but one that
  717. catches the exception and returns a value from the function }
  718. result:=
  719. (exceptframekind=tek_implicitfinally) and
  720. not((tf_safecall_exceptions in target_info.flags) and
  721. (current_procinfo.procdef.proccalloption=pocall_safecall));
  722. end;
  723. { Allocate the buffers for exception management and setjmp environment.
  724. Return a pointer to these buffers, send them to the utility routine
  725. so they are registered, and then call setjmp.
  726. Then compare the result of setjmp with 0, and if not equal
  727. to zero, then jump to exceptlabel.
  728. Also store the result of setjmp to a temporary space by calling g_save_exception_reason
  729. It is to note that this routine may be called *after* the stackframe of a
  730. routine has been called, therefore on machines where the stack cannot
  731. be modified, all temps should be allocated on the heap instead of the
  732. stack. }
  733. class procedure tcgexceptionstatehandler.get_exception_temps(list:TAsmList;var t:texceptiontemps);
  734. begin
  735. tg.gethltemp(list,rec_exceptaddr,rec_exceptaddr.size,tt_persistent,t.envbuf);
  736. tg.gethltemp(list,rec_jmp_buf,rec_jmp_buf.size,tt_persistent,t.jmpbuf);
  737. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  738. end;
  739. class procedure tcgexceptionstatehandler.unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  740. begin
  741. tg.Ungettemp(list,t.jmpbuf);
  742. tg.ungettemp(list,t.envbuf);
  743. tg.ungettemp(list,t.reasonbuf);
  744. end;
  745. class procedure tcgexceptionstatehandler.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  746. var
  747. paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
  748. pd: tprocdef;
  749. tmpresloc: tlocation;
  750. begin
  751. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  752. exceptstate.oldflowcontrol:=flowcontrol;
  753. exceptstate.finallycodelabel:=nil;;
  754. paraloc1.init;
  755. paraloc2.init;
  756. paraloc3.init;
  757. { fpc_pushexceptaddr(exceptionframetype, setjmp_buffer, exception_address_chain_entry) }
  758. pd:=search_system_proc('fpc_pushexceptaddr');
  759. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  760. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,2,paraloc2);
  761. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,3,paraloc3);
  762. if pd.is_pushleftright then
  763. begin
  764. { type of exceptionframe }
  765. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  766. { setjmp buffer }
  767. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  768. { exception address chain entry }
  769. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  770. end
  771. else
  772. begin
  773. hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
  774. hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
  775. hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
  776. end;
  777. paramanager.freecgpara(list,paraloc3);
  778. paramanager.freecgpara(list,paraloc2);
  779. paramanager.freecgpara(list,paraloc1);
  780. { perform the fpc_pushexceptaddr call }
  781. pushexceptres:=hlcg.g_call_system_proc(list,pd,[@paraloc1,@paraloc2,@paraloc3],nil);
  782. paraloc1.done;
  783. paraloc2.done;
  784. paraloc3.done;
  785. { get the result }
  786. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(pushexceptres.def));
  787. tmpresloc.register:=hlcg.getaddressregister(list,pushexceptres.def);
  788. hlcg.gen_load_cgpara_loc(list,pushexceptres.def,pushexceptres,tmpresloc,true);
  789. pushexceptres.resetiftemp;
  790. { fpc_setjmp(result_of_pushexceptaddr_call) }
  791. pd:=search_system_proc('fpc_setjmp');
  792. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  793. hlcg.a_load_reg_cgpara(list,pushexceptres.def,tmpresloc.register,paraloc1);
  794. paramanager.freecgpara(list,paraloc1);
  795. { perform the fpc_setjmp call }
  796. setjmpres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  797. paraloc1.done;
  798. location_reset(tmpresloc,LOC_REGISTER,def_cgsize(setjmpres.def));
  799. tmpresloc.register:=hlcg.getintregister(list,setjmpres.def);
  800. hlcg.gen_load_cgpara_loc(list,setjmpres.def,setjmpres,tmpresloc,true);
  801. hlcg.g_exception_reason_save(list,setjmpres.def,ossinttype,tmpresloc.register,t.reasonbuf);
  802. { if we get 1 here in the function result register, it means that we
  803. longjmp'd back here }
  804. hlcg.a_cmp_const_reg_label(list,setjmpres.def,OC_NE,0,tmpresloc.register,exceptstate.exceptionlabel);
  805. setjmpres.resetiftemp;
  806. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  807. end;
  808. class procedure tcgexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptstate: texceptionstate;var exceptiontemps:texceptiontemps);
  809. begin
  810. hlcg.a_label(list,exceptstate.exceptionlabel);
  811. end;
  812. class procedure tcgexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel);
  813. begin
  814. exceptionstate.newflowcontrol:=flowcontrol;
  815. flowcontrol:=exceptionstate.oldflowcontrol;
  816. end;
  817. class procedure tcgexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree: boolean);
  818. var
  819. reasonreg: tregister;
  820. begin
  821. popaddrstack(list);
  822. if not onlyfree then
  823. begin
  824. reasonreg:=hlcg.getintregister(list,osuinttype);
  825. hlcg.g_exception_reason_load(list,osuinttype,osuinttype,t.reasonbuf,reasonreg);
  826. hlcg.a_cmp_const_reg_label(list,osuinttype,OC_EQ,a,reasonreg,endexceptlabel);
  827. end;
  828. end;
  829. { does the necessary things to clean up the object stack }
  830. { in the except block }
  831. class procedure tcgexceptionstatehandler.cleanupobjectstack(list: TAsmList);
  832. begin
  833. hlcg.g_call_system_proc(list,'fpc_doneexception',[],nil).resetiftemp;
  834. end;
  835. { generates code to be executed when another exeception is raised while
  836. control is inside except block }
  837. class procedure tcgexceptionstatehandler.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
  838. var
  839. exitlabel: tasmlabel;
  840. begin
  841. current_asmdata.getjumplabel(exitlabel);
  842. end_try_block(list,tek_except,t,entrystate,exitlabel);
  843. emit_except_label(current_asmdata.CurrAsmList,tek_except,entrystate,t);
  844. { don't generate line info for internal cleanup }
  845. list.concat(tai_marker.create(mark_NoLineInfoStart));
  846. free_exception(list,t,entrystate,0,exitlabel,false);
  847. { we don't need to save/restore registers here because reraise never }
  848. { returns }
  849. hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil).resetiftemp;
  850. hlcg.a_label(list,exitlabel);
  851. cleanupobjectstack(list);
  852. end;
  853. class procedure tcgexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate; const exceptframekind: texceptframekind);
  854. begin
  855. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  856. end;
  857. class procedure tcgexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister);
  858. var
  859. pd: tprocdef;
  860. href2: treference;
  861. fpc_catches_res,
  862. paraloc1: tcgpara;
  863. exceptloc: tlocation;
  864. indirect: boolean;
  865. otherunit: boolean;
  866. begin
  867. paraloc1.init;
  868. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  869. indirect:=(tf_supports_packages in target_info.flags) and
  870. (target_info.system in systems_indirect_var_imports) and
  871. (cs_imported_data in current_settings.localswitches) and
  872. otherunit;
  873. { send the vmt parameter }
  874. pd:=search_system_proc('fpc_catches');
  875. reference_reset_symbol(href2, current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect), 0, sizeof(pint), []);
  876. if otherunit then
  877. current_module.add_extern_asmsym(excepttype.vmt_mangledname, AB_EXTERNAL, AT_DATA);
  878. paramanager.getintparaloc(list, pd, 1, paraloc1);
  879. hlcg.a_loadaddr_ref_cgpara(list, excepttype.vmt_def, href2, paraloc1);
  880. paramanager.freecgpara(list, paraloc1);
  881. fpc_catches_res:=hlcg.g_call_system_proc(list, pd, [@paraloc1], nil);
  882. location_reset(exceptloc, LOC_REGISTER, def_cgsize(fpc_catches_res.def));
  883. exceptloc.register:=hlcg.getaddressregister(list, fpc_catches_res.def);
  884. hlcg.gen_load_cgpara_loc(list, fpc_catches_res.def, fpc_catches_res, exceptloc, true);
  885. { is it this catch? No. go to next onlabel }
  886. hlcg.a_cmp_const_reg_label(list, fpc_catches_res.def, OC_EQ, 0, exceptloc.register, nextonlabel);
  887. paraloc1.done;
  888. exceptlocdef:=fpc_catches_res.def;
  889. exceptlocreg:=exceptloc.register;
  890. end;
  891. class procedure tcgexceptionstatehandler.end_catch(list: TAsmList);
  892. begin
  893. { nothing to do by default }
  894. end;
  895. class procedure tcgexceptionstatehandler.catch_all_start(list: TAsmList);
  896. begin
  897. { nothing to do by default }
  898. end;
  899. class procedure tcgexceptionstatehandler.catch_all_end(list: TAsmList);
  900. begin
  901. { nothing to do by default }
  902. end;
  903. class procedure tcgexceptionstatehandler.popaddrstack(list: TAsmList);
  904. begin
  905. hlcg.g_call_system_proc(list,'fpc_popaddrstack',[],nil).resetiftemp;
  906. end;
  907. {*****************************************************************************
  908. SecondTryExcept
  909. *****************************************************************************}
  910. var
  911. endexceptlabel : tasmlabel;
  912. { jump out of an try/except block }
  913. procedure tcgtryexceptnode.emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel);
  914. begin
  915. hlcg.a_label(list,framelabel);
  916. { we must also destroy the address frame which guards
  917. the exception object }
  918. cexceptionstatehandler.popaddrstack(list);
  919. hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
  920. if frametype=ft_except then
  921. begin
  922. cexceptionstatehandler.cleanupobjectstack(list);
  923. cexceptionstatehandler.end_catch(list);
  924. end;
  925. hlcg.a_jmp_always(list,outerlabel);
  926. end;
  927. procedure tcgtryexceptnode.pass_generate_code;
  928. var
  929. oldendexceptlabel,
  930. lastonlabel,
  931. exitexceptlabel,
  932. continueexceptlabel,
  933. breakexceptlabel,
  934. exittrylabel,
  935. continuetrylabel,
  936. breaktrylabel,
  937. oldCurrExitLabel,
  938. oldContinueLabel,
  939. oldBreakLabel : tasmlabel;
  940. destroytemps,
  941. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  942. trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  943. afteronflowcontrol: tflowcontrol;
  944. label
  945. errorexit;
  946. begin
  947. location_reset(location,LOC_VOID,OS_NO);
  948. continuetrylabel:=nil;
  949. breaktrylabel:=nil;
  950. continueexceptlabel:=nil;
  951. breakexceptlabel:=nil;
  952. doobjectdestroyandreraisestate:=Default(tcgexceptionstatehandler.texceptionstate);
  953. { this can be called recursivly }
  954. oldBreakLabel:=nil;
  955. oldContinueLabel:=nil;
  956. oldendexceptlabel:=endexceptlabel;
  957. { save the old labels for control flow statements }
  958. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  959. if assigned(current_procinfo.CurrBreakLabel) then
  960. begin
  961. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  962. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  963. end;
  964. { get new labels for the control flow statements }
  965. current_asmdata.getjumplabel(exittrylabel);
  966. current_asmdata.getjumplabel(exitexceptlabel);
  967. if assigned(current_procinfo.CurrBreakLabel) then
  968. begin
  969. current_asmdata.getjumplabel(breaktrylabel);
  970. current_asmdata.getjumplabel(continuetrylabel);
  971. current_asmdata.getjumplabel(breakexceptlabel);
  972. current_asmdata.getjumplabel(continueexceptlabel);
  973. end;
  974. current_asmdata.getjumplabel(endexceptlabel);
  975. current_asmdata.getjumplabel(lastonlabel);
  976. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  977. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
  978. { try block }
  979. { set control flow labels for the try block }
  980. current_procinfo.CurrExitLabel:=exittrylabel;
  981. if assigned(oldBreakLabel) then
  982. begin
  983. current_procinfo.CurrContinueLabel:=continuetrylabel;
  984. current_procinfo.CurrBreakLabel:=breaktrylabel;
  985. end;
  986. secondpass(left);
  987. if codegenerror then
  988. goto errorexit;
  989. { don't generate line info for internal cleanup }
  990. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  991. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,endexceptlabel);
  992. cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,tek_except,trystate,excepttemps);
  993. cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList, excepttemps, trystate, 0, endexceptlabel, false);
  994. { end cleanup }
  995. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  996. { set control flow labels for the except block }
  997. { and the on statements }
  998. current_procinfo.CurrExitLabel:=exitexceptlabel;
  999. if assigned(oldBreakLabel) then
  1000. begin
  1001. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  1002. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  1003. end;
  1004. flowcontrol:=[fc_inflowcontrol];
  1005. { on statements }
  1006. if assigned(right) then
  1007. secondpass(right);
  1008. afteronflowcontrol:=flowcontrol;
  1009. { don't generate line info for internal cleanup }
  1010. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1011. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  1012. { default handling except handling }
  1013. if assigned(t1) then
  1014. begin
  1015. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  1016. it doesn't change any state and its return value is ignored (Sergei)
  1017. }
  1018. { the destruction of the exception object must be also }
  1019. { guarded by an exception frame, but it can be omitted }
  1020. { if there's no user code in 'except' block }
  1021. cexceptionstatehandler.catch_all_start(current_asmdata.CurrAsmList);
  1022. if not (has_no_code(t1)) then
  1023. begin
  1024. { if there is an outer frame that catches exceptions, remember this for the "except"
  1025. part of this try/except }
  1026. flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1027. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  1028. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
  1029. { the flowcontrol from the default except-block must be merged
  1030. with the flowcontrol flags potentially set by the
  1031. on-statements handled above (secondpass(right)), as they are
  1032. at the same program level }
  1033. flowcontrol:=
  1034. flowcontrol+
  1035. afteronflowcontrol;
  1036. { except block needs line info }
  1037. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1038. secondpass(t1);
  1039. cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
  1040. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  1041. cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
  1042. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  1043. end
  1044. else
  1045. begin
  1046. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  1047. cexceptionstatehandler.cleanupobjectstack(current_asmdata.CurrAsmList);
  1048. cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
  1049. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  1050. end;
  1051. end
  1052. else
  1053. begin
  1054. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,trystate,tek_except);
  1055. doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
  1056. end;
  1057. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  1058. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,exitexceptlabel,oldCurrExitLabel);
  1059. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  1060. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,breakexceptlabel,oldBreakLabel);
  1061. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  1062. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,continueexceptlabel,oldContinueLabel);
  1063. if fc_exit in trystate.newflowcontrol then
  1064. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,exittrylabel,oldCurrExitLabel);
  1065. if fc_break in trystate.newflowcontrol then
  1066. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,breaktrylabel,oldBreakLabel);
  1067. if fc_continue in trystate.newflowcontrol then
  1068. emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,continuetrylabel,oldContinueLabel);
  1069. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1070. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  1071. { end cleanup }
  1072. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1073. errorexit:
  1074. { restore all saved labels }
  1075. endexceptlabel:=oldendexceptlabel;
  1076. { restore the control flow labels }
  1077. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1078. if assigned(oldBreakLabel) then
  1079. begin
  1080. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1081. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1082. end;
  1083. { return all used control flow statements }
  1084. flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
  1085. trystate.newflowcontrol - [fc_inflowcontrol,fc_catching_exceptions]);
  1086. end;
  1087. procedure tcgonnode.pass_generate_code;
  1088. var
  1089. nextonlabel,
  1090. exitonlabel,
  1091. continueonlabel,
  1092. breakonlabel,
  1093. oldCurrExitLabel,
  1094. oldContinueLabel,
  1095. oldBreakLabel : tasmlabel;
  1096. doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
  1097. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  1098. exceptvarsym : tlocalvarsym;
  1099. exceptlocdef: tdef;
  1100. exceptlocreg: tregister;
  1101. begin
  1102. location_reset(location,LOC_VOID,OS_NO);
  1103. oldCurrExitLabel:=nil;
  1104. continueonlabel:=nil;
  1105. breakonlabel:=nil;
  1106. exitonlabel:=nil;
  1107. current_asmdata.getjumplabel(nextonlabel);
  1108. cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nextonlabel,exceptlocdef,exceptlocreg);
  1109. { Retrieve exception variable }
  1110. if assigned(excepTSymtable) then
  1111. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1112. else
  1113. internalerror(2011020401);
  1114. if assigned(exceptvarsym) then
  1115. begin
  1116. location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
  1117. tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
  1118. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
  1119. end;
  1120. { in the case that another exception is risen
  1121. we've to destroy the old one, so create a new
  1122. exception frame for the catch-handler }
  1123. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1124. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,doobjectdestroyandreraisestate);
  1125. oldBreakLabel:=nil;
  1126. oldContinueLabel:=nil;
  1127. if assigned(right) then
  1128. begin
  1129. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1130. current_asmdata.getjumplabel(exitonlabel);
  1131. current_procinfo.CurrExitLabel:=exitonlabel;
  1132. if assigned(current_procinfo.CurrBreakLabel) then
  1133. begin
  1134. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1135. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1136. current_asmdata.getjumplabel(breakonlabel);
  1137. current_asmdata.getjumplabel(continueonlabel);
  1138. current_procinfo.CurrContinueLabel:=continueonlabel;
  1139. current_procinfo.CurrBreakLabel:=breakonlabel;
  1140. end;
  1141. secondpass(right);
  1142. end;
  1143. cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
  1144. { clear some stuff }
  1145. if assigned(exceptvarsym) then
  1146. begin
  1147. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1148. exceptvarsym.localloc.loc:=LOC_INVALID;
  1149. end;
  1150. cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
  1151. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  1152. if assigned(right) then
  1153. begin
  1154. { special handling for control flow instructions }
  1155. if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
  1156. begin
  1157. { the address and object pop does secondtryexcept }
  1158. hlcg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  1159. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  1160. end;
  1161. if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
  1162. begin
  1163. { the address and object pop does secondtryexcept }
  1164. hlcg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  1165. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  1166. end;
  1167. if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
  1168. begin
  1169. { the address and object pop does secondtryexcept }
  1170. hlcg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  1171. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  1172. end;
  1173. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1174. if assigned(oldBreakLabel) then
  1175. begin
  1176. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1177. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1178. end;
  1179. end;
  1180. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1181. hlcg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  1182. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1183. { propagate exit/break/continue }
  1184. flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1185. { next on node }
  1186. if assigned(left) then
  1187. secondpass(left);
  1188. end;
  1189. {*****************************************************************************
  1190. SecondTryFinally
  1191. *****************************************************************************}
  1192. { jump out of a finally block }
  1193. procedure tcgtryfinallynode.emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
  1194. begin
  1195. hlcg.a_label(list,framelabel);
  1196. hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
  1197. hlcg.g_exception_reason_save_const(list,osuinttype,reason,excepttemps.reasonbuf);
  1198. hlcg.a_jmp_always(list,finallycodelabel);
  1199. end;
  1200. function tcgtryfinallynode.get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
  1201. begin
  1202. current_asmdata.getjumplabel(result);
  1203. end;
  1204. procedure tcgtryfinallynode.handle_safecall_exception;
  1205. var
  1206. cgpara: tcgpara;
  1207. selfsym: tparavarsym;
  1208. pd: tprocdef;
  1209. begin
  1210. { call fpc_safecallhandler, passing self for methods of classes,
  1211. nil otherwise. }
  1212. pd:=search_system_proc('fpc_safecallhandler');
  1213. cgpara.init;
  1214. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  1215. if is_class(current_procinfo.procdef.struct) then
  1216. begin
  1217. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  1218. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  1219. InternalError(2011123101);
  1220. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.localloc,cgpara);
  1221. end
  1222. else
  1223. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_ADDR,0,cgpara);
  1224. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  1225. cgpara.done;
  1226. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLHANDLER');
  1227. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
  1228. end;
  1229. procedure tcgtryfinallynode.pass_generate_code;
  1230. var
  1231. endfinallylabel,
  1232. exitfinallylabel,
  1233. continuefinallylabel,
  1234. breakfinallylabel,
  1235. oldCurrExitLabel,
  1236. oldContinueLabel,
  1237. oldBreakLabel,
  1238. finallyNoExceptionLabel: tasmlabel;
  1239. finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
  1240. excepttemps : tcgexceptionstatehandler.texceptiontemps;
  1241. reasonreg : tregister;
  1242. exceptframekind: tcgexceptionstatehandler.texceptframekind;
  1243. tmplist: TAsmList;
  1244. procedure handle_breakcontinueexit(const finallycode: tasmlabel; doreraise: boolean);
  1245. begin
  1246. { no exception happened, but maybe break/continue/exit }
  1247. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1248. if fc_exit in finallyexceptionstate.newflowcontrol then
  1249. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  1250. if fc_break in finallyexceptionstate.newflowcontrol then
  1251. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  1252. if fc_continue in finallyexceptionstate.newflowcontrol then
  1253. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  1254. if doreraise then
  1255. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,tek_normalfinally)
  1256. else
  1257. hlcg.g_unreachable(current_asmdata.CurrAsmList);
  1258. { redirect break/continue/exit to the label above, with the reasonbuf set appropriately }
  1259. if fc_exit in finallyexceptionstate.newflowcontrol then
  1260. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,2,finallycode,excepttemps,exitfinallylabel);
  1261. if fc_break in finallyexceptionstate.newflowcontrol then
  1262. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,3,finallycode,excepttemps,breakfinallylabel);
  1263. if fc_continue in finallyexceptionstate.newflowcontrol then
  1264. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,4,finallycode,excepttemps,continuefinallylabel);
  1265. end;
  1266. begin
  1267. location_reset(location,LOC_VOID,OS_NO);
  1268. oldBreakLabel:=nil;
  1269. oldContinueLabel:=nil;
  1270. continuefinallylabel:=nil;
  1271. breakfinallylabel:=nil;
  1272. if not implicitframe then
  1273. exceptframekind:=tek_normalfinally
  1274. else
  1275. exceptframekind:=tek_implicitfinally;
  1276. current_asmdata.getjumplabel(endfinallylabel);
  1277. { call setjmp, and jump to finally label on non-zero result }
  1278. cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1279. cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
  1280. { the finally block must catch break, continue and exit }
  1281. { statements }
  1282. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1283. exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1284. current_procinfo.CurrExitLabel:=exitfinallylabel;
  1285. if assigned(current_procinfo.CurrBreakLabel) then
  1286. begin
  1287. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1288. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1289. breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1290. continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
  1291. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  1292. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  1293. end;
  1294. { try code }
  1295. if assigned(left) then
  1296. begin
  1297. secondpass(left);
  1298. if codegenerror then
  1299. exit;
  1300. end;
  1301. { don't generate line info for internal cleanup }
  1302. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1303. cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,finallyexceptionstate.finallycodelabel);
  1304. if assigned(third) then
  1305. begin
  1306. tmplist:=TAsmList.create;
  1307. { emit the except label already (to a temporary list) to ensure that any calls in the
  1308. finally block refer to the outer exception frame rather than to the exception frame
  1309. that emits this same finally code in case an exception does happen }
  1310. cexceptionstatehandler.emit_except_label(tmplist,exceptframekind,finallyexceptionstate,excepttemps);
  1311. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1312. current_asmdata.getjumplabel(finallyNoExceptionLabel);
  1313. hlcg.a_label(current_asmdata.CurrAsmList,finallyNoExceptionLabel);
  1314. if not implicitframe then
  1315. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1316. secondpass(third);
  1317. if codegenerror then
  1318. exit;
  1319. if not implicitframe then
  1320. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1321. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  1322. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  1323. handle_breakcontinueexit(finallyNoExceptionLabel,false);
  1324. current_asmdata.CurrAsmList.concatList(tmplist);
  1325. tmplist.free;
  1326. end
  1327. else
  1328. cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,exceptframekind,finallyexceptionstate,excepttemps);
  1329. { just free the frame information }
  1330. cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,1,finallyexceptionstate.exceptionlabel,true);
  1331. { end cleanup }
  1332. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1333. { finally code (don't unconditionally set fc_inflowcontrol, since the
  1334. finally code is unconditionally executed; we do have to filter out
  1335. flags regarding break/contrinue/etc. because we have to give an
  1336. error in case one of those is used in the finally-code }
  1337. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
  1338. secondpass(right);
  1339. { goto is allowed if it stays inside the finally block,
  1340. this is checked using the exception block number }
  1341. if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
  1342. CGMessage(cg_e_control_flow_outside_finally);
  1343. if codegenerror then
  1344. exit;
  1345. { don't generate line info for internal cleanup }
  1346. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1347. { same level as before try, but this part is only executed if an exception occcurred
  1348. -> always fc_in_flowcontrol }
  1349. flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_catching_exceptions];
  1350. include(flowcontrol,fc_inflowcontrol);
  1351. if not assigned(third) then
  1352. begin
  1353. { the value should now be in the exception handler }
  1354. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  1355. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  1356. if implicitframe then
  1357. begin
  1358. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1359. { finally code only needed to be executed on exception (-> in
  1360. if-branch -> fc_inflowcontrol) }
  1361. if (tf_safecall_exceptions in target_info.flags) and
  1362. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  1363. handle_safecall_exception
  1364. else
  1365. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  1366. { we have to load 0 into the execepttemp, else the program thinks an exception happended }
  1367. emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,0,finallyexceptionstate.exceptionlabel,excepttemps,exitfinallylabel);
  1368. end
  1369. else
  1370. begin
  1371. handle_breakcontinueexit(finallyexceptionstate.exceptionlabel,true);
  1372. end;
  1373. end
  1374. else
  1375. begin
  1376. if implicitframe then
  1377. begin
  1378. if (tf_safecall_exceptions in target_info.flags) and
  1379. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  1380. handle_safecall_exception
  1381. else
  1382. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  1383. end
  1384. else
  1385. begin
  1386. cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
  1387. end;
  1388. end;
  1389. cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1390. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  1391. { end cleanup }
  1392. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1393. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1394. if assigned(current_procinfo.CurrBreakLabel) then
  1395. begin
  1396. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1397. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1398. end;
  1399. flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
  1400. end;
  1401. function tcgraisenode.pass_1: tnode;
  1402. begin
  1403. if not(tf_use_psabieh in target_info.flags) or assigned(left) then
  1404. result:=inherited
  1405. else
  1406. begin
  1407. expectloc:=LOC_VOID;
  1408. result:=nil;
  1409. end;
  1410. end;
  1411. procedure tcgraisenode.pass_generate_code;
  1412. var
  1413. CurrentLandingPad, CurrentAction, ReRaiseLandingPad: TPSABIEHAction;
  1414. begin
  1415. if not(tf_use_psabieh in target_info.flags) then
  1416. Internalerror(2019021701);
  1417. location_reset(location,LOC_VOID,OS_NO);
  1418. CurrentLandingPad:=nil;
  1419. { a reraise must raise the exception to the parent exception frame }
  1420. if fc_catching_exceptions in flowcontrol then
  1421. begin
  1422. current_procinfo.CreateNewPSABIEHCallsite;
  1423. CurrentLandingPad:=current_procinfo.CurrentLandingPad;
  1424. if current_procinfo.PopLandingPad(CurrentLandingPad) then
  1425. exclude(flowcontrol,fc_catching_exceptions);
  1426. CurrentAction:=current_procinfo.CurrentAction;
  1427. current_procinfo.PopAction(CurrentAction);
  1428. ReRaiseLandingPad:=TPSABIEHAction.Create(nil);
  1429. current_procinfo.PushAction(ReRaiseLandingPad);
  1430. current_procinfo.PushLandingPad(ReRaiseLandingPad);
  1431. end;
  1432. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  1433. if assigned(CurrentLandingPad) then
  1434. begin
  1435. current_procinfo.CreateNewPSABIEHCallsite;
  1436. current_procinfo.PopLandingPad(current_procinfo.CurrentLandingPad);
  1437. current_procinfo.PopAction(ReRaiseLandingPad);
  1438. current_procinfo.PushAction(CurrentAction);
  1439. current_procinfo.PushLandingPad(CurrentLandingPad);
  1440. include(flowcontrol,fc_catching_exceptions);
  1441. end;
  1442. end;
  1443. begin
  1444. cwhilerepeatnode:=tcgwhilerepeatnode;
  1445. cifnode:=tcgifnode;
  1446. cfornode:=tcgfornode;
  1447. cexitnode:=tcgexitnode;
  1448. cbreaknode:=tcgbreaknode;
  1449. ccontinuenode:=tcgcontinuenode;
  1450. cgotonode:=tcggotonode;
  1451. clabelnode:=tcglabelnode;
  1452. craisenode:=tcgraisenode;
  1453. ctryexceptnode:=tcgtryexceptnode;
  1454. ctryfinallynode:=tcgtryfinallynode;
  1455. connode:=tcgonnode;
  1456. cexceptionstatehandler:=tcgexceptionstatehandler;
  1457. end.