This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_5_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_5_0_X by this push:
     new e31f89d007 GROOVY-11841: use `ConcurrentHashMap` for mutable property 
index maps
e31f89d007 is described below

commit e31f89d007f0dc4c2b2e0cb24872ea1e77cd4cdb
Author: Eric Milles <[email protected]>
AuthorDate: Thu Jan 15 13:30:51 2026 -0600

    GROOVY-11841: use `ConcurrentHashMap` for mutable property index maps
    
    5_0_X backport
---
 src/main/java/groovy/lang/MetaClassImpl.java | 101 +++++++++++----------------
 1 file changed, 39 insertions(+), 62 deletions(-)

diff --git a/src/main/java/groovy/lang/MetaClassImpl.java 
b/src/main/java/groovy/lang/MetaClassImpl.java
index 1f90450e74..d2a92cc5b6 100644
--- a/src/main/java/groovy/lang/MetaClassImpl.java
+++ b/src/main/java/groovy/lang/MetaClassImpl.java
@@ -154,13 +154,15 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     protected final boolean isMap;
     protected final MetaMethodIndex metaMethodIndex;
 
-    private final Map<CachedClass, LinkedHashMap<String, MetaProperty>> 
classPropertyIndex = new LinkedHashMap<>();
+    private static Map<String, MetaProperty> subMap(Map<CachedClass, 
Map<String, MetaProperty>> map, CachedClass key) {
+        return map.computeIfAbsent(key, k -> new LinkedHashMap<>());
+    }
+    private final Map<CachedClass, Map<String, MetaProperty>> 
classPropertyIndexForSuper = new ConcurrentHashMap<>();
+    private final Map<CachedClass, Map<String, MetaProperty>> 
classPropertyIndex = new ConcurrentHashMap<>();
     private final Map<String, MetaProperty> staticPropertyIndex = new 
LinkedHashMap<>();
+
     private final Map<String, MetaMethod> listeners = new LinkedHashMap<>();
     private final List<MetaMethod> allMethods = new ArrayList<>();
-    // we only need one of these that can be reused over and over.
-    private final MetaProperty arrayLengthProperty = new 
MetaArrayLengthProperty();
-    private final Map<CachedClass, LinkedHashMap<String, MetaProperty>> 
classPropertyIndexForSuper = new LinkedHashMap<>();
     private final Set<MetaMethod> newGroovyMethodsSet = new LinkedHashSet<>();
     private final MetaMethod[] myNewMetaMethods;
     private final MetaMethod[] additionalMetaMethods;
