19 Method Invocation and Return

orders orders backward   forward
comments comments
1997 The McGraw-Hill Companies, Inc. All rights reserved.
Any use of this Beta Book is subject to the rules stated in the Terms of Use.

Method Invocation and Return

The Java Virtual Machine ­s instruction set has four different instructions that invoke methods . This chapter describes these four instructions and the situations in which each is used.

Method Invocation

The Java programming language provides two basic kinds of methods: instance methods and class (or static) methods. The difference between these two kinds of methods are:

  1. instance methods require an instance before they can be invoked; class methods do not,
  2. instance methods use dynamic (late) binding; class methods use static (early) binding.

When the Java Virtual Machine invokes a class method, it selects the method to invoke based on the type of the object reference, which is always known at compile-time. When the virtual machine invokes an instance method, by contrast, it selects the method to invoke based on the actual class of the object, which may be known only at run-time.

The Java Virtual Machine uses two different instructions to invoke these two different kinds of methods: invokevirtual for instance methods and invokestatic for class methods. These instructions are shown in Table 19-1.

Table 19-1. Method invocation

Opcode Operand(s) Description
invokevirtual indexbyte1, indexbyte2 pop objectref and args, invoke instance method at constant pool index
invokestatic indexbyte1, indexbyte2 pop args, invoke class method at constant pool index

As mentioned in earlier chapters, references to methods are initially symbolic. All invoke instructions, such as invokevirtual and invokestatic , refer to a constant pool entry that initially contains a symbolic reference. When the Java Virtual Machine encounters an invoke instruction, if the symbolic reference has not yet been resolved, the virtual machine resolves it as part of the execution of the invoke instruction.

To resolve a symbolic reference, the Java Virtual Machine locates the method being referred to symbolically and replaces the symbolic reference with a direct reference. A direct reference, such as a pointer or offset, allows the virtual machine to invoke the method more quickly if the reference is ever used again in the future.

For example, upon encountering an invokevirtual instruction, the Java Virtual Machine forms an unsigned 16-bit index into the constant pool of the current class from the indexbyte1 and indexbyte2 operands that follow the invokevirtual opcode. The constant pool entry contains a symbolic reference to the method to invoke.

During resolution, the Java Virtual Machine also performs several verification checks. These checks ensure that Java language rules are followed and that the invoke instruction is safe to execute. For example, the virtual machine first makes sure the symbolically referenced method even exists. If it exists, it checks to make sure the current class can legally access the method. For instance, if the method is private, it must be a member of the current class. If any of these checks fail, the Java Virtual Machine throws an exception. Chapter 5, "The Java Virtual Machine," gives an overview of the resolution process. Chapter 8, "The Linking Model," describes the process in detail.

Once a method has been resolved, the Java Virtual Machine is ready to invoke it. If the method is an instance method, it must be invoked on an object. For every instance method invocation, the virtual machine expects a reference to the object (objectref) to be on the stack. In addition to objectref, the virtual machine expects the arguments (args) required by the method, if any, to be on the stack. If the method is a class method, which doesn't require an objectref because class methods aren ­t invoked on an object, only the args are on the stack.

The objectref and args (or just args, in the case of a class method) must be pushed onto the calling method ­s operand stack by the instructions that precede the invoke instruction.

Invoking a Java Method

As mentioned in Chapter 5, "The Java Virtual Machine," the virtual machine creates a new stack frame for each Java (not native) method it invokes. The stack frame contains space for the method's local variables, its operand stack, and any other information required by a particular virtual machine implementation. The size of the local variables and operand stack are calculated at compile-time and placed into the class file, so the virtual machine knows just how much memory will be needed by the method's stack frame. When it invokes a method, it creates a stack frame of the proper size for that method. The virtual machine pushes the new stack frame onto the Java stack.

For an instance method, the virtual machine pops the objectref and args from the operand stack of the calling method's stack frame. It places the objectref on the new stack frame as local variable 0, and all the args as local variable 1, 2, and so on. The objectref is the implicit this pointer that is passed to any instance method.

For a class method, the virtual machine just pops the args from the operand stack of the calling method's frame and places them onto the new stack frame as local variable 0, 1, 2, and so on.

