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.

- Charlie

---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply via email to