Record classfile and runtime API

forax at forax at
Sun Sep 1 20:05:51 UTC 2019

----- Mail original -----
> De: "Brian Goetz" <brian.goetz at>
> À: "Remi Forax" <forax at>
> Cc: "amber-spec-experts" <amber-spec-experts at>
> Envoyé: Dimanche 1 Septembre 2019 20:22:36
> Objet: Re: Record classfile and runtime API

> Thanks Remi; its a good time to revisit this.  The current strategy was a
> stake-in-the-ground, but needs to be refined before we finalize the design, as
> the bootstrap APIs are forever once we do that.
>> The arguments of the bootstrap methods are redundant, you don't need to pass the
>> record class because the Lookup object contains the record class (you have the
>> API in Lookup to create an intermediary lookup from a Lookup and a class so no
>> need to duplicate that information). For the first boostrap methods, the
>> parameter containing "x;y" is due to the fact that a constant method handle is
>> opaque by default so you can not get the corresponding field name. First, if
>> you have the lookup that have created that object, you can get back the name
>> with a "reveal". But i think here, the problem is that the arguments are the
>> constant method handles and not the constant decriptor (ConstantDec).
> Redundancy in and of itself is not necessarily bad.  Sure, you can get the class
> from the lookup, but then the bootstrap API is not exactly computing the same
> thing.  Maybe that’s OK,  maybe not, but the design should come first, not
> class file compression.

I'm more worried about people trying to use the API in nasty way, by example what if the lookup class is not able to see the class you sent as parameter, etc.
Avoiding duplication of the informations is a simple yet effective way to avoid misuse of the API.

A record = a class + the record attribute. If we pass more information, then you are sending more bits than we should.

> Personally, I would prefer to have ONE bootstrap for all three methods (for
> example, using the invocation name to describe which method should be linked.)
> Assumed we did that, what should the argument list be?  As you point out,
> specifying the name string as a single string (“x;y”) is a hack, so we should
> probably not do that.  Using reflection during linkage risks trading class
> file clarity for startup performance, which might not be a good trade.  There’s
> a lot of ways to slice this, but we want to choose something that works well on
> all the measures.

yes and no, currently each constant pool constant initialization requires an upcall from the VM to the Java code that will create the corresponding Java object,
if we are using the reflection it's one downcall, then because the bootstrap method is inside the JDK, you can cheat and calls the trusted Lookup.linkMethodHandleConstant which already has a cache of direct method handles.

Otherwise, you can always a constant dynamic as argument of the BSM that will resolve all arguments at once, it will be faster than resolving each argument one by one.

> If we had a common API, we could have a common meta-model constant that is
> resolved once and passed to all three methods.  Not sure that carries its
> weight, unless the meta-model object were exposed to users as well.

your meta-model is my constant dynamic described above.
And it can be typed as Object because the producer of the meta-model and the consumer are both from the same bootstrap class, so they can agree to use a class which is not visible to the user.

BTW, this very same argument can be used for avoiding to publish any extractor related type at least not until we are not sure of the design,
using Object as type of the extractor you are losing the fast that other languages than Java can specify some non Java patterns, but you can always publish the API in a later release (the fact that the bootstrap method is called as a invoke and not an invokeExact is what make it working).

>> The java.lang.invoke API has currently the limitation that you can not use the
>> ConstantDesc API to type values of the constant pool.
> And, the code to put JLC constants in the constant pool isn’t there yet either
> (it originally was, but got pulled back waiting for “invoke” support in condy,
> which is coming soon.)

i think i would prefer that it auto-magically work if the corresponding BSM type is a ConstantDesc, a kind of target typing, instead of having to have one constant dynamic per constant i wanted to see. 

>> Now we have to talk about the reflection API, currently the method that reflects
>> the attribute Record is Class.getRecordAccessors() that returns an array of
>> Method corresponding to the accessors and there are many things wrong with this
>> method.
> There are already plans to replace this with a proper reflective object
> (RecordComponent), this is just not done yet.

yes, it's a better idea, have a java.lang.reflect.RecordComponent like there is a java.lang.reflect.Field.

>> So first, let's have a method getRecordComponentFields() in java.lang.Class that
>> returns an array of
> That’s just as bad as returning methods, probably worse (since the fields are
> private.)  Something more abstract is needed.  But the rest of what you say
> should work well with what we’ve got in the works.

it's not bad because a constant desc is not a live representation of a VM data structure, given that resolveConstantDesc requires a Lookup, we are fine here.
Anyway, having a dedicated class RecordComponent is better.

>> BTW, why do we need an extractor for a record ? we should not need one because
>> we can inside the algorithm that create the pattern tree have a if
>> class.isRecord() ? (the same way the serailization is specilized for enums by
>> example).
> Currently, it’s in there so we can prototype the following phase of pattern
> matching, deconstruction patterns on records.  But, even if records go in much
> earlier than deconstruction patterns, having the pattern support in the class
> file now is valuable, as we don’t want to create the problem of “you can use
> deconstruction on records, but you have to recompile your old record classifies
> first.”

There is no issue if you need to get the deconstructor by reflection because the reflection code can fill the gap.

Anyway, i kind a like my proposal to have a deconstructor that returns Object now and may return a real type in the future.


More information about the amber-spec-observers mailing list