Quellcode durchsuchen

Check for refcount = 1 first.

Rika Ichinose vor 5 Monaten
Ursprung
Commit
900b1fc4ec
5 geänderte Dateien mit 39 neuen und 37 gelöschten Zeilen
  1. 1 1
      rtl/i386/i386.inc
  2. 19 16
      rtl/inc/astrings.inc
  3. 1 1
      rtl/inc/dynarr.inc
  4. 15 16
      rtl/inc/objpas.inc
  5. 3 3
      rtl/inc/ustrings.inc

+ 1 - 1
rtl/i386/i386.inc

@@ -2907,8 +2907,8 @@ asm
         jz      .Lquit
         movl    $0,(%eax)          // s:=nil
         cmpl    $1,-8(%edx)        // exit if refcount<1
-        jl      .Lquit
         je      .Lfree             // skip the decrement if refcount=1.
+        jl      .Lquit
   {$ifdef FPC_PIC}
         call	fpc_geteipasecx
         addl	$_GLOBAL_OFFSET_TABLE_,%ecx

+ 19 - 16
rtl/inc/astrings.inc

@@ -123,9 +123,9 @@ Begin
   If p=Nil then
     exit;
   s:=nil;
-  If (PAnsiRec(p-AnsiFirstOff)^.ref>0) and { ref = -1 is constant string. }
-     ((PAnsiRec(p-AnsiFirstOff)^.ref=1) { Shortcut declocked on ref = 1. }
-      or declocked(PAnsiRec(p-AnsiFirstOff)^.ref)) then
+  If (PAnsiRec(p-AnsiFirstOff)^.ref=1) or { Shortcut declocked on ref = 1. }
+     (PAnsiRec(p-AnsiFirstOff)^.ref>0) { ref = -1 is constant string. }
+     and declocked(PAnsiRec(p-AnsiFirstOff)^.ref) then
     FreeMem(p-AnsiFirstOff);
 end;
 {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
@@ -138,11 +138,8 @@ Procedure fpc_ansistr_decr_ref (Var S : Pointer); [external name 'FPC_ANSISTR_DE
 {$define FPC_SYSTEM_HAS_ANSISTR_INCR_REF}
 Procedure fpc_AnsiStr_Incr_Ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF'];  compilerproc; inline;
 Begin
-  If S=Nil then
-    exit;
-  { Let's be paranoid : Constant string ??}
-  If PAnsiRec(S-AnsiFirstOff)^.Ref<0 then exit;
-  inclocked(PAnsiRec(S-AnsiFirstOff)^.Ref);
+  If (S<>Nil) and (PAnsiRec(S-AnsiFirstOff)^.Ref>0) then
+    inclocked(PAnsiRec(S-AnsiFirstOff)^.Ref);
 end;
 {$endif FPC_SYSTEM_HAS_ANSISTR_DECR_REF}
 
@@ -156,16 +153,22 @@ Procedure fpc_AnsiStr_Assign (Var DestS : Pointer;S2 : Pointer);[Public,Alias:'F
 {
   Assigns S2 to S1 (S1:=S2), taking in account reference counts.
 }
+var
+  old : Pointer;
 begin
-  if DestS=S2 then
+  old:=DestS;
+  if old=S2 then
     exit;
-  If S2<>nil then
-    If PAnsiRec(S2-AnsiFirstOff)^.Ref>0 then
-      inclocked(PAnsiRec(S2-AnsiFirstOff)^.Ref);
-  { Decrease the reference count on the old S1 }
-  fpc_ansistr_decr_ref (DestS);
-  { And finally, have DestS pointing to S2 (or its copy) }
-  DestS:=S2;
+  DestS:=S2; { Doing this early frees the DestS register. }
+  { Inlined incr_ref(S2). }
+  If (S2<>nil) and (PAnsiRec(S2-AnsiFirstOff)^.Ref>0) then
+    inclocked(PAnsiRec(S2-AnsiFirstOff)^.Ref);
+  { Inlined decr_ref(old). }
+  If (old<>nil) and
+     ((PAnsiRec(old-AnsiFirstOff)^.ref=1) or { Shortcut declocked on ref = 1. }
+      (PAnsiRec(old-AnsiFirstOff)^.ref>0) { ref = -1 is constant string. }
+      and declocked(PAnsiRec(old-AnsiFirstOff)^.ref)) then
+    FreeMem(old-AnsiFirstOff);
 end;
 {$endif FPC_HAS_ANSISTR_ASSIGN}
 

+ 1 - 1
rtl/inc/dynarr.inc

@@ -86,7 +86,7 @@ procedure fpc_dynarray_clear(var p : pointer;ti : pointer); [Public,Alias:'FPC_D
     if not assigned(pv) then
       exit;
     p:=nil;
-    if (pv[-1].refcount>0) and ((pv[-1].refcount=1) or declocked(pv[-1].refcount)) then
+    if (pv[-1].refcount=1) or (pv[-1].refcount>0) and declocked(pv[-1].refcount) then
       begin
         ti:=pdynarraytypedata(aligntoqword(ti+2+PByte(ti)[1]))^.elType;
         if assigned(ti) then

+ 15 - 16
rtl/inc/objpas.inc

@@ -1172,33 +1172,32 @@ end;
 
       begin
          _addref:=frefcount;
-         if _addref>0 then
-           _addref:=interlockedincrement(frefcount)
-         else if _addref=0 then
+         if _addref<>0 then
            begin
-             frefcount:=1; { Work non-atomically in the common case of refcount = 0 (typical state after the complete object construction). }
-             _addref:=1;
+             if _addref>0 then
+               _addref:=interlockedincrement(frefcount);
+             exit;
            end;
+         frefcount:=1; { Work non-atomically in the common case of refcount = 0 (typical state after the complete object construction). }
+         _addref:=1;
       end;
 
     function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
 
       begin
          _Release:=frefcount;
-         if _Release<=0 then { -1 means recursive call from destructor... 0 is impossible. }
-           exit;
-         if _Release=1 then
+         if _Release<>1 then
            begin
-             _Release:=0; { Work non-atomically in the common case of refcount = 1 (typical state for the last owner... which is often the only owner). }
-             frefcount:=0;
+             if _Release<=0 then { -1 means recursive call from destructor... 0 is impossible. }
+               exit;
+             _Release:=interlockeddecrement(frefcount);
+             if _Release>0 then
+               exit;
            end
          else
-           _Release:=interlockeddecrement(frefcount);
-         if _Release=0 then
-           begin
-             frefcount:=-1; { Prevent recursive _Release from destroying twice (bug 32168). }
-             self.destroy;
-           end;
+           _Release:=0; { Work non-atomically in the common case of refcount = 1 (typical state for the last owner... which is often the only owner). }
+         frefcount:=-1; { Prevent recursive _Release from destroying twice (bug 32168). }
+         self.destroy;
       end;
 
    destructor TInterfacedObject.Destroy;

+ 3 - 3
rtl/inc/ustrings.inc

@@ -195,9 +195,9 @@ Begin
   If p=Nil then
     exit;
   s:=nil;
-  If (PUnicodeRec(p-UnicodeFirstOff)^.ref>0) and { ref = -1 is constant string. }
-     ((PUnicodeRec(p-UnicodeFirstOff)^.ref=1) { Shortcut declocked on ref = 1. }
-      or declocked(PUnicodeRec(p-UnicodeFirstOff)^.ref)) then
+  If (PUnicodeRec(p-UnicodeFirstOff)^.ref=1) or { Shortcut declocked on ref = 1. }
+     (PUnicodeRec(p-UnicodeFirstOff)^.ref>0) { ref = -1 is constant string. }
+     and declocked(PUnicodeRec(p-UnicodeFirstOff)^.ref) then
     FreeMem(p-UnicodeFirstOff);
 end;