Jelajahi Sumber

Values of managed variables are never ever used after decrementing reference on the variable, so there is no point of having a 'decrement reference' as a separate operation. We can always do 'finalize', i.e. clear the contents after decref.
* Modified fpc_ansistr_decr_ref and fpc_widestr_decr_ref so they always zero the pointer passed by reference. Other _decr_ref helpers already do it.
- Removed tcg.g_decrrefcount, calling cg.g_finalize instead.
- finalize_data_node and tcg.g_finalize: removed code generation for zeroing locations, because it is now done by RTL helpers. This further reduces code size.

As a total result of this change and r20118, the size of Lazarus executable is reduced by about 12%.

git-svn-id: trunk@20119 -

sergei 13 tahun lalu
induk
melakukan
06192a8137
7 mengubah file dengan 73 tambahan dan 192 penghapusan
  1. 36 101
      compiler/cgobj.pas
  2. 3 7
      compiler/ncgcal.pas
  3. 2 2
      compiler/ncgutil.pas
  4. 14 44
      compiler/nutils.pas
  5. 14 30
      rtl/i386/i386.inc
  6. 2 4
      rtl/inc/astrings.inc
  7. 2 4
      rtl/inc/ustrings.inc

+ 36 - 101
compiler/cgobj.pas

@@ -446,7 +446,6 @@ unit cgobj;
           procedure g_copyvariant(list : TAsmList;const source,dest : treference);
 
           procedure g_incrrefcount(list : TAsmList;t: tdef; const ref: treference);
-          procedure g_decrrefcount(list : TAsmList;t: tdef; const ref: treference);
           procedure g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation;
             const name: string);
           procedure g_initialize(list : TAsmList;t : tdef;const ref : treference);
@@ -3514,72 +3513,6 @@ implementation
       end;
 
 
-    procedure tcg.g_decrrefcount(list : TAsmList;t: tdef; const ref: treference);
-      var
-        href : treference;
-        decrfunc : string;
-        needrtti : boolean;
-        cgpara1,cgpara2 : TCGPara;
-        tempreg1,tempreg2 : TRegister;
-      begin
-        cgpara1.init;
-        cgpara2.init;
-        paramanager.getintparaloc(pocall_default,1,cgpara1);
-        paramanager.getintparaloc(pocall_default,2,cgpara2);
-        needrtti:=false;
-        if is_interfacecom_or_dispinterface(t) then
-          decrfunc:='FPC_INTF_DECR_REF'
-        else if is_ansistring(t) then
-          decrfunc:='FPC_ANSISTR_DECR_REF'
-         else if is_widestring(t) then
-          decrfunc:='FPC_WIDESTR_DECR_REF'
-         else if is_unicodestring(t) then
-          decrfunc:='FPC_UNICODESTR_DECR_REF'
-         else if is_dynamic_array(t) then
-          begin
-            decrfunc:='FPC_DYNARRAY_DECR_REF';
-            needrtti:=true;
-          end
-         else
-          decrfunc:='';
-         { call the special decr function or the generic decref }
-         if decrfunc<>'' then
-          begin
-            if needrtti then
-             begin
-               reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
-               tempreg2:=getaddressregister(list);
-               a_loadaddr_ref_reg(list,href,tempreg2);
-             end;
-            tempreg1:=getaddressregister(list);
-            a_loadaddr_ref_reg(list,ref,tempreg1);
-            if needrtti then
-              a_load_reg_cgpara(list,OS_ADDR,tempreg2,cgpara2);
-            a_load_reg_cgpara(list,OS_ADDR,tempreg1,cgpara1);
-            paramanager.freecgpara(list,cgpara1);
-            if needrtti then
-              paramanager.freecgpara(list,cgpara2);
-            allocallcpuregisters(list);
-            a_call_name(list,decrfunc,false);
-            deallocallcpuregisters(list);
-          end
-         else
-          begin
-            if is_open_array(t) then
-              InternalError(201103053);
-            reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
-            a_loadaddr_ref_cgpara(list,href,cgpara2);
-            a_loadaddr_ref_cgpara(list,ref,cgpara1);
-            paramanager.freecgpara(list,cgpara1);
-            paramanager.freecgpara(list,cgpara2);
-            allocallcpuregisters(list);
-            a_call_name(list,'FPC_DECREF',false);
-            deallocallcpuregisters(list);
-         end;
-        cgpara2.done;
-        cgpara1.done;
-      end;
-
     procedure tcg.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);
       var
         cgpara1,cgpara2,cgpara3: TCGPara;
