Skip to content

Startup regression due to HotSpot JVM's population of vtables with default methods #243

Open
@retronym

Description

@retronym

Running scalac -version in 2.12.0-SNAPSHOT takes 0.9s, a significant regression from 2.11.8, which took 0.2s.

% time scalac -debug -version

/Library/Java/JavaVirtualMachines/jbsdk8u112b403_osx_x64/Contents/Home/bin/java
-Xmx256M
-Xms32M
-Xbootclasspath/a:/Users/jason/scala/2.11.8/lib/akka-actor_2.11-2.3.10.jar:/Users/jason/scala/2.11.8/lib/config-1.2.1.jar:/Users/jason/scala/2.11.8/lib/jline-2.12.1.jar:/Users/jason/scala/2.11.8/lib/scala-actors-2.11.0.jar:/Users/jason/scala/2.11.8/lib/scala-actors-migration_2.11-1.1.0.jar:/Users/jason/scala/2.11.8/lib/scala-compiler.jar:/Users/jason/scala/2.11.8/lib/scala-continuations-library_2.11-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-continuations-plugin_2.11.8-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-library.jar:/Users/jason/scala/2.11.8/lib/scala-parser-combinators_2.11-1.0.4.jar:/Users/jason/scala/2.11.8/lib/scala-reflect.jar:/Users/jason/scala/2.11.8/lib/scala-swing_2.11-1.0.2.jar:/Users/jason/scala/2.11.8/lib/scala-xml_2.11-1.0.4.jar:/Users/jason/scala/2.11.8/lib/scalap-2.11.8.jar
-classpath
""
-Dscala.home=/Users/jason/scala/2.11.8
-Dscala.usejavacp=true
-Denv.emacs=
scala.tools.nsc.Main
-version

Scala compiler version 2.11.8 -- Copyright 2002-2016, LAMP/EPFL

real    0m0.219s
user    0m0.213s
sys 0m0.047s

% time qscalac -debug -version

/Library/Java/JavaVirtualMachines/jbsdk8u112b403_osx_x64/Contents/Home/bin/java
-Xmx256M
-Xms32M
-Xbootclasspath/a:/Users/jason/code/scala/build/quick/classes/compiler:/Users/jason/code/scala/build/quick/classes/library:/Users/jason/code/scala/build/quick/classes/reflect:/Users/jason/.ivy2/cache/org.apache.ant/ant/jars/ant-1.9.4.jar:/Users/jason/.ivy2/cache/org.apache.ant/ant-launcher/jars/ant-launcher-1.9.4.jar:/Users/jason/.ivy2/cache/org.scala-lang.modules/scala-asm/bundles/scala-asm-5.1.0-scala-1.jar:/Users/jason/.ivy2/cache/org.scala-lang.modules/scala-xml_2.12.0-RC1/bundles/scala-xml_2.12.0-RC1-1.0.5.jar:/Users/jason/.ivy2/cache/jline/jline/jars/jline-2.14.1.jar
-classpath
""
-Dscala.home=/Users/jason/code/scala/build/quick
-Dscala.usejavacp=true
-Denv.emacs=
scala.tools.nsc.Main
-version

Scala compiler version 2.12.0-20161011-181858-1e81a09 -- Copyright 2002-2016, LAMP/EPFL and Lightbend, Inc.

real    0m0.897s
user    0m0.923s
sys 0m0.088s

Profiling this suggests that the dominant factor is resolution of default methods, which HotSpot JVM performs eagerly during classloading. I believe that collections present the biggest challenge, which suggests that this regression will be felt by all Scala programs, not just the compiler.

This might be inherent complexity required to implement method resolution, in particular:

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html#jvms-5.4.3.3

A maximally-specific superinterface method of a class or interface C for a particular method name and descriptor is any method for which all of the following are true:

The method is declared in a superinterface (direct or indirect) of C.

The method is declared with the specified name and descriptor.

The method has neither its ACC_PRIVATE flag nor its ACC_STATIC flag set.

Where the method is declared in interface I, there exists no other maximally-specific superinterface method of C with the specified name and descriptor that is declared in a subinterface of I.

For completeness, here's the corresponding spec in the Java language:
https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5

The implementation in OpenJDK is in defaultmethods.cpp.

I have ported this to Scala to try to understand the algorithm and potential optimizations (either in our code generation or in OpenJDK itself).

I have also synthesized a pure Java test case that demonstrates exponential performance, both in javac and java.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions