From af415514a2be02dfe8b0ed9130a24469c867c8d0 Mon Sep 17 00:00:00 2001 From: Jochen Theodorou Date: Fri, 22 Dec 2023 01:31:13 +0100 Subject: [PATCH] replacing the custom hashmap implementation in MetaMethodIndex with normal hashmaps --- src/main/java/groovy/lang/MetaClassImpl.java | 131 +++--- src/main/java/groovy/lang/MetaMethod.java | 2 + .../groovy/reflection/ParameterTypes.java | 4 + .../runtime/metaclass/ClosureMetaClass.java | 12 +- .../runtime/metaclass/MetaMethodIndex.java | 385 ++++-------------- .../methoddispatching/vm8/FooThree.java | 2 +- .../runtime/methoddispatching/vm8/FooTwo.java | 2 +- 7 files changed, 152 insertions(+), 386 deletions(-) diff --git a/src/main/java/groovy/lang/MetaClassImpl.java b/src/main/java/groovy/lang/MetaClassImpl.java index c253e2b5f0b..690cc8d8ed0 100644 --- a/src/main/java/groovy/lang/MetaClassImpl.java +++ b/src/main/java/groovy/lang/MetaClassImpl.java @@ -18,6 +18,36 @@ */ package groovy.lang; +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.Introspector; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; import org.apache.groovy.internal.util.UncheckedThrow; import org.apache.groovy.util.BeanUtils; import org.apache.groovy.util.SystemUtil; @@ -82,37 +112,6 @@ import org.codehaus.groovy.vmplugin.VMPluginFactory; import org.objectweb.asm.Opcodes; -import java.beans.BeanInfo; -import java.beans.EventSetDescriptor; -import java.beans.Introspector; -import java.beans.MethodDescriptor; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.net.URL; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.BiConsumer; - import static groovy.lang.Tuple.tuple; import static java.lang.Character.isUpperCase; import static org.apache.groovy.util.Arrays.concat; @@ -177,7 +176,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass { private MetaMethod propertyMissingGet; private MetaMethod propertyMissingSet; private MetaMethod methodMissing; - private MetaMethodIndex.Header mainClassMethodHeader; + private Map mainClassMethodHeader; private boolean permissivePropertyAccess = PERMISSIVE_PROPERTY_ACCESS; /** @@ -372,7 +371,7 @@ private void fillMethodIndex() { } private void populateMethods(final List superClasses, final CachedClass firstGroovySuper) { - MetaMethodIndex.Header header = metaMethodIndex.getHeader(firstGroovySuper.getTheClass()); + var header = metaMethodIndex.getHeader(firstGroovySuper.getTheClass()); CachedClass c; Iterator iter = superClasses.iterator(); while (iter.hasNext()) { @@ -396,7 +395,7 @@ private void populateMethods(final List superClasses, final CachedC break; } - MetaMethodIndex.Header last = header; + var last = header; while (iter.hasNext()) { c = iter.next(); header = metaMethodIndex.getHeader(c.getTheClass()); @@ -452,7 +451,7 @@ public boolean skipClass(final Class clazz) { } @Override - public void methodNameAction(final Class clazz, final MetaMethodIndex.Entry e) { + public void methodNameAction(final Class clazz, final MetaMethodIndex.Cache e) { if (e.methods == null) return; @@ -499,7 +498,7 @@ class MOPIter extends MethodIndexAction { boolean useThis; @Override - public void methodNameAction(final Class c, final MetaMethodIndex.Entry e) { + public void methodNameAction(final Class c, final MetaMethodIndex.Cache e) { Object arrayOrMethod = (useThis ? e.methods : e.methodsForSuper); if (arrayOrMethod instanceof FastArray) { FastArray methods = (FastArray) arrayOrMethod; @@ -618,11 +617,11 @@ private void inheritInterfaceNewMetaMethods(final Set interfaces) { } private void connectMultimethods(final List superClasses, final CachedClass firstGroovyClass) { - MetaMethodIndex.Header last = null; + Map last = null; for (ListIterator iter = superClasses.listIterator(superClasses.size()); iter.hasPrevious(); ) { CachedClass c = iter.previous(); - MetaMethodIndex.Header methodIndex = metaMethodIndex.getHeader(c.getTheClass()); + var methodIndex = metaMethodIndex.getHeader(c.getTheClass()); // We don't copy DGM methods to superclasses' indexes // The reason we can do that is particular set of DGM methods in use, // if at some point we will define DGM method for some Groovy class or @@ -673,7 +672,7 @@ private CachedClass calcFirstGroovySuperClass(final List superClass private Object getMethods(final Class sender, final String name, final boolean isCallToSuper) { Object answer; - final MetaMethodIndex.Entry entry = metaMethodIndex.getMethods(sender, name); + final MetaMethodIndex.Cache entry = metaMethodIndex.getMethods(sender, name); if (entry == null) { answer = FastArray.EMPTY_LIST; } else if (isCallToSuper) { @@ -711,7 +710,7 @@ private Object getMethods(final Class sender, final String name, final boolea * @return static methods available from this class for given name */ private Object getStaticMethods(final Class sender, final String name) { - final MetaMethodIndex.Entry entry = metaMethodIndex.getMethods(sender, name); + final MetaMethodIndex.Cache entry = metaMethodIndex.getMethods(sender, name); if (entry == null) return FastArray.EMPTY_LIST; Object answer = entry.staticMethods; @@ -743,7 +742,7 @@ public void addNewInstanceMethod(final Method method) { addNewInstanceMethodToIndex(newMethod, metaMethodIndex.getHeader(newMethod.getDeclaringClass().getTheClass())); } - private void addNewInstanceMethodToIndex(final MetaMethod newMethod, final MetaMethodIndex.Header header) { + private void addNewInstanceMethodToIndex(final MetaMethod newMethod, final Map header) { if (!newGroovyMethodsSet.contains(newMethod)) { newGroovyMethodsSet.add(newMethod); addMetaMethodToIndex(newMethod, header); @@ -762,7 +761,7 @@ public void addNewStaticMethod(final Method method) { addNewStaticMethodToIndex(newMethod, metaMethodIndex.getHeader(newMethod.getDeclaringClass().getTheClass())); } - private void addNewStaticMethodToIndex(final MetaMethod newMethod, final MetaMethodIndex.Header header) { + private void addNewStaticMethodToIndex(final MetaMethod newMethod, final Map header) { if (!newGroovyMethodsSet.contains(newMethod)) { newGroovyMethodsSet.add(newMethod); addMetaMethodToIndex(newMethod, header); @@ -1362,25 +1361,25 @@ private MetaMethod getMethodWithCachingInternal(final Class sender, final CallSi if (GroovyCategorySupport.hasCategoryInCurrentThread()) return getMethodWithoutCaching(sender, site.getName(), params, false); - MetaMethodIndex.Entry e = metaMethodIndex.getMethods(sender, site.getName()); + MetaMethodIndex.Cache e = metaMethodIndex.getMethods(sender, site.getName()); if (e == null || e.methods == null) return null; - MetaMethodIndex.CacheEntry cacheEntry = e.cachedMethod; + MetaMethodIndex.MetaMethodCache cacheEntry = e.cachedMethod; if (cacheEntry != null && (sameClasses(cacheEntry.params, params))) { return cacheEntry.method; } - cacheEntry = e.cachedMethod = new MetaMethodIndex.CacheEntry(params, (MetaMethod) chooseMethod(e.name, e.methods, params)); + cacheEntry = e.cachedMethod = new MetaMethodIndex.MetaMethodCache(params, (MetaMethod) chooseMethod(e.name, e.methods, params)); return cacheEntry.method; } - private MetaMethod getSuperMethodWithCaching(final Object[] arguments, final MetaMethodIndex.Entry e) { + private MetaMethod getSuperMethodWithCaching(final Object[] arguments, final MetaMethodIndex.Cache e) { if (e.methodsForSuper == null) return null; - MetaMethodIndex.CacheEntry cacheEntry = e.cachedMethodForSuper; + MetaMethodIndex.MetaMethodCache cacheEntry = e.cachedMethodForSuper; if (cacheEntry != null && cacheEntry.method != null && MetaClassHelper.sameClasses(cacheEntry.params, arguments, e.methodsForSuper instanceof MetaMethod)) { @@ -1389,16 +1388,16 @@ private MetaMethod getSuperMethodWithCaching(final Object[] arguments, final Met Class[] types = MetaClassHelper.convertToTypeArray(arguments); MetaMethod method = (MetaMethod) chooseMethod(e.name, e.methodsForSuper, types); - cacheEntry = e.cachedMethodForSuper = new MetaMethodIndex.CacheEntry(types, method.isAbstract() ? null : method); + cacheEntry = e.cachedMethodForSuper = new MetaMethodIndex.MetaMethodCache(types, method.isAbstract() ? null : method); return cacheEntry.method; } - private MetaMethod getNormalMethodWithCaching(final Object[] arguments, final MetaMethodIndex.Entry e) { + private MetaMethod getNormalMethodWithCaching(final Object[] arguments, final MetaMethodIndex.Cache e) { if (e.methods == null) return null; - MetaMethodIndex.CacheEntry cacheEntry = e.cachedMethod; + MetaMethodIndex.MetaMethodCache cacheEntry = e.cachedMethod; if (cacheEntry != null && cacheEntry.method != null && MetaClassHelper.sameClasses(cacheEntry.params, arguments, e.methods instanceof MetaMethod)) { @@ -1407,7 +1406,7 @@ private MetaMethod getNormalMethodWithCaching(final Object[] arguments, final Me Class[] types = MetaClassHelper.convertToTypeArray(arguments); MetaMethod method = (MetaMethod) chooseMethod(e.name, e.methods, types); - cacheEntry = e.cachedMethod = new MetaMethodIndex.CacheEntry(types, method); + cacheEntry = e.cachedMethod = new MetaMethodIndex.MetaMethodCache(types, method); return cacheEntry.method; } @@ -1421,8 +1420,8 @@ public Constructor retrieveConstructor(Class[] arguments) { } public MetaMethod retrieveStaticMethod(String methodName, Object[] arguments) { - final MetaMethodIndex.Entry e = metaMethodIndex.getMethods(theClass, methodName); - MetaMethodIndex.CacheEntry cacheEntry; + final MetaMethodIndex.Cache e = metaMethodIndex.getMethods(theClass, methodName); + MetaMethodIndex.MetaMethodCache cacheEntry; if (e != null) { cacheEntry = e.cachedStaticMethod; @@ -1432,7 +1431,7 @@ public MetaMethod retrieveStaticMethod(String methodName, Object[] arguments) { } final Class[] classes = MetaClassHelper.convertToTypeArray(arguments); - cacheEntry = new MetaMethodIndex.CacheEntry(classes, pickStaticMethod(methodName, classes)); + cacheEntry = new MetaMethodIndex.MetaMethodCache(classes, pickStaticMethod(methodName, classes)); e.cachedStaticMethod = cacheEntry; @@ -2485,8 +2484,8 @@ private void applyStrayPropertyMethods(Iterable classes, Map target, boolean isThis) { - MetaMethodIndex.Header header = metaMethodIndex.getHeader(source.getTheClass()); - for (MetaMethodIndex.Entry e = header.head; e != null; e = e.nextClassEntry) { + var header = metaMethodIndex.getHeader(source.getTheClass()); + for (MetaMethodIndex.Cache e : header.values()) { String methodName = e.name; int methodNameLength = methodName.length(); boolean isBooleanGetter = methodName.startsWith("is"); @@ -3026,15 +3025,9 @@ public void addMetaMethod(MetaMethod method) { addMetaMethodToIndex(method, metaMethodIndex.getHeader(declaringClass.getTheClass())); } - protected void addMetaMethodToIndex(MetaMethod method, MetaMethodIndex.Header header) { + protected void addMetaMethodToIndex(MetaMethod method, Map cacheIndex) { checkIfStdMethod(method); - - String name = method.getName(); - MetaMethodIndex.Entry e = metaMethodIndex.getOrPutMethods(name, header); - if (method.isStatic()) { - e.staticMethods = metaMethodIndex.addMethodToList(e.staticMethods, method); - } - e.methods = metaMethodIndex.addMethodToList(e.methods, method); + metaMethodIndex.addMetaMethod(method, cacheIndex); } /** @@ -3751,17 +3744,17 @@ protected Object getSubclassMetaMethods(String methodName) { private abstract class MethodIndexAction { public void iterate() { - for (Map.Entry classEntry : metaMethodIndex.methodHeaders.entrySet()) { - Class clazz = classEntry.getKey(); + for (Map.Entry, Map> classEntry : metaMethodIndex.indexMap.entrySet()) { + Class clazz = classEntry.getKey(); if (skipClass(clazz)) continue; - MetaMethodIndex.Header header = classEntry.getValue(); - for (MetaMethodIndex.Entry nameEntry = header.head; nameEntry != null; nameEntry = nameEntry.nextClassEntry) { + var header = classEntry.getValue(); + for (MetaMethodIndex.Cache nameEntry : header.values()) { methodNameAction(clazz, nameEntry); } } } - public abstract void methodNameAction(Class clazz, MetaMethodIndex.Entry methods); + public abstract void methodNameAction(Class clazz, MetaMethodIndex.Cache methods); public boolean skipClass(final Class clazz) { return false; diff --git a/src/main/java/groovy/lang/MetaMethod.java b/src/main/java/groovy/lang/MetaMethod.java index 34612b917d7..e8d8cb6849a 100644 --- a/src/main/java/groovy/lang/MetaMethod.java +++ b/src/main/java/groovy/lang/MetaMethod.java @@ -84,7 +84,9 @@ public MetaMethod(Class [] pt) { * * @param arguments the arguments to check * @throws IllegalArgumentException if the parameters are not valid + * @deprecated */ + @Deprecated public void checkParameters(Class[] arguments) { // let's check that the argument types are valid if (!isValidMethod(arguments)) { diff --git a/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java index bff88f441ee..99d3ee5080d 100644 --- a/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java +++ b/src/main/java/org/codehaus/groovy/reflection/ParameterTypes.java @@ -39,6 +39,10 @@ public ParameterTypes(Class[] pt) { nativeParamTypes = pt; } + /** + * @deprecated + */ + @Deprecated public ParameterTypes(String[] pt) { nativeParamTypes = new Class[pt.length]; for (int i = 0; i != pt.length; ++i) { diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java index 2ccaabfa20a..04585f83c69 100644 --- a/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java +++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java @@ -398,14 +398,12 @@ private synchronized void initAttributes() { public synchronized void initialize() { if (!isInitialized()) { CachedMethod[] methodArray = theCachedClass.getMethods(); - synchronized (theCachedClass) { - for (final CachedMethod cachedMethod : methodArray) { - if (!cachedMethod.getName().equals(CLOSURE_DO_CALL_METHOD)) continue; - closureMethods.add(cachedMethod); - } + for (final CachedMethod cachedMethod : methodArray) { + if (!cachedMethod.getName().equals(CLOSURE_DO_CALL_METHOD)) continue; + closureMethods.add(cachedMethod); } assignMethodChooser(); - setInitialized(true); + super.reinitialize(); } } @@ -664,7 +662,7 @@ public List respondsTo(final Object obj, final String name) { } private synchronized void loadMetaInfo() { - if (metaMethodIndex.isEmpty()) { + if (!isInitialized()) { reinitialize(); } } diff --git a/src/main/java/org/codehaus/groovy/runtime/metaclass/MetaMethodIndex.java b/src/main/java/org/codehaus/groovy/runtime/metaclass/MetaMethodIndex.java index 85a33be59f0..25f26f680ce 100644 --- a/src/main/java/org/codehaus/groovy/runtime/metaclass/MetaMethodIndex.java +++ b/src/main/java/org/codehaus/groovy/runtime/metaclass/MetaMethodIndex.java @@ -19,250 +19,105 @@ package org.codehaus.groovy.runtime.metaclass; import groovy.lang.MetaMethod; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; import org.codehaus.groovy.reflection.CachedClass; import org.codehaus.groovy.reflection.GeneratedMetaMethod; import org.codehaus.groovy.util.FastArray; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; - public class MetaMethodIndex { - public final Map methodHeaders = new LinkedHashMap<>(32); - - public static class Header { - public Entry head; - Class cls; - public Class subclass; - public int clsHashCode31; - - public Header(final Class cls) { - this(cls, null); - } - - public Header(final Class cls, final Class subclass) { - this.cls = cls; - this.subclass = subclass; - this.clsHashCode31 = 31 * cls.hashCode(); - } - } + private static final int DEFAULT_CAPACITY = 32; + /** + * a map of the starter class plus its super classes to save method lists for + * static/normal/super method calls. It also provides a simple cache of one + * method name and call signature to method per static/normal/super call. + */ + public final Map, Map> indexMap = new ConcurrentHashMap<>(DEFAULT_CAPACITY); + public final Class mainClass; - public static class CacheEntry { - public final Class[] params; + public static class MetaMethodCache { + public final Class[] params; public final MetaMethod method; - public CacheEntry(final Class[] params, final MetaMethod method) { + /** + * create a new method entry + * @param params in case of caching params might not be the same as {@link MetaMethod#getParameterTypes} + * @param method the meta method + */ + public MetaMethodCache(final Class[] params, final MetaMethod method) { this.params = params; this.method = method; } } - public static class Entry { - public int hash; - public Class cls; - public String name; - public Entry nextHashEntry, nextClassEntry; - public Object methods, methodsForSuper, staticMethods; - public CacheEntry cachedMethod, cachedMethodForSuper, cachedStaticMethod; + public static class Cache { + public final String name; + public Object methods; + public Object methodsForSuper; + public Object staticMethods; + public MetaMethodCache cachedMethod; + public MetaMethodCache cachedMethodForSuper; + public MetaMethodCache cachedStaticMethod; + + public Cache(String name) { + this.name = name; + } @Override public String toString() { - return "[" + name + ", " + cls.getName() + "]"; + return "[name=" + name + "]"; } } - public interface EntryIterator { - boolean hasNext(); - Entry next(); - } //-------------------------------------------------------------------------- public MetaMethodIndex(final CachedClass theCachedClass) { - init(DEFAULT_CAPACITY); - - CachedClass last = null; + this.mainClass = theCachedClass.getTheClass(); if (!theCachedClass.isInterface()) { for (CachedClass c = theCachedClass; c != null; c = c.getCachedSuperClass()) { - methodHeaders.put(c.getTheClass(), new Header(c.getTheClass(), last == null ? null : last.getTheClass())); - last = c; + indexMap.put(c.getTheClass(), new ConcurrentHashMap<>()); } } else { - methodHeaders.put(Object.class, new Header(Object.class, theCachedClass.getTheClass())); - } - } - - protected Entry[] table; - - protected static final int DEFAULT_CAPACITY = 32; - protected static final int MINIMUM_CAPACITY = 4; - protected static final int MAXIMUM_CAPACITY = 1 << 28; - - protected int size; - protected transient int threshold; - - public static int hash(int h) { - h += ~(h << 9); - h ^= (h >>> 14); - h += (h << 4); - h ^= (h >>> 10); - return h; - } - - public int size() { - return size; - } - - public boolean isEmpty() { - return size == 0; - } - - public void clear() { - Object[] tab = table; - Arrays.fill(tab, null); - size = 0; - } - - public void init(final int initCapacity) { - threshold = (initCapacity * 6) / 8; - table = new Entry[initCapacity]; - } - - public void resize(final int newLength) { - Entry[] oldTable = table; - Entry[] newTable = new Entry[newLength]; - - for (Entry entry : oldTable) { - for (Entry e = entry, next; e != null; e = next) { - next = e.nextHashEntry; - - int index = e.hash & (newLength - 1); - e.nextHashEntry = newTable[index]; - newTable[index] = e; - } + indexMap.put(Object.class, new ConcurrentHashMap<>()); + indexMap.put(mainClass, new ConcurrentHashMap<>()); } - - table = newTable; - threshold = (6 * newLength) / 8; - } - - public Entry[] getTable() { - return table; } - public EntryIterator getEntrySetIterator() { - return new EntryIterator() { - Entry next; // next entry to return - int index; // current slot - - { - Entry[] t = table; - int i = t.length; - Entry n = null; - if (size != 0) { // advance to first entry - while (i > 0 && (n = t[--i]) == null) { - } - } - next = n; - index = i; - } - - @Override - public boolean hasNext() { - return next != null; - } - - @Override - public Entry next() { - return nextEntry(); - } - - Entry nextEntry() { - Entry e = next; - if (e == null) - throw new NoSuchElementException(); - - Entry n = e.nextHashEntry; - Entry[] t = table; - int i = index; - while (n == null && i > 0) - n = t[--i]; - index = i; - next = n; - return e; - } - }; + public final Cache getMethods(final Class cls, final String name) { + var map = indexMap.get(cls); + return map == null ? null : map.get(name); } - public final Entry getMethods(final Class cls, final String name) { - int h = hash(31 * cls.hashCode() + name.hashCode()); - for (Entry e = table[h & (table.length - 1)]; e != null; e = e.nextHashEntry) { - if (e.hash == h && cls == e.cls && Objects.equals(e.name, name)) { - return e; - } - } - return null; - } + public void addMetaMethod(MetaMethod method, Map map) { + var cache = map.computeIfAbsent(method.getName(), Cache::new); - public Entry getOrPutMethods(final String name, final Header header) { - final Class cls = header.cls; - int h = hash(header.clsHashCode31 + name.hashCode()); - final Entry[] t = table; - final int index = h & (t.length - 1); - for (Entry e = t[index]; e != null; e = e.nextHashEntry) { - if (e.hash == h && cls == e.cls && Objects.equals(e.name, name)) { - return e; - } + if (method.isStatic()) { + cache.staticMethods = addMethodToList(cache.staticMethods, method); } - Entry entry = new Entry(); - entry.nextHashEntry = t[index]; - entry.hash = h; - entry.name = name; - entry.cls = cls; - t[index] = entry; - - entry.nextClassEntry = header.head; - header.head = entry; - - if (++size == threshold) - resize(2 * t.length); - - return entry; + cache.methods = addMethodToList(cache.methods, method); } - public Header getHeader(final Class cls) { - return methodHeaders.computeIfAbsent(cls, k -> new Header(cls)); + private Cache getOrPutMethods(final String name, final Map cacheIndex) { + return cacheIndex.computeIfAbsent(name, Cache::new); } - public void copyNonPrivateMethods(final Class from, final Class to) { - copyNonPrivateMethods(getHeader(from), getHeader(to)); + public Map getHeader(final Class cls) { + return indexMap.get(cls); } - public void copyNonPrivateMethods(final Header from, final Header to) { - for (Entry e = from.head; e != null; e = e.nextClassEntry) { + public void copyNonPrivateMethods(final Map from, final Map to) { + for (Cache e : from.values()) { copyNonPrivateMethods(e, to); } } - public void copyAllMethodsToSuper(final Header from, final Header to) { - for (Entry e = from.head; e != null; e = e.nextClassEntry) { - copyAllMethodsToSuper(e, to); - } - } - - public void copyNonPrivateMethodsFromSuper(final Header from) { - for (Entry e = from.head; e != null; e = e.nextClassEntry) { - copyNonPrivateMethodsFromSuper(e); - } - } - - private void copyNonPrivateMethods(final Entry from, final Header to) { + private void copyNonPrivateMethods(final Cache from, final Map to) { Object oldListOrMethod = from.methods; if (oldListOrMethod instanceof FastArray) { FastArray oldList = (FastArray) oldListOrMethod; - Entry e = null; + Cache e = null; final int n = oldList.size(); Object[] array = oldList.getArray(); for (int i = 0; i != n; i += 1) { @@ -275,66 +130,18 @@ private void copyNonPrivateMethods(final Entry from, final Header to) { } else { MetaMethod method = (MetaMethod) oldListOrMethod; if (!method.isPrivate()) { - Entry e = getOrPutMethods(from.name, to); - e.methods = addMethodToList(e.methods, method); - } - } - } - - private void copyAllMethodsToSuper(final Entry from, final Header to) { - Object oldListOrMethod = from.methods; - if (oldListOrMethod instanceof FastArray) { - FastArray oldList = (FastArray) oldListOrMethod; - Entry e = null; - final int n = oldList.size(); - Object[] array = oldList.getArray(); - for (int i = 0; i != n; i += 1) { - MetaMethod method = (MetaMethod) array[i]; - if (e == null) - e = getOrPutMethods(from.name, to); - e.methodsForSuper = addMethodToList(e.methodsForSuper, method); - } - } else { - MetaMethod method = (MetaMethod) oldListOrMethod; - Entry e = getOrPutMethods(from.name, to); - e.methodsForSuper = addMethodToList(e.methodsForSuper, method); - } - } - - private void copyNonPrivateMethodsFromSuper(final Entry e) { - Object oldListOrMethod = e.methodsForSuper; - if (oldListOrMethod == null) { - return; - } - - if (oldListOrMethod instanceof FastArray) { - FastArray oldList = (FastArray) oldListOrMethod; - final int n = oldList.size(); - Object[] array = oldList.getArray(); - for (int i = 0; i != n; i += 1) { - MetaMethod method = (MetaMethod) array[i]; - if (method.isPrivate()) continue; - e.methods = addMethodToList(e.methods, method); - } - } else { - MetaMethod method = (MetaMethod) oldListOrMethod; - if (!method.isPrivate()) { + Cache e = getOrPutMethods(from.name, to); e.methods = addMethodToList(e.methods, method); } } } - - public void copyNonPrivateMethodsDown(final Class from, final Class to) { - copyNonPrivateNonNewMetaMethods(getHeader(from), getHeader(to)); - } - - public void copyNonPrivateNonNewMetaMethods(final Header from, final Header to) { - for (Entry e = from.head; e != null; e = e.nextClassEntry) { + public void copyNonPrivateNonNewMetaMethods(final Map from, final Map to) { + for (Cache e : from.values()) { copyNonPrivateNonNewMetaMethods(e, to); } } - private void copyNonPrivateNonNewMetaMethods(final Entry from, final Header to) { + private void copyNonPrivateNonNewMetaMethods(final Cache from, final Map to) { Object oldListOrMethod = from.methods; if (oldListOrMethod == null) { return; @@ -342,7 +149,7 @@ private void copyNonPrivateNonNewMetaMethods(final Entry from, final Header to) if (oldListOrMethod instanceof FastArray) { FastArray oldList = (FastArray) oldListOrMethod; - Entry e = null; + Cache e = null; final int n = oldList.size(); Object[] array = oldList.getArray(); for (int i = 0; i != n; i += 1) { @@ -355,7 +162,7 @@ private void copyNonPrivateNonNewMetaMethods(final Entry from, final Header to) } else { MetaMethod method = (MetaMethod) oldListOrMethod; if (method instanceof NewMetaMethod || method.isPrivate()) return; - Entry e = getOrPutMethods(from.name, to); + Cache e = getOrPutMethods(from.name, to); e.methods = addMethodToList(e.methods, method); } } @@ -374,14 +181,14 @@ public Object addMethodToList(final Object o, final MetaMethod toIndex) { } if (o instanceof FastArray) { - final FastArray index = (FastArray) o; - int found = findMatchingMethod(index, toIndex); + final FastArray array = (FastArray) o; + int found = findMatchingMethod(array, toIndex); if (found == -1) { - index.add(toIndex); + array.add(toIndex); } else { - final MetaMethod inIndex = (MetaMethod) index.get(found); + final MetaMethod inIndex = (MetaMethod) array.get(found); if (inIndex != toIndex && isOverridden(inIndex, toIndex)) { - index.set(found, toIndex); + array.set(found, toIndex); } } } @@ -390,8 +197,6 @@ public Object addMethodToList(final Object o, final MetaMethod toIndex) { } /** - * TODO - *

* Note: private methods from parent classes are not handled here, but when * doing the multi-method connection step, methods of the parent class will * be overwritten with methods of a subclass and in that case private methods @@ -455,64 +260,28 @@ private static int findMatchingMethod(final FastArray list, final MetaMethod met } public void copyMethodsToSuper() { - for (Entry e : table) { - for (; e != null; e = e.nextHashEntry) { - if (e.methods instanceof FastArray) { - e.methodsForSuper = ((FastArray) e.methods).copy(); - } else { - e.methodsForSuper = e.methods; - } + allEntries().forEach(cacheEntry -> { + if (cacheEntry.methods instanceof FastArray) { + cacheEntry.methodsForSuper = ((FastArray) cacheEntry.methods).copy(); + } else { + cacheEntry.methodsForSuper = cacheEntry.methods; } - } - } - - public void copy(final Class c, final Header index) { - copy(getHeader(c), index); - } - - public void copy(final Header from, final Header to) { - for (Entry e = from.head; e != null; e = e.nextClassEntry) { - copyAllMethods(e, to); - } + }); } - private void copyAllMethods(final Entry from, final Header to) { - Object oldListOrMethod = from.methods; - if (oldListOrMethod instanceof FastArray) { - FastArray oldList = (FastArray) oldListOrMethod; - Entry e = null; - final int n = oldList.size(); - Object[] array = oldList.getArray(); - for (int i = 0; i != n; i += 1) { - MetaMethod method = (MetaMethod) array[i]; - if (e == null) - e = getOrPutMethods(from.name, to); - e.methods = addMethodToList(e.methods, method); - } - } else { - MetaMethod method = (MetaMethod) oldListOrMethod; - if (!method.isPrivate()) { - Entry e = getOrPutMethods(from.name, to); - e.methods = addMethodToList(e.methods, method); - } - } + private Stream allEntries() { + return indexMap.values().stream().flatMap(map -> map.values().stream()); } public void clearCaches() { - for (Entry e : table) { - for (; e != null; e = e.nextHashEntry) { - e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null; - } - } + allEntries().forEach(e -> + e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null + ); } public void clearCaches(String name) { - for (Entry e : table) { - for (; e != null; e = e.nextHashEntry) { - if (e.name.equals(name)) { - e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null; - } - } - } + allEntries().filter(cache -> cache.name.equals(name)).forEach(e -> + e.cachedMethod = e.cachedMethodForSuper = e.cachedStaticMethod = null + ); } } diff --git a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooThree.java b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooThree.java index d74871b349f..33a22182fe4 100644 --- a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooThree.java +++ b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooThree.java @@ -22,7 +22,7 @@ /** * To test the case when we call a static method on a class and while we load all the methods from its interface, - * {@link MetaMethodIndex.Entry} contains more than one method from interface already + * {@link MetaMethodIndex.Cache} contains more than one method from interface already */ interface FooThree { static String foo() { diff --git a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooTwo.java b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooTwo.java index f91e9d8742a..19e64fad67a 100644 --- a/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooTwo.java +++ b/src/test/org/codehaus/groovy/runtime/methoddispatching/vm8/FooTwo.java @@ -21,7 +21,7 @@ import org.codehaus.groovy.runtime.metaclass.MetaMethodIndex; /** - * To test the case when we call a static method on a class and {@link MetaMethodIndex.Entry} + * To test the case when we call a static method on a class and {@link MetaMethodIndex.Cache} * contains more than one method from interface already */ interface FooTwo {