Method Invocation

Read section 10.3 (pg 214)

Invoking Static Methods

To invoke a static method, push all of the arguments onto the stack, then execute:

invokestatic METHOD  ; <c b a...> -> <d...> where d = METHOD(a, b, c)

Here METHOD is the fully qualified signature of the method to be invoked:

PACKAGE/CLASS/METHOD(PARAM TYPES)TYPE

After this instruction the return value should be on top of the stack.

Executing this instruction pops the arguments off the stack, creates a new stack frame, pushes the arguments onto that stack, and sets the PC to the first instruction of the method.

Example

The following instruction sequence computes Math.sin(pi/4) where pi = 3.1416:

ldc2_w 3.1416
ldc2_w 4.0
ddiv
invokestatic java/lang/Math/sin(D)D

Example

Recall the definition of the static factorial function (n!) given in Functions.java.

The following instruction sequence loads Functions.fact(4) into locals[0]:

ldc 4
invokestatic Functions/fact(I)I
istore 0

Loading & Storing Fields

Pushing a field onto the stack is done with

getfield Class/Field Type

getstatic Class/Fieeld Type

Storing the top of the stack into a field is done with

putfield Class/Field Type

putstatic Class/Field Type

Invoking non-Static Methods

To invoke a non-static method, push the object that invokes the method onto the stack (this) along with any other explicit arguments, then execute:

invokevirtual METHOD  ;<c b a...> -> <d...> where d = a.METHOD(b, c)

After this instruction the return value should be on top of the stack.

Executing this instruction pops the arguments off the stack, creates a new stack frame, pushes the arguments onto that stack, and sets the PC to the first instruction of the method.

Example

The Java method invocation:

System.out.println("Hello World!");

is translated into Jasmin as:

getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hello World!"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V

Example

The Java method invocation:

Math.sin(Math.PI/4);

is translated into Jasmin as:

getstatic java/lang/Math/PI D
ldc2_w 4.0
ddiv
invokestatic java/lang/Math/sin(D)D

Example

Recall the temperature conversion calculator defined in Calculator.java.

The following sequence assumes a reference to a Calculator object is stored in locals[1] After the call the centigrade value of 98.6 degrees is stored in locals[2]:

aload 1
ldc 98.6
invokevirtual Calculator/f2c(F)F
fstore 2

invokespecial

Invoke special is similar to invokevirtual, but is used in tricky situations such as invoking constructors:

.method public <init>()V
   aload_0 ; push this
   invokespecial java/lang/Object/<init>()V ; call super
   return
.end method

Demos

Until now we have been invoking Jasmin methods in Java. We can reverse this.

Recall Functions.java contained several static methods. In TestFunctions.j we invoke these methods.

Recall the Fahrenheit-Centigrade calculator:

Calculator.java

We test these functions in TestCalculator.j.

Recursion

A recursive function is a function that calls itself!

Why wouldn't this cause an infinite loop? Why wouldn't f(n) call f(n) call f(n) ...?

It would. Normally f(n) calls f(n – 1) calls f(n – 2) ... calls f(0).

But instead of calling f(-1), f(0) terminates the recursion by returning the answer.

For example, here's a recursive definition of the factorial function:

class RecursiveFunctions {
   public static int fact(int n) {
      if (n <= 0) {
         return 1;
      } else {
         return n * fact(n – 1);
      }
   }
}

Let's trace a call:

RecursiveFunctions.fact(4)
4 * RecursiveFunctions.fact(3)
4 * 3 * RecursiveFunctions.fact(2)
4 * 3 * 2 * RecursiveFunctions.fact(1)
4 * 3 * 2 * 1 * RecursiveFunctions.fact(0)
4 * 3 * 2 * 1 * 1
4 * 3 * 2 * 1
4 * 3 * 2
4 * 6
24

Sometimes recursive functions are easier to write than non-recurive functions.

In the example above we get to assume fact(n – 1) works properly. We don't need to know how it works. We only need to know how to compute fact(n) from fact(n – 1). The answer: multiply by n!

Of course we also need to know fact(0).

Compilers often depend on recursion. For example, to compile a program n lines long, translate the first line into the the target language, then append to this the result of recursively compiling the remaining n – 1 lines:

Compliler {
   Program compile(Program p) {
      if (length(p) == 0) {
         return null; // nothing to do!
      } else {
         Instruction q0 = translate(head(p));
         Program q = compile(tail(p));
         return append(q0, q);
      }
   }
}

See RecursiveFunctions.j for the recursive Jasmin definition of the factorial function.

 

 

recursively compile the first n – 1 lines, then figure out how to translate the last line.