Loop handle?
Charles Oliver Nutter
headius at headius.com
Fri Apr 9 11:23:03 PDT 2010
On Fri, Apr 9, 2010 at 4:53 AM, Fredrik Öhrström
<fredrik.ohrstrom at oracle.com> wrote:
> It might be fun, but I do not think that it is a good idea to implement
> an interpreter in this way,
> or more precisely, to implement any interpreter of bytecodes, using Java.
I never said anything about a bytecode interpreter :)
> For languages like Ruby where the executable format is the source, I
> assume that your interpreter works on the source text by
> parsing/interpreting each source code line after each other. Since each
> interpreter step requires so much computation you will not gain any
> measurable performance by putting the interpreter loop inside the
> MethodHandle.
In JRuby, we actually interpret Ruby code by walking the AST. It's a
series of interpret calls chained form one to the next. So if we can
represent Ruby code as a tree of executable objects of one kind...
> On the other hand, if you interpret bytecodes, then each interpreter
> step is very small. At first it might look like a good idea to try to
> shave a few instructions from each interpreter step.
>
> But the whole point of achieving good performance on the JVM is that you
> translate the bytecodes of the other language into JVM bytecodes and
> then allow the JVM technology to do its magic.
>
> When you implement an interpreter with JVM bytecodes (or MethodHandles)
> then you immediately shut the door hard in the face of the JVM. It is
> simply impossible for the JVM to optimize >through< your interpreter
> loop into your application. The JVM will try to optimize your
> interpreter loop, but it is still only the interpreter loop. No
> variables will be optimized away from your code, no objects allocations
> will disappear, no inlining will happen!
I think you misunderstand what I mean. I don't want to implement an
interpreter using MethodHandles...I want to represent the actual Ruby
code by recomposing the AST's structure in an identical structure of
MethodHandles. In otherwords, a piece of code like this:
if a.foo() # condition
b + c # then
else
bar() # else
end
which would be an AST something like
If
..Call "foo" # condition
....LocalVar "a"
..Call "+" # then
....LocalVar "b"
....LocalVar "c"
..Call "bar" # else
would get recomposed into handles something like this:
GuardWithTest
..InvokeDynamic "foo" # condition
....VariableLookup "a"
..InvokeDynamic "+" # then
....VariableLookup "b"
....VariableLookup "c"
..InvokeDynamic "bar # else
And because direct method handles get composed together, it would
essentially become the native code version of the Ruby AST, without
any compile phase (or rather, the compile phase is the recomposition
as DMHs).
The reason a loop handle is needed is because there's "while"
constructs in Ruby I need to represent somehow...*not* because I want
to construct a bytecode loop:
while a.foo # condition
b.bar # body
end
needs to become
Loop
..InvokeDynamic "foo" # condition
....VariableLookup "a"
..InvokeDynamic "bar" # body
....VariableLookup "b"
There's no way to represent this using handles without a loop construct.
Think about this more like if I were using LLVM and calling its
various methods for representing variable/memory access, flow control,
basic blocks, and so on. That's what I want: a toolkit for composing
the spirit of my code in a recognizable form which then optimizes and
assembles that spirit into native code (or bytecode).
- Charlie
More information about the mlvm-dev
mailing list