Enhancing java.lang.constant for Valhalla

Brian Goetz brian.goetz at oracle.com
Tue Dec 14 19:48:42 UTC 2021


The jl.constant API will have to be updated somewhat for Valhalla.  
Since it was already on the drawing board when we designed jl.constant, 
shouldn't be too bad, but there are a few subtleties.  Now that the 
descriptors are largely settling down, we can take a stab at this.

ClassDesc (the base abstraction) has several factories to get a CD from 
a String:

     of(String qualifiedName)
     of(String packageName, unqualifiedClassName)
     ofDescriptor(String fieldDescriptor)

Obviously we can already represent extended primitives with the last of 
these, but doing nothing else would make them somewhat second-class.

For reference, we also have combinators:

     nested(String unqualifiedNestedName): give me a ClassDesc for a 
class nested in this one
     arrayType(): give me a ClassDesc for the array with this component type
     componentType(): (partial) give me a ClassDesc for the component 
type of this one, assuming this one is an array type

With the addition of Q descriptors, this library reveals itself to be 
L-biased; ClassDesc.of("com.foo.Bar") gives us an L-Bar. ("You could 
look in the classfile", I hear some of you say.  Not so fast; this is a 
symbolic API, not a reflective one, by design.)  But this is OK; L is a 
reasonable default.

The fully orthogonal version would involve adding:

     static ClassDesc ofValue(qualifiedName)
     static ClassDesc ofValue(String packageName, unqualifiedClassName)
     boolean isValue()
     ClassDesc valueType() // flip to Q
     ClassDesc refType()   // flip to L

But the first two are not really necessary, since they can be expressed 
both with ClassDesc.of(name).valueType(), or with 
ClassDesc.ofDescriptor(desc), and I'm inclined to go that route -- the 
canonical constructor is ofDescriptor, the others are conveniences 
around that, and complex transforms are done by combinators.

Separately, over in bytecode-API land, we have identified a desire for 
another overload of ClassDesc::of, which is one that takes an internal 
(slash-separated) name.

One of the horrors of classfile APIs is that the classfile format is 
woefully inconsistent about names.  Sometimes it wants an internal 
binary name (foo/Bar), sometimes a descriptor (Lfoo/Bar;), and there are 
other exceptions (e.g., module and package names use dots, operand to 
`new` is sometimes an internal binary name, but a descriptor for 
arrays.)  So accepting any sort of String immediately raises the 
question: "in what format?"  A more strongly typed API would use 
ClassDesc in some places, but given that we might have an internal 
binary name, or external binary name, or descriptor in hand, we need a 
way to convert all of these to a ClassDesc.  For the external binary 
name and descriptor, we have ClassDesc::of and ::ofDescriptor, but we're 
missing one for internal binary names.  So I'm proposing:

     ClassDesc ofInternal(String internalBinaryName)

to round out the set.

So, summarizing the new methods (modulo naming changes to reflect 
changes in Valhalla language syntax):

     ClassDesc ofInternal(String internalBinaryName)
     boolean isValue()
     ClassDesc valueType()
     ClassDesc refType()



Also, eventually, all the *Impl classes in this library can become B2 
primitives, since identity doesn't matter.



More information about the valhalla-spec-observers mailing list