Discussion:
[fpc-devel] FreeInstance
Ryan Joseph
2018-07-31 15:36:18 UTC
Permalink
Looking at the FPC source now and it appears FreeInstance is a hidden method which is not called from the TObject destructor.

Where/how is this method called in the source? I’ve been in the debugger for over an hour and I still can’t find it.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.o
Thorsten Engler
2018-07-31 15:48:01 UTC
Permalink
I don't think it's called anywhere in the source. It's called by the compiler after the destructor has finished. The same way that InitInstance is run before the constructor is called.

This way the memory for the object is already allocated before the first constructor is run (and not only after calling inherited and getting all the way to TObject) and it is only freed after the destructor has completed (so again, you aren't in limbo after calling inherited in the destructor).
-----Original Message-----
Of Ryan Joseph
Sent: Wednesday, 1 August 2018 01:36
Subject: [fpc-devel] FreeInstance
Looking at the FPC source now and it appears FreeInstance is a
hidden method which is not called from the TObject destructor.
Where/how is this method called in the source? I’ve been in the
debugger for over an hour and I still can’t find it.
Regards,
Ryan Joseph
_______________________________________________
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lis
Ryan Joseph
2018-07-31 15:56:54 UTC
Permalink
Post by Thorsten Engler
I don't think it's called anywhere in the source. It's called by the compiler after the destructor has finished. The same way that InitInstance is run before the constructor is called.
then how does it get invoked then? there must be some node added somewhere but I can’t find it.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.fre
Ryan Joseph
2018-07-31 20:29:21 UTC
Permalink
Post by Ryan Joseph
then how does it get invoked then? there must be some node added somewhere but I can’t find it.
I’m still trying to find this with no luck. I suspect there’s a call node added when the compiler detects a destructor was called (maybe in ncal.pas or similar node unit) but I have no idea where. Any ideas?

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/lis
Sven Barth via fpc-devel
2018-08-01 15:17:07 UTC
Permalink
Post by Ryan Joseph
then how does it get invoked then? there must be some node added
somewhere but I can’t find it.
I’m still trying to find this with no luck. I suspect there’s a call node
added when the compiler detects a destructor was called (maybe in ncal.pas
or similar node unit) but I have no idea where. Any ideas?
Search the compiler's source for the string 'FREEINSTANCE'; you'll find two
locations, one in ngenutil and one in psub. The latter is the one you want.

Regards,
Sven
Ryan Joseph
2018-08-01 15:27:45 UTC
Permalink
Search the compiler's source for the string 'FREEINSTANCE'; you'll find two locations, one in ngenutil and one in psub. The latter is the one you want.
Yeah, this is the first place I looked but current_structdef is always nil so it never progresses past that point.

Is this test program not enough to get FreeInstance called?

program test;
var
obj1: TObject;
begin
obj1 := TObject.Create;
obj1.Free;
end.


===========

function generate_bodyexit_block:tnode;
var
srsym : tsym;
para : tcallparanode;
newstatement : tstatementnode;
oldlocalswitches: tlocalswitches;
begin
result:=internalstatements(newstatement);

if assigned(current_structdef) then
begin
{ Don't test self and the vmt here. The reason is that }
{ a constructor already checks whether these are valid }
{ before. Further, in case of TThread the thread may }
{ free the class instance right after AfterConstruction }
{ has been called, so it may no longer be valid (JM) }
oldlocalswitches:=current_settings.localswitches;
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];

{ a destructor needs a help procedure }
if (current_procinfo.procdef.proctypeoption=potype_destructor) then
begin
if is_class(current_structdef) then
begin
srsym:=search_struct_member(current_structdef,'FREEINSTANCE');

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin
Sven Barth via fpc-devel
2018-08-01 21:28:12 UTC
Permalink
On Aug 1, 2018, at 9:17 AM, Sven Barth via fpc-devel <
Search the compiler's source for the string 'FREEINSTANCE'; you'll find
two locations, one in ngenutil and one in psub. The latter is the one you
want.
Yeah, this is the first place I looked but current_structdef is always nil
so it never progresses past that point.
Is this test program not enough to get FreeInstance called?
program test;
var
obj1: TObject;
begin
obj1 := TObject.Create;
obj1.Free;
end.
===========
function generate_bodyexit_block:tnode;
var
srsym : tsym;
para : tcallparanode;
newstatement : tstatementnode;
oldlocalswitches: tlocalswitches;
begin
result:=internalstatements(newstatement);
if assigned(current_structdef) then
begin
{ Don't test self and the vmt here. The reason is that }
{ a constructor already checks whether these are valid }
{ before. Further, in case of TThread the thread may }
{ free the class instance right after AfterConstruction }
{ has been called, so it may no longer be valid (JM) }
oldlocalswitches:=current_settings.localswitches;
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
{ a destructor needs a help procedure }
if (current_procinfo.procdef.proctypeoption=potype_destructor) then
begin
if is_class(current_structdef) then
begin
srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
If you'd look at the code you quoted you'd see that this is only inserted
*inside* a destructor (the check for potype_destructor; current_procinfo is
the currently compiled routine). So, no, your code is not enough. You need
to declare a class with a destructor, then the code would be entered.

Regards,
Sven
Ryan Joseph
2018-08-01 22:21:25 UTC
Permalink
If you'd look at the code you quoted you'd see that this is only inserted *inside* a destructor (the check for potype_destructor; current_procinfo is the currently compiled routine). So, no, your code is not enough. You need to declare a class with a destructor, then the code would be entered.
Now I see what’s happening! I would have caught this before but I had the class in another unit so it was compiled before I ran the debugger and I never got inside the destructor.

Thanks guys.

Regards,
Ryan Joseph

_______________________________________________
fpc-devel maillist - fpc-***@lists.freepascal.org
http://lists.free

Ben Grasset
2018-08-01 16:04:19 UTC
Permalink
Post by Ryan Joseph
Yeah, this is the first place I looked but current_structdef is always
nil so it never progresses past that point.
Post by Ryan Joseph
Is this test program not enough to get FreeInstance called?
You need to declare a class, and give that class at least one method for
current_structdef to ever not be nil at all. You'll only specifically get
to the FreeInstance part after that if it has a destructor.
Ben Grasset
2018-08-01 16:11:00 UTC
Permalink
Forgot to mention a record or object with at least one method will get to
the first part also, but never the FreeInstance part as they can never have
destructors.
Ben Grasset
2018-08-01 13:06:01 UTC
Permalink
I’m still trying to find this with no luck.
Doing a quick search for the word "freeinstance" in the compiler source
shows two places where it looks for a member function with that name in the
global "current_structdef" variable. I'm fairly certain the one you're
looking for is in a function called "generate_bodyexit_block" at line 587
of psub.pas.

https://github.com/graemeg/freepascal/blob/master/compiler/psub.pas#L587
Loading...