Q-types are dead, long live non-null side attributes !
Dan Smith
daniel.smith at oracle.com
Wed Jan 11 19:46:51 UTC 2023
Yes, we've noticed the advantages of such a strategy independently. It aligns well with our plans for specialization, which push everything into a side channel (a 'T' always erases to a 'LObject' descriptor, and the specialized type information is in a side channel).
There are some difficulties—one significant problem is how to handle overriding, especially in the special case that an inherited class method overrides an interface method. The downsides may end up outweighing the benefits. But we'll have to compare notes and see what you've learned.
> On Jan 11, 2023, at 5:23 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
> Hi everybody, i would like to propose a slightly different semantics for Valhalla which is more backward compatible than the current one and that follows the vision of Brian that a non null zero-default value type is equivalent to what we currently what we call the .val mirror of a primitive class.
>
> Why do we need Q-types ?
> (1) to indicate that a field can be flattened,
> (2) to indicate that a method parameter can be called "by value",
> (3) to indicate that an array can be flattened,
> (4) to indicate the type argument of a universal generics.
>
> What is the problem with a Q-type ?
> Sadly we do not have all these benefits without paying a price.
> - a Q-type encodes compile time information not runtime information, so it does not support separate compilation
> (especially if Q-type is not compatible with its equivalent L-type),
> - a Q-type can not be erased. Erasure helps a lot adoptions when both use-site and declaration-site need to be updated to follow a new protocol.
>
> I propose to encode the same information as a Q-type using a side attribute instead to avoid the problems raised by the Q-type notation.
>
> A Q-type is use site notation equivalent to a L-type (a class name) + a non-null bit. I propose to store the non-null bit into a separate attribute associated to a field or a method declaration.
> For cover the use-cases (1) and (2) but not (3) and (4).
>
> In fact (3) and (4) are the same use-case, we need to create a specialized generics or an array specialized by a non-null type. In both case, the specialised array/generics is a runtime construction so we do not need a descriptor for it but a way to inject a runtime class of a non-null type (the secondary class as this is actually called in the prototype) as a descriptor. The parametric VM design proposed by John already propose such mechanism.
>
> Using a side attribute (on methods and fields) to record the nullability information greatly simplify the classfile verifier, because the verifier does not need to be aware of the side attribute. A worst the VM will throw a NPE at runtime.
>
> It makes the VM implementation slightly more complex because,
> - when calling a method, the VM (the interpreter) needs to checks the side attribute and emits a NPE accordingly
> - when storing a value inside a field, the VM needs to check the side attribute and if the field type is a zero-default value type at runtime and emits a NPE in that case (the VM already does the same thing for arrays).
>
> The JIT has the same information as before,
> - a field can be flattened if the type is zero-default value type at runtime and the non-null bit is set,
> - an argument can be passed by value if the type is a zero-default value type at runtime and the non-null bit is set,
> - a local variable of a zero-default value type at runtime + a nullcheck is scalarizable.
>
> I've implemented a prototype (John asks for it) of this semantics on top of the LW5 prototype,
> https://github.com/forax/civilizer
>
> It uses annotations, both at declaration site (@Value and @ZeroDefault) and use site (@NonNull and @Nullable) + bytecode rewriting because it's easier than modifying the compiler and the VM.
> - The nullchecks of the parameter is done by adding calls to Objects.requireNonNull() at the beginning of the methods,
> - The nullcheck of the field is done by declaring it with a Q-type + rewriting the access to the field using invokedynamic, so the access are done using L-types.
>
> Q-types are dead, long live non-null side attributes !
>
> regards,
> Rémi
>
>
More information about the valhalla-spec-experts
mailing list