On 12/03/2010 07:21 PM, John Rose wrote:
On Dec 1, 2010, at 6:39 AM, Charles Oliver Nutter wrote:
On Wed, Dec 1, 2010 at 8:20 AM, Rémi Forax <[email protected]
<mailto:[email protected]>> wrote:
Here objs[..].each is megamorphic. That's the problem.
It's not related to closure or EA.
So yes, in your example, you have to heap allocate p,
but you will have to do it once.
Yes, but that's the point. EA is too fragile since it can't see
through megamorphic (or N > 2 polymorphic) call sites of any kind. So
you can't just say "if it can be stack allocated, it doesn't escape"
because that's now how Hotspot sees it.
Yes. HotSpot's EA logic is very conservative.
There may be language-specific EA conditions which you can define to
be more permissive in such cases.
If you are able to prove (in the JRuby compiler and runtime) that 'p'
does not escape the 'each' call, you can pass a static code pointer
for 'p' and handle the data link ('i' or a frame containing 'i') via
another means. The simplest means is defining another entry point to
'each', invisible to the user, which takes the closure "on the stack"
broken into components.
Breaking the static code pointer and data link is the same as manual
scalarization of any other immutable structure. Compare:
Object c = new Complex(3,4);
Object m1 = Complex.modulus(c);
Object m2 = Complex.#"modulus:scalarized"(3,4);
vs.
Object p = #localPutsProcBody.bindTo(i);
Object r1 = x.each(p);
Object r2 = x.#"each:scalarized"(#localPutsProcBody, i);
With closures, if you are desperate to keep one entry point, you can
play around with thread-local values to pass in the data links:
static Object p = #localPutsProcBodyUsingTL;
static ThreadLocal reg42 = new JRubyRegister();
{ reg42.set(i); x.each(p); }
The problem here is you have to prove non-interference on your virtual
register and deal any spills and fills. Maybe you end up with a
try/finally to spill and refill the previous value. Also, this level
of "dirty" optimization steps on the toes of the JIT's optimizer,
which is also trying to map values into (lower-level) registers.
BTW, I wonder if instead of using invokevirtual when calling each
you use invokedynamic and produce a tree of guardWithtest.
In my own abstract hotspot mental model, the megamorphic callsite
should be inlineable (at least in this example).
Yes, I've wondered that as well. Having a tree of GWT should simulate
a PIC, and rebalancing the PIC would simply be reordering the GWTs. In
theory, if Hotspot treats each GWT as its own call site in the graph,
they should all inline. One of these days I'll get back to indyfying
JRuby...but maybe you can come up with a contrived example to try it
out.
That's a different problem, but in general managing your own dynamic
call site is a good idea *if* you know something language-specific
about the site that the JVM won't be able to figure out.
John, bindTo() doesn't work here, because i is not a receiver,
you should use convertArguments instead.
You can also create a local variable and bind it when you create a method
containing the code if the lambda can be proved constant.
function(p) {
Object r1 = x.each(p);
}
MH lambda = MHs.insertArguments(#localPutsProcBody, 0, 1234);
MH function = MHs.insertArguments(#function(MethodHandle), 0, lambda);
PHP.reboot does use that trick for variables declared 'const'.
-- John
Rémi
--
You received this message because you are subscribed to the Google Groups "JVM
Languages" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/jvm-languages?hl=en.