invokestatic <method-spec><method-spec> is a method specification. It is a single token made up of three parts: a classname, a methodname and a descriptor. e.g.
java/lang/System/exit(I)Vis the method called "exit" in the class called "java.lang.System", and it has the descriptor "(I)V" (i.e. it takes an integer argument and returns no result). In Jasmin, the characters up to the '(' character in <method-spec> form the classname and methodname (the classname is all the characters up to the last '/' character, and the methodname is all the characters between the last '/' and the '(' character). The characters from '(' to the end of the string are the descriptor. This is illustrated in the following diagram:
foo/baz/Myclass/myMethod(Ljava/lang/String;)V --------------- --------------------- | -------- | | | | classname methodname descriptorStack
Before | After |
argN | [result] |
... | ... |
arg3 | |
arg2 | |
arg1 |
invokestatic calls a static method (also known as a class method). For example, if you write in Java:
System.exit(1);this is compiled into the JVM code:
iconst_1 ; push 1 onto the stack. ; now call System.exit() invokestatic java/lang/System/exit(I)VBefore performing the method invokation, the class and the method identified by <method-spec> are resolved. See Chapter 9 for a description of how methods are resolved.
invokestatic looks at the descriptor given in <method-spec>, and determines how many arguments the method takes (this may be zero). It pops these arguments off the operand stack. Then it searches the list of static methods defined by the class, locating the method methodname with a descriptor descriptor.
Once the method has been located, invokestatic calls the method. First, if the method is marked as synchronized, the monitor associated with the class object for the method's class is entered. Next, a new stack frame structure is established on the call stack. Then the arguments for the method (which were popped off the current method's operand stack) are placed in local variables of the new stack frame structure. arg1 is stored in local variable 0, arg2 is stored in local variable 1 and so on. Finally, 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 invokestatic 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 the class named in <method-spec> is exited. Execution continues at the instruction that follows invokestatic in the bytecode.
Exceptions
StackOverflowError - no more space in callstack for a new stack frame
Bytecode
In bytecode, after the invokestatic opcode is a 16-bit unsigned integer index. This is the index of an entry in the constant pool. The entry is tagged as a CONSTANT_Methodref entry. This entry has two fields. One field points to a CONSTANT_Class entry in the constant pool whose name is the classname from <method-spec>, and the other points to a CONSTANT_NameAndType entry in the constant pool whose name is the methodname from <method-spec> and whose descriptor is the type descriptor from <method-spec>.
Type | Description |
u1 | invokestatic opcode = 0xB8 (184) |
u2 | index |
invokevirtual, invokespecial, invokeinterface