]> source.dussan.org Git - aspectj.git/commitdiff
296734: various optimizations for LTW and aop.xml include/exclude processing
authoraclement <aclement>
Thu, 10 Dec 2009 20:03:37 +0000 (20:03 +0000)
committeraclement <aclement>
Thu, 10 Dec 2009 20:03:37 +0000 (20:03 +0000)
loadtime/.classpath
loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java
loadtime/src/org/aspectj/weaver/loadtime/ConcreteAspectCodeGen.java
loadtime/testsrc/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptorTest.java

index 2d821b9df91b7d2949715b887e4abf6c1045c71a..c4d795a663a34e7407baa40e567238c9b7d10cc6 100644 (file)
@@ -14,5 +14,6 @@
        <classpathentry kind="lib" path="/lib/bcel/bcel.jar" sourcepath="/lib/bcel/bcel-src.zip"/>
        <classpathentry kind="lib" path="/lib/ext/jrockit/jrockit.jar"/>
        <classpathentry combineaccessrules="false" kind="src" path="/org.aspectj.matcher"/>
+       <classpathentry kind="lib" path="/lib/aspectj/lib/aspectjrt.jar"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
index b8dc0ff1df9517befa4d2f0cd3dbab3592e43e58..694e7afb57abe1f41bf559d829717d5350d5fac5 100644 (file)
@@ -63,10 +63,21 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
        private List m_dumpTypePattern = new ArrayList();
        private boolean m_dumpBefore = false;
        private boolean dumpDirPerClassloader = false;
-       private List m_includeTypePattern = new ArrayList();
-       private List m_excludeTypePattern = new ArrayList();
-       private List m_includeStartsWith = new ArrayList();
-       private List m_excludeStartsWith = new ArrayList();
+
+       private boolean hasExcludes = false;
+       private List<TypePattern> excludeTypePattern = new ArrayList<TypePattern>(); // anything
+       private List<String> excludeStartsWith = new ArrayList<String>(); // com.foo..*
+       private List<String> excludeStarDotDotStar = new ArrayList<String>(); // *..*CGLIB*
+       private List<String> excludeExactName = new ArrayList<String>(); // com.foo.Bar
+       private List<String> excludeEndsWith = new ArrayList<String>(); // com.foo.Bar
+       private List<String[]> excludeSpecial = new ArrayList<String[]>();
+
+       private boolean hasIncludes = false;
+       private List<TypePattern> includeTypePattern = new ArrayList<TypePattern>();
+       private List<String> m_includeStartsWith = new ArrayList<String>();
+       private List<String> includeExactName = new ArrayList<String>();
+       private boolean includeStar = false;
+
        private List m_aspectExcludeTypePattern = new ArrayList();
        private List m_aspectExcludeStartsWith = new ArrayList();
        private List m_aspectIncludeTypePattern = new ArrayList();
@@ -135,7 +146,6 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                }
 
                boolean success = true;
-               // if (trace.isTraceEnabled()) trace.enter("initialize",this,new Object[] { classLoader, context });
 
                this.weavingContext = context;
                if (weavingContext == null) {
@@ -155,9 +165,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                        return;
                }
 
-               bcelWorld = new LTWWorld(classLoader, weavingContext, // TODO when the world works in terms of the context, we can remove
-                               // the loader...
-                               getMessageHandler(), null);
+               // TODO when the world works in terms of the context, we can remove the loader
+               bcelWorld = new LTWWorld(classLoader, weavingContext, getMessageHandler(), null);
 
                weaver = new BcelWeaver(bcelWorld);
 
@@ -371,6 +380,9 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                                bcelWorld.getLint().loadDefaultProperties();
                        } else {
                                bcelWorld.getLint().setAll(weaverOption.lint);
+                               if (weaverOption.lint.equals("ignore")) {
+                                       bcelWorld.setAllLintIgnored();
+                               }
                        }
                }
                // TODO proceedOnError option
@@ -474,7 +486,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                                                break;
                                        }
 
-                                       ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()));
+                                       ((BcelWorld) weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(concreteAspect.name, gen.getBytes()),
+                                                       true);
 
                                        concreteAspects.add(gen);
 
