; traditionalClassesDemo.asm ; ; A program that demonstrates protocols in MASM. option casemap:none include aoaTypes.inc include aoaMacros.inc include traditionalClasses.asm include aoalib.inc includelib aoalib.lib .const ; Program title: align word ttlStr byte "Traditional Classes Demo", 0 ; Here's an example of a "pure" protocol, ; containing only virtual method definitions. ; You don't create a VMT for pure protocols, ; and you don't call the methods (so you don't ; write any methods for these, either. proto123 protocol () virtual proc1 virtual proc2 virtual proc3 endpr ; Here's a second pure protocol, to demonstrate ; "multiple inheritance" of protocols: proto1a protocol () ;Does not inherit pureProto! virtual proc1 endpr proto1b protocol () ;Does not inherit pureProto! virtual proc1 endpr ; Here's a specific protocol for the ; "protoClass" class based on the ; proto123 protocol. Note that it ; overrides all the methods in the ; pure prototype. protoClass$proto123 protocol (proto123) override proc1, protoClass$proc1 override proc2, protoClass$proc2 override proc3, protoClass$proc3 endpr ; Here's a class-specific protocol for the ; "proto1a" protocol. Note that we have ; to map proto1a.proc1 to a different ; name than protoClass$proc1, which already ; exists (from protoClass$proto123). protoClass$proto1a protocol (proto1a) override proc1, protoClass$proc4 endpr protoClass$proto1b protocol (proto1b) override proc1, protoClass$proc4 endpr ; A sample class that uses a protocol. ; It adds one additional function that ; is not part of the protocol. protoClass class (protoClass$proto123, protoClass$proto1a, protoClass$proto1b) virtual protoClass$pcFunc protoClass endc () protoClass$ textequ <(protoClass ptr [rsi])> _protoClass macro field namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) echo *********************************** echo Error:unexpected _protoClass member % echo function=field echo *********************************** exitm <.err> endm ; A second class that uses the proto123 protocol. protoClass2$proto4pc4 protocol (proto123) override proc1, protoClass2$proc1 override proc2, protoClass2$proc2 override proc3, protoClass2$proc3 endpr protoClass2 class (protoClass2$proto4pc4) virtual protoClass$pcFunc protoClass2 endc () protoClass2$ textequ <(protoClass2 ptr [rsi])> _protoClass2 macro field namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) namespace (&field, , ) echo ************************************ echo Error:unexpected _protoClass2 member % echo function=field echo ************************************ exitm <.err> endm ; Emit the VMTs for these classes. .const emitVMT protoClass$proto123 emitVMT protoClass$proto1a emitVMT protoClass$proto1b emitVMT protoClass2$proto4pc4 emitVMT protoClass emitVMT protoClass2 .data pc protoClass {} pc2 protoClass2 {} .code include mallocFree.inc ;--------------------------------------------------- ; ; Constructor code for protoClass: ; protoClass$create proc push rax test rsi, rsi ;NULL? jnz notNULL ; If RSI was NULL on entry, allocate storage for ; a "protoClass" object on the heap: mov eax, sizeof protoClass call mem$alloc mov rsi, rax test rsi, rsi jz failure ; Initialize the VMT pointer for the proto field ; in protoClass: notNULL: lea rdi, vmtAdrs(protoClass$proto123) mov protoClass$.vmtPtr(protoClass$proto123), rdi ; Initialize the protoClass VMT pointer: lea rdi, vmtAdrs(protoClass) mov protoClass$.VMT, rdi failure: pop rax ret protoClass$create endp ; Constructor code for protoClass2: ; protoClass2$create proc push rax test rsi, rsi ;NULL? jnz notNULL ; If RSI was NULL on entry, allocate storage for ; a "protoClass2" object on the heap: mov eax, sizeof protoClass2 call mem$alloc mov rsi, rax test rsi, rsi jz failure ; Initialize the VMT pointer for the proto field ; in protoClass2: notNULL: lea rdi, vmtAdrs(protoClass2$proto4pc4) mov protoClass2$.vmtPtr(protoClass2$proto4pc4), rdi ; Initialize the protoClass2 VMT pointer: lea rdi, vmtAdrs(protoClass2) mov protoClass2$.VMT, rdi failure: pop rax ret protoClass2$create endp ;--------------------------------------------------- ; ; Procedures for the protoClass class: protoClass$pcFunc proc call print byte "Inside protoClass$pcFunc" byte nl, 0 ret protoClass$pcFunc endp protoClass$proc1 proc call print byte "Inside protoClass$proc1", nl, 0 ret protoClass$proc1 endp protoClass$proc2 proc call print byte "Inside protoClass$proc2", nl, 0 ret protoClass$proc2 endp protoClass$proc3 proc call print byte "Inside protoClass$proc3", nl, 0 ret protoClass$proc3 endp protoClass$proc4 proc call print byte "Inside protoClass$proc4", nl, 0 ret protoClass$proc4 endp ;--------------------------------------------------- ; ; Procedures for the protoClass2 class: protoClass2$pcFunc proc call print byte "Inside protoClass2$pcFunc" byte nl, 0 ret protoClass2$pcFunc endp protoClass2$proc1 proc call print byte "Inside protoClass2$proc1", nl, 0 ret protoClass2$proc1 endp protoClass2$proc2 proc call print byte "Inside protoClass2$proc2", nl, 0 ret protoClass2$proc2 endp protoClass2$proc3 proc call print byte "Inside protoClass2$proc3", nl, 0 ret protoClass2$proc3 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 pc/pc2 class objects: lea rsi, pc call protoClass$create lea rsi, pc2 call protoClass2$create ; Directly call the methods in pc, just to demonstrate ; that they work: call print byte "Calling protoClass.pcFunc", nl, 0 inv protoClass, _protoClass(pcFunc), \ RSI, RDI call print byte nl byte "Calling protoClass.protoClass$proto123" byte "functions", nl, 0 inv protoClass, _protoClass(proc1), rsi,\ protoClass$.vmtPtr(protoClass$proto123) inv protoClass, _protoClass(proc2), rsi,\ protoClass$.vmtPtr(protoClass$proto123) inv protoClass, _protoClass(proc3), rsi,\ protoClass$.vmtPtr(protoClass$proto123) inv protoClass, _protoClass(proc1), rsi,\ protoClass$.vmtPtr(protoClass$proto1a) ; Given a generic pointer, call the protocol functions ; across both classes: lea rsi, pc inv proto123, proc1, rsi, \ protoClass$.vmtPtr(protoClass$proto123) lea rsi, pc2 inv proto123, proc1, rsi, \ protoClass2$.vmtPtr(protoClass2$proto4pc4) mov rbx, saveRBX mov rsi, saveRSI mov rdi, saveRDI leave ret ;Returns to caller asmMain endp end