|
@@ -28,8 +28,10 @@ interface
|
|
|
|
|
|
uses
|
|
uses
|
|
globtype,
|
|
globtype,
|
|
- aasmbase,aasmdata,nflw,
|
|
|
|
- pass_2,cgutils,ncgutil;
|
|
|
|
|
|
+ symtype,symdef,
|
|
|
|
+ aasmbase,aasmdata,
|
|
|
|
+ node,nflw,
|
|
|
|
+ pass_2,cgbase,cgutils,ncgutil,cgexcept;
|
|
|
|
|
|
type
|
|
type
|
|
tcgwhilerepeatnode = class(twhilerepeatnode)
|
|
tcgwhilerepeatnode = class(twhilerepeatnode)
|
|
@@ -72,43 +74,27 @@ interface
|
|
end;
|
|
end;
|
|
|
|
|
|
tcgraisenode = class(traisenode)
|
|
tcgraisenode = class(traisenode)
|
|
|
|
+ function pass_1: tnode;override;
|
|
|
|
+{$ifndef jvm}
|
|
|
|
+ procedure pass_generate_code;override;
|
|
|
|
+{$endif jvm}
|
|
end;
|
|
end;
|
|
|
|
|
|
- { 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. }
|
|
|
|
- tcgexceptionstatehandler = class
|
|
|
|
- type
|
|
|
|
- texceptiontemps=record
|
|
|
|
- jmpbuf,
|
|
|
|
- envbuf,
|
|
|
|
- reasonbuf : treference;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- texceptionstate = record
|
|
|
|
- exceptionlabel: TAsmLabel;
|
|
|
|
- oldflowcontrol,
|
|
|
|
- newflowcontrol: tflowcontrol;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); virtual;
|
|
|
|
- class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); virtual;
|
|
|
|
- class procedure new_exception(list:TAsmList;const t:texceptiontemps; out exceptstate: texceptionstate); virtual;
|
|
|
|
- class procedure emit_except_label(list: TAsmList; var exceptstate: texceptionstate); virtual;
|
|
|
|
- class procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean); virtual;
|
|
|
|
- class procedure cleanupobjectstack; virtual;
|
|
|
|
- class procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;var entrystate: texceptionstate); virtual;
|
|
|
|
- end;
|
|
|
|
- tcgexceptionstatehandlerclass = class of tcgexceptionstatehandler;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
tcgtryexceptnode = class(ttryexceptnode)
|
|
tcgtryexceptnode = class(ttryexceptnode)
|
|
|
|
+ protected
|
|
|
|
+ type
|
|
|
|
+ tframetype = (ft_try,ft_except);
|
|
|
|
+
|
|
|
|
+ procedure emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel); virtual;
|
|
|
|
+ public
|
|
procedure pass_generate_code;override;
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
end;
|
|
|
|
|
|
tcgtryfinallynode = class(ttryfinallynode)
|
|
tcgtryfinallynode = class(ttryfinallynode)
|
|
|
|
+ protected
|
|
|
|
+ procedure emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
|
|
|
|
+ function get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
|
|
|
|
+ public
|
|
procedure handle_safecall_exception;
|
|
procedure handle_safecall_exception;
|
|
procedure pass_generate_code;override;
|
|
procedure pass_generate_code;override;
|
|
end;
|
|
end;
|
|
@@ -118,22 +104,21 @@ interface
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
- var
|
|
|
|
- cexceptionstatehandler: tcgexceptionstatehandlerclass;
|
|
|
|
-
|
|
|
|
implementation
|
|
implementation
|
|
|
|
|
|
uses
|
|
uses
|
|
cutils,
|
|
cutils,
|
|
verbose,globals,systems,
|
|
verbose,globals,systems,
|
|
- symconst,symdef,symsym,symtable,symtype,aasmtai,aasmcpu,defutil,
|
|
|
|
- procinfo,cgbase,parabase,
|
|
|
|
|
|
+ symconst,symsym,symtable,aasmtai,aasmcpu,defutil,
|
|
|
|
+ procinfo,parabase,
|
|
fmodule,
|
|
fmodule,
|
|
cpubase,
|
|
cpubase,
|
|
tgobj,paramgr,
|
|
tgobj,paramgr,
|
|
cgobj,hlcgobj,nutils
|
|
cgobj,hlcgobj,nutils
|
|
|
|
+{$ifndef jvm}
|
|
|
|
+ ,psabiehpi
|
|
|
|
+{$endif jvm}
|
|
;
|
|
;
|
|
-
|
|
|
|
{*****************************************************************************
|
|
{*****************************************************************************
|
|
Second_While_RepeatN
|
|
Second_While_RepeatN
|
|
*****************************************************************************}
|
|
*****************************************************************************}
|
|
@@ -533,160 +518,6 @@ implementation
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
-{*****************************************************************************
|
|
|
|
- tcgexceptionstatehandler
|
|
|
|
-*****************************************************************************}
|
|
|
|
-
|
|
|
|
- { Allocate the buffers for exception management and setjmp environment.
|
|
|
|
- Return a pointer to these buffers, send them to the utility routine
|
|
|
|
- so they are registered, and then call setjmp.
|
|
|
|
-
|
|
|
|
- Then compare the result of setjmp with 0, and if not equal
|
|
|
|
- to zero, then jump to exceptlabel.
|
|
|
|
-
|
|
|
|
- Also store the result of setjmp to a temporary space by calling g_save_exception_reason
|
|
|
|
-
|
|
|
|
- It is to note that this routine may be called *after* the stackframe of a
|
|
|
|
- routine has been called, therefore on machines where the stack cannot
|
|
|
|
- be modified, all temps should be allocated on the heap instead of the
|
|
|
|
- stack. }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- class procedure tcgexceptionstatehandler.get_exception_temps(list:TAsmList;var t:texceptiontemps);
|
|
|
|
- begin
|
|
|
|
- tg.gethltemp(list,rec_exceptaddr,rec_exceptaddr.size,tt_persistent,t.envbuf);
|
|
|
|
- tg.gethltemp(list,rec_jmp_buf,rec_jmp_buf.size,tt_persistent,t.jmpbuf);
|
|
|
|
- tg.gethltemp(list,ossinttype,ossinttype.size,tt_persistent,t.reasonbuf);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- class procedure tcgexceptionstatehandler.unget_exception_temps(list:TAsmList;const t:texceptiontemps);
|
|
|
|
- begin
|
|
|
|
- tg.Ungettemp(list,t.jmpbuf);
|
|
|
|
- tg.ungettemp(list,t.envbuf);
|
|
|
|
- tg.ungettemp(list,t.reasonbuf);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- class procedure tcgexceptionstatehandler.new_exception(list:TAsmList;const t:texceptiontemps; out exceptstate: texceptionstate);
|
|
|
|
- var
|
|
|
|
- paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
|
|
|
|
- pd: tprocdef;
|
|
|
|
- tmpresloc: tlocation;
|
|
|
|
- begin
|
|
|
|
- current_asmdata.getjumplabel(exceptstate.exceptionlabel);
|
|
|
|
- exceptstate.oldflowcontrol:=flowcontrol;
|
|
|
|
-
|
|
|
|
- paraloc1.init;
|
|
|
|
- paraloc2.init;
|
|
|
|
- paraloc3.init;
|
|
|
|
-
|
|
|
|
- { fpc_pushexceptaddr(exceptionframetype, setjmp_buffer, exception_address_chain_entry) }
|
|
|
|
- pd:=search_system_proc('fpc_pushexceptaddr');
|
|
|
|
- paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
|
|
|
|
- paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,2,paraloc2);
|
|
|
|
- paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,3,paraloc3);
|
|
|
|
- if pd.is_pushleftright then
|
|
|
|
- begin
|
|
|
|
- { type of exceptionframe }
|
|
|
|
- hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
|
|
|
|
- { setjmp buffer }
|
|
|
|
- hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
|
|
|
|
- { exception address chain entry }
|
|
|
|
- hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- hlcg.a_loadaddr_ref_cgpara(list,rec_exceptaddr,t.envbuf,paraloc3);
|
|
|
|
- hlcg.a_loadaddr_ref_cgpara(list,rec_jmp_buf,t.jmpbuf,paraloc2);
|
|
|
|
- hlcg.a_load_const_cgpara(list,paraloc1.def,1,paraloc1);
|
|
|
|
- end;
|
|
|
|
- paramanager.freecgpara(list,paraloc3);
|
|
|
|
- paramanager.freecgpara(list,paraloc2);
|
|
|
|
- paramanager.freecgpara(list,paraloc1);
|
|
|
|
- { perform the fpc_pushexceptaddr call }
|
|
|
|
- pushexceptres:=hlcg.g_call_system_proc(list,pd,[@paraloc1,@paraloc2,@paraloc3],nil);
|
|
|
|
- paraloc1.done;
|
|
|
|
- paraloc2.done;
|
|
|
|
- paraloc3.done;
|
|
|
|
-
|
|
|
|
- { get the result }
|
|
|
|
- location_reset(tmpresloc,LOC_REGISTER,def_cgsize(pushexceptres.def));
|
|
|
|
- tmpresloc.register:=hlcg.getaddressregister(list,pushexceptres.def);
|
|
|
|
- hlcg.gen_load_cgpara_loc(list,pushexceptres.def,pushexceptres,tmpresloc,true);
|
|
|
|
- pushexceptres.resetiftemp;
|
|
|
|
-
|
|
|
|
- { fpc_setjmp(result_of_pushexceptaddr_call) }
|
|
|
|
- pd:=search_system_proc('fpc_setjmp');
|
|
|
|
- paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
|
|
|
|
-
|
|
|
|
- hlcg.a_load_reg_cgpara(list,pushexceptres.def,tmpresloc.register,paraloc1);
|
|
|
|
- paramanager.freecgpara(list,paraloc1);
|
|
|
|
- { perform the fpc_setjmp call }
|
|
|
|
- setjmpres:=hlcg.g_call_system_proc(list,pd,[@paraloc1],nil);
|
|
|
|
- paraloc1.done;
|
|
|
|
- location_reset(tmpresloc,LOC_REGISTER,def_cgsize(setjmpres.def));
|
|
|
|
- tmpresloc.register:=hlcg.getintregister(list,setjmpres.def);
|
|
|
|
- hlcg.gen_load_cgpara_loc(list,setjmpres.def,setjmpres,tmpresloc,true);
|
|
|
|
- hlcg.g_exception_reason_save(list,setjmpres.def,ossinttype,tmpresloc.register,t.reasonbuf);
|
|
|
|
- { if we get 0 here in the function result register, it means that we
|
|
|
|
- longjmp'd back here }
|
|
|
|
- hlcg.a_cmp_const_reg_label(list,setjmpres.def,OC_NE,0,tmpresloc.register,exceptstate.exceptionlabel);
|
|
|
|
- setjmpres.resetiftemp;
|
|
|
|
-
|
|
|
|
- flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- class procedure tcgexceptionstatehandler.emit_except_label(list: TAsmList; var exceptstate: texceptionstate);
|
|
|
|
- begin
|
|
|
|
- hlcg.a_label(list,exceptstate.exceptionlabel);
|
|
|
|
- exceptstate.newflowcontrol:=flowcontrol;
|
|
|
|
- flowcontrol:=exceptstate.oldflowcontrol;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- class procedure tcgexceptionstatehandler.free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
|
|
|
|
- var
|
|
|
|
- reasonreg: tregister;
|
|
|
|
- begin
|
|
|
|
- hlcg.g_call_system_proc(list,'fpc_popaddrstack',[],nil);
|
|
|
|
- if not onlyfree then
|
|
|
|
- begin
|
|
|
|
- reasonreg:=hlcg.getintregister(list,osuinttype);
|
|
|
|
- hlcg.g_exception_reason_load(list,osuinttype,osuinttype,t.reasonbuf,reasonreg);
|
|
|
|
- hlcg.a_cmp_const_reg_label(list,osuinttype,OC_EQ,a,reasonreg,endexceptlabel);
|
|
|
|
- end;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- { does the necessary things to clean up the object stack }
|
|
|
|
- { in the except block }
|
|
|
|
- class procedure tcgexceptionstatehandler.cleanupobjectstack;
|
|
|
|
- begin
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
- { generates code to be executed when another exeception is raised while
|
|
|
|
- control is inside except block }
|
|
|
|
- class procedure tcgexceptionstatehandler.handle_nested_exception(list:TAsmList;const t:texceptiontemps;var entrystate: texceptionstate);
|
|
|
|
- var
|
|
|
|
- exitlabel: tasmlabel;
|
|
|
|
- begin
|
|
|
|
- { don't generate line info for internal cleanup }
|
|
|
|
- list.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
- current_asmdata.getjumplabel(exitlabel);
|
|
|
|
- emit_except_label(current_asmdata.CurrAsmList,entrystate);
|
|
|
|
- free_exception(list,t,0,exitlabel,false);
|
|
|
|
- { we don't need to save/restore registers here because reraise never }
|
|
|
|
- { returns }
|
|
|
|
- hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil);
|
|
|
|
- hlcg.a_label(list,exitlabel);
|
|
|
|
- cleanupobjectstack;
|
|
|
|
- end;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
{*****************************************************************************
|
|
{*****************************************************************************
|
|
SecondTryExcept
|
|
SecondTryExcept
|
|
*****************************************************************************}
|
|
*****************************************************************************}
|
|
@@ -694,6 +525,22 @@ implementation
|
|
var
|
|
var
|
|
endexceptlabel : tasmlabel;
|
|
endexceptlabel : tasmlabel;
|
|
|
|
|
|
|
|
+ { jump out of an try/except block }
|
|
|
|
+ procedure tcgtryexceptnode.emit_jump_out_of_try_except_frame(list: TasmList; frametype: tframetype; const exceptiontate: tcgexceptionstatehandler.texceptionstate; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel, outerlabel: tasmlabel);
|
|
|
|
+ begin
|
|
|
|
+ hlcg.a_label(list,framelabel);
|
|
|
|
+ { we must also destroy the address frame which guards
|
|
|
|
+ the exception object }
|
|
|
|
+ cexceptionstatehandler.popaddrstack(list);
|
|
|
|
+ hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
|
|
|
|
+ if frametype=ft_except then
|
|
|
|
+ begin
|
|
|
|
+ cexceptionstatehandler.cleanupobjectstack(list);
|
|
|
|
+ cexceptionstatehandler.end_catch(list);
|
|
|
|
+ end;
|
|
|
|
+ hlcg.a_jmp_always(list,outerlabel);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
|
|
procedure tcgtryexceptnode.pass_generate_code;
|
|
procedure tcgtryexceptnode.pass_generate_code;
|
|
|
|
|
|
@@ -712,6 +559,7 @@ implementation
|
|
destroytemps,
|
|
destroytemps,
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
|
|
trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
|
|
|
|
+ afteronflowcontrol: tflowcontrol;
|
|
label
|
|
label
|
|
errorexit;
|
|
errorexit;
|
|
begin
|
|
begin
|
|
@@ -750,7 +598,7 @@ implementation
|
|
current_asmdata.getjumplabel(lastonlabel);
|
|
current_asmdata.getjumplabel(lastonlabel);
|
|
|
|
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
- cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,trystate);
|
|
|
|
|
|
+ cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,trystate);
|
|
|
|
|
|
{ try block }
|
|
{ try block }
|
|
{ set control flow labels for the try block }
|
|
{ set control flow labels for the try block }
|
|
@@ -768,9 +616,10 @@ implementation
|
|
{ don't generate line info for internal cleanup }
|
|
{ don't generate line info for internal cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
|
|
- cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,trystate);
|
|
|
|
|
|
+ cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,tek_except,excepttemps,trystate,endexceptlabel);
|
|
|
|
|
|
- cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
|
|
|
|
|
|
+ cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,tek_except,trystate,excepttemps);
|
|
|
|
+ cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList, excepttemps, trystate, 0, endexceptlabel, false);
|
|
|
|
|
|
{ end cleanup }
|
|
{ end cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
@@ -784,11 +633,13 @@ implementation
|
|
current_procinfo.CurrBreakLabel:=breakexceptlabel;
|
|
current_procinfo.CurrBreakLabel:=breakexceptlabel;
|
|
end;
|
|
end;
|
|
|
|
|
|
- flowcontrol:=[fc_inflowcontrol];
|
|
|
|
|
|
+ flowcontrol:=[fc_inflowcontrol]+trystate.oldflowcontrol*[fc_catching_exceptions];
|
|
{ on statements }
|
|
{ on statements }
|
|
if assigned(right) then
|
|
if assigned(right) then
|
|
secondpass(right);
|
|
secondpass(right);
|
|
|
|
|
|
|
|
+ afteronflowcontrol:=flowcontrol;
|
|
|
|
+
|
|
{ don't generate line info for internal cleanup }
|
|
{ don't generate line info for internal cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
|
|
@@ -804,18 +655,22 @@ implementation
|
|
{ guarded by an exception frame, but it can be omitted }
|
|
{ guarded by an exception frame, but it can be omitted }
|
|
{ if there's no user code in 'except' block }
|
|
{ if there's no user code in 'except' block }
|
|
|
|
|
|
|
|
+ cexceptionstatehandler.catch_all_start(current_asmdata.CurrAsmList);
|
|
if not (has_no_code(t1)) then
|
|
if not (has_no_code(t1)) then
|
|
begin
|
|
begin
|
|
|
|
+ { if there is an outer frame that catches exceptions, remember this for the "except"
|
|
|
|
+ part of this try/except }
|
|
|
|
+ flowcontrol:=trystate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
|
|
- cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
|
|
|
|
|
|
+ cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,tek_except,doobjectdestroyandreraisestate);
|
|
|
|
+ cexceptionstatehandler.catch_all_add(current_asmdata.CurrAsmList);
|
|
{ the flowcontrol from the default except-block must be merged
|
|
{ the flowcontrol from the default except-block must be merged
|
|
with the flowcontrol flags potentially set by the
|
|
with the flowcontrol flags potentially set by the
|
|
on-statements handled above (secondpass(right)), as they are
|
|
on-statements handled above (secondpass(right)), as they are
|
|
at the same program level }
|
|
at the same program level }
|
|
flowcontrol:=
|
|
flowcontrol:=
|
|
flowcontrol+
|
|
flowcontrol+
|
|
- doobjectdestroyandreraisestate.oldflowcontrol;
|
|
|
|
-
|
|
|
|
|
|
+ afteronflowcontrol;
|
|
|
|
|
|
{ except block needs line info }
|
|
{ except block needs line info }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
@@ -825,79 +680,41 @@ implementation
|
|
cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
|
|
cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
|
|
|
|
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
|
|
|
|
+ cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
|
|
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
end
|
|
end
|
|
- else
|
|
|
|
- begin
|
|
|
|
- doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
|
|
|
|
- cexceptionstatehandler.cleanupobjectstack;
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
|
|
|
|
+ cexceptionstatehandler.cleanupobjectstack(current_asmdata.CurrAsmList);
|
|
|
|
+ cexceptionstatehandler.catch_all_end(current_asmdata.CurrAsmList);
|
|
|
|
+ hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
|
|
+ end;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
|
|
|
|
- doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
|
|
|
|
|
|
+ cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,trystate,tek_except);
|
|
|
|
+ doobjectdestroyandreraisestate.newflowcontrol:=afteronflowcontrol;
|
|
end;
|
|
end;
|
|
|
|
|
|
if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
|
|
if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
|
|
- begin
|
|
|
|
- { do some magic for exit in the try block }
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
|
|
|
|
- { we must also destroy the address frame which guards }
|
|
|
|
- { exception object }
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- cexceptionstatehandler.cleanupobjectstack;
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,exitexceptlabel,oldCurrExitLabel);
|
|
|
|
|
|
if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
|
|
if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
|
|
- begin
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
|
|
|
|
- { we must also destroy the address frame which guards }
|
|
|
|
- { exception object }
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- cexceptionstatehandler.cleanupobjectstack;
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,breakexceptlabel,oldBreakLabel);
|
|
|
|
|
|
if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
|
|
if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
|
|
- begin
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
|
|
|
|
- { we must also destroy the address frame which guards }
|
|
|
|
- { exception object }
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- cexceptionstatehandler.cleanupobjectstack;
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_except,doobjectdestroyandreraisestate,excepttemps,continueexceptlabel,oldContinueLabel);
|
|
|
|
|
|
if fc_exit in trystate.newflowcontrol then
|
|
if fc_exit in trystate.newflowcontrol then
|
|
- begin
|
|
|
|
- { do some magic for exit in the try block }
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,exittrylabel);
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,exittrylabel,oldCurrExitLabel);
|
|
|
|
|
|
if fc_break in trystate.newflowcontrol then
|
|
if fc_break in trystate.newflowcontrol then
|
|
- begin
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,breaktrylabel,oldBreakLabel);
|
|
|
|
|
|
if fc_continue in trystate.newflowcontrol then
|
|
if fc_continue in trystate.newflowcontrol then
|
|
- begin
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ emit_jump_out_of_try_except_frame(current_asmdata.CurrAsmList,ft_try,trystate,excepttemps,continuetrylabel,oldContinueLabel);
|
|
|
|
+
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
|
|
|
|
|
|
@@ -933,16 +750,10 @@ implementation
|
|
oldBreakLabel : tasmlabel;
|
|
oldBreakLabel : tasmlabel;
|
|
doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
|
|
doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
- href2: treference;
|
|
|
|
- paraloc1 : tcgpara;
|
|
|
|
exceptvarsym : tlocalvarsym;
|
|
exceptvarsym : tlocalvarsym;
|
|
- pd : tprocdef;
|
|
|
|
- fpc_catches_res: TCGPara;
|
|
|
|
- fpc_catches_resloc: tlocation;
|
|
|
|
- otherunit,
|
|
|
|
- indirect : boolean;
|
|
|
|
|
|
+ exceptlocdef: tdef;
|
|
|
|
+ exceptlocreg: tregister;
|
|
begin
|
|
begin
|
|
- paraloc1.init;
|
|
|
|
location_reset(location,LOC_VOID,OS_NO);
|
|
location_reset(location,LOC_VOID,OS_NO);
|
|
oldCurrExitLabel:=nil;
|
|
oldCurrExitLabel:=nil;
|
|
continueonlabel:=nil;
|
|
continueonlabel:=nil;
|
|
@@ -951,27 +762,7 @@ implementation
|
|
|
|
|
|
current_asmdata.getjumplabel(nextonlabel);
|
|
current_asmdata.getjumplabel(nextonlabel);
|
|
|
|
|
|
- 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;
|
|
|
|
-
|
|
|
|
- { send the vmt parameter }
|
|
|
|
- pd:=search_system_proc('fpc_catches');
|
|
|
|
- reference_reset_symbol(href2,current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname,AT_DATA,indirect),0,sizeof(pint),[]);
|
|
|
|
- if otherunit then
|
|
|
|
- current_module.add_extern_asmsym(excepttype.vmt_mangledname,AB_EXTERNAL,AT_DATA);
|
|
|
|
- paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
|
|
|
|
- hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,excepttype.vmt_def,href2,paraloc1);
|
|
|
|
- paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
|
|
|
|
- fpc_catches_res:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@paraloc1],nil);
|
|
|
|
- location_reset(fpc_catches_resloc,LOC_REGISTER,def_cgsize(fpc_catches_res.def));
|
|
|
|
- fpc_catches_resloc.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fpc_catches_res.def);
|
|
|
|
- hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fpc_catches_res.def,fpc_catches_res,fpc_catches_resloc,true);
|
|
|
|
-
|
|
|
|
- { is it this catch? No. go to next onlabel }
|
|
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,fpc_catches_res.def,OC_EQ,0,fpc_catches_resloc.register,nextonlabel);
|
|
|
|
|
|
+ cexceptionstatehandler.begin_catch(current_asmdata.CurrAsmList,excepttype,nextonlabel,exceptlocdef,exceptlocreg);
|
|
|
|
|
|
{ Retrieve exception variable }
|
|
{ Retrieve exception variable }
|
|
if assigned(excepTSymtable) then
|
|
if assigned(excepTSymtable) then
|
|
@@ -981,16 +772,15 @@ implementation
|
|
|
|
|
|
if assigned(exceptvarsym) then
|
|
if assigned(exceptvarsym) then
|
|
begin
|
|
begin
|
|
- location_reset_ref(exceptvarsym.localloc,LOC_REFERENCE,def_cgsize(voidpointertype),voidpointertype.alignment,[]);
|
|
|
|
- tg.GetLocal(current_asmdata.CurrAsmList,exceptvarsym.vardef.size,exceptvarsym.vardef,exceptvarsym.localloc.reference);
|
|
|
|
- hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,fpc_catches_res.def,exceptvarsym.vardef,fpc_catches_resloc.register,exceptvarsym.localloc.reference);
|
|
|
|
|
|
+ location_reset_ref(exceptvarsym.localloc, LOC_REFERENCE, def_cgsize(voidpointertype), voidpointertype.alignment, []);
|
|
|
|
+ tg.GetLocal(current_asmdata.CurrAsmList, exceptvarsym.vardef.size, exceptvarsym.vardef, exceptvarsym.localloc.reference);
|
|
|
|
+ hlcg.a_load_reg_ref(current_asmdata.CurrAsmList, exceptlocdef, exceptvarsym.vardef, exceptlocreg, exceptvarsym.localloc.reference);
|
|
end;
|
|
end;
|
|
-
|
|
|
|
{ in the case that another exception is risen
|
|
{ in the case that another exception is risen
|
|
- we've to destroy the old one:
|
|
|
|
- call setjmp, and jump to finally label on non-zero result }
|
|
|
|
|
|
+ we've to destroy the old one, so create a new
|
|
|
|
+ exception frame for the catch-handler }
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
- cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
|
|
|
|
|
|
+ cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,tek_except,doobjectdestroyandreraisestate);
|
|
|
|
|
|
oldBreakLabel:=nil;
|
|
oldBreakLabel:=nil;
|
|
oldContinueLabel:=nil;
|
|
oldContinueLabel:=nil;
|
|
@@ -1020,6 +810,7 @@ implementation
|
|
tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
|
|
tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
|
|
exceptvarsym.localloc.loc:=LOC_INVALID;
|
|
exceptvarsym.localloc.loc:=LOC_INVALID;
|
|
end;
|
|
end;
|
|
|
|
+ cexceptionstatehandler.end_catch(current_asmdata.CurrAsmList);
|
|
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
|
|
|
|
|
|
if assigned(right) then
|
|
if assigned(right) then
|
|
@@ -1056,10 +847,11 @@ implementation
|
|
|
|
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,nextonlabel);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,nextonlabel);
|
|
- flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
|
|
|
|
- paraloc1.done;
|
|
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
|
|
|
|
|
|
+ { propagate exit/break/continue }
|
|
|
|
+ flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol,fc_catching_exceptions]);
|
|
|
|
+
|
|
{ next on node }
|
|
{ next on node }
|
|
if assigned(left) then
|
|
if assigned(left) then
|
|
secondpass(left);
|
|
secondpass(left);
|
|
@@ -1069,6 +861,22 @@ implementation
|
|
SecondTryFinally
|
|
SecondTryFinally
|
|
*****************************************************************************}
|
|
*****************************************************************************}
|
|
|
|
|
|
|
|
+ { jump out of a finally block }
|
|
|
|
+ procedure tcgtryfinallynode.emit_jump_out_of_try_finally_frame(list: TasmList; const reason: byte; const finallycodelabel: tasmlabel; var excepttemps: tcgexceptionstatehandler.texceptiontemps; framelabel: tasmlabel);
|
|
|
|
+ begin
|
|
|
|
+ hlcg.a_label(list,framelabel);
|
|
|
|
+ hlcg.g_exception_reason_discard(list,osuinttype,excepttemps.reasonbuf);
|
|
|
|
+ hlcg.g_exception_reason_save_const(list,osuinttype,reason,excepttemps.reasonbuf);
|
|
|
|
+ hlcg.a_jmp_always(list,finallycodelabel);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ function tcgtryfinallynode.get_jump_out_of_try_finally_frame_label(const finallyexceptionstate: tcgexceptionstatehandler.texceptionstate): tasmlabel;
|
|
|
|
+ begin
|
|
|
|
+ current_asmdata.getjumplabel(result);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+
|
|
procedure tcgtryfinallynode.handle_safecall_exception;
|
|
procedure tcgtryfinallynode.handle_safecall_exception;
|
|
var
|
|
var
|
|
cgpara: tcgpara;
|
|
cgpara: tcgpara;
|
|
@@ -1095,6 +903,7 @@ implementation
|
|
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
|
|
cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+
|
|
procedure tcgtryfinallynode.pass_generate_code;
|
|
procedure tcgtryfinallynode.pass_generate_code;
|
|
var
|
|
var
|
|
endfinallylabel,
|
|
endfinallylabel,
|
|
@@ -1103,10 +912,37 @@ implementation
|
|
breakfinallylabel,
|
|
breakfinallylabel,
|
|
oldCurrExitLabel,
|
|
oldCurrExitLabel,
|
|
oldContinueLabel,
|
|
oldContinueLabel,
|
|
- oldBreakLabel : tasmlabel;
|
|
|
|
|
|
+ oldBreakLabel,
|
|
|
|
+ finallyNoExceptionLabel: tasmlabel;
|
|
finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
|
|
finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
excepttemps : tcgexceptionstatehandler.texceptiontemps;
|
|
reasonreg : tregister;
|
|
reasonreg : tregister;
|
|
|
|
+ exceptframekind: tcgexceptionstatehandler.texceptframekind;
|
|
|
|
+ tmplist: TAsmList;
|
|
|
|
+
|
|
|
|
+ procedure handle_breakcontinueexit(const finallycode: tasmlabel; doreraise: boolean);
|
|
|
|
+ begin
|
|
|
|
+ { no exception happened, but maybe break/continue/exit }
|
|
|
|
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
|
|
|
|
+ if fc_exit in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
|
|
|
|
+ if fc_break in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
|
|
|
|
+ if fc_continue in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
|
|
|
|
+ if doreraise then
|
|
|
|
+ cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,tek_normalfinally)
|
|
|
|
+ else
|
|
|
|
+ hlcg.g_unreachable(current_asmdata.CurrAsmList);
|
|
|
|
+ { redirect break/continue/exit to the label above, with the reasonbuf set appropriately }
|
|
|
|
+ if fc_exit in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,2,finallycode,excepttemps,exitfinallylabel);
|
|
|
|
+ if fc_break in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,3,finallycode,excepttemps,breakfinallylabel);
|
|
|
|
+ if fc_continue in finallyexceptionstate.newflowcontrol then
|
|
|
|
+ emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,4,finallycode,excepttemps,continuefinallylabel);
|
|
|
|
+ end;
|
|
|
|
+
|
|
begin
|
|
begin
|
|
location_reset(location,LOC_VOID,OS_NO);
|
|
location_reset(location,LOC_VOID,OS_NO);
|
|
oldBreakLabel:=nil;
|
|
oldBreakLabel:=nil;
|
|
@@ -1114,34 +950,28 @@ implementation
|
|
continuefinallylabel:=nil;
|
|
continuefinallylabel:=nil;
|
|
breakfinallylabel:=nil;
|
|
breakfinallylabel:=nil;
|
|
|
|
|
|
|
|
+ if not implicitframe then
|
|
|
|
+ exceptframekind:=tek_normalfinally
|
|
|
|
+ else
|
|
|
|
+ exceptframekind:=tek_implicitfinally;
|
|
|
|
+
|
|
current_asmdata.getjumplabel(endfinallylabel);
|
|
current_asmdata.getjumplabel(endfinallylabel);
|
|
|
|
|
|
{ call setjmp, and jump to finally label on non-zero result }
|
|
{ call setjmp, and jump to finally label on non-zero result }
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
- cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate);
|
|
|
|
|
|
+ cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,exceptframekind,finallyexceptionstate);
|
|
|
|
|
|
{ the finally block must catch break, continue and exit }
|
|
{ the finally block must catch break, continue and exit }
|
|
{ statements }
|
|
{ statements }
|
|
oldCurrExitLabel:=current_procinfo.CurrExitLabel;
|
|
oldCurrExitLabel:=current_procinfo.CurrExitLabel;
|
|
- if implicitframe then
|
|
|
|
- exitfinallylabel:=finallyexceptionstate.exceptionlabel
|
|
|
|
- else
|
|
|
|
- current_asmdata.getjumplabel(exitfinallylabel);
|
|
|
|
|
|
+ exitfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
|
|
current_procinfo.CurrExitLabel:=exitfinallylabel;
|
|
current_procinfo.CurrExitLabel:=exitfinallylabel;
|
|
if assigned(current_procinfo.CurrBreakLabel) then
|
|
if assigned(current_procinfo.CurrBreakLabel) then
|
|
begin
|
|
begin
|
|
oldContinueLabel:=current_procinfo.CurrContinueLabel;
|
|
oldContinueLabel:=current_procinfo.CurrContinueLabel;
|
|
oldBreakLabel:=current_procinfo.CurrBreakLabel;
|
|
oldBreakLabel:=current_procinfo.CurrBreakLabel;
|
|
- if implicitframe then
|
|
|
|
- begin
|
|
|
|
- breakfinallylabel:=finallyexceptionstate.exceptionlabel;
|
|
|
|
- continuefinallylabel:=finallyexceptionstate.exceptionlabel;
|
|
|
|
- end
|
|
|
|
- else
|
|
|
|
- begin
|
|
|
|
- current_asmdata.getjumplabel(breakfinallylabel);
|
|
|
|
- current_asmdata.getjumplabel(continuefinallylabel);
|
|
|
|
- end;
|
|
|
|
|
|
+ breakfinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
|
|
|
|
+ continuefinallylabel:=get_jump_out_of_try_finally_frame_label(finallyexceptionstate);
|
|
current_procinfo.CurrContinueLabel:=continuefinallylabel;
|
|
current_procinfo.CurrContinueLabel:=continuefinallylabel;
|
|
current_procinfo.CurrBreakLabel:=breakfinallylabel;
|
|
current_procinfo.CurrBreakLabel:=breakfinallylabel;
|
|
end;
|
|
end;
|
|
@@ -1157,9 +987,37 @@ implementation
|
|
{ don't generate line info for internal cleanup }
|
|
{ don't generate line info for internal cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
|
|
- cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,finallyexceptionstate);
|
|
|
|
|
|
+ cexceptionstatehandler.end_try_block(current_asmdata.CurrAsmList,exceptframekind,excepttemps,finallyexceptionstate,finallyexceptionstate.finallycodelabel);
|
|
|
|
+ if assigned(third) then
|
|
|
|
+ begin
|
|
|
|
+ tmplist:=TAsmList.create;
|
|
|
|
+ { emit the except label already (to a temporary list) to ensure that any calls in the
|
|
|
|
+ finally block refer to the outer exception frame rather than to the exception frame
|
|
|
|
+ that emits this same finally code in case an exception does happen }
|
|
|
|
+ cexceptionstatehandler.emit_except_label(tmplist,exceptframekind,finallyexceptionstate,excepttemps);
|
|
|
|
+
|
|
|
|
+ flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
|
|
|
|
+ current_asmdata.getjumplabel(finallyNoExceptionLabel);
|
|
|
|
+ hlcg.a_label(current_asmdata.CurrAsmList,finallyNoExceptionLabel);
|
|
|
|
+ if not implicitframe then
|
|
|
|
+ current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
|
|
+ secondpass(third);
|
|
|
|
+ if codegenerror then
|
|
|
|
+ exit;
|
|
|
|
+ if not implicitframe then
|
|
|
|
+ current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
+ reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
|
|
|
|
+ hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
|
|
|
|
+ handle_breakcontinueexit(finallyNoExceptionLabel,false);
|
|
|
|
+
|
|
|
|
+ current_asmdata.CurrAsmList.concatList(tmplist);
|
|
|
|
+ tmplist.free;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,exceptframekind,finallyexceptionstate,excepttemps);
|
|
|
|
+
|
|
{ just free the frame information }
|
|
{ just free the frame information }
|
|
- cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallyexceptionstate.exceptionlabel,true);
|
|
|
|
|
|
+ cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,1,finallyexceptionstate.exceptionlabel,true);
|
|
|
|
|
|
{ end cleanup }
|
|
{ end cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
|
|
@@ -1168,11 +1026,11 @@ implementation
|
|
finally code is unconditionally executed; we do have to filter out
|
|
finally code is unconditionally executed; we do have to filter out
|
|
flags regarding break/contrinue/etc. because we have to give an
|
|
flags regarding break/contrinue/etc. because we have to give an
|
|
error in case one of those is used in the finally-code }
|
|
error in case one of those is used in the finally-code }
|
|
- flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol];
|
|
|
|
|
|
+ flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
|
|
secondpass(right);
|
|
secondpass(right);
|
|
{ goto is allowed if it stays inside the finally block,
|
|
{ goto is allowed if it stays inside the finally block,
|
|
this is checked using the exception block number }
|
|
this is checked using the exception block number }
|
|
- if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol]) then
|
|
|
|
|
|
+ if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
|
|
CGMessage(cg_e_control_flow_outside_finally);
|
|
CGMessage(cg_e_control_flow_outside_finally);
|
|
if codegenerror then
|
|
if codegenerror then
|
|
exit;
|
|
exit;
|
|
@@ -1180,53 +1038,52 @@ implementation
|
|
{ don't generate line info for internal cleanup }
|
|
{ don't generate line info for internal cleanup }
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
|
|
|
|
|
|
- { the value should now be in the exception handler }
|
|
|
|
- reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
|
|
|
|
- hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
|
|
|
|
- if implicitframe then
|
|
|
|
|
|
+ { same level as before try, but this part is only executed if an exception occcurred
|
|
|
|
+ -> always fc_in_flowcontrol }
|
|
|
|
+ flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_catching_exceptions];
|
|
|
|
+ include(flowcontrol,fc_inflowcontrol);
|
|
|
|
+ if not assigned(third) then
|
|
begin
|
|
begin
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
|
|
|
|
- { finally code only needed to be executed on exception (-> in
|
|
|
|
- if-branch -> fc_inflowcontrol) }
|
|
|
|
- flowcontrol:=[fc_inflowcontrol];
|
|
|
|
- if (tf_safecall_exceptions in target_info.flags) and
|
|
|
|
- (current_procinfo.procdef.proccalloption=pocall_safecall) then
|
|
|
|
- handle_safecall_exception
|
|
|
|
|
|
+ { the value should now be in the exception handler }
|
|
|
|
+ reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
|
|
|
|
+ hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
|
|
|
|
+ if implicitframe then
|
|
|
|
+ begin
|
|
|
|
+ hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
|
|
|
|
+ { finally code only needed to be executed on exception (-> in
|
|
|
|
+ if-branch -> fc_inflowcontrol) }
|
|
|
|
+ if (tf_safecall_exceptions in target_info.flags) and
|
|
|
|
+ (current_procinfo.procdef.proccalloption=pocall_safecall) then
|
|
|
|
+ begin
|
|
|
|
+ handle_safecall_exception;
|
|
|
|
+ { we have to jump immediatly as we have to return the value of FPC_SAFECALL }
|
|
|
|
+ hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
|
|
|
|
+ { we have to load 0 into the execepttemp, else the program thinks an exception happended }
|
|
|
|
+ emit_jump_out_of_try_finally_frame(current_asmdata.CurrAsmList,0,finallyexceptionstate.exceptionlabel,excepttemps,exitfinallylabel);
|
|
|
|
+ end
|
|
else
|
|
else
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
|
|
|
|
|
|
+ begin
|
|
|
|
+ handle_breakcontinueexit(finallyexceptionstate.exceptionlabel,true);
|
|
|
|
+ end;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
|
|
|
|
- if fc_exit in finallyexceptionstate.newflowcontrol then
|
|
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
|
|
|
|
- if fc_break in finallyexceptionstate.newflowcontrol then
|
|
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
|
|
|
|
- if fc_continue in finallyexceptionstate.newflowcontrol then
|
|
|
|
- hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
|
|
|
|
- hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
|
|
|
|
- { do some magic for exit,break,continue in the try block }
|
|
|
|
- if fc_exit in finallyexceptionstate.newflowcontrol then
|
|
|
|
|
|
+ if implicitframe then
|
|
begin
|
|
begin
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,2,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
|
|
|
|
- end;
|
|
|
|
- if fc_break in finallyexceptionstate.newflowcontrol then
|
|
|
|
- begin
|
|
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,3,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
|
|
|
|
- end;
|
|
|
|
- if fc_continue in finallyexceptionstate.newflowcontrol then
|
|
|
|
|
|
+ if (tf_safecall_exceptions in target_info.flags) and
|
|
|
|
+ (current_procinfo.procdef.proccalloption=pocall_safecall) then
|
|
|
|
+ handle_safecall_exception
|
|
|
|
+ else
|
|
|
|
+ cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
begin
|
|
begin
|
|
- hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
|
|
|
|
- hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
|
|
|
|
- hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,4,excepttemps.reasonbuf);
|
|
|
|
- hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
|
|
|
|
|
|
+ cexceptionstatehandler.handle_reraise(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate,exceptframekind);
|
|
end;
|
|
end;
|
|
|
|
+
|
|
end;
|
|
end;
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
|
|
hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
|
|
@@ -1244,6 +1101,67 @@ implementation
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
+ function tcgraisenode.pass_1: tnode;
|
|
|
|
+ begin
|
|
|
|
+ if not(tf_use_psabieh in target_info.flags) or assigned(left) then
|
|
|
|
+ result:=inherited
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ expectloc:=LOC_VOID;
|
|
|
|
+ result:=nil;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+{$ifndef jvm}
|
|
|
|
+ { has to be factored out as well }
|
|
|
|
+ procedure tcgraisenode.pass_generate_code;
|
|
|
|
+ var
|
|
|
|
+ CurrentLandingPad, CurrentAction, ReRaiseLandingPad: TPSABIEHAction;
|
|
|
|
+ psabiehprocinfo: tpsabiehprocinfo;
|
|
|
|
+ begin
|
|
|
|
+ if not(tf_use_psabieh in target_info.flags) then
|
|
|
|
+ Internalerror(2019021701);
|
|
|
|
+
|
|
|
|
+ location_reset(location,LOC_VOID,OS_NO);
|
|
|
|
+ CurrentLandingPad:=nil;
|
|
|
|
+ CurrentAction:=nil;
|
|
|
|
+ ReRaiseLandingPad:=nil;
|
|
|
|
+ psabiehprocinfo:=current_procinfo as tpsabiehprocinfo;
|
|
|
|
+ { a reraise must raise the exception to the parent exception frame }
|
|
|
|
+ if fc_catching_exceptions in flowcontrol then
|
|
|
|
+ begin
|
|
|
|
+ psabiehprocinfo.CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
|
|
|
|
+ CurrentLandingPad:=psabiehprocinfo.CurrentLandingPad;
|
|
|
|
+ if psabiehprocinfo.PopLandingPad(CurrentLandingPad) then
|
|
|
|
+ exclude(flowcontrol,fc_catching_exceptions);
|
|
|
|
+ CurrentAction:=psabiehprocinfo.CurrentAction;
|
|
|
|
+ psabiehprocinfo.FinalizeAndPopAction(CurrentAction);
|
|
|
|
+
|
|
|
|
+ if not(fc_catching_exceptions in flowcontrol) then
|
|
|
|
+ begin
|
|
|
|
+ ReRaiseLandingPad:=psabiehprocinfo.NoAction;
|
|
|
|
+ psabiehprocinfo.PushAction(ReRaiseLandingPad);
|
|
|
|
+ psabiehprocinfo.PushLandingPad(ReRaiseLandingPad);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil).resetiftemp;
|
|
|
|
+ if assigned(CurrentLandingPad) then
|
|
|
|
+ begin
|
|
|
|
+ psabiehprocinfo.CreateNewPSABIEHCallsite(current_asmdata.CurrAsmList);
|
|
|
|
+ if not(fc_catching_exceptions in flowcontrol) then
|
|
|
|
+ begin
|
|
|
|
+ psabiehprocinfo.PopLandingPad(psabiehprocinfo.CurrentLandingPad);
|
|
|
|
+ psabiehprocinfo.PopAction(ReRaiseLandingPad);
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ psabiehprocinfo.PushAction(CurrentAction);
|
|
|
|
+ psabiehprocinfo.PushLandingPad(CurrentLandingPad);
|
|
|
|
+ include(flowcontrol,fc_catching_exceptions);
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+{$endif jvm}
|
|
|
|
+
|
|
|
|
+
|
|
begin
|
|
begin
|
|
cwhilerepeatnode:=tcgwhilerepeatnode;
|
|
cwhilerepeatnode:=tcgwhilerepeatnode;
|
|
cifnode:=tcgifnode;
|
|
cifnode:=tcgifnode;
|