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

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Fri Jun 2 14:44:11 UTC 2017

Here's a second revision of the jdk changes:


* I've shared the initialization of the static flag used by both 
LambdaForm and MethodTypeForm in MethodHandleStatics.
* I've removed tabs from MVTTest


On 02/06/17 01:09, Maurizio Cimadamore wrote:
> On 02/06/17 01:00, Paul Sandoz wrote:
>>> On 1 Jun 2017, at 05:26, Maurizio Cimadamore 
>>> <maurizio.cimadamore at oracle.com> wrote:
>>> Hi,
>>> please review the following patches which add support for q-types in 
>>> lambda forms (LFs).
>>> http://cr.openjdk.java.net/~mcimadamore/specialized_lforms_hs/
>>> http://cr.openjdk.java.net/~mcimadamore/specialized_lforms_jdk/
>> A minor point, it can make it easier to remember the flags if they 
>> are grouped in a known place, such as MethodHandleStatics.
> Good suggestion, I'll do that
>> At least the test has some tabs vs. spaces, which results in 
>> off-kilter formatting. Perhaps auto format the code in IntellJ?
> Yeah there's something up there...
>> 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. 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.
> 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