Rocky Bernstein wrote:
>     Currently we do not optimize away call frame information in most cases,
> 
> 
> Most cases? You wrote before
...
 >
 > which gave me the impression that "optimizing frames away" was important
 > for JRuby.
 >

We statically, conservatively optimize away frames at present.

- Ruby-based methods always have frame objects right now
- Java-based core class methods have frames if they need to have frames, 
such as if they call back out to Ruby again or need to show up in a 
backtrace. But in many cases, we do not bother allocating a frame for 
most core methods. This has the benefit of improving performance 
substantially, but sometimes alters stack traces.

I've been looking into a few areas to minimize the cost of frames:

1) a more aggressive static optimization to omit frames when they're not 
needed. Performance improves quite a bit as a result:

Framed method dispatch benchmark
Test ruby method: 100k loops calling self's foo 100 times
   1.241000   0.000000   1.241000 (  1.157000)
   0.970000   0.000000   0.970000 (  0.970000)
   0.830000   0.000000   0.830000 (  0.830000)
   0.826000   0.000000   0.826000 (  0.827000)
...

Unframed:
Test ruby method: 100k loops calling self's foo 100 times
   1.214000   0.000000   1.214000 (  1.130000)
   0.351000   0.000000   0.351000 (  0.351000)
   0.331000   0.000000   0.331000 (  0.331000)
   0.259000   0.000000   0.259000 (  0.259000)
   0.249000   0.000000   0.249000 (  0.249000)
   0.246000   0.000000   0.246000 (  0.246000)
...

For comparison, Ruby 1.9:

Test ruby method: 100k loops calling self's foo 100 times
   0.920000   0.010000   0.930000 (  0.928233)
   0.930000   0.000000   0.930000 (  0.929611)
   0.920000   0.000000   0.920000 (  0.925376)
   0.920000   0.000000   0.920000 (  0.926120)
   0.920000   0.010000   0.930000 (  0.925559)

But this isn't enabled by default in JRuby because it destroys exception 
backtraces (since there's no frames, there's no way to report each call 
in the backtrace)...so then....

2) Using the Java backtrace for Ruby's backtrace. This would allow JRuby 
to piggyback on all the optimization Java does for frames and 
backtraces, but allow me to eliminate my heap-based frame objects when I 
know they won't be used. Then heap-based frame objects would only be 
necessary for call state that must cross call boundaries.

Really the primary limiting factor for JRuby to omit frame objects is 
being able to supply a useful backtrace. Why can't we just use Java's 
backtrace all the time? JRuby supports both interpreted and compiled 
execution...so Java's backtrace may show a mix of compiled and 
interpreted logic.

> Nevertheless, unless this is the case that it can /never/ happen when 
> caller() is used, what in fact happens now?

We would probably flag 'caller' as a "special" method since it can 
access information beyond the reach of the calling method, and using it 
would deoptimize. But of course it complicates other things...use of 
caller could happen after calls higher in the stack have been optimized 
to run without framing...in which case caller will not be able to get 
accurate information.

> Personally, I don't see anything wrong clarifying the explanation of  
> caller() to mean that it gives reports the frames it sees is currently 
> there if that's in fact what's going on in the YARV and JRuby 
> implementations. The other alternative of course is to have these 
> implementations try to support caller as though no frames were removed.

Is it useful if the result could vary depending on how you write your 
code and how long the code has run?

Another option is that various features like this that require extra 
performance-degrading bookkeeping would be enabled or disabled by a 
flag, as in JRuby's ObjectSpace implementation (where each_object only 
worked for Class by default, but +O makes it work for everything). That 
would allow folks interested in using the feature to enable it (or leave 
it enabled) and those interested in more performance but fewer features 
to turn it off. This is the approach we're taking with many features in 
Ruby; you can choose to use them or not use them, and the performance 
implications are in your hands.

- Charlie

- Charlie