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