Once the objectref and args (or just the args, for a class method) have been placed into the local variables of the new frame, the virtual machine makes the new stack frame current and sets the program counter to point to the first instruction in the new method.

Invoking a Native Method

As mentioned in Chapter 5, "The Java Virtual Machine," the virtual machine invokes native methods in an implementation dependent manner. When invoking a native method, the virtual machine does not push a new stack frame onto the Java stack for the native method. At the point in which the thread enters the native method, it leaves the Java stack behind. When the native method returns, the Java stack will once again be used.

Other Forms of Method Invocation

Although instance methods are normally invoked with invokevirtual , in certain situations, two other opcodes may be used: invokespecial and invokeinterface . These opcodes are shown in Table 19-2.

The invokespecial instruction is used for three situations in which an instance method must be invoked based on the type of the reference, not on the class of the object. The three situations are:

  1. instance initialization ( <init() ) methods
  2. private methods
  3. methods invoked with the super keyword

Invokeinterface is used to invoke an instance method given a reference to an interface.

Table 19-2. Method invocation

Opcode Operand(s) Description
invokespecial indexbyte1, indexbyte2 pop objectref and args, invoke instance method at constant pool index
invokeinterface indexbyte1, indexbyte2 pop objectref and args, invoke instance method at constant pool index

As mentioned in Chapter 7, "The Lifetime of a Class," class initialization (or <clinit ()) methods are always invoked directly by the Java Virtual Machine itself, never by any bytecodes. There is no instruction in the Java Virtual Machine ­s instruction set that will invoke a method named <clinit (). If some class file attempts to invoke a <clinit () method with any of the four instructions described in this chapter, the virtual machine will throw an exception.

The invokespecial instruction

Invokespecial differs from invokevirtual primarily in that invokespecial normally (with one special exception) selects a method based on the type of the reference rather than the class of the object. In other words, it does static binding instead of dynamic binding. In each of the three situations where invokespecial is used, dynamic binding wouldn't yield the desired result.

invokespecial and <init()

As mentioned in Chapter 7, "The Lifetime of a Class," the <init() method, or instance initialization method, is where the compiler places code for constructors and instance variable initializers. A class gets one <init() method in the class file for each constructor in the source. If you don't explicitly declare a constructor in the source, the compiler will generate a default no-arg constructor for you. This default constructor also ends up as an <init() method in the class file. So just as every class will have at least one constructor, every class will have at least one <init() method. These methods are always invoked with invokespecial .

The <init() methods are called only when a new instance is created. At least one <init() method will be invoked for each class along the inheritance path of the newly created object, and multiple <init() methods could be invoked for any one class along that path.

The reason invokespecial is used to invoke <init() methods is that subclass <init() methods need to be able to invoke superclass <init() methods. This is how multiple <init() methods get invoked when an object is instantiated . The virtual machine invokes an <init() method declared in the object's class. That <init() method first invokes either another <init() method in the same class, or an <init() method in its superclass. This process continues all the way up to Object .

For example, consider this code:

 

begin

// On CD-ROM in file invoke/ex1/Dog.java

class Dog {

}

// On CD-ROM in file invoke/ex1/CockerSpaniel.java

class CockerSpaniel extends Dog {

public static void main(String args[]) {

CockerSpaniel bootsie = new CockerSpaniel();

}

}

end

When you invoke main() , the virtual machine will allocate space for a new CockerSpaniel object, then invoke CockerSpaniel 's default no-arg <init() method to initialize that space. That method will invoke Dog 's <init() method, which will invoke Object 's <init() method. Here are the bytecodes for the main() method of class CockerSpaniel :

 

begin

0 new #1 <Class CockerSpaniel

3 invokespecial #3 <Method <init() of class CockerSpaniel

6 return

end

CockerSpaniel ­s main() method allocates memory for the new CockerSpaniel object and initializes that memory to default initial values with the new instruction. (The " #1 " specifies the constant pool entry that refers to the class to instantiate, in this case, class CockerSpaniel .) The new instruction pushes a reference to the newly created CockerSpaniel object onto the stack. The main() method then calls the <init () method of class CockerSpaniel using invokespecial on that object reference. (The " #3 " specifies the constant pool entry that contains the reference to CockerSpaniel ­s <init () method.) The Java Virtual Machine pushes a new frame onto the Java Stack and places the object reference into local variable 0 of the new frame. Here are the bytecodes for the <init () method of class CockerSpaniel :

 

