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


Reply via email to