mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-10-31 21:29:41 +01:00 
			
		
		
		
	 fe57cd3536
			
		
	
	
		fe57cd3536
		
	
	
	
	
		
			
			* global gotos really use the return type of fpc_setjmp to test where we come from git-svn-id: trunk@48835 -
		
			
				
	
	
		
			816 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			816 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
|     Copyright (c) 1998-2002 by Florian Klaempfl
 | |
| 
 | |
|     Information about the current procedure that is being compiled
 | |
| 
 | |
|     This program is free software; you can redistribute it and/or modify
 | |
|     it under the terms of the GNU General Public License as published by
 | |
|     the Free Software Foundation; either version 2 of the License, or
 | |
|     (at your option) any later version.
 | |
| 
 | |
|     This program is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|     GNU General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU General Public License
 | |
|     along with this program; if not, write to the Free Software
 | |
|     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | |
| 
 | |
|  ****************************************************************************
 | |
| }
 | |
| unit psabiehpi;
 | |
| 
 | |
| { $define debug_eh}
 | |
| 
 | |
| {$i fpcdefs.inc}
 | |
| 
 | |
|   interface
 | |
| 
 | |
|     uses
 | |
|       { common }
 | |
|       cclasses,
 | |
|       { global }
 | |
|       globtype,
 | |
|       { symtable }
 | |
|       symconst,symtype,symdef,symsym,
 | |
|       node,nutils,
 | |
|       { aasm }
 | |
|       cpubase,cgbase,cgutils,
 | |
|       aasmbase,aasmdata,aasmtai,
 | |
|       psub;
 | |
| 
 | |
|     type
 | |
|        TPSABIEHAction = class
 | |
|          landingpad : TAsmLabel;
 | |
|          actiontablelabel : TAsmLabel;
 | |
|          actionlist : TAsmList;
 | |
|          first : boolean;
 | |
|          constructor Create(pad : TAsmLabel);
 | |
|          destructor Destroy; override;
 | |
|          function AddAction(p: tobjectdef): LongInt;
 | |
|        end;
 | |
| 
 | |
|        { This object gives information on the current routine being
 | |
|          compiled.
 | |
|        }
 | |
|        tpsabiehprocinfo = class(tcgprocinfo)
 | |
|          { set if the procedure needs exception tables because it
 | |
|            has exception generating nodes }
 | |
|          CreateExceptionTable: Boolean;
 | |
| 
 | |
|          { if a procedure needs exception tables, this is the outmost landing pad
 | |
|            with "no action", covering everything not covered by other landing pads
 | |
|            since a procedure which has one landing pad need to be covered completely by landing pads }
 | |
|          OutmostLandingPad: TPSABIEHAction;
 | |
| 
 | |
|          { This is a "no action" action for re-use, normally equal to OutmostLandingPad }
 | |
|          NoAction: TPSABIEHAction;
 | |
| 
 | |
|          { label to language specific data }
 | |
|          LSDALabel : TAsmLabel;
 | |
|          callsite_table_data,
 | |
|          action_table_data,
 | |
|          gcc_except_table_data : TAsmList;
 | |
|          typefilterlistlabel,typefilterlistlabelref,
 | |
|          callsitetablestart,callsitetableend,
 | |
|          { first label which must be inserted into the entry code }
 | |
|          entrycallsitestart,
 | |
|          callsitelaststart : TAsmLabel;
 | |
|          typefilterlist,
 | |
|          landingpadstack,
 | |
|          actionstack : tfplist;
 | |
|          CurrentCallSiteNumber : Longint;
 | |
| 
 | |
|          destructor destroy; override;
 | |
| 
 | |
|          { PSABIEH stuff }
 | |
|          procedure PushAction(action: TPSABIEHAction);
 | |
|          function CurrentAction: TPSABIEHAction;inline;
 | |
|          function PopAction(action: TPSABIEHAction): boolean;
 | |
|          function FinalizeAndPopAction(action: TPSABIEHAction): boolean;
 | |
|          { a landing pad is also an action, however, when the landing pad is popped from the stack
 | |
|            the area covered by this landing pad ends, i.e. it is popped at the beginning of the finally/except clause,
 | |
|            the action above is popped at the end of the finally/except clause, so if on clauses add new types, they
 | |
|            are added to CurrentAction }
 | |
|          procedure PushLandingPad(action: TPSABIEHAction);
 | |
|          function CurrentLandingPad: TPSABIEHAction;inline;
 | |
|          function PopLandingPad(action: TPSABIEHAction): boolean;
 | |
