Jochen Theodorou wrote:
> Charles Oliver Nutter schrieb:
>> I'd expect you can have a single argument return converter that converts 
>> the value on the way out. Being able to convert only incoming arguments 
>> and not outgoing values wouldn't be useful.
> 
> well, of course:
> 
>>    class Groovy2ArgConverter {
>>      MethodHandle arg1conv, arg2conv;  // called to convert the incoming 
>> arguments
>>      MethodHandle retconv;             // called to convert the return value
>>      MethodHandle target;              // called on the converted arguments
>>      Object invoke(Object a1, Object a2) { 
>>        return retconv.invoke(target.invoke(arg1conv.invoke(a1), 
>> arg2conv.invoke(a2))); 
>>      }
>>    }
> 
> my point wasn't so much, that it is not possible, it is more that when 
> target is invoked, the call to target is no tail call anymore now. That 
> means the stack frame can not be removed, even if we had tail calls. 
> retconv is in tail call position, but that won't get me much

You wouldn't do this; you'd provide those handles to some 
MethodHandles.adapt* variant and it would handle invoking each of them 
for you. My general assumption in all this is that once we've presented 
a set of handles to self-contained functions and told the JVM how to 
stitch them together, it can do what it pleases with the stack.

I don't think there's a reason that a Java stack frame ever *has to* be 
created unless the JVM actually needs it; and in this case it does not. 
Each of the pieces is free-standing, has no side effects, and does not 
directly intervene in the call stack. Now if you have dependencies on 
converting arguments being returned, that's a complication introduced by 
your implementation that's unavoidable; the return values from the 
actual call is no longer the last operation in the method. I don't doubt 
the JVM can reduce that cost, but it could never be a tail call because 
it's not a tail call. How common is this?

But back to the point; even if it's not a tail call, I don't expect 
you'd ever see anything but a chain of Groovy methods in the call stack, 
all the way up to the first non-Groovy target method. The handles would 
ideally be entirely invisible.

>> As does JRuby...but I think we are not formal about which method we 
>> select. The first best match, in reflection order, I guess.
> 
> we are formal, we use the most common version, for example if there is 
> foo(Object), then it gets it... we introduced a NullObject class, but 
> that can not be used for method parameters yet. In the long term we want 
> to change that, so that you can define foo(null) to catch the null 
> cases. Well, it has no priority atm

You mean the most general version? That's not a bad rule. Perhaps we 
could adopt the same. It's better than the reflection order we "let 
work" now.

>> You can put more than one signature in a given class and invoke through 
>> it that way.
> 
> well.. currently it reads as if the signature of invoke must match 
> exactly what MethodTypes says. Which is redundant, so maybe I 
> misunderstood it
> 
>> There's no reason to generate a class for every single 
>> permutation of arity and type. Heck, they could all be in one class with 
>> MethodHandles to reference them. I'm not sure where the class explosion 
>> you're talking about comes from.
> 
> depends... I can not call invoke(Object) with an int unless boxing is 
> done for me... but my goal is to not have any boxing if possible. And 
> even if I use only double, float, int, long and Object I have already 5 
> types that can be combined in argument types and return types. And 
> counting for positions I have over 500 possibilities00. 4 positions, 
> that are 4 arguments and void/Object, or 3 arguments and return type. Or 
> did I make a mistake?

Mathematically, probably not. But you would not generate all these 
signatures. The actual number of real signatures in a real application 
would be far, far fewer than all permutations of all known types. The 
practical maximum would be one for every method in the system, and 
that's if you loaded all of them, bound all their methods, and they all 
had different signatures. Let's call that the worst case scenario. So 
this is where using composable method handles makes a lot more sense 
than generating all your own signature into a static class or generating 
them at runtime. MethodHandles would provide a lightweight mechanism for 
efficiently referencing all those method signatures, and for composing 
adapters for them as needed. At the very least, the method handles for 
all those methods would be far smaller in memory than, for example, the 
bytecode that represents them; so this theoretical worst case would be 
gigantic already, with or without a handle per signature. Real systems 
won't be like that, and I doubt the method handle cost would be as high 
as you think.

>> Does Groovy still use reflection to invoke arbitrary Java methods?
> 
> partially. For some GDK methods no reflection will be used, because we 
> have pre-build stubs for them. For general methods... we still use 
> reflection, because of possible class loader issues if we generate 
> direct code.

JRuby uses direct calls for all core JRuby classes and any extensions 
written directly to JRuby, and for classes outside JRuby (Java classes) 
we use reflection. But I see a path to removing *all* of that binding 
logic, PLUS our call site logic, PLUS Java argument conversion logic, 
PLUS Ruby argument coersion, PLUS a bunch of pre/post method logic and 
stuffing it all into method handles. The picture in my head is pretty 
nice, and I'm trying to communicate it to John as best I can while he 
moves forward with things on his end. I think it's going well so far.

>> I guess I'm a little confused what it is in your call site that you feel 
>> you'd need to keep under invokedynamic. The prototype invokedynamic 
>> support already in JRuby bypasses our call site logic entirely, 
>> dispatching dynamically, bootstrapping, and so on. What is it about 
>> Groovy's call site you don't think invokedynamic/method handles can help 
>> with?
> 
> I am not so much thinking about our current call sites, I am thinking 
> about next year Groovy and trying to get the maximum potential out of 
> this. For example in the GSOC we got a JIT compiler for Groovy, which 
> does for example replace our call sites with almost direct method 
> invocations. So I want to compare call sites with that JIT, not with our 
> current call sites. Of course, since our method invocation is so slow 
> atm, we have many places that could get tweaked a little to give more 
> performance, but currently the method call performance makes such 
> actions not necessary. To get good number performance one thing is 
> essential: get rid of boxing. Even though we have introduced primitive 
> types in our bytecode, we still have the boxing problem. The power of 
> the JIT can be seen here:
...
> and that's the JIT version. This does in no way reflect arbitrary method 
> calls for 1.6, but the JIT version does. And while a groovy method call 
> can currently grow to being 30 times slower, a JIT version can be better 
> than factor 2. invokedynamic needs to be measured at this

JRuby can in general perform similarly, though there's overhead related 
to Ruby features that's more difficult to eliminate than in Groovy's 
case. I would expect that the JIT can work in concert with invokedynamic:

- First compiled output produces the most generate invokedynamic sites 
possible, which get bound to handles that inspect arg lists, do full 
lookup, and so on.
- Future refinements to the compiled output produce specialized 
invocations with guards, so that if the types match those seen 
previously you can pass more information on to the bootstrap.
- The dynamic binding passes through some adapted method handle in each 
case, but the resulting stack trace looks as though the call went 
directly from the call site to the target method. You would cut out all 
intervening logic.

So iterative specialization of the bytecode becomes a matter of 
generating a series of likely dynamic invocation method signatures 
(potentially one, if you've only seen one) to choose from that will each 
get bound to the appropriate target method.

Honestly, I believe invokedynamic as it's currently coming together is 
going to work extremely well for Groovy. Nothing I've heard so far makes 
me think otherwise.

- Charlie

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JVM 
Languages" group.
To post to this group, send email to jvm-languages@googlegroups.com
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