> Yes, but what I mean is that as stated in the jvm
> documentation the invokespecial was once called
> invokenonvirtual, and final methods are nonvirtual,
> so wouldn't it make more sence that the invokespecial
> was also used for final methods, instead of the more
> heavyweight invokevirtual?
I believe invokenonvirtual was less restrictive than invokespecial but as to why it was changed I don't know. Simplicity possibly, but maybe one of the Sun engineers here know.
There is no meaningful sense in which 'invokevirtual' is heavier than 'invokespecial', any more than the Intel 'addl' opcode is heavier than the 'adcl' opcode. They perform related tasks that are conveniently expressed with different opcodes.
Their specifications are of comparable complexity, and they provide complementary parts of a range of semantic special casees required to implement Java. The first could have been split into 'invokevirtual' and 'invokefinal', but this would have had an impact on the class evolution rules, would have made them more restrictive. In fact some interpreters do split them, internally. Likewise, 'invokespecial' could have been split into 'invokesuper' and 'invokeconstructor', but there was no reason to burn two instruction code points. When processing 'invokespecial' an interpreter may have to distinguish the two cases, but that's just part the cost of doing business.
The cases of class vs. interface invocation were split ('invokevirtual' vs. 'invokeinterface') were split, and this did cause restrictions in the class evolution rules. (These are the rules that govern the ability to compile and upgrade classes separately.)I suppose that those two bytecodes were orginally split because the designers contemplated a use for the extra two bytes in the latter instruction's format, which is ironic because typical Java implementations simply ignore those bytes. Yes, interface calls are a little trickier than virtual calls (than final calls), but in practice interpreters and JITs use a lot of common code to handle all call cases, and regardless of original bytecode they all tend to merge into each other. (See doCall.cpp in the Hotspot sources.) In particular, an 'invokeinterface' will be downgraded to an 'invokevirtual' if the receiver type is a class which implements the target method, and the call may be further downgraded to final. Even if the call cannot be statically strength-reduced, any non-special call might be implemented as a monomorphic call site, regardless of original opcode.
I guess the main point is that bytecodes have little to do with performance; they are a semantic specification, and any competent system will tend to optimize away superficial differences. When was the last time you worried about the performance difference between pre-increment and post-increment or register and non-register in a C++ program? It's been a while, and we're long past that point with JVMs also.