ObjectSpace.each_object alternatives for enumerating modules

87 views
Skip to first unread message

Dmitry Gutov

unread,
Jun 11, 2013, 6:25:56 PM6/11/13
to rubini...@googlegroups.com
Hi all,

I'm developing a code assistance package for Emacs
(http://github.com/dgutov/robe), and I'd like to provide better support
for Rubinius.

It already works, but it's considerably slower than MRI because I'm
using ObjectSpace.each_object there, for any operation. It's quite fast
on MRI, so it seemed appropriate.

Is there a faster way to do the following things on Rubinius?

1) Enumerate all modules (or all classes) loaded in the current
environment.

2) Enumerate all descendants of a given class. I've looked at
ActiveSupport::DescendantsTracker, and it kinda works, but ideally I
would like to be able to enumerate even the core classes, that are
loaded during IRB startup. It doesn't seem to help with that.

Even JRuby, with ObjectSpace "disabled" by default, runs the following
successfully and within 1 ms:

ObjectSpace.each_object(Module) {|m|}

It takes ~80ms on Rubinius on my machine.

Best regards,
Dmitry

Dirkjan Bussink

unread,
Jun 12, 2013, 5:13:54 AM6/12/13
to rubini...@googlegroups.com
Hi Dmitry,

> It already works, but it's considerably slower than MRI because I'm
> using ObjectSpace.each_object there, for any operation. It's quite fast
> on MRI, so it seemed appropriate.

In general terms, we don't consider this actually to be appropriate. The biggest problem is that it basically entails having to do the same work as a full GC cycle, to walk all of the objects in the system.

> Is there a faster way to do the following things on Rubinius?
>
> 1) Enumerate all modules (or all classes) loaded in the current
> environment.

We could add special case logic here like JRuby has. They basically treat each_object with Class or Module specially so it doesn't suffer from the problem of having to track way more runtime information or depend on GC infrastructure to track this. It might be useful to add similar mechanisms to Rubinius.

> 2) Enumerate all descendants of a given class. I've looked at
> ActiveSupport::DescendantsTracker, and it kinda works, but ideally I
> would like to be able to enumerate even the core classes, that are
> loaded during IRB startup. It doesn't seem to help with that.

This information is actually already available in Rubinius, but there is currently not a standardized API across Ruby implementations for this. We already track this information for method cache invalidation purposes. Every Module (and thus also Class) has an instance variable name @hierarchy_subclasses. This contains an Array of Weakref objects pointing to inheriting classes. You could walk this recursively to obtain all the children.

Please note however that this is currently an internal API and could change in the future. We could look at providing an API for this, but the biggest problem is that we can't just use something that would collide with something like DescendantsTracker.

--
Regards,

Dirkjan Bussink
Reply all
Reply to author
Forward
0 new messages