Assembly Language Methods


This tutorial is intended to follow the tutorial on assembly language input/output.

The INVOKEVIRTUAL instruction invokes a method. This instruction creates the method's stack frame (pointed to by the LV register) and sets the PC register to the address of the first instruction in the method. The stack frame consists of

The IRETURN instruction terminates a method and returns control to the calling method. This instruction restores the previous LV value, loads the return address into the PC register, removes the stack frame, and copies the method's return value to the top of the stack.

Methods (other than the main method) are optional. If present in a program, they must follow the main method. The general format for a method is given here:

General Format
.method methodId ( paramList )
    [variable declarations]
    executable code
.end-method

Return Value

Every method returns a value. The value on the top of the stack prior to the execution of the IRETURN instruction is copied to the new top of stack when the method terminates. When implementing a "value-returning" function, the calling routine should do something with this value. When implementing a void function (a procedure), the calling routine should just pop this value off the stack.

Implicit Object Reference Parameter

Every method must have at least one parameter: an object reference. This parameter is not included in the parameter list; it is implied. In a real Java Virtual Machine, it would identify the particular object that is invoking a class method. Since IJVM does not support objects, the value of this parameter is never actually used and it can be given any value. Nevertheless, the parameter is still required.

The object reference should be the first (and possibly the only) parameter pushed onto the stack prior to executing the INVOKEVIRTUAL instruction. Following the execution of INVOKEVIRTUAL, the LV register points at this parameter (which is at the base of the corresponding stack frame). The parameter value itself is replaced by a pointer to the return address.

When writing assembly code, declare a constant named OBJREF and give it an arbitrary value. Use the LDC_W instruction to load this constant onto the top of the stack as the object reference. (Technically, any instruction that places a value on top of the stack would suffice.)

Explicit Parameters

A method's explicit parameters appear as a comma-delimited list of identifiers enclosed by parentheses. If the function has no parameters, the list is empty but the parentheses are still required. Since parameters are local to a method, you may use the same identifier in different methods.

Explicit parameters should be pushed onto the stack after the object reference parameter and, of course, before invoking the method. The values should be pushed onto the stack in the same order as the corresponding identifiers appear in the parameter list. That is, the first value pushed onto the stack becomes the value of the first parameter in the list. All parameters, including the object reference, become part of the stack frame and are automatically removed when the method terminates.

All explicit parameters are passed by value; just as integer parameters are in Java. There is no mechanism for passing a parameter by address (as a reference parameter).

Example Program

The example program asks the user for an integer in the range 0 to 5, finds the sum of the integers up to and including this value, and displays the sum in hexadecimal. It includes four methods:

 1. Clear the memory of the computer (Memory menu; Clear Memory).

 2. If necessary, clear the source code editor (Source menu, Clear Source Code).

 3. Enter the following assembly language program using the source code editor.

.constant
    OBJREF 100
    NEWLINE 10
.end-constant

.main
    .var
        n sum
    .end-var

    ldc_w OBJREF
    invokevirtual DisplayPrompt
    pop

    ldc_w OBJREF
    invokevirtual GetInput
    istore n

    ldc_w OBJREF
    iload n
    invokevirtual FindSum
    istore sum

    ldc_w OBJREF
    iload sum
    invokevirtual DisplaySum
    pop

    halt
.end-main

//-------------------------------------------
// DisplayPrompt displays a prompt asking for
// a number between 0 and 5.
//-------------------------------------------
.method DisplayPrompt()
    bipush 'N'       // Display "N(0-5)? "
    out
    bipush '('
    out
    bipush '0'
    out
    bipush '-'
    out
    bipush '5'
    out
    bipush ')'
    out
    bipush '?'
    out
    bipush ' '
    out
    ireturn
.end-method

//-------------------------------------------
// GetInput returns the single digit number
// entered by the user. No error checking is
// performed.
//-------------------------------------------
.method GetInput()
    .var
        ch
    .end-var

// Loop until a character is entered

top:
    in
    dup
    ifeq clear
    goto end
clear:
    pop
    goto top
end:
    istore ch

// Echo print character followed by new line

    iload ch
    out
    ldc_w NEWLINE
    out

// Convert ASCII character to decimal digit
// digit = ch - '0'

    iload ch
    bipush '0'
    isub
    ireturn