@@ -534,7 +547,7 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
        }
 
        /**
-        * Register the include / exclude filters We duplicate simple patterns in startWith filters that will allow faster matching
+        * Register the include / exclude filters. We duplicate simple patterns in startWith filters that will allow faster matching
         * without ResolvedType
         * 
         * @param weaver
@@ -546,38 +559,120 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                for (Iterator iterator = definitions.iterator(); iterator.hasNext();) {
                        Definition definition = (Definition) iterator.next();
                        for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) {
+                               hasIncludes = true;
                                String include = (String) iterator1.next();
-                               TypePattern includePattern = new PatternParser(include).parseTypePattern();
-                               m_includeTypePattern.add(includePattern);
                                fastMatchInfo = looksLikeStartsWith(include);
                                if (fastMatchInfo != null) {
                                        m_includeStartsWith.add(fastMatchInfo);
+                               } else if (include.equals("*")) {
+                                       includeStar = true;
+                               } else if ((fastMatchInfo = looksLikeExactName(include)) != null) {
+                                       includeExactName.add(fastMatchInfo);
+                               } else {
+                                       TypePattern includePattern = new PatternParser(include).parseTypePattern();
+                                       includeTypePattern.add(includePattern);
                                }
                        }
                        for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) {
+                               hasExcludes = true;
                                String exclude = (String) iterator1.next();
-                               TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
-                               m_excludeTypePattern.add(excludePattern);
                                fastMatchInfo = looksLikeStartsWith(exclude);
                                if (fastMatchInfo != null) {
-                                       m_excludeStartsWith.add(fastMatchInfo);
+                                       excludeStartsWith.add(fastMatchInfo);
+                               } else if ((fastMatchInfo = looksLikeStarDotDotStarExclude(exclude)) != null) {
+                                       excludeStarDotDotStar.add(fastMatchInfo);
+                               } else if ((fastMatchInfo = looksLikeExactName(exclude)) != null) {
+                                       excludeExactName.add(exclude);
+                               } else if ((fastMatchInfo = looksLikeEndsWith(exclude)) != null) {
+                                       excludeEndsWith.add(fastMatchInfo);
+                               } else if (exclude
+                                               .equals("org.codehaus.groovy..* && !org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController*")) {
+                                       // TODO need a more sophisticated analysis here, to allow for similar situations
+                                       excludeSpecial.add(new String[] { "org.codehaus.groovy.",
+                                                       "org.codehaus.groovy.grails.web.servlet.mvc.SimpleGrailsController" });
+                                       // for the related test:
+                                       // } else if (exclude.equals("testdata..* && !testdata.sub.Oran*")) {
+                                       // excludeSpecial.add(new String[] { "testdata.", "testdata.sub.Oran" });
+                               } else {
+                                       TypePattern excludePattern = new PatternParser(exclude).parseTypePattern();
+                                       excludeTypePattern.add(excludePattern);
                                }
                        }
                }
        }
 
        /**
-        * Checks if the type pattern can be handled as a startswith check
-        * 
-        * TODO AV - enhance to support "char.sss" ie FQN direclty (match iff equals) we could also add support for "*..*charss"
-        * endsWith style?
+        * Checks if the pattern looks like "*..*XXXX*" and if so returns XXXX. This will enable fast name matching of CGLIB exclusion
         * 
-        * @param typePattern
-        * @return null if not possible, or the startWith sequence to test against
+        */
+       private String looksLikeStarDotDotStarExclude(String typePattern) {
+               if (!typePattern.startsWith("*..*")) {
+                       return null;
+               }
+               if (!typePattern.endsWith("*")) {
+                       return null;
+               }
+               String subPattern = typePattern.substring(4, typePattern.length() - 1);
+               if (hasStarDot(subPattern, 0)) {
+                       return null;
+               }
+               return subPattern.replace('$', '.');
+       }
+
+       /**
+        * Checks if the pattern looks like "com.foo.Bar" - an exact name
+        */
+       private String looksLikeExactName(String typePattern) {
+               if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.indexOf("*") != -1) {
+                       return null;
+               }
+               return typePattern.replace('$', '.');
+       }
+
+       /**
+        * Checks if the pattern looks like "*Exception"
+        */
+       private String looksLikeEndsWith(String typePattern) {
+               if (typePattern.charAt(0) != '*') {
+                       return null;
+               }
+               if (hasSpaceAnnotationPlus(typePattern, 1) || hasStarDot(typePattern, 1)) {
+                       return null;
+               }
+               return typePattern.substring(1).replace('$', '.');
+       }
+
+       /**
+        * Determine if something in the string is going to affect our ability to optimize. Checks for: ' ' '@' '+'
+        */
+       private boolean hasSpaceAnnotationPlus(String string, int pos) {
+               for (int i = pos, max = string.length(); i < max; i++) {
+                       char ch = string.charAt(i);
+                       if (ch == ' ' || ch == '@' || ch == '+') {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Determine if something in the string is going to affect our ability to optimize. Checks for: '*' '.'
+        */
+       private boolean hasStarDot(String string, int pos) {
+               for (int i = pos, max = string.length(); i < max; i++) {
+                       char ch = string.charAt(i);
+                       if (ch == '*' || ch == '.') {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Checks if the type pattern looks like "com.foo..*"
         */
        private String looksLikeStartsWith(String typePattern) {
-               if (typePattern.indexOf('@') >= 0 || typePattern.indexOf('+') >= 0 || typePattern.indexOf(' ') >= 0
-                               || typePattern.charAt(typePattern.length() - 1) != '*') {
+               if (hasSpaceAnnotationPlus(typePattern, 0) || typePattern.charAt(typePattern.length() - 1) != '*') {
                        return null;
                }
                // now must looks like with "charsss..*" or "cha.rss..*" etc
@@ -586,9 +681,8 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                int length = typePattern.length();
                if (typePattern.endsWith("..*") && length > 3) {
                        if (typePattern.indexOf("..") == length - 3 // no ".." before last sequence
-                                       && typePattern.indexOf('*') == length - 1) { // no "*" before last sequence
-                               return typePattern.substring(0, length - 2).replace('$', '.');
-                               // ie "charsss." or "char.rss." etc
+                                       && typePattern.indexOf('*') == length - 1) { // no earlier '*'
+                               return typePattern.substring(0, length - 2).replace('$', '.'); // "charsss." or "char.rss." etc
                        }
                }
                return null;
@@ -618,67 +712,120 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
                }
        }
 
+       /**
+        * Determine whether a type should be accepted for weaving, by checking it against any includes/excludes.
+        * 
+        * @param className the name of the type to possibly accept
+        * @param bytes the bytecode for the type (in case we need to look inside, eg. annotations)
+        * @return true if it should be accepted for weaving
+        */
        @Override
        protected boolean accept(String className, byte[] bytes) {
-               // avoid ResolvedType if not needed
-               if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) {
+
+               if (!hasExcludes && !hasIncludes) {
                        return true;
                }
 
                // still try to avoid ResolvedType if we have simple patterns
                String fastClassName = className.replace('/', '.').replace('$', '.');
-               for (int i = 0; i < m_excludeStartsWith.size(); i++) {
-                       if (fastClassName.startsWith((String) m_excludeStartsWith.get(i))) {
+               for (String excludeStartsWithString : excludeStartsWith) {
+                       if (fastClassName.startsWith(excludeStartsWithString)) {
                                return false;
                        }
                }
 
+               // Fast exclusion of patterns like: "*..*CGLIB*"
+               if (!excludeStarDotDotStar.isEmpty()) {
+                       for (String namePiece : excludeStarDotDotStar) {
+                               int index = fastClassName.lastIndexOf('.');
+                               if (fastClassName.indexOf(namePiece, index + 1) != -1) {
+                                       return false;
+                               }
+                       }
+               }
+
+               if (!excludeEndsWith.isEmpty()) {
+                       for (String lastPiece : excludeEndsWith) {
+                               if (fastClassName.endsWith(lastPiece)) {
+                                       return false;
+                               }
+                       }
+               }
+
+               // Fast exclusion of exact names
+               if (!excludeExactName.isEmpty()) {
+                       for (String name : excludeExactName) {
+                               if (fastClassName.equals(name)) {
+                                       return false;
+                               }
+                       }
+               }
+
+               if (!excludeSpecial.isEmpty()) {
+                       for (String[] entry : excludeSpecial) {
+                               String excludeThese = entry[0];
+                               String exceptThese = entry[1];
+                               if (fastClassName.startsWith(excludeThese) && !fastClassName.startsWith(exceptThese)) {
+                                       return false;
+                               }
+                       }
+               }
+
                /*
                 * Bug 120363 If we have an exclude pattern that cannot be matched using "starts with" then we cannot fast accept
                 */
-               if (m_excludeTypePattern.isEmpty()) {
+               boolean didSomeIncludeMatching = false;
+               if (excludeTypePattern.isEmpty()) {
+                       if (includeStar) {
+                               return true;
+                       }
+                       if (!includeExactName.isEmpty()) {
+                               didSomeIncludeMatching = true;
+                               for (String exactname : includeExactName) {
+                                       if (fastClassName.equals(exactname)) {
+                                               return true;
+                                       }
+                               }
+                       }
                        boolean fastAccept = false;// defaults to false if no fast include
                        for (int i = 0; i < m_includeStartsWith.size(); i++) {
-                               fastAccept = fastClassName.startsWith((String) m_includeStartsWith.get(i));
+                               didSomeIncludeMatching = true;
+                               fastAccept = fastClassName.startsWith(m_includeStartsWith.get(i));
                                if (fastAccept) {
-                                       break;
+                                       return true;
                                }
                        }
+                       // We may have processed all patterns now... check that and return
+                       if (includeTypePattern.isEmpty()) {
+                               return !didSomeIncludeMatching;
+                       }
                }
 
-               // needs further analysis
-               // TODO AV - needs refactoring
-               // during LTW this calling resolve at that stage is BAD as we do have the bytecode from the classloader hook
-               // but still go thru resolve that will do a getResourcesAsStream on disk
-               // this is also problematic for jit stub which are not on disk - as often underlying infra
-               // does returns null or some other info for getResourceAsStream (f.e. WLS 9 CR248491)
-               // Instead I parse the given bytecode. But this also means it will be parsed again in
-               // new WeavingClassFileProvider() from WeavingAdaptor.getWovenBytes()...
-
-               ensureDelegateInitialized(className, bytes);
-               ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();// BAD:
-               // weaver.getWorld().resolve(UnresolvedType.forName(
-               // className), true);
+               boolean accept;
+               try {
+                       ensureDelegateInitialized(className, bytes);
 
-               // exclude are "AND"ed
-               for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) {
-                       TypePattern typePattern = (TypePattern) iterator.next();
-                       if (typePattern.matchesStatically(classInfo)) {
-                               // exclude match - skip
-                               return false;
+                       ResolvedType classInfo = delegateForCurrentClass.getResolvedTypeX();
+
+                       // exclude are "AND"ed
+                       for (TypePattern typePattern : excludeTypePattern) {
+                               if (typePattern.matchesStatically(classInfo)) {
+                                       // exclude match - skip
+                                       return false;
+                               }
                        }
-               }
-               // include are "OR"ed
-               boolean accept = true;// defaults to true if no include
-               for (Iterator iterator = m_includeTypePattern.iterator(); iterator.hasNext();) {
-                       TypePattern typePattern = (TypePattern) iterator.next();
-                       accept = typePattern.matchesStatically(classInfo);
-                       if (accept) {
-                               break;
+                       // include are "OR"ed
+                       accept = !didSomeIncludeMatching; // only true if no includes at all
+                       for (TypePattern typePattern : includeTypePattern) {
+                               accept = typePattern.matchesStatically(classInfo);
+                               if (accept) {
+                                       break;
+                               }
+                               // goes on if this include did not match ("OR"ed)
                        }
-                       // goes on if this include did not match ("OR"ed)
+               } finally {
+                       this.bcelWorld.demote();
                }
-               this.bcelWorld.demote();
                return accept;
        }
 
index 18176f0e2b6bd62a05bb427e715019cf750f0d33..41b9b4ca3f65a2a8636267bab880cbc88c963449 100644 (file)
@@ -270,12 +270,14 @@ public class ConcreteAspectCodeGen {
        // hierarchy that have not been
        // concretized.
        private void getOutstandingAbstractMethodsHelper(ResolvedType type, Map collector) {
-               if (type == null)
+               if (type == null) {
                        return;
+               }
                // Get to the top
                if (!type.equals(ResolvedType.OBJECT)) {
-                       if (type.getSuperclass() != null)
+                       if (type.getSuperclass() != null) {
                                getOutstandingAbstractMethodsHelper(type.getSuperclass(), collector);
+                       }
                }
                ResolvedMember[] rms = type.getDeclaredMethods();
                if (rms != null) {
@@ -309,8 +311,9 @@ public class ConcreteAspectCodeGen {
 
        private boolean hasPointcutAnnotation(ResolvedMember member) {
                AnnotationAJ[] as = member.getAnnotations();
-               if (as == null || as.length == 0)
+               if (as == null || as.length == 0) {
                        return false;
+               }
                for (int i = 0; i < as.length; i++) {
                        if (as[i].getTypeSignature().equals("Lorg/aspectj/lang/annotation/Pointcut;")) {
                                return true;
@@ -440,7 +443,7 @@ public class ConcreteAspectCodeGen {
                // register the fresh new class into the world repository as it does not
                // exist on the classpath anywhere
                JavaClass jc = cg.getJavaClass((BcelWorld) world);
-               ((BcelWorld) world).addSourceObjectType(jc);
+               ((BcelWorld) world).addSourceObjectType(jc, true);
 
                return jc.getBytes();
        }
index 805b989a6620f446d9ae3fcf3a43eacf3e1c520d..58166e20c4dee4fb7a5f6e4215d47a27c383c690 100644 (file)
  *******************************************************************************/
 package org.aspectj.weaver.loadtime;
 
+import java.io.File;
+import java.lang.reflect.Field;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
+import org.aspectj.apache.bcel.classfile.JavaClass;
+import org.aspectj.apache.bcel.util.ClassPath;
+import org.aspectj.apache.bcel.util.SyntheticRepository;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.weaver.World;
+import org.aspectj.weaver.World.TypeMap;
+import org.aspectj.weaver.bcel.BcelWorld;
+import org.aspectj.weaver.loadtime.definition.Definition;
+import org.aspectj.weaver.tools.WeavingAdaptor;
+
 public class ClassLoaderWeavingAdaptorTest extends TestCase {
 
        public void testClassLoaderWeavingAdaptor() {
                ClassLoader loader = new URLClassLoader(new URL[] {}, null);
                ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
-               adaptor.initialize(loader,null);
+               adaptor.initialize(loader, null);
        }
 
        public void testGetNamespace() {
                ClassLoader loader = new URLClassLoader(new URL[] {}, null);
                ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
-               adaptor.initialize(loader,null);
+               adaptor.initialize(loader, null);
                String namespace = adaptor.getNamespace();
-               assertEquals("Namespace should be empty","",namespace);
+               assertEquals("Namespace should be empty", "", namespace);
        }
 
        public void testGeneratedClassesExistFor() {
                ClassLoader loader = new URLClassLoader(new URL[] {}, null);
                ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
-               adaptor.initialize(loader,null);
+               adaptor.initialize(loader, null);
                boolean exist = adaptor.generatedClassesExistFor("Junk");
-               assertFalse("There should be no generated classes",exist);
+               assertFalse("There should be no generated classes", exist);
        }
 
        public void testFlushGeneratedClasses() {
                ClassLoader loader = new URLClassLoader(new URL[] {}, null);
                ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
-               adaptor.initialize(loader,null);
+               adaptor.initialize(loader, null);
                adaptor.flushGeneratedClasses();
                boolean exist = adaptor.generatedClassesExistFor("Junk");
-               assertFalse("There should be no generated classes",exist);
+               assertFalse("There should be no generated classes", exist);
+       }
+
+       /**
+        * Testing fast excludes of the pattern "com.foo..*". World should not have any new types in it after rejection.
+        */
+       public void testFastExclusionOne() throws Exception {
+               TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "testdata..*");
+
+               String orangesSub = "testdata.sub.Oranges";
+               JavaClass orangesClass = getClassFrom(orangesSub);
+               byte[] orangesBytes = orangesClass.getBytes();
+
+               boolean accepted = adaptor.accept(orangesSub, orangesBytes);
+               assertFalse("Should not be accepted", accepted);
+               TypeMap map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               // Important thing here is that the rejection of testdata.sub.Oranges did not require it to be loaded into the world at all
+       }
+
+       /**
+        * Testing fast includes of the pattern "*". World should not have any new types in it after inclusion.
+        */
+       public void testFastInclusionOne() throws Exception {
+               TestClassLoaderWeavingAdaptor adaptor = getAdaptor("*", null);
+
+               String orangesSub = "testdata.sub.Oranges";
+               JavaClass orangesClass = getClassFrom(orangesSub);
+               byte[] orangesBytes = orangesClass.getBytes();
+
+               boolean accepted = adaptor.accept(orangesSub, orangesBytes);
+               assertTrue("Should be accepted", accepted);
+               TypeMap map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               // Important thing here is that the rejection of testdata.sub.Oranges did not require it to be loaded into the world at all
+       }
+
+       /**
+        * Testing fast excludes of the pattern "*Oranges". World should not have any new types in it after rejection.
+        */
+       public void testFastExclusionTwo() throws Exception {
+               TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "*Oranges");
+
+               String oranges = "testdata.Oranges";
+               JavaClass orangesClass = getClassFrom(oranges);
+               byte[] orangesBytes = orangesClass.getBytes();
+
+               boolean accepted = adaptor.accept(oranges, orangesBytes);
+               assertFalse("Should not be accepted", accepted);
+               TypeMap map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               String orangesSub = "testdata.sub.Oranges";
+
+               JavaClass orangesSubClass = getClassFrom(orangesSub);
+               byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+               accepted = adaptor.accept(orangesSub, orangesSubBytes);
+               assertFalse("Should not be accepted", accepted);
+               map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+       }
+
+       /**
+        * Testing fast excludes of the pattern "*..*Oranges*". World should not have any new types in it after rejection.
+        */
+       public void testFastExclusionThree() throws Exception {
+               TestClassLoaderWeavingAdaptor adaptor = getAdaptor(null, "*..*ran*");
+
+               String oranges = "testdata.Oranges";
+               JavaClass orangesClass = getClassFrom(oranges);
+               byte[] orangesBytes = orangesClass.getBytes();
+
+               boolean accepted = adaptor.accept(oranges, orangesBytes);
+               assertFalse("Should not be accepted", accepted);
+               TypeMap map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               String orangesSub = "testdata.sub.Oranges";
+               JavaClass orangesSubClass = getClassFrom(orangesSub);
+               byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+               accepted = adaptor.accept(orangesSub, orangesSubBytes);
+               assertFalse("Should not be accepted", accepted);
+               map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               String apples = "testdata.Apples";
+               JavaClass applesClass = getClassFrom(apples);
+               byte[] applesBytes = applesClass.getBytes();
+
+               accepted = adaptor.accept(apples, applesBytes);
+               assertTrue("Should be accepted", accepted);
+               map = accessTypeMap(adaptor);
+
+               // The aspect and the Apples type
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+       }
+
+       /**
+        * Testing fast inclusion checking of exact include names eg. "testdata.sub.Oranges"
+        */
+       public void testFastInclusionTwo() throws Exception {
+               TestClassLoaderWeavingAdaptor adaptor = getAdaptor("testdata.sub.Oranges", null);
+
+               String oranges = "testdata.Oranges";
+               JavaClass orangesClass = getClassFrom(oranges);
+               byte[] orangesBytes = orangesClass.getBytes();
+
+               boolean accepted = adaptor.accept(oranges, orangesBytes);
+               assertFalse("Should not be accepted", accepted);
+               TypeMap map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               String orangesSub = "testdata.sub.Oranges";
+               JavaClass orangesSubClass = getClassFrom(orangesSub);
+               byte[] orangesSubBytes = orangesSubClass.getBytes();
+
+               accepted = adaptor.accept(orangesSub, orangesSubBytes);
+               assertTrue("Should be accepted", accepted);
+               map = accessTypeMap(adaptor);
+
+               // The aspect
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
+
+               String apples = "testdata.Apples";
+               JavaClass applesClass = getClassFrom(apples);
+               byte[] applesBytes = applesClass.getBytes();
+
+               accepted = adaptor.accept(apples, applesBytes);
+               assertFalse("Should not be accepted", accepted);
+               map = accessTypeMap(adaptor);
+
+               // The aspect and the Apples type
+               assertEquals(1, map.getExpendableMap().size());
+               // primitives, void and jlObject
+               assertEquals(10, map.getMainMap().size());
        }
 
+       /**
+        * Testing fast excludes of the pattern groovy related pattern -
+        */
+       // public void testFastExclusionFour() throws Exception {
+       // TestClassLoaderWeavingAdaptor adaptor = getAdaptor("*", "testdata..* && !testdata.sub.Oran*");
+       //
+       // String oranges = "testdata.Oranges";
+       // JavaClass orangesClass = getClassFrom(oranges);
+       // byte[] orangesBytes = orangesClass.getBytes();
+       //
+       // boolean accepted = adaptor.accept(oranges, orangesBytes);
+       // assertFalse("Should not be accepted", accepted);
+       // TypeMap map = accessTypeMap(adaptor);
+       //
+       // // The aspect
+       // assertEquals(1, map.getExpendableMap().size());
+       //
+       // // primitives, void and jlObject
+       // assertEquals(10, map.getMainMap().size());
+       //
+       // String orangesSub = "testdata.sub.Oranges";
+       // JavaClass orangesSubClass = getClassFrom(orangesSub);
+       // byte[] orangesSubBytes = orangesSubClass.getBytes();
+       //
+       // accepted = adaptor.accept(orangesSub, orangesSubBytes);
+       // assertTrue("Should be accepted", accepted);
+       // map = accessTypeMap(adaptor);
+       //
+       // // The aspect
+       // assertEquals(1, map.getExpendableMap().size());
+       // // primitives, void and jlObject
+       // assertEquals(10, map.getMainMap().size());
+       // }
+
+       public void testAcceptanceSpeedStarDotDotStar() throws Exception {
+               URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+
+               JavaClass jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne");
+               byte[] bs = jc.getBytes();
+               jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB");
+               byte[] bs2 = jc.getBytes();
+               // InputStream is = loader.getResourceAsStream("org.aspectj.weaver.loadtime.ClassLoaderWeaverAdaptorTests$TestOne");
+               assertNotNull(bs);
+               TestWeavingContext wc = new TestWeavingContext(loader);
+               Definition d = new Definition();
+               d.getExcludePatterns().add("*..*CGLIB*");
+               d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+               wc.addDefinition(d);
+               ClassLoaderWeavingAdaptor adaptor = new ClassLoaderWeavingAdaptor();
+               adaptor.initialize(loader, wc);
+               boolean exist = adaptor.generatedClassesExistFor("Junk");
+               assertFalse("There should be no generated classes", exist);
+
+               // before:
+               // Acceptance 331ms
+               // Rejection 3368ms
+
+               // after:
+               // Acceptance 343ms
+               // Rejection 80ms
+
+               long stime = System.currentTimeMillis();
+               for (int i = 0; i < 100000; i++) {
+                       boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne", bs);
+                       assertTrue("Should be accepted", b);
+               }
+               long etime = System.currentTimeMillis();
+               System.out.println("Acceptance " + (etime - stime) + "ms");
+               stime = System.currentTimeMillis();
+               for (int i = 0; i < 100000; i++) {
+                       adaptor.delegateForCurrentClass = null;
+                       boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB", bs2);
+                       assertFalse("Should not be accepting CGLIB", b);
+               }
+               etime = System.currentTimeMillis();
+               System.out.println("Rejection " + (etime - stime) + "ms");
+
+       }
+
+       // TODO
+       // shouldn't add it to the type patterns if we are going to fast handle it
+       // include for exact name, what does it mean?
+       // excludes="!xxxx" should also be fast matched...
+
+       public void testAcceptanceSpeedExactName() throws Exception {
+               URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+
+               JavaClass jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne");
+               byte[] bs = jc.getBytes();
+               jc = getClassFrom("../loadtime/bin", "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB");
+               byte[] bs2 = jc.getBytes();
+               // InputStream is = loader.getResourceAsStream("org.aspectj.weaver.loadtime.ClassLoaderWeaverAdaptorTests$TestOne");
+               assertNotNull(bs);
+               TestWeavingContext wc = new TestWeavingContext(loader);
+               Definition d = new Definition();
+               d.getExcludePatterns().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest.TestOneCGLIB");
+               d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+               wc.addDefinition(d);
+               TestClassLoaderWeavingAdaptor adaptor = new TestClassLoaderWeavingAdaptor();
+               adaptor.initialize(loader, wc);
+               boolean exist = adaptor.generatedClassesExistFor("Junk");
+               assertFalse("There should be no generated classes", exist);
+
+               // before:
+               // Acceptance 331ms
+               // Rejection 3160ms
+
+               // after:
+               // Acceptance 379ms
+               // Rejection 103ms
+
+               long stime = System.currentTimeMillis();
+               for (int i = 0; i < 100000; i++) {
+                       boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOne", bs);
+                       assertTrue("Should be accepted", b);
+               }
+               long etime = System.currentTimeMillis();
+               System.out.println("Acceptance " + (etime - stime) + "ms");
+               stime = System.currentTimeMillis();
+               for (int i = 0; i < 100000; i++) {
+                       adaptor.delegateForCurrentClass = null;
+                       boolean b = adaptor.accept("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$TestOneCGLIB", bs2);
+                       assertFalse("Should not be accepting CGLIB", b);
+               }
+               etime = System.currentTimeMillis();
+               System.out.println("Rejection " + (etime - stime) + "ms");
+               BcelWorld world = adaptor.getWorld();
+               Field f = World.class.getDeclaredField("typeMap");
+               f.setAccessible(true);
+               TypeMap typeMap = (TypeMap) f.get(world);
+               System.out.println(typeMap.getExpendableMap().size());
+               System.out.println(typeMap.getMainMap().size());
+               printExpendableMap(typeMap.getExpendableMap());
+               printMainMap(typeMap.getMainMap());
+       }
+
+       // --- infrastructure ---
+
+       private TypeMap accessTypeMap(TestClassLoaderWeavingAdaptor adaptor) {
+               try {
+                       BcelWorld world = adaptor.getWorld();
+                       Field f = World.class.getDeclaredField("typeMap");
+                       f.setAccessible(true);
+                       TypeMap typeMap = (TypeMap) f.get(world);
+                       return typeMap;
+               } catch (Exception e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       public TestClassLoaderWeavingAdaptor getAdaptor(String includePattern, String excludePattern) {
+               return getAdaptor(includePattern == null ? null : new String[] { includePattern }, excludePattern == null ? null
+                               : new String[] { excludePattern });
+       }
+
+       public TestClassLoaderWeavingAdaptor getAdaptor(String[] includePatterns, String[] excludePatterns) {
+               try {
+                       URLClassLoader loader = new URLClassLoader(new URL[] { new File("../loadtime/bin").toURI().toURL() }, null);
+                       TestWeavingContext wc = new TestWeavingContext(loader);
+                       Definition d = new Definition();
+                       if (includePatterns != null) {
+                               for (String s : includePatterns) {
+                                       d.getIncludePatterns().add(s);
+                               }
+                       }
+                       if (excludePatterns != null) {
+                               for (String s : excludePatterns) {
+                                       d.getExcludePatterns().add(s);
+                               }
+                       }
+                       // need some random aspect or the weaver will shut down!
+                       d.getAspectClassNames().add("org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptorTest$AnAspect");
+                       wc.addDefinition(d);
+                       TestClassLoaderWeavingAdaptor adaptor = new TestClassLoaderWeavingAdaptor();
+                       adaptor.initialize(loader, wc);
+                       return adaptor;
+               } catch (Exception e) {
+                       throw new RuntimeException(e);
+               }
+       }
+
+       private void printMaps(TypeMap map) {
+               printExpendableMap(map.getExpendableMap());
+               printMainMap(map.getMainMap());
+       }
+
+       private void printExpendableMap(Map m) {
+               for (Object o : m.keySet()) {
+                       String sig = (String) o;
+                       System.out.println(sig + "=" + m.get(sig));
+               }
+       }
+
+       private void printMainMap(Map m) {
+               for (Object o : m.keySet()) {
+                       String sig = (String) o;
+                       System.out.println(sig + "=" + m.get(sig));
+               }
+       }
+
+       static class TestClassLoaderWeavingAdaptor extends ClassLoaderWeavingAdaptor {
+
+               public BcelWorld getWorld() {
+                       return bcelWorld;
+               }
+       }
+
+       public static JavaClass getClassFrom(String clazzname) throws ClassNotFoundException {
+               return getClassFrom("../loadtime/bin", clazzname);
+       }
+
+       public static JavaClass getClassFrom(String frompath, String clazzname) throws ClassNotFoundException {
+               SyntheticRepository repos = createRepos(frompath);
+               return repos.loadClass(clazzname);
+       }
+
+       public static SyntheticRepository createRepos(String cpentry) {
+               ClassPath cp = new ClassPath(cpentry + File.pathSeparator + System.getProperty("java.class.path"));
+               return SyntheticRepository.getInstance(cp);
+       }
+
+       @Aspect
+       class AnAspect {
+
+       }
+
+       class TestOne {
+
+       }
+
+       class TestOneCGLIB {
+
+       }
+
+       static class TestWeavingContext extends DefaultWeavingContext {
+
+               List testList = new ArrayList();
+
+               public TestWeavingContext(ClassLoader loader) {
+                       super(loader);
+               }
+
+               public void addDefinition(Definition d) {
+                       testList.add(d);
+               }
+
+               @Override
+               public List getDefinitions(final ClassLoader loader, final WeavingAdaptor adaptor) {
+                       return testList;
+               }
+       }
 }
+
+// --- testclasses and aspects ---
\ No newline at end of file