L-type, Q-type and class mirrors

Brian Goetz brian.goetz at oracle.com
Wed Jan 12 12:27:07 UTC 2022



> Let's take a detour, and try to answer to the question, how do we do reflection on method with Q-types ?
> Given that reflection is using the class java.lang.Class, it means that we need a class that represents a L-type and a class that represent a Q-type.

Correct.  In addition to all sorts of VM reasons for this, users need a 
way of distinguishing between

     m(Point.ref p)
and
     m(Point p)

with reflection, MH.Lookup, etc.

> The class that represents a Q-type does not have to be a 'real' class, the same way int.class (Integer.TYPE) is not a real class,
> it's a mirror class that represent 'I' in the method signature, same with void.class (Void.TYPE) represent 'V'.

Correct.  We've been calling these "secondary mirrors".  Note that with 
extended primitives, it is possible (though not required) that the 
secondary mirror reflect almost everything that the primary does -- 
methods, fields, supertypes, etc.  Alternately, they could be more like 
int.class, which is pretty limited.

Unfortunately, though, we run into a user expectation problem: users 
will reasonable expect that if they reflect over

     m(Point p)

they will get Point.class back.  Since the user views "Point" as the 
primary type (Point.ref is a supporting player), they'll expect 
Point.class to be the "important" mirror.  This asymmetry with the 
current state of affairs is a challenge.

> So the class that represents a Q-type is a mirror class synthesized by the VM at runtime.
> Given that it is synthesized, i believe it should be only accessible using a method of java.lang.Class,
> by example
>    Complex.class.mirrorType()  // the name "mirror" is perhaps not the best

Stepping back, what you're saying is to expose only Point.class, and 
make it harder to get at the "other" mirror, such as by relegating it to 
a method like Class::otherMirror.  This is a reasonable move, but it 
does run smack into the above problem -- that if there's one mirror, 
users will expect Point.class to reflect the Point type they are most 
familiar with, which is QPoint.

> I propose to introduce a new kind of primitive class, the builtin primitive class, that

Whether we call it that, or summon it by magic, we are stuck with some 
form of this anyway, because of the asymmetries you've observed; the 
existing int/Integer pairs have subtle differences from declared 
Point/Point.ref pairs.  There will have to be some special pleading for 
built-in/legacy/basic primitives.

I think where you're going is some flavor of this:

     special-legacy-backwards value class Integer
         with-legacy-primitive int { ... }

where we declare the Integer/int pair, but do so through Integer, but 
declare it to be backwards from the other primitives, where there are 
only eight of these allowed.

  



More information about the valhalla-spec-observers mailing list