begin

0 aload_0

1 invokespecial #4 <Method <init

() of class Dog

4 return

end

As mentioned above, this <init () method corresponds to the default no-arg constructor generated automatically by the compiler for class CockerSpaniel . It first pushes the reference to the object being initialized onto the stack from local variable 0, then it invokes the Dog ­s <init () method on that reference. (The " #4 " specifies the constant pool entry that contains the reference to Dog ­s <init () method.) Here are the bytecodes for Dog ­s <init () method:

 

begin

0 aload_0

1 invokespecial #3 <Method <init

() of class java.lang.Object

4 return

end

This <init () method corresponds to the default no-arg constructor generated automatically by the compiler for class Dog . It first pushes the reference to the object being initialized onto the stack from local variable 0, then it invokes the Object ­s <init () method on that reference. (The " #3 " specifies the constant pool entry that contains the reference to Object ­s <init () method. Remember that this is not the same constant pool as that referred to by the methods of class CockerSpaniel . Each class has its own constant pool.) When all three of these <init () methods have returned, the new CockerSpaniel object created by main() is fully initialized and ready for use.

Because every class has at least one <init() method, it is common that classes have <init() methods with the same signature. (A method's signature is its name and the number and types of its arguments.) The <init() methods for the three classes in the inheritance path for CockerSpaniel, for example, all have the same signature. CockerSpaniel , Dog , and Object all contain a method named <init() that takes no arguments.

It would be impossible to invoke a Dog 's <init() method from CockerSpaniel 's <init() method using invokevirtual , because invokevirtual would perform dynamic binding and invoke CockerSpaniel 's <init() method. With invokespecial , however, Dog 's <init method can be invoked from CockerSpaniel 's <init() method, because the type of the reference placed in CockerSpaniel ­s class file (in constant pool entry " #4 ") is Dog .

invokespecial and Private Methods

In the case of private instance methods, it must be possible for a subclass to declare an instance method with the same signature as a private instance method in a superclass. ( invokespecial is not used to invoke private class methods, just private instance methods. Private class methods are invoked with invokestatic .) For example, consider the following code in which interestingMethod() is declared as private in a superclass and with package access in a subclass:

 

begin

// On CD-ROM in file invoke/ex2/Superclass.java

class Superclass {

private void interestingMethod() {

System.out.println("Superclass's interesting method.");

}

void exampleMethod() {

interestingMethod();

}

}

// On CD-ROM in file invoke/ex2/Subclass.java

class Subclass extends Superclass {

void interestingMethod() {

System.out.println("Subclass's interesting method.");

}

public static void main(String args[]) {

Subclass me = new Subclass();

me.exampleMethod();

}

}

end

When you invoke main() in Subclass as defined above, it instantiates a new Subclass object and invokes exampleMethod() on it. Here are the bytecodes for the main() method of class Subclass :

 

begin

0 new #2 <Class Subclass

3 dup

4 invokespecial #6 <Method <init() of class Subclass

7 astore_1

8 aload_1

9 invokevirtual #8 <Method void exampleMethod() of class Superclass

12 return

end

Subclass inherits exampleMethod() from Superclass . When main() invokes exampleMethod() on a Subclass object, it uses invokevirtual . The Java Virtual Machine will create and push a new frame onto the stack and begin executing the bytecodes of exampleMethod() as defined in class Superclass . Here are the bytecodes for exampleMethod() :

 

begin

0 aload_0

1 invokespecial #7 <Method void interestingMethod() of Superclass

4 return

end

Note that exampleMethod() first pushes the reference passed in local variable 0 (the hidden this passed to all instance methods) onto the stack. It then invokes interestingMethod() on that reference with the invokespecial instruction. The class identified in the constant pool entry specified by the invokespecial instruction, entry #7, is Superclass . The Java Virtual Machine invokes the interestingMethod() defined in Superclass even though the object is an instance of class Subclass and there is an accessible interestingMethod() defined in Subclass .

The program correctly prints "Superclass's interesting method" . If interestingMethod() had been invoked with an invokevirtual instruction instead of invokespecial , the program would have printed "Subclass's interesting method" . Why? Because the virtual machine would choose the interestingMethod() to call based on the actual class of the object, which is Subclass . So it would use Subclass 's interestingMethod() . With invokespecial however, the virtual machine selects the method based on the type of the reference, so Superclass 's version of interestingMethod()is invoked.

invokespecial and super

In the case of invocation of a method with the super keyword, as in super.someMethod() , you want the superclass ­s version of a method to be invoked, even if the current class overrides the method. Once again, invokevirtual would invoke the current class ­s version, so it can ­t be used. For an example, consider this code:

 

begin

// On CD-ROM in file invoke/ex3/Cat.java

class Cat {

void someMethod() {

}

}

// On CD-ROM in file invoke/ex3/TabbyCat.java

class TabbyCat extends Cat{

void someMethod() {

super.someMethod();

}

}

end

Here are the bytecodes for TabbyCat ­s someMethod() :

 

begin

0 aload_0

1 invokespecial #4 <Method void someMethod() of class Cat

4 return

end

Had invokevirtual been used in this case, the someMethod() defined in class TabbyCat would have been invoked. Because invokespecial is used and the constant pool entry (#4, in this case) indicates the someMethod() declared in class Cat should be invoked, the Java Virtual Machine correctly invokes the superclass ­s ( Cat ­s) version of someMethod() .

Whether or not the Java Virtual Machine actually uses static binding to execute an invokespecial instruction, or instead uses a special kind of dynamic binding, depends on whether or not the referring class ­s ACC_SUPER flag is set. Prior to JDK version 1.0.2, the invokespecial instruction was called invokenonvirtual and always resulted in static binding. It turned out, however, that invokenonvirtual ­s stubborn insistence on static binding did not yield a correct implementation of the semantics of the Java language in all cases. (In other words, there was a "bug" in the instruction set.) In JDK 1.0.2, the invokenonvirtual instruction was renamed invokespecial and its semantics were changed. In addition, a new flag, ACC_SUPER , was added to the access_flags item of the Java class file.

The ACC_SUPER flag item of a class file indicates to the Java Virtual Machine which semantics it should use to execute invokespecial instructions it encounters in the bytecodes of that class file. If the ACC_SUPER flag is not set, the virtual machine uses the old ( invokenonvirtual ) semantics. Else, if the ACC_SUPER flag is set, the virtual machine uses the new semantics. All new Java compilers are supposed to set the ACC_SUPER flag in every class file they generate.

According to the old semantics, the virtual machine will perform static binding in all cases when executing invokespecial . By contrast, the new semantics requires static binding in all cases except one: the invocation of superclass methods.

According to the new semantics, when the Java Virtual Machine resolves an invokespecial instruction ­s symbolic reference to a superclass method, it dynamically searches the current class ­s superclasses to find the nearest superclass implementation of the method. (As used here, " nearest " means the implementation of the method declared in the superclass that is closest to the current class in its inheritance hierarchy.) In most cases, the virtual machine will likely discover that the nearest implementation of the method is in the superclass listed in the symbolic reference. But it is possible that the virtual machine could find the nearest implementation in a different superclass.

For example, imagine you create an inheritance hierarchy of three classes: Animal , Dog , and CockerSpaniel . Assume class Dog extends class Animal , class CockerSpaniel extends class Dog , and that a method defined in CockerSpaniel uses invokespecial to invoke a non-private superclass method named walk() . Assume also that when you compiled CockerSpaniel , the compiler set the ACC_SUPER flag. In addition, assume that when you compiled CockerSpaniel , class Animal defined a walk() method, but Dog didn ­t. In that case, the symbolic reference from CockerSpaniel to the walk() method would give Animal as its class. When the invokespecial instruction in CockerSpaniel ­s method is executed, the virtual machine would dynamically select and invoke Animal ­s walk() method.

Now imagine that later, you added a walk() method to Dog , and recompiled Dog , but didn ­t recompile CockerSpaniel . CockerSpaniel ­s symbolic reference to the superclass walk() method still claims Animal as its class, even though there is now an implementation of walk() in Dog ­s class file. Nevertheless, when the invokespecial instruction in CockerSpaniel ­s method is executed, the virtual machine would dynamically select and invoke Dog ­s implementation of the walk() method.

The invokeinterface Instruction

The invokeinterface opcode performs the same function as invokevirtual , it invokes instance methods and uses dynamic binding. The difference between these two instructions is that invokevirtual is used when the type of the reference is a class , whereas invokeinterface is used when the type of the reference is an interface .

The Java Virtual Machine uses a different opcode to invoke a method on an interface reference because it can't make as many assumptions about the method table offset given an interface reference as it can given a class reference. (Method tables are described in Chapter 8, "The Linking Model.") Given a class reference, a method will always occupy the same position in the method table, independent of the actual class of the object. This is not true given an interface reference. The method could occupy different locations for different classes that implement the same interface.

For examples of the use of invokeinterface in bytecodes, see the "Examples of Method Invocation" section later in this chapter.

Invocation Instructions and Speed

As you might imagine, invoking a method given an interface reference is likely slower than invoking a method given a class reference. When the Java Virtual Machine encounters an invokevirtual instruction and resolves the symbolic reference to a direct reference to an instance method, that direct reference is likely an offset into a method table. From that point forward, the same offset can be used. For an invokeinterface instruction, however, the virtual machine will have to search through the method table every single time the instruction is encountered , because it can't assume the offset is the same as the previous time.

The fastest instructions will likely be invokespecial and invokestatic , because methods invoked by these instructions are statically bound. When the Java Virtual Machine resolves the symbolic reference for these instructions and replaces it with a direct reference, that direct reference will likely include a pointer to the actual bytecodes.

Examples of Method Invocation

The following code illustrates the various ways the Java Virtual Machine invokes methods and shows which invocation opcode is used in each situation:

 

begin

// On CD-ROM in file invoke/ex4/InYourFace.java

interface InYourFace {

void interfaceMethod ();

}

// On CD-ROM in file invoke/ex4/ItsABirdItsAPlaneItsSuperclass.java

class ItsABirdItsAPlaneItsSuperclass implements InYourFace {

ItsABirdItsAPlaneItsSuperclass(int i) {

super(); // invokespecial (of an <init

)

}

static void classMethod() {

}

void instanceMethod() {

}

final void finalInstanceMethod() {

}

public void interfaceMethod() {

}

}

// On CD-ROM in file invoke/ex4/Subclass.java

class Subclass extends ItsABirdItsAPlaneItsSuperclass {

Subclass() {

this(0); // invokespecial (of an <init

)

}

Subclass(int i) {

super(i); // invokespecial (of an <init)

}

private void privateMethod() {

}

void instanceMethod() {

}

final void anotherFinalInstanceMethod() {

}

void exampleInstanceMethod() {

instanceMethod(); // invokevirtual

super.instanceMethod(); // invokespecial

privateMethod(); // invokespecial

finalInstanceMethod(); // invokevirtual

anotherFinalInstanceMethod(); // invokevirtual

interfaceMethod(); // invokevirtual

classMethod(); // invokestatic

}

}

