Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2014-08

Newbie question: how does the compiler know the class type of an object ( the Is operator)

19 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Dennis Poon

I am just curious, what is the instance size of an Tobject?

in many notifyevents, we would test whether an object is actually of a certain class by
if Sender is TComponent then
...
end;

How does the "is" operator work? Is the memory space occupied by that object reference contain a pointer to a class table? If that is true, the minimal instance size of an Tobject is sizeof(pointer)?

Sorry if my question is dumb.

Dennis

Reply by email

Dennis Poon
to Howard Page-Clark
Howard Page-Clark wrote 7 lines
program Project1; uses classes; begin WriteLn('InstanceSize of TObject=',TObject.InstanceSize); ReadLn; end.

I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how does the "as" and "is" get the class type of an object.
So, does that imply the 4 byte is used to store a pointer to the class type and Virtual Method table?

Dennis

Reply by email

Ewald
to Dennis Poon
Dennis Poon wrote 16 lines
Howard Page-Clark wrote: > program Project1; > > uses classes; > begin > WriteLn('InstanceSize of TObject=',TObject.InstanceSize); > ReadLn; > end. I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how does the "as" and "is" get the class type of an object. So, does that imply the 4 byte is used to store a pointer to the class type and Virtual Method table?

Have a look at the documentation concerning TObject.

It's the boilerplate of TObject that does the magic. (at least at runtime, I don't know about compile time optimizations concerning the `as` and `is` operators)

Also, to get a better idea of the size of a TObject in memory, SizeOf(TVmt) will get you started?

Ewald

Reply by email

Sven Barth
to Dennis Poon: I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how…
Dennis Poon wrote 16 lines
Howard Page-Clark wrote: > program Project1; > > uses classes; > begin > WriteLn('InstanceSize of TObject=',TObject.InstanceSize); > ReadLn; > end. I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how does the "as" and "is" get the class type of an object. So, does that imply the 4 byte is used to store a pointer to the class type and Virtual Method table?

Yes. You can see this when looking at the assembler code of a simple example:

=== code begin ===

unit tvmtptr;
{$mode objfpc}
interface
type
   TTest = class
   end;
implementation
var
   t: TObject;
   b: Boolean;
initialization
   t := TTest.Create;
   b := t is TTest;
end.

=== code end ===

Compiling this using "fpc -al tvmtptr.pp" results in assembly code similar to this (i386-linux, only relevant parts):

=== assembly begin ===

# Begin asmlist al_procedures

.section .text
.balign 16,0x90
.globl INIT$_TVMTPTR
.type INIT$_TVMTPTR,@function
INIT$_TVMTPTR:
.globl TVMTPTR_init
.type TVMTPTR_init,@function
TVMTPTR_init:
.Lc1:
# Temps allocated between ebp+0 and ebp+0
# [tvmtptr.pas]
# [17] initialization
pushl %ebp
.Lc3:
.Lc4:
movl %esp,%ebp
.Lc5:
# [18] t := TTest.Create;
movl $VMT_TVMTPTR_TTEST,%edx
movl $0,%eax
call SYSTEM_TOBJECT_$__CREATE$$TOBJECT
movl %eax,U_TVMTPTR_T
# [19] b := t is TTest;
movl U_TVMTPTR_T,%edx
movl $VMT_TVMTPTR_TTEST,%eax
call fpc_do_is
movb %al,U_TVMTPTR_B
# [20] end.
leave
ret
.Lc2:
.Le0:
.size TVMTPTR_init, .Le0 - TVMTPTR_init
# End asmlist al_procedures
# Begin asmlist al_globals

.section .bss
.balign 4
# [15] t: TObject;
.type U_TVMTPTR_T,@object
.size U_TVMTPTR_T,4
U_TVMTPTR_T:
.zero 4

.section .bss
# [16] b: Boolean;
.type U_TVMTPTR_B,@object
.size U_TVMTPTR_B,1
U_TVMTPTR_B:
.zero 1
.section .data
.balign 4
.globl _$TVMTPTR$_Ld1
_$TVMTPTR$_Ld1:
.byte 5
# [21]
.ascii "TTest"

.section .data
.balign 4
.globl VMT_TVMTPTR_TTEST
.type VMT_TVMTPTR_TTEST,@object
VMT_TVMTPTR_TTEST:
.long 4,-4
.long VMT_SYSTEM_TOBJECT
.long _$TVMTPTR$_Ld1
.long 0,0
.long _$TVMTPTR$_Ld2
.long RTTI_TVMTPTR_TTEST
.long 0,0
.long FPC_EMPTYINTF
.long 0
.long SYSTEM_TOBJECT_$__DESTROY
.long SYSTEM_TOBJECT_$__NEWINSTANCE$$TOBJECT
.long SYSTEM_TOBJECT_$__FREEINSTANCE
.long
SYSTEM_TOBJECT_$__SAFECALLEXCEPTION$TOBJECT$POINTER$$HRESULT .long SYSTEM_TOBJECT_$__DEFAULTHANDLER$formal
.long SYSTEM_TOBJECT_$__AFTERCONSTRUCTION
.long SYSTEM_TOBJECT_$__BEFOREDESTRUCTION
.long SYSTEM_TOBJECT_$__DEFAULTHANDLERSTR$formal .long SYSTEM_TOBJECT_$__DISPATCH$formal
.long SYSTEM_TOBJECT_$__DISPATCHSTR$formal
.long SYSTEM_TOBJECT_$__EQUALS$TOBJECT$$BOOLEAN
.long SYSTEM_TOBJECT_$__GETHASHCODE$$LONGINT
.long SYSTEM_TOBJECT_$__TOSTRING$$ANSISTRING
.long 0
.Le1:
.size VMT_TVMTPTR_TTEST, .Le1 - VMT_TVMTPTR_TTEST