@@ -291,12 +293,12 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     public MetaProperty getMetaProperty(final String name) {
         MetaProperty metaProperty = null;
 
-        LinkedHashMap<String, MetaProperty> propertyMap = 
classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+        Map<String, MetaProperty> propertyMap = subMap(classPropertyIndex, 
theCachedClass);
         metaProperty = propertyMap.get(name);
         if (metaProperty == null) {
             metaProperty = staticPropertyIndex.get(name);
             if (metaProperty == null) {
-                propertyMap = 
classPropertyIndexForSuper.computeIfAbsent(theCachedClass, k -> new 
LinkedHashMap<>());
+                propertyMap = subMap(classPropertyIndexForSuper, 
theCachedClass);
                 metaProperty = propertyMap.get(name);
                 if (metaProperty == null) {
                     MetaBeanProperty property = 
findPropertyInClassHierarchy(name, theCachedClass);
@@ -1287,7 +1289,10 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
      * Tries to find a callable property and make the call.
      */
     private Object invokePropertyOrMissing(final Object object, final String 
methodName, final Object[] originalArguments, final boolean fromInsideClass, 
final boolean isCallToSuper) {
-        MetaProperty metaProperty = this.getMetaProperty(methodName, false);
+        MetaProperty metaProperty = null;
+
+        Map<String, MetaProperty> propertyMap = 
classPropertyIndex.get(theCachedClass);
+        if (propertyMap != null) metaProperty = propertyMap.get(methodName);
 
         Object value = null;
         if (metaProperty != null) {
@@ -2329,23 +2334,17 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     }
 
     /**
-     * This will build up the property map (Map of MetaProperty objects, keyed 
on
-     * property name).
+     * Populates the map of MetaProperty objects, keyed by class and property 
name.
      *
      * @param propertyDescriptors the property descriptors
      */
     private void setUpProperties(final PropertyDescriptor[] 
propertyDescriptors) {
         if (theCachedClass.isInterface) {
-            for (CachedClass iface : theCachedClass.getInterfaces()) { // 
includes theCachedClass
-                classPropertyIndex.computeIfAbsent(iface, x -> {
-                    var index = new LinkedHashMap<String, MetaProperty>();
-                    addConsts(iface, index);
-                    return index;
-                });
-            }
+            addConsts(theCachedClass, subMap(classPropertyIndex, 
theCachedClass));
+
             applyPropertyDescriptors(propertyDescriptors);
             CachedClass superClass = ReflectionCache.OBJECT_CLASS;
-            applyStrayPropertyMethods(superClass, 
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>()), 
true);
+            applyStrayPropertyMethods(superClass, subMap(classPropertyIndex, 
superClass), true);
         } else {
             List<CachedClass> superClasses = getSuperClasses();
             List<CachedClass> superInterfaces = new 
ArrayList<>(theCachedClass.getInterfaces());
@@ -2356,9 +2355,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
             }
 
             if (theCachedClass.isArray) { // add the special read-only 
"length" property
-                var map = new LinkedHashMap<String, MetaProperty>();
-                map.put("length", arrayLengthProperty);
-                classPropertyIndex.put(theCachedClass, map);
+                subMap(classPropertyIndex, theCachedClass).put("length", new 
MetaArrayLengthProperty());
             }
 
             inheritStaticInterfaceFields(superClasses, superInterfaces);
@@ -2390,7 +2387,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
             }
         };
 
-        classPropertyIndex.computeIfAbsent(theCachedClass, x -> new 
LinkedHashMap<>()).forEach(indexStaticProperty);
+        subMap(classPropertyIndex, 
theCachedClass).forEach(indexStaticProperty);
 
         if (theCachedClass.isInterface) { // GROOVY-10592: static interface 
accessors
             Map<String, MetaProperty> strayProperties = new LinkedHashMap<>();
@@ -2457,14 +2454,14 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
 
     private void inheritStaticInterfaceFields(List<CachedClass> superClasses, 
Iterable<CachedClass> interfaces) {
         for (CachedClass iface : interfaces) {
-            LinkedHashMap<String, MetaProperty> iPropertyIndex = 
classPropertyIndex.computeIfAbsent(iface, x -> {
+            Map<String, MetaProperty> iPropertyIndex = 
classPropertyIndex.computeIfAbsent(iface, x -> {
                 var index = new LinkedHashMap<String, MetaProperty>();
                 addConsts(iface, index);
                 return index;
             });
             for (CachedClass superClass : superClasses) {
                 if 
(!iface.getTheClass().isAssignableFrom(superClass.getTheClass())) continue;
-                LinkedHashMap<String, MetaProperty> sPropertyIndex = 
classPropertyIndex.computeIfAbsent(superClass, x -> new LinkedHashMap<>());
+                Map<String, MetaProperty> sPropertyIndex = 
subMap(classPropertyIndex, superClass);
                 copyNonPrivateFields(iPropertyIndex, sPropertyIndex, null);
             }
         }
@@ -2473,11 +2470,11 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
     private void inheritFields(final Iterable<CachedClass> superClasses) {
         Map<String, MetaProperty> sci = null;
         for (CachedClass cc : superClasses) {
-            Map<String, MetaProperty> cci = 
classPropertyIndex.computeIfAbsent(cc, x -> new LinkedHashMap<>());
+            Map<String, MetaProperty> cci = subMap(classPropertyIndex, cc);
             if (sci != null && !sci.isEmpty()) {
                 copyNonPrivateFields(sci, cci, cc);
                 // GROOVY-9608, GROOVY-9609: add public, protected, and 
package-private fields to index for super
-                copyNonPrivateFields(sci, 
classPropertyIndexForSuper.computeIfAbsent(cc, x -> new LinkedHashMap<>()), cc);
+                copyNonPrivateFields(sci, subMap(classPropertyIndexForSuper, 
cc), cc);
             }
             sci = cci;
             addFields(cc, cci);
@@ -2507,9 +2504,9 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         }
     }
 
-    private void applyStrayPropertyMethods(Iterable<CachedClass> classes, 
Map<CachedClass, LinkedHashMap<String, MetaProperty>> propertyIndex, boolean 
isThis) {
+    private void applyStrayPropertyMethods(Iterable<CachedClass> classes, 
Map<CachedClass, Map<String, MetaProperty>> propertyIndex, boolean isThis) {
         for (CachedClass cc : classes) {
-            applyStrayPropertyMethods(cc, propertyIndex.computeIfAbsent(cc, x 
-> new LinkedHashMap<>()), isThis);
+            applyStrayPropertyMethods(cc, subMap(propertyIndex, cc), isThis);
         }
     }
 
@@ -2649,7 +2646,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         if (staticProperty != null) {
             staticPropertyIndex.put(mp.getName(), mp);
         } else {
-            Map<String, MetaProperty> propertyMap = 
classPropertyIndex.computeIfAbsent(theCachedClass, k -> new LinkedHashMap<>());
+            Map<String, MetaProperty> propertyMap = subMap(classPropertyIndex, 
theCachedClass);
             // remember field
             CachedField field;
             MetaProperty old = propertyMap.get(mp.getName());
@@ -2695,7 +2692,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         boolean isStatic = (theClass != Class.class && object instanceof 
Class);
         if (isStatic && object != theClass) {
             MetaClass mc = registry.getMetaClass((Class<?>) object);
-            mc.getProperty(sender, object, name, useSuper, fromInsideClass);
+            mc.setProperty(sender, object, name, newValue, useSuper, 
fromInsideClass);
             return;
         }
 
@@ -2779,7 +2776,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         
//----------------------------------------------------------------------
         // generic set method
         
//----------------------------------------------------------------------
-        // check for a generic get method provided through a category
+        // check for a generic set method provided through a category
         if (method == null && !useSuper && !isStatic && 
GroovyCategorySupport.hasCategoryInCurrentThread()) {
             method = getCategoryMethodSetter(theClass, "set", true);
             if (method != null) arguments = new Object[]{name, newValue};
@@ -2834,44 +2831,25 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         }
     }
 
-    private MetaProperty getMetaProperty(final Class clazz, final String name, 
final boolean useSuper, final boolean useStatic) {
-        if (clazz == theClass && !useSuper)
-            return getMetaProperty(name, useStatic);
-
-        CachedClass cachedClass = ReflectionCache.getCachedClass(clazz);
-        while (true) {
-            Map<String, MetaProperty> propertyMap;
-            if (useStatic) {
-                propertyMap = staticPropertyIndex;
-            } else if (useSuper) {
-                propertyMap = classPropertyIndexForSuper.get(cachedClass);
-            } else {
-                propertyMap = classPropertyIndex.get(cachedClass);
-            }
-            if (propertyMap == null) {
-                if (cachedClass != theCachedClass) {
-                    cachedClass = theCachedClass;
-                    continue;
-                } else {
-                    return null;
-                }
-            }
-            return propertyMap.get(name);
-        }
-    }
+    private MetaProperty getMetaProperty(final Class<?> clazz, final String 
name, final boolean useSuper, final boolean useStatic) {
+        CachedClass cachedClass = (clazz == theClass ? theCachedClass : 
ReflectionCache.getCachedClass(clazz));
 
-    private MetaProperty getMetaProperty(final String name, final boolean 
useStatic) {
-        CachedClass clazz = theCachedClass;
         Map<String, MetaProperty> propertyMap;
         if (useStatic) {
             propertyMap = staticPropertyIndex;
+        } else if (!useSuper) {
+            propertyMap = classPropertyIndex.get(cachedClass);
         } else {
-            propertyMap = classPropertyIndex.get(clazz);
+            propertyMap = classPropertyIndexForSuper.get(cachedClass);
         }
-        if (propertyMap == null) {
+
+        if (propertyMap != null) {
+            return propertyMap.get(name);
+        } else if (cachedClass != theCachedClass) {
+            return getMetaProperty(theClass, name, useSuper, useStatic);
+        } else {
             return null;
         }
-        return propertyMap.get(name);
     }
 
     /**
@@ -3410,7 +3388,7 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
         Set<String> componentNames = new 
HashSet<>(plugin.getRecordComponentNames(theClass));
         if (!componentNames.isEmpty()) {
             MethodDescriptor[] methodDescriptors = info.getMethodDescriptors();
-            Map<String, MetaProperty> propIndex = 
classPropertyIndex.computeIfAbsent(theCachedClass, x -> new LinkedHashMap<>());
+            Map<String, MetaProperty> propIndex = subMap(classPropertyIndex, 
theCachedClass);
             for (MethodDescriptor md : methodDescriptors) {
                 if (md.getMethod().getParameterCount() != 0) continue;
                 String name = md.getName();
@@ -3630,7 +3608,6 @@ public class MetaClassImpl implements MetaClass, 
MutableMetaClass {
                 property = searchInterfacesForMetaProperty(propertyName, 
superInterfaces);
                 if (property != null) break;
             }
-
         }
         return property;
     }

Reply via email to