(15) RFR: JDK-8247444: Trust final fields in records
Mandy Chung
mandy.chung at oracle.com
Wed Jun 17 17:26:11 UTC 2020
Hi Vladimir,
Thanks for the review and feedback.
FWIW. The spec of java.lang.reflect.AccessibleObject and Field
specifies which final fields can be modified or not. It use the
*non-modifiable* term and JVM can rely on.
I will keep the patch as is. I'm happy to clean this up when a more
disciplined approach is coming.
Mandy
On 6/17/20 4:13 AM, Vladimir Ivanov wrote:
> Looks good!
>
> I welcome and fully support such hardening of final field handling for
> new language features.
>
> Minor comment on naming: "trusted final field" is an JVM
> implementation detail and I'd prefer to keep it internal to JVM. (I
> hope it'll eventually go away and will be replaced with a more
> disciplined approach.)
>
> Probably, a better alternative is a name that clearly communicates
> that the JVM expects/allows modifications of a final field. Or, at
> least, that it's *the JVM* which "trusts" the contents of a final
> field after its initialization is over
> (vmTrustedFinal/isVMTrustedFinalField).
>
> But I'm fine with keeping the patch as is.
>
> Best regards,
> Vladimir Ivanov
>
> On 16.06.2020 00:58, Mandy Chung wrote:
>> This patch is joint contribution from Christoph Dreis [1] and me.
>>
>> Webrev:
>> http://cr.openjdk.java.net/~mchung/jdk15/webrevs/8247444/webrev.00/
>> CSR: https://bugs.openjdk.java.net/browse/JDK-8247517
>>
>> This proposes to make final fields in records notmodifiable via
>> reflection. Field::set throws IAE if a Field is not modifiable.
>> Thecurrent specification specifies the following Fields not modifiable:
>> - static final fields in any class
>> - final fields in a hidden class
>>
>> The spec of Field::set is changed to specify that records are not
>> modifiable via reflection.
>> Noe that no change in Field::setAccessible(true), i.e. it will
>> succeed to allow existing frameworks to have read access to final
>> fields in records. Just no write access.
>>
>> VarHandle does not support write access if it's a static final field
>> or an instance final field.
>>
>> This patch also proposes `sun.misc.Unsafe::objectFieldOffset` and
>> `sun.misc.Unsafe::staticField{Offset/Base}` not to support records.
>>
>> No change is made in JNI. JNI could be considered to disallow
>> modification of final fields in records and hidden classes (static
>> and instance fields). But JNI has superpower and the current spec
>> already allows to modify the value of a final static field even after
>> it's constant folded (via JNI Set<type>Field and
>> SetStatic<type>Field), then all bets are off. This should be
>> re-visited when we consider "final is truly final" for all classes.
>>
>> Make final fields in records not modifiable via reflection enables
>> JIT optimization as these final fields are effectively truly final.
>>
>> This change impacts 3rd-party frameworks including 3rd-party
>> serialization framework that rely on core reflection `setAccessible`
>> or `sun.misc.Unsafe::allocateInstance` and `objectFieldOffset` etc to
>> construct records but not using the canonical constructor.
>> These frameworks would need to be updated to construct records via
>> its canonical constructor as done by the Java serialization.
>>
>> I see this change gives a good opportunity to engage the maintainers
>> of the serialization frameworks and work together to support new
>> features including records, inline classes and the new serialization
>> mechanism and which I think it is worth the investment.
>>
>> This is a low risk enhancement. I'd like to request approval for a
>> late enhancement in JDK 15. It extends the pre-existing code path
>> with refactoring the hidden classes to prepare for new kinds of
>> classes with trusted final fields. The change is straight-forward.
>>
>> Can this wait to integrate in JDK 16?
>>
>> It's important to get this enhancement in when record is a preview
>> feature that we can get feedback and give time to 3rd-party
>> serialization frameworks to look into adding the support for records.
>> If we delayed this change in 16 and records exit preview, it would be
>> bad for frameworks if they verify that they support records in 15 but
>> fail in 16. OTOH the risk of this patch is low.
>>
>> Performance Impact
>>
>> I addressed the performance concern I raised earlier myself. For
>> reflection, VM creates the reflective Field objects and fills in
>> MemberName when resolving a member. VM will tag if this
>> Field/MemberName is trusted final field. I think this is a cleaner
>> approach rather than in each place to check for final static and
>> final fields in hidden or record class to determine if it has write
>> access or not.
>>
>> `sun.misc.Unsafe` does not use Field::isTrustedFinalField because (1)
>> Unsafe has been allowing access of static final fields of any classes
>> but isTrustedFinalField is not limited to instance fields (2) Unsafe
>> disallows access to all fields in a hidden class (not limited to
>> trusted final fields). So it follows the precedence and simply
>> checks if the declaring class is a record. `Class::isRecord` calls
>> `Class::getSuperclass` to check if it's a subtype of `Record`. As
>> `Class::getSuperclass` is intrinsified, the call on isRecord on a
>> normal class is fast. Christoph has contributed the microbenchmarks
>> that confirm that no performance regression.
>>
>> Thanks
>> Mandy
>> [1]
>> https://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2020-June/040096.html
>>
More information about the amber-dev
mailing list