Recent

Author Topic: class procedures are not procedures of object !  (Read 3616 times)

guest58172

  • Guest
class procedures are not procedures of object !
« on: November 21, 2015, 02:17:46 am »
Class procedures work without a context pointer. This is well know, for example you won't be able to access a variable that's itself not a class var. However if you take a pointer to a class procedure, a program will allocate a fat pointer made of the entry point (address in process image) and object address (instance of the object). But the second pointer (instance of the object) is totally superfluous.

The problem is that we won't be able to cast a pointer to class procedure as a pointer to a free procedure, even if it's actually one.
We should be able to do it, as shown in this example, the object instance is not needed at all:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$ASMMODE INTEL}
  3. type
  4.   TProc = procedure();
  5.   TTempProc = procedure() of object;
  6.   TFoo = class
  7.     class var a: integer;
  8.     class procedure foo();
  9.   end;
  10.  
  11. var
  12.   proc: TProc;
  13.   tempproc: TTempProc;
  14.   Foo: TFoo;
  15.  
  16. class procedure TFoo.foo();
  17. begin
  18.   writeln('works');
  19.   a := 8;
  20.   writeln(a);
  21. end;
  22.  
  23. function toProc(a: pointer): TProc; assembler;
  24. asm
  25.   {$IFDEF CPU64}
  26.   mov rax, [a];
  27.   {$ELSE}
  28.   mov eax, [a];
  29.   {$ENDIF}
  30. end;
  31.  
  32. begin
  33.   Foo := TFoo.Create;
  34.  
  35.   // not allowed because this returns a procedure of object
  36.   //proc := toProc(@tempproc);
  37.  
  38.   tempproc := @Foo.foo;
  39.   proc := toProc(@tempproc);
  40.  
  41.   proc();
  42.   readln;
  43. end.  
  44.  

So what's the rationale for the pointers to class proc being some pointer to object proc ?
It looks like an error, no ? Do you have a counter example where the cast would be unsafe ?
Otherwise, I'll file an issue.

Blaazen

  • Hero Member
  • *****
  • Posts: 3011
  • POKE 54296,15
    • Eye-Candy Controls
Re: class procedures are not procedures of object !
« Reply #1 on: November 21, 2015, 03:19:35 am »
I simply retyped it and it works, without asm:
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2. {$mode objfpc}{$H+}
  3.  
  4. interface
  5.  
  6. uses
  7.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
  8.  
  9. type
  10.   { TForm1 }
  11.   TForm1 = class(TForm)
  12.     Button1: TButton;
  13.     procedure Button1Click(Sender: TObject);
  14.   private
  15.     { private declarations }
  16.   public
  17.     { public declarations }
  18.   end;
  19.  
  20.   TProc = procedure;
  21.  
  22.   { TFoo }
  23.   TFoo = class
  24.     class procedure cp;
  25.   end;
  26.  
  27. var
  28.   Form1: TForm1;
  29.   p: TProc;
  30.  
  31. implementation
  32.  
  33. {$R *.lfm}
  34.  
  35. { TForm1 }
  36.  
  37. procedure TForm1.Button1Click(Sender: TObject);
  38. begin
  39.   p:=TProc(@Tfoo.cp);
  40.   p;  //click button writes out "Done"
  41. end;
  42.  
  43. { TFoo }
  44.  
  45. class procedure TFoo.cp;
  46. begin
  47.   writeln('Done');
  48. end;
  49.  
  50. end.
Lazarus 2.1.0 r64115 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

guest58172

  • Guest
Re: class procedures are not procedures of object !
« Reply #2 on: November 21, 2015, 09:00:57 am »
I haven't noticed that it worked when taking the pointer from the type (you use @TFoo no @Foo). But there is definitively still two bugs:

- it should work when taking the pointer from Foo. Even if it's an instance, the class proc doesn't become a proc of object.
- it should work without explicit cast.

Code: Pascal  [Select][+][-]
  1. proc := TProc(@TFoo.foo); // ok but should work without explicit cast
  2. proc := TProc(@Foo.foo);  //project1.lpr(40,11) Error: Illegal type conversion: "<class method type of procedure of object;Register>" to "<procedure variable type of procedure;Register>"
  3.  

foo is still a class proc. The compiler should detect this, there's a hole somewhere.

Thaddy

  • Hero Member
  • *****
  • Posts: 10697
Re: class procedures are not procedures of object !
« Reply #3 on: November 21, 2015, 10:53:36 am »
AFAIK Florian fixed something like this last weekend in trunk.
Let's have a quick test:
Code: Pascal  [Select][+][-]
  1. program testme2;
  2. {$mode objfpc}{$H+}
  3. type
  4.   TProc = procedure;
  5.   { TFoo }
  6.   TFoo = class
  7.     class procedure cp; //static;
  8.   end;
  9.  
  10. var
  11.   p: TProc;
  12.  
  13. procedure testmeproc;
  14. begin
  15.   p:=TProc(@Tfoo.cp);
  16.   p;
  17. end;
  18.  
  19. { TFoo }
  20.  
  21. class procedure TFoo.cp;
  22. begin
  23.   writeln('Done');
  24. end;
  25.  
  26. begin
  27.   TestmeProc;
  28.   readln;
  29. end.

Ergo: this is fixed in trunk. I tested with r32385.
« Last Edit: November 21, 2015, 11:00:15 am by Thaddy »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 818
Re: class procedures are not procedures of object !
« Reply #4 on: November 21, 2015, 11:30:50 am »
Class procedures work without a context pointer.
All class methods have a hidden "self" pointer, which is a "class of <classtype>" of the class used to call the class used to invoke it. That is why taking the address of a class method results in a "procedure of object". This self pointer is mainly used when calling virtual class methods.

If you have a class method that you do not want to get a self pointer, you have to declare it as "static;". The bug Thaddy is referring to can be found at http://bugs.freepascal.org/view.php?id=27414 (which means that in current non-trunk versions, getting the address of a static class method *in objfpc mode* still returned a procedure of object, which was wrong).

Thaddy

  • Hero Member
  • *****
  • Posts: 10697
Re: class procedures are not procedures of object !
« Reply #5 on: November 21, 2015, 11:47:30 am »
The case Jonas pointed out is already in my example, but commented out. Just remove the slashes.

 

TinyPortal © 2005-2018