Hi Peter, Thanks for looking at this. I like the idea, but I think you need to use LangReflectAccess, which almost isn’t in use today. I would like to think some more about how to best do it so I think this should be a potential follow up.
cheers /Joel On 10 jun 2014, at 08:14, Peter Levart <peter.lev...@gmail.com> wrote: > Hi Joel, > > I don't know if this is warranted, since this is on slow path (the resulting > methods are cached) and the number of overloaded methods is typically not > large, but the following MethodArray method: > > 2803 private boolean matchesNameAndDescriptor(Method m1, Method m2) { > > could use a JavaLangAccess bridge to access the Method's parameter types > without cloning the array each time. Especially since it's called many times > inside nested loop (see removeLessSpecifics()) where the number of > invocations grows quadratically with the MethodArray's length. > Method.getParameterTypes() is only invoked for pairs of overloaded methods, > so this might not be a real issue. > > Number of invocations could be halved though with this optimization of > removeLessSpecific(): > > void removeLessSpecifics() { > if (!hasDefaults()) > return; > > for (int i = 1; i < length; i++) { > Method m = get(i); > if (m == null) > continue; > > for (int j = 0; j < i; j++) { > Method n = get(j); > if (n == null || !(m.isDefault() || n.isDefault())) > continue; > > if (!matchesNameAndDescriptor(m, n)) > continue; > > if (hasMoreSpecificClass(m, n)) > remove(j); > else if (hasMoreSpecificClass(n, m)) > remove(i); > } > } > } > > > Regards, Peter > > > On 05/07/2014 07:43 PM, Joel Borggrén-Franck wrote: >> Hi, >> >> Since Java 8 the methods Class.getMethod() and Class.getMethods() can in >> some circumstances return methods that are not members of the class. This is >> due to a spec change in 8 not due to a code change. For this to happen you >> need to have an interface hierarchy that looks something like: >> >> interface I { void m(); } >> interface J extends I { void m(); } >> >> and either one of: >> >> interface K extends ***I,*** J {} >> class C implements ***I,*** J {} >> >> In Java 7 K.class.getMethods() would return [ I.m, J.m ]. The 7 spec is a >> bit vague but I have been convinced by experts that this is actually correct >> in 7. However this was changed in the spec for 8, now only J.m() is a member >> of K or C so the result should only contain [ J.m() ]. >> >> See the bug: >> https://bugs.openjdk.java.net/browse/JDK-8029674 >> for a more thorough discussion of this. >> >> The fix proposed for 8u (and 9 at first) is a partial fix that ensures that: >> >> - a concrete class does not have any abstract methods >> - nothing is changed unless someone introduces default methods into the >> interface hierarchy >> >> This is to minimise the behavioural compatibility concerns in a minor >> release. For 9 we might implement the full solution. (See the 9 bug: >> https://bugs.openjdk.java.net/browse/JDK-8029459 >> ). >> >> Basically in the fix proposed for 8u, default methods prune less specific >> methods from the result if they have the same discriptor. There are some >> complications due to preserving the old lookup order and the fact that we >> don’t want different results depending on the order of pairwise comparisons. >> Since this work and MethodArray in general is comparing descriptors bridges >> should not interact with this patch. >> >> Bug: >> https://bugs.openjdk.java.net/browse/JDK-8029674 >> >> Patch: >> http://cr.openjdk.java.net/~jfranck/8029674/webrev.02/ >> >> >> *** Testing *** >> >> I made a test with a bit over 100 cases where 40 of the tests test behaviour >> that shouldn’t change (IE they pass both with and without the patch). The >> test is a bit vast, but I have commented some of the more interesting >> results. >> >> *** Performance *** >> >> The time complexity of this is O(defaultMethods * methods). getMethods() is >> already somewhat quadratic in complexity due to removing interface methods >> that have a concrete implementation. Also the result is cached so this is a >> one time increase per Class. >> >> I have done some experiments on a patched jdk without the cache and the >> performance looks decent: >> >> - Loading every class in rt.jar and calling getMethods() on every Class >> takes 8s on my laptop both before and after the patch. Perhaps not that >> surprising since there aren’t that many default methods in the jdk and this >> is probably dominated by IO. >> >> - Calling getMethods on a Class with 16K methods, 10% which are default >> methods, seem to take roughly 50% longer on my laptop (2,4 instead of 1,7 >> seconds). I’m working on converting this benchmark to JMH, but at least I >> don’t think I have made the most basic benchmark errors. >> >> If this turns out to be a performance problem I have an idea for an index >> that will make this O(methods sharing name * methods) for an addition of a >> few allocations, but I don’t expect this to be necessary. >> >> Thanks in advance >> >> cheers >> /Joel >> >