Просмотр исходного кода

* copy arrays passed by value to cdecl routines on the callee side even on
platforms that normally must copy value parameters on the caller side,
because
o if we copy them on the caller side, then the behaviour will be different
compared to other platforms if the called routine is implemented in C
(since they are passed by reference, changes to the array contents will
be visible on other platforms, while they wouldn't be visible if the
copy is made on the caller side)
o if we don't copy them on the caller nor on the callee side, then behaviour
will be different compared to other platforms if the called routine is
implemented in Pascal and modifies the array (since then changes won't be
visible on the caller side, except on platforms that normally perform
the copy on the caller side)

git-svn-id: trunk@29873 -

Jonas Maebe 10 лет назад
Родитель
Сommit
edb3124ae8
4 измененных файлов с 20 добавлено и 13 удалено
  1. 3 3
      compiler/hlcgobj.pas
  2. 5 3
      compiler/ncal.pas
  3. 1 2
      compiler/ncgutil.pas
  4. 11 5
      compiler/pparautl.pas

+ 3 - 3
compiler/hlcgobj.pas

@@ -4665,8 +4665,7 @@ implementation
       { generate copies of call by value parameters, must be done before
         the initialization and body is parsed because the refcounts are
         incremented using the local copies }
-      if not(target_info.system in systems_caller_copy_addr_value_para) then
-        current_procinfo.procdef.parast.SymList.ForEachCall(@g_copyvalueparas,list);
+      current_procinfo.procdef.parast.SymList.ForEachCall(@g_copyvalueparas,list);
 
       if not(po_assembler in current_procinfo.procdef.procoptions) then
         begin
@@ -4693,7 +4692,8 @@ implementation
       list:=TAsmList(arg);
       if (tsym(p).typ=paravarsym) and
          ((vo_has_local_copy in tparavarsym(p).varoptions) or
-          ((is_open_array(tparavarsym(p).vardef) or
+          (not(target_info.system in systems_caller_copy_addr_value_para) and
+           (is_open_array(tparavarsym(p).vardef) or
             is_array_of_const(tparavarsym(p).vardef)) and
            (tparavarsym(p).varspez=vs_value))) then
         begin

+ 5 - 3
compiler/ncal.pas

@@ -949,9 +949,11 @@ implementation
              (parasym.varspez=vs_value)) or
             (cpf_varargs_para in callparaflags)) and
            (left.nodetype<>nothingn) and
-           (not(aktcallnode.procdefinition.proccalloption in cdecl_pocalls) or
-            (left.resultdef.typ<>arraydef)) and
-           paramanager.push_addr_param(vs_value,left.resultdef,
+           not(vo_has_local_copy in parasym.varoptions) and
+           ((not is_open_array(parasym.vardef) and
+             not is_array_of_const(parasym.vardef)) or
+            not(aktcallnode.procdefinition.proccalloption in cdecl_pocalls)) and
+           paramanager.push_addr_param(vs_value,parasym.vardef,
                       aktcallnode.procdefinition.proccalloption) then
           copy_value_by_ref_para;
 

+ 1 - 2
compiler/ncgutil.pas

@@ -1258,8 +1258,7 @@ implementation
         { generate copies of call by value parameters, must be done before
           the initialization and body is parsed because the refcounts are
           incremented using the local copies }
-        if not(target_info.system in systems_caller_copy_addr_value_para) then
-          current_procinfo.procdef.parast.SymList.ForEachCall(@hlcg.g_copyvalueparas,list);
+        current_procinfo.procdef.parast.SymList.ForEachCall(@hlcg.g_copyvalueparas,list);
 {$ifdef powerpc}
         { unget the register that contains the stack pointer before the procedure entry, }
         { which is used to access the parameters in their original callee-side location  }

+ 11 - 5
compiler/pparautl.pas

@@ -331,15 +331,21 @@ implementation
            { We need a local copy for a value parameter when only the
              address is pushed. Open arrays and Array of Const are
              an exception because they are allocated at runtime and the
-             address that is pushed is patched. Arrays passed to cdecl routines
-             also because arrays are treated like pointers in C. }
+             address that is pushed is patched.
+
+             Arrays passed to cdecl routines are special: they are pointers in
+             C and hence must be passed as such. Due to historical reasons, if
+             a cdecl routine is implemented in Pascal, we still make a copy on
+             the callee side. Do this the same on platforms that normally must
+             make a copy on the caller side, as otherwise the behaviour will
+             be different (and less perfomant) for routines implemented in C }
            if (varspez=vs_value) and
               paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
               not(is_open_array(vardef) or
                   is_array_of_const(vardef)) and
-              not(target_info.system in systems_caller_copy_addr_value_para) and
-              (not(pd.proccalloption in cdecl_pocalls) or
-               (vardef.typ<>arraydef)) then
+              (not(target_info.system in systems_caller_copy_addr_value_para) or
+               ((pd.proccalloption in cdecl_pocalls) and
+                (vardef.typ=arraydef))) then
              include(varoptions,vo_has_local_copy);
 
            { needs high parameter ? }