On Thu, Sep 9, 2010 at 2:53 AM, John Rose <[email protected]> wrote:
> Here's something to think about as an alternative to the
> instanceof/cast/invoke dance for getting metaclasses.
>
> At the Summit we were talking about managing metaobjects via a class-specific
> analogue of ThreadLocal. Here's a sketch of what the JSR 292 EG is thinking
> about in that vein:
>
> http://cr.openjdk.java.net/~jrose/pres/indy-javadoc-mlvm-0908/java/dyn/ClassValue.html
>
> The implementation of such a thing should be tuned (as ThreadLocal is tuned)
> to execute in a small number of memory references, without locks or
> volatiles. Ideally the code would use a one-element cache, like this:
I think I told you and Jochen about my annotation trick, yes?
The trick is basically this: implement
java.lang.annotations.Annotation with your own "carrier" class:
public class MetaCarrier implements Annotation {
public final MetaClass metaClass;
public MetaCarrier(MetaClass metaClass) {
this.metaClass = metaClass;
}
}
Then, use reflection to crack open the java.lang.Class object and
inject carrier instances into it at runtime. The cost of retrieving
those instances is still ultimately a hash lookup or linear scan of an
array, as in someClass.getAnnotation(MetaCarrier.class).metaClass.
However, since the instance is *actually* attached to the
java.lang.Class object, you don't have to manually maintain a separate
weak/soft cache.
Obviously it's a hack, but I still think it's cute. Built-in support
would be much nicer. :)
> RubyClass metaClass = RUBY_META_OBJECT.get(object.getClass());
> =>
> mov (object+4), classtemp
> mov (classtemp+56), cachetemp
> cmp (cachetemp,8), RUBY_META_OBJECT
> jne slowpath
> mov (cachetemp,4), metaClass
>
> This provides an alternative path to interface injection for storing
> per-runtime data on *all* classes (RubyArray and java.lang.String alike).
> How useful would this be?
>
> Your feedback might help us decide on where ClassValue sits in a Plan A vs.
> Plan B feature cut, if such a cut comes about. See Mark Reinhold's blog for
> the A/B conversation.
Currently, JRuby is bound to pass IRubyObject implementations
throughout the system. This was a decision made before my time, and it
has advantages and disadvantages:
* For Ruby objects (which comprises most typical Ruby apps, since we
provide a full complement of our own String, collections, IO and other
APIs), it means we have only a single hop to get an object's
metaclass, via that monomorphic implementation and a shared field on
their common superclass RubyBasicObject. This means that for the vast
majority of objects in a typical Ruby app, we pay no additional
penalties to retrieve or cache metaclasses (as in Groovy, for
example).
* For Java objects (which we'd ideally like people to use more as a
value-add in JRuby), we are force to wrap them with an
IRubyObject-implementing wrapper. These wrappers are small, but for
repeated calls across the Ruby/Java barrier (blood/brain barrier?) it
can be costly to either maintain a weak cache of wrappers or to
recreate them on each pass-through. However, once the object is in
"Ruby space", we can always get at the metaclass through the same
single hop.
For the tightest possible integration with Java, we would obviously
want to do away with the IRubyObject wrapper, but by working very hard
to hide it most users never know it's there.
The largest challenge keeping us from moving everything toward Object
and away from IRubyObject as the basic atom in the system is metaclass
management. I've heard plenty of Jochen's horror stories about
managing their weak/soft/volatile/whatever caching mechanisms for
metaclasses, and if I understood his problems from JVMLS, this cache
remains one of the biggest problems for Groovy performance and
optimization. That scares the bejeezus out of me, and it's largely why
I haven't tackled the IRubyObject to Object conversion in earnest.
Having a reliable way to manage arbitrary per-class data would go a
long way toward making the transition easier (as would, of course,
interface injection...but even in that case we need a way to look up
the class once we're in the injected interface).
So, long story short, it seems like the inability to attach clean,
safe, lifecycle-attached data to classes is a fundamental problem for
mutable-metaclass or runtime-class-decorating languages like Groovy
and JRuby.
I'll have a look at Mark's blog.
- 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.