On constant folding of final field loads

Vladimir Ivanov vladimir.x.ivanov at oracle.com
Wed Jul 22 16:14:26 UTC 2015


John,

>> In order to avoid surprises and inconsistencies (old value vs new value depending on execution path) which are *very* hard to track down, VM should either completely forbid final field changes or keep track of them and adapt accordingly.
>
> I like the "forbid" option, also known as "fail fast".  I think (in general)
> we should (where we can) remove indeterminate behavior from the
> JVM specification, such as "what happens when I store a new value
> to a final at an unexpected time".
>
> We have enough bits in the object header to encode frozen-ness.
> This is an opposite property:  slushiness-of-finals.  We could require
> that the newInstance operation used by deserialization would create
> slushy objects.  (The normal new/<init> sequence doesn't need this.)
> Ideally, we would want the deserializer to issue an explicit "publish"
> operation, which would clear the slushy flag.  JITs would consult
> that flag to gate final-folding.  Reflection (and other users of
> Unsafe) would consult the flag and throw a fail-fast error if it
> failed.  There would have to be some way to limit the time
> an object is in the slushy state, ideally by enforcing an error
> on deserializers who neglect to publish (or discard) a slushy
> object.  For example, we could require an annotation on
> deserialization methods, as we do today on caller-sensitive
> methods.
>
> That's the sort of thing I would prefer to see, to remove
> indeterminate behavior.
Yes, fail-fast approach is very appealing and I like slushy bit idea, 
but it is more intrusive (from user perspective), unfortunately.

Though Reflection & MethodHandles can be instrument with slushy bit 
checks and Unsafe left as-is, what can be done for JNI? Do you think it 
is acceptable for JVM to throw exceptions on "illegal" (slushy bit off) 
final field writes? SetXXXField JNI functions aren't declared to throw 
any exceptions [1], so it seems like an intrusive change, even with JNI 
spec adjustments.

Thinking more about "slushiness", limiting the time an object is in that 
state doesn't look like an easy problem to solve, considering there are 
3 interacting operations (instantiate, initialize, freeze).
VM can do some analysis to ensure slushy objects don't escape, but it 
looks either too fragile or too complex to implement.

I don't see a big problem with "runaway" objects with slushy bit on. It 
means JIT will be always conservative when working with them. Or are you 
mostly concerned about abuse of slushy objects?

It can be mitigated by:
   (1) requiring a user to perform additional actions to set slushy bit 
(e.g. calling specialized newInstance() equivalent or marking caller 
method akin to caller-sensitive methods); in that case it is less likely 
a user won't freeze previously allocated object;

   (2) providing VM diagnostics to detect runaway slushy objects;

In the end, it is expert level API. I don't think many people write 
their own deserialization frameworks :-) If you bungle it, you are on 
your own.

>> Though offset value is explicitly described in API as an opaque offset cookie, I spotted 2 inconsistencies in the API itself:
>>
>>   * Unsafe.get/set*Unaligned() require absolute offsets;
>> These methods were added in 9, so haven't leaked into public yet.
>
> Yep.  That seems to push for a high-tag (color bits in the MSB of
> the offset), or (my preference) no tag or separate tag.
> You could also copy the alignment bits into the LSB to co-exist
> with a tag.
>
> (The "separate tag" option means something like having a
> query for the "tag" as well as the base and offset of a variable.
> The operations getInt, etc., would take an optional third argument,
> which would be the tag associated with the base and offset.
> This would allow address arithmetic to remain trivial, at
> the expense of retooling uses of Unsafe that need to be
> sensitive to tagging concerns.)
Separate tag has the same shortcoming as high-tag: it is not translated 
into a single machine instruction. VM needs to inspect the tag before 
performing a field update, though original setXXX() methods aren't 
affected.

Considering fail-fast approach and slushy bits, I'm inclined to leave 
Unsafe as is (no tag approach). Probably, adding diagnostic mode to VM 
signalling when a final field is updated using Unsafe.

Best regards,
Vladimir Ivanov

[1] 
https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#Set_type_Field_routines


More information about the hotspot-compiler-dev mailing list