Skip to content

Commit 5c8f8bb

Browse files
committed
optimized implementation for weak references
1 parent 224d15b commit 5c8f8bb

File tree

1 file changed

+168
-96
lines changed

1 file changed

+168
-96
lines changed

Source/Base/Spring.pas

Lines changed: 168 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ TLazyInitializer = record
19231923

19241924
{$REGION 'Shared smart pointer'}
19251925

1926-
{$IFDEF DELPHIXE6_UP}{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS(DefaultFieldRttiVisibility)}{$ENDIF}
1926+
{$IFDEF DELPHIXE6_UP}{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}{$ENDIF}
19271927

19281928
IShared<T> = reference to function: T;
19291929

@@ -2014,37 +2014,17 @@ THandleFinalizer<T> = class(TInterfacedObject, IShared<T>)
20142014

20152015
{$REGION 'Weak smart pointer'}
20162016

2017-
{$IFDEF DELPHIXE6_UP}{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS(DefaultFieldRttiVisibility)}{$ENDIF}
2018-
2019-
TWeakReference = class abstract(TRefCountedObject)
2020-
private
2021-
fTarget: Pointer;
2022-
class procedure RegisterWeakRef(address: Pointer; instance: Pointer); static;
2023-
class procedure UnregisterWeakRef(address: Pointer; instance: Pointer); static;
2024-
end;
2017+
{$IFDEF DELPHIXE6_UP}{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}{$ENDIF}
20252018

20262019
Weak<T> = record
2027-
strict private type
2028-
IWeakReference = interface
2029-
procedure SetTarget(const value: T);
2030-
end;
2031-
2032-
TWeakReference = class(TWeakReference, IWeakReference)
2033-
private
2034-
procedure SetTarget(const value: T);
2035-
constructor Create(const target: T; var ref: PPointer);
2036-
public
2037-
destructor Destroy; override;
2038-
end;
20392020
strict private
2021+
fReference: IInterface;
20402022
fTarget: PPointer;
2041-
fReference: IWeakReference;
2042-
function GetIsAlive: Boolean;
2023+
function GetIsAlive: Boolean; inline;
20432024
function GetTarget: T;
2044-
procedure SetTarget(const value: T);
20452025
type PT = ^T;
20462026
public
2047-
constructor Create(const target: T);
2027+
constructor Create(const value: T);
20482028

20492029
class operator Implicit(const value: Shared<T>): Weak<T>;
20502030
class operator Implicit(const value: T): Weak<T>;
@@ -2054,10 +2034,49 @@ TWeakReference = class(TWeakReference, IWeakReference)
20542034
class operator NotEqual(const left: Weak<T>; const right: T): Boolean; inline;
20552035

20562036
function TryGetTarget(out target: T): Boolean;
2057-
property Target: T read GetTarget write SetTarget;
2037+
property Target: T read GetTarget;
20582038
property IsAlive: Boolean read GetIsAlive;
20592039
end;
20602040