@@ -3671,43 +3604,45 @@ implementation
       var
          href : treference;
          cgpara1,cgpara2 : TCGPara;
+         decrfunc : string;
       begin
+        if is_interfacecom_or_dispinterface(t) then
+          decrfunc:='FPC_INTF_DECR_REF'
+        else if is_ansistring(t) then
+          decrfunc:='FPC_ANSISTR_DECR_REF'
+        else if is_widestring(t) then
+          decrfunc:='FPC_WIDESTR_DECR_REF'
+        else if is_unicodestring(t) then
+          decrfunc:='FPC_UNICODESTR_DECR_REF'
+        else if t.typ=variantdef then
+          decrfunc:='FPC_VARIANT_CLEAR'
+        else
+          begin
+            cgpara1.init;
+            cgpara2.init;
+            if is_open_array(t) then
+              InternalError(201103051);
+            paramanager.getintparaloc(pocall_default,1,cgpara1);
+            paramanager.getintparaloc(pocall_default,2,cgpara2);
+            reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
+            a_loadaddr_ref_cgpara(list,href,cgpara2);
+            a_loadaddr_ref_cgpara(list,ref,cgpara1);
+            paramanager.freecgpara(list,cgpara1);
+            paramanager.freecgpara(list,cgpara2);
+            if is_dynamic_array(t) then
+              g_call(list,'FPC_DYNARRAY_CLEAR')
+            else
+              g_call(list,'FPC_FINALIZE');
+            cgpara1.done;
+            cgpara2.done;
+            exit;
+          end;
         cgpara1.init;
-        cgpara2.init;
-         if is_ansistring(t) or
-            is_widestring(t) or
-            is_unicodestring(t) or
-            is_interfacecom_or_dispinterface(t) then
-            begin
-              g_decrrefcount(list,t,ref);
-              a_load_const_ref(list,OS_ADDR,0,ref);
-            end
-         else if t.typ=variantdef then
-           begin
-             paramanager.getintparaloc(pocall_default,1,cgpara1);
-             a_loadaddr_ref_cgpara(list,ref,cgpara1);
-             paramanager.freecgpara(list,cgpara1);
-             allocallcpuregisters(list);
-             a_call_name(list,'FPC_VARIANT_CLEAR',false);
-             deallocallcpuregisters(list);
-           end
-         else
-           begin
-              if is_open_array(t) then
-                InternalError(201103051);
-              paramanager.getintparaloc(pocall_default,1,cgpara1);
-              paramanager.getintparaloc(pocall_default,2,cgpara2);
-              reference_reset_symbol(href,RTTIWriter.get_rtti_label(t,initrtti),0,sizeof(pint));
-              a_loadaddr_ref_cgpara(list,href,cgpara2);
-              a_loadaddr_ref_cgpara(list,ref,cgpara1);
-              paramanager.freecgpara(list,cgpara1);
-              paramanager.freecgpara(list,cgpara2);
-              allocallcpuregisters(list);
-              a_call_name(list,'FPC_FINALIZE',false);
-              deallocallcpuregisters(list);
-           end;
+        paramanager.getintparaloc(pocall_default,1,cgpara1);
+        a_loadaddr_ref_cgpara(list,ref,cgpara1);
+        paramanager.freecgpara(list,cgpara1);
+        g_call(list,decrfunc);
         cgpara1.done;
-        cgpara2.done;
       end;
 
 

+ 3 - 7
compiler/ncgcal.pas

