ncgflw.pas 71 KB

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