Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Java 8 default interface methods be inlined by the JIT compiler?

I was analyzing the HotSpot logs for a benchmark I ran for a piece of code in JITWatch and noticed a lot of methods calls not being inlined due to "no static binding". These seem to only occur for calls to default interface methods.

My question is are default interface methods preventing the JIT compiler from inlining their calls?

interface A {
    default double a() {
        return Math.random();
    }
}

interface B extends A {
    default double b() {
        return a();
    }
}

class C implements B {
    public double c() {
        double c = 0;
        for (int i = 0; i < 1_000_000; ++i) {
            c += b();
        }
        return c;
    }

    public static void main(String[] args) {
        System.out.println(new C().c());
    }
}

Upon further inspection in JITWatch, it seems that this problem pertains to default interface methods calling other default interface methods. That would make more sense given the "no static binding" message.

like image 687
Hao Zhang Avatar asked Dec 28 '20 06:12

Hao Zhang


People also ask

Can we override default method of interface Java 8?

A default method cannot override a method from java.

What is the use of default method in interface in Java 8?

Java 8 introduces a new concept of default method implementation in interfaces. This capability is added for backward compatibility so that old interfaces can be used to leverage the lambda expression capability of Java 8. For example, 'List' or 'Collection' interfaces do not have 'forEach' method declaration.

What are Java 8 interface default and static methods?

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces. A static method is a method that is associated with the class in which it is defined rather than with any object.

Can we call interface method in Java 8?

Prior to java 8, interface in java can only have abstract methods. All the methods of interfaces are public & abstract by default. Java 8 allows the interfaces to have default and static methods.

What are the methods of interfaces in Java 8?

Prior to java 8, interface in java can only have abstract methods. All the methods of interfaces are public & abstract by default. Java 8 allows the interfaces to have default and static methods.

What is default method in interface in Java 8?

Java 8 Example: Default method in Interface. The method newMethod() in MyInterface is a default method, which means we need not to implement this method in the implementation class Example. This way we can add the default methods to existing interfaces without bothering about the classes that implements these interfaces.

How to override the default implementation of an interface in Java?

An implementing class can override the default implementation provided by the interface. For Java 8, the JDK collections have been extended and the forEach method is added to the entire collection (which work in conjunction with lambdas ). With the conventional way, the code looks like below:

Is it possible to add method implementation to a Java interface?

Java Interface always can contain the method declaration and cannot contain method implementation (method body), “there is no possible way of adding method implementation to a Java Interface” has become a myth now after the introduction of Default Method in Java 8.


2 Answers

Eugene's example shows that default methods can be inlined.

In fact, I think that the criteria for inlining should be the same as for any other non-static method.

  • The size of the code to be inlined must be smaller than a tunable threshold.
  • The method must not be overridden by a method in any (currently loaded) subclass of the class or interface.

In your example, I think that inlining should be possible, assuming that this is all of the code involved in the example.

However, there may be other limitations with / in the specific JIT that is being used here. For example, a default method calling another default method might be an edge case that is rare enough that it was deemed not worth supporting. Another possible explanation is that the C1 compiler doesn't do deep monomorphic dispatch analysis / optimization.

And the flip-side of this is that this could be premature optimization ... unless your performance profiling has identified a specific hotspot in your code where inlining could make a significant difference. Normally, the best strategy is to leave this to the compiler. If you micro-optimize your code to give optimal performance for a given Java version, there is a good chance that you will need to redo the work when you change to a newer version.

like image 128
Stephen C Avatar answered Oct 19 '22 18:10

Stephen C


It is inlined. Here is an example:

public class DefaultInline {

    public static void main(String[] args) {
        System.out.println(callMe());
    }

    static int callMe(){
        A instance = new A(){};
        int x = 0;
        for (int i = 0; i < 1_000_000; ++i) {
            x += (int)instance.myRandom();
        }
        return x;
    }

    interface A {
        default double myRandom() {
            return Math.random();
        }
    }

}

Run it with:

java -XX:+UnlockDiagnosticVMOptions 
     -XX:+PrintInlining 
     -XX:CICompilerCount=2 
     DefaultInline.java

And see a line that has:

@ 20   zero.x.so.DefaultInline$A::myRandom (4 bytes)   inline

As to that "no static binding", it is present here, notice that this is in C1. Because calling the method myRandom compiles with invokeInterface (and you can look above at the types of the methods C1 will inline), C1 compiler will not inline it (as far as I understand the code), but C2 will.

like image 1
Eugene Avatar answered Oct 19 '22 19:10

Eugene