Browse Source

more overweaving tests and fixes: method call/field get/set

tags/V1_6_9M2
aclement 14 years ago
parent
commit
8764d5f36d

+ 22
- 6
weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java View File

@@ -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);
}
}
}
}

+ 60
- 209
weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java View File

@@ -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;
}
}

+ 25
- 13
weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java View File

@@ -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() {

+ 4
- 0
weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java View File

@@ -1735,4 +1735,8 @@ public final class LazyMethodGen implements Traceable {
return toShortString();
}

public ConstantPool getConstantPool() {
return enclosingClass.getConstantPool();
}

}

Loading…
Cancel
Save