diff options
author | aclement <aclement> | 2010-05-13 04:05:25 +0000 |
---|---|---|
committer | aclement <aclement> | 2010-05-13 04:05:25 +0000 |
commit | 8764d5f36d7acb2c2af4051accac4f9c1b7e830d (patch) | |
tree | e27e3d4a42b117eb1514f5a617ecbf3392d1b352 /weaver/src | |
parent | c9ddef9fd762835484653acd5434ee366a3bc04a (diff) | |
download | aspectj-8764d5f36d7acb2c2af4051accac4f9c1b7e830d.tar.gz aspectj-8764d5f36d7acb2c2af4051accac4f9c1b7e830d.zip |
more overweaving tests and fixes: method call/field get/set
Diffstat (limited to 'weaver/src')
4 files changed, 111 insertions, 228 deletions
diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java index f13d2b69e..1bef5f968 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -92,10 +92,6 @@ class BcelClassWeaver implements IClassWeaver { private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelClassWeaver.class); - /** - * This is called from {@link BcelWeaver} to perform the per-class weaving process. - * - */ public static boolean weave(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers, List<ConcreteTypeMunger> typeMungers, List lateTypeMungers, boolean inReweavableMode) { BcelClassWeaver classWeaver = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers); @@ -2503,7 +2499,7 @@ class BcelClassWeaver implements IClassWeaver { private boolean match(LazyMethodGen mg) { BcelShadow enclosingShadow; List<BcelShadow> shadowAccumulator = new ArrayList<BcelShadow>(); - + boolean isOverweaving = world.isOverWeaving(); boolean startsAngly = mg.getName().charAt(0) == '<'; // we want to match ajsynthetic constructors... if (startsAngly && mg.getName().equals("<init>")) { @@ -2520,6 +2516,10 @@ class BcelClassWeaver implements IClassWeaver { } else { AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature(); if (effective == null) { + // Don't want ajc$preClinit to be considered for matching + if (isOverweaving && mg.getName().startsWith(NameMangler.PREFIX)) { + return false; + } enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows); } else if (effective.isWeaveBody()) { ResolvedMember rm = effective.getEffectiveSignature(); @@ -3043,7 +3043,23 @@ class BcelClassWeaver implements IClassWeaver { } } else { if (canMatch(Shadow.MethodCall)) { - match(BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow), shadowAccumulator); + boolean proceed = true; + // overweaving needs to ignore some calls added by the previous weave + if (world.isOverWeaving()) { + String s = invoke.getClassName(mg.getConstantPool()); + // skip all the inc/dec/isValid/etc + if (s.equals("org.aspectj.runtime.internal.CFlowCounter") + || s.equals("org.aspectj.runtime.internal.CFlowStack")) { + proceed = false; + } else { + if (methodName.equals("aspectOf")) { + proceed = false; + } + } + } + if (proceed) { + match(BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow), shadowAccumulator); + } } } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index 0622a5170..8ca8ae963 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -1,16 +1,11 @@ /* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * Copyright (c) 2002-2010 Contributors * All rights reserved. * This program and the accompanying materials are made available * under the terms of the Eclipse Public License v1.0 * which accompanies this distribution and is available at * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * PARC initial implementation - * Alexandre Vasseur support for @AJ aspects * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.io.ByteArrayInputStream; @@ -96,6 +91,12 @@ import org.aspectj.weaver.patterns.WithinPointcut; import org.aspectj.weaver.tools.Trace; import org.aspectj.weaver.tools.TraceFactory; +/** + * + * @author PARC + * @author Andy Clement + * @author Alexandre Vasseur + */ public class BcelWeaver { public static final String CLOSURE_CLASS_PREFIX = "$Ajc"; @@ -108,14 +109,14 @@ public class BcelWeaver { private boolean inReweavableMode = false; - // private Map /*String,UnwovenClassFile*/sourceJavaClasses = new HashMap(); - // private Map /*String,UnwovenClassFile*/resources = new HashMap(); private transient List<UnwovenClassFile> addedClasses = new ArrayList<UnwovenClassFile>(); private transient List<String> deletedTypenames = new ArrayList<String>(); - private transient List<ShadowMunger> shadowMungerList = null; // setup by prepareForWeave - private transient List typeMungerList = null; // setup by prepareForWeave - private transient List lateTypeMungerList = null; // setup by prepareForWeave - private transient List declareParentsList = null; // setup by prepareForWeave + + // These four are setup by prepareForWeave + private transient List<ShadowMunger> shadowMungerList = null; + private transient List typeMungerList = null; + private transient List lateTypeMungerList = null; + private transient List declareParentsList = null; private Manifest manifest = null; private boolean needToReweaveWorld = false; @@ -125,8 +126,6 @@ public class BcelWeaver { private ZipOutputStream zipOutputStream; private CustomMungerFactory customMungerFactory; - // --- - public BcelWeaver(BcelWorld world) { super(); if (trace.isTraceEnabled()) { @@ -139,11 +138,6 @@ public class BcelWeaver { } } - // only called for testing - public void setShadowMungers(List shadowMungers) { - shadowMungerList = shadowMungers; - } - /** * Add the given aspect to the weaver. The type is resolved to support DOT for static inner classes as well as DOLLAR * @@ -230,8 +224,7 @@ public class BcelWeaver { /** * - * @param inFile File path to class directory or zip/jar class archive - * @throws IOException + * @param inFile directory containing classes or zip/jar class archive */ public void addLibraryJarFile(File inFile) throws IOException { List<ResolvedType> addedAspects = null; @@ -243,9 +236,8 @@ public class BcelWeaver { if (world.isOverWeaving()) { return; } - for (Iterator<ResolvedType> i = addedAspects.iterator(); i.hasNext();) { - ResolvedType aspectX = i.next(); - xcutSet.addOrReplaceAspect(aspectX); + for (ResolvedType addedAspect : addedAspects) { + xcutSet.addOrReplaceAspect(addedAspect); } } @@ -282,32 +274,50 @@ public class BcelWeaver { return addedAspects; } - private List<ResolvedType> addAspectsFromDirectory(File dir) throws FileNotFoundException, IOException { + /** + * Look for .class files that represent aspects in the supplied directory - return the list of accumulated aspects. + * + * @param directory the directory in which to look for Aspect .class files + * @return the list of discovered aspects + * @throws FileNotFoundException + * @throws IOException + */ + private List<ResolvedType> addAspectsFromDirectory(File directory) throws FileNotFoundException, IOException { List<ResolvedType> addedAspects = new ArrayList<ResolvedType>(); - File[] classFiles = FileUtil.listFiles(dir, new FileFilter() { - + File[] classFiles = FileUtil.listFiles(directory, new FileFilter() { public boolean accept(File pathname) { return pathname.getName().endsWith(".class"); } - }); - for (int i = 0; i < classFiles.length; i++) { - FileInputStream fis = new FileInputStream(classFiles[i]); - byte[] bytes = FileUtil.readAsByteArray(fis); - addIfAspect(bytes, classFiles[i].getAbsolutePath(), addedAspects, dir); + for (File classFile : classFiles) { + FileInputStream fis = new FileInputStream(classFile); + byte[] classBytes = FileUtil.readAsByteArray(fis); + ResolvedType aspectType = isAspect(classBytes, classFile.getAbsolutePath(), directory); + if (aspectType != null) { + addedAspects.add(aspectType); + } fis.close(); } return addedAspects; } - private void addIfAspect(byte[] bytes, String name, List<ResolvedType> toList, File dir) throws IOException { - ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), name); + /** + * Determine if the supplied bytes represent an aspect, if they do then create a ResolvedType instance for the aspect and return + * it, otherwise return null + * + * @param classbytes the classbytes that might represent an aspect + * @param name the name of the class + * @param directory directory which contained the class file + * @return a ResolvedType if the classbytes represent an aspect, otherwise null + */ + private ResolvedType isAspect(byte[] classbytes, String name, File dir) throws IOException { + ClassParser parser = new ClassParser(new ByteArrayInputStream(classbytes), name); JavaClass jc = parser.parse(); ResolvedType type = world.addSourceObjectType(jc, false).getResolvedTypeX(); String typeName = type.getName().replace('.', File.separatorChar); int end = name.lastIndexOf(typeName + ".class"); String binaryPath = null; - // if end is -1 then something wierd happened, the class file is not in + // if end is -1 then something weird happened, the class file is not in // the correct place, something like // bin/A.class when the declaration for A specifies it is in a package. if (end == -1) { @@ -316,9 +326,7 @@ public class BcelWeaver { binaryPath = name.substring(0, end - 1); } type.setBinaryPath(binaryPath); - if (type.isAspect()) { - toList.add(type); - } + return (type.isAspect() ? type : null); } // // The ANT copy task should be used to copy resources across. @@ -424,25 +432,6 @@ public class BcelWeaver { return addedClassFiles; } - // public void addResource(String name, File inPath, File outDir) throws - // IOException { - // - // /* Eliminate CVS files. Relative paths use "/" */ - // if (!name.startsWith("CVS/") && (-1 == name.indexOf("/CVS/")) && - // !name.endsWith("/CVS")) { - // // System.err.println("? addResource('" + name + "')"); - // // BufferedInputStream inStream = new BufferedInputStream(new - // FileInputStream(inPath)); - // // byte[] bytes = new byte[(int)inPath.length()]; - // // inStream.read(bytes); - // // inStream.close(); - // byte[] bytes = FileUtil.readAsByteArray(inPath); - // UnwovenClassFile resourceFile = new UnwovenClassFile(new File(outDir, - // name).getAbsolutePath(), bytes); - // addResource(name,resourceFile); - // } - // } - public boolean needToReweaveWorld() { return needToReweaveWorld; } @@ -452,10 +441,6 @@ public class BcelWeaver { */ public ReferenceType addClassFile(UnwovenClassFile classFile, boolean fromInpath) { addedClasses.add(classFile); - // if (null != sourceJavaClasses.put(classFile.getClassName(), - // classFile)) { - // // throw new RuntimeException(classFile.getClassName()); - // } ReferenceType type = world.addSourceObjectType(classFile.getJavaClass(), false).getResolvedTypeX(); if (fromInpath) { type.setBinaryPath(classFile.getFilename()); @@ -489,21 +474,9 @@ public class BcelWeaver { public void deleteClassFile(String typename) { deletedTypenames.add(typename); - // sourceJavaClasses.remove(typename); world.deleteSourceObjectType(UnresolvedType.forName(typename)); } - // public void addResource (String name, UnwovenClassFile resourceFile) { - // /* bug-44190 Change error to warning and copy first resource */ - // if (!resources.containsKey(name)) { - // resources.put(name, resourceFile); - // } - // else { - // world.showMessage(IMessage.WARNING, "duplicate resource: '" + name + "'", - // null, null); - // } - // } - // ---- weave preparation public void setIsBatchWeave(boolean b) { @@ -618,10 +591,9 @@ public class BcelWeaver { * remember their match decision on the last shadow, this makes matching faster when many pointcuts share common elements, or * even when one single pointcut has one common element (which can be a side-effect of DNF rewriting). */ - private void rewritePointcuts(List/* ShadowMunger */shadowMungers) { + private void rewritePointcuts(List<ShadowMunger> shadowMungers) { PointcutRewriter rewriter = new PointcutRewriter(); - for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) { - ShadowMunger munger = (ShadowMunger) iter.next(); + for (ShadowMunger munger : shadowMungers) { Pointcut p = munger.getPointcut(); Pointcut newP = rewriter.rewrite(p); // validateBindings now whilst we still have around the pointcut @@ -959,56 +931,6 @@ public class BcelWeaver { .getSourceLocation(), null); } - // public void dumpUnwoven(File file) throws IOException { - // BufferedOutputStream os = FileUtil.makeOutputStream(file); - // this.zipOutputStream = new ZipOutputStream(os); - // dumpUnwoven(); - // /* BUG 40943*/ - // dumpResourcesToOutJar(); - // zipOutputStream.close(); //this flushes and closes the acutal file - // } - // - // - // public void dumpUnwoven() throws IOException { - // Collection filesToDump = new HashSet(sourceJavaClasses.values()); - // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // dumpUnchanged(classFile); - // } - // } - - // public void dumpResourcesToOutPath() throws IOException { - // // System.err.println("? dumpResourcesToOutPath() resources=" + - // resources.keySet()); - // Iterator i = resources.keySet().iterator(); - // while (i.hasNext()) { - // UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); - // dumpUnchanged(res); - // } - // //resources = new HashMap(); - // } - // - /* BUG #40943 */ - // public void dumpResourcesToOutJar() throws IOException { - // // System.err.println("? dumpResourcesToOutJar() resources=" + - // resources.keySet()); - // Iterator i = resources.keySet().iterator(); - // while (i.hasNext()) { - // String name = (String)i.next(); - // UnwovenClassFile res = (UnwovenClassFile)resources.get(name); - // writeZipEntry(name,res.getBytes()); - // } - // resources = new HashMap(); - // } - // - // // halfway house for when the jar is managed outside of the weaver, but - // the resources - // // to be copied are known in the weaver. - // public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException - // { - // this.zipOutputStream = zos; - // dumpResourcesToOutJar(); - // } public void addManifest(Manifest newManifest) { // System.out.println("? addManifest() newManifest=" + newManifest); if (manifest == null) { @@ -1016,13 +938,12 @@ public class BcelWeaver { } } - private static final String WEAVER_MANIFEST_VERSION = "1.0"; - private static final Attributes.Name CREATED_BY = new Name("Created-By"); - private static final String WEAVER_CREATED_BY = "AspectJ Compiler"; - public Manifest getManifest(boolean shouldCreate) { - if (manifest == null && shouldCreate) { + String WEAVER_MANIFEST_VERSION = "1.0"; + Attributes.Name CREATED_BY = new Name("Created-By"); + String WEAVER_CREATED_BY = "AspectJ Compiler"; + manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); @@ -1035,7 +956,7 @@ public class BcelWeaver { // ---- weaving - // Used by some test cases only... + // FOR TESTING public Collection<String> weave(File file) throws IOException { OutputStream os = FileUtil.makeOutputStream(file); this.zipOutputStream = new ZipOutputStream(os); @@ -1082,80 +1003,6 @@ public class BcelWeaver { return c; } - // public Collection weave() throws IOException { - // prepareForWeave(); - // Collection filesToWeave; - // - // if (needToReweaveWorld) { - // filesToWeave = sourceJavaClasses.values(); - // } else { - // filesToWeave = addedClasses; - // } - // - // Collection wovenClassNames = new ArrayList(); - // world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + - // "(world=" + needToReweaveWorld + ")", null, null); - // - // - // //System.err.println("typeMungers: " + typeMungerList); - // - // prepareToProcessReweavableState(); - // // clear all state from files we'll be reweaving - // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // String className = classFile.getClassName(); - // BcelObjectType classType = getClassType(className); - // processReweavableStateIfPresent(className, classType); - // } - // - // - // - // //XXX this isn't quite the right place for this... - // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // String className = classFile.getClassName(); - // addTypeMungers(className); - // } - // - // // first weave into aspects - // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // String className = classFile.getClassName(); - // BcelObjectType classType = - // BcelWorld.getBcelObjectType(world.resolve(className)); - // if (classType.isAspect()) { - // weave(classFile, classType); - // wovenClassNames.add(className); - // } - // } - // - // // then weave into non-aspects - // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // String className = classFile.getClassName(); - // BcelObjectType classType = - // BcelWorld.getBcelObjectType(world.resolve(className)); - // if (! classType.isAspect()) { - // weave(classFile, classType); - // wovenClassNames.add(className); - // } - // } - // - // if (zipOutputStream != null && !needToReweaveWorld) { - // Collection filesToDump = new HashSet(sourceJavaClasses.values()); - // filesToDump.removeAll(filesToWeave); - // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { - // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - // dumpUnchanged(classFile); - // } - // } - // - // addedClasses = new ArrayList(); - // deletedTypenames = new ArrayList(); - // - // return wovenClassNames; - // } - // variation of "weave" that sources class files from an external source. public Collection<String> weave(IClassFileProvider input) throws IOException { if (trace.isTraceEnabled()) { @@ -1168,8 +1015,7 @@ public class BcelWeaver { for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { UnwovenClassFile classFile = i.next(); if (world.getModel() != null /* AsmManager.isCreatingModel() */&& !isBatchWeave) { - // remove all relationships where this file being woven is the - // target of the relationship + // remove all relationships where this file being woven is the target of the relationship world.getModelAsAsmManager().removeRelationshipsTargettingThisType(classFile.getClassName()); } } @@ -1774,7 +1620,7 @@ public class BcelWeaver { return weave(classFile, classType, false); } - // non-private for testing + // FOR TESTING LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { LazyClassGen ret = weave(classFile, classType, true); return ret; @@ -2041,4 +1887,9 @@ public class BcelWeaver { public void write(DataOutputStream dos) throws IOException { xcutSet.write(dos); } + + // only called for testing + public void setShadowMungers(List shadowMungers) { + shadowMungerList = shadowMungers; + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index fd0634ad5..af93b758c 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -909,20 +909,29 @@ public final class LazyClassGen { return clinit; } + /** + * Retrieve the ajc$preClinit method - this method captures any initialization AspectJ wants to ensure happens in a class. It is + * called from the static initializer. Maintaining this separation enables overweaving to ignore join points added due to + * earlier weaves. If the ajc$preClinit method cannot be found, it is created and a call to it is placed in the real static + * initializer (the call is placed at the start of the static initializer). + * + * @return the LazyMethodGen representing the ajc$ clinit + */ public LazyMethodGen getAjcPreClinit() { - for (Iterator i = methodGens.iterator(); i.hasNext();) { - LazyMethodGen gen = (LazyMethodGen) i.next(); - if (gen.getName().equals(NameMangler.AJC_PRE_CLINIT_NAME)) { - return gen; + if (this.isInterface()) { + throw new IllegalStateException(); + } + for (LazyMethodGen methodGen : methodGens) { + if (methodGen.getName().equals(NameMangler.AJC_PRE_CLINIT_NAME)) { + return methodGen; } } - LazyMethodGen ajcClinit = new LazyMethodGen(Modifier.STATIC, Type.VOID, NameMangler.AJC_PRE_CLINIT_NAME, new Type[0], - NO_STRINGS, this); - ajcClinit.getBody().insert(InstructionConstants.RETURN); - methodGens.add(ajcClinit); - - getStaticInitializer().getBody().insert(Utility.createInvoke(getFactory(), ajcClinit)); - return ajcClinit; + LazyMethodGen ajcPreClinit = new LazyMethodGen(Modifier.PRIVATE | Modifier.STATIC, Type.VOID, + NameMangler.AJC_PRE_CLINIT_NAME, Type.NO_ARGS, NO_STRINGS, this); + ajcPreClinit.getBody().insert(InstructionConstants.RETURN); + methodGens.add(ajcPreClinit); + getStaticInitializer().getBody().insert(Utility.createInvoke(fact, ajcPreClinit)); + return ajcPreClinit; } // reflective thisJoinPoint support @@ -1092,8 +1101,11 @@ public final class LazyClassGen { il.append(InstructionFactory.PUSH(getConstantPool(), calculatedSerialVersionUID)); il.append(getFactory().createFieldAccess(getClassName(), "serialVersionUID", BasicType.LONG, Constants.PUTSTATIC)); } - - getStaticInitializer().getBody().insert(il); + if (this.isInterface()) { // Cannot sneak stuff into another static method in an interface + getStaticInitializer().getBody().insert(il); + } else { + getAjcPreClinit().getBody().insert(il); + } } private InstructionList initializeAllTjps() { diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java index a8a7209bb..3eab53d7b 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -1735,4 +1735,8 @@ public final class LazyMethodGen implements Traceable { return toShortString(); } + public ConstantPool getConstantPool() { + return enclosingClass.getConstantPool(); + } + } |