psabiehpi.pas 32 KB

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