RFR: implementation for JEP 334: JVM Constants API

Brian Goetz brian.goetz at oracle.com
Tue May 29 20:06:46 UTC 2018

I understand why you're hammering on this issue; it seems like something 
that is unnecessarily complex.  So, if it can be simplified without 
oversimplifying, that's great.  That said, the signature is the tail, 
and we shouldn't let the tail wag the dog. Ideas like "let's not have 
DCD extend Constable" are tail wagging dog, so let's not go there.

The reason all the concrete subclasses of ConstantDesc implement 
Constable is that we want the nominal descriptors to _themselves_ be 
constants, which can further be embedded in the constant pool (this 
means they can often be reconstituted more efficiently than by 
generating the obvious bytecode; this is groundwork for the enhanced 
constant folding work to come.)  This is subtle; while ConstantDesc and 
Constable are in some ways mirrors of each other, in some ways they are 
not.  That is, when you do:

     Class aClass = ClassRef.of("java.lang.String");
     ConstantDesc cd = aClass.describeConstable()  // gonna be a ClassDesc
     ConstantDesc cdd = cd.describeConstable() // Definitely not ClassDesc!

Here, `cd` describes a constant for a Class; `cdd` describes one for a 
ClassDesc, which is a dynamic constant which, when resolved, resolves to 
a ClassDesc.

In turn, this is conditioned by a lot of historical baggage, such as: 
there is a live object type, Class, which can represent both reference 
class literals (String.class) and primitive class literals (int.class).  
Both (as of 11) have a constant pool representation.  However, their CP 
representation is different; reference types are represented with 
Constant_Class_info, whereas primitive types are represented with 
condy.  Therefore, they will use different kinds of ConstantDesc to 
describe them.  But just as we have a single Class type that describes 
all runtime types, we want a single ClassDesc type that describes them 
all nominally, so other APIs (like MethodTypeDesc) don't have to 
propagate this unfortunate representational bifurcation.  Papering over 
this rift contributed to the signature complexity.

The first `? extends` is needed because we don't want to force APIs to 
return _exactly_ a `ConstantDesc`; we want to allow them to return a 
more decriptive subtype, if desired, as `EnumDesc` does.  So we have

     Optional<? extends ConstantDesc<X>> describeConstable()

and we have to fill in the X.

But its good you pressed on this, because the super-constraint actually 
came from someplace else, which was totally accidental:

     Class<T> extends Constable<Class<T>>

which was inconsistent with

     ClassDesc extends ConstantDesc<Class<?>>

This turned out to be the constraint that was killing us, for which the 
`super` was the only way out (and one that was not really correct).  By 
fixing this, I was able to drop the super (along with some other changes 
elsewhere along the line.)  So it looks like your Sunday was well-spent 
(assuming all goes well downstream.)

On 5/27/2018 8:52 PM, jbvernee wrote:
> Hello (again),
> Sorry for keeping this going, but I keep thinking of new things a few 
> hours later (there goes my Sunday :/).
> I'm wondering if the return type of `Constable::describeConstable` is 
> actually correct. Right now it's `Optional<? extends ConstantDesc<? 
> super T>>`, but why are you using `ConstantDesc<? super T>`? Since 
> `ConstantDesc` is a _producer_ of `T` PECS dictates that it should use 
> co-variance, i.e.: `ConstantDesc<? extends T>`, so that would make 
> `Optional<? extends ConstantDesc<? extends T>>` the return type. (a 
> ConstantDesc that resolves to a String can also be viewed as a 
> ConstantDesc that resolves to an Object)
> That way you don't even have the problem I was trying to solve before, 
> and the return type of `EnumDesc::describeConstable` (and similarly 
> for `VarHandleDesc`) can be 
> `Optional<DynamicConstantDesc<EnumDesc<E>>>` which is the exact type 
> that is being returned, which is what is wanted right?
> On that note, you could also change the return type of 
> `describeConstable` for the box types and String to return an optional 
> of the type itself (since they're their own descriptor, each 
> implements `ConstantDesc` of itself). For instance, for `Double` this 
> would change from `Optional<ConstantDesc<Double>>` to `Optional<Double>`.
> Best regards,
> Jorn Vernee

More information about the amber-dev mailing list