; Listing6-1.asm
;
; A program that demonstrates classes in MASM.

            option     casemap:none
            include    aoaTypes.inc
            include    aoaMacros.inc
            include    aoaClasses.inc
            include    aoalib.inc
            includelib aoalib.lib
            
            .const

; Program title:

             align  word
ttlStr       byte   "Listing 6-1", 0

; Class names for to the class objects:

myClassName  byte   "myClass", 0
myClass2Name byte   "myClass2", 0


                         
; Sample class type declarations:
;
; myClass is a base class (not derived
; from any other class).

class myClass
onHeap      byte    ?
className   qword   ?
            virtual myFunc
            virtual myFunc2
endc myClass

; The "this" pointer for myClass:

myClass@    textequ <(myClass ptr [rsi])>



; myClass2 is derived from myClass.
;
; It adds a new data field ("c").
; It adds a new virtual method ("myFunc3")
; It overrides the myFunc2 method in the
; base class (replacing it with myFunc2a).


class myClass2, inherits(myClass)
c           byte    ?
            virtual myFunc3
            override myFunc2, myClass2$myFunc2
endc myClass2

; The "this" pointer for myClass2:

myClass2@   textequ <(myClass2 ptr [rsi])>

            
            .data

; Allocate storage for two objects of the
; two class types above:

mc1         myClass  {}
mc2         myClass2 {}
mc3         qword    ?      ;Ptr to myClass2


            .const
            
; Emit the VMTs for these classes.

            emitVMT myClass
            emitVMT myClass2
            
            
            
            
            .code

; Here are the four methods for the two classes:

; myClass$myFunc:

myClass$myFunc    proc
                  push    rdx
                  mov     rdx, myClass@.className
                  call    print
                  byte    "In %s:myClass$myFunc", nl, 0
                  pop     rdx
                  ret
myClass$myFunc    endp


; myClass$myFunc2:

myClass$myFunc2   proc
                  push    rdx
                  mov     rdx, myClass@.className
                  call    print
                  byte    "In %s:myClass$myFunc2", nl, 0
                  pop     rdx
                  ret
myClass$myFunc2   endp


; myClass2$myFunc2 -- override2 myClass$myFunc2:

myClass2$myFunc2  proc
                  push  rdx
                  mov   rdx, myClass2@.className
                  call  print
                  byte  "In %s:myClass2$myFunc2(ovr)", nl
                  byte  "Calling super->myFunc2", nl, 0
            
; Demonstrate how to call the "super" myFunc2
; function (myClass$myFunc2) from within this method.
; RSI points at the current object (which is fine)
; but we have to use the VMT for myClass (the parent,
; or super, class) when calling myFunc2

                  inv   myClass2, myFunc2, rsi, super

                  pop   rdx
                  ret
myClass2$myFunc2  endp


; myClass2.myFunc3:

myClass2$myFunc3  proc
                  push    rdx
                  mov     rdx, myClass2@.className
                  call    print
                  byte    "In %s:myClass2$myFunc3", nl, 0
                  pop     rdx
                  ret
myClass2$myFunc3  endp


; Constructor for myClass:
;
; On entry:
;
;  RSI-     Pointer to object to initialize, or
;           NULL (0) if this constructor is to
;           allocate storage on the heap for the
;           object.
;  RCX-     Point to string containing the name
;           of the class.

myClass$create      proc
                    push    rcx
                    push    rsi      ;To NULL check
                    
                    mov     ecx, sizeof myClass
                    lea     rdi, vmtAdrs(myClass)
                    call    generic$Class$Constructor
                    pop     rcx      ;Original RSI value
                    test    rsi, rsi ;Did allocation fail?
                    jz      failure
                    
; Check to see if object was allocated on heap. Set the
; onHeap field to true if it was:

                    test    rcx, rcx
                    setz    cl
                    mov     myClass@.onHeap, cl
                    
; Initialize pointer to field name:

                    lea     rcx, myClassName
                    mov     myClass@.className, rcx

                    
failure:            pop     rcx
                    ret     
myClass$create      endp


; Constructor for myClass2:

myClass2$create     proc
                    push    rcx
                    push    rsi
                     
                    
                    mov     ecx, sizeof myClass2
                    lea     rdi, vmtAdrs(myClass2)
                    call    generic$Class$Constructor
                    pop     rcx      ;Original RSI value
                    
                    test    rsi, rsi ;Did allocation fail?
                    jz      failure
 
