@@ -137,8 +137,10 @@ public abstract class World implements Dump.INode { | |||
public boolean forDEBUG_structuralChangesCode = false; | |||
public boolean forDEBUG_bridgingCode = false; | |||
public boolean optimizedMatching = true; | |||
protected long timersPerJoinpoint; | |||
protected long timersPerType; | |||
public boolean infoMessagesEnabled = false; | |||
public int infoMessagesEnabled = 0; // 0=uninitialized, 1=no, 2=yes | |||
private static Trace trace = TraceFactory.getTraceFactory().getTrace(World.class); | |||
@@ -631,7 +633,6 @@ public abstract class World implements Dump.INode { | |||
} else { | |||
this.messageHandler = messageHandler; | |||
} | |||
infoMessagesEnabled = !messageHandler.isIgnoring(IMessage.INFO); | |||
} | |||
/** | |||
@@ -800,7 +801,10 @@ public abstract class World implements Dump.INode { | |||
} | |||
public boolean areInfoMessagesEnabled() { | |||
return infoMessagesEnabled; | |||
if (infoMessagesEnabled == 0) { | |||
infoMessagesEnabled = (messageHandler.isIgnoring(IMessage.INFO) ? 1 : 2); | |||
} | |||
return infoMessagesEnabled == 2; | |||
} | |||
/** | |||
@@ -841,6 +845,8 @@ public abstract class World implements Dump.INode { | |||
public final static String xsetFAST_PACK_METHODS = "fastPackMethods"; // default true | |||
public final static String xsetOVERWEAVING = "overWeaving"; | |||
public final static String xsetOPTIMIZED_MATCHING = "optimizedMatching"; | |||
public final static String xsetTIMERS_PER_JOINPOINT = "timersPerJoinpoint"; | |||
public final static String xsetTIMERS_PER_FASTMATCH_CALL = "timersPerFastMatchCall"; | |||
public boolean isInJava5Mode() { | |||
return behaveInJava5Way; | |||
@@ -1348,6 +1354,22 @@ public abstract class World implements Dump.INode { | |||
getMessageHandler().handleMessage(MessageUtil.info("[optimizedMatching=false] optimized matching turned off")); | |||
} | |||
s = p.getProperty(xsetTIMERS_PER_JOINPOINT, "25000"); | |||
try { | |||
timersPerJoinpoint = Integer.parseInt(s); | |||
} catch (Exception e) { | |||
getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerJoinpoint value of " + s)); | |||
timersPerJoinpoint = 25000; | |||
} | |||
s = p.getProperty(xsetTIMERS_PER_FASTMATCH_CALL, "250"); | |||
try { | |||
timersPerType = Integer.parseInt(s); | |||
} catch (Exception e) { | |||
getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerType value of " + s)); | |||
timersPerType = 250; | |||
} | |||
} | |||
checkedAdvancedConfiguration = true; | |||
} | |||
@@ -1495,6 +1517,7 @@ public abstract class World implements Dump.INode { | |||
*/ | |||
public void record(Pointcut pointcut, long timetaken) { | |||
if (timeCollector == null) { | |||
ensureAdvancedConfigurationProcessed(); | |||
timeCollector = new TimeCollector(this); | |||
} | |||
timeCollector.record(pointcut, timetaken); | |||
@@ -1506,6 +1529,7 @@ public abstract class World implements Dump.INode { | |||
*/ | |||
public void recordFastMatch(Pointcut pointcut, long timetaken) { | |||
if (timeCollector == null) { | |||
ensureAdvancedConfigurationProcessed(); | |||
timeCollector = new TimeCollector(this); | |||
} | |||
timeCollector.recordFastMatch(pointcut, timetaken); | |||
@@ -1516,17 +1540,15 @@ public abstract class World implements Dump.INode { | |||
long joinpointCount; | |||
long typeCount; | |||
long perJoinpointCount; | |||
long perTypes; | |||
Map<String, Long> joinpointsPerPointcut = new HashMap<String, Long>(); | |||
Map<String, Long> timePerPointcut = new HashMap<String, Long>(); | |||
Map<String, Long> fastMatchTimesPerPointcut = new HashMap<String, Long>(); | |||
Map<String, Long> fastMatchTypesPerPointcut = new HashMap<String, Long>(); | |||
TimeCollector(World world) { | |||
try { | |||
this.perJoinpointCount = Integer.parseInt(System.getProperty("org.aspectj.timing.perjoinpoints", "25000")); | |||
} catch (Throwable t) { | |||
System.err.println("Problem reading property 'org.aspectj.timing.perjoinpoints':" + t.toString()); | |||
this.perJoinpointCount = 25000; | |||
} | |||
this.perJoinpointCount = world.timersPerJoinpoint; | |||
this.perTypes = world.timersPerType; | |||
this.world = world; | |||
this.joinpointCount = 0; | |||
this.typeCount = 0; | |||
@@ -1558,7 +1580,7 @@ public abstract class World implements Dump.INode { | |||
totalTime += timePerPointcut.get(p); | |||
} | |||
world.getMessageHandler().handleMessage( | |||
MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms):")); | |||
MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms for "+joinpointCount+" joinpoint match calls):")); | |||
for (String p : joinpointsPerPointcut.keySet()) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("Time:" + (timePerPointcut.get(p) / 1000000) + "ms (jps:#" + joinpointsPerPointcut.get(p) | |||
@@ -1572,6 +1594,14 @@ public abstract class World implements Dump.INode { | |||
void recordFastMatch(Pointcut pointcut, long timetakenInNs) { | |||
typeCount++; | |||
String pointcutText = pointcut.toString(); | |||
Long typecounter = fastMatchTypesPerPointcut.get(pointcutText); | |||
if (typecounter == null) { | |||
typecounter = 1L; | |||
} else { | |||
typecounter++; | |||
} | |||
fastMatchTypesPerPointcut.put(pointcutText, typecounter); | |||
Long time = fastMatchTimesPerPointcut.get(pointcutText); | |||
if (time == null) { | |||
time = timetakenInNs; | |||
@@ -1579,16 +1609,17 @@ public abstract class World implements Dump.INode { | |||
time += timetakenInNs; | |||
} | |||
fastMatchTimesPerPointcut.put(pointcutText, time); | |||
if ((typeCount % 250) == 0) { | |||
if ((typeCount % perTypes) == 0) { | |||
long totalTime = 0L; | |||
for (String p : fastMatchTimesPerPointcut.keySet()) { | |||
totalTime += fastMatchTimesPerPointcut.get(p); | |||
} | |||
world.getMessageHandler().handleMessage( | |||
MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms):")); | |||
MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms for " + typeCount | |||
+ " fast match calls):")); | |||
for (String p : fastMatchTimesPerPointcut.keySet()) { | |||
StringBuffer sb = new StringBuffer(); | |||
sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms fast matching against " + p); | |||
sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms (types:#"+fastMatchTypesPerPointcut.get(p)+") fast matching against " + p); | |||
world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString())); | |||
} | |||
world.getMessageHandler().handleMessage(MessageUtil.info("---")); |
@@ -147,4 +147,8 @@ class EllipsisAnnotationTypePattern extends AnnotationTypePattern { | |||
return this; | |||
} | |||
@Override | |||
public void setForParameterAnnotationMatch() { | |||
} | |||
} |
@@ -9,7 +9,7 @@ | |||
* Contributors | |||
* Andy Clement - extracted from AnnotationTypePattern | |||
* ******************************************************************/ | |||
package org.aspectj.weaver.patterns; | |||
package org.aspectj.weaver.patterns; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
@@ -17,39 +17,57 @@ import java.util.Map; | |||
import org.aspectj.util.FuzzyBoolean; | |||
import org.aspectj.weaver.AnnotatedElement; | |||
import org.aspectj.weaver.World; | |||
import org.aspectj.weaver.ResolvedType; | |||
import org.aspectj.weaver.World; | |||
public class AnyAnnotationTypePattern extends AnnotationTypePattern { | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
@Override | |||
public FuzzyBoolean fastMatches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
@Override | |||
public FuzzyBoolean matches(AnnotatedElement annotated) { | |||
return FuzzyBoolean.YES; | |||
} | |||
public FuzzyBoolean matches(AnnotatedElement annotated,ResolvedType[] parameterAnnotations) { | |||
@Override | |||
public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) { | |||
return FuzzyBoolean.YES; | |||
} | |||
@Override | |||
public void write(DataOutputStream s) throws IOException { | |||
s.writeByte(AnnotationTypePattern.ANY_KEY); | |||
} | |||
@Override | |||
public void resolve(World world) { | |||
} | |||
public String toString() { return "@ANY"; } | |||
public Object accept(PatternNodeVisitor visitor, Object data) { | |||
return visitor.visit(this, data); | |||
} | |||
public boolean isAny() { return true; } | |||
public AnnotationTypePattern parameterizeWith(Map arg0,World w) { | |||
return this; | |||
} | |||
@Override | |||
public String toString() { | |||
return "@ANY"; | |||
} | |||
@Override | |||
public Object accept(PatternNodeVisitor visitor, Object data) { | |||
return visitor.visit(this, data); | |||
} | |||
@Override | |||
public boolean isAny() { | |||
return true; | |||
} | |||
@Override | |||
public AnnotationTypePattern parameterizeWith(Map arg0, World w) { | |||
return this; | |||
} | |||
@Override | |||
public void setForParameterAnnotationMatch() { | |||
} | |||
} |
@@ -47,6 +47,10 @@ public class SignaturePattern extends PatternNode { | |||
private TypePattern declaringType; | |||
private NamePattern name; | |||
private TypePatternList parameterTypes; | |||
private int bits = 0x0000; | |||
private static final int PARAMETER_ANNOTATION_MATCHING = 0x0001; | |||
private static final int CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING = 0x0002; | |||
private ThrowsPattern throwsPattern; | |||
private AnnotationTypePattern annotationPattern; | |||
private transient int hashcode = -1; | |||
@@ -456,24 +460,47 @@ public class SignaturePattern extends PatternNode { | |||
if (subjectMatch && !throwsPattern.matches(aMethod.getExceptions(), world)) { | |||
return FuzzyBoolean.NO; | |||
} | |||
if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) { | |||
return FuzzyBoolean.MAYBE; | |||
} | |||
if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) { | |||
// looking bad, but there might be parameterization to consider... | |||
if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) { | |||
// ok, it's bad. | |||
// '*' trivially matches everything, no need to check further | |||
if (!declaringType.isStar()) { | |||
if (!declaringType.matchesStatically(aMethod.getDeclaringType().resolve(world))) { | |||
return FuzzyBoolean.MAYBE; | |||
} | |||
} | |||
// '*' would match any return value | |||
if (!returnType.isStar()) { | |||
if (!returnType.matchesStatically(aMethod.getReturnType().resolve(world))) { | |||
// looking bad, but there might be parameterization to consider... | |||
if (!returnType.matchesStatically(aMethod.getGenericReturnType().resolve(world))) { | |||
// ok, it's bad. | |||
return FuzzyBoolean.MAYBE; | |||
} | |||
} | |||
} | |||
// The most simple case: pattern is (..) will match anything | |||
if (parameterTypes.size() == 1 && parameterTypes.get(0).isEllipsis()) { | |||
return FuzzyBoolean.YES; | |||
} | |||
if (!parameterTypes.canMatchSignatureWithNParameters(aMethod.getParameterTypes().length)) { | |||
return FuzzyBoolean.NO; | |||
} | |||
// OPTIMIZE both resolution of these types and their annotations should be deferred - just pass down a world and do it lower | |||
// down | |||
ResolvedType[] resolvedParameters = world.resolve(aMethod.getParameterTypes()); | |||
ResolvedType[][] parameterAnnotationTypes = aMethod.getParameterAnnotationTypes(); | |||
if (parameterAnnotationTypes == null || parameterAnnotationTypes.length == 0) { | |||
parameterAnnotationTypes = null; | |||
// Only fetch the parameter annotations if the pointcut is going to be matching on them | |||
ResolvedType[][] parameterAnnotationTypes = null; | |||
if (isMatchingParameterAnnotations()) { | |||
parameterAnnotationTypes = aMethod.getParameterAnnotationTypes(); | |||
if (parameterAnnotationTypes != null && parameterAnnotationTypes.length == 0) { | |||
parameterAnnotationTypes = null; | |||
} | |||
} | |||
if (!parameterTypes.matches(resolvedParameters, TypePattern.STATIC, parameterAnnotationTypes).alwaysTrue()) { | |||
// It could still be a match based on the generic sig parameter types of a parameterized type | |||
if (!parameterTypes.matches(world.resolve(aMethod.getGenericParameterTypes()), TypePattern.STATIC, | |||
@@ -493,6 +520,58 @@ public class SignaturePattern extends PatternNode { | |||
return FuzzyBoolean.YES; | |||
} | |||
/** | |||
* Determine if any pattern in the parameter type pattern list is attempting to match on parameter annotations. | |||
* | |||
* @return true if a parameter type pattern wants to match on a parameter annotation | |||
*/ | |||
private boolean isMatchingParameterAnnotations() { | |||
if ((bits & CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING) == 0) { | |||
bits |= CHECKED_FOR_PARAMETER_ANNOTATION_MATCHING; | |||
for (int tp = 0, max = parameterTypes.size(); tp < max; tp++) { | |||
TypePattern typePattern = parameterTypes.get(tp); | |||
if (isParameterAnnotationMatching(typePattern)) { | |||
bits |= PARAMETER_ANNOTATION_MATCHING; | |||
} | |||
} | |||
} | |||
return (bits & PARAMETER_ANNOTATION_MATCHING) != 0; | |||
} | |||
/** | |||
* Walk the simple structure of a type pattern and determine if any leaf node is involved in parameter annotation matching. | |||
*/ | |||
private boolean isParameterAnnotationMatching(TypePattern tp) { | |||
if (tp instanceof OrTypePattern) { | |||
OrTypePattern orAtp = (OrTypePattern) tp; | |||
return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight())); | |||
} else if (tp instanceof AndTypePattern) { | |||
AndTypePattern andAtp = (AndTypePattern) tp; | |||
return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight())); | |||
} else if (tp instanceof NotTypePattern) { | |||
NotTypePattern notAtp = (NotTypePattern) tp; | |||
return (isParameterAnnotationMatching(notAtp.getNegatedPattern())); | |||
} else { | |||
AnnotationTypePattern atp = tp.getAnnotationPattern(); | |||
return isParameterAnnotationMatching(atp); | |||
} | |||
} | |||
private boolean isParameterAnnotationMatching(AnnotationTypePattern tp) { | |||
if (tp instanceof OrAnnotationTypePattern) { | |||
OrAnnotationTypePattern orAtp = (OrAnnotationTypePattern) tp; | |||
return (isParameterAnnotationMatching(orAtp.getLeft()) || isParameterAnnotationMatching(orAtp.getRight())); | |||
} else if (tp instanceof AndAnnotationTypePattern) { | |||
AndAnnotationTypePattern andAtp = (AndAnnotationTypePattern) tp; | |||
return (isParameterAnnotationMatching(andAtp.getLeft()) || isParameterAnnotationMatching(andAtp.getRight())); | |||
} else if (tp instanceof NotAnnotationTypePattern) { | |||
NotAnnotationTypePattern notAtp = (NotAnnotationTypePattern) tp; | |||
return (isParameterAnnotationMatching(notAtp.negatedPattern)); | |||
} else { | |||
return tp.isForParameterAnnotationMatch(); | |||
} | |||
} | |||
private ResolvedType[] getResolvedParameters(World world, UnresolvedType[] unresolvedParams) { | |||
return world.resolve(unresolvedParams); | |||
} |