CDA-4101 Lecture 20 Notes



IJVM Method Invocation

Procedure for Invoking a Method

  1. Caller pushes reference (pointer) to object (OBJREF) to be called
    (Note: This reference is not used by IJVM since we will not dynmically determine the method start location, but we keep it as part of the invocation procedure anyway, thus the actual value is unimportant.)
  2. Push other method parameters onto the stack (if any) in proper order (first to last)
  3. Execute the INVOKEVIRTUAL instruction (op-code 0xB6)

Procedure for Returning from a Method

  1. Caller pushes an integer return value onto the stack: this is required!
  2. Execute the IRETURN instruction (op-code 0xAC)

    Make sure to do something with the return value on the stack after returning from a method.


Method Invocation IJVM Assembly Code

.constant
OBJREF 0x40   // dummy value used for method invocation
.end-constant

.main

    // Push the object reference onto the stack
    LDC_W OBJREF

    // Push the parameters on the stack (2 in this case)
    BIPUSH 0x03
    BIPUSH 0x04

    INVOKEVIRTUAL adddigits

    BIPUSH 0x30    // Convert to an ASCII digit
    IADD
    OUT     // display result which is on top of stack

    HALT
.end-main

.method adddigits(num1, num2)

    ILOAD num1
    ILOAD num2
    IADD        // This will leave the sum on top of stack.
                // This is just as good as pushing the return value.

    IRETURN

.end-method

INVOKEVIRTUAL <disp>

  • The operand to the INVOKEVIRTUAL instruction is a displacement off the CPP constant pool pointer.
  • The contents of that location in the constant pool is a memory address (pointer) into the method area for the start of the actual code.
  • Thus, we get to the method code indirectly.
  • This is actually very useful and not just some arbitrary wasteful mechanism
  • This allows the method area's exact memory location to be easily changed without having to chnage any of the code (only the address pointers in the constant pool need to be changed.)

