refactoring BMH

John Rose john.r.rose at
Tue Jul 18 18:21:49 UTC 2017

On Jul 18, 2017, at 7:49 AM, Maurizio Cimadamore <maurizio.cimadamore at> wrote:
> Hi,
> it's good to see this kind of effort being started. I have a general question on the shape of the classes generated by the ClassSpecializer; in the doc you say:
> class Species_[[types]] extends [[T]] {
>         *     final [[S]] speciesData() { return ... }
>         *     static [[T]] make([[fields]]) { return ... }
>         *     [[fields]]
>         *     final [[T]] transform([[args]]) { return ... }
> How much the 'transform' primitives belong in here? The fact that the underlying species kind is able to apply transforms to get new kinds seem very BMH specific.

Short answer:  None of them.  The CSpec has a *hook* for the BMH transforms.
The jtreg smoke test doesn't use them (which could be made better).

> Also, the fact that Species_XYZ classes are constructed with an initially empty 'kind', which is injected later through Unsafe, also seems very specific.

Good point.  That's optional.  The smoke test doesn't specify one.
(The default method returns null, which tells the framework there isn't one.)
I will try to remove it completely.

> I guess it would help to have a bit more background on what kind of things you imagine would be possible to express given this framework, and judge how much of the existing BMH cruft is getting in the way.

Use cases:
 - reusable lambda implementations (key = interface + captured field types)
 - argument list (key = parameter types)
 - vector (key = lane type and lane count)
 - C pointer type (key = base type of pointer + Java carrier type + on/off heap)
 - fake generic specializations (key = specialization parameters)
 - foreign data structures (key = struct layout formula)

Some of these anticipate generic specialization; some don't (unless generic
specialization grows very generic indeed).  The ones that *do* overlap with
generic specialization will give us a way to quickly experiment with specialization
schemes before committing to bytecode formats.

The BMH cruft can be observed in the refactored BMH source file: <>

It is embodied mainly in these two nested classes:

    static final class BMHSpecies extends ClassSpecializer<BoundMethodHandle, String, BMHSpecies>.SpeciesData<BoundMethodHandle, String> {
        // This array is filled in lazily, as new species come into being over time.
        @Stable final private BMHSpecies[] extensions = new BMHSpecies[ARG_TYPE_LIMIT];

    static final class Specializer extends ClassSpecializer<BoundMethodHandle, String, BMHSpecies> {
        private Specializer() {
            super(  // Reified type parameters:
                    BoundMethodHandle.class, String.class, BMHSpecies.class,
                    // Principal constructor type:
                    MethodType.methodType(void.class, MethodType.class, LambdaForm.class),
                    // Required linkage between class and species:
                    reflectMethod(BoundMethodHandle.class, "speciesData"),

        protected String topSpeciesKey() {
            return "";


The special BMH logic factored out has to do with the bind-single protocol,
which adds a new field of some particular type to whatever fields are already
present.  Adding a new field to the end of an object is specific to BMHs,
so that logic is only in the BMH customizations, not the basic ClassSpecializer.

The bare minimum provided by the ClassSpecializer is (a) a factory and (b) one
getter per component field.  Everything else (including whether and how to make
those things public) is in the subclasses.

Thanks for looking at this.

— John

More information about the valhalla-dev mailing list