|          procedure CreateNewPSABIEHCallsite(list: TAsmList);
 | |
|          { adds a new type to the type filter list and returns its index
 | |
|            be aware, that this method can also handle catch all filters so it
 | |
|            is valid to pass nil }
 | |
|          function AddTypeFilter(p: tobjectdef): Longint;
 | |
|          procedure set_eh_info; override;
 | |
|          procedure setup_eh; override;
 | |
|          procedure finish_eh; override;
 | |
|          procedure start_eh(list : TAsmList); override;
 | |
|          procedure end_eh(list : TAsmList); override;
 | |
| 
 | |
|          function find_exception_handling(var n: tnode; para: pointer): foreachnoderesult; virtual;
 | |
|        end;
 | |
| 
 | |
| implementation
 | |
| 
 | |
|     uses
 | |
|       cutils,
 | |
|       verbose,
 | |
|       systems,
 | |
|       dwarfbase,
 | |
|       cfidwarf,
 | |
|       globals,
 | |
|       procinfo,
 | |
|       symtable,
 | |
|       defutil,
 | |
|       tgobj,
 | |
|       cgobj,cgexcept,
 | |
|       parabase,paramgr,
 | |
|       hlcgobj,
 | |
|       pass_2
 | |
| {$ifdef i386}
 | |
|       ,aasmcpu
 | |
| {$endif i386}
 | |
|       ;
 | |
| 
 | |
| 
 | |
|     type
 | |
|        { Utility class for exception handling state management that is used
 | |
|          by tryexcept/tryfinally/on nodes (in a separate class so it can both
 | |
|          be shared and overridden)
 | |
| 
 | |
|          Never instantiated. }
 | |
|        tpsabiehexceptionstatehandler = class(tcgexceptionstatehandler)
 | |
|        protected
 | |
|          class procedure begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; add_catch: boolean; out exceptlocdef: tdef; out
 | |
|            exceptlocreg: tregister);
 | |
|          class procedure catch_all_start_internal(list: TAsmList; add_catch: boolean);
 | |
|        public
 | |
|          class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
 | |
|          class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
 | |
|          class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
 | |
|          { start of "except/finally" block }
 | |
|          class procedure emit_except_label(list: TAsmList; exceptframekind: texceptframekind; var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps); override;
 | |
|          { end of a try-block, label comes after the end of try/except or
 | |
|            try/finally }
 | |
|          class procedure end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps; var exceptionstate: texceptionstate; endlabel: TAsmLabel); override;
 | |
|          class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
 | |
|          class procedure handle_reraise(list:TAsmList;const t:texceptiontemps;const entrystate: texceptionstate; const exceptframekind: texceptframekind); override;
 | |
|          { start of an "on" (catch) block }
 | |
|          class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
 | |
|          { end of an "on" (catch) block }
 | |
|          class procedure end_catch(list: TAsmList); override;
 | |
|          { called for a catch all exception }
 | |
|          class procedure catch_all_start(list: TAsmList); override;
 | |
|          class procedure catch_all_end(list: TAsmList); override;
 | |
|          class procedure catch_all_add(list: TAsmList); override;
 | |
|          class procedure cleanupobjectstack(list: TAsmList); override;
 | |
|          class procedure popaddrstack(list: TAsmList); override;
 | |
|        end;
 | |
| 
 | |
| 
 | |
|     constructor TPSABIEHAction.Create(pad: TAsmLabel);
 | |
|       begin
 | |
|         landingpad:=pad;
 | |
|         actionlist:=TAsmList.create;
 | |
|         current_asmdata.getlabel(actiontablelabel,alt_data);
 | |
|         actionlist.concat(tai_label.create(actiontablelabel));
 | |
|         first:=true;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     destructor TPSABIEHAction.Destroy;
 | |
|       begin
 | |
|         if not(actionlist.Empty) then
 | |
|           Internalerror(2019020501);
 | |
|         actionlist.Free;
 | |
|         inherited Destroy;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function TPSABIEHAction.AddAction(p: tobjectdef) : LongInt;
 | |
|       var
 | |
|         index: LongInt;
 | |
|       begin
 | |
|         { if not first entry, signal that another action follows }
 | |
|         if not(first) then
 | |
|           actionlist.concat(tai_const.Create_sleb128bit(1));
 | |
|         first:=false;
 | |
| 
 | |
|         { catch all? }
 | |
|         if p=tobjectdef(-1) then
 | |
|           index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(nil)
 | |
|         else if assigned(p) then
 | |
|           index:=(current_procinfo as tpsabiehprocinfo).AddTypeFilter(p)
 | |
