We take this one as example.
I have included same !NOP's so you can more easily find the parts in each part.
This is our CLASS to examine:
CLASS MyClass
INSTANCE Counter AS LONG
INTERFACE MyInterface
INHERIT IUNKNOWN ' inherit the base class
METHOD BumpIt(Inc AS LONG) AS LONG
!NOP
!NOP
!NOP
Temp& = Counter + Inc
INCR Counter
!NOP
!NOP
!NOP
METHOD = Temp&
END METHOD
END INTERFACE
' more interfaces could be implemented here
END CLASS
SUB TestfuncA()
'REGISTER R01 AS dword,R02 AS dword
'#register NONE
LOCAL R01 AS LONG,R02 AS LONG
! NOP
! NOP
DIM Stuff AS MyInterface
LET Stuff = CLASS "MyClass"
! NOP
! NOP
! NOP
! NOP
x& = Stuff.BumpIt(&H99)
! NOP
! NOP
! NOP
EXIT SUB
Laba:
GOSUB Labb
RETURN
Labb:
! NOP
! NOP
RETURN
END SUB
First we take a look on the METHOD from inside the Object:
402502 PUSH ESI
402503 NOP
402504 NOP
402505 NOP
402506 MOV EBX, DWORD PTR [EBP+0C]
402509 MOV EAX, DWORD PTR [EBX]
40250B MOV EBX, DWORD PTR [EBP+08]
40250E MOV EBX, DWORD PTR [EBX+04]
402511 ADD EBX, BYTE 34
402514 ADD EAX, DWORD PTR [EBX]
402516 MOV ESI, EAX
402518 MOV EBX, DWORD PTR [EBP+08]
40251B MOV EBX, DWORD PTR [EBX+04]
40251E ADD EBX, BYTE 34 <- Here we are with the Addition and following the increment
402521 INC DWORD PTR [EBX]
402523 NOP
402524 NOP
402525 NOP
402526 MOV DWORD PTR [EBP+FFFFFF68], ESI
40252C MOV EAX, DWORD PTR [EBP+FFFFFF68]
402532 LEA ESP, DWORD PTR [EBP-0C]
402535 POP EDI
402536 POP ESI
402537 POP EBX
402538 POP EBP
402539 RET NEAR 0008
These are mostly MOV and ADD Istructions. Modern CPU's eat quite some of them each cycle.
Now lets take a look on the call of the Object-Method:
40254D PUSH EBP
40254E MOV EBP, ESP
402550 PUSH EBX
402551 PUSH ESI
402552 PUSH EDI
402553 PUSH DWORD 0000133F
402558 SUB ESP, BYTE 70
40255B PUSH DWORD 0040254D
402560 XOR ESI, ESI
402562 XOR EDI, EDI
402564 PUSH ESI
402565 PUSH ESI
402566 PUSH ESI
402567 PUSH ESI
402568 PUSH ESI
402569 PUSH ESI
40256A PUSH ESI
40256B PUSH ESI
'------------------
40256C NOP
40256D NOP
40256E LEA EBX, DWORD PTR [EBP+FFFFFF60]
402574 PUSH DWORD 2E41253D
402579 PUSH DWORD 1C9369B7
40257E PUSH DWORD 4B025CAF
402583 PUSH DWORD 1D3AFB8B
402588 MOV EDX, DWORD 00407818
40258D CALL L4063A2
402592 MOV EAX, DWORD 00000008
402597 CALL L403AE0
40259C NOP
40259D NOP
40259E NOP
40259F NOP ' Here starts the call to BumpIt
4025A0 PUSH BYTE 00
4025A2 MOV EAX, DWORD 00000099
4025A7 LEA EBX, DWORD PTR [ESP+00]
4025AB PUSH EBX
4025AC MOV DWORD PTR [EBX], EAX
4025AE MOV EBX, DWORD PTR [EBP+FFFFFF60]
4025B4 PUSH EBX
4025B5 MOV EBX, DWORD PTR [EBX]
4025B7 CALL DWORD PTR [EBX+0C] ' This is where the Method is going to be called.
4025BA FLDCW WORD PTR [EBP-10]
4025BD ADD ESP, BYTE 04
4025C0 MOV DWORD PTR [EBP+FFFFFF5C], EAX
4025C6 NOP ' and is here finished
4025C7 NOP
4025C8 NOP
4025C9 JMP L4025D7
4025CE CALL L4025D4
4025D3 RET NEAR
4025D4 NOP
4025D5 NOP
4025D6 RET NEAR
Now we'll compare this to a normal FUNCTION CALL, that is always still possible in PB 9 for highly timecritical things. This is our example-code:
FUNCTION Test(BYVAL x AS LONG) AS LONG
LOCAL Temp&,Counter&
Temp& = Counter + x&
INCR x&
END FUNCTION
SUB TestfuncA()
'REGISTER R01 AS dword,R02 AS dword
'#register NONE
LOCAL R01 AS LONG,R02 AS LONG
! NOP
! NOP
! NOP
! NOP
! NOP
! NOP
x& = Test(&H99)
! NOP
! NOP
! NOP
EXIT SUB
Laba:
GOSUB Labb
RETURN
Labb:
! NOP
! NOP
RETURN
END SUB
And this is the result:
4024BC PUSH EBP
4024BD MOV EBP, ESP
4024BF PUSH EBX
4024C0 PUSH ESI
4024C1 PUSH EDI
4024C2 PUSH DWORD 0000133F
4024C7 SUB ESP, BYTE 70
4024CA PUSH DWORD 004024BC
4024CF XOR ESI, ESI
4024D1 XOR EDI, EDI
4024D3 PUSH ESI
4024D4 PUSH ESI
4024D5 PUSH ESI
4024D6 PUSH ESI
4024D7 PUSH ESI
4024D8 PUSH ESI
4024D9 PUSH ESI ' Das ist der Funktionsteil
4024DA MOV EAX, DWORD PTR [EBP+08]
4024DD ADD EAX, EDI
4024DF MOV ESI, EAX
4024E1 INC DWORD PTR [EBP+08]
4024E4 MOV EAX, DWORD PTR [EBP+FFFFFF68]
4024EA LEA ESP, DWORD PTR [EBP-0C]
4024ED POP EDI
4024EE POP ESI
4024EF POP EBX
4024F0 POP EBP
4024F1 RET NEAR 0004
'****************************************
4024F4 ADD BYTE PTR [EAX], AL
4024F6 ADD BYTE PTR [EAX], AL
4024F8 ADD BYTE PTR [EAX], AL
4024FA ADD BYTE PTR [EAX], AL
4024FC ADD BYTE PTR [EAX], AL
4024FE ADD BYTE PTR [EAX+62], DH
402501 PUSH EBP
402502 MOV EBP, ESP
402504 PUSH EBX
402505 PUSH ESI
402506 PUSH EDI
402507 PUSH DWORD 0000133F
40250C SUB ESP, BYTE 70
40250F PUSH DWORD 00402501
402514 XOR ESI, ESI
402516 XOR EDI, EDI
402518 PUSH ESI
402519 PUSH ESI
40251A PUSH ESI
40251B PUSH ESI
40251C PUSH ESI
40251D PUSH ESI
40251E PUSH ESI
40251F NOP
402520 NOP
402521 NOP
402522 NOP
402523 NOP
402524 NOP
402525 PUSH DWORD 00000099
40252A CALL L4024BC ' <- This is the CAll to the Function, hardcoded adress.
40252F MOV DWORD PTR [EBP+FFFFFF60], EAX
402535 NOP
402536 NOP
402537 NOP
402538 JMP L402546
40253D CALL L402543
402542 RET NEAR
402543 NOP
402544 NOP
402545 RET NEAR
Actually I just leave this uncommented for those who know what it shows.
After all we see that Objects have many abilities that Functions did not have, for this reason there is also a bit more code that has to be executed, on a function call. But its much less then somebody could expect.
What we see is, that the FUNCTION-Call is hardcoded (Adress) while the Adress of the METHOD has to be computed first.
Side note:
In our example we have used Register Variables in the Function, not in the Object, that also makes a bit of the small difference on the FUNCTION / METHOD Side. Actually the bigger difference seems to be on the CALLING side, to get the right adress and then to return the Parameter-Result.
This is a general rule in computing - the more versatile something is - the more code needs to be executed.