psabiehpi.pas 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  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,
  106. parabase,paramgr,
  107. hlcgobj,
  108. pass_2,
  109. ncgflw
  110. {$ifdef i386}
  111. ,aasmcpu
  112. {$endif i386}
  113. ;
  114. type
  115. { Utility class for exception handling state management that is used
  116. by tryexcept/tryfinally/on nodes (in a separate class so it can both
  117. be shared and overridden)
  118. Never instantiated. }
  119. tpsabiehexceptionstatehandler = class(tcgexceptionstatehandler)
  120. protected
  121. class procedure begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; add_catch: boolean; out exceptlocdef: tdef; out
  122. exceptlocreg: tregister);
  123. class procedure catch_all_start_internal(list: TAsmList; add_catch: boolean);
  124. public
  125. class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
  126. class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
  127. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  128. { start of "except/finally" block }
  129. class procedure emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps); override;
  130. { end of a try-block, label comes after the end of try/except or
  131. try/finally }
  132. class procedure end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel); override;
  133. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  134. class procedure handle_reraise(list:TAsmList;const t:texceptiontemps;const entrystate: texceptionstate; const exceptframekind: texceptframekind); override;
  135. { start of an "on" (catch) block }
  136. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  137. { end of an "on" (catch) block }
  138. class procedure end_catch(list: TAsmList); override;
  139. { called for a catch all exception }
  140. class procedure catch_all_start(list: TAsmList); override;
  141. class procedure catch_all_end(list: TAsmList); override;
  142. class procedure catch_all_add(list: TAsmList); override;
  143. class procedure cleanupobjectstack(list: TAsmList); override;
  144. class procedure popaddrstack(list: TAsmList); override;
  145. end;
  146. constructor TPSABIEHAction.Create(pad: TAsmLabel);
  147. begin
  148. landingpad:=pad;
  149. actionlist:=TAsmList.create;
  150. current_asmdata.getlabel(actiontablelabel,alt_data);
  151. actionlist.concat(tai_label.create(actiontablelabel));
  152. first:=true;
  153. end;
  154. destructor TPSABIEHAction.Destroy;
  155. begin
  156. if not(actionlist.Empty) then
  157. Internalerror(2019020501);
  158. actionlist.Free;
  159. inherited Destroy;
  160. end;
  161. function TPSABIEHAction.AddAction(p: tobjectdef) : LongInt;
  162. var
  163. index: LongInt;
  164. begin
  165. { if not first entry, signal that another action follows }
  166. if not(first) then
  167. actionlist.concat(tai_const.Create_uleb128bit(1));
  168. first:=false;
  169. { catch all? }
  170. if p=tobjectdef(-1) then
  171. index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(nil)
  172. else if assigned(p) then
  173. index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(p)
  174. else
  175. index:=-1;
  176. {$ifdef debug_eh}
  177. if p=tobjectdef(-1) then
  178. actionlist.concat(tai_comment.Create(strpnew('Catch all')))
  179. else if assigned(p) then
  180. actionlist.concat(tai_comment.Create(strpnew('Action for '+p.GetTypeName)))
  181. else
  182. actionlist.concat(tai_comment.Create(strpnew('Cleanup')));
  183. {$endif debug_eh}
  184. if assigned(p) then
  185. actionlist.concat(tai_const.Create_uleb128bit(index+1))
  186. else
  187. actionlist.concat(tai_const.Create_uleb128bit(0));
  188. Result:=index;
  189. end;
  190. {****************************************************************************
  191. tpsabiehprocinfo
  192. ****************************************************************************}
  193. destructor tpsabiehprocinfo.destroy;
  194. begin
  195. gcc_except_table_data.free;
  196. actionstack.free;
  197. landingpadstack.free;
  198. typefilterlist.free;
  199. callsite_table_data.Free;
  200. action_table_data.Free;
  201. inherited;
  202. end;
  203. procedure tpsabiehprocinfo.PushAction(action: TPSABIEHAction);
  204. begin
  205. actionstack.add(action);
  206. end;
  207. function tpsabiehprocinfo.PopAction(action: TPSABIEHAction): boolean;
  208. begin
  209. if CurrentAction<>action then
  210. internalerror(2019022501);
  211. actionstack.count:=actionstack.count-1;
  212. result:=actionstack.count=0;
  213. end;
  214. function tpsabiehprocinfo.FinalizeAndPopAction(action: TPSABIEHAction): boolean;
  215. var
  216. curpos: tasmlabel;
  217. begin
  218. include(flags,pi_has_except_table_data);
  219. if CurrentAction<>action then
  220. internalerror(2019021006);
  221. { no further actions follow, finalize table
  222. we check for >1 as the outmost landing pad has no action, so
  223. we can ignore it }
  224. if landingpadstack.count>1 then
  225. begin
  226. current_asmdata.getlabel(curpos,alt_data);
  227. action.actionlist.concat(tai_label.create(curpos));
  228. action.actionlist.concat(tai_const.Create_rel_sym(aitconst_sleb128bit,curpos,TPSABIEHAction(landingpadstack[landingpadstack.count-1]).actiontablelabel));
  229. end
  230. else
  231. action.actionlist.concat(tai_const.Create_uleb128bit(0));
  232. action_table_data.concatList(action.actionlist);
  233. actionstack.count:=actionstack.count-1;
  234. result:=actionstack.count=0;
  235. end;
  236. procedure tpsabiehprocinfo.PushLandingPad(action: TPSABIEHAction);
  237. begin
  238. landingpadstack.add(action);
  239. end;
  240. function tpsabiehprocinfo.CurrentLandingPad: TPSABIEHAction;
  241. begin
  242. result:=TPSABIEHAction(landingpadstack.last);
  243. end;
  244. function tpsabiehprocinfo.PopLandingPad(action: TPSABIEHAction): boolean;
  245. begin
  246. if CurrentLandingPad<>action then
  247. internalerror(2019021007);
  248. landingpadstack.count:=landingpadstack.count-1;
  249. result:=landingpadstack.count=0;
  250. end;
  251. procedure tpsabiehprocinfo.CreateNewPSABIEHCallsite(list : TAsmList);
  252. var
  253. callsiteend : TAsmLabel;
  254. begin
  255. include(flags,pi_has_except_table_data);
  256. { first, finish last entry }
  257. if assigned(callsitelaststart) and assigned(CurrentLandingPad) then
  258. begin
  259. {$ifdef debug_eh}
  260. if assigned(CurrentLandingPad.actiontablelabel) then
  261. callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))))
  262. else
  263. callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', no action')));
  264. {$endif debug_eh}
  265. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,TDwarfAsmCFI(current_asmdata.AsmCFI).get_frame_start,callsitelaststart));
  266. current_asmdata.getlabel(callsiteend,alt_eh_end);
  267. list.concat(tai_label.create(callsiteend));
  268. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitelaststart,callsiteend));
  269. { landing pad? }
  270. if assigned(CurrentLandingPad.landingpad) then
  271. callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,TDwarfAsmCFI(current_asmdata.AsmCFI).get_frame_start,CurrentLandingPad.landingpad))
  272. else
  273. callsite_table_data.concat(tai_const.Create_uleb128bit(0));
  274. { action number set? if yes, concat }
  275. if assigned(CurrentLandingPad.actiontablelabel) then
  276. begin
  277. callsite_table_data.concat(tai_const.Create_rel_sym_offset(aitconst_uleb128bit,callsitetableend,CurrentLandingPad.actiontablelabel,1));
  278. {$ifdef debug_eh}
  279. list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))));
  280. {$endif debug_eh}
  281. end
  282. else
  283. begin
  284. callsite_table_data.concat(tai_const.Create_uleb128bit(0));
  285. {$ifdef debug_eh}
  286. list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', no action')));
  287. {$endif debug_eh}
  288. end;
  289. current_asmdata.getlabel(callsitelaststart,alt_eh_begin);
  290. list.concat(tai_label.create(callsitelaststart));
  291. end
  292. else
  293. begin
  294. current_asmdata.getlabel(entrycallsitestart,alt_eh_begin);
  295. callsitelaststart:=entrycallsitestart
  296. end;
  297. Inc(CurrentCallSiteNumber);
  298. end;
  299. function tpsabiehprocinfo.AddTypeFilter(p: tobjectdef) : Longint;
  300. var
  301. i: Integer;
  302. begin
  303. for i:=0 to typefilterlist.count-1 do
  304. begin
  305. if tobjectdef(typefilterlist[i])=p then
  306. begin
  307. result:=i;
  308. exit;
  309. end;
  310. end;
  311. result:=typefilterlist.add(p);
  312. end;
  313. procedure tpsabiehprocinfo.set_eh_info;
  314. begin
  315. inherited set_eh_info;
  316. if (tf_use_psabieh in target_info.flags) and not(pi_has_except_table_data in flags) then
  317. (current_asmdata.AsmCFI as TDwarfAsmCFI).LSDALabel:=nil;
  318. end;
  319. function tpsabiehprocinfo.CurrentAction: TPSABIEHAction; inline;
  320. begin
  321. result:=TPSABIEHAction(actionstack.last);
  322. end;
  323. function tpsabiehprocinfo.find_exception_handling(var n: tnode; para: pointer): foreachnoderesult;
  324. begin
  325. if n.nodetype in [tryfinallyn,tryexceptn,raisen,onn] then
  326. Result:=fen_norecurse_true
  327. else
  328. Result:=fen_false;
  329. end;
  330. procedure tpsabiehprocinfo.setup_eh;
  331. var
  332. gcc_except_table: tai_section;
  333. begin
  334. if tf_use_psabieh in target_info.flags then
  335. begin
  336. CreateExceptionTable:=foreachnode(code,@find_exception_handling,nil);
  337. gcc_except_table_data:=TAsmList.Create;
  338. callsite_table_data:=TAsmList.Create;
  339. action_table_data:=TAsmList.Create;
  340. actionstack:=TFPList.Create;
  341. landingpadstack:=TFPList.Create;
  342. typefilterlist:=TFPList.Create;
  343. gcc_except_table:=new_section(gcc_except_table_data,sec_gcc_except_table,'',0);
  344. gcc_except_table.secflags:=SF_A;
  345. gcc_except_table.secprogbits:=SPB_PROGBITS;
  346. if not(current_asmdata.AsmCFI is TDwarfAsmCFI) then
  347. internalerror(2019021003);
  348. {$ifdef debug_eh}
  349. gcc_except_table_data.concat(tai_comment.Create(strpnew('gcc_except_table for '+procdef.fullprocname(true))));
  350. {$endif debug_eh}
  351. current_asmdata.getlabel(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel,alt_data);
  352. current_asmdata.getlabel(callsitetablestart,alt_data);
  353. current_asmdata.getlabel(callsitetableend,alt_data);
  354. callsite_table_data.concat(tai_label.create(callsitetablestart));
  355. cexceptionstatehandler:=tpsabiehexceptionstatehandler;
  356. if CreateExceptionTable then
  357. begin
  358. CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
  359. OutmostLandingPad:=TPSABIEHAction.Create(nil);
  360. NoAction:=OutmostLandingPad;
  361. PushAction(OutmostLandingPad);
  362. PushLandingPad(OutmostLandingPad);
  363. OutmostLandingPad.AddAction(nil);
  364. end;
  365. end;
  366. end;
  367. procedure tpsabiehprocinfo.finish_eh;
  368. var
  369. i: Integer;
  370. begin
  371. if tf_use_psabieh in target_info.flags then
  372. begin
  373. if pi_has_except_table_data in flags then
  374. begin
  375. gcc_except_table_data.concat(tai_label.create(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel));
  376. { landing pad base is relative to procedure start, so write an omit }
  377. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  378. if typefilterlist.count>0 then
  379. begin
  380. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata4));
  381. current_asmdata.getlabel(typefilterlistlabel,alt_data);
  382. current_asmdata.getlabel(typefilterlistlabelref,alt_data);
  383. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,typefilterlistlabel,typefilterlistlabelref));
  384. gcc_except_table_data.concat(tai_label.create(typefilterlistlabel));
  385. end
  386. else
  387. { default types table encoding }
  388. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  389. { call-site table encoded using uleb128 }
  390. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_uleb128));
  391. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitetablestart,callsitetableend));
  392. callsite_table_data.concat(tai_label.create(callsitetableend));
  393. {$ifdef debug_eh}
  394. gcc_except_table_data.concat(tai_comment.Create(strpnew('Call site table for '+procdef.fullprocname(true))));
  395. {$endif debug_eh}
  396. gcc_except_table_data.concatList(callsite_table_data);
  397. { action table must follow immediatly after callsite table }
  398. {$ifdef debug_eh}
  399. if not(action_table_data.Empty) then
  400. gcc_except_table_data.concat(tai_comment.Create(strpnew('Action table for '+procdef.fullprocname(true))));
  401. {$endif debug_eh}
  402. gcc_except_table_data.concatlist(action_table_data);
  403. if typefilterlist.count>0 then
  404. begin
  405. {$ifdef debug_eh}
  406. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter list for '+procdef.fullprocname(true))));
  407. {$endif debug_eh}
  408. for i:=typefilterlist.count-1 downto 0 do
  409. begin
  410. {$ifdef debug_eh}
  411. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter '+tostr(i))));
  412. {$endif debug_eh}
  413. if assigned(typefilterlist[i]) then
  414. gcc_except_table_data.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(tobjectdef(typefilterlist[i]).vmt_mangledname, AT_DATA)))
  415. else
  416. gcc_except_table_data.concat(tai_const.Create_32bit(0));
  417. end;
  418. { the types are resolved by the negative offset, so the label must be written after all types }
  419. gcc_except_table_data.concat(tai_label.create(typefilterlistlabelref));
  420. end;
  421. new_section(gcc_except_table_data,sec_code,'',0);
  422. aktproccode.concatlist(gcc_except_table_data);
  423. end;
  424. end;
  425. end;
  426. procedure tpsabiehprocinfo.start_eh(list: TAsmList);
  427. begin
  428. inherited start_eh(list);
  429. if CreateExceptionTable then
  430. list.insert(tai_label.create(entrycallsitestart));
  431. end;
  432. procedure tpsabiehprocinfo.end_eh(list: TAsmList);
  433. begin
  434. inherited end_eh(list);
  435. if CreateExceptionTable then
  436. begin
  437. CreateNewPSABIEHCallsite(list);
  438. PopLandingPad(CurrentLandingPad);
  439. FinalizeAndPopAction(OutmostLandingPad);
  440. end;
  441. end;
  442. class procedure tpsabiehexceptionstatehandler.get_exception_temps(list: TAsmList; var t: texceptiontemps);
  443. begin
  444. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  445. end;
  446. class procedure tpsabiehexceptionstatehandler.unget_exception_temps(list: TAsmList; const t: texceptiontemps);
  447. begin
  448. tg.ungettemp(list,t.reasonbuf);
  449. (current_procinfo as tpsabiehprocinfo).FinalizeAndPopAction((current_procinfo as tpsabiehprocinfo).CurrentAction);
  450. end;
  451. class procedure tpsabiehexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps;
  452. const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  453. var
  454. reg: tregister;
  455. action: TPSABIEHAction;
  456. begin
  457. exceptstate.oldflowcontrol:=flowcontrol;
  458. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  459. if exceptframekind<>tek_except then
  460. begin
  461. current_asmdata.getjumplabel(exceptstate.finallycodelabel);
  462. action:=TPSABIEHAction.Create(exceptstate.finallycodelabel);
  463. end
  464. else
  465. begin
  466. exceptstate.finallycodelabel:=nil;
  467. action:=TPSABIEHAction.Create(exceptstate.exceptionlabel);
  468. end;
  469. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  470. (current_procinfo as tpsabiehprocinfo).PushAction(action);
  471. (current_procinfo as tpsabiehprocinfo).PushLandingPad(action);
  472. if exceptframekind<>tek_except then
  473. { no safecall? }
  474. if use_cleanup(exceptframekind) then
  475. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil)
  476. else
  477. { if safecall, catch all }
  478. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  479. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  480. if exceptframekind<>tek_except then
  481. begin
  482. reg:=hlcg.getintregister(list,ossinttype);
  483. hlcg.a_load_const_reg(list,ossinttype,1,reg);
  484. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  485. end;
  486. end;
  487. class procedure tpsabiehexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind;
  488. var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps);
  489. begin
  490. hlcg.g_unreachable(list);
  491. hlcg.a_label(list,exceptionstate.exceptionlabel);
  492. if exceptframekind<>tek_except then
  493. begin
  494. if not assigned(exceptionstate.finallycodelabel) then
  495. internalerror(2019021002);
  496. hlcg.a_label(list,exceptionstate.finallycodelabel);
  497. exceptionstate.finallycodelabel:=nil;
  498. exceptiontemps.unwind_info:=cg.getaddressregister(list);
  499. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,exceptiontemps.unwind_info);
  500. end;
  501. end;
  502. class procedure tpsabiehexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps;
  503. var exceptionstate: texceptionstate; endlabel: TAsmLabel);
  504. var
  505. reg: TRegister;
  506. begin
  507. if exceptframekind<>tek_except then
  508. begin
  509. { record that no exception happened in the reason buf, in case we are in a try block of a finally statement }
  510. reg:=hlcg.getintregister(list,ossinttype);
  511. hlcg.a_load_const_reg(list,ossinttype,0,reg);
  512. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  513. end;
  514. inherited;
  515. if exceptframekind=tek_except then
  516. hlcg.a_jmp_always(list,endlabel);
  517. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  518. (current_procinfo as tpsabiehprocinfo).PopLandingPad((current_procinfo as tpsabiehprocinfo).CurrentLandingPad);
  519. end;
  520. class procedure tpsabiehexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint;
  521. endexceptlabel: tasmlabel; onlyfree: boolean);
  522. begin
  523. { nothing to do }
  524. end;
  525. class procedure tpsabiehexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate;
  526. const exceptframekind: texceptframekind);
  527. var
  528. cgpara1: tcgpara;
  529. pd: tprocdef;
  530. action, ReRaiseLandingPad: TPSABIEHAction;
  531. psabiehprocinfo: tpsabiehprocinfo;
  532. begin
  533. if not(fc_catching_exceptions in flowcontrol) and
  534. use_cleanup(exceptframekind) then
  535. begin
  536. { Resume might not be called outside of an landing pad else
  537. the unwind is immediatly terminated, so create an empty landing pad }
  538. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  539. if psabiehprocinfo.landingpadstack.count>1 then
  540. begin
  541. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  542. psabiehprocinfo.PushAction(psabiehprocinfo.NoAction);
  543. psabiehprocinfo.PushLandingPad(psabiehprocinfo.NoAction);
  544. end;
  545. pd:=search_system_proc('_unwind_resume');
  546. cgpara1.init;
  547. paramanager.getintparaloc(list,pd,1,cgpara1);
  548. hlcg.a_load_reg_cgpara(list,voidpointertype,t.unwind_info,cgpara1);
  549. paramanager.freecgpara(list,cgpara1);
  550. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'_unwind_resume',[@cgpara1],nil).resetiftemp;
  551. { we do not have to clean up the stack, we never return }
  552. cgpara1.done;
  553. if psabiehprocinfo.landingpadstack.count>1 then
  554. begin
  555. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  556. psabiehprocinfo.PopLandingPad(psabiehprocinfo.NoAction);
  557. psabiehprocinfo.PopAction(psabiehprocinfo.NoAction);
  558. end;
  559. end
  560. else
  561. begin
  562. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  563. { empty landing pad needed to avoid immediate termination? }
  564. if psabiehprocinfo.landingpadstack.Count=0 then
  565. begin
  566. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  567. ReRaiseLandingPad:=psabiehprocinfo.NoAction;
  568. psabiehprocinfo.PushAction(ReRaiseLandingPad);
  569. psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
  570. end
  571. else
  572. ReRaiseLandingPad:=nil;
  573. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  574. if assigned(ReRaiseLandingPad) then
  575. begin
  576. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  577. psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
  578. psabiehprocinfo.PopAction(ReRaiseLandingPad);
  579. end;
  580. end;
  581. end;
  582. class procedure tpsabiehexceptionstatehandler.begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel;
  583. add_catch: boolean; out exceptlocdef: tdef; out exceptlocreg: tregister);
  584. var
  585. catchstartlab : tasmlabel;
  586. begincatchres,
  587. typeidres,
  588. paraloc1: tcgpara;
  589. pd: tprocdef;
  590. landingpadstructdef,
  591. landingpadtypeiddef: tdef;
  592. rttisym: TAsmSymbol;
  593. rttidef: tdef;
  594. rttiref: treference;
  595. wrappedexception,
  596. exceptiontypeidreg,
  597. landingpadres: tregister;
  598. exceptloc: tlocation;
  599. indirect: boolean;
  600. otherunit: boolean;
  601. typeindex : aint;
  602. begin
  603. paraloc1.init;
  604. rttidef:=nil;
  605. rttisym:=nil;
  606. wrappedexception:=hlcg.getaddressregister(list,voidpointertype);
  607. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,wrappedexception);
  608. if add_catch then
  609. begin
  610. if assigned(excepttype) then
  611. begin
  612. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  613. indirect:=(tf_supports_packages in target_info.flags) and
  614. (target_info.system in systems_indirect_var_imports) and
  615. (cs_imported_data in current_settings.localswitches) and
  616. otherunit;
  617. { add "catch exceptiontype" clause to the landing pad }
  618. rttidef:=cpointerdef.getreusable(excepttype.vmt_def);
  619. rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect);
  620. end;
  621. end;
  622. { check if the exception is handled by this node }
  623. if assigned(excepttype) then
  624. begin
  625. typeindex:=(current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(excepttype);
  626. current_asmdata.getjumplabel(catchstartlab);
  627. {$if defined(i386)}
  628. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab);
  629. {$elseif defined(x86_64)}
  630. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_RDX,catchstartlab);
  631. {$else}
  632. { we need to find a way to fix this in a generic way }
  633. Internalerror(2019021008);
  634. {$endif}
  635. hlcg.a_jmp_always(list,nextonlabel);
  636. hlcg.a_label(list,catchstartlab);
  637. end
  638. else
  639. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  640. pd:=search_system_proc('fpc_psabi_begin_catch');
  641. paramanager.getintparaloc(list, pd, 1, paraloc1);
  642. hlcg.a_load_reg_cgpara(list,voidpointertype,wrappedexception,paraloc1);
  643. begincatchres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  644. location_reset(exceptloc, LOC_REGISTER, def_cgsize(begincatchres.def));
  645. exceptloc.register:=hlcg.getaddressregister(list, begincatchres.def);
  646. hlcg.gen_load_cgpara_loc(list, begincatchres.def, begincatchres, exceptloc, true);
  647. begincatchres.resetiftemp;
  648. paraloc1.done;
  649. exceptlocdef:=begincatchres.def;
  650. exceptlocreg:=exceptloc.register;
  651. end;
  652. class procedure tpsabiehexceptionstatehandler.catch_all_start_internal(list: TAsmList; add_catch: boolean);
  653. var
  654. exceptlocdef: tdef;
  655. exceptlocreg: tregister;
  656. begin
  657. begin_catch_internal(list,nil,nil,add_catch,exceptlocdef,exceptlocreg);
  658. end;
  659. class procedure tpsabiehexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out
  660. exceptlocreg: tregister);
  661. begin
  662. begin_catch_internal(list,excepttype,nextonlabel,true,exceptlocdef,exceptlocreg);
  663. end;
  664. class procedure tpsabiehexceptionstatehandler.end_catch(list: TAsmList);
  665. begin
  666. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  667. inherited;
  668. end;
  669. class procedure tpsabiehexceptionstatehandler.catch_all_start(list: TAsmList);
  670. begin
  671. catch_all_start_internal(list,true);
  672. end;
  673. class procedure tpsabiehexceptionstatehandler.catch_all_add(list: TAsmList);
  674. begin
  675. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil);
  676. end;
  677. class procedure tpsabiehexceptionstatehandler.catch_all_end(list: TAsmList);
  678. begin
  679. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  680. end;
  681. class procedure tpsabiehexceptionstatehandler.cleanupobjectstack(list: TAsmList);
  682. begin
  683. { there is nothing to do }
  684. end;
  685. class procedure tpsabiehexceptionstatehandler.popaddrstack(list: TAsmList);
  686. begin
  687. { there is no addr stack, so do nothing }
  688. end;
  689. end.