[fpc-devel] Proof of Concept ARC implementation

Sven Barth pascaldragon at googlemail.com
Fri Oct 24 23:23:33 CEST 2014


Hello together!

I've now finished my Proof of Concept ARC implementation which is based 
on the RFC I published a few weeks back: 
http://lists.freepascal.org/fpc-devel/2014-September/034263.html

To recap:
- there are no reference counted classes by default, but reference 
counting can be introduced to sub hierarchies by declaring a class as 
"refcounted"
- only variables with a static type of those "refcounted" classes will 
experience reference counting and thus IncRef/DecRef calls
- a class instance is destroyed once the reference count reaches zero 
(and Free does not work for them)
- variables/paremeters/fields can be declared as "weak" which disables 
reference counting for them
- all variables/parameters/fields that are of a non reference counted 
class type are implicitely assumed as "weak" (also "self" is assumed as 
"weak")
- TObject is extended with methods to allow manual reference counting 
and to determine whether an instance is reference counted

Please keep in mind that this is a proof of concept implementation to 
have something on which further discussions can be based on, thus there 
can still be bugs here and there (that said: the testsuite completes 
without regressions). Also it's nowhere said that this will be merged to 
trunk as is in the future.

The code is available here: 
http://svn.freepascal.org/svn/fpc/branches/svenbarth/arc

And here is a test program (and compiled with -gh no leaks are reported 
;) ):

=== code begin ===

program trefcounted;

{$mode objfpc}

type
   TTest = class refcounted // a parent class would follow immediately 
after "refcounted" like for "sealed" and "abstract"
     Field: LongInt;
     constructor Create;
     destructor Destroy; override;
     procedure IncField;
   end;

   TTest2 = class
     Test1: TTest;
     Test2: TTest weak;
     Test3: TTest;
     constructor Create(aTest1: TTest; aTest2: TTest weak);
   end;

   TTest3 = class(TTest)
   end;

   TTestRec = record
     NonWeak: TTest;
     IsWeak: TTest weak;
   end;

constructor TTest.Create;
begin
   Field := $1234ABCD;
end;

destructor TTest.Destroy;
begin
   Writeln(ClassName, '.Destroy');
   inherited;
end;

procedure TTest.IncField;
begin
   Inc(Field);
end;

constructor TTest2.Create(aTest1: TTest; aTest2: TTest weak);
begin
   Test1 := aTest1;
   Test2 := aTest2;
   Test3 := TTest.Create;
end;

procedure TestValue(aTest: TTest);
begin
   Writeln(aTest.ARCRefCount);
end;

procedure TestConst(const aTest: TTest);
begin
   Writeln(aTest.ARCRefCount);
end;

procedure TestVar(var aTest: TTest);
begin
   Writeln(aTest.ARCRefCount);
end;

procedure TestWeak(aTest: TTest weak);
begin
   Writeln(aTest.ARCRefCount);
end;

function TestWeakResult(aTest: TTest weak): TTest weak;
begin
   Result := aTest;
end;

procedure Test;
var
   t: TTest;
   t2: TTest;
   o: TObject;
   t3: TTest weak;
begin
   Writeln('Test');
   Writeln(HexStr(Pointer(t)));
   t := TTest.Create;
   Writeln(HexStr(t));
   Writeln('Before TTest assignment: ', t.ARCRefCount);
   t2 := t;
   Writeln('Before TObject assignment: ', t.ARCRefCount);
   o := t;
   Writeln('Before weak assignment: ', t.ARCRefCount);
   t3 := t;
   Writeln('Before TestValue: ', t.ARCRefCount);
   TestValue(t);
   Writeln('Before TestConst: ', t.ARCRefCount);
   TestConst(t);
   Writeln('Before TestVar: ', t.ARCRefCount);
   TestVar(t);
   Writeln('Before TestWeak: ', t.ARCRefCount);
   TestWeak(t);
   Writeln('Before TestWeakResult: ', t.ARCRefCount);
   t2 := TestWeakResult(t);
   Writeln('Before IncField: ', t.ARCRefCount);
   t.IncField;
end;

procedure Test2;
var
   r, r2: TTestRec;
begin
   Writeln('Test2');
   Writeln(HexStr(Pointer(r.NonWeak)), ' ', HexStr(Pointer(r.IsWeak)));
   r.NonWeak := TTest.Create;
   Writeln('After create: ', r.NonWeak.ARCRefCount);
   r.IsWeak := r.NonWeak;
   Writeln('After weak assignment: ', r.NonWeak.ARCRefCount);
   r2 := r;
   Writeln('After record assignment: ', r.NonWeak.ARCRefCount);
   r.NonWeak := Nil;
   Writeln('After nil: ', r2.NonWeak.ARCRefCount);
end;

procedure Test3;
var
   t, t1: TTest;
   t2: TTest2;
begin
   Writeln('Test3');
   t := TTest.Create;
   t1 := TTest.Create;
   t2 := TTest2.Create(t, t1);
   Writeln('t: ', t.ARCRefCount, ' t1: ', t1.ARCRefCount);
   t2.Free;
   Writeln('t: ', t.ARCRefCount, ' t1: ', t1.ARCRefCount);
end;

procedure Test4;
var
   t: TTest;
   t2, t1: TTest3;
begin
   Writeln('Test4');
   t2 := TTest3.Create;
   Writeln('t2: ', t2.ARCRefCount);
   t := t2;
   Writeln('t2: ', t2.ARCRefCount);
   t1 := t2;
   Writeln('t2: ', t2.ARCRefCount);
   t := Nil;
   Writeln('t2: ', t2.ARCRefCount);
end;

begin
   Test;
   Test2;
   Test3;
   Test4;
   Writeln('Done');
end.

=== code end ===

Regards,
Sven


More information about the fpc-devel mailing list