When a method is called via invokevirtual, the calling method pops off the values to pass to the called method along with the objectref and places them in the new stack frame.
How does it know which stack entry is the objectref? My guess is that it does so by looking at the type of the called method and parses this to determine how many values to pop off, but this seems extremely inefficient. Is there some other mechanism that I'm overlooking?
When you use the class file format as starting point, the method descriptor is the only way to determine, which values from the operand stack have to become the first local variables of the new stack frame.
As an exception to the rule, the
invokeinterfaceinstruction has an embedded count which can be used to determine the number of (type 1) elements to consume. As the documentation states:This historical redundancy doesn’t change the fact that the JVM has to cope with method descriptors as the source of this information, e.g. for
invokevirtual,invokestatic,invokespecial, orinvokedynamic. Further, a conforming JVM is required to verify this information, to throw an error if theinvokeinterface’s count differs from the count derived from the method descriptor.Generally, the verifier is responsible for detecting when method invocations are inconsistent to the stack frame’s state and therefore, has to process the method descriptors and model their effect on the operand stack. This implies that, unless you’re using a JVM that verifies each instruction right before its actual execution, it has to handle these descriptors even without executing an actual invocation. The obvious solution is to convert the method descriptors into an easier-to-process internal representation in a first step.
In short, these method descriptors are inefficient but with a reasonable JVM implementation you’re paying the costs only once, not for every invocation.