Browse Source

* extracted exception state handling helpers into a utility class so
they can be overridden

git-svn-id: trunk@35156 -

Jonas Maebe 8 years ago
parent
commit
3ae1f6664a
1 changed files with 90 additions and 65 deletions
  1. 90 65
      compiler/ncgflw.pas

+ 90 - 65
compiler/ncgflw.pas

@@ -27,7 +27,9 @@ unit ncgflw;
 interface
 interface
 
 
     uses
     uses
-      aasmbase,node,nflw,ncgutil;
+      globtype,
+      aasmbase,aasmdata,node,nflw,
+      pass_2,cgutils,ncgutil;
 
 
     type
     type
        tcgwhilerepeatnode = class(twhilerepeatnode)
        tcgwhilerepeatnode = class(twhilerepeatnode)
@@ -72,6 +74,36 @@ interface
        tcgraisenode = class(traisenode)
        tcgraisenode = class(traisenode)
        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)
           procedure pass_generate_code;override;
           procedure pass_generate_code;override;
        end;
        end;
@@ -85,17 +117,21 @@ interface
           procedure pass_generate_code;override;
           procedure pass_generate_code;override;
        end;
        end;
 
 
+
+     var
+       cexceptionstatehandler: tcgexceptionstatehandlerclass;
+
 implementation
 implementation
 
 
     uses
     uses
       cutils,
       cutils,
-      verbose,globals,systems,globtype,constexp,
-      symconst,symdef,symsym,symtable,symtype,aasmtai,aasmdata,aasmcpu,defutil,
-      procinfo,cgbase,pass_2,parabase,
+      verbose,globals,systems,constexp,
+      symconst,symdef,symsym,symtable,symtype,aasmtai,aasmcpu,defutil,
+      procinfo,cgbase,parabase,
       fmodule,
       fmodule,
       cpubase,ncon,
       cpubase,ncon,
       tgobj,paramgr,
       tgobj,paramgr,
-      cgutils,cgobj,hlcgobj,nutils
+      cgobj,hlcgobj,nutils
       ;
       ;
 
 
 {*****************************************************************************
 {*****************************************************************************
@@ -506,7 +542,7 @@ implementation
 
 
 
 
 {*****************************************************************************
 {*****************************************************************************
-                   Exception management
+                     tcgexceptionstatehandler
 *****************************************************************************}
 *****************************************************************************}
 
 
     {  Allocate the buffers for exception management and setjmp environment.
     {  Allocate the buffers for exception management and setjmp environment.
@@ -522,21 +558,9 @@ implementation
        routine has been called, therefore on machines where the stack cannot
        routine has been called, therefore on machines where the stack cannot
        be modified, all temps should be allocated on the heap instead of the
        be modified, all temps should be allocated on the heap instead of the
        stack. }
        stack. }
-     type
-       texceptiontemps=record
-         jmpbuf,
-         envbuf,
-         reasonbuf  : treference;
-       end;
-
-      texceptionstate = record
-        exceptionlabel: TAsmLabel;
-        oldflowcontrol,
-        newflowcontrol: tflowcontrol;
-      end;
 
 
 
 
-    procedure get_exception_temps(list:TAsmList;var t:texceptiontemps);
+    class procedure tcgexceptionstatehandler.get_exception_temps(list:TAsmList;var t:texceptiontemps);
      begin
      begin
         tg.gethltemp(list,rec_exceptaddr,rec_exceptaddr.size,tt_persistent,t.envbuf);
         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,rec_jmp_buf,rec_jmp_buf.size,tt_persistent,t.jmpbuf);
@@ -544,7 +568,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps);
+    class procedure tcgexceptionstatehandler.unget_exception_temps(list:TAsmList;const t:texceptiontemps);
       begin
       begin
         tg.Ungettemp(list,t.jmpbuf);
         tg.Ungettemp(list,t.jmpbuf);
         tg.ungettemp(list,t.envbuf);
         tg.ungettemp(list,t.envbuf);
@@ -552,7 +576,7 @@ implementation
       end;
       end;
 
 
 
 
-    procedure new_exception(list:TAsmList;const t:texceptiontemps; out exceptstate: texceptionstate);
+    class procedure tcgexceptionstatehandler.new_exception(list:TAsmList;const t:texceptiontemps; out exceptstate: texceptionstate);
       var
       var
         paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
         paraloc1, paraloc2, paraloc3, pushexceptres, setjmpres: tcgpara;
         pd: tprocdef;
         pd: tprocdef;
@@ -621,15 +645,15 @@ implementation
      end;
      end;
 
 
 
 
-    procedure emit_except_label(list: TAsmList; var exceptionstate: texceptionstate);
+    class procedure tcgexceptionstatehandler.emit_except_label(list: TAsmList; var exceptstate: texceptionstate);
       begin
       begin
