psabiehpi.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Information about the current procedure that is being compiled
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit psabiehpi;
  18. { $define debug_eh}
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. { common }
  23. cclasses,
  24. { global }
  25. globtype,
  26. { symtable }
  27. symconst,symtype,symdef,symsym,
  28. node,nutils,
  29. { aasm }
  30. cpubase,cgbase,cgutils,
  31. aasmbase,aasmdata,aasmtai,
  32. psub;
  33. type
  34. TPSABIEHAction = class
  35. landingpad : TAsmLabel;
  36. actiontablelabel : TAsmLabel;
  37. actionlist : TAsmList;
  38. first : boolean;
  39. constructor Create(pad : TAsmLabel);
  40. destructor Destroy; override;
  41. function AddAction(p: tobjectdef): LongInt;
  42. end;
  43. { This object gives information on the current routine being
  44. compiled.
  45. }
  46. tpsabiehprocinfo = class(tcgprocinfo)
  47. { set if the procedure needs exception tables because it
  48. has exception generating nodes }
  49. CreateExceptionTable: Boolean;
  50. { if a procedure needs exception tables, this is the outmost landing pad
  51. with "no action", covering everything not covered by other landing pads
  52. since a procedure which has one landing pad need to be covered completely by landing pads }
  53. OutmostLandingPad: TPSABIEHAction;
  54. { This is a "no action" action for re-use, normally equal to OutmostLandingPad }
  55. NoAction: TPSABIEHAction;
  56. callsite_table_data,
  57. action_table_data,
  58. gcc_except_table_data : TAsmList;
  59. typefilterlistlabel,typefilterlistlabelref,
  60. callsitetablestart,callsitetableend,
  61. { first label which must be inserted into the entry code }
  62. entrycallsitestart,
  63. callsitelaststart : TAsmLabel;
  64. typefilterlist,
  65. landingpadstack,
  66. actionstack : tfplist;
  67. CurrentCallSiteNumber : Longint;
  68. destructor destroy; override;
  69. { PSABIEH stuff }
  70. procedure PushAction(action: TPSABIEHAction);
  71. function CurrentAction: TPSABIEHAction;inline;
  72. function PopAction(action: TPSABIEHAction): boolean;
  73. function FinalizeAndPopAction(action: TPSABIEHAction): boolean;
  74. { a landing pad is also an action, however, when the landing pad is popped from the stack
  75. the area covered by this landing pad ends, i.e. it is popped at the beginning of the finally/except clause,
  76. the action above is popped at the end of the finally/except clause, so if on clauses add new types, they
  77. are added to CurrentAction }
  78. procedure PushLandingPad(action: TPSABIEHAction);
  79. function CurrentLandingPad: TPSABIEHAction;inline;
  80. function PopLandingPad(action: TPSABIEHAction): boolean;
  81. procedure CreateNewPSABIEHCallsite(list: TAsmList);
  82. { adds a new type to the type filter list and returns its index
  83. be aware, that this method can also handle catch all filters so it
  84. is valid to pass nil }
  85. function AddTypeFilter(p: tobjectdef): Longint;
  86. procedure set_eh_info; override;
  87. procedure setup_eh; override;
  88. procedure finish_eh; override;
  89. procedure start_eh(list : TAsmList); override;
  90. procedure end_eh(list : TAsmList); override;
  91. function find_exception_handling(var n: tnode; para: pointer): foreachnoderesult; virtual;
  92. end;
  93. implementation
  94. uses
  95. cutils,
  96. verbose,
  97. systems,
  98. dwarfbase,
  99. cfidwarf,
  100. globals,
  101. procinfo,
  102. symtable,
  103. defutil,
  104. tgobj,
  105. cgobj,cgexcept,
  106. parabase,paramgr,
  107. hlcgobj,
  108. pass_2
  109. {$ifdef i386}
  110. ,aasmcpu
  111. {$endif i386}
  112. ;
  113. type
  114. { Utility class for exception handling state management that is used
  115. by tryexcept/tryfinally/on nodes (in a separate class so it can both
  116. be shared and overridden)
  117. Never instantiated. }
  118. tpsabiehexceptionstatehandler = class(tcgexceptionstatehandler)
  119. protected
  120. class procedure begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; add_catch: boolean; out exceptlocdef: tdef; out
  121. exceptlocreg: tregister);
  122. class procedure catch_all_start_internal(list: TAsmList; add_catch: boolean);
  123. public
  124. class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
  125. class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
  126. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  127. { start of "except/finally" block }
  128. class procedure emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps); override;
  129. { end of a try-block, label comes after the end of try/except or
  130. try/finally }
  131. class procedure end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel); override;
  132. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  133. class procedure handle_reraise(list:TAsmList;const t:texceptiontemps;const entrystate: texceptionstate; const exceptframekind: texceptframekind); override;
  134. { start of an "on" (catch) block }
  135. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  136. { end of an "on" (catch) block }
  137. class procedure end_catch(list: TAsmList); override;
  138. { called for a catch all exception }
  139. class procedure catch_all_start(list: TAsmList); override;
  140. class procedure catch_all_end(list: TAsmList); override;
  141. class procedure catch_all_add(list: TAsmList); override;
  142. class procedure cleanupobjectstack(list: TAsmList); override;
  143. class procedure popaddrstack(list: TAsmList); override;
  144. end;
  145. constructor TPSABIEHAction.Create(pad: TAsmLabel);
  146. begin
  147. landingpad:=pad;
  148. actionlist:=TAsmList.create;
  149. current_asmdata.getlabel(actiontablelabel,alt_data);
  150. actionlist.concat(tai_label.create(actiontablelabel));
  151. first:=true;
  152. end;
  153. destructor TPSABIEHAction.Destroy;
  154. begin
  155. if not(actionlist.Empty) then
  156. Internalerror(2019020501);
  157. actionlist.Free;
  158. inherited Destroy;
  159. end;
  160. function TPSABIEHAction.AddAction(p: tobjectdef) : LongInt;
  161. var
  162. index: LongInt;
  163. begin
  164. { if not first entry, signal that another action follows }
  165. if not(first) then
  166. actionlist.concat(tai_const.Create_uleb128bit(1));
  167. first:=false;
  168. { catch all? }
  169. if p=tobjectdef(-1) then
  170. index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(nil)
  171. else if assigned(p) then
  172. index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(p)
  173. else
  174. index:=-1;
  175. {$ifdef debug_eh}
  176. if p=tobjectdef(-1) then
  177. actionlist.concat(tai_comment.Create(strpnew('Catch all')))
  178. else if assigned(p) then
  179. actionlist.concat(tai_comment.Create(strpnew('Action for '+p.GetTypeName)))
  180. else
  181. actionlist.concat(tai_comment.Create(strpnew('Cleanup')));
  182. {$endif debug_eh}
  183. if assigned(p) then
  184. actionlist.concat(tai_const.Create_uleb128bit(index+1))
  185. else
  186. actionlist.concat(tai_const.Create_uleb128bit(0));
  187. Result:=index;
  188. end;
  189. {****************************************************************************
  190. tpsabiehprocinfo
  191. ****************************************************************************}
  192. destructor tpsabiehprocinfo.destroy;
  193. begin
  194. gcc_except_table_data.free;
  195. actionstack.free;
  196. landingpadstack.free;
  197. typefilterlist.free;
  198. callsite_table_data.Free;
  199. action_table_data.Free;
  200. inherited;
  201. end;
  202. procedure tpsabiehprocinfo.PushAction(action: TPSABIEHAction);
  203. begin
  204. actionstack.add(action);
  205. end;
  206. function tpsabiehprocinfo.PopAction(action: TPSABIEHAction): boolean;
  207. begin
  208. if CurrentAction<>action then
  209. internalerror(2019022501);
  210. actionstack.count:=actionstack.count-1;
  211. result:=actionstack.count=0;
  212. end;
  213. function tpsabiehprocinfo.FinalizeAndPopAction(action: TPSABIEHAction): boolean;
  214. var
  215. curpos: tasmlabel;
  216. begin
  217. include(flags,pi_has_except_table_data);
  218. if CurrentAction<>action then
  219. internalerror(2019021006);
  220. { no further actions follow, finalize table
  221. we check for >1 as the outmost landing pad has no action, so
  222. we can ignore it }
  223. if landingpadstack.count>1 then
  224. begin
  225. current_asmdata.getlabel(curpos,alt_data);
  226. action.actionlist.concat(tai_label.create(curpos));
  227. action.actionlist.concat(tai_const.Create_rel_sym(aitconst_sleb128bit,curpos,TPSABIEHAction(landingpadstack[landingpadstack.count-1]).actiontablelabel));
  228. end
  229. else
  230. action.actionlist.concat(tai_const.Create_uleb128bit(0));
  231. action_table_data.concatList(action.actionlist);
  232. actionstack.count:=actionstack.count-1;
  233. result:=actionstack.count=0;
  234. end;
  235. procedure tpsabiehprocinfo.PushLandingPad(action: TPSABIEHAction);
  236. begin
  237. landingpadstack.add(action);
  238. end;
  239. function tpsabiehprocinfo.CurrentLandingPad: TPSABIEHAction;
  240. begin
  241. result:=TPSABIEHAction(landingpadstack.last);
  242. end;
  243. function tpsabiehprocinfo.PopLandingPad(action: TPSABIEHAction): boolean;
  244. begin
  245. if CurrentLandingPad<>action then
  246. internalerror(2019021007);
  247. landingpadstack.count:=landingpadstack.count-1;
  248. result:=landingpadstack.count=0;
  249. end;
  250. procedure tpsabiehprocinfo.CreateNewPSABIEHCallsite(list : TAsmList);
  251. var
  252. callsiteend : TAsmLabel;
  253. begin
  254. include(flags,pi_has_except_table_data);
  255. { first, finish last entry }
  256. if assigned(callsitelaststart) and assigned(CurrentLandingPad) then
  257. begin
  258. {$ifdef debug_eh}
  259. if assigned(CurrentLandingPad.actiontablelabel) then
  260. callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))))
  261. else
  262. callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', no action')));
  263. {$endif debug_eh}
  264. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,TDwarfAsmCFI(current_asmdata.AsmCFI).get_frame_start,callsitelaststart));
  265. current_asmdata.getlabel(callsiteend,alt_eh_end);
  266. list.concat(tai_label.create(callsiteend));
  267. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitelaststart,callsiteend));
  268. { landing pad? }
  269. if assigned(CurrentLandingPad.landingpad) then
  270. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,TDwarfAsmCFI(current_asmdata.AsmCFI).get_frame_start,CurrentLandingPad.landingpad))
  271. else
  272. callsite_table_data.concat(tai_const.Create_uleb128bit(0));
  273. { action number set? if yes, concat }
  274. if assigned(CurrentLandingPad.actiontablelabel) then
  275. begin
  276. callsite_table_data.concat(tai_const.Create_rel_sym_offset(aitconst_uleb128bit,callsitetableend,CurrentLandingPad.actiontablelabel,1));
  277. {$ifdef debug_eh}
  278. list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))));
  279. {$endif debug_eh}
  280. end
  281. else
  282. begin
  283. callsite_table_data.concat(tai_const.Create_uleb128bit(0));
  284. {$ifdef debug_eh}
  285. list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', no action')));
  286. {$endif debug_eh}
  287. end;
  288. current_asmdata.getlabel(callsitelaststart,alt_eh_begin);
  289. list.concat(tai_label.create(callsitelaststart));
  290. end
  291. else
  292. begin
  293. current_asmdata.getlabel(entrycallsitestart,alt_eh_begin);
  294. callsitelaststart:=entrycallsitestart
  295. end;
  296. Inc(CurrentCallSiteNumber);
  297. end;
  298. function tpsabiehprocinfo.AddTypeFilter(p: tobjectdef) : Longint;
  299. var
  300. i: Integer;
  301. begin
  302. for i:=0 to typefilterlist.count-1 do
  303. begin
  304. if tobjectdef(typefilterlist[i])=p then
  305. begin
  306. result:=i;
  307. exit;
  308. end;
  309. end;
  310. result:=typefilterlist.add(p);
  311. end;
  312. procedure tpsabiehprocinfo.set_eh_info;
  313. begin
  314. inherited set_eh_info;
  315. if (tf_use_psabieh in target_info.flags) and not(pi_has_except_table_data in flags) then
  316. (current_asmdata.AsmCFI as TDwarfAsmCFI).LSDALabel:=nil;
  317. end;
  318. function tpsabiehprocinfo.CurrentAction: TPSABIEHAction; inline;
  319. begin
  320. result:=TPSABIEHAction(actionstack.last);
  321. end;
  322. function tpsabiehprocinfo.find_exception_handling(var n: tnode; para: pointer): foreachnoderesult;
  323. begin
  324. if n.nodetype in [tryfinallyn,tryexceptn,raisen,onn] then
  325. Result:=fen_norecurse_true
  326. else
  327. Result:=fen_false;
  328. end;
  329. procedure tpsabiehprocinfo.setup_eh;
  330. var
  331. gcc_except_table: tai_section;
  332. begin
  333. if tf_use_psabieh in target_info.flags then
  334. begin
  335. CreateExceptionTable:=foreachnode(code,@find_exception_handling,nil);
  336. gcc_except_table_data:=TAsmList.Create;
  337. callsite_table_data:=TAsmList.Create;
  338. action_table_data:=TAsmList.Create;
  339. actionstack:=TFPList.Create;
  340. landingpadstack:=TFPList.Create;
  341. typefilterlist:=TFPList.Create;
  342. gcc_except_table:=new_section(gcc_except_table_data,sec_gcc_except_table,'',0);
  343. gcc_except_table.secflags:=SF_A;
  344. gcc_except_table.secprogbits:=SPB_PROGBITS;
  345. if not(current_asmdata.AsmCFI is TDwarfAsmCFI) then
  346. internalerror(2019021003);
  347. {$ifdef debug_eh}
  348. gcc_except_table_data.concat(tai_comment.Create(strpnew('gcc_except_table for '+procdef.fullprocname(true))));
  349. {$endif debug_eh}
  350. current_asmdata.getlabel(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel,alt_data);
  351. current_asmdata.getlabel(callsitetablestart,alt_data);
  352. current_asmdata.getlabel(callsitetableend,alt_data);
  353. callsite_table_data.concat(tai_label.create(callsitetablestart));
  354. cexceptionstatehandler:=tpsabiehexceptionstatehandler;
  355. if CreateExceptionTable then
  356. begin
  357. CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
  358. OutmostLandingPad:=TPSABIEHAction.Create(nil);
  359. NoAction:=OutmostLandingPad;
  360. PushAction(OutmostLandingPad);
  361. PushLandingPad(OutmostLandingPad);
  362. OutmostLandingPad.AddAction(nil);
  363. end;
  364. end;
  365. end;
  366. procedure tpsabiehprocinfo.finish_eh;
  367. var
  368. i: Integer;
  369. begin
  370. if tf_use_psabieh in target_info.flags then
  371. begin
  372. if pi_has_except_table_data in flags then
  373. begin
  374. gcc_except_table_data.concat(tai_label.create(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel));
  375. { landing pad base is relative to procedure start, so write an omit }
  376. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  377. if typefilterlist.count>0 then
  378. begin
  379. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata4));
  380. current_asmdata.getlabel(typefilterlistlabel,alt_data);
  381. current_asmdata.getlabel(typefilterlistlabelref,alt_data);
  382. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,typefilterlistlabel,typefilterlistlabelref));
  383. gcc_except_table_data.concat(tai_label.create(typefilterlistlabel));
  384. end
  385. else
  386. { default types table encoding }
  387. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  388. { call-site table encoded using uleb128 }
  389. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_uleb128));
  390. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitetablestart,callsitetableend));
  391. callsite_table_data.concat(tai_label.create(callsitetableend));
  392. {$ifdef debug_eh}
  393. gcc_except_table_data.concat(tai_comment.Create(strpnew('Call site table for '+procdef.fullprocname(true))));
  394. {$endif debug_eh}
  395. gcc_except_table_data.concatList(callsite_table_data);
  396. { action table must follow immediatly after callsite table }
  397. {$ifdef debug_eh}
  398. if not(action_table_data.Empty) then
  399. gcc_except_table_data.concat(tai_comment.Create(strpnew('Action table for '+procdef.fullprocname(true))));
  400. {$endif debug_eh}
  401. gcc_except_table_data.concatlist(action_table_data);
  402. if typefilterlist.count>0 then
  403. begin
  404. {$ifdef debug_eh}
  405. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter list for '+procdef.fullprocname(true))));
  406. {$endif debug_eh}
  407. for i:=typefilterlist.count-1 downto 0 do
  408. begin
  409. {$ifdef debug_eh}
  410. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter '+tostr(i))));
  411. {$endif debug_eh}
  412. if assigned(typefilterlist[i]) then
  413. gcc_except_table_data.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(tobjectdef(typefilterlist[i]).vmt_mangledname, AT_DATA)))
  414. else
  415. gcc_except_table_data.concat(tai_const.Create_32bit(0));
  416. end;
  417. { the types are resolved by the negative offset, so the label must be written after all types }
  418. gcc_except_table_data.concat(tai_label.create(typefilterlistlabelref));
  419. end;
  420. new_section(gcc_except_table_data,sec_code,'',0);
  421. aktproccode.concatlist(gcc_except_table_data);
  422. end;
  423. end;
  424. end;
  425. procedure tpsabiehprocinfo.start_eh(list: TAsmList);
  426. begin
  427. inherited start_eh(list);
  428. if CreateExceptionTable then
  429. list.insert(tai_label.create(entrycallsitestart));
  430. end;
  431. procedure tpsabiehprocinfo.end_eh(list: TAsmList);
  432. begin
  433. inherited end_eh(list);
  434. if CreateExceptionTable then
  435. begin
  436. CreateNewPSABIEHCallsite(list);
  437. PopLandingPad(CurrentLandingPad);
  438. FinalizeAndPopAction(OutmostLandingPad);
  439. end;
  440. end;
  441. class procedure tpsabiehexceptionstatehandler.get_exception_temps(list: TAsmList; var t: texceptiontemps);
  442. begin
  443. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  444. end;
  445. class procedure tpsabiehexceptionstatehandler.unget_exception_temps(list: TAsmList; const t: texceptiontemps);
  446. begin
  447. tg.ungettemp(list,t.reasonbuf);
  448. (current_procinfo as tpsabiehprocinfo).FinalizeAndPopAction((current_procinfo as tpsabiehprocinfo).CurrentAction);
  449. end;
  450. class procedure tpsabiehexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps;
  451. const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  452. var
  453. reg: tregister;
  454. action: TPSABIEHAction;
  455. begin
  456. exceptstate.oldflowcontrol:=flowcontrol;
  457. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  458. if exceptframekind<>tek_except then
  459. begin
  460. current_asmdata.getjumplabel(exceptstate.finallycodelabel);
  461. action:=TPSABIEHAction.Create(exceptstate.finallycodelabel);
  462. end
  463. else
  464. begin
  465. exceptstate.finallycodelabel:=nil;
  466. action:=TPSABIEHAction.Create(exceptstate.exceptionlabel);
  467. end;
  468. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  469. (current_procinfo as tpsabiehprocinfo).PushAction(action);
  470. (current_procinfo as tpsabiehprocinfo).PushLandingPad(action);
  471. if exceptframekind<>tek_except then
  472. { no safecall? }
  473. if use_cleanup(exceptframekind) then
  474. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil)
  475. else
  476. { if safecall, catch all }
  477. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  478. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  479. if exceptframekind<>tek_except then
  480. begin
  481. reg:=hlcg.getintregister(list,ossinttype);
  482. hlcg.a_load_const_reg(list,ossinttype,1,reg);
  483. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  484. end;
  485. end;
  486. class procedure tpsabiehexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind;
  487. var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps);
  488. begin
  489. hlcg.g_unreachable(list);
  490. hlcg.a_label(list,exceptionstate.exceptionlabel);
  491. if exceptframekind<>tek_except then
  492. begin
  493. if not assigned(exceptionstate.finallycodelabel) then
  494. internalerror(2019021002);
  495. hlcg.a_label(list,exceptionstate.finallycodelabel);
  496. exceptionstate.finallycodelabel:=nil;
  497. exceptiontemps.unwind_info:=cg.getaddressregister(list);
  498. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,exceptiontemps.unwind_info);
  499. end;
  500. end;
  501. class procedure tpsabiehexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps;
  502. var exceptionstate: texceptionstate; endlabel: TAsmLabel);
  503. var
  504. reg: TRegister;
  505. begin
  506. if exceptframekind<>tek_except then
  507. begin
  508. { record that no exception happened in the reason buf, in case we are in a try block of a finally statement }
  509. reg:=hlcg.getintregister(list,ossinttype);
  510. hlcg.a_load_const_reg(list,ossinttype,0,reg);
  511. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  512. end;
  513. inherited;
  514. if exceptframekind=tek_except then
  515. hlcg.a_jmp_always(list,endlabel);
  516. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  517. (current_procinfo as tpsabiehprocinfo).PopLandingPad((current_procinfo as tpsabiehprocinfo).CurrentLandingPad);
  518. end;
  519. class procedure tpsabiehexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint;
  520. endexceptlabel: tasmlabel; onlyfree: boolean);
  521. begin
  522. { nothing to do }
  523. end;
  524. class procedure tpsabiehexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate;
  525. const exceptframekind: texceptframekind);
  526. var
  527. cgpara1: tcgpara;
  528. pd: tprocdef;
  529. action, ReRaiseLandingPad: TPSABIEHAction;
  530. psabiehprocinfo: tpsabiehprocinfo;
  531. begin
  532. if not(fc_catching_exceptions in flowcontrol) and
  533. use_cleanup(exceptframekind) then
  534. begin
  535. { Resume might not be called outside of an landing pad else
  536. the unwind is immediatly terminated, so create an empty landing pad }
  537. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  538. if psabiehprocinfo.landingpadstack.count>1 then
  539. begin
  540. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  541. psabiehprocinfo.PushAction(psabiehprocinfo.NoAction);
  542. psabiehprocinfo.PushLandingPad(psabiehprocinfo.NoAction);
  543. end;
  544. pd:=search_system_proc('_unwind_resume');
  545. cgpara1.init;
  546. paramanager.getintparaloc(list,pd,1,cgpara1);
  547. hlcg.a_load_reg_cgpara(list,voidpointertype,t.unwind_info,cgpara1);
  548. paramanager.freecgpara(list,cgpara1);
  549. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'_unwind_resume',[@cgpara1],nil).resetiftemp;
  550. { we do not have to clean up the stack, we never return }
  551. cgpara1.done;
  552. if psabiehprocinfo.landingpadstack.count>1 then
  553. begin
  554. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  555. psabiehprocinfo.PopLandingPad(psabiehprocinfo.NoAction);
  556. psabiehprocinfo.PopAction(psabiehprocinfo.NoAction);
  557. end;
  558. end
  559. else
  560. begin
  561. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  562. { empty landing pad needed to avoid immediate termination? }
  563. if psabiehprocinfo.landingpadstack.Count=0 then
  564. begin
  565. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  566. ReRaiseLandingPad:=psabiehprocinfo.NoAction;
  567. psabiehprocinfo.PushAction(ReRaiseLandingPad);
  568. psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
  569. end
  570. else
  571. ReRaiseLandingPad:=nil;
  572. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  573. if assigned(ReRaiseLandingPad) then
  574. begin
  575. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  576. psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
  577. psabiehprocinfo.PopAction(ReRaiseLandingPad);
  578. end;
  579. end;
  580. end;
  581. class procedure tpsabiehexceptionstatehandler.begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel;
  582. add_catch: boolean; out exceptlocdef: tdef; out exceptlocreg: tregister);
  583. var
  584. catchstartlab : tasmlabel;
  585. begincatchres,
  586. typeidres,
  587. paraloc1: tcgpara;
  588. pd: tprocdef;
  589. landingpadstructdef,
  590. landingpadtypeiddef: tdef;
  591. rttisym: TAsmSymbol;
  592. rttidef: tdef;
  593. rttiref: treference;
  594. wrappedexception,
  595. exceptiontypeidreg,
  596. landingpadres: tregister;
  597. exceptloc: tlocation;
  598. indirect: boolean;
  599. otherunit: boolean;
  600. typeindex : aint;
  601. begin
  602. paraloc1.init;
  603. rttidef:=nil;
  604. rttisym:=nil;
  605. wrappedexception:=hlcg.getaddressregister(list,voidpointertype);
  606. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,wrappedexception);
  607. if add_catch then
  608. begin
  609. if assigned(excepttype) then
  610. begin
  611. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  612. indirect:=(tf_supports_packages in target_info.flags) and
  613. (target_info.system in systems_indirect_var_imports) and
  614. (cs_imported_data in current_settings.localswitches) and
  615. otherunit;
  616. { add "catch exceptiontype" clause to the landing pad }
  617. rttidef:=cpointerdef.getreusable(excepttype.vmt_def);
  618. rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect);
  619. end;
  620. end;
  621. { check if the exception is handled by this node }
  622. if assigned(excepttype) then
  623. begin
  624. typeindex:=(current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(excepttype);
  625. current_asmdata.getjumplabel(catchstartlab);
  626. {$if defined(i386)}
  627. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab);
  628. {$elseif defined(x86_64)}
  629. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_RDX,catchstartlab);
  630. {$else}
  631. { we need to find a way to fix this in a generic way }
  632. Internalerror(2019021008);
  633. {$endif}
  634. hlcg.a_jmp_always(list,nextonlabel);
  635. hlcg.a_label(list,catchstartlab);
  636. end
  637. else
  638. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  639. pd:=search_system_proc('fpc_psabi_begin_catch');
  640. paramanager.getintparaloc(list, pd, 1, paraloc1);
  641. hlcg.a_load_reg_cgpara(list,voidpointertype,wrappedexception,paraloc1);
  642. begincatchres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  643. location_reset(exceptloc, LOC_REGISTER, def_cgsize(begincatchres.def));
  644. exceptloc.register:=hlcg.getaddressregister(list, begincatchres.def);
  645. hlcg.gen_load_cgpara_loc(list, begincatchres.def, begincatchres, exceptloc, true);
  646. begincatchres.resetiftemp;
  647. paraloc1.done;
  648. exceptlocdef:=begincatchres.def;
  649. exceptlocreg:=exceptloc.register;
  650. end;
  651. class procedure tpsabiehexceptionstatehandler.catch_all_start_internal(list: TAsmList; add_catch: boolean);
  652. var
  653. exceptlocdef: tdef;
  654. exceptlocreg: tregister;
  655. begin
  656. begin_catch_internal(list,nil,nil,add_catch,exceptlocdef,exceptlocreg);
  657. end;
  658. class procedure tpsabiehexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out
  659. exceptlocreg: tregister);
  660. begin
  661. begin_catch_internal(list,excepttype,nextonlabel,true,exceptlocdef,exceptlocreg);
  662. end;
  663. class procedure tpsabiehexceptionstatehandler.end_catch(list: TAsmList);
  664. begin
  665. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  666. inherited;
  667. end;
  668. class procedure tpsabiehexceptionstatehandler.catch_all_start(list: TAsmList);
  669. begin
  670. catch_all_start_internal(list,true);
  671. end;
  672. class procedure tpsabiehexceptionstatehandler.catch_all_add(list: TAsmList);
  673. begin
  674. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil);
  675. end;
  676. class procedure tpsabiehexceptionstatehandler.catch_all_end(list: TAsmList);
  677. begin
  678. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  679. end;
  680. class procedure tpsabiehexceptionstatehandler.cleanupobjectstack(list: TAsmList);
  681. begin
  682. { there is nothing to do }
  683. end;
  684. class procedure tpsabiehexceptionstatehandler.popaddrstack(list: TAsmList);
  685. begin
  686. { there is no addr stack, so do nothing }
  687. end;
  688. end.