AnonCL and dynamic invocation
Charles Oliver Nutter
charles.nutter at sun.com
Sun Apr 27 11:45:57 PDT 2008
Additional late-night thoughts about ACL and dynamic invocation.
Obviously when I mentioned that in JRuby we'd use ACL to reduce handle
generation cost, I neglected to mention that that would only be the case
until the actual method handle API lands. That is assuming we'd be able
to provide enough customizable behavior for the handles (such as
pre/post call JRuby runtime preparation, like framing, heap scopes, and
Is there any way to efficiently load classes under JDK6 and lower such
that they would share bytecode stores and only have differing constant
pools? Any backported solution would need to utilize this.
A particular scenario I'm considering would be of use in most JVM
dynlangs: the ability to cheaply generate a bucket of handles for any
new Java class that enters a program's execution. Currently JRuby only
generates handles for bound Ruby methods due to the cost of generating
and managing so many classes. Groovy generates no handles at all, since
the call pipeline is focused on making dynamic invocation against
arbitrary Java types possible. So in both cases, when we're calling Java
code we're paying reflection cost (and memory cost associated with
managing a *crapload* of reflected objects). The ability to build up a
cheap set of handles here would be invaluable.
It's all starting to come into focus for me now re: JSR-292 use of this
stuff. First we need a cheap way to load tiny code snippits that
represent anonymous methods and method handles. Then we need a nice
method handle generator to make it easier to build a collection of
"callables" for an arbitrary class...handles that can do everything with
that class we'd be able to do from inside it, to escape the
reflected/generated handle problem of accessing protected and private
members. Once we have our handle mechanism, we need two additional
piecs: the ability to ask the JVM to do a dynamic invocation on our
behalf, specifying only a target object and list of arguments; and a way
to register our own method lookup and invalidation mechanism.
I think the dynamic invocation has been discussed a bit already and is
not going to be a particularly difficult API to design. Last I heard it
was simply an invokeinterface against a special type under java.dyn.
The second item, however, will take some discussion.
Currently JRuby uses the efficient but not-entirely-threadsafe approach
of registering all call sites in a "cache map" associating a method
handle with a list of caching sites. When classes in the system make
structural changes that would cause method handles to be replaced, they
call into the cache map, which then triggers all call sites associated
with the method handle to be flushed. It is efficient because it
requires only a simple type equality check in the inline cache, rather
than a type check plus a type modification guard like a serial number.
But it is thread-unsafe because the caching process is not atomic;
there's a small change that a method could get redefined in the middle
of caching, before a call site has registered with the cache map. This
has the effect of making the call site permanently stale. So we are
considering the serial number approach now, since the cache map *could
be* a lot of memory use and it's not entirely thread-safe.
Another use case for caching in dynamic invocation we have seen is
caching *failed* hits. In Ruby, it is very common for APIs to check if a
target object "responds to" a given message before proceeding. This is
their "duck typing" where an object's supported operations is considered
before its physical type. This leads to nicely type-decoupled code and
some rather elegant type-coercion mechanisms, but it also means that
without caching negative results you end up re-searching a hierarchy of
types for methods that will never be there. Because our current call
site caching mechanism only caches positive hits, we pay a full search
cost for all "responds to" checks. And because the cache flushing
mechanism depends on being triggered by real method handles being
replaced, there would be no way to flush call sites caching negative
results anyway. So we are considering the serial number approach, since
we could cache anything we want and just flush based on the target
type's new serial number.
I am interested in better approaches for this, and would like to discuss
mechanisms for JSR-292 to be notified that previously returned handles
are no longer valid.
More information about the mlvm-dev