[fpc-devel] Newbie question: how does the compiler know the class type of an object ( the Is operator)

Sven Barth pascaldragon at googlemail.com
Fri Aug 22 21:04:06 CEST 2014


On 22.08.2014 19:53, Dennis Poon wrote:
>
>
> 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, at function
INIT$_TVMTPTR:
.globl  TVMTPTR_init
         .type   TVMTPTR_init, at 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, at object
         .size U_TVMTPTR_T,4
U_TVMTPTR_T:
         .zero 4

.section .bss
# [16] b: Boolean;
         .type U_TVMTPTR_B, at 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, at 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, at 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



More information about the fpc-devel mailing list