mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-06 00:47:52 +02:00

* 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.
|