You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by cc...@apache.org on 2017/04/08 08:41:09 UTC

[3/3] groovy git commit: Reduce memory footprint of the compiler

Reduce memory footprint of the compiler

The compiler creates a lot of maps and lists where it could avoid it. This optimizes
creation by doing it lazily, and improves memory pressure in real world context.

Signed-off-by: Cedric Champeau <cc...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/ec080fe2
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/ec080fe2
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/ec080fe2

Branch: refs/heads/GROOVY_2_5_X
Commit: ec080fe2c7c28020a64c91684007b5b5ad46c469
Parents: 1f2a5b5
Author: Cedric Champeau <cc...@apache.org>
Authored: Fri Apr 7 22:29:49 2017 +0200
Committer: Cedric Champeau <cc...@apache.org>
Committed: Sat Apr 8 10:40:49 2017 +0200

----------------------------------------------------------------------
 .../org/codehaus/groovy/ast/AnnotationNode.java |  25 ++-
 src/main/org/codehaus/groovy/ast/ClassNode.java |  10 +-
 .../groovy/reflection/ParameterTypes.java       | 156 +++++++++----------
 .../transform/AnnotationCollectorTransform.java |  45 +++++-
 4 files changed, 143 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/ec080fe2/src/main/org/codehaus/groovy/ast/AnnotationNode.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/AnnotationNode.java b/src/main/org/codehaus/groovy/ast/AnnotationNode.java
index 50eddd0..e00f977 100644
--- a/src/main/org/codehaus/groovy/ast/AnnotationNode.java
+++ b/src/main/org/codehaus/groovy/ast/AnnotationNode.java
@@ -18,11 +18,12 @@
  */
 package org.codehaus.groovy.ast;
 
