Repository: groovy Updated Branches: refs/heads/parrot ce1260900 -> 3caf3a458
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 <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/e0d55966 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/e0d55966 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/e0d55966 Branch: refs/heads/parrot Commit: e0d55966369dd6513c35fa6738dcc4f8f389e2cb Parents: fb1f14a Author: Cedric Champeau <[email protected]> Authored: Fri Apr 7 22:29:49 2017 +0200 Committer: Cedric Champeau <[email protected]> Committed: Fri Apr 7 22:33:36 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/e0d55966/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/e0d55966/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/e0d55966/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/e0d55966/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;
