Constant_Dynamic first experiences

Brian Goetz brian.goetz at
Tue Jul 3 19:19:04 UTC 2018

I suspect the startup regression has to do with spinning the needed lambda forms.  We’ve done some work with pre-spinning the ones we know will be needed, and bundling them into the runtime.  Obviously this only works if you’re packaging a runtime, but its an option.

> On Jul 3, 2018, at 3:13 PM, Ghadi Shayban <gshayban at> wrote:
> Thank you both.
> For _nested constant aggregates_, I'll try John's leaf+steering suggestion,
> but that will take a bit more surgery.
> Re: getting rid of array bytecode boilerplate, I tried a few things in the
> context of making a _non-constant_ vector.
> Emission styles:
> A)
> push MethodHandle for clojure.lang.RT.vector(Object...)
> push all elements
> signature polymorphic call to MH.invoke
> B)
> push all elements
> invokedynamic, with BSM returning a CCS around RT.vector(Object...),
> adapted for the incoming signature with asType()
> C) same as B but the CallSite+MH is memoized for arities <= 6 using
> asCollector()
> All of these worked but had a slight startup regression, more severe in
> approach A (~0.65s -> ~0.85s).
> I'm not sure whether I am using MH combinators properly, or invoke vs
> invokeExact.
> Are there any other approaches to try out?  I wasn't sure about the List.of
> bit. Are you suggesting unrolling the target constructor?
> [1] found this old gem
> On Mon, Jul 2, 2018 at 5:05 PM, John Rose <john.r.rose at> wrote:
>> On Jul 2, 2018, at 1:31 PM, Ghadi Shayban <gshayban at> wrote:
>> 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.)
>> Is there anything that you would suggest for speeding up the (one-time)
>> creation of constant aggregates? Or am I best off with aastores then
>> calling a varargs constructor as we do currently?
>> If you are creating a true constant aggregate, you shouldn't need
>> to execute any aastores to set up component arrays and/or argument
>> lists.  Instead, use a BSM that takes a varargs of the elements, and
>> let the BSM execution logic stack those things for you.  That should
>> be about as fast as a one-time run of anewarray/aastore/invokestatic.
>> A similar point applies to component tuples or small structs, although
>> varargs BSMs very naturally encode arrays.  As Brian says, they also
>> naturally encode List.of calls, which are built on top of throw-away array.
>> Suppose you had a constant k/v pair:  You could bind that to a condy
>> constant, and so for a constant map of N pairs you'd have N+1 condys.
>> I don't recommend going that far, since CP entries are scarce compared
>> to bytecodes (limit of 2^16).  Instead, for a complex constant aggregate
>> structure, perhaps with nesting, devise a variadic BSM which takes
>> all of the leaf data in one argument list, and DTRT to assemble it.
>> In general you'll need steering tokens mixed with your argument list,
>> such as argument counts (java.lang.Integer) etc.  That gets your
>> job done in 1 condy (plus a various non-condy tokens or recursive
>> uses of unrelated condy constants).  As a compromise, you could
>> assemble a variable number of aggregate components into a fixed
>> number M of List.of constants (which work great with condy, and will
>> get better in the future).  Then a final BSM would assemble the
>> M lists with ad hoc steering data into you aggregate, for M+1
>> (<< N+1) condy nodes in the constant pool.
>> If you run into performance potholes in BSM execution, please do
>> let us know; we care about rounding off rough edges in BSMs,
>> since they are so pervasively used.
>> Thank you for the kind words; we do this work so you can develop
>> cool stuff like Clojure on top of Java and the JVM, and it's encouraging
>> to know when our mad plans succeed.
>> — John

More information about the amber-dev mailing list