-        hlcg.a_label(list,exceptionstate.exceptionlabel);
-        exceptionstate.newflowcontrol:=flowcontrol;
-        flowcontrol:=exceptionstate.oldflowcontrol;
+        hlcg.a_label(list,exceptstate.exceptionlabel);
+        exceptstate.newflowcontrol:=flowcontrol;
+        flowcontrol:=exceptstate.oldflowcontrol;
       end;
       end;
 
 
 
 
-    procedure free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
+    class procedure tcgexceptionstatehandler.free_exception(list:TAsmList;const t:texceptiontemps;a:aint;endexceptlabel:tasmlabel;onlyfree:boolean);
       var
       var
         reasonreg: tregister;
         reasonreg: tregister;
       begin
       begin
@@ -643,25 +667,16 @@ implementation
       end;
       end;
 
 
 
 
-
-{*****************************************************************************
-                             SecondTryExcept
-*****************************************************************************}
-
-    var
-       endexceptlabel : tasmlabel;
-
-
     { does the necessary things to clean up the object stack }
     { does the necessary things to clean up the object stack }
     { in the except block                                    }
     { in the except block                                    }
-    procedure cleanupobjectstack;
+    class procedure tcgexceptionstatehandler.cleanupobjectstack;
       begin
       begin
          hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
          hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
       end;
       end;
 
 
     { generates code to be executed when another exeception is raised while
     { generates code to be executed when another exeception is raised while
       control is inside except block }
       control is inside except block }
-    procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;var entrystate: texceptionstate);
+    class procedure tcgexceptionstatehandler.handle_nested_exception(list:TAsmList;const t:texceptiontemps;var entrystate: texceptionstate);
       var
       var
          exitlabel: tasmlabel;
          exitlabel: tasmlabel;
       begin
       begin
@@ -678,6 +693,15 @@ implementation
       end;
       end;
 
 
 
 
+
+{*****************************************************************************
+                             SecondTryExcept
+*****************************************************************************}
+
+    var
+       endexceptlabel : tasmlabel;
+
+
     procedure tcgtryexceptnode.pass_generate_code;
     procedure tcgtryexceptnode.pass_generate_code;
 
 
       var
       var
@@ -693,8 +717,8 @@ implementation
          oldContinueLabel,
          oldContinueLabel,
          oldBreakLabel : tasmlabel;
          oldBreakLabel : tasmlabel;
          destroytemps,
          destroytemps,
-         excepttemps : texceptiontemps;
-         trystate,doobjectdestroyandreraisestate: texceptionstate;
+         excepttemps : tcgexceptionstatehandler.texceptiontemps;
+         trystate,doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
       label
       label
          errorexit;
          errorexit;
       begin
       begin
@@ -731,8 +755,8 @@ implementation
          current_asmdata.getjumplabel(endexceptlabel);
          current_asmdata.getjumplabel(endexceptlabel);
          current_asmdata.getjumplabel(lastonlabel);
          current_asmdata.getjumplabel(lastonlabel);
 
 
-         get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
-         new_exception(current_asmdata.CurrAsmList,excepttemps,trystate);
+         cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
+         cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,trystate);
 
 
          { try block }
          { try block }
          { set control flow labels for the try block }
          { set control flow labels for the try block }
@@ -750,9 +774,9 @@ 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));
 
 
-         emit_except_label(current_asmdata.CurrAsmList,trystate);
+         cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,trystate);
 
 
-         free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
+         cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList, excepttemps, 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));
@@ -788,8 +812,8 @@ implementation
 
 
               if not (has_no_code(t1)) then
               if not (has_no_code(t1)) then
                begin
                begin
-                 get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
-                 new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
+                 cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
+                 cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
                  { 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
@@ -804,15 +828,15 @@ implementation
 
 
                  secondpass(t1);
                  secondpass(t1);
 
 
-                 handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
+                 cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraisestate);
 
 
-                 unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
+                 cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
                  hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
                  hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
                end
                end
                else
                else
                  begin
                  begin
                    doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
                    doobjectdestroyandreraisestate.newflowcontrol:=flowcontrol;
-                   cleanupobjectstack;
+                   cexceptionstatehandler.cleanupobjectstack;
                    hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
                    hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
                  end;
                  end;
            end
            end
@@ -830,7 +854,7 @@ implementation
               { exception object                                    }
               { exception object                                    }
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
-              cleanupobjectstack;
+              cexceptionstatehandler.cleanupobjectstack;
               hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
               hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
            end;
            end;
 
 
@@ -841,7 +865,7 @@ implementation
               { exception object                                    }
               { exception object                                    }
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
-              cleanupobjectstack;
+              cexceptionstatehandler.cleanupobjectstack;
               cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
               cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
            end;
            end;
 
 
