diff options
author | avasseur <avasseur> | 2005-10-26 12:43:37 +0000 |
---|---|---|
committer | avasseur <avasseur> | 2005-10-26 12:43:37 +0000 |
commit | da73b475cc03e7fd8553f2091911ce9b066da5ac (patch) | |
tree | e093084232569ac6fdcc4a4c9cca7b2a7106d2d7 | |
parent | ea305990eec2a76cfd286d060b52cab76f47def6 (diff) | |
download | aspectj-da73b475cc03e7fd8553f2091911ce9b066da5ac.tar.gz aspectj-da73b475cc03e7fd8553f2091911ce9b066da5ac.zip |
detects starttWith pattern in aop.xml include/exclude and do fast match
avoid type resolve to do aop.xml include/exclude regular match but use the passed in bytecode (else issue with Stubs not on disk as f.e. in WLS)
5 files changed, 178 insertions, 19 deletions
diff --git a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java index cdccc0e09..3c36bee68 100644 --- a/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java +++ b/loadtime/src/org/aspectj/weaver/loadtime/ClassLoaderWeavingAdaptor.java @@ -23,6 +23,8 @@ import org.aspectj.weaver.UnresolvedType; import org.aspectj.weaver.World; import org.aspectj.weaver.bcel.BcelWeaver; import org.aspectj.weaver.bcel.BcelWorld; +import org.aspectj.weaver.bcel.Utility; +import org.aspectj.weaver.bcel.BcelObjectType; import org.aspectj.weaver.loadtime.definition.Definition; import org.aspectj.weaver.loadtime.definition.DocumentParser; import org.aspectj.weaver.patterns.PatternParser; @@ -52,8 +54,11 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { private List m_dumpTypePattern = new ArrayList(); 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 List m_aspectExcludeTypePattern = new ArrayList(); - + private List m_aspectExcludeStartsWith = new ArrayList(); + private StringBuffer namespace; private IWeavingContext weavingContext; @@ -235,12 +240,17 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { } private void registerAspectExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + String fastMatchInfo = null; for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { Definition definition = (Definition) iterator.next(); for (Iterator iterator1 = definition.getAspectExcludePatterns().iterator(); iterator1.hasNext();) { String exclude = (String) iterator1.next(); TypePattern excludePattern = new PatternParser(exclude).parseTypePattern(); m_aspectExcludeTypePattern.add(excludePattern); + fastMatchInfo = looksLikeStartsWith(exclude); + if (fastMatchInfo != null) { + m_aspectExcludeStartsWith.add(fastMatchInfo); + } } } } @@ -314,28 +324,68 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { /** * Register the include / exclude filters + * We duplicate simple patterns in startWith filters that will allow faster matching without ResolvedType * * @param weaver * @param loader * @param definitions */ private void registerIncludeExclude(final BcelWeaver weaver, final ClassLoader loader, final List definitions) { + String fastMatchInfo = null; for (Iterator iterator = definitions.iterator(); iterator.hasNext();) { Definition definition = (Definition) iterator.next(); for (Iterator iterator1 = definition.getIncludePatterns().iterator(); iterator1.hasNext();) { 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); + } } for (Iterator iterator1 = definition.getExcludePatterns().iterator(); iterator1.hasNext();) { 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); + } } } } /** + * 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? + * + * @param typePattern + * @return null if not possible, or the startWith sequence to test against + */ + private String looksLikeStartsWith(String typePattern) { + if (typePattern.indexOf('@') >= 0 + || typePattern.indexOf('+') >= 0 + || typePattern.indexOf(' ') >= 0 + || typePattern.charAt(typePattern.length()-1) != '*') { + return null; + } + // now must looks like with "charsss..*" or "cha.rss..*" etc + // note that "*" and "*..*" won't be fast matched + // and that "charsss.*" will not neither + 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 + } + } + return null; + } + + /** * Register the dump filter * * @param weaver @@ -353,13 +403,41 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { } } - protected boolean accept(String className) { + protected boolean accept(String className, byte[] bytes) { // avoid ResolvedType if not needed if (m_excludeTypePattern.isEmpty() && m_includeTypePattern.isEmpty()) { return true; } - //TODO AV - optimize for className.startWith only - ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(className), 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))) { + return false; + } + } + 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)); + if (fastAccept) { + break; + } + } + if (fastAccept) { + return true; + } + + // 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()... + BcelObjectType bct = ((BcelWorld)weaver.getWorld()).addSourceObjectType(Utility.makeJavaClass(null, bytes)); + ResolvedType classInfo = bct.getResolvedTypeX();//BAD: weaver.getWorld().resolve(UnresolvedType.forName(className), true); + //exclude are "AND"ed for (Iterator iterator = m_excludeTypePattern.iterator(); iterator.hasNext();) { TypePattern typePattern = (TypePattern) iterator.next(); @@ -386,7 +464,16 @@ public class ClassLoaderWeavingAdaptor extends WeavingAdaptor { if (m_aspectExcludeTypePattern.isEmpty()) { return true; } - //TODO AV - optimize for className.startWith only + + // still try to avoid ResolvedType if we have simple patterns + String fastClassName = aspectClassName.replace('/', '.').replace('.', '$'); + for (int i = 0; i < m_aspectExcludeStartsWith.size(); i++) { + if (fastClassName.startsWith((String)m_aspectExcludeStartsWith.get(i))) { + return false; + } + } + + // needs further analysis ResolvedType classInfo = weaver.getWorld().resolve(UnresolvedType.forName(aspectClassName), true); //exclude are "AND"ed for (Iterator iterator = m_aspectExcludeTypePattern.iterator(); iterator.hasNext();) { diff --git a/tests/java5/ataspectj/ataspectj/UnweavableTest.java b/tests/java5/ataspectj/ataspectj/UnweavableTest.java index 4ce689723..a731bb886 100644 --- a/tests/java5/ataspectj/ataspectj/UnweavableTest.java +++ b/tests/java5/ataspectj/ataspectj/UnweavableTest.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.security.ProtectionDomain; +import java.io.Serializable; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @@ -76,6 +77,12 @@ public class UnweavableTest extends TestCase { assertEquals(1, TestAspect2.I); } + public void testJitNotMatched() { + // just load a jit to make sure the weaver does not complains for classes coming from nowhere + Serializable serial = getJitNoMatch(); + assertEquals(0, serial.getClass().getDeclaredMethods().length); + } + @Retention(RetentionPolicy.RUNTIME) static @interface ASome {} @@ -108,6 +115,29 @@ public class UnweavableTest extends TestCase { } } + Serializable getJitNoMatch() { + ClassWriter cw = new ClassWriter(true, true); + cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "ataspectj/unmatched/Gen", null, "java/lang/Object", new String[]{"java/io/Serializable"}); + + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, new String[0]); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(0, 0); + cw.visitEnd(); + + try { + ClassLoader loader = this.getClass().getClassLoader(); + Method def = ClassLoader.class.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class, int.class}); + def.setAccessible(true); + Class gen = (Class) def.invoke(loader, "ataspectj.unmatched.Gen", cw.toByteArray(), 0, cw.toByteArray().length); + return (Serializable) gen.newInstance(); + } catch (Throwable t) { + fail(t.toString()); + return null; + } + } + @Aspect public static class TestAspect2 { static int I = 0; diff --git a/tests/java5/ataspectj/ataspectj/aop-unweavabletest.xml b/tests/java5/ataspectj/ataspectj/aop-unweavabletest.xml index 7ed6d2905..2cb2c62c7 100644 --- a/tests/java5/ataspectj/ataspectj/aop-unweavabletest.xml +++ b/tests/java5/ataspectj/ataspectj/aop-unweavabletest.xml @@ -1,6 +1,11 @@ <?xml version="1.0"?> <aspectj> - <weaver options="-verbose -showWeaveInfo"/> + <weaver options="-verbose -showWeaveInfo"> + <!-- the pattern below will be fastmatched and it will exclude a jit class --> + <!-- as a consequence we will ask if this class is an @Aspect for special case of aspectof munging --> + <!-- and there we will do a raw BCEL parse and @Aspect annotation lookup insteead of going thru type resolve --> + <exclude within="someataspectj.unmatched..*"/> + </weaver> <aspects> <aspect name="ataspectj.UnweavableTest.TestAspect"/> <aspect name="ataspectj.UnweavableTest.TestAspect2"/> diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java index 0fa7fea16..0495515b3 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java @@ -16,6 +16,9 @@ package org.aspectj.weaver.bcel; import java.io.File; import java.io.IOException; +import java.io.DataInputStream; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Iterator; @@ -25,6 +28,7 @@ import java.util.StringTokenizer; import org.aspectj.apache.bcel.classfile.ClassParser; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.apache.bcel.classfile.annotation.Annotation; import org.aspectj.apache.bcel.generic.ConstantPoolGen; import org.aspectj.apache.bcel.generic.FieldInstruction; import org.aspectj.apache.bcel.generic.GETSTATIC; @@ -467,7 +471,7 @@ public class BcelWorld extends World implements Repository { * * @param aspect * @param kind - * @return + * @return munger */ public ConcreteTypeMunger makePerClauseAspect(ResolvedType aspect, PerClause.Kind kind) { return new BcelPerClauseAspectAdder(aspect, kind); @@ -541,4 +545,35 @@ public class BcelWorld extends World implements Repository { // e.printStackTrace(); // } } + + /** + * Checks if given bytecode is an @AspectJ aspect + * + * @param name + * @param bytes + * @return true if so + */ + public boolean isAnnotationStyleAspect(String name, byte[] bytes) { + try { + ClassParser cp = new ClassParser(new ByteArrayInputStream(bytes), null); + JavaClass jc = cp.parse(); + if (!jc.isClass()) { + return false; + } + Annotation anns[] = jc.getAnnotations(); + if (anns.length == 0) { + return false; + } + for (int i = 0; i < anns.length; i++) { + Annotation ann = anns[i]; + if ("Lorg/aspectj/lang/annotation/Aspect;".equals(ann.getTypeSignature())) { + return true; + } + } + return false; + } catch (IOException e) { + // assume it is one as a best effort + return true; + } + } } diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java index c98773e3b..eac30f383 100644 --- a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java +++ b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java @@ -33,8 +33,8 @@ import org.aspectj.bridge.IMessage.Kind; import org.aspectj.util.FileUtil; import org.aspectj.weaver.IClassFileProvider; import org.aspectj.weaver.IWeaveRequestor; -import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.UnresolvedType; +import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.bcel.BcelWeaver; import org.aspectj.weaver.bcel.BcelWorld; import org.aspectj.weaver.bcel.UnwovenClassFile; @@ -169,11 +169,11 @@ public class WeavingAdaptor { * @exception IOException weave failed */ public byte[] weaveClass (String name, byte[] bytes) throws IOException { - if (shouldWeave(name)) { + if (shouldWeave(name, bytes)) { //System.out.println("WeavingAdaptor.weaveClass " + name); info("weaving '" + name + "'"); bytes = getWovenBytes(name, bytes); - } else if (shouldWeaveAtAspect(name)) { + } else if (shouldWeaveAnnotationStyleAspect(name, bytes)) { // an @AspectJ aspect needs to be at least munged by the aspectOf munger info("weaving '" + name + "'"); bytes = getAtAspectJAspectBytes(name, bytes); @@ -186,19 +186,19 @@ public class WeavingAdaptor { * @param name * @return true if should weave (but maybe we still need to munge it for @AspectJ aspectof support) */ - private boolean shouldWeave (String name) { + private boolean shouldWeave (String name, byte[] bytes) { name = name.replace('/','.'); boolean b = enabled && !generatedClasses.containsKey(name) && shouldWeaveName(name); - return b && accept(name); -// && shouldWeaveAtAspect(name); -// // we recall shouldWeaveAtAspect as we need to add aspectOf methods for @Aspect anyway + return b && accept(name, bytes); +// && shouldWeaveAnnotationStyleAspect(name); +// // we recall shouldWeaveAnnotationStyleAspect as we need to add aspectOf methods for @Aspect anyway // //FIXME AV - this is half ok as the aspect will be weaved by others. In theory if the aspect // // is excluded from include/exclude config we should only weave late type mungers for aspectof -// return b && (accept(name) || shouldWeaveAtAspect(name)); +// return b && (accept(name) || shouldWeaveAnnotationStyleAspect(name)); } //ATAJ - protected boolean accept(String name) { + protected boolean accept(String name, byte[] bytes) { return true; } @@ -220,11 +220,13 @@ public class WeavingAdaptor { * (and not part of the source compilation) * * @param name + * @param bytes bytecode (from classloader), allow to NOT lookup stuff on disk again during resolve * @return true if @Aspect */ - private boolean shouldWeaveAtAspect(String name) { - ResolvedType type = bcelWorld.resolve(UnresolvedType.forName(name), true); - return (type == null || type.isAnnotationStyleAspect()); + private boolean shouldWeaveAnnotationStyleAspect(String name, byte[] bytes) { + // AV: instead of doing resolve that would lookup stuff on disk thru BCEL ClassLoaderRepository + // we reuse bytes[] here to do a fast lookup for @Aspect annotation + return bcelWorld.isAnnotationStyleAspect(name, bytes); } /** |