Bytecode
Type | Description |
u1 | invokeinterface opcode = 0xB9 (185) |
u2 | index |
u1 | <n> |
u1 | 0 |
Stack ..., objectref, [arg1, [arg2 ...]] => ...
Description
invokeinterface is used to invoke a method declared within a Java interface. For example, if you have the Java code:
void test(Enumeration enum) { boolean x = enum.hasMoreElements(); ... }
invokeinterface will be used to call the hasMoreElements() method, since Enumeration is a Java interface, and hasMoreElements() is a method declared in that interface. In this example, the Java compiler generates code like:
aload_1 ; push local variable 1 (i.e. the enum object) onto the stack ; call hasMoreElements() invokeinterface java/util/Enumeration/hasMoreElements()Z 1 istore_2 ; store the boolean result in local variable 2 (i.e. x)
Which particular implementation of hasMoreElements() is used will depend on the type of object held in local variable 1 at runtime.
Before performing the method invokation, the interface and the method identified by <method-spec> are resolved. See Chapter 9 for a description of how methods are resolved.
To invoke an interface method, the interpreter first pops <n> items off the operand stack, where <n> is an 8-bit unsigned integer parameter taken from the bytecode. The first of these items is objectref, a reference to the object whose method is being called. The rest of the items are the arguments for the method.
Then the class of the object referred to by objectref is retrieved. This class must implement the interface named in <method-spec>. The method table for this class is searched, and the method with the given methodname and descriptor is located.
Once the method has been located, invokeinterface calls the method. First, if the method is marked as synchronized, the monitor associated with objectref is entered. Next, a new stack frame is established on the callstack. Then the arguments for the method are placed in the local variable slots of the new stack frame structure. arg1 is stored in local variable 1, arg2 is stored in local variable 2 and so on. objectref is stored in local variable 0, the local variable used by the special Java variable this. Execution continues at the first instruction in the bytecode of the new method.
Methods marked as native are handled slightly differently. For native methods, the runtime system locates the platform-specific code for the method, loading it and linking it into the JVM if necessary. Then the native method code is executed with the arguments that were popped from the operand stack. The exact mechanism used to invoke native methods is implementation-specific.
When the method called by invokeinterface returns, any single (or double) word return result is placed on the operand stack of the current method. If the invoked method was marked as synchronized, the monitor associated with objectref is exited. Then execution continues at the instruction that follows invokeinterface in the bytecode.
The nargs operand is an unsigned byte which must not be
zero. The objectref must be of type reference
and must be followed on
the operands stack by nargs - 1 words of arguments. The number of words of
arguments and the type and order of the values they represent must be consistent with the
descriptor of the selected interface method.
The method table of the class of the type of objectref is
determined. If objectref is an array type, then the method table of class Object
is used. The method table is searched for a method whose name and descriptor are identical
to the name and descriptor of the resolved constant pool entry.
The result of the search is a method table entry, which includes a direct reference to
the code for the interface method and the method's modifier information . The method table
entry must be that of a public
method.
If the method is synchronized
, the monitor
associated with objectref is acquired.
If the method is not native
, the nargs - 1
words of arguments and objectref are popped from the operand stack. A new stack
frame is created for the method being invoked, and objectref and the words of
arguments are made the values of its first nargs local variables, with objectref
in local variable 0, arg1 in local variable 1, and so on. The new
stack frame is then made current, and the Java Virtual Machine pc
is set to
the opcode of the first instruction of the method to be invoked. Execution continues with
the first instruction of the method.
If the method is native
and the platform-dependent
code that implements it has not yet been loaded and linked into the Java Virtual Machine,
that is done. The nargs - 1 words of arguments and objectref are popped from
the operand stack; the code that implements the method is invoked in an
implementation-dependent manner.
NullPointerException - objectref is null
StackOverflowError - no more space in callstack for a new stack frame
Notes
1. Of the instructions used to invoke instance methods, invokeinterface is the most complex to implement, and typically the least efficient. See Chapter 10 (Implementation) for more details on this.
2. invokevirtual cannot be used to invoke the special methods <init> or <clinit> - see invokespecial.
3. The <n> and 0 byte parameters in bytecode are present mostly for historical reasons.
Unlike invokevirtual, invokestatic, and invokespecial, the number of arguments words (nargs) for the method invocation is made available as an operand of the invokeinterface instruction. As with the other instructions, that value can also be derived from the descriptor of the selected method. The derived value must be identical to the value of the nargs operand. This redundancy is historical, but the nargs operand also reserves space in the instruction for an operand used by the invokeinterface_quick pseudo-instruction which may replace invokeinterface at run time.
The fourth operand byte of the invokeinterface instruction is unused by the instruction itself and must be zero. It exists only to reserve space for an additional operand added if the invokeinterface instruction is replaced by the invokeinterface_quick pseudo-instruction at run time.