Browse Source

* Changed code generation for assignments of managed types, it now generates a single call to helper procedure (significantly reducing code size) and is handled entirely in firstpass.

git-svn-id: trunk@20118 -
sergei 13 years ago
parent
commit
afb4992113
2 changed files with 54 additions and 65 deletions
  1. 4 36
      compiler/ncgld.pas
  2. 50 29
      compiler/nld.pas

+ 4 - 36
compiler/ncgld.pas

@@ -574,6 +574,9 @@ implementation
          oldflowcontrol : tflowcontrol;
       begin
         location_reset(location,LOC_VOID,OS_NO);
+        { managed types should be handled in firstpass }
+        if is_managed_type(left.resultdef) or is_managed_type(right.resultdef) then
+          InternalError(2012011901);
 
         otlabel:=current_procinfo.CurrTrueLabel;
         oflabel:=current_procinfo.CurrFalseLabel;
@@ -594,31 +597,13 @@ implementation
           loading the left node afterwards can destroy the flags.
         }
         if not(right.expectloc in [LOC_FLAGS,LOC_JUMP]) and
-           (is_managed_type(right.resultdef) or
-            (node_complexity(right)>node_complexity(left))) then
+            (node_complexity(right)>node_complexity(left)) then
          begin
            secondpass(right);
-           { increment source reference counter, this is
-             useless for constants }
-           if is_managed_type(right.resultdef) and
-              not is_constnode(right) then
-            begin
-              location_force_mem(current_asmdata.CurrAsmList,right.location);
-              location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false,sizeof(pint));
-              cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
-            end;
            if codegenerror then
              exit;
 
-           { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
-           { can be false                                             }
            secondpass(left);
-           { decrement destination reference counter }
-           if is_managed_type(left.resultdef) then
-             begin
-               location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
-               cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
-             end;
            if codegenerror then
              exit;
          end
@@ -626,12 +611,6 @@ implementation
          begin
            { calculate left sides }
            secondpass(left);
-           { decrement destination reference counter }
-           if is_managed_type(left.resultdef) then
-             begin
-               location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
-               cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
-             end;
            if codegenerror then
              exit;
 
@@ -641,19 +620,8 @@ implementation
            oldflowcontrol:=flowcontrol;
            include(flowcontrol,fc_lefthandled);
 
-           { left can't be never a 64 bit LOC_REGISTER, so the 3. arg }
-           { can be false                                             }
            secondpass(right);
            flowcontrol:=oldflowcontrol;
-           { increment source reference counter, this is
-             useless for string constants}
-           if is_managed_type(right.resultdef) and
-              (right.nodetype<>stringconstn) then
-             begin
-               location_force_mem(current_asmdata.CurrAsmList,right.location);
-               location_get_data_ref(current_asmdata.CurrAsmList,right.location,href,false,sizeof(pint));
-               cg.g_incrrefcount(current_asmdata.CurrAsmList,right.resultdef,href);
-             end;
 
            if codegenerror then
              exit;

+ 50 - 29
compiler/nld.pas

@@ -702,6 +702,8 @@ implementation
         hp: tnode;
         oldassignmentnode : tassignmentnode;
         hdef: tdef;
+        hs: string;
+        needrtti: boolean;
       begin
          result:=nil;
          expectloc:=LOC_VOID;
@@ -731,6 +733,8 @@ implementation
          if is_managed_type(left.resultdef) then
            include(current_procinfo.flags,pi_do_call);
 
+         needrtti:=false;
+
         if (is_shortstring(left.resultdef)) then
           begin
            if right.resultdef.typ=stringdef then
@@ -748,9 +752,9 @@ implementation
                  firstpass(result);
                  left:=nil;
                  right:=nil;
-                 exit;
                end;
             end;
+            exit;
            end
         { call helpers for composite types containing automated types }
         else if is_managed_type(left.resultdef) and
@@ -790,34 +794,51 @@ implementation
            right:=nil;
            exit;
          end
-        { call helpers for windows widestrings, they aren't ref. counted }
-        else if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resultdef) then
-         begin
-           { The first argument of fpc_widestr_assign is a var parameter. Properties cannot   }
-           { be passed to var or out parameters, because in that case setters/getters are not }
-           { used. Further, if we would allow it in case there are no getters or setters, you }
-           { would need source changes in case these are introduced later on, thus defeating  }
-           { part of the transparency advantages of properties. In this particular case,      }
-           { however:                                                                         }
-           {   a) if there is a setter, this code will not be used since then the assignment  }
-           {      will be converted to a procedure call                                       }
-           {   b) the getter is irrelevant, because fpc_widestr_assign must always decrease   }
-           {      the refcount of the field to which we are writing                           }
-           {   c) source code changes are not required if a setter is added/removed, because  }
-           {      this transformation is handled at compile time                              }
-           {  -> we can remove the nf_isproperty flag (if any) from left, so that in case it  }
-           {     is a property which refers to a field without a setter call, we will not get }
-           {     an error about trying to pass a property as a var parameter                  }
-           exclude(left.flags,nf_isproperty);
-           hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
-               ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
-               nil));
-           result:=ccallnode.createintern('fpc_widestr_assign',hp);
-           firstpass(result);
-           left:=nil;
-           right:=nil;
-           exit;
-         end;
+        { call helpers for pointer-sized managed types }
+        else if is_widestring(left.resultdef) then
+          hs:='fpc_widestr_assign'
+        else if is_ansistring(left.resultdef) then
+          hs:='fpc_ansistr_assign'
+        else if is_unicodestring(left.resultdef) then
+          hs:='fpc_unicodestr_assign'
+        else if is_interfacecom_or_dispinterface(left.resultdef) then
+          hs:='fpc_intf_assign'
+        else if is_dynamic_array(left.resultdef) then
+          begin
+            hs:='fpc_dynarray_assign';
+            needrtti:=true;
+          end
+        else
+          exit;
+
+        { The first argument of these procedures is a var parameter. Properties cannot     }
+        { be passed to var or out parameters, because in that case setters/getters are not }
+        { used. Further, if we would allow it in case there are no getters or setters, you }
+        { would need source changes in case these are introduced later on, thus defeating  }
+        { part of the transparency advantages of properties. In this particular case,      }
+        { however:                                                                         }
+        {   a) if there is a setter, this code will not be used since then the assignment  }
+        {      will be converted to a procedure call                                       }
+        {   b) the getter is irrelevant, because fpc_widestr_assign must always decrease   }
+        {      the refcount of the field to which we are writing                           }
+        {   c) source code changes are not required if a setter is added/removed, because  }
+        {      this transformation is handled at compile time                              }
+        {  -> we can remove the nf_isproperty flag (if any) from left, so that in case it  }
+        {     is a property which refers to a field without a setter call, we will not get }
+        {     an error about trying to pass a property as a var parameter                  }
+        exclude(left.flags,nf_isproperty);
+        hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
+            ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
+            nil));
+        if needrtti then
+          hp:=ccallparanode.create(
+            caddrnode.create_internal(
+              crttinode.create(tstoreddef(left.resultdef),initrtti,rdt_normal)),
+            hp);
+        result:=ccallnode.createintern(hs,hp);
+        firstpass(result);
+        left:=nil;
+        right:=nil;
       end;