@@ -177,15 +177,11 @@ implementation
                            InternalError(201103063);
                          secondpass(third);
                          cg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef,
-                           href,third.location,'FPC_DECREF_ARRAY');
+                           href,third.location,'FPC_FINALIZE_ARRAY');
                        end;
                    end
-                 else if (resultdef.typ=formaldef) then
-                   { stuff being passed to formal parameter has to be completely cleaned,
-                     because it cannot be initialized at callee side (bug #20962) }
-                   cg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
                  else
-                   cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
+                   cg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
                end;
 
              paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
@@ -397,7 +393,7 @@ implementation
               function since this is code is only executed after the function call has returned }
             if is_managed_type(funcretnode.resultdef) and
                (funcretnode.nodetype<>temprefn) then
-              cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
+              cg.g_finalize(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
 
             case location.loc of
               LOC_REGISTER :

+ 2 - 2
compiler/ncgutil.pas

@@ -1712,10 +1712,10 @@ implementation
                   eldef:=tarraydef(tparavarsym(p).vardef).elementdef;
                   if not assigned(hsym) then
                     internalerror(201003032);
-                  cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_DECREF_ARRAY');
+                  cg.g_array_rtti_helper(list,eldef,href,hsym.initialloc,'FPC_FINALIZE_ARRAY');
                 end
               else
-                cg.g_decrrefcount(list,tparavarsym(p).vardef,href);
+                cg.g_finalize(list,tparavarsym(p).vardef,href);
             end;
          end;
         { open arrays can contain elements requiring init/final code, so the else has been removed here }

+ 14 - 44
compiler/nutils.pas

@@ -626,57 +626,27 @@ implementation
     function finalize_data_node(p:tnode):tnode;
       var
         newstatement : tstatementnode;
+        hs : string;
       begin
         if not assigned(p.resultdef) then
           typecheckpass(p);
+        { 'decr_ref' suffix is somewhat misleading, all these helpers
+          set the passed pointer to nil now }
         if is_ansistring(p.resultdef) then
-          begin
-            result:=internalstatements(newstatement);
-            addstatement(newstatement,ccallnode.createintern('fpc_ansistr_decr_ref',
-                  ccallparanode.create(
-                    ctypeconvnode.create_internal(p,voidpointertype),
-                  nil)));
-            addstatement(newstatement,cassignmentnode.create(
-               ctypeconvnode.create_internal(p.getcopy,voidpointertype),
-               cnilnode.create
-               ));
-          end
+          hs:='fpc_ansistr_decr_ref'
         else if is_widestring(p.resultdef) then
-          begin
-            result:=internalstatements(newstatement);
-            addstatement(newstatement,ccallnode.createintern('fpc_widestr_decr_ref',
-                  ccallparanode.create(
-                    ctypeconvnode.create_internal(p,voidpointertype),
-                  nil)));
-            addstatement(newstatement,cassignmentnode.create(
-               ctypeconvnode.create_internal(p.getcopy,voidpointertype),
-               cnilnode.create
-               ));
-          end
+          hs:='fpc_widestr_decr_ref'
         else if is_unicodestring(p.resultdef) then
-          begin
-            result:=internalstatements(newstatement);
-            addstatement(newstatement,ccallnode.createintern('fpc_unicodestr_decr_ref',
-                  ccallparanode.create(
-                    ctypeconvnode.create_internal(p,voidpointertype),
-                  nil)));
-            addstatement(newstatement,cassignmentnode.create(
-               ctypeconvnode.create_internal(p.getcopy,voidpointertype),
-               cnilnode.create
-               ));
-          end
+          hs:='fpc_unicodestr_decr_ref'
         else if is_interfacecom_or_dispinterface(p.resultdef) then
-          begin
-            result:=internalstatements(newstatement);
-            addstatement(newstatement,ccallnode.createintern('fpc_intf_decr_ref',
-                  ccallparanode.create(
-                    ctypeconvnode.create_internal(p,voidpointertype),
-                  nil)));
-            addstatement(newstatement,cassignmentnode.create(
-               ctypeconvnode.create_internal(p.getcopy,voidpointertype),
-               cnilnode.create
-               ));
-          end
+          hs:='fpc_intf_decr_ref'
+        else
+          hs:='';
+        if hs<>'' then
+          result:=ccallnode.createintern(hs,
+             ccallparanode.create(
+               ctypeconvnode.create_internal(p,voidpointertype),
+               nil))
         else if p.resultdef.typ=variantdef then
           begin
             result:=ccallnode.createintern('fpc_variant_clear',

+ 14 - 30
rtl/i386/i386.inc

@@ -1333,23 +1333,14 @@ function fpc_freemem_x(p:pointer):ptrint; [external name 'FPC_FREEMEM_X'];
 
 Procedure fpc_AnsiStr_Decr_Ref (Var S : Pointer); [Public,Alias:'FPC_ANSISTR_DECR_REF']; compilerproc; nostackframe; assembler;
 asm
-        cmpl $0,(%eax)
-        jne .Ldecr_ref_continue
-        ret
-.Ldecr_ref_continue:
-// Temps allocated between ebp-24 and ebp+0
-        subl    $4,%esp
-// Var S located in register
-// Var l located in register
-        movl    %eax,(%esp)
-// [101] l:=@PAnsiRec(S-FirstOff)^.Ref;
-        movl    (%eax),%edx
-        subl    $8,%edx
-// [102] If l^<0 then exit;
-        cmpl    $0,(%edx)
+        cmpl    $0,(%eax)
+        je      .Lquit
+        pushl   %esi
+        movl    (%eax),%esi
+        subl    $12,%esi           // points to start of allocation
+        movl    $0,(%eax)          // s:=nil
+        cmpl    $0,4(%esi)         // exit if refcount<0
         jl      .Lj3596
-.Lj3603:
-// [104] If declocked(l^) then
   {$ifdef FPC_PIC}
 	pushl	%ebx
         call	fpc_geteipasebx
@@ -1362,27 +1353,20 @@ asm
         cmpl    $0,ismultithread
   {$endif FPC_PIC}
         jne     .Lj3610
-        decl    (%edx)
+        decl    4(%esi)
         je      .Lj3620
-        addl    $4,%esp
-        ret
+        jmp     .Lj3596
 .Lj3610:
-        movl    %edx,%eax
+        leal    4(%esi),%eax
         call    cpudeclocked
         testb   %al,%al
-        je      .Lj3605
+        je      .Lj3596
 .Lj3620:
-        movl    (%esp),%eax
-        movl    (%eax),%eax
-        subl    $12,%eax
+        movl    %esi,%eax
         call    FPC_FREEMEM_X
-        movl    (%esp),%eax
-        movl    $0,(%eax)
-.Lj3618:
-.Lj3605:
 .Lj3596:
-// [107] end;
-        addl $4,%esp
+        popl    %esi
+.Lquit:
 end;
 
 function fpc_truely_ansistr_unique(Var S : Pointer): Pointer; forward;

+ 2 - 4
rtl/inc/astrings.inc

@@ -92,13 +92,11 @@ Begin
     exit;
   { check for constant strings ...}
   p:=PAnsiRec(S-AnsiFirstOff);
+  s:=nil;
   If p^.ref<0 then exit;
   { declocked does a MT safe dec and returns true, if the counter is 0 }
   If declocked(p^.ref) then
-    begin
-      FreeMem(p);
-      s:=nil;
-    end;
+    FreeMem(p);
 end;
 
 {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}

+ 2 - 4
rtl/inc/ustrings.inc

@@ -216,15 +216,13 @@ Begin
     exit;
   { check for constant strings ...}
   p:=PUnicodeRec(S-UnicodeFirstOff);
+  S:=nil;
   if p^.Ref<0 then
     exit;
 
   { declocked does a MT safe dec and returns true, if the counter is 0 }
   if declocked(p^.Ref) then
-    begin
-      FreeMem(p);
-      S:=nil;
-    end;
+    FreeMem(p);
 end;
 
 { alias for internal use }