2041+
Weak = record
2042+
private type
2043+
PReference = ^TReference;
2044+
TReference = record
2045+
private
2046+
Vtable: Pointer;
2047+
RefCount: Integer;
2048+
Target: Pointer;
2049+
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
2050+
function _AddRef: Integer; stdcall;
2051+
function _Release_Obj: Integer; stdcall;
2052+
function _Release_Intf: Integer; stdcall;
2053+
end;
2054+
2055+
PWeakRec = ^TWeakRec;
2056+
TWeakRec = record
2057+
Ref: PReference;
2058+
Target: PPointer;
2059+
end;
2060+
2061+
const
2062+
ObjectReferenceVtable: array[0..2] of Pointer =
2063+
(
2064+
@TReference.QueryInterface,
2065+
@TReference._AddRef,
2066+
@TReference._Release_Obj
2067+
);
2068+
2069+
InterfaceReferenceVtable: array[0..2] of Pointer =
2070+
(
2071+
@TReference.QueryInterface,
2072+
@TReference._AddRef,
2073+
@TReference._Release_Intf
2074+
);
2075+
private
2076+
class procedure MakeFromObject(const value; var result); overload; static;
2077+
class procedure MakeFromInterface(const value; var result); overload; static;
2078+
end;
2079+
20612080
{$RTTI INHERIT
20622081
METHODS(DefaultMethodRttiVisibility)
20632082
FIELDS(DefaultFieldRttiVisibility)
@@ -3896,16 +3915,6 @@ function NopQueryInterface(inst: Pointer; const IID: TGUID; out Obj): HResult; s
38963915
Result := E_NOINTERFACE;
38973916
end;
38983917

3899-
procedure RegisterWeakRef(address: Pointer; const instance: TObject);
3900-
begin
3901-
TWeakReference.RegisterWeakRef(address, instance);
3902-
end;
3903-
3904-
procedure UnregisterWeakRef(address: Pointer; const instance: TObject);
3905-
begin
3906-
TWeakReference.UnregisterWeakRef(address, instance);
3907-
end;
3908-
39093918
{$ENDREGION}
39103919

39113920

@@ -8169,40 +8178,42 @@ class function Shared<T>.GetMake: IShared<T>;
81698178
{$REGION 'Shared'}
81708179

81718180
class procedure Shared.Make(const value: TObject; var result);
8181+
var
8182+
finalizer: PObjectFinalizer absolute result;
81728183
begin
8173-
if Assigned(Pointer(result))
8174-
and (AtomicDecrement(PObjectFinalizer(result).RefCount) = 0) then
8175-
PObjectFinalizer(result).Value.Free
8184+
if Assigned(finalizer) and (AtomicDecrement(finalizer.RefCount) = 0) then
8185+
finalizer.Value.Free
81768186
else
81778187
begin
8178-
GetMem(Pointer(result), SizeOf(TObjectFinalizer));
8179-
PObjectFinalizer(result).Vtable := @Shared.ObjectFinalizerVtable;
8188+
GetMem(finalizer, SizeOf(TObjectFinalizer));
8189+
finalizer.Vtable := @Shared.ObjectFinalizerVtable;
81808190
{$IFDEF AUTOREFCOUNT}
8181-
Pointer(PObjectFinalizer(result).Value) := nil;
8191+
Pointer(finalizer.Value) := nil;
81828192
{$ENDIF}
81838193
end;
8184-
PObjectFinalizer(result).RefCount := 1;
8185-
PObjectFinalizer(result).Value := value;
8194+
finalizer.RefCount := 1;
8195+
finalizer.Value := value;
81868196
end;
81878197

81888198
class procedure Shared.Make(const value: Pointer; typeInfo: PTypeInfo; var result);
8199+
var
8200+
finalizer: PRecordFinalizer absolute result;
81898201
begin
81908202
typeInfo := typeInfo.TypeData.RefType^;
8191-
if Assigned(Pointer(result))
8192-
and (AtomicDecrement(PRecordFinalizer(result).RefCount) = 0) then
8203+
if Assigned(finalizer) and (AtomicDecrement(finalizer.RefCount) = 0) then
81938204
begin
8194-
FinalizeArray(PRecordFinalizer(result).Value, typeInfo, 1);
8195-
FillChar(PRecordFinalizer(result).Value^, typeInfo.TypeData.RecSize, 0);
8196-
FreeMem(PRecordFinalizer(result).Value);
8205+
FinalizeArray(finalizer.Value, typeInfo, 1);
8206+
FillChar(finalizer.Value^, typeInfo.TypeData.RecSize, 0);
8207+
FreeMem(finalizer.Value);
81978208
end
81988209
else
81998210
begin
8200-
GetMem(Pointer(result), SizeOf(TRecordFinalizer));
8201-
PRecordFinalizer(result).Vtable := @Shared.RecordFinalizerVtable;
8211+
GetMem(finalizer, SizeOf(TRecordFinalizer));
8212+
finalizer.Vtable := @Shared.RecordFinalizerVtable;
82028213
end;
8203-
PRecordFinalizer(result).RefCount := 1;
8204-
PRecordFinalizer(result).Value := value;
8205-
PRecordFinalizer(result).TypeInfo := typeInfo;
8214+
finalizer.RefCount := 1;
8215+
finalizer.Value := value;
8216+
finalizer.TypeInfo := typeInfo;
82068217
end;
82078218

82088219
class procedure Shared.Make(typeInfo: PTypeInfo; var result);
@@ -8399,11 +8410,6 @@ procedure TWeakReferences.UnregisterWeakRef(address, instance: Pointer);
83998410
var
84008411
WeakRefInstances: TWeakReferences;
84018412

8402-
{$ENDREGION}
8403-
8404-
8405-
{$REGION 'TWeakReference'}
8406-
84078413
type
84088414
TVirtualClasses = class(Spring.VirtualClass.TVirtualClasses);
84098415

@@ -8416,14 +8422,14 @@ procedure WeakRefFreeInstance(const Self: TObject);
84168422
freeInstance(Self);
84178423
end;
84188424

8419-
class procedure TWeakReference.RegisterWeakRef(address, instance: Pointer);
8425+
procedure RegisterWeakRef(address: Pointer; const instance: TObject);
84208426
begin
84218427
TVirtualClasses.Default.Proxify(instance);
84228428
GetClassData(TObject(instance).ClassType).FreeInstance := WeakRefFreeInstance;
84238429
WeakRefInstances.RegisterWeakRef(address, instance);
84248430
end;
84258431

8426-
class procedure TWeakReference.UnregisterWeakRef(address, instance: Pointer);
8432+
procedure UnregisterWeakRef(address: Pointer; const instance: TObject);
84278433
begin
84288434
WeakRefInstances.UnregisterWeakRef(address, instance);
84298435
end;
@@ -8433,9 +8439,12 @@ class procedure TWeakReference.UnregisterWeakRef(address, instance: Pointer);
84338439

84348440
{$REGION 'Weak<T>'}
84358441

8436-
constructor Weak<T>.Create(const target: T);
8442+
constructor Weak<T>.Create(const value: T);
84378443
begin
8438-
fReference := TWeakReference.Create(target, fTarget);
8444+
case TType.Kind<T> of
8445+
tkClass: Weak.MakeFromObject(value, fReference);
8446+
tkInterface: Weak.MakeFromInterface(value, fReference);
8447+
end;
84398448
end;
84408449

84418450
function Weak<T>.GetIsAlive: Boolean;
@@ -8445,18 +8454,9 @@ function Weak<T>.GetIsAlive: Boolean;
84458454

84468455
function Weak<T>.GetTarget: T;
84478456
begin
8457+
Result := Default(T);
84488458
if Assigned(fReference) then
8449-
Result := PT(fTarget)^
8450-
else
8451-
Result := Default(T);
8452-
end;
8453-
8454-
procedure Weak<T>.SetTarget(const value: T);
8455-
begin
8456-
if Assigned(fReference) then
8457-
fReference.SetTarget(value)
8458-
else
8459-
fReference := TWeakReference.Create(value, fTarget);
8459+
Result := PT(fTarget)^;
84608460
end;
84618461

84628462
function Weak<T>.TryGetTarget(out target: T): Boolean;
@@ -8470,20 +8470,25 @@ function Weak<T>.TryGetTarget(out target: T): Boolean;
84708470

84718471
class operator Weak<T>.Implicit(const value: Shared<T>): Weak<T>;
84728472
begin
8473-
Result.Target := value.Value;
8473+
case TType.Kind<T> of
8474+
tkClass: Weak.MakeFromObject(value.Value, Result.fReference);
8475+
tkInterface: Weak.MakeFromInterface(value.Value, Result.fReference);
8476+
end;
84748477
end;
84758478

84768479
class operator Weak<T>.Implicit(const value: T): Weak<T>;
84778480
begin
8478-
Result.Target := value;
8481+
case TType.Kind<T> of
8482+
tkClass: Weak.MakeFromObject(value, Result.fReference);
8483+
tkInterface: Weak.MakeFromInterface(value, Result.fReference);
8484+
end;
84798485
end;
84808486

84818487
class operator Weak<T>.Implicit(const value: Weak<T>): T;
84828488
begin
8489+
Result := Default(T);
84838490
if Assigned(value.fReference) then
84848491
Result := PT(value.fTarget)^
8485-
else
8486-
Result := Default(T);
84878492
end;
84888493

84898494
class operator Weak<T>.Equal(const left: Weak<T>;
@@ -8507,32 +8512,99 @@ function Weak<T>.TryGetTarget(out target: T): Boolean;
85078512
{$ENDREGION}
85088513

85098514

8510-
{$REGION 'Weak<T>.TWeakReference'}
8515+
{$REGION 'Weak'}
85118516

8512-
constructor Weak<T>.TWeakReference.Create(const target: T; var ref: PPointer);
8517+
class procedure Weak.MakeFromObject(const value; var result);
8518+
var
8519+
rec: PWeakRec;
85138520
begin
8514-
SetTarget(target);
8515-
ref := @fTarget;
8521+
rec := @result;
8522+
if Assigned(rec.Ref) and (AtomicDecrement(rec.Ref.RefCount) = 0) then
8523+
begin
8524+
rec.Ref.RefCount := 1;
8525+
if rec.Ref.Target = Pointer(value) then
8526+
Exit;
8527+
if Assigned(rec.Ref.Target) then
8528+
UnregisterWeakRef(rec.Target, rec.Ref.Target);
8529+
end
8530+
else
8531+
begin
8532+
GetMem(rec.Ref, SizeOf(TReference));
8533+
rec.Ref.Vtable := @Weak.ObjectReferenceVtable;
8534+
rec.Ref.RefCount := 1;
8535+
rec.Target := @rec.Ref.Target;
8536+
end;
8537+
8538+
rec.Ref.Target := Pointer(value);
8539+
if Assigned(rec.Ref.Target) then
8540+
RegisterWeakRef(rec.Target, rec.Ref.Target);
85168541
end;
85178542

8518-
destructor Weak<T>.TWeakReference.Destroy;
8543+
class procedure Weak.MakeFromInterface(const value; var result);
8544+
var
8545+
rec: PWeakRec;
85198546
begin
8520-
SetTarget(Default(T));
8547+
rec := @result;
8548+
if Assigned(rec.Ref) and (AtomicDecrement(rec.Ref.RefCount) = 0) then
8549+
begin
8550+
rec.Ref.RefCount := 1;
8551+
if rec.Ref.Target = Pointer(value) then
8552+
Exit;
8553+
if Assigned(rec.Ref.Target) then
8554+
UnregisterWeakRef(@rec.Ref.Target, IInterface(rec.Ref.Target) as TObject);
8555+
end
8556+
else
8557+
begin
8558+
GetMem(rec.Ref, SizeOf(TReference));
8559+
rec.Ref.Vtable := @Weak.InterfaceReferenceVtable;
8560+
rec.Ref.RefCount := 1;
8561+
rec.Target := @rec.Ref.Target;
8562+
end;
8563+
8564+
rec.Ref.Target := Pointer(value);
8565+
if Assigned(rec.Ref.Target) then
8566+
RegisterWeakRef(@rec.Ref.Target, IInterface(rec.Ref.Target) as TObject);
85218567
end;
85228568

8523-
procedure Weak<T>.TWeakReference.SetTarget(const value: T);
8569+
8570+
{$ENDREGION}
8571+
8572+
8573+
{$REGION 'Weak.TReference'}
8574+
8575+
function Weak.TReference.QueryInterface(const IID: TGUID;
8576+
out Obj): HResult;
85248577
begin
8525-
if Assigned(fTarget) then
8526-
case TType.Kind<T> of
8527-
tkClass: UnregisterWeakRef(@fTarget, fTarget);
8528-
tkInterface: UnregisterWeakRef(@fTarget, IInterface(fTarget) as TObject);
8529-
end;
8530-
fTarget := PPointer(@value)^;
8531-
if Assigned(fTarget) then
8532-
case TType.Kind<T> of
8533-
tkClass: RegisterWeakRef(@fTarget, fTarget);
8534-
tkInterface: RegisterWeakRef(@fTarget, IInterface(fTarget) as TObject);
8535-
end;
8578+
Result := E_NOINTERFACE;
8579+
end;
8580+
8581+
function Weak.TReference._AddRef: Integer;
8582+
begin
8583+
Result := AtomicIncrement(RefCount);
8584+
end;
8585+
8586+
function Weak.TReference._Release_Obj: Integer;
8587+
begin
8588+
Result := AtomicDecrement(RefCount);
8589+
if Result = 0 then
8590+
begin
8591+
if Assigned(Target) then
8592+
UnregisterWeakRef(@Target, Target);
8593+
Target := nil;
8594+
FreeMem(@Self);
8595+
end;
8596+
end;
8597+
8598+
function Weak.TReference._Release_Intf: Integer;
8599+
begin
8600+
Result := AtomicDecrement(RefCount);
8601+
if Result = 0 then
8602+
begin
8603+
if Assigned(Target) then
8604+
UnregisterWeakRef(@Target, IInterface(Target) as TObject);
8605+
Target := nil;
8606+
FreeMem(@Self);
8607+
end;
85368608
end;
85378609

85388610
{$ENDREGION}

0 commit comments

Comments
 (0)