On constant folding of final field loads (original) (raw)
Aleksey Shipilev aleksey.shipilev at oracle.com
Tue Jun 30 09:49:32 UTC 2015
- Previous message: On constant folding of final field loads
- Next message: On constant folding of final field loads
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi,
On 06/29/2015 04:10 PM, Vladimir Ivanov wrote:
On 6/29/15 1:35 PM, Aleksey Shipilev wrote:
On 06/27/2015 04:27 AM, Vladimir Ivanov wrote: Big picture question: do we actually care about propagating final field values once the object escaped (and in this sense, available to be introspected by the compiler)?
Java memory model does not guarantee the final field visibility when the object had escaped. The very reason why deserialization works is because the deserialized object had not yet been published. That is, are we in line with the spec and general expectations by folding the final values, and not deoptimizing on the store? Can you elaborate on your point and interaction with JMM a bit? Are you talking about not tracking constant folded final field values at all, since there are no guarantees by JMM such updates are visible?
Yup. AFAIU the JMM, there is no guarantees you would see the updated value for final field after the object had leaked. So, spec-wise you may just use the final field values as constants. I think the only reason you have to do the dependency tracking is when constant folding depends on instance identity.
So, my question is, do we knowingly make a goodwill call to deopt on final field store, even though it is not required by spec? I am not opposing the change, but I'd like us to understand the implications better.
For example, I can see the change gives rise to some interesting low-level coding idioms, like:
final boolean running = true; Field runningField = resolve(...); // reflective
// run stuff for minutes void m() { while (running) { // compiler hoists, turns into while(true) // do stuff } }
void hammerTime() { runningField.set(this, false); // deopt, break the loop! }
Once we allow users to go crazy like that, it would be cruel to retract/break/change this behavior.
But I speculate those cases are not pervasive. By and large, people care about final ops to jump through the barriers. For example, the final load can be commonned through the acquires / control flow. See e.g.: http://psy-lob-saw.blogspot.ru/2014/02/when-i-say-final-i-mean-final.html
Regarding alternative approaches to track the finality, an offset bitmap on per-class basis can be used (containing locations of final fields). Possible downsides are: (1) memory footprint (1/8th of instance size per class); and (2) more complex checking logic (load a relevant piece of a bitmap from a klass, instead of checking locally available offset cookie). The advantage is that it is completely transparent to a user: it doesn't change offset translation scheme.
I like this one. Paying with slightly larger memory footprint for API compatibility sounds reasonable to me. I don't care about cases when Unsafe API is abused (e.g. raw memory writes on absolute address or arbitrary offset in an object). In the end, it's unsafe API, right? :-)
Yeah, but with millions of users, we are in a bit of a (implicit) compatibility bind here ;)
So, my next question is how to proceed. Does changing API and providing 2 set of functions working with absolute and encoded offsets solve the problem? Or leaving Unsafe as is (but clarifying the API) and migrating Reflection/j.l.i to VarHandles solve the problem? That's what I'm trying to understand.
I would think Reflection/j.l.i would eventually migrate to VarHandles anyway. Paul? The interim solution for encoding final field flags shouldn't leak into (even Unsafe) API, or at least should not break the existing APIs.
I further think that an interim solution makes auxiliary single Unsafe.fireDepChange(Field f / long addr) or something, and uses it along with the Unsafe calls in Reflection/j.l.i, when wrappers know they are dealing with final fields. In other words, should we try to reuse the knowledge those wrappers already have, instead of trying to encode the same knowledge into offset cookies?
II. Managing relations between final fields and nmethods Another aspect is how expensive dependency checking becomes.
Isn't the underlying problem being the dependencies are searched linearly? At least in ConstantFieldDep, can we compartmentalize the dependencies by holder class in some sort of hash table? In some cases (when coarse-grained (per-class) tracking is used), linear traversal is fine, since all nmethods will be invalidated. In order to construct a more efficient data structure, you need a way to order or hash oops. The problem with that is oops aren't stable - they can change at any GC. So, either some stable value should be associated with them (System.identityHashCode()?) or dependency tables should be updated on every GC.
Yeah, like Symbol::_identity_hash.
Unless existing machinery can be sped up to appropriate level, I wouldn't consider complicating things so much.
Okay. I just can't escape the feeling we keep band-aiding the linear searches everywhere in VM on case-to-case basis, instead of providing the asymptotic guarantees with better data structures.
The 3 optimizations I initially proposed allow to isolate ConstantFieldDep from other kinds of dependencies, so dependency traversal speed will affect only final field writes. Which is acceptable IMO.
Except for an overwhelming number of cases where the final field stores happen in the course of deserialization. What's particularly bad about this scenario is that you wouldn't see the time burned in the VM unless you employ the native profiler, as we discovered in Nashorn perf work.
Recapping the discussion in this thread, I think we would need to have a more thorough performance work for this change, since it touches the very core of the platform. I think many people outside the hotspot-compiler-dev understand some corner intricacies of the problem that we miss. JEP and outcry for public comments, maybe?
Thanks, -Aleksey.
-------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: OpenPGP digital signature URL: <http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20150630/fca2e712/signature.asc>
- Previous message: On constant folding of final field loads
- Next message: On constant folding of final field loads
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the hotspot-compiler-dev mailing list