.section .data
.balign 4
.globl THREADVARLIST_TVMTPTR
.type THREADVARLIST_TVMTPTR,@object
THREADVARLIST_TVMTPTR:
.long 0
.Le2:
.size THREADVARLIST_TVMTPTR, .Le2 - THREADVARLIST_TVMTPTR # End asmlist al_globals

=== assembly end ===

You can see that the call to TTest.Create (or in this case TObject.Create) passes a pointer to the VMT named VMT_TVMTPTR_TTEST. The constructor will then store this pointer in the first entry of the class instance.
The same VMT pointer (and the instance variable) are then passed to the implementation of the is-operator fpc_do_is (the implementation of the as-operator is fpc_do_as). You can find the corresponding code in $fpcsrc/rtl/inc/objpas.inc)

Regards,
Sven

Reply by email

Andrew Haines
to Dennis Poon: I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how…
Dennis Poon wrote 17 lines
Howard Page-Clark wrote: > program Project1; > > uses classes; > begin > WriteLn('InstanceSize of TObject=',TObject.InstanceSize); > ReadLn; > end. I tried and it says the instancesize is 4 (on win 32 bit). My question actually was how does the "as" and "is" get the class type of an object. So, does that imply the 4 byte is used to store a pointer to the class type and Virtual Method table?

http://www.freepascal.org/docs-html/prog/progsu168.html#x212-2250008.2.13

Table 8.6 is the class instance memory layout and 8.7 is the class vmt which has info on it's name and ancestor classes.

Regards,

Andrew Haines

Reply by email

Dennis Poon
to Andrew Haines
http://www.freepascal.org/docs-html/prog/progsu168.html#x212-2250008.2.13 Table 8.6 is the class instance memory layout and 8.7 is the class vmt which has info on it's name and ancestor classes.

Andrew,

the page says:

8.2.13 Class types
<http://www.freepascal.org/docs-html/prog/prog.html#QQ2-212-239>

Just like objects, classes are stored....

Look like it is referring to a TClass instance instead of an TObject instance but thanks a lot for pointing me into the right direction.

My second newbie question is, in modern day CPUs and fpc compiler, are optimized code generated for fpc program to cleverly use the available registers and instructions to look up method address of an object when the method is called, so that Object oriented language code can now run as fast as procedural languages?

I don't know assembly so cannot tell from the asm generated for the sample program:
# [18] t := TTest.Create;
movl $VMT_TVMTPTR_TTEST,%edx
movl $0,%eax
call SYSTEM_TOBJECT_$__CREATE$$TOBJECT
movl %eax,U_TVMTPTR_T

With modern CPU, can the above 4 lines be further optimized?

Dennis

Show quoted text 14 lines
Regards, Andrew Haines _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel ----- No virus found in this message. Checked by AVG - www.avg.com Version: 2014.0.4745 / Virus Database: 4007/8083 - Release Date: 08/22/14

Reply by email

Ewald
to Dennis Poon
Dennis Poon wrote 8 lines
8.2.13 Class types <http://www.freepascal.org/docs-html/prog/prog.html#QQ2-212-239> Just like objects, classes are stored.... Look like it is referring to a TClass instance instead of an TObject instance but thanks a lot for pointing me into the right direction. \
No, it is referring to the difference between
    Type
        TA = Object
        End;
and
    Type
        TB = Class
        End;

If you type

    Var
           A: TA;
           B: TB;
    Begin
    End;
Then TA is allocated on the stack, whereas TB will be allocated on the
heap once you call TB.Create;
Ewald

Reply by email

Dennis Poon
to Ewald
Ewald wrote 31 lines
On 08/23/2014 11:34 AM, Dennis Poon wrote: > 8.2.13 Class types > <http://www.freepascal.org/docs-html/prog/prog.html#QQ2-212-239> > > Just like objects, classes are stored.... > > Look like it is referring to a TClass instance instead of an TObject > instance but thanks a lot for pointing me into the right direction. \ No, it is referring to the difference between Type TA = Object End; and Type TB = Class End; If you type Var A: TA; B: TB; Begin End; Then TA is allocated on the stack, whereas TB will be allocated on the heap once you call TB.Create;