Method Code Area Layout

  • The pointer in the constant pool points to the method code area, but the first 4 bytes of this area are not actually instructions to be executed.
  • First 2 bytes interpreted as a 16 bit (unsigned?) integer indicating the number of parameters to this method.
    • OBJREF counted as one of the parameters (parameter #0)
    • Once all parameters have been pushed onto the stack and the method invoked, SP minus this 16 bit integer will be the location of the first parameter (i.e., OBJREF), and hence where the LV pointer should be set to.
  • Second 2 bytes also interpreted as a 16 bit (unsigned?) integer, and this represents the number of local variables (not including the parameters) for this method.
    • when called, only the parameters have stack space allocated.
    • there are also locally declared variables that may be used in the method
    • we will need to bump the stack pointer SP up to accomodate these extra local variables
  • Therefore, the first instruction of the method is the 5th byte from the constant pool's pointer

INVOKEVIRTUAL Op-code and Operand

  • op-code followed by two bytes
  • two bytes are an unsigned 16 bit operand
  • high-order integer byte comes first
  • this integer is the displacement within the constant pool (CPP register)
  • e.g., method address is at
         CPP + 0x0100
      
  • again, this would be a word address, since pointers are 4 bytes too

3 byte of code for INVOKEVIRTUAL instruction

INVOKEVIRTUAL Sequence

INVOKEVIRTUAL Implementation Overview

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.

Initial Constant Pool


Initial Method Area


Initial Stack

Initial Registers

Mic-1 Registers
MAR don't care
MDR don't care
PC 0x00000041
MBR 0x01
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS don't care
OPC don't care
H don't care

Invoke Step 1

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Read the 16 bit displacement operand.
Mic-1 Implementation
  • First byte after op-code is already in MBR when we start executing the microcode for this instruction
  • Put MBR (unsigned, shifted 8 bits left) into register H
  • Load second byte after opcode into MBR (incrementing PC first)
  • Put MBR (unsigned, OR'ed with H) into register H
  • Register H now has the full displacement operand
Mic-1 Registers
MAR don't care
MDR don't care
PC 0x00000042
MBR 0x00
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS don't care
OPC don't care
H 0x00000100

Invoke Step 2

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Compute the index into the constant pool where method code address is stored.
Mic-1 Implementation
  • Put CPP + H into MAR register
Mic-1 Registers
MAR 0x00001100
MDR don't care
PC 0x00000042
MBR 0x00
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS don't care
OPC don't care
H 0x00000100

Invoke Step 3

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • From the constant pool, get the address of the method code in the method area
Mic-1 Implementation
  • Read memory using MAR so that MDR will have address of method area
Mic-1 Registers
MAR 0x00001100
MDR 0x00000080
PC 0x00000042
MBR 0x00
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS don't care
OPC don't care
H 0x00000100

Invoke Step 4

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • From the method area, get the two bytes indicating how many parameters this method has.
Mic-1 Implementation
  • Save current PC temporarily into OPC register (actually PC + 1).
  • Set program counter to point to new method code area, i.e., move MDR into PC
  • Load first byte of method area using PC into MBR
  • Put MBR (unsigned, shifted 8 bits left) into register H
  • Load second byte into MBR (incrementing PC first)
  • Put MBR (unsigned, OR'ed with H) into register H
  • Register H now has the number of method parameters
Mic-1 Registers
MAR 0x00001100
MDR 0x00000080
PC 0x00000081
MBR 0x04
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS don't care
OPC 0x00000043
H 0x00000004

Invoke Step 5

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Compute new location of the local variable stack frame.
  • This will be the current stack pointer minus the number of parameters to the method, and add one so it points to the first parameter and not the address below the first parameter.
Mic-1 Implementation
  • Subtract number of parameters from current stack pointer, so we put SP - H into register TOS
  • Add one to TOS register to make it point to first parameter.
  • Note that we do not yet put this value into the LV register, since there we still need its value for some things.
Mic-1 Registers
MAR 0x00001100
MDR 0x00000080
PC 0x00000081
MBR 0x04
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS 0x0000200B
OPC 0x00000043
H 0x00000004

Invoke Step 6

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.

Invoke Step 7

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Look in the method area to find out how many extra local variables this method uses.
Mic-1 Implementation
  • Increment PC register to point to the third byte of the new method's area.
  • Load byte at PC into MBR (incrementing PC first)
  • Put MBR (unsigned, shifted 8 bits left) into register H
  • Load fourth byte of method area into the MBR (incrementing PC first)
  • Put MBR (unsigned, OR'ed with H) into register H
  • Register H now has the number of extra local variables
  • PC now points to the 4th byte of the method area, which is just before first op-code of the method
Mic-1 Registers
MAR 0x00001100
MDR 0x00000080
PC 0x00000083
MBR 0x03
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS 0x0000200B
OPC 0x00000043
H 0x00000003

Invoke Step 8

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Make room on the stack for the extra local variables.
  • At the same time this tells us where on the stack the old PC and LV will be stored.
Mic-1 Implementation
  • TOS points to new local variable area, which is also the address of first parameter OBJREF: load this into the MAR register
  • Put stack location for saved registers, SP + H + 1, into the MDR regsiter
  • We overwrite the OBJREF value with a link pointer
  • MDR) contains that link which points upward into the stack where old PC and LV registers will be stored.
  • Doing a memory write will overwrite OBJREF

Note: If we were actually using the OBJREF value, by this time in the process we would be finished with it and overwriting would be alright.

Mic-1 Registers
MAR 0x0000200B
MDR 0x00002013
PC 0x00000083
MBR 0x03
SP 0x0000200E
LV 0x00002000
CPP 0x00001000
TOS 0x0000200B
OPC 0x00000043
H 0x00000003

Invoke Step 9

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Put the old PC and LV registers onto the stack.
  • The PC register is pushed first and then the LV register is pushed.
Mic-1 Implementation
  • MDR still contains the address of the stack location where old registers will be saved
  • Put MDR into MAR and also into SP since after writing the old PC this will be the top of the stack.
  • Save old program counter, which we stored in the OPC register earlier, this means putting OPC into MDR and initiating a memory read.
  • Increment stack pointer to point where we will save old LV: put SP + 1 into SP and MAR
  • Move the LV register into MDR and initiate a memory write.
Mic-1 Registers
MAR 0x00002013
MDR 0x00002000
PC 0x00000083
MBR 0x03
SP 0x00002013
LV 0x00002000
CPP 0x00001000
TOS 0x0000200B
OPC 0x00000043
H 0x00000003

Invoke Step 10

1 Read the 16 bit displacement operand
2 Compute the index into the constant pool where method code address is stored.
3 From the constant pool, get the address of the method code in the method area
4 From the method area, get the two bytes indicating how many parameters this method has.
5 Compute new location of the local variable stack frame.
6 Save the current value of the PC and LV registers.
7 Look in the method area to find out how many extra local variables this method uses.
8 Make room on the stack for the extra local variables.
9 Put the old PC and LV registers onto the stack.
10 Set the local variable stack frame for this new method and start executing its instructions.
  • Set the local variable stack frame for this new method and start executing its instructions.
Mic-1 Implementation
  • We computed and saved the new local variable frame location in the TOS register, so now we just need to move it into the LV register
  • Increment PC to move from pointing to the 4th method area byte to the fifth, which is the first op-code of the method
  • Fetch the method's first op-code and branch to microcode for that instruction
Mic-1 Registers
MAR 0x00002013
MDR 0x00002000
PC 0x00000084
MBR 0x15
SP 0x00002013
LV 0x0000200B
CPP 0x00001000
TOS 0x0000200B
OPC 0x00000043
H 0x00000003

IRETURN Sequence

  • The IRETURN instruction executes after return value is pushed onto stack. (For our example, we will assume 15 is pushed, i.e., OxF)

IRETURN Implementation Overview

1 Reset the stack pointer.SP
2 Restore the program counter.PC
3 Restore the local variable pointer.LV
4 move return value to top of current stack

Current Stack

Current Registers

Mic-1 Registers
MAR don't care
MDR don't care
PC 0x00000103
MBR 0xAC
SP 0x00002014
LV 0x0000200B
CPP 0x00001000
TOS 0x0000000F
OPC don't care
H don't care

Return Step 1

1 Reset the stack pointer.SP
2 Restore the program counter.PC
3 Restore the local variable pointer.LV
4 move return value to top of current stack
  • Reset the stack pointer to point to the bottom of the current local variable frame.
Mic-1 Implementation
  • Just copy the value in LV into SP
  • Note that this effectively removes all the method's data from the stack, but the data still exists in those memory locations.
  • The old data will persist until the stack grows to those locations again.
  • subsequent steps will actually access data above the stack pointer (using the link pointer that still points up there)
Mic-1 Registers
MAR don't care
MDR don't care
PC 0x00000103
MBR 0xAC
SP 0x0000200B
LV 0x0000200B
CPP 0x00001000
TOS 0x0000000F
OPC don't care
H don't care

Return Step 2

1 Reset the stack pointer.SP
2 Restore the program counter.PC
3 Restore the local variable pointer.LV
4 move return value to top of current stack
  • Restore the previous PC to point to the instruction just after the original INVOKEVIRTUAL call.
Mic-1 Implementation
  • First get the link pointer, which can be accessed with the LV register
  • This requires putting LV into the MAR and doing a read.
  • After the read, the MDR register has the link pointer address, which is where the previous PC is stored.
  • Temporarily store the link pointer in LV and also put the link pointer into the MAR register.
  • Then doing a read will put the previous PC value into the MDR register.
  • Finally, copy the MDR register (previous PC) into the PC
Mic-1 Registers
MAR 0x00002012
MDR 0x00000043
PC 0x00000043
MBR 0xAC
SP 0x0000200B
LV 0x00002012
CPP 0x00001000
TOS 0x0000000F
OPC don't care
H don't care

Return Step 3

1 Reset the stack pointer.SP
2 Restore the program counter.PC
3 Restore the local variable pointer.LV
4 move return value to top of current stack
  • Restore the previous LV pointer to the begining of the local variable stack frame for the method that originally executed INVOKEVIRTUAL.
Mic-1 Implementation
  • The LV register is temporarily pointing to the address just before where the old LV register is stored.
  • Load the MAR with LV + 1 and inititate a memory read.
  • This leaves the old LV value in the MDR which we simply copy to the LV register.
Mic-1 Registers
MAR 0x00002013
MDR 0x00002000
PC 0x00000043
MBR 0xAC
SP 0x0000200B
LV 0x00002000
CPP 0x00001000
TOS 0x0000000F
OPC don't care
H don't care

Return Step 4

1 Reset the stack pointer.SP
2 Restore the program counter.PC
3 Restore the local variable pointer.LV
4 move return value to top of current stack
  • Write return value to top of stack.
  • The return value was on top of the stack, but we moved the stack pointer
  • we need to put the return value on the top of the current stack so the calling method can access it.
Mic-1 Implementation
  • The TOS register should have been set to have the return value from the BIPUSH that preceded the IRETURN call, thus we do not have to get it from memory.
  • Since SP points to the top of the stack, and since we no longer need the link pointer, we can just just write the return value at the current stack pointer.
  • Load the MAR register with the SP register, load the MDR register with the TOS register and initiate a memory write.
Mic-1 Registers
MAR 0x0000200B
MDR 0x0000000F
PC 0x00000043
MBR 0xAC
SP 0x0000200B
LV 0x00002000
CPP 0x00001000
TOS 0x0000000F
OPC don't care
H don't care

Mic-1 Microcode for IJVM ISA