[mvt] RFR - add support for q-types in lambda forms

Remi Forax forax at univ-mlv.fr
Sat Jun 3 11:51:02 UTC 2017

Hi Paul, Hi Maurizio,
bindTo() or insertArguments use the corresponding types from the method type to unbox the argument if necessary,
so actually bindTo(3) will insert 3 and not the boxed Integer if the corresponding type is an int.

The same way, a boxed value type can be unboxed if the corresponding type is a Q-type,
so there is no need of a bindTo(__Value).

In term of performance, this is not an issue because neither bindTo() nor insertArguments() should be called on a fast path.


----- Mail original -----
> De: "Paul Sandoz" <paul.sandoz at oracle.com>
> À: "Maurizio Cimadamore" <maurizio.cimadamore at oracle.com>
> Cc: valhalla-dev at openjdk.java.net
> Envoyé: Vendredi 2 Juin 2017 19:06:16
> Objet: Re: [mvt] RFR - add support for q-types in lambda forms

>> On 1 Jun 2017, at 17:09, Maurizio Cimadamore <maurizio.cimadamore at oracle.com>
>> wrote:
>>> For BMHs i am guessing we would require some expansion to include Q in the set
>>> of support basic types e.g. Species_Q and appropriate modifications to the code
>>> generation like you did for LamdaForm?
>> I think one problem is to fix BMH/Species_Q and the classes it heavily relies on
>> (LambdaFormEditor) to support Q-types.
> Ok.
>> But the other flip of the coin is to handle APIs - if you have a method handle
>> that takes a Q-type, how do you 'bind' its argument? The APIs we have today are
>> boxy. Some of these APIs are used internally by some of the BMH classes, so you
>> could hit them through combinators too.
> Yeah:
>  public MethodHandle bindTo(Object x)
> Do we need something like:
>  public MethodHandle bindToValue (__Value v)
> ?
> Such a bifurcation is somewhat awkward.
> Paul.
>> Maurizio
>>> Paul.
>>>> Adding q-type support in LFs is not straightforward, and we have played with a
>>>> number of approaches. The big issue is that LFs are a mechanism to _share_ code
>>>> between method handles (MHs) and they do so by means of 'erasure' - that is,
>>>> two method handles taking String and Integer can (in principle) share the
>>>> underlying LF (whose type is erased to Object - or L in the basic type lingo).
>>>> With value types, erasure/sharing becomes an issue - on the one hand, we have to
>>>> make sure that value types are not erased to the basic type L - which would
>>>> then lead to nonsensical bytecode generation (such as areturn on a value
>>>> operand). On the other hand there's a question of how much type information on
>>>> value types we want to preserve during LF spinning. Two options are available:
>>>> 1) value types do not get erased. That is, if a method type mentions one or more
>>>> value types, such types are not erased in the underlying method form (MF)
>>>> 2) a new basic type is added for value types (Q) and all value types 'erase' to
>>>> that
>>>> We started our experiments with (1) - while it is doable, there are two major
>>>> pain points:
>>>> * keeping sharp type information on value types inside LF effectively undoes one
>>>> of the big advantages of LFs - that is, code sharing. A MH taking a QPoint and
>>>> a MH taking a QPerson will _not_ be able to share the underlying LF.
>>>> * this approach is basically at odds with the rest of the LF machinery, which is
>>>> fundamentally basic-type based. This is particularly evident in the handling of
>>>> intrinsics (see LambdaForm.createFormsFor) where special LF (such as 'identity'
>>>> or 'zero') are cached in an array that is indexed by basic type. If we followed
>>>> this approach we would split the implementation in two: parts for which caching
>>>> can be enabled, and parts for which caching is not possible.
>>>> For these reasons, we moved on to consider (2). The most problematic aspect of
>>>> (2) is to find a common type to which all values can be safely 'erased' to.
>>>> Turns out that hotspot already has this type - that's what java.lang.__Value is
>>>> used for. So, we can indeed define a new basic type for Q, and use the
>>>> j.l.Class of j.l.Value as its standard representation (while Object.class is
>>>> still used for the boxed representation).
>>>> All the rest is can be regarded as implementation details - that is, we need to
>>>> make sure that Q-types are erased accordingly when going to method types to MF
>>>> - and we also need to make sure that LF with values in them generate the
>>>> correct bytecode. This was a major implementation challenge, as the current
>>>> InvokeBytecodeGenerator is written in terms of ASM which doesn't (yet) have
>>>> support for value opcodes. To workaround the issue, I've written an alternate
>>>> InvokeBytecodeGenerator - called LambdaFormBuilder which is specifically used
>>>> to spin bytecode for LF containing values. This builder is based on the
>>>> bytecode API already bundled with the valhalla repo.
>>>> Now, to the practical bits :-)
>>>> There are a bunch of flags I've added to enable the new support; the first and
>>>> most important is:
>>>> -Dvalhalla.enableValueLambdaForms=true
>>>> which allows value types to survive MethodType->MethodForm conversion, and
>>>> enables the alternate LambdaFormBuilder class for spinning bytecode.
>>>> There's also a second flag:
>>>> -Dvalhalla.enablePoolPatches=true
>>>> Which can be used to allow constant pool patching in the MethodHandleBuilder
>>>> machinery - this should bring the generated code for LambdaFormBuilder closer
>>>> to what InvokeBytecodeGenerator was emitting. But it can be mostly regarded as
>>>> an optional optimization.
>>>> Finally, more work needs to be done in this area; first, this support only works
>>>> if JIT is disabled (e.g. -Xint is used). Some work in this area is currently
>>>> under way - see:
>>>> http://mail.openjdk.java.net/pipermail/valhalla-dev/2017-May/002464.html
>>>> Secondly, bound method handle are _not_ supported. It seems like adding support
>>>> for Q-types here would require some major surgery to the underlying machinery
>>>> (most of the signatures for BMH are expressed in terms of Object[] anyway - see
>>>> insertArguments).
>>>> I would like to thank Vladimir Ivanov - this work would not have been possible
>>>> w/o his many thoughtful insights. I'd also like to thank Roland Westrelin for
>>>> 'alpha-testing' this patch, a thankless job which led to many bug fixes.
>>>> Maurizio

More information about the valhalla-dev mailing list