--- old/src/java.base/share/classes/java/lang/Class.java 2014-11-05 16:59:39.630969445 +0100 +++ new/src/java.base/share/classes/java/lang/Class.java 2014-11-05 16:59:39.539971126 +0100 @@ -45,7 +45,6 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashMap; @@ -411,7 +410,9 @@ } try { Class[] empty = {}; - final Constructor c = getConstructor0(empty, Member.DECLARED); + // must copy constructor since we are modifying it + final Constructor c = getReflectionFactory().copyConstructor( + getConstructor0(empty, Member.DECLARED)); // Disable accessibility checks on the constructor // since we have to do the security check here anyway // (the stack depth is wrong for the Constructor's @@ -842,6 +843,10 @@ * @return an array of interfaces implemented by this class. */ public Class[] getInterfaces() { + return getInterfaces(true); + } + + private Class[] getInterfaces(boolean cloneArray) { ReflectionData rd = reflectionData(); if (rd == null) { // no cloning required @@ -852,8 +857,8 @@ interfaces = getInterfaces0(); rd.interfaces = interfaces; } - // defensively copy before handing over to user code - return interfaces.clone(); + // defensively copy cached array before handing over to user code + return cloneArray ? interfaces.clone() : interfaces; } } @@ -1710,7 +1715,7 @@ if (field == null) { throw new NoSuchFieldException(name); } - return field; + return getReflectionFactory().copyField(field); } @@ -1793,7 +1798,7 @@ if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); } - return method; + return getReflectionFactory().copyMethod(method); } @@ -1830,7 +1835,8 @@ public Constructor getConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return getConstructor0(parameterTypes, Member.PUBLIC); + return getReflectionFactory().copyConstructor( + getConstructor0(parameterTypes, Member.PUBLIC)); } @@ -2077,7 +2083,7 @@ if (field == null) { throw new NoSuchFieldException(name); } - return field; + return getReflectionFactory().copyField(field); } @@ -2137,7 +2143,7 @@ if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); } - return method; + return getReflectionFactory().copyMethod(method); } @@ -2183,7 +2189,8 @@ public Constructor getDeclaredConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return getConstructor0(parameterTypes, Member.DECLARED); + return getReflectionFactory().copyConstructor( + getConstructor0(parameterTypes, Member.DECLARED)); } /** @@ -2623,7 +2630,7 @@ addAll(fields, tmp); // Direct superinterfaces, recursively - for (Class c : getInterfaces()) { + for (Class c : getInterfaces(false)) { if (!traversedInterfaces.contains(c)) { traversedInterfaces.add(c); addAll(fields, c.privateGetPublicFields(traversedInterfaces)); @@ -2717,179 +2724,7 @@ return res; } - static class MethodArray { - // Don't add or remove methods except by add() or remove() calls. - private Method[] methods; - private int length; - private int defaults; - - MethodArray() { - this(20); - } - - MethodArray(int initialSize) { - if (initialSize < 2) - throw new IllegalArgumentException("Size should be 2 or more"); - - methods = new Method[initialSize]; - length = 0; - defaults = 0; - } - - boolean hasDefaults() { - return defaults != 0; - } - - void add(Method m) { - if (length == methods.length) { - methods = Arrays.copyOf(methods, 2 * methods.length); - } - methods[length++] = m; - - if (m != null && m.isDefault()) - defaults++; - } - - void addAll(Method[] ma) { - for (Method m : ma) { - add(m); - } - } - - void addAll(MethodArray ma) { - for (int i = 0; i < ma.length(); i++) { - add(ma.get(i)); - } - } - - void addIfNotPresent(Method newMethod) { - for (int i = 0; i < length; i++) { - Method m = methods[i]; - if (m == newMethod || (m != null && m.equals(newMethod))) { - return; - } - } - add(newMethod); - } - - void addAllIfNotPresent(MethodArray newMethods) { - for (int i = 0; i < newMethods.length(); i++) { - Method m = newMethods.get(i); - if (m != null) { - addIfNotPresent(m); - } - } - } - - /* Add Methods declared in an interface to this MethodArray. - * Static methods declared in interfaces are not inherited. - */ - void addInterfaceMethods(Method[] methods) { - for (Method candidate : methods) { - if (!Modifier.isStatic(candidate.getModifiers())) { - add(candidate); - } - } - } - - int length() { - return length; - } - - Method get(int i) { - return methods[i]; - } - - Method getFirst() { - for (Method m : methods) - if (m != null) - return m; - return null; - } - - void removeByNameAndDescriptor(Method toRemove) { - for (int i = 0; i < length; i++) { - Method m = methods[i]; - if (m != null && matchesNameAndDescriptor(m, toRemove)) { - remove(i); - } - } - } - - private void remove(int i) { - if (methods[i] != null && methods[i].isDefault()) - defaults--; - methods[i] = null; - } - - private boolean matchesNameAndDescriptor(Method m1, Method m2) { - return m1.getReturnType() == m2.getReturnType() && - m1.getName() == m2.getName() && // name is guaranteed to be interned - arrayContentsEq(m1.getParameterTypes(), - m2.getParameterTypes()); - } - - void compactAndTrim() { - int newPos = 0; - // Get rid of null slots - for (int pos = 0; pos < length; pos++) { - Method m = methods[pos]; - if (m != null) { - if (pos != newPos) { - methods[newPos] = m; - } - newPos++; - } - } - if (newPos != methods.length) { - methods = Arrays.copyOf(methods, newPos); - } - } - - /* Removes all Methods from this MethodArray that have a more specific - * default Method in this MethodArray. - * - * Users of MethodArray are responsible for pruning Methods that have - * a more specific concrete Method. - */ - void removeLessSpecifics() { - if (!hasDefaults()) - return; - - for (int i = 0; i < length; i++) { - Method m = get(i); - if (m == null || !m.isDefault()) - continue; - - for (int j = 0; j < length; j++) { - if (i == j) - continue; - - Method candidate = get(j); - if (candidate == null) - continue; - - if (!matchesNameAndDescriptor(m, candidate)) - continue; - - if (hasMoreSpecificClass(m, candidate)) - remove(j); - } - } - } - - Method[] getArray() { - return methods; - } - - // Returns true if m1 is more specific than m2 - static boolean hasMoreSpecificClass(Method m1, Method m2) { - Class m1Class = m1.getDeclaringClass(); - Class m2Class = m2.getDeclaringClass(); - return m1Class != m2Class && m2Class.isAssignableFrom(m1Class); - } - } - + private static final Method[] EMPTY_METHODS = new Method[0]; // Returns an array of "root" methods. These Method objects must NOT // be propagated to the outside world, but must instead be copied @@ -2903,52 +2738,59 @@ if (res != null) return res; } - // No cached value available; compute value recursively. - // Start by fetching public declared methods - MethodArray methods = new MethodArray(); - { - Method[] tmp = privateGetDeclaredMethods(true); - methods.addAll(tmp); - } - // Now recur over superclass and direct superinterfaces. - // Go over superinterfaces first so we can more easily filter - // out concrete implementations inherited from superclasses at - // the end. - MethodArray inheritedMethods = new MethodArray(); - for (Class i : getInterfaces()) { - inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods()); - } - if (!isInterface()) { - Class c = getSuperclass(); - if (c != null) { - MethodArray supers = new MethodArray(); - supers.addAll(c.privateGetPublicMethods()); - // Filter out concrete implementations of any - // interface methods - for (int i = 0; i < supers.length(); i++) { - Method m = supers.get(i); - if (m != null && - !Modifier.isAbstract(m.getModifiers()) && - !m.isDefault()) { - inheritedMethods.removeByNameAndDescriptor(m); + Method[] declaredMethods = privateGetDeclaredMethods(true); + Class superclass = getSuperclass(); + Class[] interfaces = getInterfaces(false); + + // optimization: + // if we don't have a superclass (either we are j.l.Object or an interface) + // and don't have (super)interfaces either, then public methods consist + // of declared public methods + if (superclass == null && interfaces.length == 0) { + res = declaredMethods; + } else { + // we have to do some logic + Method[] superclassMethods = (superclass == null) + ? EMPTY_METHODS + : superclass.privateGetPublicMethods(); + Method[][] interfacesMethods = new Method[interfaces.length][]; + int interfacesMethodsCount = 0; + for (int i = 0; i < interfaces.length; i++) { + interfacesMethods[i] = interfaces[i].privateGetPublicMethods(); + interfacesMethodsCount += interfacesMethods[i].length; + } + + // ensure enough working capacity + // (MethodTable implementation may not support dynamic resizing) + MethodTable methodTable = MethodTable.newInstance( + declaredMethods.length + + superclassMethods.length + + interfacesMethodsCount + ); + + // declared methods first + for (Method m : declaredMethods) { + methodTable.add(m); + } + + // inherited methods from superclass + for (Method m : superclassMethods) { + methodTable.addUnlessDeclaredExists(m, this); + } + + // inherited methods from (super)interfaces + for (Method[] ms : interfacesMethods) { + for (Method m : ms) { + // interface static methods are not inherited + if (!Modifier.isStatic(m.getModifiers())) { + methodTable.consolidate(m, this); } } - // Insert superclass's inherited methods before - // superinterfaces' to satisfy getMethod's search - // order - supers.addAll(inheritedMethods); - inheritedMethods = supers; - } - } - // Filter out all local methods from inherited ones - for (int i = 0; i < methods.length(); i++) { - Method m = methods.get(i); - inheritedMethods.removeByNameAndDescriptor(m); - } - methods.addAllIfNotPresent(inheritedMethods); - methods.removeLessSpecifics(); - methods.compactAndTrim(); - res = methods.getArray(); + } + + res = methodTable.getMethods(); + } + if (rd != null) { rd.publicMethods = res; } @@ -2960,16 +2802,25 @@ // Helpers for fetchers of one field, method, or constructor // + /** + * This method does not copy returned 'root' Field object. It MUST be copied + * with ReflectionFactory before handed to any code outside java.lang.Class + * or modified. + */ private static Field searchFields(Field[] fields, String name) { String internedName = name.intern(); for (Field field : fields) { if (field.getName() == internedName) { - return getReflectionFactory().copyField(field); + return field; } } return null; } + /** + * This method returns 'root' Field object. It MUST be copied with ReflectionFactory + * before handed to any code outside java.lang.Class or modified. + */ private Field getField0(String name) throws NoSuchFieldException { // Note: the intent is that the search algorithm this routine // uses be equivalent to the ordering imposed by @@ -2984,7 +2835,7 @@ return res; } // Direct superinterfaces, recursively - Class[] interfaces = getInterfaces(); + Class[] interfaces = getInterfaces(false); for (Class c : interfaces) { if ((res = c.getField0(name)) != null) { return res; @@ -3002,6 +2853,11 @@ return null; } + /** + * This method does not copy returned 'root' Method object. It MUST be copied + * with ReflectionFactory before handed to any code outside java.lang.Class + * or modified. + */ private static Method searchMethods(Method[] methods, String name, Class[] parameterTypes) @@ -3016,24 +2872,14 @@ res = m; } - return (res == null ? res : getReflectionFactory().copyMethod(res)); + return res; } + /** + * This method returns 'root' Method object. It MUST be copied with ReflectionFactory + * before handed to any code outside java.lang.Class or modified. + */ private Method getMethod0(String name, Class[] parameterTypes, boolean includeStaticMethods) { - MethodArray interfaceCandidates = new MethodArray(2); - Method res = privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates); - if (res != null) - return res; - - // Not found on class or superclass directly - interfaceCandidates.removeLessSpecifics(); - return interfaceCandidates.getFirst(); // may be null - } - - private Method privateGetMethodRecursive(String name, - Class[] parameterTypes, - boolean includeStaticMethods, - MethodArray allInterfaceCandidates) { // Note: the intent is that the search algorithm this routine // uses be equivalent to the ordering imposed by // privateGetPublicMethods(). It fetches only the declared @@ -3041,40 +2887,45 @@ // number of Method objects which have to be created for the // common case where the method being requested is declared in // the class which is being queried. - // - // Due to default methods, unless a method is found on a superclass, - // methods declared in any superinterface needs to be considered. - // Collect all candidates declared in superinterfaces in {@code - // allInterfaceCandidates} and select the most specific if no match on - // a superclass is found. - - // Must _not_ return root methods Method res; - // Search declared public methods + // 1st search declared public methods if ((res = searchMethods(privateGetDeclaredMethods(true), name, - parameterTypes)) != null) { - if (includeStaticMethods || !Modifier.isStatic(res.getModifiers())) - return res; + parameterTypes)) != null && + (includeStaticMethods || + !Modifier.isStatic(res.getModifiers()))) { + return res; } - // Search superclass's methods - if (!isInterface()) { - Class c = getSuperclass(); - if (c != null) { - if ((res = c.getMethod0(name, parameterTypes, true)) != null) { - return res; - } + + // 2nd we try the superclass. + Class superclass = getSuperclass(); + if (superclass != null && + (res = superclass.getMethod0(name, parameterTypes, includeStaticMethods)) != null) { + return res; + } + + // last we check (super) interfaces + Class[] interfaces = getInterfaces(false); + if (interfaces.length == 0) { + return null; + } + // have to construct a MethodTable to consolidate + // public methods from (super)interfaces + MethodTable methodTable = MethodTable.newInstance(interfaces.length); + for (Class c : interfaces) { + if ((res = c.getMethod0(name, parameterTypes, false)) != null) { + methodTable.consolidate(res, this); } } - // Search superinterfaces' methods - Class[] interfaces = getInterfaces(); - for (Class c : interfaces) - if ((res = c.getMethod0(name, parameterTypes, false)) != null) - allInterfaceCandidates.add(res); - // Not found - return null; + + // return the first method with the most specific return type + return methodTable.getFirstMethodWithMostSpecificReturnType(); } + /** + * This method returns 'root' Constructor object. It MUST be copied with ReflectionFactory + * before handed to any code outside java.lang.Class or modified. + */ private Constructor getConstructor0(Class[] parameterTypes, int which) throws NoSuchMethodException { @@ -3082,7 +2933,7 @@ for (Constructor constructor : constructors) { if (arrayContentsEq(parameterTypes, constructor.getParameterTypes())) { - return getReflectionFactory().copyConstructor(constructor); + return constructor; } } throw new NoSuchMethodException(getName() + "." + argumentTypesToString(parameterTypes));