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