.end-method

//-------------------------------------------
// FindSum returns the sum 0 + 1 + ... + n.
//
// Parameter: n
//-------------------------------------------
.method FindSum(n)
    iload n                  // if (n == 0)
    dup
    ifeq end                 //     return 0
                             // else
    iinc n -1                //     return n + FindSum(n-1)
    ldc_w OBJREF
    iload n
    invokevirtual FindSum
    iadd
    goto end
end:
    ireturn
.end-method

//-------------------------------------------
// DisplaySum displays the sum as a
// hexadecimal digit.
//
// Parameter: sum
//
// Precondition: 0 <= sum <= 15
//-------------------------------------------
.method DisplaySum(Sum)

// Display "Sum: 0x"
    ldc_w NEWLINE
    out
    bipush 'S'
    out
    bipush 'u'
    out
    bipush 'm'
    out
    bipush ':'
    out
    bipush ' '
    out
    bipush '0'
    out
    bipush 'x'
    out

// If (sum <= 9)
//     output digit (sum + '0')
// else
//     output letter ((sum - 10) + 'A')

    bipush 9
    iload sum
    isub
    iflt letter
// digit:
    iload sum
    bipush '0'
    iadd
    out
    goto end
letter:
    iload sum
    bipush 10
    isub
    bipush 'A'
    iadd
    out
end:
    ireturn
.end-method

Be careful as you work through these instructions. It is easy to make mistakes and get out of sync.

 4. Assemble the program (tap the F2 function key). If you do not want to save this program, just click the Cancel button in the file save dialog; the machine language code will still be loaded into memory.

 5. Check the Single-Step through IJVM Code checkbox below the input/output window.

 6. Click the Reset button.

 7. Click the Display Words button below the memory display.

 8. Click the IJVM Step button twice to allow the machine language interpreter to perform its start-up routine.

Display the User Prompt

 9. Click the IJVM Step button. This places the object reference parameter (OBJREF) on the top of the stack:

 10. Click the IJVM Step button to invoke the DisplayPrompt method. The object reference parameter has been replaced by a pointer to the return address (4098). This is the first value in the stack frame and is pointed to by the LV register. The stack frame also includes the return address (6) and the previous LV value (8192):

 11. Click the IJVM Step button sixteen (16) times executing the statements in the DisplayPrompt method up to but not including the IRETURN instruction. The prompt is displayed in the input/output window. The stack is in the same state that it was immediately after invoking this method. The value at the top of the stack is the previous LV value (8192).

 12. Click the IJVM Step button to execute the IRETURN instruction. Notice that the stack frame has been removed and the value that had been at the top of the stack has been copied to the new top of stack location:

 13. Logically, the DisplayPrompt method is a void function. Even so, as we have just seen, the method returned the value that is currently on the top of the stack. Click the IJVM Step button to pop this unused value from the stack:

Get the User's Input

 14. Click the IJVM Step button two (2) times to invoke the GetInput method. The stack frame for this method begins at address 4097 and contains a pointer to the return address, the local variable (ch), the return address, and the previous value of the LV register (at the top of the stack). Notice that the initial value of the local variable (at address 4098) is simply the value that was left there from previous stack manipulations (it was the return address when the first method was invoked):

 15. Before continuing program execution, you should input a single digit as follows. Click anywhere in the input/output window to give it the focus. Enter the digit '2'. Click the IJVM Step button. The IN instruction reads the character '2' from the input buffer and puts its code value on the top of the stack:

 16. Click the IJVM Step button four (4) times executing the instructions up to and including "79:  ISTORE 1". The method has confirmed that you typed in a keystroke and has stored its code value in the local variable "ch" at address 4098:

 17. Click the IJVM Step button four (4) times to echo print your keystroke and send a new line character to the input/output window.

 18. The method should return the number 2 rather than the character '2'. To convert a numeral to its corresponding decimal value, subtract the code value for the numeral '0'. In this case '2' - '0' is really 50 - 48 or the number 2. Click the IJVM Step button three (3) times to perform this arithmetic and leave the result on the top of the stack as the return value of the method:

 19. Click the IJVM Step button to terminate the GetInput method. The stack frame has been removed and the return value of the method is on the top of the stack:

 20. Click the IJVM Step button once. The value returned by the GetInput method is removed from the stack (SP points to 4096) and stored in the main method variable "n" (pointed to by the LV register).

