* group emitting a label of a try-block and restoring the control flow flags

in a single routine, so that both happen at the same time (needed for LLVM
    where inside a try-block all calls need to be performed using "invoke"
    and refer to the current try-block/catching label)

git-svn-id: trunk@35144 -
This commit is contained in:
Jonas Maebe 2016-12-16 22:41:30 +00:00
parent a1c0d1a1ff
commit c0f4e4db34

View File

@ -529,6 +529,12 @@ implementation
reasonbuf : treference;
end;
texceptionstate = record
exceptionlabel: TAsmLabel;
oldflowcontrol,
newflowcontrol: tflowcontrol;
end;
procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
begin
@ -546,12 +552,16 @@ implementation
end;
procedure new_exception(list:TAsmList;const t:texceptiontemps;exceptlabel:tasmlabel);
procedure 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;
flowcontrol:=[fc_inflowcontrol];
paraloc1.init;
paraloc2.init;
paraloc3.init;
@ -606,11 +616,19 @@ implementation
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,exceptlabel);
hlcg.a_cmp_const_reg_label(list,setjmpres.def,OC_NE,0,tmpresloc.register,exceptstate.exceptionlabel);
setjmpres.resetiftemp;
end;
procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
begin
hlcg.a_label(list,exceptionstate.exceptionlabel);
exceptionstate.newflowcontrol:=flowcontrol;
flowcontrol:=exceptionstate.oldflowcontrol;
end;
procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
var
reasonreg: tregister;
@ -643,14 +661,14 @@ implementation
{ generates code to be executed when another exeception is raised while
control is inside except block }
procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;entrylabel:TAsmLabel);
procedure 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);
hlcg.a_label(list,entrylabel);
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 }
@ -671,26 +689,21 @@ implementation
exittrylabel,
continuetrylabel,
breaktrylabel,
doobjectdestroyandreraise,
oldCurrExitLabel,
oldContinueLabel,
oldBreakLabel : tasmlabel;
oldflowcontrol,tryflowcontrol,
exceptflowcontrol : tflowcontrol;
destroytemps,
excepttemps : texceptiontemps;
trystate,doobjectdestroyandreraisestate: texceptionstate;
label
errorexit;
begin
location_reset(location,LOC_VOID,OS_NO);
exceptflowcontrol:=[];
continuetrylabel:=nil;
breaktrylabel:=nil;
continueexceptlabel:=nil;
breakexceptlabel:=nil;
oldflowcontrol:=flowcontrol;
flowcontrol:=[fc_inflowcontrol];
{ this can be called recursivly }
oldBreakLabel:=nil;
oldContinueLabel:=nil;
@ -715,12 +728,11 @@ implementation
current_asmdata.getjumplabel(continueexceptlabel);
end;
current_asmdata.getjumplabel(exceptlabel);
current_asmdata.getjumplabel(endexceptlabel);
current_asmdata.getjumplabel(lastonlabel);
get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
new_exception(current_asmdata.CurrAsmList,excepttemps,exceptlabel);
new_exception(current_asmdata.CurrAsmList,excepttemps,trystate);
{ try block }
{ set control flow labels for the try block }
@ -731,16 +743,14 @@ implementation
current_procinfo.CurrBreakLabel:=breaktrylabel;
end;
flowcontrol:=[fc_inflowcontrol];
secondpass(left);
tryflowcontrol:=flowcontrol;
if codegenerror then
goto errorexit;
{ don't generate line info for internal cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
hlcg.a_label(current_asmdata.CurrAsmList,exceptlabel);
emit_except_label(current_asmdata.CurrAsmList,trystate);
free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
@ -778,27 +788,30 @@ implementation
if not (has_no_code(t1)) then
begin
current_asmdata.getjumplabel(doobjectdestroyandreraise);
get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
{ the flowcontrol from the default except-block must be merged
with the flowcontrol flags potentially set by the
on-statements handled above (secondpass(right)), as they are
at the same program level }
flowcontrol:=
flowcontrol+
doobjectdestroyandreraisestate.oldflowcontrol;
{ except block needs line info }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
{ here we don't have to reset flowcontrol }
{ the default and on flowcontrols are handled equal }
secondpass(t1);
exceptflowcontrol:=flowcontrol;
handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
end
else
begin
exceptflowcontrol:=flowcontrol;
doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
cleanupobjectstack;
hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
end;
@ -806,10 +819,10 @@ implementation
else
begin
hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
exceptflowcontrol:=flowcontrol;
doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
end;
if fc_exit in exceptflowcontrol 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);
@ -821,7 +834,7 @@ implementation
hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
end;
if fc_break in exceptflowcontrol 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 }
@ -832,7 +845,7 @@ implementation
cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
end;
if fc_continue in exceptflowcontrol 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 }
@ -843,7 +856,7 @@ implementation
hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
end;
if fc_exit in tryflowcontrol 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);
@ -852,7 +865,7 @@ implementation
hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
end;
if fc_break in tryflowcontrol 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);
@ -860,7 +873,7 @@ implementation
cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
end;
if fc_continue in tryflowcontrol 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);
@ -886,8 +899,8 @@ implementation
end;
{ return all used control flow statements }
flowcontrol:=oldflowcontrol+(exceptflowcontrol +
tryflowcontrol - [fc_inflowcontrol]);
flowcontrol:=trystate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol +
trystate.newflowcontrol - [fc_inflowcontrol]);
end;
@ -899,9 +912,8 @@ implementation
breakonlabel,
oldCurrExitLabel,
oldContinueLabel,
doobjectdestroyandreraise,
oldBreakLabel : tasmlabel;
oldflowcontrol : tflowcontrol;
doobjectdestroyandreraisestate: texceptionstate;
excepttemps : texceptiontemps;
href2: treference;
paraloc1 : tcgpara;
@ -919,8 +931,6 @@ implementation
breakonlabel:=nil;
exitonlabel:=nil;
oldflowcontrol:=flowcontrol;
flowcontrol:=[fc_inflowcontrol];
current_asmdata.getjumplabel(nextonlabel);
otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
@ -959,12 +969,10 @@ implementation
end;
{ in the case that another exception is risen
we've to destroy the old one }
current_asmdata.getjumplabel(doobjectdestroyandreraise);
{ call setjmp, and jump to finally label on non-zero result }
we've to destroy the old one:
call setjmp, and jump to finally label on non-zero result }
get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
oldBreakLabel:=nil;
oldContinueLabel:=nil;
@ -986,7 +994,7 @@ implementation
secondpass(right);
end;
handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
{ clear some stuff }
if assigned(exceptvarsym) then
@ -999,21 +1007,21 @@ implementation
if assigned(right) then
begin
{ special handling for control flow instructions }
if fc_exit in flowcontrol then
if fc_exit in doobjectdestroyandreraisestate.newflowcontrol then
begin
{ the address and object pop does secondtryexcept }
cg.a_label(current_asmdata.CurrAsmList,exitonlabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
end;
if fc_break in flowcontrol then
if fc_break in doobjectdestroyandreraisestate.newflowcontrol then
begin
{ the address and object pop does secondtryexcept }
cg.a_label(current_asmdata.CurrAsmList,breakonlabel);
cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
end;
if fc_continue in flowcontrol then
if fc_continue in doobjectdestroyandreraisestate.newflowcontrol then
begin
{ the address and object pop does secondtryexcept }
cg.a_label(current_asmdata.CurrAsmList,continueonlabel);
@ -1030,7 +1038,7 @@ implementation
unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol]);
paraloc1.done;
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
@ -1071,7 +1079,6 @@ implementation
procedure tcgtryfinallynode.pass_generate_code;
var
finallylabel,
endfinallylabel,
exitfinallylabel,
continuefinallylabel,
@ -1079,28 +1086,28 @@ implementation
oldCurrExitLabel,
oldContinueLabel,
oldBreakLabel : tasmlabel;
oldflowcontrol,tryflowcontrol : tflowcontrol;
finallyexceptionstate: texceptionstate;
prefinallyflowcontrol : tflowcontrol;
excepttemps : texceptiontemps;
reasonreg : tregister;
begin
location_reset(location,LOC_VOID,OS_NO);
tryflowcontrol:=[];
oldBreakLabel:=nil;
oldContinueLabel:=nil;
continuefinallylabel:=nil;
breakfinallylabel:=nil;
{ check if child nodes do a break/continue/exit }
oldflowcontrol:=flowcontrol;
flowcontrol:=[fc_inflowcontrol];
current_asmdata.getjumplabel(finallylabel);
current_asmdata.getjumplabel(endfinallylabel);
{ call setjmp, and jump to finally label on non-zero result }
get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
new_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate);
{ the finally block must catch break, continue and exit }
{ statements }
oldCurrExitLabel:=current_procinfo.CurrExitLabel;
if implicitframe then
exitfinallylabel:=finallylabel
exitfinallylabel:=finallyexceptionstate.exceptionlabel
else
current_asmdata.getjumplabel(exitfinallylabel);
current_procinfo.CurrExitLabel:=exitfinallylabel;
@ -1110,8 +1117,8 @@ implementation
oldBreakLabel:=current_procinfo.CurrBreakLabel;
if implicitframe then
begin
breakfinallylabel:=finallylabel;
continuefinallylabel:=finallylabel;
breakfinallylabel:=finallyexceptionstate.exceptionlabel;
continuefinallylabel:=finallyexceptionstate.exceptionlabel;
end
else
begin
@ -1122,15 +1129,10 @@ implementation
current_procinfo.CurrBreakLabel:=breakfinallylabel;
end;
{ call setjmp, and jump to finally label on non-zero result }
get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
new_exception(current_asmdata.CurrAsmList,excepttemps,finallylabel);
{ try code }
if assigned(left) then
begin
secondpass(left);
tryflowcontrol:=flowcontrol;
if codegenerror then
exit;
end;
@ -1138,19 +1140,22 @@ implementation
{ don't generate line info for internal cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
hlcg.a_label(current_asmdata.CurrAsmList,finallylabel);
emit_except_label(current_asmdata.CurrAsmList,finallyexceptionstate);
{ just free the frame information }
free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallylabel,true);
free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallyexceptionstate.exceptionlabel,true);
{ end cleanup }
current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
{ finally code }
flowcontrol:=[fc_inflowcontrol];
{ finally code (don't unconditionally set fc_inflowcontrol, since the
finally code is unconditionally executed; we do have to filter out
flags regarding break/contrinue/etc. because we have to give an
error in case one of those is used in the finally-code }
flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol];
secondpass(right);
{ goto is allowed if it stays inside the finally block,
this is checked using the exception block number }
if (flowcontrol-[fc_gotolabel])<>[fc_inflowcontrol] then
if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol]) then
CGMessage(cg_e_control_flow_outside_finally);
if codegenerror then
exit;
@ -1164,7 +1169,8 @@ implementation
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 }
{ finally code only needed to be executed on exception (-> in
if-branch -> fc_inflowcontrol) }
flowcontrol:=[fc_inflowcontrol];
secondpass(t1);
if flowcontrol<>[fc_inflowcontrol] then
@ -1180,34 +1186,34 @@ implementation
else
begin
hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
if fc_exit in tryflowcontrol then
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 tryflowcontrol then
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 tryflowcontrol then
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 tryflowcontrol then
if fc_exit in finallyexceptionstate.newflowcontrol then
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,finallylabel);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
end;
if fc_break in tryflowcontrol then
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,finallylabel);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
end;
if fc_continue in tryflowcontrol then
if fc_continue in finallyexceptionstate.newflowcontrol then
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,finallylabel);
hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
end;
end;
unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
@ -1222,7 +1228,7 @@ implementation
current_procinfo.CurrContinueLabel:=oldContinueLabel;
current_procinfo.CurrBreakLabel:=oldBreakLabel;
end;
flowcontrol:=oldflowcontrol+(tryflowcontrol-[fc_inflowcontrol]);
flowcontrol:=finallyexceptionstate.oldflowcontrol+(finallyexceptionstate.newflowcontrol-[fc_inflowcontrol]);
end;