psabiehpi.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  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. CreateExceptionTable:=foreachnode(code,@find_exception_handling,nil);
  335. gcc_except_table_data:=TAsmList.Create;
  336. callsite_table_data:=TAsmList.Create;
  337. action_table_data:=TAsmList.Create;
  338. actionstack:=TFPList.Create;
  339. landingpadstack:=TFPList.Create;
  340. typefilterlist:=TFPList.Create;
  341. gcc_except_table:=new_section(gcc_except_table_data,sec_gcc_except_table,'',0);
  342. gcc_except_table.secflags:=SF_A;
  343. gcc_except_table.secprogbits:=SPB_PROGBITS;
  344. if not(current_asmdata.AsmCFI is TDwarfAsmCFI) then
  345. internalerror(2019021003);
  346. {$ifdef debug_eh}
  347. gcc_except_table_data.concat(tai_comment.Create(strpnew('gcc_except_table for '+procdef.fullprocname(true))));
  348. {$endif debug_eh}
  349. current_asmdata.getlabel(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel,alt_data);
  350. current_asmdata.getlabel(callsitetablestart,alt_data);
  351. current_asmdata.getlabel(callsitetableend,alt_data);
  352. callsite_table_data.concat(tai_label.create(callsitetablestart));
  353. cexceptionstatehandler:=tpsabiehexceptionstatehandler;
  354. if CreateExceptionTable then
  355. begin
  356. CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
  357. OutmostLandingPad:=TPSABIEHAction.Create(nil);
  358. NoAction:=OutmostLandingPad;
  359. PushAction(OutmostLandingPad);
  360. PushLandingPad(OutmostLandingPad);
  361. OutmostLandingPad.AddAction(nil);
  362. end;
  363. end;
  364. procedure tpsabiehprocinfo.finish_eh;
  365. var
  366. i: Integer;
  367. begin
  368. if (tf_use_psabieh in target_info.flags) then
  369. begin
  370. if pi_has_except_table_data in flags then
  371. begin
  372. gcc_except_table_data.concat(tai_label.create(TDwarfAsmCFI(current_asmdata.AsmCFI).LSDALabel));
  373. { landing pad base is relative to procedure start, so write an omit }
  374. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  375. if typefilterlist.count>0 then
  376. begin
  377. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata4));
  378. current_asmdata.getlabel(typefilterlistlabel,alt_data);
  379. current_asmdata.getlabel(typefilterlistlabelref,alt_data);
  380. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,typefilterlistlabel,typefilterlistlabelref));
  381. gcc_except_table_data.concat(tai_label.create(typefilterlistlabel));
  382. end
  383. else
  384. { default types table encoding }
  385. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
  386. { call-site table encoded using uleb128 }
  387. gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_uleb128));
  388. gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitetablestart,callsitetableend));
  389. callsite_table_data.concat(tai_label.create(callsitetableend));
  390. {$ifdef debug_eh}
  391. gcc_except_table_data.concat(tai_comment.Create(strpnew('Call site table for '+procdef.fullprocname(true))));
  392. {$endif debug_eh}
  393. gcc_except_table_data.concatList(callsite_table_data);
  394. { action table must follow immediatly after callsite table }
  395. {$ifdef debug_eh}
  396. if not(action_table_data.Empty) then
  397. gcc_except_table_data.concat(tai_comment.Create(strpnew('Action table for '+procdef.fullprocname(true))));
  398. {$endif debug_eh}
  399. gcc_except_table_data.concatlist(action_table_data);
  400. if typefilterlist.count>0 then
  401. begin
  402. {$ifdef debug_eh}
  403. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter list for '+procdef.fullprocname(true))));
  404. {$endif debug_eh}
  405. for i:=typefilterlist.count-1 downto 0 do
  406. begin
  407. {$ifdef debug_eh}
  408. gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter '+tostr(i))));
  409. {$endif debug_eh}
  410. if assigned(typefilterlist[i]) then
  411. gcc_except_table_data.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(tobjectdef(typefilterlist[i]).vmt_mangledname, AT_DATA)))
  412. else
  413. gcc_except_table_data.concat(tai_const.Create_32bit(0));
  414. end;
  415. { the types are resolved by the negative offset, so the label must be written after all types }
  416. gcc_except_table_data.concat(tai_label.create(typefilterlistlabelref));
  417. end;
  418. new_section(gcc_except_table_data,sec_code,'',0);
  419. aktproccode.concatlist(gcc_except_table_data);
  420. end;
  421. end;
  422. end;
  423. procedure tpsabiehprocinfo.start_eh(list: TAsmList);
  424. begin
  425. inherited start_eh(list);
  426. if CreateExceptionTable then
  427. list.insert(tai_label.create(entrycallsitestart));
  428. end;
  429. procedure tpsabiehprocinfo.end_eh(list: TAsmList);
  430. begin
  431. inherited end_eh(list);
  432. if CreateExceptionTable then
  433. begin
  434. CreateNewPSABIEHCallsite(list);
  435. PopLandingPad(CurrentLandingPad);
  436. FinalizeAndPopAction(OutmostLandingPad);
  437. end;
  438. end;
  439. class procedure tpsabiehexceptionstatehandler.get_exception_temps(list: TAsmList; var t: texceptiontemps);
  440. begin
  441. tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
  442. end;
  443. class procedure tpsabiehexceptionstatehandler.unget_exception_temps(list: TAsmList; const t: texceptiontemps);
  444. begin
  445. tg.ungettemp(list,t.reasonbuf);
  446. (current_procinfo as tpsabiehprocinfo).FinalizeAndPopAction((current_procinfo as tpsabiehprocinfo).CurrentAction);
  447. end;
  448. class procedure tpsabiehexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps;
  449. const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  450. var
  451. reg: tregister;
  452. action: TPSABIEHAction;
  453. begin
  454. exceptstate.oldflowcontrol:=flowcontrol;
  455. current_asmdata.getjumplabel(exceptstate.exceptionlabel);
  456. if exceptframekind<>tek_except then
  457. begin
  458. current_asmdata.getjumplabel(exceptstate.finallycodelabel);
  459. action:=TPSABIEHAction.Create(exceptstate.finallycodelabel);
  460. end
  461. else
  462. begin
  463. exceptstate.finallycodelabel:=nil;
  464. action:=TPSABIEHAction.Create(exceptstate.exceptionlabel);
  465. end;
  466. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  467. (current_procinfo as tpsabiehprocinfo).PushAction(action);
  468. (current_procinfo as tpsabiehprocinfo).PushLandingPad(action);
  469. if exceptframekind<>tek_except then
  470. { no safecall? }
  471. if use_cleanup(exceptframekind) then
  472. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil)
  473. else
  474. { if safecall, catch all }
  475. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  476. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  477. if exceptframekind<>tek_except then
  478. begin
  479. reg:=hlcg.getintregister(list,ossinttype);
  480. hlcg.a_load_const_reg(list,ossinttype,1,reg);
  481. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  482. end;
  483. end;
  484. class procedure tpsabiehexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind;
  485. var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps);
  486. begin
  487. hlcg.g_unreachable(list);
  488. hlcg.a_label(list,exceptionstate.exceptionlabel);
  489. if exceptframekind<>tek_except then
  490. begin
  491. if not assigned(exceptionstate.finallycodelabel) then
  492. internalerror(2019021002);
  493. hlcg.a_label(list,exceptionstate.finallycodelabel);
  494. exceptionstate.finallycodelabel:=nil;
  495. exceptiontemps.unwind_info:=cg.getaddressregister(list);
  496. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,exceptiontemps.unwind_info);
  497. end;
  498. end;
  499. class procedure tpsabiehexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps;
  500. var exceptionstate: texceptionstate; endlabel: TAsmLabel);
  501. var
  502. reg: TRegister;
  503. begin
  504. if exceptframekind<>tek_except then
  505. begin
  506. { record that no exception happened in the reason buf, in case we are in a try block of a finally statement }
  507. reg:=hlcg.getintregister(list,ossinttype);
  508. hlcg.a_load_const_reg(list,ossinttype,0,reg);
  509. hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
  510. end;
  511. inherited;
  512. if exceptframekind=tek_except then
  513. hlcg.a_jmp_always(list,endlabel);
  514. (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
  515. (current_procinfo as tpsabiehprocinfo).PopLandingPad((current_procinfo as tpsabiehprocinfo).CurrentLandingPad);
  516. end;
  517. class procedure tpsabiehexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint;
  518. endexceptlabel: tasmlabel; onlyfree: boolean);
  519. begin
  520. { nothing to do }
  521. end;
  522. class procedure tpsabiehexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate;
  523. const exceptframekind: texceptframekind);
  524. var
  525. cgpara1: tcgpara;
  526. pd: tprocdef;
  527. action, ReRaiseLandingPad: TPSABIEHAction;
  528. psabiehprocinfo: tpsabiehprocinfo;
  529. begin
  530. if not(fc_catching_exceptions in flowcontrol) and
  531. use_cleanup(exceptframekind) then
  532. begin
  533. { Resume might not be called outside of an landing pad else
  534. the unwind is immediatly terminated, so create an empty landing pad }
  535. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  536. if psabiehprocinfo.landingpadstack.count>1 then
  537. begin
  538. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  539. psabiehprocinfo.PushAction(psabiehprocinfo.NoAction);
  540. psabiehprocinfo.PushLandingPad(psabiehprocinfo.NoAction);
  541. end;
  542. pd:=search_system_proc('_unwind_resume');
  543. cgpara1.init;
  544. paramanager.getintparaloc(list,pd,1,cgpara1);
  545. hlcg.a_load_reg_cgpara(list,voidpointertype,t.unwind_info,cgpara1);
  546. paramanager.freecgpara(list,cgpara1);
  547. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'_unwind_resume',[@cgpara1],nil).resetiftemp;
  548. { we do not have to clean up the stack, we never return }
  549. cgpara1.done;
  550. if psabiehprocinfo.landingpadstack.count>1 then
  551. begin
  552. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  553. psabiehprocinfo.PopLandingPad(psabiehprocinfo.NoAction);
  554. psabiehprocinfo.PopAction(psabiehprocinfo.NoAction);
  555. end;
  556. end
  557. else
  558. begin
  559. psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
  560. { empty landing pad needed to avoid immediate termination? }
  561. if psabiehprocinfo.landingpadstack.Count=0 then
  562. begin
  563. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  564. ReRaiseLandingPad:=psabiehprocinfo.NoAction;
  565. psabiehprocinfo.PushAction(ReRaiseLandingPad);
  566. psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
  567. end
  568. else
  569. ReRaiseLandingPad:=nil;
  570. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
  571. if assigned(ReRaiseLandingPad) then
  572. begin
  573. psabiehprocinfo.CreateNewPSABIEHCallsite(list);
  574. psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
  575. psabiehprocinfo.PopAction(ReRaiseLandingPad);
  576. end;
  577. end;
  578. end;
  579. class procedure tpsabiehexceptionstatehandler.begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel;
  580. add_catch: boolean; out exceptlocdef: tdef; out exceptlocreg: tregister);
  581. var
  582. catchstartlab : tasmlabel;
  583. begincatchres,
  584. typeidres,
  585. paraloc1: tcgpara;
  586. pd: tprocdef;
  587. landingpadstructdef,
  588. landingpadtypeiddef: tdef;
  589. rttisym: TAsmSymbol;
  590. rttidef: tdef;
  591. rttiref: treference;
  592. wrappedexception,
  593. exceptiontypeidreg,
  594. landingpadres: tregister;
  595. exceptloc: tlocation;
  596. indirect: boolean;
  597. otherunit: boolean;
  598. typeindex : aint;
  599. begin
  600. paraloc1.init;
  601. rttidef:=nil;
  602. rttisym:=nil;
  603. wrappedexception:=hlcg.getaddressregister(list,voidpointertype);
  604. hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,wrappedexception);
  605. if add_catch then
  606. begin
  607. if assigned(excepttype) then
  608. begin
  609. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  610. indirect:=(tf_supports_packages in target_info.flags) and
  611. (target_info.system in systems_indirect_var_imports) and
  612. (cs_imported_data in current_settings.localswitches) and
  613. otherunit;
  614. { add "catch exceptiontype" clause to the landing pad }
  615. rttidef:=cpointerdef.getreusable(excepttype.vmt_def);
  616. rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect);
  617. end;
  618. end;
  619. { check if the exception is handled by this node }
  620. if assigned(excepttype) then
  621. begin
  622. typeindex:=(current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(excepttype);
  623. current_asmdata.getjumplabel(catchstartlab);
  624. {$if defined(i386)}
  625. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab);
  626. {$elseif defined(x86_64)}
  627. hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_RDX,catchstartlab);
  628. {$else}
  629. { we need to find a way to fix this in a generic way }
  630. Internalerror(2019021008);
  631. {$endif}
  632. hlcg.a_jmp_always(list,nextonlabel);
  633. hlcg.a_label(list,catchstartlab);
  634. end
  635. else
  636. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
  637. pd:=search_system_proc('fpc_psabi_begin_catch');
  638. paramanager.getintparaloc(list, pd, 1, paraloc1);
  639. hlcg.a_load_reg_cgpara(list,voidpointertype,wrappedexception,paraloc1);
  640. begincatchres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
  641. location_reset(exceptloc, LOC_REGISTER, def_cgsize(begincatchres.def));
  642. exceptloc.register:=hlcg.getaddressregister(list, begincatchres.def);
  643. hlcg.gen_load_cgpara_loc(list, begincatchres.def, begincatchres, exceptloc, true);
  644. begincatchres.resetiftemp;
  645. paraloc1.done;
  646. exceptlocdef:=begincatchres.def;
  647. exceptlocreg:=exceptloc.register;
  648. end;
  649. class procedure tpsabiehexceptionstatehandler.catch_all_start_internal(list: TAsmList; add_catch: boolean);
  650. var
  651. exceptlocdef: tdef;
  652. exceptlocreg: tregister;
  653. begin
  654. begin_catch_internal(list,nil,nil,add_catch,exceptlocdef,exceptlocreg);
  655. end;
  656. class procedure tpsabiehexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out
  657. exceptlocreg: tregister);
  658. begin
  659. begin_catch_internal(list,excepttype,nextonlabel,true,exceptlocdef,exceptlocreg);
  660. end;
  661. class procedure tpsabiehexceptionstatehandler.end_catch(list: TAsmList);
  662. begin
  663. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  664. inherited;
  665. end;
  666. class procedure tpsabiehexceptionstatehandler.catch_all_start(list: TAsmList);
  667. begin
  668. catch_all_start_internal(list,true);
  669. end;
  670. class procedure tpsabiehexceptionstatehandler.catch_all_add(list: TAsmList);
  671. begin
  672. (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil);
  673. end;
  674. class procedure tpsabiehexceptionstatehandler.catch_all_end(list: TAsmList);
  675. begin
  676. hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
  677. end;
  678. class procedure tpsabiehexceptionstatehandler.cleanupobjectstack(list: TAsmList);
  679. begin
  680. { there is nothing to do }
  681. end;
  682. class procedure tpsabiehexceptionstatehandler.popaddrstack(list: TAsmList);
  683. begin
  684. { there is no addr stack, so do nothing }
  685. end;
  686. end.