@@ -852,7 +876,7 @@ implementation
               { exception object                                    }
               { exception object                                    }
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
-              cleanupobjectstack;
+              cexceptionstatehandler.cleanupobjectstack;
               hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
               hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
            end;
            end;
 
 
@@ -880,7 +904,7 @@ implementation
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
               hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
               cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
               cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
            end;
            end;
-         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);
 
 
          { end cleanup }
          { end cleanup }
@@ -913,8 +937,8 @@ implementation
          oldCurrExitLabel,
          oldCurrExitLabel,
          oldContinueLabel,
          oldContinueLabel,
          oldBreakLabel : tasmlabel;
          oldBreakLabel : tasmlabel;
-         doobjectdestroyandreraisestate: texceptionstate;
-         excepttemps : texceptiontemps;
+         doobjectdestroyandreraisestate: tcgexceptionstatehandler.texceptionstate;
+         excepttemps : tcgexceptionstatehandler.texceptiontemps;
          href2: treference;
          href2: treference;
          paraloc1 : tcgpara;
          paraloc1 : tcgpara;
          exceptvarsym : tlocalvarsym;
          exceptvarsym : tlocalvarsym;
@@ -971,8 +995,8 @@ implementation
          { in the case that another exception is risen
          { in the case that another exception is risen
            we've to destroy the old one:
            we've to destroy the old one:
            call setjmp, and jump to finally label on non-zero result }
            call setjmp, and jump to finally label on non-zero result }
-         get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
-         new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
+         cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
+         cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
 
 
          oldBreakLabel:=nil;
          oldBreakLabel:=nil;
          oldContinueLabel:=nil;
          oldContinueLabel:=nil;
@@ -994,7 +1018,7 @@ implementation
               secondpass(right);
               secondpass(right);
            end;
            end;
 
 
-         handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
+         cexceptionstatehandler.handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraisestate);
 
 
          { clear some stuff }
          { clear some stuff }
          if assigned(exceptvarsym) then
          if assigned(exceptvarsym) then
@@ -1036,7 +1060,7 @@ implementation
                end;
                end;
            end;
            end;
 
 
-         unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
+         cexceptionstatehandler.unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
          cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
          cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
          flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol]);
          flowcontrol:=doobjectdestroyandreraisestate.oldflowcontrol+(doobjectdestroyandreraisestate.newflowcontrol-[fc_inflowcontrol]);
          paraloc1.done;
          paraloc1.done;
@@ -1086,9 +1110,9 @@ implementation
          oldCurrExitLabel,
          oldCurrExitLabel,
          oldContinueLabel,
          oldContinueLabel,
          oldBreakLabel : tasmlabel;
          oldBreakLabel : tasmlabel;
-         finallyexceptionstate: texceptionstate;
+         finallyexceptionstate: tcgexceptionstatehandler.texceptionstate;
          prefinallyflowcontrol : tflowcontrol;
          prefinallyflowcontrol : tflowcontrol;
-         excepttemps : texceptiontemps;
+         excepttemps : tcgexceptionstatehandler.texceptiontemps;
          reasonreg : tregister;
          reasonreg : tregister;
       begin
       begin
          location_reset(location,LOC_VOID,OS_NO);
          location_reset(location,LOC_VOID,OS_NO);
@@ -1100,8 +1124,8 @@ implementation
          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 }
-         get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
-         new_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate);
+         cexceptionstatehandler.get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
+         cexceptionstatehandler.new_exception(current_asmdata.CurrAsmList,excepttemps,finallyexceptionstate);
 
 
          { the finally block must catch break, continue and exit }
          { the finally block must catch break, continue and exit }
          { statements                                            }
          { statements                                            }
@@ -1140,9 +1164,9 @@ 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));
 
 
-         emit_except_label(current_asmdata.CurrAsmList,finallyexceptionstate);
+         cexceptionstatehandler.emit_except_label(current_asmdata.CurrAsmList,finallyexceptionstate);
          { just free the frame information }
          { just free the frame information }
-         free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallyexceptionstate.exceptionlabel,true);
+         cexceptionstatehandler.free_exception(current_asmdata.CurrAsmList,excepttemps,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));
@@ -1216,7 +1240,7 @@ implementation
                   hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
                   hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallyexceptionstate.exceptionlabel);
                end;
                end;
            end;
            end;
-         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);
 
 
          { end cleanup }
          { end cleanup }
@@ -1245,5 +1269,6 @@ begin
    ctryexceptnode:=tcgtryexceptnode;
    ctryexceptnode:=tcgtryexceptnode;
    ctryfinallynode:=tcgtryfinallynode;
    ctryfinallynode:=tcgtryfinallynode;
    connode:=tcgonnode;
    connode:=tcgonnode;
+   cexceptionstatehandler:=tcgexceptionstatehandler;
 end.
 end.