The Record Attribute - What does it mean to be a record at runtime?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Nov 12 21:15:05 UTC 2020


I think the point Chris is raising is a bit more subtle.

The VM has a notion of classes in which final fields are trusted - when 
that happens, the value of final fields are constant folded by the JIT 
(yayy!).

There is a problem though: in practice, final fields can be mutated e.g. 
by reflection, or via 292 (var handles) or via Unsafe.

For this reason, when we trust final fields in class C, we typically do 
other changes to prevent fields in class C from being exposed (e.g. via 
reflection), so as to decrease the potential that JIT optimization would 
be invalidated, either accidentally or maliciously.

I think the current state of affair for records has at least 3 issues:

* The paths which controls which fields are trusted by VM and which 
fields are exposed via reflection/292/unsafe do not align 100%. For 
instance, Unsafe refuses to give up field offset based on the stricter 
Class::isRecord definition, thus creating a safety gap.

* In an attempt to prevent changes to records fields via reflection, the 
specification of Field::set was updated to say that if the field holder 
is a record, the field update will fail. This is good, if it weren't 
that the javadoc has to define what it means for a field holder to be a 
record; and the way that's done is by referring to Class::isRecord, 
which is not what the implementation does (the implementation uses the 
broader "isRecord" definition based on the presence/absence of the 
record attribute - the same used by the VM).

* All clients have now a way to enable the (fragile) final field 
optimization: generate a class, then attach a record attribute to it 
(e.g. with ASM). The VM will trust all fields in that class no matter 
what. I think this is probably not what was originally intended by the 
changes in JDK-8247444. In other words, we now have a mechanism which is 
kind of like the internal @ForceInline annotation - not as handy as an 
annotation perhaps, but much more public (because, any classfile can be 
augmented to contain an extra, maybe empty, record attribute).

So, the way I see it, is that there are few ways out of this conundrum:

1) Back away from final field optimization for records; we could in fact 
get rid of all the asymmetries described above by simply _not_ trusting 
record fields - at which point VM support would become again very minimal.

2) Enforce a definition of "is a record" which makes sense - and then 
enable extra optimizations on top. Since we need to be able to specific 
reflection restriction (Field::set) I think the only defensible 
definition for what constitutes a record is to delegate to 
Class::isRecord. This doesn't mean that the JVM will have to start 
taking into account the JLS definition of a record at verification time 
- it simply means that the final field optimization, instead of being 
gated on the mere _presence_ of the record attribute, it would be 
governed by a more complex definition which matches the behavior of 
Class::isRecord. Note that this is all below the JVMS surface.

What Chris is saying is (I think) that the current implementation is 
caught in some inconsistent place between (1) and (2) - a place where, 
on one hand, we claim VM neutrality w.r.t. the record definition 
contained in the JLS but where, at the same time, we apply extra 
optimizations to speed up access to record fields.

Maurizio

On 11/11/2020 02:39, Dan Smith wrote:
>> On Nov 10, 2020, at 1:51 PM, Chris Hegarty <chris.hegarty at oracle.com> wrote:
>>
>> My issue is with how the VM determines whether a field is trusted or not. The VM trusts fields in (among other types) “record” classes. So what is a record class to the VM?   (that is the question that I am trying to resolve) - the answer is not in the JVMS ( which is fine ).
> Suggestion: the VM shouldn't bother to provide any definition for "record class". That's up to Java language compilers and reflection (which should be in agreement).
>
> Instead, can't we say the VM trusts fields in classes that have a Record attribute? Who cares whether those classes are "real" records or not? (I may be missing something because I don't fully understand the concept of "trusted final field", but it seems to me like HotSpot has a lot of freedom to decide to trust or not trust whatever fields it wants.)
>


More information about the amber-spec-experts mailing list