Oh I see now. The old "object" style used in turbo pascal!

Dennis

Reply by email

Michael Schnell
to Dennis Poon
Dennis Poon wrote
Oh I see now. The old "object" style used in turbo pascal!

Your original question was about TObject.

AFAIK, old style TP "Object" is depreciated and usually can be replaced by records containing methods.

-Michael

Reply by email

Sven Barth
to Michael Schnell
"Michael Schnell" wrote 9 lines
On 08/23/2014 06:17 PM, Dennis Poon wrote: > > > Oh I see now. The old "object" style used in turbo pascal! > Your original question was about TObject. AFAIK, old style TP "Object" is depreciated and usually can be replaced

by records containing methods.

It is *not* deprecated. At least not in FPC. Also unlike records it supports inheritance.

Regards,
Sven

Reply by email

Marco van de Voort
to Sven Barth

In our previous episode, Sven Barth said:

Show quoted text 8 lines
>> Oh I see now. The old "object" style used in turbo pascal! >> > Your original question was about TObject. > > AFAIK, old style TP "Object" is depreciated and usually can be replaced by records containing methods. It is *not* deprecated.

It was flagged as one of the constructs to be removed from the Delphi "Nextgen" compiler. But that was all "looking at".

Afaik the mobile compiler is the fruit of that
project, but I don't have it, haven't tested it, so I don't know if

At least not in FPC. Also unlike records it supports inheritance.

Limited use without dynamic instantiation.

Reply by email

Sven Barth
to Marco van de Voort
"Marco van de Voort" wrote 7 lines
In our previous episode, Sven Barth said: > >> Oh I see now. The old "object" style used in turbo pascal! > >> > > Your original question was about TObject. > > > > AFAIK, old style TP "Object" is depreciated and usually can be

replaced

Show quoted text 6 lines
> by records containing methods. > > It is *not* deprecated. It was flagged as one of the constructs to be removed from the Delphi "Nextgen" compiler. But that was all "looking at".

In Delphi they are to be considered deprecated for a long time already. But I don't care about that as I'm a FPC developer where they aren't deprecated...

Show quoted text 8 lines
Afaik the mobile compiler is the fruit of that project, but I don't have it, haven't tested it, so I don't know if > At least not in FPC. Also unlike records it > supports inheritance. Limited use without dynamic instantiation.

I wouldn't say that. Even without dynamic instantiation it would at least allow for reduced amount of code for structures that share some fields and thus maybe logic...

Regards,
Sven

Reply by email

Marco van de Voort
to Sven Barth

In our previous episode, Sven Barth said:

Show quoted text 6 lines
> It was flagged as one of the constructs to be removed from the Delphi > "Nextgen" compiler. But that was all "looking at". In Delphi they are to be considered deprecated for a long time already. But I don't care about that as I'm a FPC developer where they aren't deprecated...

I don't recommend them for any new code.

Show quoted text 8 lines
> > At least not in FPC. Also unlike records it > > supports inheritance. > > Limited use without dynamic instantiation. I wouldn't say that. Even without dynamic instantiation it would at least allow for reduced amount of code for structures that share some fields and thus maybe logic...

As I said, that is a limited use :_)

But IMHO that's more trying to find uses then anything real. In practice the record functionality superceded them.

In recent years I only used them for things like static iterator objects. And that code had origins before D2006 even, so maybe nowadays I would do that with records.

Reply by email

Marco van de Voort
to Michael Schnell

In our previous episode, Michael Schnell said:

Show quoted text 5 lines
> As I said, that is a limited use :_) > > IMHO, a "static" or similar keyword for a class type definition would nicely allow for doing away with "Object" and "Record" altogether..

IMHO it would bring the "sometimes maps 1:1 to record, sometimes not" misery of object back again, while I would rather have it gone.

Reply by email

Tomas Hajny
to Marco van de Voort
Marco van de Voort wrote
In our previous episode, Michael Schnell said:

Hi,

Show quoted text 9 lines
> > As I said, that is a limited use :_) > > > > > IMHO, a "static" or similar keyword for a class type definition would > nicely allow for doing away with "Object" and "Record" altogether.. IMHO it would bring the "sometimes maps 1:1 to record, sometimes not" misery of object back again, while I would rather have it gone.

Am I right to assume that this thread was not meant to discuss a proposal for getting rid of the TP/BP-style of objects from FPC and thus there is no need of summarizing all pros and cons of keeping or removing them (including their use cases and their potential alternatives)?

Thanks

Tomas

Reply by email

Michael Schnell
to Marco van de Voort: In our previous episode, Michael Schnell said: IMHO it would bring the "sometimes maps…
Marco van de Voort wrote
IMHO it would bring the "sometimes maps 1:1 to record, sometimes not" misery of object back again, while I would rather have it gone.

Some incompatibility easily could occur, if you would remove the dedicated support for Object and Record and use these keywords just as alias for a static class.

Supposedly not worth the risk...

-Michael

Reply by email