[mvt] RFR - add support for q-types in lambda forms
maurizio.cimadamore at oracle.com
Thu Jun 1 12:26:23 UTC 2017
please review the following patches which add support for q-types in
lambda forms (LFs).
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
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:
which allows value types to survive MethodType->MethodForm conversion,
and enables the alternate LambdaFormBuilder class for spinning bytecode.
There's also a second flag:
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:
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.
More information about the valhalla-dev