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 -~----------~----~----~----~------~----~------~--~---