|         else
 | |
|           index:=-1;
 | |
| {$ifdef debug_eh}
 | |
|         if p=tobjectdef(-1) then
 | |
|           actionlist.concat(tai_comment.Create(strpnew('Catch all')))
 | |
|         else if assigned(p) then
 | |
|           actionlist.concat(tai_comment.Create(strpnew('Action for '+p.GetTypeName)))
 | |
|         else
 | |
|           actionlist.concat(tai_comment.Create(strpnew('Cleanup')));
 | |
| {$endif debug_eh}
 | |
|         if assigned(p) then
 | |
|           actionlist.concat(tai_const.Create_sleb128bit(index+1))
 | |
|         else
 | |
|           actionlist.concat(tai_const.Create_sleb128bit(0));
 | |
|         Result:=index;
 | |
|       end;
 | |
| 
 | |
| {****************************************************************************
 | |
|                                  tpsabiehprocinfo
 | |
| ****************************************************************************}
 | |
| 
 | |
| 
 | |
|     destructor tpsabiehprocinfo.destroy;
 | |
|       begin
 | |
|          gcc_except_table_data.free;
 | |
|          actionstack.free;
 | |
|          landingpadstack.free;
 | |
|          typefilterlist.free;
 | |
|          callsite_table_data.Free;
 | |
|          action_table_data.Free;
 | |
|          inherited;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.PushAction(action: TPSABIEHAction);
 | |
|       begin
 | |
|         actionstack.add(action);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.PopAction(action: TPSABIEHAction): boolean;
 | |
|       begin
 | |
|         if CurrentAction<>action then
 | |
|           internalerror(2019022501);
 | |
|         actionstack.count:=actionstack.count-1;
 | |
|         result:=actionstack.count=0;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.FinalizeAndPopAction(action: TPSABIEHAction): boolean;
 | |
|       var
 | |
|         curpos: tasmlabel;
 | |
|       begin
 | |
|         include(flags,pi_has_except_table_data);
 | |
|         if CurrentAction<>action then
 | |
|           internalerror(2019021006);
 | |
|         { no further actions follow, finalize table
 | |
|           we check for >1 as the outmost landing pad has no action, so
 | |
|           we can ignore it }
 | |
|         if landingpadstack.count>1 then
 | |
|           begin
 | |
|             current_asmdata.getlabel(curpos,alt_data);
 | |
|             action.actionlist.concat(tai_label.create(curpos));
 | |
|             action.actionlist.concat(tai_const.Create_rel_sym(aitconst_sleb128bit,curpos,TPSABIEHAction(landingpadstack[landingpadstack.count-1]).actiontablelabel));
 | |
|           end
 | |
|         else
 | |
|           action.actionlist.concat(tai_const.Create_sleb128bit(0));
 | |
|         action_table_data.concatList(action.actionlist);
 | |
|         actionstack.count:=actionstack.count-1;
 | |
|         result:=actionstack.count=0;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.PushLandingPad(action: TPSABIEHAction);
 | |
|       begin
 | |
|         landingpadstack.add(action);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.CurrentLandingPad: TPSABIEHAction;
 | |
|       begin
 | |
|         result:=TPSABIEHAction(landingpadstack.last);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.PopLandingPad(action: TPSABIEHAction): boolean;
 | |
|       begin
 | |
|         if CurrentLandingPad<>action then
 | |
|           internalerror(2019021007);
 | |
|         landingpadstack.count:=landingpadstack.count-1;
 | |
|         result:=landingpadstack.count=0;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.CreateNewPSABIEHCallsite(list : TAsmList);
 | |
|       var
 | |
|         callsiteend : TAsmLabel;
 | |
|       begin
 | |
|         include(flags,pi_has_except_table_data);
 | |
|         { first, finish last entry }
 | |
|         if assigned(callsitelaststart) and assigned(CurrentLandingPad) then
 | |
|           begin
 | |
| {$ifdef debug_eh}
 | |
|             if assigned(CurrentLandingPad.actiontablelabel) then
 | |
|               callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))))
 | |
|             else
 | |
|               callsite_table_data.concat(tai_comment.Create(strpnew('Call site '+tostr(CurrentCallSiteNumber)+', no action')));
 | |
| {$endif debug_eh}
 | |
|             callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,current_asmdata.AsmCFI.get_frame_start,callsitelaststart));
 | |
|             current_asmdata.getlabel(callsiteend,alt_eh_end);
 | |
|             list.concat(tai_label.create(callsiteend));
 | |
|             callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitelaststart,callsiteend));
 | |
