5

Disassembling some Java 8 code I found out that some invokestatic calls on static methods in interface (particularly this was java.util.function.Function.identity()) uses InterfaceMethodRef in const pool; this is what javap -s -c -v p show me:

    15: invokestatic  #66  // InterfaceMethod java/util/function/Function.identity:()Ljava/util/function/Function;

According to JVM 8 spec this is not possible, and when I've used this instruction in classfile with version Java 7 (major version=51), it has thrown VerifyError on this instruction.

However, when I've changed the major version to 52, it started working like a charm. Note that I am running on Oracle JDK 1.8.0_60. I wonder why this change was needed (the invoked method is linked statically, isn't it?) and whether this is documented anywhere.

assylias
  • 321,522
  • 82
  • 660
  • 783
Radim Vansa
  • 5,686
  • 2
  • 25
  • 40

1 Answers1

9

Well, before Java 8, static methods in interfaces were not allowed, so obviously, any attempt to use them in a previous version or within a class file having an older version is doomed to fail, regardless of how it is implemented in Java 8.

Before Java 8, we had the following two rules:

  1. The class_index item of a CONSTANT_Methodref_info structure must be a class type, not an interface type.

    The class_index item of a CONSTANT_InterfaceMethodref_info structure must be an interface type.

    (See JVMSpec 7 §4.4.2)

  2. The method descriptor of an invokestatic must refer a CONSTANT_Methodref_info entry

    (See JVMSpec 7 §6.5)

    The run-time constant pool item at that index must be a symbolic reference to a method (§5.1), which gives the name and descriptor (§4.3.3) of the method as well as a symbolic reference to the class in which the method is to be found.

    It might not look that clear that “symbolic reference to a method” precludes interface methods, but without that assumption we had no difference to the behavior of Java 8 at all. It also will become clearer by comparing with the JVM specification for Java 8 or considering that interface methods were always implied to be non-static.

It should be obvious that for adding support for static methods in interfaces, to be invoked via invokestatic, at least one rule has to change.

If we look at the rules and their wording, we see that the first one is quite clear whereas in the second one, it’s not entirely obvious that “symbolic reference to a method” is referring to CONSTANT_Methodref_info entries and precluding a “symbolic reference to an interface method”. The decision was to change that rule and make the wording clearer at the same time:

(JVMSpec 8 §6.5):

The run-time constant pool item at that index must be a symbolic reference to a method or an interface method (§5.1), which gives the name and descriptor (§4.3.3) of the method as well as a symbolic reference to the class or interface in which the method is to be found.

Now it’s clear that invokestatic may refer to interface methods and thus the first rule doesn’t need to be touched, and it hasn’t been touched. But note that the first rule never mandated the interface methods to be non-static. It’s only about whether the declaring type is an interface or not.


This obviously reduces the value of the distinction between CONSTANT_Methodref_info and CONSTANT_InterfaceMethodref_info but this was unavoidable. If the first rule was relaxed instead, it would also soften this distinction.

But there was a strong reason to change the invocation side instead: due to the introduction of default methods, there is now the possibility to invoke an overridden default method via invokespecial just like other overridden non-abstract methods before. Thus, invokespecial may now refer to interface methods as well.

Insisting on a match between the type of the invocation instruction and the constant pool entry type, like with the old rules, would imply that in the case of default methods, we would sometimes need two pool entries to describe the same target method, one for invokeinterface and a different one for invokespecial.

Holger
  • 285,553
  • 42
  • 434
  • 765