// On CD-ROM in file invoke/ex4/UnrelatedClass.java

class UnrelatedClass {

public static void main(String args[]) {

Subclass sc = new Subclass(); // invokespecial (of an <init

)

Subclass.classMethod(); // invokestatic

sc.classMethod(); // invokestatic

sc.instanceMethod(); // invokevirtual

sc.finalInstanceMethod(); // invokevirtual

sc.interfaceMethod(); // invokevirtual

InYourFace iyf = sc;

iyf.interfaceMethod(); // invokeinterface

}

}

end

Here are the bytecodes generated by javac for each of these classes (The compiler generates no bytecodes for the InYourFace interface.):

 

begin

// Methods of class ItsABirdItsAPlaneItsSuperclass

// Method <init

(int)

0 aload_0

1 invokespecial #4 <Method <init() of class java.lang.Object

4 return

// Method void classMethod()

0 return

// Method void instanceMethod()

0 return

// Method void finalInstanceMethod()

0 return

// Method void interfaceMethod()

0 return

// ------------------------------------

// Methods of class Subclass

// Method <init()

0 aload_0

1 iconst_0

2 invokespecial #4 <Method <init(int) of class Subclass

5 return

// Method <init(int)

0 aload_0

1 iload_1

2 invokespecial #3 <Method <init(int) of class

