Browse Source

Call the RTL helpers for reference counted classes.

hlcgobj.pas, thlcgobj:
  * g_incrrefcount: call fpc_refcountclass_incr_ref for reference counted classes and pass along the offset to the hidden reference count field
  * g_finalize: call fpc_refcountclass_decr_ref for reference counted classes and pass along the offset to the hidden reference count field
ngenutil.pas, tnodeutils:
  * finalize_data_node: call fpc_refcountclass_decr_ref for reference counted classes and pass along the offset to the hidden reference count field
nld.pas, tassignmentnode:
  * pass_1: call fpc_refcountclass_assign if both sides of the assignment are reference counted classes and neither of them is declared as "weak"; also pass along the offset to the hidden reference count field

git-svn-id: branches/svenbarth/arc@28864 -
svenbarth 10 years ago
parent
commit
41269d6072
3 changed files with 88 additions and 6 deletions
  1. 32 0
      compiler/hlcgobj.pas
  2. 20 4
      compiler/ngenutil.pas
  3. 36 2
      compiler/nld.pas

+ 32 - 0
compiler/hlcgobj.pas

@@ -3054,9 +3054,11 @@ implementation
       incrfunc : string;
       cgpara1,cgpara2 : TCGPara;
       pd : tprocdef;
+      offsetsym : tfieldvarsym;
     begin
        cgpara1.init;
        cgpara2.init;
+       offsetsym:=nil;
        if is_interfacecom_or_dispinterface(t) then
          incrfunc:='fpc_intf_incr_ref'
        else if is_ansistring(t) then
@@ -3067,6 +3069,13 @@ implementation
          incrfunc:='fpc_unicodestr_incr_ref'
        else if is_dynamic_array(t) then
          incrfunc:='fpc_dynarray_incr_ref'
+       else if is_class(t) and (oo_is_reference_counted in tobjectdef(t).objectoptions) then
+         begin
+           incrfunc:='fpc_refcountclass_incr_ref';
+           offsetsym:=tfieldvarsym(tobjectdef(t).refcount_field);
+           if not assigned(offsetsym) or (offsetsym.typ<>fieldvarsym) then
+             internalerror(2014092201);
+         end
        else
         incrfunc:='';
        { call the special incr function or the generic addref }
@@ -3082,6 +3091,12 @@ implementation
             { these functions get the pointer by value }
             a_load_ref_cgpara(list,t,ref,cgpara1);
           paramanager.freecgpara(list,cgpara1);
+          if assigned(offsetsym) then
+            begin
+              paramanager.getintparaloc(pd,2,cgpara2);
+              a_load_const_cgpara(list,s32inttype,offsetsym.fieldoffset,cgpara2);
+              paramanager.freecgpara(list,cgpara2);
+            end;
           g_call_system_proc(list,pd,nil);
         end
        else
@@ -3164,7 +3179,9 @@ implementation
        cgpara1,cgpara2 : TCGPara;
        pd : tprocdef;
        decrfunc : string;
+       offsetsym : tfieldvarsym;
     begin
+      offsetsym:=nil;
       if is_interfacecom_or_dispinterface(t) then
         decrfunc:='fpc_intf_decr_ref'
       else if is_ansistring(t) then
@@ -3175,6 +3192,13 @@ implementation
         decrfunc:='fpc_unicodestr_decr_ref'
       else if t.typ=variantdef then
         decrfunc:='fpc_variant_clear'
+      else if is_class(t) and (oo_is_reference_counted in tobjectdef(t).objectoptions) then
+        begin
+          decrfunc:='fpc_refcountclass_decr_ref';
+          offsetsym:=tfieldvarsym(tobjectdef(t).refcount_field);
+          if not assigned(offsetsym) or (offsetsym.typ<>fieldvarsym) then
+            internalerror(2014092203);
+        end
       else
         begin
           cgpara1.init;
@@ -3209,11 +3233,19 @@ implementation
         end;
       pd:=search_system_proc(decrfunc);
       cgpara1.init;
+      cgpara1.init;
       paramanager.getintparaloc(pd,1,cgpara1);
       a_loadaddr_ref_cgpara(list,t,ref,cgpara1);
       paramanager.freecgpara(list,cgpara1);
+      if assigned(offsetsym) then
+        begin
+          paramanager.getintparaloc(pd,2,cgpara2);
+          a_load_const_cgpara(list,s32inttype,offsetsym.fieldoffset,cgpara2);
+          paramanager.freecgpara(list,cgpara2);
+        end;
       g_call_system_proc(list,pd,nil);
       cgpara1.done;
+      cgpara2.done;
     end;
 
   procedure thlcgobj.g_array_rtti_helper(list: TAsmList; t: tdef; const ref: treference; const highloc: tlocation; const name: string);

