Browse Source

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

Jonas Maebe 8 years ago
parent
commit
c0f4e4db34
1 changed files with 83 additions and 77 deletions
  1. 83 77
      compiler/ncgflw.pas

+ 83 - 77
compiler/ncgflw.pas

@@ -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;