It seems to me that *all* calls to "dangerous methods" are basically leaf calls, because you only need to grab the "frame" information one frame above where the information was added. So you should be able to have each Ruby *thread* allocate a single thread-local slot per "frame" variable plus a flag slot. A call through the "frame" protocol would look like this:
call method look in flag slot if flag on copy frame variables into local context end This effectively means that calling a method through the protocol when the method turns out to not be dangerous just adds a single boolean check, which should be incredibly cheap. Also, if someone aliases a dangerous method, it's probably ok to just flush all compiled bytecode (because it basically never happens and when it does it's reasonably to take a big hit). -- Yehuda On Sat, Jul 25, 2009 at 3:44 PM, Charles Oliver Nutter <[email protected]>wrote: > I was talking with Yehuda today and I think we came up with a couple > solutions for eliminating frames. > > The cases where we have problems are: > > * All methods that read or write backref > * All methods that read or write lastline > * All methods that read or write visibility > * All methods that have arbitrary access to the binding (eval, binding, > ...) > * Methods that have closures that do any of these things, or where the > closure is used as a binding elsewhere > > The first three cases could be solved as follows: > > Backref and lastline can only be read or written in one of two ways: > via a Java-implemented core class methods, or via the syntactic > constructs $~ for backref or $_ for lastline. Visibility can only be > written by public/private/protected method calls, and only gets read > by Java code that handles plumbing new methods. All three are scoped > at the nearest "hard" scoping boundary, like a method or a class, and > closures within that scope share the same slot (this last point is a > little fuzzy, but it's good enough for illustration purposes). > > Currently, all Ruby code bodies prepare a heap-based structure (Frame) > for every call, just in case it might be needed. This is in large part > a reason for remaining slowness in Ruby execution, since even in > compiled mode we have to prepare this structure on the way in and drop > it on the way out, even if it's never used. > > However it turns out that the methods that read/write > backref/lastline/visibility are *leaf* methods; there's exactly one > hop to get to the native code that manipulates them. > > I believe it's time we had an additional call path that can include a > "Blob" object that contains these fields. With this call path, any > time one of these "potentially dangerous" method names is seen in > code, we could *lazily* prepare the Blob and pass it down the call > path. It would eventually arrive in the target method and be used to > do the read/write as though it were an "out" variable. So this > immediately isolates those frame fields' overhead to cases where > they're potentially going to be called (barring aliasing effects). > > If we lifted the lookup of the target method all the way to the call > site, we could physically inspect it to see if it *is* one of those > "dangerous methods" and only pass the Blob in those cases. > > If we also added construction and passing of this Blob into the IR, we > could see whether the Blob is ever subsequently read from or written > to, and potentially *never* allocate it whatsoever. > > I think this is a very simple way for us to safely eliminate some > framing cost. I'll try to make the idea a bit more concrete. > > - Charlie > > --------------------------------------------------------------------- > To unsubscribe from this list, please visit: > > http://xircles.codehaus.org/manage_email > > > -- Yehuda Katz Developer | Engine Yard (ph) 718.877.1325
