Discussion:
[jruby-dev] IR JIT status update
Charles Oliver Nutter
2014-02-06 23:46:43 UTC
Permalink
A lot more code is working now that I've just opted to back off
specializing anything beyond what the IR does itself. This means that
passing a block to nested closures is done by reifying it into a Proc,
sticking it in the DynamicScope, and unboxing it on the other side...among
other things. Methods always use boxed argument lists; invokedynamic is
used to handle boxing arguments on the calling side and unboxing them on
the receiving side. This *might* make that boxing eligible for escape
analysis to eliminate the allocation, but I have not dug deeper to see.

I also have closures basically working now, though non-local flow control
still requires too much data from IR structures to implement right now
(non-local break and return, for example).

I also ran into an issue with how heap variable assignment is being
optimized:

for the closure passed to foo: a = 'here'; foo { a = 'bar'; puts a }

Linearized instructions for JIT:
0 thread_poll
1 line_num(0)
2 %t_a_1 = "bar"
3 %cl_1_0 = call_1o(FUNCTIONAL, 'puts', %self, [%t_a_1]){1O}
4 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
5 return(%cl_1_0)
6 %cl_1_2 = recv_jruby_exc
7 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
8 runtime_helper(catchUncaughtBreakInLambdas, [%cl_1_2])

The exception table here handles exceptions from 0 to 5 by branching to 6.
However, 7 attempts to load a value first assigned within that catch range.
When I try to compile this to JVM bytecode, it fails because there's no
guarantee that %t_a_1 has been assigned before 7 runs.

In any case, things are moving along well. There's a few things to fix and
lots of things to optimize, but progress is being made.

- Charlie
Thomas E Enebo
2014-02-07 00:45:37 UTC
Permalink
I am actually working on unboxing interpreter through common call paths on
a private branch with an eventual goal of adding specialized interpreters
for methods(class/instance) and for script/eval bodies (two different
patterns of instructions). It seemed wrong to implement new interpreters
without punching argument unboxing through first.

Hopefully something interesting for next week?

-Tom


On Thu, Feb 6, 2014 at 5:46 PM, Charles Oliver Nutter
Post by Charles Oliver Nutter
A lot more code is working now that I've just opted to back off
specializing anything beyond what the IR does itself. This means that
passing a block to nested closures is done by reifying it into a Proc,
sticking it in the DynamicScope, and unboxing it on the other side...among
other things. Methods always use boxed argument lists; invokedynamic is
used to handle boxing arguments on the calling side and unboxing them on
the receiving side. This *might* make that boxing eligible for escape
analysis to eliminate the allocation, but I have not dug deeper to see.
I also have closures basically working now, though non-local flow control
still requires too much data from IR structures to implement right now
(non-local break and return, for example).
I also ran into an issue with how heap variable assignment is being
for the closure passed to foo: a = 'here'; foo { a = 'bar'; puts a }
0 thread_poll
1 line_num(0)
2 %t_a_1 = "bar"
3 %cl_1_0 = call_1o(FUNCTIONAL, 'puts', %self, [%t_a_1]){1O}
4 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
5 return(%cl_1_0)
6 %cl_1_2 = recv_jruby_exc
7 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
8 runtime_helper(catchUncaughtBreakInLambdas, [%cl_1_2])
The exception table here handles exceptions from 0 to 5 by branching to 6.
However, 7 attempts to load a value first assigned within that catch range.
When I try to compile this to JVM bytecode, it fails because there's no
guarantee that %t_a_1 has been assigned before 7 runs.
In any case, things are moving along well. There's a few things to fix and
lots of things to optimize, but progress is being made.
- Charlie
--
blog: http://blog.enebo.com twitter: tom_enebo
mail: tom.enebo-***@public.gmane.org
Subramanya Sastry
2014-02-07 00:49:33 UTC
Permalink
On Thu, Feb 6, 2014 at 5:46 PM, Charles Oliver Nutter
Post by Charles Oliver Nutter
A lot more code is working now that I've just opted to back off
specializing anything beyond what the IR does itself.
Makes sense. Let us fix the IR and add any missing info to make sure what
JIT gets is mostly ready to go.
Post by Charles Oliver Nutter
I also have closures basically working now, though non-local flow control
still requires too much data from IR structures to implement right now
(non-local break and return, for example).
Yes, we still have to add info to StaticScope to remove dependency on
IRScope. IRStaticScope was a "temporary" fix to get IR mode functional
without disrupting / touching existing runtime.
Post by Charles Oliver Nutter
I also ran into an issue with how heap variable assignment is being
for the closure passed to foo: a = 'here'; foo { a = 'bar'; puts a }
0 thread_poll
1 line_num(0)
2 %t_a_1 = "bar"
3 %cl_1_0 = call_1o(FUNCTIONAL, 'puts', %self, [%t_a_1]){1O}
4 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
5 return(%cl_1_0)
6 %cl_1_2 = recv_jruby_exc
7 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
8 runtime_helper(catchUncaughtBreakInLambdas, [%cl_1_2])
The exception table here handles exceptions from 0 to 5 by branching to 6.
However, 7 attempts to load a value first assigned within that catch range.
When I try to compile this to JVM bytecode, it fails because there's no
guarantee that %t_a_1 has been assigned before 7 runs.
This looks like a bug in the AddLocalVarLoadStoreInstrs pass ... It should
have dumped dirty vars at all sites that could raise excs. -- in this case
before the puts.
Will take a look in the coming days.

We should also think about adding additional tests beyond rubyspecs to
stress test some of this ... given that the rubyspec run is back to old
state (10 fails, 3 errors) with this pass enabled.

Subbu.
Post by Charles Oliver Nutter
In any case, things are moving along well. There's a few things to fix and
lots of things to optimize, but progress is being made.
- Charlie
Subramanya Sastry
2014-02-12 02:09:07 UTC
Permalink
Post by Charles Oliver Nutter
I also ran into an issue with how heap variable assignment is being
Post by Charles Oliver Nutter
for the closure passed to foo: a = 'here'; foo { a = 'bar'; puts a }
0 thread_poll
1 line_num(0)
2 %t_a_1 = "bar"
3 %cl_1_0 = call_1o(FUNCTIONAL, 'puts', %self, [%t_a_1]){1O}
4 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
5 return(%cl_1_0)
6 %cl_1_2 = recv_jruby_exc
7 store_lvar(%t_a_1, -e_CLOSURE_1, a(1:0))
8 runtime_helper(catchUncaughtBreakInLambdas, [%cl_1_2])
The exception table here handles exceptions from 0 to 5 by branching to
6. However, 7 attempts to load a value first assigned within that catch
range. When I try to compile this to JVM bytecode, it fails because there's
no guarantee that %t_a_1 has been assigned before 7 runs.
This looks like a bug in the AddLocalVarLoadStoreInstrs pass ... It
should have dumped dirty vars at all sites that could raise excs. -- in
this case before the puts.
Will take a look in the coming days.
We should also think about adding additional tests beyond rubyspecs to
stress test some of this ... given that the rubyspec run is back to old
state (10 fails, 3 errors) with this pass enabled.
This bug is now fixed (
https://github.com/jruby/jruby/commit/f5facaa1be5656da02e18131aca90cdc8ef0d94f
)

-S.

Loading...