Browse Source

* most of tcgcallparanode.secondcallparan's code was moved into two new methods:
secondcallparan_do_secondpass and secondcallparan_after_secondpass. These are
protected methods, meant to be called in secondcallparan's descendants, to
provide alternative parameter handling algorithms (needed for WebAssembly). No
functional changes.

Nikolay Nikolov 10 months ago
parent
commit
e237da95d2
1 changed files with 125 additions and 111 deletions
  1. 125 111
      compiler/ncgcal.pas

+ 125 - 111
compiler/ncgcal.pas

@@ -40,6 +40,9 @@ interface
           procedure push_formal_para;virtual;
           procedure push_copyout_para;virtual;abstract;
           function maybe_push_unused_para:boolean;virtual;
+
+          procedure secondcallparan_do_secondpass;
+          procedure secondcallparan_after_secondpass;
        public
           tempcgpara : tcgpara;
 
@@ -317,127 +320,138 @@ implementation
       end;
 
 
-    procedure tcgcallparanode.secondcallparan;
-      var
-         pushaddr: boolean;
+    procedure tcgcallparanode.secondcallparan_do_secondpass;
       begin
-         if not(assigned(parasym)) then
-           internalerror(200304242);
+        if assigned(fparainit) then
+          secondpass(fparainit);
+        secondpass(left);
+      end;
 
-         { Skip nothingn nodes which are used after disabling
-           a parameter }
-         if (left.nodetype<>nothingn) then
-           begin
-             if assigned(fparainit) then
-               secondpass(fparainit);
-             secondpass(left);
 
-             hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true);
+    procedure tcgcallparanode.secondcallparan_after_secondpass;
+      var
+        pushaddr: boolean;
+      begin
+        hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true);
 
-             paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
+        paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
 
