Next: Evolution of the stack
Up: Unit 11
Previous: Stack of activation records
Let us consider the following methods main(), A(), and
B() and see what happens during the execution of the main()
method.
public static int B(int pb) {
/* b0 */ System.out.println("In B. Parameter pb = " + pb);
/* b1 */ return pb+1;
}
public static int A(int pa) {
/* a0 */ System.out.println("In A. Parameter pa = " + pa);
/* a1 */ System.out.println("Call of B(" + (pa * 2) + ").");
/* a2 */ int va = B(pa * 2);
/* a3 */ System.out.println("Again in A. va = " + va);
/* a4 */ return va + pa;
}
public static void main(String[] args) {
/* m0 */ System.out.println("In main.");
/* m1 */ int vm = 22;
/* m2 */ System.out.println("Call of A(" + vm + ").");
/* m3 */ vm = A(vm);
/* m4 */ System.out.println("Again in main. vm = " + vm);
/* m5 */ return;
}
For simplicity, we ignore the invocation of the println() method, and
consider it as if it were a simple statement; moreover, we assume that each
statement of the Java source code corresponds to a single statement in the Java
bytecode. We also assume that the bytecode is loaded by the JVM in the
following memory locations:
Output generated by the program:
In main.
Call of A(22).
In A. Parameter pa = 22
Call of B(44).
In B. Parameter pb = 44
Again in A. va = 45
Again in main. vm = 67
Evolution of the stack of ARs:
To understand what happens during the execution of the code, it is necessary to
refer, in addition to the stack of ARs, to the program counter (PC),
whose value is the address of the next Java bytecode statement to execute.
We analyze in detail what happens when A(vm) is activated from the
main() method. Before the activation, the stack of ARs is as shown
in 1 in the above figure:
- The actual parameters are evaluated: in our case, the actual
parameter is the expression vm, whose value is the integer 22.
- The method to execute is determined based on the number and types
of the actual parameters, by looking for the definition of a method whose
signature corresponds to the invocation (the name of the method must be the
same, and the actual parameters must correspond in number and types to the
formal parameters): in our case, the method to execute must have the
signature A(int).
- The execution of the calling method is suspended: in our case, it
is the main() method.
- The AR is created for the current activation of the called method:
in our case, the AR for the current activation of A() is created;
the AR contains:
- the memory locations for the formal parameters: in our case, the
parameter pa of type int;
- the memory locations for the local variables: in our case, the
parameter va of type int;
- a memory location for the return value: in our case indicated with RV;
- a memory location for the return address: in our case indicated with
RA.
- The values of the actual parameters are assigned to the
corresponding formal parameters: in our case, the formal parameter
pa is initialized to the value 22.
- The return address in the AR is set to the address of the next
statement in the calling method that must be executed at the end of the
current invocation: in our case, the return address in the AR for the
activation of A() is set to the value 104, which is the
address of the statement m4 of main(), to be executed when
the activation of A() will be finished; the AR at this point is as
shown in 2 in the above figure.
- The address of the first statement of the invoked method is
assigned to the program counter: in our case, the address 200,
which is the address of the first statement of A(), is assigned to the
program counter.
- The next statement indicated by the program counter is executed
(this is the first statement of the invoked method): in our case, the
statement at address 200, i.e., the first statement of A().
After these steps, the statements of the called method, in our case of
A(), are executed in sequence. Specifically, if the method contains
itself method calls, such methods will be activated and executed, and will
terminate. In our case, the method B() will be activate and,
executed, and will terminate, with a mechanisms analogous to that for method
A(); the stack of ARs evolves as shown above in 3 and 4.
Let us now analyze in detail what happens when the activation of A()
terminates, i.e., when the statement return va+pa; is
executed. Before the execution of this statement, the stack of ARs is as shown
in 4 in the figure above (to be precise, the memory location reserved for the
return value, indicated with RV in the figure, is initialized the moment the
return statement is executed, and not before).
- The value stored in the memory location reserved for the return
address in the current AR is assigned to the program counter: in our case,
such a value is equal to 104, which is precisely the address, stored
in AR, of the next statement in main() that should be executed.
- If the called method needs to return a value, such a value is
stored in a specific memory location in the current AR: in our case, the
value 67, which is the result of the evaluation of the expression
va+pa, is stored in the memory location indicated with RV, which is
suited to contain the return value.
- The AR for the current activation is removed from the stack of ARs,
and the current AR becomes the one immediately below it in the stack;
together with the elimination of the AR from the stack of ARs, the return
value, if present, is copied into a memory location of the AR of the calling
method: in our case, the AR for the activation of A() is removed
from the stack, and the current AR becomes the one for the activation of
main(); moreover, the value 67, stored in the memory location RV,
is assigned to the variable vm in the AR of main(); the
stack of ARs is as shown in 5 in the figure above.
- The next statement indicated by the program counter is executed
(i.e., the statement specified in step 1): in our case, the statement with
address 104 is executed, and this corresponds to continuing the
execution of main().
Next: Evolution of the stack
Up: Unit 11
Previous: Stack of activation records