In Ruby, you can use a block as though it were a binding:

def foo(&b)
  eval 'puts a', b
end

def bar
  a = 1
  foo {} # prints out '1'
end

It is largely because of this feature that our block scoping is very
costly; whenever a block is present, the containing method's local
variables must all be lifted to the heap, so they can be accessed
across calls. This means that 'bar' above will have a permanent
performance penalty for all local variables, even though none of them
are accessed within the block passed to 'foo'.

In Groovy, there's no ability to use a block as a binding, so they
only close over the variables that will actually be accessed. This
means that you only pay the heap-scoping cost for variables you
explicitly use across the closure boundary. This allows Groovy's
closures to be considerably lighter-weight, and in many cases be as
fast as any other call.

But there is a way out of this. Yehuda and I talked a bit about it and
realized that if we could inspect the target method whenever we're
calling a block, we could determine whether a full heap scope would be
needed. There are only three constructs that would trigger this
potential:

* A block argument (&arg) in the parameter list, because it's
capturing the block for later use
* A zsuper call (no-arg, no-parens super), because that call could
capture the block for later use
* If the call itself is Proc.new, proc, or lambda, because it's
capturing the block (or -> in 1.9)
* Any eval-like call (binding, eval)

All three of these are inspectable at method-construction time, so we
could have a flag on method objects for "might do evil things with
your block". At that point, we could lazily lift all our local
variables to a heap structure and follow the heap-scoping path from
then on, This would have to be a hard trap + branch to deoptimized
code, but it could work. We will need to think about how to deoptimize
by branching to a new body of codewith current execution state, but I
think it's possible.

An alternative to dynamic deopt would be to add profiling information
at the call site indicating whether we ever see a block used as a
binding. We would still need to consider a deopt mechanism, but we
would not necessarily need to depend on it as much, due to the
profiling probably being all the information we need.

I would strongly prefer this feature just disappear, but it's not going to.

- Charlie

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

    http://xircles.codehaus.org/manage_email


Reply via email to