Fwd: Field initialization before 'super'
Brian Goetz
brian.goetz at oracle.com
Fri Dec 15 21:08:03 UTC 2023
> The 'Field.setAccessible' method, which provides a standard API
> mechanism for mutating final fields, considers strict finals to be
> "non-modifiable", and will not enable reflective writes. (It already
> does the same for record fields.)
We discussed this at the EG meeting and I'm still uncomfortable.
There are two not-completely-coincident sets of constraints:
- Final instance fields that can be modified using setAccessible
- Final instance fields that are trusted by the VM to stay constant
The former is specified as: final instance fields that are not in
records and hidden classes, as well as the modularity constraint that
prevent use of setAccessible in the absence of an "opens" edge (see
AccessibleObject::checkCanSetAccessible).
The latter is a larger and somewhat more embarassing set: hidden
classes, box classes, record classes, String, atomic field updaters, and
a whitelisted set of packages (java.lang, java.lang.{invoke,reflect},
sun.invoke, jdk.internal.{reflect,foreign.layout,foreign,vm.vector},
jdk.incubator.vector (except for the weird in/out fields in System).
Plus a flag to just turn on "trust them all, except the weird ones in
System".
The former is specified through JDK specifications; the latter is a VM
implementation detail that conservatively gives up optimization when we
cannot prove that initialization is race-free.
Adding "value classes" to both lists seems reasonable. Driving towards
fewer modifiable final fields is a desirable goal; driving towards all
final fields being trustable is also.
But this proposal also adds another entry to both lists: "final fields
whose initialization precedes the super-call in all constructors." This
is not an easily describable property of the programming model, and it
is pretty hard to explain why this is relevant. Their presence on the
first list may show up as weird breakage with existing frameworks under
harmless-looking refactorings. Plus, since we don't have a reasonable
description for these fields at the language level (unlike "fields in
records, hidden classes, or value classes"), it's hard to even talk about.
The stated purpose of the setAccessible loophole is deserialization; the
existence of the non-trusting of final fields is due to the possibility
that the JIT might inline the wrong value, either due to races (if the
field is set after this escapes) or setAccessible shenanigans.
On the other hand, I think we all agree that we don't want a
`really-final-i-mean-it` modifier on fields, and that if we'd like for
most classes to be strictly initialized, then having a strict modifier
on classes/ctors is another "wrong default".
tl;dr: I think the "strict field" formulation beyond that needed for
value classes needs some more bake time.
More information about the valhalla-spec-experts
mailing list