+ 20 - 4
compiler/ngenutil.pas

@@ -212,11 +212,14 @@ implementation
   class function tnodeutils.finalize_data_node(p:tnode):tnode;
     var
       hs : string;
+      offsetsym : tfieldvarsym;
+      paranode : tcallparanode;
     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 }
+      offsetsym:=nil;
       if is_ansistring(p.resultdef) then
         hs:='fpc_ansistr_decr_ref'
       else if is_widestring(p.resultdef) then
@@ -225,13 +228,26 @@ implementation
         hs:='fpc_unicodestr_decr_ref'
       else if is_interfacecom_or_dispinterface(p.resultdef) then
         hs:='fpc_intf_decr_ref'
+      else if is_class(p.resultdef) and (oo_is_reference_counted in tobjectdef(p.resultdef).objectoptions) then
+        begin
+          hs:='fpc_refcountclass_decr_ref';
+          offsetsym:=tfieldvarsym(tobjectdef(p.resultdef).refcount_field);
+          if not assigned(offsetsym) or (offsetsym.typ<>fieldvarsym) then
+            internalerror(2014092202);
+        end
       else
         hs:='';
       if hs<>'' then
-        result:=ccallnode.createintern(hs,
-           ccallparanode.create(
-             ctypeconvnode.create_internal(p,voidpointertype),
-             nil))
+        begin
+          paranode:=ccallparanode.create(
+               ctypeconvnode.create_internal(p,voidpointertype),
+               nil);
+          if assigned(offsetsym) then
+            paranode:=ccallparanode.create(
+                        cordconstnode.create(offsetsym.fieldoffset,s32inttype,false),
+                        paranode);
+          result:=ccallnode.createintern(hs,paranode);
+        end
       else if p.resultdef.typ=variantdef then
         begin
           result:=ccallnode.createintern('fpc_variant_clear',

+ 36 - 2
compiler/nld.pas

@@ -754,12 +754,30 @@ implementation
 
 
     function tassignmentnode.pass_1 : tnode;
+
+      function is_weak_var(node:tnode):boolean;
+        var
+          actnode : tnode;
+        begin
+          result:=true;
+          actnode:=actualtargetnode(@node)^;
+          if (actnode.nodetype=loadn) and
+              (tloadnode(actnode).symtableentry.typ in [localvarsym,staticvarsym,paravarsym]) and
+              (vo_is_weakref in tabstractvarsym(tloadnode(actnode).symtableentry).varoptions) then
+            exit;
+          if (actnode.nodetype=subscriptn) and
+              (vo_is_weakref in tsubscriptnode(actnode).vs.varoptions) then
+            exit;
+          result:=false;
+        end;
+
       var
-        hp: tnode;
+        hp : tnode;
         oldassignmentnode : tassignmentnode;
         hdef: tdef;
         hs: string;
         needrtti: boolean;
+        offsetsym : tfieldvarsym;
       begin
          result:=nil;
          expectloc:=LOC_VOID;
@@ -790,6 +808,7 @@ implementation
            include(current_procinfo.flags,pi_do_call);
 
          needrtti:=false;
+         offsetsym:=nil;
 
         if (is_shortstring(left.resultdef)) then
           begin
@@ -817,6 +836,7 @@ implementation
             (left.resultdef.typ in [arraydef,objectdef,recorddef]) and
             not is_interfacecom_or_dispinterface(left.resultdef) and
             not is_dynamic_array(left.resultdef) and
+            not is_class(left.resultdef) and
             not(target_info.system in systems_garbage_collected_managed_types) then
          begin
            hp:=ccallparanode.create(caddrnode.create_internal(
@@ -869,6 +889,15 @@ implementation
                 hs:='fpc_dynarray_assign';
                 needrtti:=true;
               end
+            else if is_class(left.resultdef) and (oo_is_reference_counted in tobjectdef(left.resultdef).objectoptions) then
+              begin
+                if is_weak_var(left) or is_weak_var(right) then
+                  exit;
+                hs:='fpc_refcountclass_assign';
+                offsetsym:=tfieldvarsym(tobjectdef(left.resultdef).refcount_field);
+                if not assigned(offsetsym) or (offsetsym.typ<>fieldvarsym) then
+                  internalerror(2014092205);
+              end
             else
               exit;
           end
@@ -898,7 +927,12 @@ implementation
           hp:=ccallparanode.create(
             caddrnode.create_internal(
               crttinode.create(tstoreddef(left.resultdef),initrtti,rdt_normal)),
-            hp);
+            hp)
+        else
+          if assigned(offsetsym) then
+            hp:=ccallparanode.create(
+                  cordconstnode.create(offsetsym.fieldoffset,s32inttype,false),
+                  hp);
         result:=ccallnode.createintern(hs,hp);
         firstpass(result);
         left:=nil;