ItsABirdItsAPlaneItsSuperclass

5 return

// Method void privateMethod()

0 return

// Method void instanceMethod()

0 return

// Method void anotherFinalInstanceMethod()

0 return

// Method void exampleInstanceMethod()

0 aload_0

1 invokevirtual #9 <Method void instanceMethod() of class Subclass

4 aload_0

5 invokespecial #8 <Method void instanceMethod() of class

ItsABirdItsAPlaneItsSuperclass

8 aload_0

9 invokespecial #11 <Method void privateMethod() of class Subclass

12 aload_0

13 invokevirtual #7 <Method void finalInstanceMethod() of class

ItsABirdItsAPlaneItsSuperclass

16 aload_0

17 invokevirtual #5 <Method void anotherFinalInstanceMethod() of

class Subclass

20 aload_0

21 invokevirtual #10 <Method void interfaceMethod() of class

ItsABirdItsAPlaneItsSuperclass

24 invokestatic #6 <Method void classMethod() of class

ItsABirdItsAPlaneItsSuperclass

27 return

// ------------------------------------

// Methods of class UnrelatedClass

// Method <init()

0 aload_0

1 invokespecial #7 <Method java.lang.Object()

4 return

// Method void main(java.lang.String[])

0 new #3 <Class Subclass

3 dup