|             { landing pad? }
 | |
|             if assigned(CurrentLandingPad.landingpad) then
 | |
|               callsite_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,current_asmdata.AsmCFI.get_frame_start,CurrentLandingPad.landingpad))
 | |
|             else
 | |
|               callsite_table_data.concat(tai_const.Create_uleb128bit(0));
 | |
|             { action number set? if yes, concat }
 | |
|             if assigned(CurrentLandingPad.actiontablelabel) then
 | |
|               begin
 | |
|                 callsite_table_data.concat(tai_const.Create_rel_sym_offset(aitconst_uleb128bit,callsitetableend,CurrentLandingPad.actiontablelabel,1));
 | |
| {$ifdef debug_eh}
 | |
|                 list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', action table index = '+tostr(landingpadstack.count-1))));
 | |
| {$endif debug_eh}
 | |
|               end
 | |
|             else
 | |
|               begin
 | |
|                 callsite_table_data.concat(tai_const.Create_uleb128bit(0));
 | |
| {$ifdef debug_eh}
 | |
|                 list.concat(tai_comment.Create(strpnew('New call site '+tostr(CurrentCallSiteNumber)+', no action')));
 | |
| {$endif debug_eh}
 | |
|               end;
 | |
|             current_asmdata.getlabel(callsitelaststart,alt_eh_begin);
 | |
|             list.concat(tai_label.create(callsitelaststart));
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             current_asmdata.getlabel(entrycallsitestart,alt_eh_begin);
 | |
|             callsitelaststart:=entrycallsitestart
 | |
|           end;
 | |
| 
 | |
|         Inc(CurrentCallSiteNumber);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.AddTypeFilter(p: tobjectdef) : Longint;
 | |
|       var
 | |
|         i: Integer;
 | |
|       begin
 | |
|         for i:=0 to typefilterlist.count-1 do
 | |
|           begin
 | |
|             if tobjectdef(typefilterlist[i])=p then
 | |
|               begin
 | |
|                 result:=i;
 | |
|                 exit;
 | |
|               end;
 | |
|           end;
 | |
|         result:=typefilterlist.add(p);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.set_eh_info;
 | |
|       begin
 | |
|         inherited set_eh_info;
 | |
|         if (tf_use_psabieh in target_info.flags) and not(pi_has_except_table_data in flags) then
 | |
|           LSDALabel:=nil
 | |
|         else
 | |
|           current_asmdata.AsmCFI.get_cfa_list.concat(tdwarfitem.create_sym(DW_Set_LSDALabel,doe_32bit,LSDALabel));
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.CurrentAction: TPSABIEHAction; inline;
 | |
|       begin
 | |
|         result:=TPSABIEHAction(actionstack.last);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     function tpsabiehprocinfo.find_exception_handling(var n: tnode; para: pointer): foreachnoderesult;
 | |
|       begin
 | |
|         if n.nodetype in [tryfinallyn,tryexceptn,raisen,onn] then
 | |
|           Result:=fen_norecurse_true
 | |
|         else
 | |
|           Result:=fen_false;
 | |
|         end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.setup_eh;
 | |
|       var
 | |
|         gcc_except_table: tai_section;
 | |
|       begin
 | |
|         if tf_use_psabieh in target_info.flags then
 | |
|           begin
 | |
|             CreateExceptionTable:=foreachnode(code,@find_exception_handling,nil);
 | |
| 
 | |
|             gcc_except_table_data:=TAsmList.Create;
 | |
|             callsite_table_data:=TAsmList.Create;
 | |
|             action_table_data:=TAsmList.Create;
 | |
|             actionstack:=TFPList.Create;
 | |
|             landingpadstack:=TFPList.Create;
 | |
|             typefilterlist:=TFPList.Create;
 | |
|             gcc_except_table:=new_section(gcc_except_table_data,sec_gcc_except_table,'',0);
 | |
|             gcc_except_table.secflags:=[SF_A];
 | |
|             gcc_except_table.secprogbits:=SPB_PROGBITS;
 | |
| {$ifdef debug_eh}
 | |
|             gcc_except_table_data.concat(tai_comment.Create(strpnew('gcc_except_table for '+procdef.fullprocname(true))));
 | |
|  {$endif debug_eh}
 | |
|             current_asmdata.getlabel(LSDALabel,alt_data);
 | |
| 
 | |
|             current_asmdata.getlabel(callsitetablestart,alt_data);
 | |
|             current_asmdata.getlabel(callsitetableend,alt_data);
 | |
| 
 | |
|             callsite_table_data.concat(tai_label.create(callsitetablestart));
 | |
