EG help please with getting to LW1 re: Value Types Consistency Checking
john.r.rose at oracle.com
Sat Jun 30 00:31:15 UTC 2018
On Jun 26, 2018, at 7:30 AM, Karen Kinnear <karen.kinnear at oracle.com> wrote:
> Summary: Could we please allow eager loading for value types in the locally declared method signatures
> prior to preparation for LW1?
My answer would be "yes, if said types are mentioned in the
ValueTypes attribute". Otherwise, it seems impractical to do
eager loading of type names that appear in descriptors, on
the off chance that they might be value types.
> Without that we seriously risk being able to offer an LW1 early access binary for the JVMLS.
> We believe it is more important to get this into people’s hands for experimentation and feedback than
> to delay the eager loading at this time.
> At our EG discussion on June 20, 2018, we discussed the proposal for Value Types Consistency checking
> at http://cr.openjdk.java.net/~acorn/value-types-consistency-checking-details.pdf <http://cr.openjdk.java.net/~acorn/value-types-consistency-checking-details.pdf>
The value-types-consistency-checking-details document should
probably lead off by describing the ValueTypes attribute, before
giving the four bullet points about instance fields, static fields,
descriptor types, and cross-call consistency. Otherwise, I get
totally lost in the third bullet, when it claims "these types are
eagerly loaded" but without saying exactly what triggers this
loading. Looking at the Valhalla prototype (which not all
spec experts can do) I see that the 'is_declared_value_type'
function is queried when method adapters are created,
so we can agree that ValueTypes is the source of truth for
method arguments and return values.
(Given ValueTypes, we don't need ACC_FLATTENABLE, as has
been discussed. AFAIK, we are using ACC_FLATTENABLE in LW1
because we don't want to destabilize the system with a cleanup,
and because we might want it later, but I'm arguing that we
don't want it at all in the long run. Reason: Any such marking
of fields is *also* a desirable marking of method descriptor
components. Thus, an ACC_FLATTENABLE, applicable only
to fields, is not sufficient for our needs, while ValueTypes is
both necessary and sufficient. For nullability in particular,
what we really need is a marker for both field and method
descriptors, along the lines of Fred's N-types. By JVMLS,
I expect I will have a concrete proposal in this space that is a
side effect of supporting reified type parameters.)
(But as long as ACC_FLATTENABLE is in the mix, perhaps the
consistency checking rules should *also* insist that the field types
of fields so marked must also be mentioned in the ValueTypes
> Part of the proposal for checking value type consistency relative to the actual type
> was for locally declared methods. The proposal was to check the value types in arguments/return type
> before preparation of the declaring class.
> During the meeting, there was a request to explore whether we could either:
> 1) delay checking the value type consistency until an attempt to resolve the method for invocation, or
> 2) write the JVMS is such as way as to allow eager loading, but only throw an error related to the eager loading at method resolution.
> My understanding is that the goals of this are two-fold:
> 1) if the method is never called, the rest of the code will continue to run
> 2) reduce eager loading
> We have started this investigation, and there is non-trivial complexity in implementing either of these approaches,
> and we would like more time to explore how to make this possible, after making LW1 available.
Yep, I am not surprised that this is hard to do. So for the LW1 term
I say "yes" to both eager loading and method consistency checking.
If we can find a way to be explicit about nullability in value type descriptors,
then I think we can keep the rest of the L-world descriptor design.
The conversation (post LW1) which I see queuing up is whether to
go back to Q-types (or some analog) as explicitly non-nullable value
type descriptors, or whether to use some other "channel" to convey
the nullness information when it differs from some defined background
setting. I think that conversation hinges, in part, on how useful it is
to change the meaning of LFoo; to be contextually determined as a
value type, vs. just being plain with QFoo;. Our experiments with
a live LW1 prototype will help us scope this out.
> Some aspects of the implementation complexity that we have identified so far:
> a) At method resolution time, if there is a mismatch in value type consistency between the declaring class and the actual
> type in the signature, then there is also a mismatch in all classes that have overridden the current method. This is particularly
> painful with default methods in interfaces.
For LW1 we can insist that all the methods agree. This is a brittle state
of affairs which we will (almost certainly) need to make more flexible
with on-the-fly adapter generation. One key question post LW1 is
what design choices will make adapter generation less pervasive.
Personally, I hope we'll find a way to require adapters for a small
minority of calls, all related to partially executed migrations. This
is one reason I'm eager to avoid going back to Q-types, since those
seem to require a relatively large number of adapters.
> b) We need to ensure that we catch all method resolution, through all of the alternate accessor paths, including MethodHandles, VarHandles,
> Reflection, JNI, so that we catch both the specification and implementation changes.
> c) Our favorite, invokespecial ACC_SUPER, needs special handling, since it performs selection which is not based on overriding, but based on virtually re-resolving.
> d) Pass by value calling convention optimizations depend on loading the actual type. Loading of the parameter types on first method resolution implies that if the caller is compiled, the caller method requires deoptimization/recompilation to pass arguments by value for future calls, which is a performance cost.
I don't think it will pan out. It's less invasive than deferred loading of field
types, but it's still invasive to change the calling sequence of a v-table slot.
One design heuristic here is that fields and v-table slots are often subject
to parallel constraints. This is true when binding physical variables (memory
locations, argument registers), and also true when creating specializations
(in our future template classes).
> e) If we modify the specification to allow eager loading, and save errors to throw at method resolution, we need to work through the JVMS question of which errors would be saved (e.g. OOME, SOE might be thrown as part of the implementation vs. saving LinkageError), as well as designing a new implementation mechanism to repeat exceptions relative to signatures used for method resolution.
I hope that if there is a need to telegraph a failure from loading or
preparation phases to the resolution phase, then a simple bit will
do, rather than a saved exception. Except, of course, for quality
of service concerns; in that case a resolution-time error that stems
from a deferred value-type check could be given a getCause
of the earlier exception. But, yes, this may require JVMS work.
More information about the valhalla-spec-observers