[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