JDK-8219713 : Reduce work in DefaultMethods::generate_default_methods
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8u192,11.0.2,12,13
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2019-02-26
  • Updated: 2020-08-18
  • Resolved: 2019-03-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 13
13 b12Fixed
Related Reports
Relates :  
Description
The default methods generation scans the hierarchy of classes during load to determine what default and overpass methods to generate into the class being loaded. There are a few inefficiencies:

- java.lang.Object is scanned at least once for every interface in the hierarchy
- classes that implement multiple interfaces that extend each other will visit shared interfaces multiple times
- private static methods in java.lang.Object are added in the build-up, but then explicitly filtered out later: filter them out early

Using -Xlog:defaultmethods=debug we can see some of these inefficiencies in action (X is a noop class implementing AutoCloseable, Closeable, Predicate<Integer>):

[0,655s][debug][defaultmethods] Class X requires default method processing
[0,655s][debug][defaultmethods] X
[0,655s][debug][defaultmethods]   java/lang/Object
[0,655s][debug][defaultmethods]   java/lang/AutoCloseable
[0,655s][debug][defaultmethods]     java/lang/Object
[0,655s][debug][defaultmethods]   java/io/Closeable
[0,655s][debug][defaultmethods]     java/lang/Object
[0,655s][debug][defaultmethods]     java/lang/AutoCloseable
[0,655s][debug][defaultmethods]       java/lang/Object
[0,655s][debug][defaultmethods]   java/util/function/Predicate
[0,655s][debug][defaultmethods]     java/lang/Object
[0,655s][debug][defaultmethods] Slots that need filling:
[0,655s][debug][defaultmethods]   or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,655s][debug][defaultmethods]   and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,655s][debug][defaultmethods]   negate()Ljava/util/function/Predicate;
[0,655s][debug][defaultmethods]   <clinit>()V
[0,655s][debug][defaultmethods]   registerNatives()V
[0,655s][debug][defaultmethods]   Looking for default methods for slot or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Looking for default methods for slot and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Looking for default methods for slot negate()Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Looking for default methods for slot <clinit>()V
[0,656s][debug][defaultmethods]   Looking for default methods for slot registerNatives()V
[0,656s][debug][defaultmethods] Creating defaults and overpasses...
[0,656s][debug][defaultmethods] for slot: or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Selected method: java/util/function/Predicate.or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods] for slot: and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Selected method: java/util/function/Predicate.and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods] for slot: negate()Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods]   Selected method: java/util/function/Predicate.negate()Ljava/util/function/Predicate;
[0,656s][debug][defaultmethods] Created 0 overpass methods
[0,656s][debug][defaultmethods] Created 3 default  methods
[0,656s][debug][defaultmethods] Default method processing complete

With experimental optimization we resolve the issue with Object being scanned a multitude of times, along with adding <clinit> / registerNatives to the candidate list for every class considered: http://cr.openjdk.java.net/~redestad/scratch/defmeth_opt.00/ 

[0,657s][debug][defaultmethods] Class X requires default method processing
[0,657s][debug][defaultmethods] X
[0,657s][debug][defaultmethods]   java/lang/Object
[0,657s][debug][defaultmethods]   java/lang/AutoCloseable
[0,657s][debug][defaultmethods]   java/io/Closeable
[0,657s][debug][defaultmethods]     java/lang/AutoCloseable
[0,657s][debug][defaultmethods]   java/util/function/Predicate
[0,657s][debug][defaultmethods] Slots that need filling:
[0,657s][debug][defaultmethods]   or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   negate()Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Looking for default methods for slot or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Looking for default methods for slot and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Looking for default methods for slot negate()Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods] Creating defaults and overpasses...
[0,657s][debug][defaultmethods] for slot: or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Selected method: java/util/function/Predicate.or(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods] for slot: and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Selected method: java/util/function/Predicate.and(Ljava/util/function/Predicate;)Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods] for slot: negate()Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods]   Selected method: java/util/function/Predicate.negate()Ljava/util/function/Predicate;
[0,657s][debug][defaultmethods] Created 0 overpass methods
[0,657s][debug][defaultmethods] Created 3 default  methods
[0,657s][debug][defaultmethods] Default method processing complete

This translates to a small but scaling speedup in various startup tests.
Comments
Might be there's no way around the need to visit interfaces inherited via different classes/interfaces multiple times, but getting rid of multiple visits to Object and avoiding queuing up clinit()V and Object::registerNatives()V (which will be filtered out later on) is passing the extensive testing and means a substantial gain.
26-02-2019

There are very specific rules about how default methods are resolved and the order in which it must happen. I think you will find some of these apparent inefficiencies are a result of those strict rules.
26-02-2019