I had a chance to sit down with Rich at JavaOne to discuss this. (Thanks Rich!)
The key problem is caching the result of a partial evaluation. (For example,
an expected method dispatch at a call site, or a metaclass which summarizes the
shape of a type.) The cached value can be made "pure" (read-only) but it is
subject (at least potentially) to very slow change, once per "epoch". Let's
call such a slowly varying value a "stable value".
(Compare "stationary values" Ian Rogers's paper for PPPJ'08. What dynamic
language folks need is an epochal variation of this concept, a value which is
stationary most of the type and changes once in a blue moon. Hence, "stable
value".)
The typical dynamic language technique is to use a volatile variable to hold
the cached value. The volatility ensures that once-per-epoch changes get
immediately picked up by threads. The problem is that the volatile reference
defeats caching and inlining of all sorts.
The JVM has better tricks. It can cache and inline a vtable lookup if it can
prove (from class hierarchy analysis) that a method is not overridden. The
invokedynamic instruction has similar capabilities. If the epoch changes
(because a new overriding method is loaded), code needs to be edited or
discarded, and threads need to be interrupted. This happens at a safepoint.
Here's a sketch for a user-level hook to stable values:
public class StableValue<T> {
/** Get the current value. */
public T getStableValue() {...}
/** Set the current value. This may be costly. */
public void getStableValue(T x) {...}
/** Commit the current value. Future calls to set() will throw. */
public void getStableValue() {...}
}
I'm going to abbreviate "getStableValue" as "get", etc., from here on. It is
tempting to make an analogy with java.lang.ref.Reference, but I don't know if
that makes enough sense. By using the full term "getStableValue" we can
contemplate mixing stable values into other types:
public class CallSite extends StableValue<MethodHandle> { ... }
Anyway, the idea is that the JVM is encouraged (by the user) to perform
optimizations on the value returned by the get() call. If it does so, it must
somehow watch for future calls to set(). The freeze() call (from the user)
informs the JVM that it can stop watching. This should probably be a
system-defined class, because it may have private fields which participate in
the JVM's task of tracking dependencies.
Of course, static variables in Java are somewhat amenable to this treatment
"automagically". But the above abstraction guides the JVM much more clearly.
I don't think we can retrofit this behavior onto normal Java variables. (We
can with "static final" of course, but those guys can't evolve over the
epochs.) It's better to be explicit here, I think.
StableValue should be subclassable, in the same style as java.lang.ref classes.
That will remove gratuitous indirections. For example, a StableHashTable
could be built whose entries subclass StableValue, much like a WeakHashTable.
It should be possible to build lazy values on top of StableValues, by
overriding get() to check if the current value is null. (Another reason to
subclass.)
The StableValue.set call should perform the memory effects of a release (cf.
monitorexit) before the value is published.
The StableValue.get call should perform the memory effects of an acquire (cf.
monitorenter) before the value is fetched, the *first* time any given thread
calls get() on a given StableValue. Subsequent get() calls are "for free".
This is why a safepoint mechanism is needed, to force querying threads to
re-aquire relevant memory blocks.
A StableValue can be "entangled" with optimized code if its value is folded
into the code. If this happens, the JVM needs to keep track of the StableValue
so that it can adjust or discard the code the next time the value changes. The
StableValue class probably needs invisible synthetic fields to help it link
into the JVM's data structures for tracking code dependencies.
The caching behavior of java.dyn.CallSite with respect to setTarget could then
be defined in terms of StableValue. It will be "as if" the CallSite held its
current target in a StableValue.
Class metadata (of type MyMD) can be stored in a ClassValue<StableValue<MyMD>>.
For information on ClassValue, see:
http://cr.openjdk.java.net/~jrose/pres/indy-javadoc-mlvm/java/dyn/ClassValue.html
-- John
P.S. None of the above helps with the special case of getting invalidation when
types gain new subtypes. There's another hook needed there, I think. For
example, ClassValues could be optionally made sensitive to class hierarchy
changes, so that they get recomputed if new subtypes are loaded. Not sure if
this is needed, though.
--
You received this message because you are subscribed to the Google Groups "JVM
Languages" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/jvm-languages?hl=en.