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.

Reply via email to