On Tue, Apr 20, 2010 at 12:52 PM, Jochen Theodorou <[email protected]> wrote:
> I spend uite some time to get an overview and counted about 20 points were
> concurrent stuff is involved on the first call of a method. If the method is
> called again, this is reduced to some volatile access to see if a category
> is active and some other things. For example to get the metaclass. In case
> of a GroovyObject this is easy, since the Object itself stores the meta
> class. In the case of a Java based Object we need to get the metaclass from
> the global registry, which is more or less a concurrent map. In the best
> case this is will involve access to a volatile too.

The equivalent case in JRuby would be when a Java object enters "Ruby
space", at which time we have to look up its metaclass. However in
JRuby all such objects are then wrapped in a thin wrapper that holds a
hard reference to the metaclass. Subsequent calls then have immediate
non-volatile field access to the metaclass for the object, and the
only remaining cost is picking the right method overload (which also
gets cached based on incoming argument types).

We do want to move away from having the wrappers, however, since they
can sometimes interfere with object identity and certainly increase
the memory footprint of Java objects flowing through Rubyspace. In
that case we would have the same challenge as you to recover the
metaclass on each call. My strategy would most likely be to build in
per-site polymorphic caches that can hold references to previous
metaclasses they have seen, allowing for a simple identity check. I
assume you've done this already in your inline caching.

All classes in JRuby are mutable, which means every call must perform
a check to see if their cache is now stale. In JRuby, this boils down
to caching a tuple of [token, method] where the token is just an
Object instance. The token is compared with that on the incoming class
to know whether it's the same class in the same state as the previous
call. Failure means the tuple is dumped and re-cached. On the
metaclass side, changes to one metaclass flip the token of that class
but also flip the tokens of all descendants.

Ultimately this means for a successfully cached call site in JRuby,
the cost is only a volatile read plus an object comparison (not
counting non-volatile fields to get the cache tuple and the token and
method, of course). It's pretty small.

> Even if we had method handles (Groovy is based on Java 1.5 atm), I would
> still have to do things like checking if there is an active category, if the
> metaclass is still the same and not mutated (ExpandoMetaClass allows
> mutation)
>
> For the category stuff it might be interesting to look at
> org.codehaus.groovy.runtime.GroovyCategorySupport#hasCategoryInCurrentThread,
>  which uses an AtomicInteger in the first place and if that check fails we
> have to get a ThreadLocal storing the real category information.

The solution that comes to mind for me is that all calls should bounce
through some "invoker" that is per-thread. The invoker would be a
non-category invoker normally and once a category is active the
threadlocal invoker would be replaced with a category-aware invoker.
Because no other threads would need to see the per-thread invoker, all
access to it would be nonvolatile, and you would avoid the cost of
checking for an installed category on every call.

Of course I must admit I don't know all the details of categories.

> org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite#checkPojoMetaClass()
> contains the check we do for a cached java method. Something similar is done
> for method calls on groovy objects.

Yes, this will be interesting for us once we eliminate the wrappers
around Java object. For the moment, it appears the wrappers make it
about twice as expensive for a Java object to enter Ruby in JRuby as
it would cost for the same call to happen in Groovy.

- Charlie

-- 
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.

Reply via email to