Description
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.