|             cexceptionstatehandler:=tpsabiehexceptionstatehandler;
 | |
| 
 | |
|             if CreateExceptionTable then
 | |
|               begin
 | |
|                 CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
 | |
| 
 | |
|                 OutmostLandingPad:=TPSABIEHAction.Create(nil);
 | |
|                 NoAction:=OutmostLandingPad;
 | |
|                 PushAction(OutmostLandingPad);
 | |
|                 PushLandingPad(OutmostLandingPad);
 | |
|                 OutmostLandingPad.AddAction(nil);
 | |
|               end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.finish_eh;
 | |
|       var
 | |
|         i: Integer;
 | |
|       begin
 | |
|         if tf_use_psabieh in target_info.flags then
 | |
|           begin
 | |
|             if pi_has_except_table_data in flags then
 | |
|               begin
 | |
|                 gcc_except_table_data.concat(tai_label.create(LSDALabel));
 | |
|                 { landing pad base is relative to procedure start, so write an omit }
 | |
|                 gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
 | |
| 
 | |
|                 if typefilterlist.count>0 then
 | |
|                   begin
 | |
| {$if defined(CPU64BITADDR)}
 | |
|                     gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata8));
 | |
| {$elseif defined(CPU32BITADDR)}
 | |
|                     gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata4));
 | |
| {$elseif defined(CPU16BITADDR)}
 | |
|                     gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_udata2));
 | |
| {$endif}
 | |
|                     current_asmdata.getlabel(typefilterlistlabel,alt_data);
 | |
|                     current_asmdata.getlabel(typefilterlistlabelref,alt_data);
 | |
|                     gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,typefilterlistlabel,typefilterlistlabelref));
 | |
|                     gcc_except_table_data.concat(tai_label.create(typefilterlistlabel));
 | |
|                   end
 | |
|                 else
 | |
|                   { default types table encoding }
 | |
|                   gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_omit));
 | |
| 
 | |
|                 { call-site table encoded using uleb128 }
 | |
|                 gcc_except_table_data.concat(tai_const.create_8bit(DW_EH_PE_uleb128));
 | |
|                 gcc_except_table_data.concat(tai_const.create_rel_sym(aitconst_uleb128bit,callsitetablestart,callsitetableend));
 | |
| 
 | |
|                 callsite_table_data.concat(tai_label.create(callsitetableend));
 | |
| {$ifdef debug_eh}
 | |
|                 gcc_except_table_data.concat(tai_comment.Create(strpnew('Call site table for '+procdef.fullprocname(true))));
 | |
| {$endif debug_eh}
 | |
|                 gcc_except_table_data.concatList(callsite_table_data);
 | |
|                 { action table must follow immediatly after callsite table }
 | |
| {$ifdef debug_eh}
 | |
|                 if not(action_table_data.Empty) then
 | |
|                   gcc_except_table_data.concat(tai_comment.Create(strpnew('Action table for '+procdef.fullprocname(true))));
 | |
| {$endif debug_eh}
 | |
|                 gcc_except_table_data.concatlist(action_table_data);
 | |
|                 if typefilterlist.count>0 then
 | |
|                   begin
 | |
| {$ifdef debug_eh}
 | |
|                     gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter list for '+procdef.fullprocname(true))));
 | |
| {$endif debug_eh}
 | |
|                     for i:=typefilterlist.count-1 downto 0 do
 | |
|                       begin
 | |
| {$ifdef debug_eh}
 | |
|                         gcc_except_table_data.concat(tai_comment.Create(strpnew('Type filter '+tostr(i))));
 | |
| {$endif debug_eh}
 | |
|                         if assigned(typefilterlist[i]) then
 | |
|                           gcc_except_table_data.concat(tai_const.Create_sym(current_asmdata.RefAsmSymbol(tobjectdef(typefilterlist[i]).vmt_mangledname, AT_DATA)))
 | |
|                         else
 | |
|                           gcc_except_table_data.concat(tai_const.Create_sym(nil));
 | |
|                       end;
 | |
|                     { the types are resolved by the negative offset, so the label must be written after all types }
 | |
|                     gcc_except_table_data.concat(tai_label.create(typefilterlistlabelref));
 | |
|                   end;
 | |
| 
 | |
|                 new_section(gcc_except_table_data,sec_code,'',0);
 | |
|                 aktproccode.concatlist(gcc_except_table_data);
 | |
|               end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.start_eh(list: TAsmList);
 | |
|       begin
 | |
|         inherited start_eh(list);
 | |
|         if CreateExceptionTable then
 | |
|           list.insert(tai_label.create(entrycallsitestart));
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     procedure tpsabiehprocinfo.end_eh(list: TAsmList);
 | |
|       begin
 | |
|        inherited end_eh(list);
 | |
|        if CreateExceptionTable then
 | |
|          begin
 | |
|            CreateNewPSABIEHCallsite(list);
 | |
|            PopLandingPad(CurrentLandingPad);
 | |
|            FinalizeAndPopAction(OutmostLandingPad);
 | |
|          end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.get_exception_temps(list: TAsmList; var t: texceptiontemps);
 | |
|       begin
 | |
|         if not assigned(exceptionreasontype) then
 | |
|           exceptionreasontype:=ossinttype;
 | |
|         tg.gethltemp(list,exceptionreasontype,exceptionreasontype.size,tt_persistent,t.reasonbuf);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.unget_exception_temps(list: TAsmList; const t: texceptiontemps);
 | |
|       begin
 | |
|         tg.ungettemp(list,t.reasonbuf);
 | |
|         (current_procinfo as tpsabiehprocinfo).FinalizeAndPopAction((current_procinfo as tpsabiehprocinfo).CurrentAction);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.new_exception(list: TAsmList; const t: texceptiontemps;
 | |
|       const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
 | |
|       var
 | |
|         reg: tregister;
 | |
|         action: TPSABIEHAction;
 | |
|       begin
 | |
|         exceptstate.oldflowcontrol:=flowcontrol;
 | |
|         current_asmdata.getjumplabel(exceptstate.exceptionlabel);
 | |
|         if exceptframekind<>tek_except then
 | |
|           begin
 | |
|             current_asmdata.getjumplabel(exceptstate.finallycodelabel);
 | |
|             action:=TPSABIEHAction.Create(exceptstate.finallycodelabel);
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             exceptstate.finallycodelabel:=nil;
 | |
|             action:=TPSABIEHAction.Create(exceptstate.exceptionlabel);
 | |
|           end;
 | |
|         (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
 | |
|         (current_procinfo as tpsabiehprocinfo).PushAction(action);
 | |
|         (current_procinfo as tpsabiehprocinfo).PushLandingPad(action);
 | |
|         if exceptframekind<>tek_except then
 | |
|           { no safecall? }
 | |
|           if use_cleanup(exceptframekind) then
 | |
|             (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil)
 | |
|           else
 | |
|             { if safecall, catch all }
 | |
|             (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
 | |
| 
 | |
|         flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
 | |
|         if exceptframekind<>tek_except then
 | |
|           begin
 | |
|             reg:=hlcg.getintregister(list,ossinttype);
 | |
|             hlcg.a_load_const_reg(list,ossinttype,1,reg);
 | |
|             hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.emit_except_label(list: TAsmList; exceptframekind: texceptframekind;
 | |
|       var exceptionstate: texceptionstate;var exceptiontemps:texceptiontemps);
 | |
|       begin
 | |
|         hlcg.g_unreachable(list);
 | |
|         hlcg.a_label(list,exceptionstate.exceptionlabel);
 | |
|         if exceptframekind<>tek_except then
 | |
|           begin
 | |
|             if not assigned(exceptionstate.finallycodelabel) then
 | |
|               internalerror(2019021002);
 | |
| 
 | |
|             hlcg.a_label(list,exceptionstate.finallycodelabel);
 | |
|             exceptionstate.finallycodelabel:=nil;
 | |
|             exceptiontemps.unwind_info:=cg.getaddressregister(list);
 | |
|             hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,exceptiontemps.unwind_info);
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.end_try_block(list: TAsmList; exceptframekind: texceptframekind; const t: texceptiontemps;
 | |
|       var exceptionstate: texceptionstate; endlabel: TAsmLabel);
 | |
|       var
 | |
|         reg: TRegister;
 | |
|       begin
 | |
|         if exceptframekind<>tek_except then
 | |
|           begin
 | |
|             { record that no exception happened in the reason buf, in case we are in a try block of a finally statement }
 | |
|             reg:=hlcg.getintregister(list,ossinttype);
 | |
|             hlcg.a_load_const_reg(list,ossinttype,0,reg);
 | |
|             hlcg.g_exception_reason_save(list,ossinttype,ossinttype,reg,t.reasonbuf);
 | |
|           end;
 | |
|         inherited;
 | |
|         if exceptframekind=tek_except then
 | |
|           hlcg.a_jmp_always(list,endlabel);
 | |
|         (current_procinfo as tpsabiehprocinfo).CreateNewPSABIEHCallsite(list);
 | |
|         (current_procinfo as tpsabiehprocinfo).PopLandingPad((current_procinfo as tpsabiehprocinfo).CurrentLandingPad);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint;
 | |
|       endexceptlabel: tasmlabel; onlyfree: boolean);
 | |
|       begin
 | |
|         { nothing to do }
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.handle_reraise(list: TAsmList; const t: texceptiontemps; const entrystate: texceptionstate;
 | |
|       const exceptframekind: texceptframekind);
 | |
|       var
 | |
|         cgpara1: tcgpara;
 | |
|         pd: tprocdef;
 | |
|         ReRaiseLandingPad: TPSABIEHAction;
 | |
|         psabiehprocinfo: tpsabiehprocinfo;
 | |
|       begin
 | |
|         if not(fc_catching_exceptions in flowcontrol) and
 | |
|            use_cleanup(exceptframekind) then
 | |
|           begin
 | |
|             { Resume might not be called outside of an landing pad else
 | |
|               the unwind is immediatly terminated, so create an empty landing pad }
 | |
|             psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
 | |
| 
 | |
|             if psabiehprocinfo.landingpadstack.count>1 then
 | |
|               begin
 | |
|                 psabiehprocinfo.CreateNewPSABIEHCallsite(list);
 | |
| 
 | |
|                 psabiehprocinfo.PushAction(psabiehprocinfo.NoAction);
 | |
|                 psabiehprocinfo.PushLandingPad(psabiehprocinfo.NoAction);
 | |
|               end;
 | |
| 
 | |
|             pd:=search_system_proc('_unwind_resume');
 | |
|             cgpara1.init;
 | |
|             paramanager.getcgtempparaloc(list,pd,1,cgpara1);
 | |
|             hlcg.a_load_reg_cgpara(list,voidpointertype,t.unwind_info,cgpara1);
 | |
|             paramanager.freecgpara(list,cgpara1);
 | |
|             hlcg.g_call_system_proc(list,'_unwind_resume',[@cgpara1],nil).resetiftemp;
 | |
|             { we do not have to clean up the stack, we never return }
 | |
|             cgpara1.done;
 | |
| 
 | |
|             if psabiehprocinfo.landingpadstack.count>1 then
 | |
|               begin
 | |
|                 psabiehprocinfo.CreateNewPSABIEHCallsite(list);
 | |
|                 psabiehprocinfo.PopLandingPad(psabiehprocinfo.NoAction);
 | |
|                 psabiehprocinfo.PopAction(psabiehprocinfo.NoAction);
 | |
|               end;
 | |
|           end
 | |
|         else
 | |
|           begin
 | |
|             psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
 | |
|             { empty landing pad needed to avoid immediate termination? }
 | |
|             if psabiehprocinfo.landingpadstack.Count=0 then
 | |
|               begin
 | |
|                 psabiehprocinfo.CreateNewPSABIEHCallsite(list);
 | |
| 
 | |
|                 ReRaiseLandingPad:=psabiehprocinfo.NoAction;
 | |
|                 psabiehprocinfo.PushAction(ReRaiseLandingPad);
 | |
|                 psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
 | |
|               end
 | |
|             else
 | |
|               ReRaiseLandingPad:=nil;
 | |
|             hlcg.g_call_system_proc(list,'fpc_reraise',[],nil).resetiftemp;
 | |
|             if assigned(ReRaiseLandingPad) then
 | |
|               begin
 | |
|                 psabiehprocinfo.CreateNewPSABIEHCallsite(list);
 | |
|                 psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
 | |
|                 psabiehprocinfo.PopAction(ReRaiseLandingPad);
 | |
|              end;
 | |
|           end;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.begin_catch_internal(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel;
 | |
|       add_catch: boolean; out exceptlocdef: tdef; out exceptlocreg: tregister);
 | |
|       var
 | |
|         catchstartlab : tasmlabel;
 | |
|         begincatchres,
 | |
|         paraloc1: tcgpara;
 | |
|         pd: tprocdef;
 | |
|         {rttisym: TAsmSymbol;
 | |
|         rttidef: tdef;
 | |
|         indirect: boolean;
 | |
|         otherunit: boolean; }
 | |
|         wrappedexception: tregister;
 | |
|         exceptloc: tlocation;
 | |
| {$if defined(i386) or defined(x86_64)}
 | |
|         typeindex : aint;
 | |
| {$endif}
 | |
|       begin
 | |
|         paraloc1.init;
 | |
| {
 | |
|         rttidef:=nil;
 | |
|         rttisym:=nil;
 | |
| }
 | |
|         wrappedexception:=hlcg.getaddressregister(list,voidpointertype);
 | |
|         hlcg.a_load_reg_reg(list,voidpointertype,voidpointertype,NR_FUNCTION_RESULT_REG,wrappedexception);
 | |
| (*
 | |
|         if add_catch then
 | |
|           begin
 | |
|             if assigned(excepttype) then
 | |
|               begin
 | |
|                 otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
 | |
|                 indirect:=(tf_supports_packages in target_info.flags) and
 | |
|                         (target_info.system in systems_indirect_var_imports) and
 | |
|                         (cs_imported_data in current_settings.localswitches) and
 | |
|                         otherunit;
 | |
|                 { add "catch exceptiontype" clause to the landing pad }
 | |
|                 rttidef:=cpointerdef.getreusable(excepttype.vmt_def);
 | |
|                 rttisym:=current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect);
 | |
|               end;
 | |
|           end;
 | |
| *)
 | |