Calculate the Sum (0+1+...+n)

 21. Click the IJVM Step button three (3) times to load the object reference onto the stack, load the function parameter (n) onto the stack, and invoke the recursive function that will find the sum of the integers from 0 to n. The stack frame (pointed to by LV) contains a pointer to the return address (where the object reference parameter used to be), the function parameter (2, in this case), the return address (23), and the previous value in the LV register (8192):

 22. The recursive function, FindSum, begins by testing for the exit condition (n=0). Click the IJVM Step button to load the parameter onto the stack.

 23. Click the IJVM Step button to duplicate the parameter value on the top of the stack.

 24. Click the IJVM Step button to test for the exit condition. The branch fails and the next instruction, "104:  IINC 1 255", is the first instruction in the recursive invocation of the function. Note, in particular, that the parameter value is still at the top of the stack ready to be returned (if it had been a 0) or to be added to the value returned by the recursively invoked method:

 25. Click the IJVM Step button to decrement the value of n (at address 4098):

 26. Click the IJVM Step button three (3) times to recursively invoke the FindSum method. The stack frame for this second invocation is on the stack above the previous value of n (from the first invocation) that is just waiting to be added to the value returned by this second invocation. Notice that the previous value of LV (at the top of the stack frame) is the address of the base of the stack frame for the first invocation:

 27. Since the parameter passed to the second invocation was not zero, the FindSum method will be invoked a third time. Click the IJVM Step button seven (7) times. The stack frame from the third invocation is on the stack above the previous value of n (from the second invocation) which will be added to the value returned by this invocation:

 28. This time, the parameter passed to FindSum is 0 which is the exit condition. Click the IJVM Step button three (3) times to test for the exit condition. Notice that the return value is on top of the stack just prior to the termination of the method:

 29. Click the IJVM Step button to terminate the third invocation of the FindSum method. The return value of 0 is on the top of the stack, ready to be added to 1 (the parameter passed to the second invocation) by the IADD instruction at 115:

 30. Click the IJVM Step button to execute the IADD instruction. The value to be returned by the second invocation of FindSum (0+1) is on the top of the stack:

 31. Click the IJVM Step button two (2) times to terminate the second invocation of the FindSum method. The first click executes an unconditional branch to the IRETURN instruction and the second click executes the IRETURN instruction. The value (1) returned by the method is on the top of the stack ready to be added to the parameter passed to the first invocation (2) by the IADD instruction at 115.

 32. Click the IJVM Step button to execute the IADD instruction. The value to be returned by the first invocation of FindSum (0+1+2) is on the top of the stack:

 33. Click the IJVM Step button two (2) times to terminate the first invocation of the FindSum method. The first click executes an unconditional branch to the IRETURN instruction and the second click executes the IRETURN instruction. The value (3) returned by the method is on the top of the stack:

 34. Click the IJVM Step button to pop this value from the stack and store it in main method variable "sum":

Display the Sum

 35. Click the IJVM Step button three (3) times. These instructions invoke the DisplaySum method with the value of "sum" as the method parameter. The stack frame for this method is shown here:

 36. Click the IJVM Step button sixteen (16) times to display "Sum: 0x" in the input/output window.

 37. All that remains to do is to display the sum as a hexadecimal digit. If the sum is 9 or less, we can display a decimal digit by adding the code for '0' to the sum. Otherwise, we subtract 10 from the sum and add the code for 'A'. Click the IJVM Step button ten (10) times to display the numeral "3" and terminate the method. Even though DisplaySum implements a void function, the method itself returns a value; namely, the previous value of the LV register which had been at the top of the stack frame:

 38. Click the IJVM Step button to execute the POP instruction at address 33. This clears the stack; SP is back to 4096 where it started.

 39. Click the IJVM Step button to execute the HALT instruction at address 34.

 40. You might try running the program with inputs of 0, 1, 2, 3, 4, and 5 to confirm that you get sums of 0x0, 0x1, 0x3, 0x6, 0xA, and 0xF respectively.

This is the last assembly language tutorial.