Callsite invalidation requirements?
Charles Oliver Nutter
headius at headius.com
Tue Feb 14 12:30:18 PST 2012
On Thu, Feb 9, 2012 at 12:53 PM, Mark Roos <mroos at roos.com> wrote:
> For code changes I don't know. Waiting for all threads to finish seems
> problematic. When developing
> this is probably OK but I use code changes in production to hot update
> systems and to add features
> on the fly.
At some point you have to decide on the visibility of code changes
across threads and synchronize or volatilize accordingly. In JRuby, we
make no explicit guarantees about the visibility of class/module
mutations, but our call sites are all wrapped up in SwitchPoints that
are invalidated on mutation. That should guarantee that a call site
will always see current methods, rather than stale entries. It won't
replace running methods, obviously, but each approach to a call site
means a new guard check that should see code changes.
Obviously if you never back out of a running method you can't replace
it with new code.
As for type checks, we actively validate that the incoming type is the
one we cached, so even if the call site is stale in another thread it
won't be that way for long.
My rule of thumb is this: volatility is only important if an
inconsistent view across threads is fatal. With active guards,
inconsistency has only the minor effect of causing other threads to
invalidate the cache too.
> For lookups I am not sure there is any need to sync. If a GWT chain is
> missing an implementation
> its just gets added. As long as each thread gets the correct method the
> fact that some of the GWTs
> in a chain are lost or duplicated by other threads is just an efficiency
> issue. So just being thread safe
> is enough.
I agree with you here. JRuby does no explicit synchronization around
GWT chain building, either, but we do sync wen encountering a new type
we've never seen before. We maintain a thread-safe Set of seen types,
and use that as our gauge for when to failover to a simple monomorphic
inline cache (not using MutableCallSite.set, but using a less invasive
field on our MCS subclass).
As above, volatility is not important if threads are actively
guarding. It only becomes a problem if you expect threads to reflect
call site changes automatically without doing any of their own guard
Oddly enough this came up on Twitter...one of the JRuby contribs in
Japan was discussing call site volatility with others and discovered a
bad race in my invalidation logic. Specifically, I was looking up the
method before I got the class's SwitchPoint...which is exactly the
wrong order. There were cases where I could end up associating the
looked-up method with a newer SwitchPoint, effectively caching forever
the wrong method.
More information about the mlvm-dev