-import java.util.HashMap;
-import java.util.Map;
-
-import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.ast.expr.Expression;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 
 /**
@@ -44,7 +45,7 @@ public class AnnotationNode extends ASTNode {
         | FIELD_TARGET | PARAMETER_TARGET | LOCAL_VARIABLE_TARGET | ANNOTATION_TARGET | PACKAGE_TARGET;
     
     private final ClassNode classNode;
-    private final Map<String, Expression> members = new HashMap<String, Expression>();
+    private Map<String, Expression> members;
     private boolean runtimeRetention= false, sourceRetention= false, classRetention = false;
     private int allowedTargets = ALL_TARGETS;
 
@@ -57,14 +58,27 @@ public class AnnotationNode extends ASTNode {
     }
 
     public Map<String, Expression> getMembers() {
+        if (members == null) {
+            return Collections.emptyMap();
+        }
         return members;
     }
     
     public Expression getMember(String name) {
+        if (members == null) {
+            return null;
+        }
         return members.get(name);
     }
 
+    private void assertMembers() {
+        if (members == null) {
+             members = new LinkedHashMap<String, Expression>();
+        }
+    }
+
     public void addMember(String name, Expression value) {
+        assertMembers();
         Expression oldValue = members.get(name);
         if (oldValue == null) {
             members.put(name, value);
@@ -75,6 +89,7 @@ public class AnnotationNode extends ASTNode {
     }
 
     public void setMember(String name, Expression value) {
+        assertMembers();
         members.put(name, value);
     }
     

http://git-wip-us.apache.org/repos/asf/groovy/blob/ec080fe2/src/main/org/codehaus/groovy/ast/ClassNode.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/ast/ClassNode.java b/src/main/org/codehaus/groovy/ast/ClassNode.java
index f8858b2..702a0a8 100644
--- a/src/main/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/org/codehaus/groovy/ast/ClassNode.java
@@ -102,16 +102,21 @@ import java.util.Set;
  */
 public class ClassNode extends AnnotatedNode implements Opcodes {
     private static class MapOfLists {
-        private final Map<Object, List<MethodNode>> map = new HashMap<Object, List<MethodNode>>();
+        private Map<Object, List<MethodNode>> map;
         public List<MethodNode> get(Object key) {
-            return map.get(key);
+            return map == null ? null : map.get(key);
         }
+
         public List<MethodNode> getNotNull(Object key) {
             List<MethodNode> ret = get(key);
             if (ret==null) ret = Collections.emptyList();
             return ret;
         }
+
         public void put(Object key, MethodNode value) {
+            if (map == null) {
+                 map = new HashMap<Object, List<MethodNode>>();
+            }
             if (map.containsKey(key)) {
                 get(key).add(value);
             } else {
@@ -120,6 +125,7 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
                 map.put(key, list);
             }
         }
+
         public void remove(Object key, MethodNode value) {
             get(key).remove(value);
         }

http://git-wip-us.apache.org/repos/asf/groovy/blob/ec080fe2/src/main/org/codehaus/groovy/reflection/ParameterTypes.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/reflection/ParameterTypes.java b/src/main/org/codehaus/groovy/reflection/ParameterTypes.java
index 9e683be..4c5d5fa 100644
--- a/src/main/org/codehaus/groovy/reflection/ParameterTypes.java
+++ b/src/main/org/codehaus/groovy/reflection/ParameterTypes.java
@@ -25,17 +25,18 @@ import org.codehaus.groovy.runtime.wrappers.Wrapper;
 
 import java.lang.reflect.Array;
 
-public class ParameterTypes
-{
-  protected volatile Class [] nativeParamTypes;
-  protected volatile CachedClass [] parameterTypes;
+public class ParameterTypes {
+    private final static Class[] NO_PARAMETERS = new Class[0];
 
-  protected boolean isVargsMethod;
+    protected volatile Class[] nativeParamTypes;
+    protected volatile CachedClass[] parameterTypes;
 
-    public ParameterTypes () {
+    protected boolean isVargsMethod;
+
+    public ParameterTypes() {
     }
 
-    public ParameterTypes(Class pt []) {
+    public ParameterTypes(Class pt[]) {
         nativeParamTypes = pt;
     }
 
@@ -43,9 +44,8 @@ public class ParameterTypes
         nativeParamTypes = new Class[pt.length];
         for (int i = 0; i != pt.length; ++i) {
             try {
-              nativeParamTypes[i] = Class.forName(pt[i]);
-            }
-            catch (ClassNotFoundException e){
+                nativeParamTypes[i] = Class.forName(pt[i]);
+            } catch (ClassNotFoundException e) {
                 NoClassDefFoundError err = new NoClassDefFoundError();
                 err.initCause(e);
                 throw err;
@@ -59,29 +59,34 @@ public class ParameterTypes
 
     protected final void setParametersTypes(CachedClass[] pt) {
         this.parameterTypes = pt;
-        isVargsMethod = pt.length > 0 && pt [pt.length-1].isArray;
+        isVargsMethod = pt.length > 0 && pt[pt.length - 1].isArray;
     }
 
     public CachedClass[] getParameterTypes() {
-      if (parameterTypes == null) {
-          getParametersTypes0();
-      }
+        if (parameterTypes == null) {
+            getParametersTypes0();
+        }
 
-      return parameterTypes;
-  }
+        return parameterTypes;
+    }
 
     private synchronized void getParametersTypes0() {
-      if (parameterTypes != null)
-          return;
+        if (parameterTypes != null)
+            return;
 
-      Class [] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
+        Class[] npt = nativeParamTypes == null ? getPT() : nativeParamTypes;
+        if (npt.length == 0) {
+            nativeParamTypes = NO_PARAMETERS;
+            setParametersTypes(CachedClass.EMPTY_ARRAY);
+        } else {
 
-      CachedClass[] pt = new CachedClass [npt.length];
-      for (int i = 0; i != npt.length; ++i)
-        pt[i] = ReflectionCache.getCachedClass(npt[i]);
+            CachedClass[] pt = new CachedClass[npt.length];
+            for (int i = 0; i != npt.length; ++i)
+                pt[i] = ReflectionCache.getCachedClass(npt[i]);
 
-      nativeParamTypes = npt;
-      setParametersTypes(pt);
+            nativeParamTypes = npt;
+            setParametersTypes(pt);
+        }
     }
 
     public Class[] getNativeParameterTypes() {
@@ -92,32 +97,33 @@ public class ParameterTypes
     }
 
     private synchronized void getNativeParameterTypes0() {
-      if (nativeParamTypes != null)
-          return;
-
-      Class [] npt;
-      if (parameterTypes != null) {
-          npt = new Class [parameterTypes.length];
-          for (int i = 0; i != parameterTypes.length; ++i) {
-              npt[i] = parameterTypes[i].getTheClass();
-          }
-      }
-      else
-        npt = getPT ();
-      nativeParamTypes = npt;
+        if (nativeParamTypes != null)
+            return;
+
+        Class[] npt;
+        if (parameterTypes != null) {
+            npt = new Class[parameterTypes.length];
+            for (int i = 0; i != parameterTypes.length; ++i) {
+                npt[i] = parameterTypes[i].getTheClass();
+            }
+        } else
+            npt = getPT();
+        nativeParamTypes = npt;
     }
 
-    protected Class[] getPT() { throw new UnsupportedOperationException(getClass().getName()); }
+    protected Class[] getPT() {
+        throw new UnsupportedOperationException(getClass().getName());
+    }
 
     public boolean isVargsMethod() {
         return isVargsMethod;
     }
-    
+
     public boolean isVargsMethod(Object[] arguments) {
         // Uncomment if at some point this method can be called before parameterTypes initialized
         // getParameterTypes();
-        if(!isVargsMethod)
-          return false;
+        if (!isVargsMethod)
+            return false;
 
         final int lenMinus1 = parameterTypes.length - 1;
         // -1 because the varg part is optional
@@ -176,7 +182,7 @@ public class ParameterTypes
      * arguments to make the method callable
      *
      * @param argumentArrayOrig the arguments used to call the method
-     * @param paramTypes    the types of the parameters the method takes
+     * @param paramTypes        the types of the parameters the method takes
      */
     private static Object[] fitToVargs(Object[] argumentArrayOrig, CachedClass[] paramTypes) {
         Class vargsClassOrig = paramTypes[paramTypes.length - 1].getTheClass().getComponentType();
@@ -221,32 +227,30 @@ public class ParameterTypes
             throw new GroovyBugError("trying to call a vargs method without enough arguments");
         }
     }
-    
+
     private static Object makeCommonArray(Object[] arguments, int offset, Class baseClass) {
         Object[] result = (Object[]) Array.newInstance(baseClass, arguments.length - offset);
-        for (int i=offset; i<arguments.length; i++) {
+        for (int i = offset; i < arguments.length; i++) {
             Object v = arguments[i];
-            v = DefaultTypeTransformation.castToType(v,baseClass);
-            result[i-offset] = v;
+            v = DefaultTypeTransformation.castToType(v, baseClass);
+            result[i - offset] = v;
         }
         return result;
     }
-    
+
     public boolean isValidMethod(Class[] arguments) {
         if (arguments == null) return true;
 
         final int size = arguments.length;
         CachedClass[] pt = getParameterTypes();
-        final int paramMinus1 = pt.length-1;
+        final int paramMinus1 = pt.length - 1;
 
         if (isVargsMethod && size >= paramMinus1)
             return isValidVarargsMethod(arguments, size, pt, paramMinus1);
-        else
-            if (pt.length == size)
-                return isValidExactMethod(arguments, pt);
-            else
-                if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
-                    return true;
+        else if (pt.length == size)
+            return isValidExactMethod(arguments, pt);
+        else if (pt.length == 1 && size == 0 && !pt[0].isPrimitive)
+            return true;
         return false;
     }
 
@@ -261,13 +265,13 @@ public class ParameterTypes
         return true;
     }
 
-    public boolean isValidExactMethod(Object [] args) {
+    public boolean isValidExactMethod(Object[] args) {
         // lets check the parameter types match
         getParametersTypes0();
         int size = args.length;
         if (size != parameterTypes.length)
-          return false;
-        
+            return false;
+
         for (int i = 0; i < size; i++) {
             if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i].getClass())) {
                 return false;
@@ -276,12 +280,12 @@ public class ParameterTypes
         return true;
     }
 
-    public boolean isValidExactMethod(Class [] args) {
+    public boolean isValidExactMethod(Class[] args) {
         // lets check the parameter types match
         getParametersTypes0();
         int size = args.length;
         if (size != parameterTypes.length)
-          return false;
+            return false;
 
         for (int i = 0; i < size; i++) {
             if (args[i] != null && !parameterTypes[i].isAssignableFrom(args[i])) {
@@ -293,7 +297,7 @@ public class ParameterTypes
 
     private static boolean testComponentAssignable(Class toTestAgainst, Class toTest) {
         Class component = toTest.getComponentType();
-        if (component==null) return false;
+        if (component == null) return false;
         return MetaClassHelper.isAssignableFrom(toTestAgainst, component);
     }
 
@@ -307,10 +311,9 @@ public class ParameterTypes
         // check direct match
         CachedClass varg = pt[paramMinus1];
         Class clazz = varg.getTheClass().getComponentType();
-        if ( size==pt.length &&
-             (varg.isAssignableFrom(arguments[paramMinus1]) ||
-              testComponentAssignable(clazz, arguments[paramMinus1])))
-        {
+        if (size == pt.length &&
+                (varg.isAssignableFrom(arguments[paramMinus1]) ||
+                        testComponentAssignable(clazz, arguments[paramMinus1]))) {
             return true;
         }
 
@@ -327,28 +330,26 @@ public class ParameterTypes
 
         final int size = arguments.length;
         CachedClass[] paramTypes = getParameterTypes();
-        final int paramMinus1 = paramTypes.length-1;
+        final int paramMinus1 = paramTypes.length - 1;
 
-        if ( size >= paramMinus1 && paramTypes.length > 0 &&
-             paramTypes[(paramMinus1)].isArray) 
-        {
+        if (size >= paramMinus1 && paramTypes.length > 0 &&
+                paramTypes[(paramMinus1)].isArray) {
             // first check normal number of parameters
             for (int i = 0; i < paramMinus1; i++) {
                 if (paramTypes[i].isAssignableFrom(getArgClass(arguments[i]))) continue;
                 return false;
             }
-            
-            
+
+
             // check direct match
             CachedClass varg = paramTypes[paramMinus1];
             Class clazz = varg.getTheClass().getComponentType();
-            if ( size==paramTypes.length && 
-                 (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
-                  testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) 
-            {
+            if (size == paramTypes.length &&
+                    (varg.isAssignableFrom(getArgClass(arguments[paramMinus1])) ||
+                            testComponentAssignable(clazz, getArgClass(arguments[paramMinus1])))) {
                 return true;
             }
-            
+
 
             // check varged
             for (int i = paramMinus1; i < size; i++) {
@@ -375,9 +376,8 @@ public class ParameterTypes
             cls = null;
         } else {
             if (arg instanceof Wrapper) {
-                cls = ((Wrapper)arg).getType();
-            }
-            else
+                cls = ((Wrapper) arg).getType();
+            } else
                 cls = arg.getClass();
         }
         return cls;

http://git-wip-us.apache.org/repos/asf/groovy/blob/ec080fe2/src/main/org/codehaus/groovy/transform/AnnotationCollectorTransform.java
----------------------------------------------------------------------
diff --git a/src/main/org/codehaus/groovy/transform/AnnotationCollectorTransform.java b/src/main/org/codehaus/groovy/transform/AnnotationCollectorTransform.java
index 62ae932..80188d9 100644
--- a/src/main/org/codehaus/groovy/transform/AnnotationCollectorTransform.java
+++ b/src/main/org/codehaus/groovy/transform/AnnotationCollectorTransform.java
@@ -19,19 +19,36 @@
 package org.codehaus.groovy.transform;
 
 import groovy.transform.AnnotationCollector;
-
-import java.lang.reflect.Method;
-import java.util.*;
-
 import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.*;
-import org.codehaus.groovy.ast.expr.*;
+import org.codehaus.groovy.ast.ASTNode;
+import org.codehaus.groovy.ast.AnnotatedNode;
+import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.expr.AnnotationConstantExpression;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.ast.expr.MapExpression;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
 import org.codehaus.groovy.syntax.SyntaxException;
 
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
 import static org.objectweb.asm.Opcodes.*;
 
 /**
@@ -188,7 +205,7 @@ public class AnnotationCollectorTransform {
         List<AnnotationNode> ret = new ArrayList<AnnotationNode>(orig.size());
         for (AnnotationNode an : orig) {
             AnnotationNode newAn = new AnnotationNode(an.getClassNode());
-            newAn.getMembers().putAll(an.getMembers());
+            copyMembers(an, newAn);
             newAn.setSourcePosition(aliasAnnotationUsage);
             ret.add(newAn);
         }
@@ -204,12 +221,23 @@ public class AnnotationCollectorTransform {
             ClassNode type = an.getClassNode();
             if (type.getName().equals(AnnotationCollector.class.getName())) continue;
             AnnotationNode toAdd = new AnnotationNode(type);
-            toAdd.getMembers().putAll(an.getMembers());
+            copyMembers(an, toAdd);
             ret.add(toAdd);
         }
         return ret;
     }
 
+    private static void copyMembers(final AnnotationNode from, final AnnotationNode to) {
+        Map<String, Expression> members = from.getMembers();
+        copyMembers(members, to);
+    }
+
+    private static void copyMembers(final Map<String, Expression> members, final AnnotationNode to) {
+        for (Map.Entry<String, Expression> entry : members.entrySet()) {
+            to.addMember(entry.getKey(), entry.getValue());
+        }
+    }
+
     private static List<AnnotationNode> getTargetListFromClass(ClassNode alias) {
         Class<?> c = alias.getTypeClass();
         Object[][] data;
@@ -239,6 +267,7 @@ public class AnnotationCollectorTransform {
                 Object val = member.get(name);
                 generated.put(name, makeExpression(val));
             }
+            copyMembers(generated, toAdd);
             toAdd.getMembers().putAll(generated);
         }
         return ret;