-             { handle varargs first, because parasym is not valid }
-             if (cpf_varargs_para in callparaflags) then
-               begin
-                 if paramanager.push_addr_param(vs_value,left.resultdef,
-                        aktcallnode.procdefinition.proccalloption) then
-                   push_addr_para
-                 else
-                   push_value_para;
-               end
-             { hidden parameters }
-             else if (vo_is_hidden_para in parasym.varoptions) then
-               begin
-                 { don't push a node that already generated a pointer type
-                   by address for implicit hidden parameters }
-                 pushaddr:=(vo_is_funcret in parasym.varoptions) or
-                   { pass "this" in C++ classes explicitly as pointer
-                     because push_addr_param might not be true for them }
-                   (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or
-                    (
-                      (
-                        not(left.resultdef.typ in [pointerdef,classrefdef]) or
-                        (
-                          { allow pointerdefs (as self) to be passed as addr
-                            param if the method is part of a type helper which
-                            extends a pointer type }
-                          (vo_is_self in parasym.varoptions) and
-                          (aktcallnode.procdefinition.owner.symtabletype=objectsymtable) and
-                          (is_objectpascal_helper(tdef(aktcallnode.procdefinition.owner.defowner))) and
-                          (tobjectdef(aktcallnode.procdefinition.owner.defowner).extendeddef.typ=pointerdef)
-                        )
-                      ) and
-                     paramanager.push_addr_param(parasym.varspez,parasym.vardef,
-                         aktcallnode.procdefinition.proccalloption));
-
-                 if pushaddr then
+        { handle varargs first, because parasym is not valid }
+        if (cpf_varargs_para in callparaflags) then
+          begin
+            if paramanager.push_addr_param(vs_value,left.resultdef,
+                   aktcallnode.procdefinition.proccalloption) then
+              push_addr_para
+            else
+              push_value_para;
+          end
+        { hidden parameters }
+        else if (vo_is_hidden_para in parasym.varoptions) then
+          begin
+            { don't push a node that already generated a pointer type
+              by address for implicit hidden parameters }
+            pushaddr:=(vo_is_funcret in parasym.varoptions) or
+              { pass "this" in C++ classes explicitly as pointer
+                because push_addr_param might not be true for them }
+              (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or
+               (
+                 (
+                   not(left.resultdef.typ in [pointerdef,classrefdef]) or
+                   (
+                     { allow pointerdefs (as self) to be passed as addr
+                       param if the method is part of a type helper which
+                       extends a pointer type }
+                     (vo_is_self in parasym.varoptions) and
+                     (aktcallnode.procdefinition.owner.symtabletype=objectsymtable) and
+                     (is_objectpascal_helper(tdef(aktcallnode.procdefinition.owner.defowner))) and
+                     (tobjectdef(aktcallnode.procdefinition.owner.defowner).extendeddef.typ=pointerdef)
+                   )
+                 ) and
+                paramanager.push_addr_param(parasym.varspez,parasym.vardef,
+                    aktcallnode.procdefinition.proccalloption));
+
+            if pushaddr then
+              begin
+                { objects or advanced records could be located in registers if they are the result of a type case, see e.g. webtbs\tw26075.pp }
+                if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
+                  hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
+                push_addr_para
+              end
+            else
+              push_value_para;
+          end
+        { formal def }
+        else if (parasym.vardef.typ=formaldef) then
+          push_formal_para
+        { Normal parameter }
+        else if paramanager.push_copyout_param(parasym.varspez,parasym.vardef,
+                    aktcallnode.procdefinition.proccalloption) then
+          push_copyout_para
+        else
+          begin
+            { don't push a node that already generated a pointer type
+              by address for implicit hidden parameters }
+            if (not(
+                    (vo_is_hidden_para in parasym.varoptions) and
+                    (left.resultdef.typ in [pointerdef,classrefdef])
+                   ) and
+                paramanager.push_addr_param(parasym.varspez,parasym.vardef,
+                    aktcallnode.procdefinition.proccalloption)) and
+                { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
+                not(
+                    is_array_of_const(parasym.vardef) and
+                    is_dynamic_array(left.resultdef)
+                   ) then
+              begin
+                 { Passing a var parameter to a var parameter, we can
+                   just push the address transparently }
+                 if (left.nodetype=loadn) and
+                    (tloadnode(left).is_addr_param_load) then
                    begin
-                     { objects or advanced records could be located in registers if they are the result of a type case, see e.g. webtbs\tw26075.pp }
-                     if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
-                       hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
-                     push_addr_para
+                     if (left.location.reference.index<>NR_NO) or
+                        (left.location.reference.offset<>0) then
+                       internalerror(200410107);
+                     hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),left.location.reference.base,tempcgpara)
                    end
                  else
-                   push_value_para;
-               end
-             { formal def }
-             else if (parasym.vardef.typ=formaldef) then
-               push_formal_para
-             { Normal parameter }
-             else if paramanager.push_copyout_param(parasym.varspez,parasym.vardef,
-                         aktcallnode.procdefinition.proccalloption) then
-               push_copyout_para
-             else
-               begin
-                 { don't push a node that already generated a pointer type
-                   by address for implicit hidden parameters }
-                 if (not(
-                         (vo_is_hidden_para in parasym.varoptions) and
-                         (left.resultdef.typ in [pointerdef,classrefdef])
-                        ) and
-                     paramanager.push_addr_param(parasym.varspez,parasym.vardef,
-                         aktcallnode.procdefinition.proccalloption)) and
-                     { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
-                     not(
-                         is_array_of_const(parasym.vardef) and
-                         is_dynamic_array(left.resultdef)
-                        ) then
                    begin
-                      { Passing a var parameter to a var parameter, we can
-                        just push the address transparently }
-                      if (left.nodetype=loadn) and
-                         (tloadnode(left).is_addr_param_load) then
-                        begin
-                          if (left.location.reference.index<>NR_NO) or
-                             (left.location.reference.offset<>0) then
-                            internalerror(200410107);
-                          hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,cpointerdef.getreusable(left.resultdef),left.location.reference.base,tempcgpara)
-                        end
-                      else
-                        begin
-                          { Force to be in memory }
-                          if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
-                            hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
-                          push_addr_para;
-                        end;
-                   end
-                 else
-                   push_value_para;
-               end;
+                     { Force to be in memory }
+                     if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
+                       hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
+                     push_addr_para;
+                   end;
+              end
+            else
+              push_value_para;
+          end;
+
+        { update return location in callnode when this is the function
+          result }
+        if assigned(parasym) and
+           (
+             { for type helper/record constructor check that it is self parameter }
+             (
+               (vo_is_self in parasym.varoptions) and
+               (aktcallnode.procdefinition.proctypeoption=potype_constructor) and
+               (parasym.vardef.typ<>objectdef)
+             ) or
+             (vo_is_funcret in parasym.varoptions)
+           ) then
+          location_copy(aktcallnode.location,left.location);
+      end;
+
+
+    procedure tcgcallparanode.secondcallparan;
+      begin
+         if not(assigned(parasym)) then
+           internalerror(200304242);
 
-             { update return location in callnode when this is the function
-               result }
-             if assigned(parasym) and
-                (
-                  { for type helper/record constructor check that it is self parameter }
-                  (
-                    (vo_is_self in parasym.varoptions) and
-                    (aktcallnode.procdefinition.proctypeoption=potype_constructor) and
-                    (parasym.vardef.typ<>objectdef)
-                  ) or
-                  (vo_is_funcret in parasym.varoptions)
-                ) then
-               location_copy(aktcallnode.location,left.location);
+         { Skip nothingn nodes which are used after disabling
+           a parameter }
+         if (left.nodetype<>nothingn) then
+           begin
+             secondcallparan_do_secondpass;
+             secondcallparan_after_secondpass;
            end;
 
          { next parameter }