Why are there 4 separate bytecodes for executing static/virtual/interface/special methods when one would suffice?
Since each method call includes the target method signature it seems to me that the class verifying step could tell by analysing the target whether its invoking a static, virtual etc and do the right thi开发者_C百科ng ?
Is having 4 byte codes a waste of 3 byte codes or is this merely self documenting if one dumps a class file using javap ?
If you're talking about invokeinterface
, invokespecial
, invokestatic
, and invokevirtual
, there are differences between them. The effects on the stack for a start.
Let's assume you have only invoke opcode for both virtual and static. Let's assume in compile time you have
Test {
public static void test(Test t) {
// static method
}
}
and somewhere a call to this static with pseudo bytecode
push t
jmp Test.test(T)V
Now let's assume someone uses another Test class in runtime
Test {
public void test(Test t) {
// obj call
}
}
In this case jmp Test.test(T)V
is still valid. The problem is that it will mess up the stack. Two different opcodes allow to catch this problem link time.
This would have been possible. However, it would add extra cost every time one of the instructions is interpreted. So performance would be harmed for very little advantage.
It has been argued that separate instructions improve security, by reducing the chances of confusing the VM. Not sure I'm convinced by that.
you need this opcodes because at the time the bytecode references for methods are laid out, they only contain symbolic references to entries in the constant pool. To resolve these references, you need to know on which type you need to resolve: for example, the difference between invokespecial and invokevirtual is static vs dynamic binding . For invokespecial you resolve on the type of the reference, not the class of the object. This information cannot be gleaned without the compiler putting in a special opcode to distinguish the methods. In java the code is typically linked dynamically, which is what forces these opcodes.
At least invokespecial
is needed to be a separate instruction since java allows explicitly calling the super implementation of an overridden method:
class Super {
public void m() { }
}
class Sub {
public void m() {
super.m();
}
}
The call in Sub
has to be an invokespecial
since it would otherwise just call itself and run out of stack.
I think This debate was unnneccesary as java have this design decision. Not sure but you might want to look at one more What they call user defined data endpoints : invokedynamic
精彩评论