Recent

Author Topic: Is This A Leak?  (Read 4652 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 9183
Re: Is This A Leak?
« Reply #30 on: October 18, 2019, 03:33:45 pm »
It depends of course on register width and available instruction set.
also related to equus asinus.

ASerge

  • Hero Member
  • *****
  • Posts: 1411
Re: Is This A Leak?
« Reply #31 on: October 18, 2019, 06:09:05 pm »
A normal parameter is read/write just like a var-parameter is, but the caller (not the callee) creates a copy of the value.
As far as I know.

The external code passes parameters:
TypeNo prefixconstconstrefvarout
SimpleDirectDirectAddressAddressAddress
Complex but fit in SimpleDirectAddressAddressAddressAddress
Complex largeAddressAddressAddressAddressAddress
Pointer or classDirectDirectAddressAddressAddress
Pointer of managed typeDirectDirectAddressAddressAddress, but first dec ref

The code inside the procedure (actions are performed regardless of whether the parameter is changing or not):
TypeNo prefixconstconstrefvarout
SimpleNothingNothingNothingNothingNothing
Complex but fit in SimpleMake copyNothingNothingNothingNothing
Complex largeMake copyNothingNothingNothingNothing
Pointer/classNothingNothingNothingNothingNothing
Pointer of managed typeInc/Dec Ref+try/finallyNothingNothingNothingZeroing original or P^ := nil

Code to verify this (add/remove prefix and see asm):
Code: Pascal  [Select]
  1. program Project1;
  2. {$MODE OBJFPC}
  3. {$APPTYPE CONSOLE}
  4.  
  5. type
  6.   TA4 = packed record
  7.     A1, A2, A3, A4: Byte
  8.   end;
  9.  
  10. procedure UseByte(B: Byte);
  11. begin
  12.   Writeln(B);
  13. end;
  14.  
  15. procedure Test(A: TA4; constref B: UInt32; constref S: AnsiString);
  16. begin
  17.   UseByte(A.A1);
  18.   UseByte(B);
  19. end;
  20.  
  21. var
  22.   A: TA4 = (A1:0; A2:0; A3:0; A4:0);
  23.   B: UInt32 = 0;
  24.   S: AnsiString = '';
  25. begin
  26.   Test(A, B, S);
  27.   Readln;
  28. end.

PascalDragon

  • Hero Member
  • *****
  • Posts: 673
  • Compiler Developer
Re: Is This A Leak?
« Reply #32 on: October 19, 2019, 01:24:15 pm »
"In Free Pascal all non-trivial objects are passed by reference". True. But basically it's just a matter of bandwidth. It's cheaper to send a reference, so references are what get sent. And when you stick "var" in front of it, the called function has read / write access. If you leave the "var" out, then it's just read access. (Let's forget about "const" for the time being)

Now - at runtime - if the called function tries to modify a "no var" (read only) reference then the called function creates a local copy and uses the local copy for its local purposes. And this local copy disappears and its resources get freed when the called function exits.

So the take away for me is that objects are routinely passed as references. No need to declare (class& object) in the parameters. "Var" in the parameters means "non const". Not sure what "const" means. It's kinda covered by the absence of "var". So it must have some other meaning to the compiler.
Not quite correct. A normal parameter is read/write just like a var-parameter is, but the caller (not the callee) creates a copy of the value.

Oh boy. I initially agreed with this take. For several hours. Until that other guy mentioned that it was reference counted. Which I'm guessing means that no "deep" copies happen until there is an actual need - until one of the variables becomes different from the shared reference. And I'm assuming that the change that triggers the deep copy (the copy that gets modified) usually occurs "inside" the called function. The caller remains isolated from what's going on in the called function (because of "no var"), and continues to reference the original data. It seems inefficient for the caller to always create a deep copy (and pass a reference to it) when there are often cases in which no deep copy is ever needed.
Only few types are reference counted, namely strings and interfaces. So for the majority the general rules apply that I mentioned before. For reference counted types the compiler increases the reference count before passing such a variable to a normal parameter and then passing in the string/interface variable as is. For var-parameters and friends the reference count is not increased before the call.

Sometimes it also depends on the size whether a record is passed as reference or a direct copy (e.g. a copy of a record of size 4 could be passed directly inside a register).
That makes perfect sense. if it fits in a register and it is passed by value, it should be passed in a register (if there any still available, of course.)  I presume that in the case of a record of size 4, that implies one (1) field of size 4 and, if there were two fields whose combined size was 4 then two (2) registers would be used, correct ?
If the combined size is indeed 4 it will probably be passed in one register. But in the end it depends on the ABI as well.

del

  • Full Member
  • ***
  • Posts: 113
Re: Is This A Leak?
« Reply #33 on: November 01, 2019, 10:08:53 am »
And the answer is ... (envelope please) ...

No - it is NOT a leak. According to my new coding weapon, Heaptrc.