Stats: Effect of translating lambda with condy, and folding, on JDK

Brian Goetz brian.goetz at
Wed Mar 21 16:07:23 UTC 2018

Vicente has run some statistics on the effect of two optimizations, 
using the JDK as a corpus:
  - translating non-capturing lambdas and method refs using condy 
instead of indy
  - constant folding

Translating lambdas using condy instead of indy should result in two 
  - condy is lighter weight at link time (faster startup)
  - better sharing of duplicated method references / lambdas

Currently, if a class has two identical method references, they will 
each get their own indy site, which will share a 
Constant_InvokeDynamic_info (and bootstrap methods entry.)  But, since 
each indy is linked independently, linkage will be done redundantly, 
resulting in duplicate proxy classes being spun.  If we convert this 
over to condy, we'll have two LDCs of the same constant, which only gets 
resolved once.

As a baseline, we collected counts of { lambda, method ref } x { 
capturing, not } x { serializable, not }, in the corpus (the JDK):

                       Ser      NonSer
Lambda    Stateless    7       953
           Stateful    10       1688

Ref       Stateless   23       712
           Stateful             528

And we collected counts of indy constant pool entries and indy 
instructions that correspond to LambdaMetafactory:

#indyCP:   3683
#indyInsn: 3966

We would expect to see a count of indy instructions equal to the number 
of nonserializable lambdas/mrefs plus twice the number of serializable 
lambdas/mrefs (since there is a twin capture site in the $deserialize$ 
method.)  We got close; we expected 3961, but saw 3966.  The remaining 
five are accounted by lambdas that were in contexts that got duplicated 
by the compiler (finally blocks, instance initializers.)

The difference between the indy instructions and CP entries has to do 
with duplicated lambdas or methods refs.  We'd expect to see these for 
serializable, for those that are implicitly duplicated as above, and 
also when method refs are explicitly duplicated within a classfile.  So 
we saw ~230 reuses that must be the result of explicit source 
duplication of method refs.

We then ran the same stats with translating non-capturing lambdas and 
non-capturing (static, unbound, and constructor) method references using 

#indyCP      2156 // shared=125
#indyInsn    2281
#condyCP     1527 // shared=158
#condyLDC    1685

What this means is that approximately 40% of lambdas and method refs 
could be diverted from indy to condy.  Any explicitly duplicated method 
refs would get the benefit of constant pool sharing.

When the lambda deduplication effort completes, the numbers should get 
better, as there will be more candidates for sharing of CP entries 
(currently, even identical lambdas get their own lambda$nn method.)

Looking ahead, the richer constant propagation will help as well, as it 
may push some lambdas from the "capturing" to the "non-capturing" 
column.  Not only are non-capturing lambdas more performant today, but 
then they also become candidates for condy translation.

The JDK is probably not an ideal corpus to run this on; if someone wants 
to try the stats gathering patch on a different corpus, that would be great.

More information about the amber-dev mailing list