; Listing9-1.asm
;
; A program that demonstrates a call-by-name
; parameter.


            option     casemap:none
            .nolist
            include    aoalib.inc
            include    aoaProcs.inc
            include    aoaTypes.inc
            includelib aoalib.lib
            .list
            
            .const

; Program title:

             align  word
ttlStr       byte   "Listing 9-1", 0



            .code

; procedure zeroStorage( name array:integer, var index:integer );

            parms   zeroStorage, rbp, 16,   \
                    array:thunk_t,          \
                    index:qword
                    
zeroStorage proc
            push    rbp
            mov     rbp, rsp
            push    rax
            push    rbx
            push    rcx
            push    rdx
            
; Array is a thunk. Load the environment pointer 
; into RCX (where the thunk expects it to be) so
; we can easily access it later. Note that the
; following code assumes that the thunk code
; (zeroStorage$array.procedure) does not
; change RCX (or RDX).

            mov     rcx, zeroStorage$array.environment

; Assume index is a 32-bit integer
;           
; for index := 0 to 10
;
; Note that index is passed by reference, so we have
; to deference it whenever we want to use it. Load
; the address of index into RDX and keep it there
; so that dereferencing RDX is easy.

            mov     rdx, zeroStorage$index
            mov     dword ptr [rdx], 0          ;index
forLp:      call    zeroStorage$array.procedure ;thunk

; Now RAX contains the address returned by the thunk
; (which happens to be the address of a[i] in the
; main program). Store a zero into that array element.
            
            mov     dword ptr [rax], 0          ;Pointer to A[I]

; Increment the index variable (remember, it is passed
; by reference).
            
            inc     dword ptr [rdx]             ;index
            
; See if index (dereferenced) is greater than 10. If so,
; quit the loop; else repeat.

            cmp     dword ptr [rdx], 10         ;index
            jbe     forLp
            
            pop     rdx
            pop     rcx
            pop     rbx
            pop     rax
            pop     rbp
            ret
zeroStorage endp

;--------------------------------------------------
;
; Here is the main assembly language function.
            
            public  asmMain
                    
            locals  asmMain, i:dword, a:dword[11]
   

asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 80
            
; Initialize a with non-zero values just to show
; that the pass by name parameter works:

            lea     rcx, asmMain$a
            mov     edx, 10
storeLp:    mov     [rcx+rdx*4], edx
            dec     edx
            jnz     storeLp
            
; Just pass the parameters on the stack

            lea     rax, asmMain$i  ;Pass i by reference
            mov     [rsp+16], rax
            
; The thunk computes the address of a[i] and returns
; that address in RAX. It is passed the environment
; pointer (the pointer to asmMain's activation record)
; in the RCX register. Note: rather than copy RCX into
; RBP (and preserve RBP), this code just indexes off
; RCX into asmMain's activation record.
;
; Put the thunk on the stack:

            setTh   (thunk_t ptr [rsp])
            push    rbx
            mov     ebx, [rcx+asmMain$i$ofs]
            lea     rax, [rcx+asmMain$a$ofs+rbx*4]
            pop     rbx
            ret
            endTh
            
            call    zeroStorage
            
; Print the contents of a to show that all the
; elements have been zeroed:

            call    print
            byte    "a: ", 0
            lea     rcx, asmMain$a
            mov     r10d, 0
printLp:    mov     edx, [rcx+r10*4]
            call    print
            byte    "%d ", 0
            inc     r10d
            cmp     r10d, 11
            jb      printLp
            call    print
            byte    nl, 0
            
            
            leave
            ret
        
asmMain     endp
            end