4 invokespecial #6 <Method <init() of class Subclass

7 astore_1

8 invokestatic #8 <Method void classMethod() of class

ItsABirdItsAPlaneItsSuperclass

11 invokestatic #8 <Method void classMethod() of class

ItsABirdItsAPlaneItsSuperclass

14 aload_1

15 invokevirtual #10 <Method void instanceMethod() of class Subclass

18 aload_1

19 invokevirtual #9 <Method void finalInstanceMethod() of class

ItsABirdItsAPlaneItsSuperclass

22 aload_1

23 invokevirtual #12 <Method void interfaceMethod() of class

ItsABirdItsAPlaneItsSuperclass

26 aload_1

27 astore_2

28 aload_2

29 invokeinterface (args 1) #11 <Method void interfaceMethod() of

interface InYourFace

34 return

end

Returning from Methods

There are several opcodes that return from a method, one for each type of return value. These opcodes, which are shown in Table 19-3, take no operands. If there is a return value, it must be on the operand stack. The return value is popped off the operand stack and pushed onto the operand stack of the calling method's stack frame. The current stack frame is popped, and the calling method's stack frame becomes current. The program counter is reset to the instruction in the calling method just following the instruction that invoked the returning method.

Table 19-3. Returning from methods

Opcode Operand(s) Description
ireturn none pop int , push onto stack of calling method and return
lreturn none pop long , push onto stack of calling method and return
freturn none pop float , push onto stack of calling method and return
dreturn none pop double , push onto stack of calling method and return
areturn none pop object reference, push onto stack of calling method and return
return none return void

The ireturn instruction is used for methods that return int , char , byte , or short .

On the CD-ROM

The CD-ROM contains the source code examples from this chapter in subdirectories of the invoke directory.

The Resources Page

For more information about the material presented in this chapter, visit the resources page: http://www.artima.com/insidejvm/invoke.html .

orders orders backward   forward
comments comments

 COMPUTING MCGRAW-HILL Beta Books Contact Us Order Information Online Catalog

Computing McGraw-Hill is an imprint of the McGraw-Hill Professional Book Group.


a division of the mcgraw-hill companies
Copyright 1997 The McGraw-Hill Companies. All rights reserved. Any use is subject to the Terms of Use; the corporation also has a comprehensive Privacy Policy governing information we may collect from our customers.


Inside the Java virtual machine
Inside the Java 2 Virtual Machine
ISBN: 0071350934
EAN: 2147483647
Year: 1997
Pages: 28
Authors: Bill Venners

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net