; Check to see if object was allocated on heap. Set the
; onHeap field to true if it was:

                    test    rcx, rcx
                    setz    cl
                    mov     myClass2@.onHeap, cl
                    
 
; Initialize pointer to field name:

                    lea     rcx, myClass2Name
                    mov     myClass2@.className, rcx
                    
; Set up the VMT pointer:

                    lea     rdi, vmtAdrs(myClass2)
                    mov     myClass2@.VMT, rdi
                    
failure:            pop     rcx
                    ret     
myClass2$create     endp



        
;--------------------------------------------------
;
; Here is the main assembly language function.

            
            public  asmMain
asmMain     proc
saveRBX     textequ <[rbp-8]>
saveRSI     textequ <[rbp-16]>
saveRDI     textequ <[rbp-24]>
            
            push    rbp
            mov     rbp, rsp
            sub     rsp, 128
            and     rsp, -16
            
            mov     saveRBX, rbx
            mov     saveRSI, rsi
            mov     saveRDI, rdi

; Initialize the mc1 object by calling
; myClass$create (the constructor):
            
            lea     rsi, mc1
            call    myClass$create

; Demonstrate accessing fields and calling
; virtual methods:
            
            mov     rdx, mc1.className
            call    print
            byte    nl
            byte    "------------------------------", nl
            byte    "mc1 class=%s", nl, 0
            
            call    print
            byte    "------------------------------", nl
            byte    "Calling myFunc and myFunc2 via", nl
            byte    "the mc1 object:", nl, 0
            
            call    print
            byte    nl
            byte    "inv mc1->myClass, myFunc:", nl, 0
            inv     myClass, myFunc
            
             
            call    print
            byte    nl
            byte    "inv mc1->myClass, myFunc2:", nl, 0
            inv     myClass, myFunc2, rsi   
            
; Initialize the mc2 object by calling
; myClass2$create (the constructor):
            
            lea     rsi, mc2
            call    myClass2$create

; Access the inherited data field:
            
            mov     rdx, mc2.className
            call    print
            byte    nl
            byte    "------------------------------", nl
            byte    "mc2 class=%s", nl, 0

            call    print
            byte    "------------------------------"
            byte    nl, nl, 0
            

; Demonstrate various calls to the myClass2 object:
            
            call    print
            byte    "inv mc2->myClass2, _myClass2(myFunc), "
            byte    "rsi, rdi:", nl, 0
            inv     myClass2, myFunc, rsi, rdi
            
; This call treats the pointer in RSI as a generic
; object of type myClass. Because myFunc2 was
; overridden, this actually winds up calling
; myFunc2a rather than myClass.myFunc2.

            call    print
            byte    nl
            byte    "inv mc2->myClass, _myClass(myFunc2):", nl, 0
            inv     myClass, myFunc2
            
; We can also call myFunc2 directly:

            call    print
            byte    nl
            byte    "inv mc2->myClass2, _myClass2(myFunc2):", nl, 0
            inv     myClass2, myFunc2

; Call the virtual function that is specific
; to myClass2:

            call    print
            byte    nl
            byte    "inv mc2->myClass2, _myClass2(myFunc3):", nl, 0
            inv     myClass2, myFunc3
            

            call    print
            byte    nl
            byte    "-------------------------------", nl
            byte    "Demonstrate loading the address", nl
            byte    "of the mc1 object into RSI:"
            byte    nl, 0

; Demonstrate loading RSI with the address
; of an object using the "@" operator:
            
            call    print
            byte    nl
            byte    "inv mc1->myClass, myFunc, @mc1:", nl, 0
            inv     myClass, myFunc, @mc1
            
            call    print
            byte    nl, nl
            byte    "-------------------------------", nl
            byte    "Creating a new object on the", nl
            byte    "heap (calling myClass2$create", nl
            byte    "with RSI=0)", nl, 0
            
            xor     rsi, rsi
            call    myClass2$create
            mov     mc3, rsi
            
            call    print
            byte    "inv mc3->myClass2, _myClass2(myFunc), "
            byte    "rsi, rdi:", nl, 0
            inv     myClass2, myFunc, rsi, rdi
            
            call    print
            byte    nl
            byte    "inv mc3->myClass, _myClass2(myFunc2):", nl, 0
            inv     myClass, myFunc2
            

            call    print
            byte    nl
            byte    "inv mc3->myClass3, _myClass2(myFunc3):", nl, 0
            inv     myClass2, myFunc3
            
            mov     rbx, saveRBX
            mov     rsi, saveRSI
            mov     rdi, saveRDI
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end