some preliminary inlining work

1 view
Skip to first unread message

William Morgan

unread,
May 29, 2008, 2:52:39 PM5/29/08
to rubini...@googlegroups.com
I've made a very simple, preliminary method inliner. You can find it on
the 'inline-wip' branch of git://masanjin.net/rubinius. (Warning: I
reserve the right to do non-fast-forward updates on this branch!)

It currently only works for the case where the calling instructions are:
push_self
set_call_flags 1
send_method X OR send_stack X Y

In other words, where the callee is guaranteed to be self, and the
number of arguments is fixed (no default arguments and no splats),
and there are no blocks. Happily, this handles the case where you're
accessing an instance variable on the same object through its getter,
which is an actual thing I like to do in real life.

It's not hooked up to anything, and I'm not really sure it works, but
you can run kernel/core/inliner.rb for a simple example on one pair of
methods.

I haven't done anything with the VM, yet, in terms of detecting what to
inline and transitioning to this code. I figure I'll wait for the C++ VM
to settle down a bit, and do the method surgery bits in the meantime.

What I would really like to get working next is stuff like:
x = 0
1000.times { |i| x += i }
which will require first inlining Fixnum#times (so method dispatch to
non-self, but with no instance variable access), then inlining the block
(so a send_stack_with_block where the stack's context is the same as the
local context.) Because that's a pretty common idiom and it seems silly
that a while loop should be faster.

Comments, especially for kernel-land code idioms, appreciated.

--
William <wmo...@masanjin.net>

Dirkjan Bussink

unread,
May 29, 2008, 6:04:32 PM5/29/08
to rubini...@googlegroups.com

On 29 May, 2008, at 11:52 , William Morgan wrote:

>
> I've made a very simple, preliminary method inliner. You can find it
> on
> the 'inline-wip' branch of git://masanjin.net/rubinius. (Warning: I
> reserve the right to do non-fast-forward updates on this branch!)

Ah, really nice work :). We're all very enthusiastic about it here at
Railsconf :). When I was going through it, I did find (or better miss)
one thing that doesn't seem to be handled properly.

I think the inline will currently go wrong if there is an explicit
return before the last instruction of the method that is being
inlined, so then you jump out of the wrong method. Afaik this should
be fixable by a simple goto to the end of the inline method.

--
Regards,

Dirkjan Bussink

William Morgan

unread,
May 29, 2008, 8:27:34 PM5/29/08
to rubini...@googlegroups.com
Excerpts from Dirkjan Bussink's mail of 29 May 2008 (UTC):

> Ah, really nice work :).

Thanks!

> I think the inline will currently go wrong if there is an explicit
> return before the last instruction of the method that is being
> inlined, so then you jump out of the wrong method. Afaik this should
> be fixable by a simple goto to the end of the inline method.

Good point. I have some preliminary code for this in there now, but
actually this is non-trivial to fix because I'm replacing 1 opcode with
two at arbitrary places, so adjusting the goto labels gets complicated.

William Morgan

unread,
May 30, 2008, 3:18:48 AM5/30/08
to rubini...@googlegroups.com
Excerpts from William Morgan's mail of 30 May 2008 (UTC):

> Good point. I have some preliminary code for this in there now, but
> actually this is non-trivial to fix because I'm replacing 1 opcode
> with two at arbitrary places, so adjusting the goto labels gets
> complicated.

Fixed! I've dropped the whole offset stuff in favor of
explicitly managing the labels, so this kind of thing is now trivial.

--
William <wmo...@masanjin.net>

William Morgan

unread,
May 31, 2008, 1:01:34 PM5/31/08
to rubinius
Status update: I've pushed a bunch more stuff to the branch. It's fairly
specced out now, and the only thing that doesn't work is catching
exceptions in the caller method. Need to figure out the rescue mechanism
for that one.

Reformatted excerpts from William Morgan's message of 2008-05-29:


> What I would really like to get working next is stuff like:
> x = 0
> 1000.times { |i| x += i }
> which will require first inlining Fixnum#times (so method dispatch to
> non-self, but with no instance variable access)

I just realized that 1000.times is another type of easy dispatch (and
probably one that's specific to Ruby)---dispatch to a literal. Push_self
calls will have to be rewritten, but no guarding against type changes is
required because the class is fixed, and literals can't have
metaclasses.
--
William <wmo...@masanjin.net>

William Morgan

unread,
Jun 2, 2008, 8:04:20 PM6/2/08
to rubinius
Ok, pretty much everything is working for the inlined send-to-self case,
including exceptions! I'm about ready to merge this into the mainline
unless there are objections. It isn't hooked up to anything and only
touches stuff in kernel/.

See branch inline on git://masanjin.net/rubinius for what's to be
merged. There are a couple minor changes to kernel classes, and a big
blob of inlining code.

Known issues:
- DelegatedMethods unsupported. If you know how to get the bytecodes
out of one, then you win.
- The resulting CM just reports line 0 for everything. I could clean
that up, but there's currently only one file per method, so
backtraces are going to be wrong anyways if the methods are in
different files.
- Backtraces are going to be wrong anyways because the two methods are
merged into one.

There will probably be some fairly major refactoring once I start making
inliners to handle other types of method dispatch.
--
William <wmo...@masanjin.net>

Reply all
Reply to author
Forward
0 new messages