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

Paul Sandoz paul.sandoz at oracle.com
Fri Jun 2 17:06:16 UTC 2017


> 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