• Welcome to Jose's Read Only Forum 2023.
 

How does a CLASS look like under the Microscope?

Started by Theo Gottwald, August 16, 2008, 01:00:29 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Theo Gottwald

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.