On Wed, Jul 29, 2009 at 7:55 AM, Charles Oliver Nutter<head...@headius.com> wrote: > On Sat, Jul 25, 2009 at 10:37 PM, Thomas E Enebo<tom.en...@gmail.com> wrote: >> Hotspot will synthesize types based on runtime profiling for things >> like interfaces so that it can internally perform static dispatch (or >> so I have been told). They also have guards to deopt if their type >> assumptions are wrong. We could do something similar since as others >> have noted at some point Ruby classes hit an unchanging state in 99% >> of all applications (yes, I made that number up but I will stand by it >> :) ). > > I think this idea has a lot of promise, especially if we can cleanly > generate synthetic interfaces at runtime and slowly raise object types > to new class types that implement those interfaces. So one scenario > could be that if you have: > > class Foo > def bar; end > end > > And we generate a synthetic "bar" interface open first seeing the > method in the compiler, then we can later lift the Foo class into a > real Java class that implements "bar" and do a simple interface > dispatch from then on. Or if we've got enough information from a > single pass compile of a file, generate such interfaces and > implementations right away, using them for static interface dispatch > wherever possible. > > There's a lot of weird and unwieldy tools, but I think there's some > combination that can get us really excellent perf. > >> c is probably the grail for good closure performance. >> >> The cases for whether you can or need to keep variables around is >> probably the most interesting discussion. I think it could be broken >> into at least one thread by itself. I think collectively we can >> identify many special cases where we don't need to capture all >> variables. Of course that assume we can track changes to target >> classes method. If it changes for some reason we need to be able to >> deopt. > ... >> My bigger question is can we figure out whether these things (send, >> eval, binding) are actually the nasty methods rather than just >> assuming anything with these names are the nasty methods? I know the >> answer is yes, but I think internally we should have some systemic way >> of tracking dangerous entities so we have one framework to use for >> various optimizations.... > > We can do so at runtime, of course. If we just use the name as a > trigger that "runtime analysis is required" then we can have a simple > guard on those calls that first checks if it's *actually* the bad > version of the method, and at that point branches to a slow-path > version of the code with all local variables lifted to the heap. So > something like this: > > Ruby code: > def stringer(local1) > local2 = "to_s" > local1.send(local2) > end > > Rough generated pseudo-java > public IRubyObject _optimized_stringer_(IRubyObject local1) { > IRubyObject local2 > local2 = newString("to_s"); > > DynamicMethod sendMethod = local1.getMethod("send"); > if (sendMethod.needsHeapAccess()) { > return _deoptimized_stringer_line_2(local1, local2); > } > return sendMethod.call(local1, local2); > } > > public IRubyObject _deoptimized_stringer_line_2(IRubyObject local1, > IRubyObject local2) { > DynamicScope scope = newScope(local1, local2); > > // proceed with "bad" send with heap scope appropriately provided > } > > This obviously incurs a lot of overhead for those bad methods, since > we need the deopt path to be present, and we need to generate perhaps > one deoptimized code body per "evil" method called. But those methods > all incur their own overhead that impacts performance in the best of > cases, so they're going to be problematic no matter what. This would > at least reduce the overhead when they're not one of the bad methods. > > And if we're able to propagate throughout a method that the "eval" > we're getting back is always a "friendly" one, we only need to check > once. > >>> 6. Dynamic/Late binding: This is where the execution context comes from an >>> explicit binding argument (proc, binding, closure). This is something I was >>> not aware of till recently. >> >> Yucky stuff. There are some times when we can probably optimize based >> on knowing how the binding/proc/closure is used. As Charlie notes, >> AOT-defined Ruby methods we fully understand like core method impls >> can be optimized. I think we can even make arbitrary ruby methods >> optimize by indicating on compilation whether they do wacky stuff. >> Some chicken and egg stuff in my mind....we need to know that a block >> will be passed to a method and that that method is not using the block >> in a strange way before creating the block itself. > > Yehuda's idea would probably work well for us; we'll just add some > additional informational flags about a target DynamicMethod to the > DynamicMethod superclass, and use that to do a similar deopt as > above... targetMethod.isCapturingBlock() or something.
Yeah once we know which target method will be receiving the block we can know how the block can be abused by some flags on the method. This seems like a great idea. Similiarly (as we have talked about before), if we know that a block is not capturing any information we could just convert it to be a DynamicMethod itself and then inline the callsite to that 'new' method (that is assuming the block does not only have a single local parameter). <-- Subbu: block parameter assignment is another interesting place to study if you have not already. -Tom -- blog: http://blog.enebo.com twitter: tom_enebo mail: tom.en...@gmail.com --------------------------------------------------------------------- To unsubscribe from this list, please visit: http://xircles.codehaus.org/manage_email