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

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Sat Jun 3 13:56:58 UTC 2017

On 03/06/17 12:51, Remi Forax wrote:
> 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.
Yeah - thanks for the clarification - this corresponds to my 
understanding of the model - that is, with BMH, boxing happens 'at the 
boundaries', when you set up the method handle chain - but I think that 
in order to get there you need at least to teach BMH about value types 
(that is, the Species_XYZ classes should have methods to construct bound 
versions with value types), otherwise the chain will just get boxed to 
Object internally.

> regards,
> Rémi
> ----- 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