Why does the compiler insist that my function is inlined when not?

Why am i getting

[DCC error] ProjectCOWArray.dpr (23): E2426 Inline function must not have asm block

program ProjectCOWArray;

{$APPTYPE CONSOLE}

{$R *.res}

type
  PRefCount = ^TRefCount;
  TRefCount = array[0..1] of integer;


  TCOWArray<T> = record
  private
    fData: TArray<T>;
  private
    procedure IncRefCount;  <<-- not inline  
  end;


{ TCOWArray<T> }

procedure TCOWArray<T>.IncRefCount;
asm
  {$if defined(win32)}
  mov eax,fData;
  lock inc dword ptr [eax - 8];
  {$ifend}
  {$if defined(win64)}
  mov rax,fData;
  lock inc dword ptr[rax -12];
  {$ifend}
end;

begin
end.

Delphi XE2 does not have AtomicIncrement, so how can I solve this problem?
He would like to save the assembler, because otherwise I cannot use the prefix lock, and I do not want to use InterlockedIncrement, because it is a WinAPI function, and I do not need such overhead.

+4
source share
3 answers

, generics . , , . , , .

, InterlockedIncrement, , , Delphi, AtomicIncrement. , , AtomicIncrement, Delphi, . asm. , , , ASM, .

{$IFNDEF AtomicFunctionsAvailable}
function AtomicIncrement(var Target: Integer): Integer;
asm
  ....
end;
{$ENDIF}

, @TLama, TInterlocked System.SyncObjs .

, , . , SetLength(...) , . , :

unit COWArray;

interface

type
  TCOWArray<T> = record
  private
    FItems: TArray<T>;
    function GetLength: Integer;
    procedure SetLength(Value: Integer);
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    class function New(const Values: array of T): TCOWArray<T>; static;
    property Length: Integer read GetLength write SetLength;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

implementation

function TCOWArray<T>.GetLength: Integer;
begin
  Result := System.Length(FItems);
end;

procedure TCOWArray<T>.SetLength(Value: Integer);
begin
  System.SetLength(FItems, Value); // SetLength enforces uniqueness
end;

function TCOWArray<T>.GetItem(Index: Integer): T;
begin
  Result := FItems[Index];
end;

procedure TCOWArray<T>.SetItem(Index: Integer; const Value: T);
begin
  System.SetLength(FItems, System.Length(FItems)); // SetLength enforces uniqueness
  FItems[Index] := Value;
end;

class function TCOWArray<T>.New(const Values: array of T): TCOWArray<T>;
var
  i: Integer;
begin
  System.SetLength(Result.FItems, System.Length(Values));
  for i := 0 to high(Values) do
    Result.FItems[i] := Values[i];
end;

end.
+6

InterlockedIncrement, . . . , . . , .

var
  dummy: TArray<T>;
begin
  dummy := fData; // increment reference count
  Pointer(dummy) := nil; // circumvent decrement
end;

, , .

- :

begin
  Pointer(dummy) := fData;
  // reference count decrements automatically at scope end
end;
+4

Thanks to David for explaining all the important why.

A possible solution is to remove the AtomicIncrement from the shared record and hack.

program ProjectCOWArray;

{$APPTYPE CONSOLE}

{$R *.res}

type
  PRefCount = ^TRefCount;
  TRefCount = array[0..1] of integer;

  TCOWArray<T> = record
  private
    fData: TArray<T>;
  private
    procedure IncRefCount;
  end;

{ TCOWArray<T> }

type TAnyOldDynArray = array of integer;

procedure AtomicIncrementDynArrayRefCount(const AnArray: TAnyOldDynArray);
asm
  {$if defined(win32)}
  mov eax,AnArray;
  lock inc dword ptr [eax - 8];
  {$else}
  mov rax,AnArray;
  lock inc dword ptr [rax -12];
  {$ifend}
end;

procedure TCOWArray<T>.IncRefCount;
begin
  AtomicIncrementDynArrayRefCount(TAnyOldDynArray(fData));
end;

begin
end.
-1
source

Source: https://habr.com/ru/post/1545073/


All Articles