|         { check if the exception is handled by this node }
 | |
|         if assigned(excepttype) then
 | |
|           begin
 | |
| {$if defined(i386) or defined(x86_64)}
 | |
|             typeindex:=(current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(excepttype);
 | |
| {$endif}
 | |
|             current_asmdata.getjumplabel(catchstartlab);
 | |
| {$if defined(i386)}
 | |
|             hlcg.a_cmp_const_reg_label (list,osuinttype,OC_EQ,typeindex+1,NR_FUNCTION_RESULT64_HIGH_REG,catchstartlab);
 | |
| {$elseif defined(x86_64)}
 | |
|             hlcg.a_cmp_const_reg_label (list,s32inttype,OC_EQ,typeindex+1,NR_EDX,catchstartlab);
 | |
| {$else}
 | |
|             { we need to find a way to fix this in a generic way }
 | |
|             Internalerror(2019021008);
 | |
| {$endif}
 | |
|             hlcg.a_jmp_always(list,nextonlabel);
 | |
|             hlcg.a_label(list,catchstartlab);
 | |
|           end
 | |
|         else
 | |
|           (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(tobjectdef(-1));
 | |
| 
 | |
|         pd:=search_system_proc('fpc_psabi_begin_catch');
 | |
|         paramanager.getcgtempparaloc(list, pd, 1, paraloc1);
 | |
|         hlcg.a_load_reg_cgpara(list,voidpointertype,wrappedexception,paraloc1);
 | |
|         begincatchres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
 | |
|         location_reset(exceptloc, LOC_REGISTER, def_cgsize(begincatchres.def));
 | |
|         exceptloc.register:=hlcg.getaddressregister(list, begincatchres.def);
 | |
|         hlcg.gen_load_cgpara_loc(list, begincatchres.def, begincatchres, exceptloc, true);
 | |
| 
 | |
|         begincatchres.resetiftemp;
 | |
|         paraloc1.done;
 | |
| 
 | |
|         exceptlocdef:=begincatchres.def;
 | |
|         exceptlocreg:=exceptloc.register;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.catch_all_start_internal(list: TAsmList; add_catch: boolean);
 | |
|       var
 | |
|         exceptlocdef: tdef;
 | |
|         exceptlocreg: tregister;
 | |
|       begin
 | |
|         begin_catch_internal(list,nil,nil,add_catch,exceptlocdef,exceptlocreg);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out
 | |
|       exceptlocreg: tregister);
 | |
|       begin
 | |
|         begin_catch_internal(list,excepttype,nextonlabel,true,exceptlocdef,exceptlocreg);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.end_catch(list: TAsmList);
 | |
|       begin
 | |
|         hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
 | |
|         inherited;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.catch_all_start(list: TAsmList);
 | |
|       begin
 | |
|         catch_all_start_internal(list,true);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.catch_all_add(list: TAsmList);
 | |
|       begin
 | |
|         (current_procinfo as tpsabiehprocinfo).CurrentAction.AddAction(nil);
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.catch_all_end(list: TAsmList);
 | |
|       begin
 | |
|         hlcg.g_call_system_proc(list,'fpc_psabi_end_catch',[],nil).resetiftemp;
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.cleanupobjectstack(list: TAsmList);
 | |
|       begin
 | |
|         { there is nothing to do }
 | |
|       end;
 | |
| 
 | |
| 
 | |
|     class procedure tpsabiehexceptionstatehandler.popaddrstack(list: TAsmList);
 | |
|       begin
 | |
|         { there is no addr stack, so do nothing }
 | |
|       end;
 | |
| 
 | |
| end.
 |