Constant_Dynamic first experiences

Brian Goetz brian.goetz at
Mon Jul 2 20:46:48 UTC 2018

> In the Clojure compiler, I have been playing around with dynamic constants.
> This is pretty cool stuff and I wanted to share the experience and ask a
> couple questions.
> (defn replace [x y coll]
>    (map {:a x
>          :b y} coll))
> Currently our compiler creates and stores necessary constants into static
> final fields during the static class initializer. In the stupid example
> above, there are three such constants in the body (keywords :a, :b, the var
> #'map).
> ConstantDynamic allows us to delay the constants' construction until they
> are demanded (bsm linked).  This should save us clinit time and field
> slots.  I've tested this out, and it works nicely -- I don't know how much
> clinit time it saves, but there wasn't a startup regression, so kudos!

The hoped-for startup benefit comes from two places:
  - Direct -- work not done at <clinit> time;
  - Indirect -- additional classes loaded, and more <clinit>s run, as a 
result of the direct work.

> The other interesting thing in that function body is a map constructor.
> This one is interesting because it's not a constant map, but the keys are
> constants. The current emission strategy is to construct an array of kvs,
> populate it, then call PersistentHashMap.create().  With condy the constant
> keywords (the map's keys) be come `ldc`, but I would like to find a better
> way to construct varargs things (like maps, sets, vectors, lists) without
> all the array manipulating bytecode.  I've used MH.asCollector() and
> asVarargsCollectors() with an indy callsite, but there was a slight
> regression in startup time. In the example above the map construction
> happens during normal execution of the method, but there are a lot of
> _totally constant aggregates_ that get executed once only during clojure
> runtime initialization (nearly everything is reified in the clojure
> runtime: docstrings, file:line numbers.)

If only arrays were not mutable, then the array [ c1, c2 ] where c1,c2 
are constants, could also be a constant.  If you trust all the code this 
is exposed to, then you can write a condy bootstrap to load the array [ 
c1, c2 ] as a constant (whose bootstrap arg list takes c1 and c2.)  This 
won't help on the first time, of course, but if you go through this code 
path multiple times, you'll avoid re-creating this array.  (Alternately, 
you could consider using List.of(), which gives you an immutable list, 
and writing a bootstrap that returns that, and overload PHM.create() to 
take an array or a List.)

More information about the amber-dev mailing list