Classfile artifacts to support compilation/reflection
maurizio.cimadamore at oracle.com
Thu Apr 29 11:29:35 UTC 2021
On 28/04/2021 21:12, Brian Goetz wrote:
> I'm updating the SoV documents and it raises a few questions about
> what classfile surface we need for capturing the language model. The
> good news is that with the single-classfile model, the translation
> complexity collapses almost to zero. But there are a few questions of
> "what do we retain in the classfile."
> 1. Ref-favoring vs val-favoring. Whether a primitive class P is
> ref-favoring or val-favoring no longer affects translation of the
> classfile (yay), it only affects translation of _type uses_ of the
> unadorned name. But, this has to be capture somewhere in the
> classfile, so that the compiler can read in P.class and know what the
> name `P` means. There are a few choices here:
> - An ACC_ bit. Meh, these are pretty expensive.
> - An attribute, which only javac and reflection would need to pay
> attention to.
> - A supertype (implements RefFavoring).
> My preference is an attribute; this feels closest to `Signature` to
> me. Reflection might want to reflect the ref-favoring bit.
In fact, I think we could even roll it in the Signature attribute itself?
> 2. Whether abstract classes are primitive superclass candidates. The
> static compiler will check this at compilation time when it sees a
> superclass of a primitive class, but the JVM will want to recheck
> anyway. There are two sensible ways to handle this in the classfile:
> - An attribute that says "I am a primitive superclass candidate."
> The static compiler puts it there, and the JVM checks it.
> - Infer and tag. If an abstract class is loaded that is not a
> primitive superclass candidate, the JVM injects IdentityObject as a
> superinterface of the newly loaded class; when we go to load a
> primitive subclass, this will fail because primitive classes cannot
> implement both IdentityObject and PrimitiveObject.
Can't we check this lazily, when a primitive class is loaded? That
triggers loading of supers, at which point we can check the various
constraints and throw if needed. Tagging is an impl detail of the VM
(and javac) IMHO - in case we don't want to repeat the checks multiple
times - but injecting extra supertypes as a way of tagging seems a bit
on the "too public" side of things (as I view this as, essentially, an
> Reflection probably doesn't have to reflect whether a class is
> primitive superclass candidate; it already reflects the things needed
> to make this determination.
> 3. T.ref. In generic code, we can say `T.ref`, which is a total
> operator on types; if T is already a reference type, then T.ref = T,
> and if it is a primitive value type P.val., then T.ref = P.ref. The
> Signature attribute should be extended to support the distinction
> between a use of `T` and a use of `T.ref`. (T.val is partial, so
> doesn't make sense in the general case, and in the specific cases
> where it does make sense, does not currently look worth supporting.)
Yep, we need signature attribute support for all this stuff. Unless we
want to get clever and infer some things for side channels - but this
probably won't work in all cases.
> 4. Other flavors, as needed. We've considered a "null-default"
> primitive class; if so, this has to be captured in a similar way as
> (1). These can probably all be folded into a single PrimitiveClass
True - if we do have a PrimitiveClass attr, I agree that null-default,
ref-default and such would belong there.
More information about the valhalla-spec-observers