diff options
author | Andy Clement <aclement@pivotal.io> | 2019-01-25 15:14:30 -0800 |
---|---|---|
committer | Andy Clement <aclement@pivotal.io> | 2019-01-25 15:14:30 -0800 |
commit | d3da67c03dc7d19782d60d82fdf8fc7c7895280e (patch) | |
tree | b8c82793fa0b6843e022a126f942dc132133b3fd /weaver/src/org | |
parent | 7758d629f9bc6818709d5ae97bbb98a27c908f75 (diff) | |
download | aspectj-d3da67c03dc7d19782d60d82fdf8fc7c7895280e.tar.gz aspectj-d3da67c03dc7d19782d60d82fdf8fc7c7895280e.zip |
mavenizing weaver - wip
Diffstat (limited to 'weaver/src/org')
72 files changed, 0 insertions, 33454 deletions
diff --git a/weaver/src/org/aspectj/weaver/IClassFileProvider.java b/weaver/src/org/aspectj/weaver/IClassFileProvider.java deleted file mode 100644 index 029bba7c6..000000000 --- a/weaver/src/org/aspectj/weaver/IClassFileProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.aspectj.weaver; - -import java.util.Iterator; - -import org.aspectj.weaver.bcel.UnwovenClassFile; - -/** - * @author colyer - * - * Clients implementing the IClassFileProvider can have a set of class files under their control woven by a weaver, by - * calling the weave(IClassFileProvider source) method. The contract is that a call to getRequestor().acceptResult() is - * providing a result for the class file most recently returned from the getClassFileIterator(). - */ -public interface IClassFileProvider { - - /** - * Answer an iterator that can be used to iterate over a set of UnwovenClassFiles to be woven. During a weave, this method may - * be called multiple times. - * - * @return iterator over UnwovenClassFiles. - */ - Iterator<UnwovenClassFile> getClassFileIterator(); - - /** - * The client to which the woven results should be returned. - */ - IWeaveRequestor getRequestor(); - - /** - * @return true if weaver should only do some internal munging as the one needed for @AspectJ aspectOf methods creation - */ - boolean isApplyAtAspectJMungersOnly(); - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java deleted file mode 100644 index 60aa84125..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessFieldVar.java +++ /dev/null @@ -1,186 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008 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: - * Andy Clement initial implementation - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import java.util.List; - -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.ElementValue; -import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.UnresolvedType; - -/** - * An AnnotationAccessVar represents access to a particular annotation, whilst an AnnotationAccessFieldVar represents access to a - * specific field of that annotation. - * - * @author Andy Clement - */ -class AnnotationAccessFieldVar extends BcelVar { - - private AnnotationAccessVar annoAccessor; - private ResolvedType annoFieldOfInterest; - private String name; - private int elementValueType; - - public AnnotationAccessFieldVar(AnnotationAccessVar aav, ResolvedType annoFieldOfInterest, String name) { - super(annoFieldOfInterest, 0); - this.annoAccessor = aav; - this.name = name; - String sig = annoFieldOfInterest.getSignature(); - if (sig.length() == 1) { - switch (sig.charAt(0)) { - case 'I': - elementValueType = ElementValue.PRIMITIVE_INT; - break; - default: - throw new IllegalStateException(sig); - } - } else if (sig.equals("Ljava/lang/String;")) { - elementValueType = ElementValue.STRING; - } else if (annoFieldOfInterest.isEnum()) { - elementValueType = ElementValue.ENUM_CONSTANT; - } else { - throw new IllegalStateException(sig); - } - this.annoFieldOfInterest = annoFieldOfInterest; - } - - @Override - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - // Only possible to do annotation field value extraction at MethodExecution - if (annoAccessor.getKind() != Shadow.MethodExecution) { - return; - } - String annotationOfInterestSignature = annoAccessor.getType().getSignature(); - // So we have an entity that has an annotation on and within it is the value we want - Member holder = annoAccessor.getMember(); - AnnotationAJ[] annos = holder.getAnnotations(); - for (AnnotationAJ anno : annos) { - AnnotationGen annotation = ((BcelAnnotation) anno).getBcelAnnotation(); - boolean foundValueInAnnotationUsage = false; - if (annotation.getTypeSignature().equals(annotationOfInterestSignature)) { - ResolvedMember[] annotationFields = toType.getWorld() - .resolve(UnresolvedType.forSignature(annotation.getTypeSignature())).getDeclaredMethods(); - // Check how many fields there are of the type we are looking for. If >1 then we'll need - // to use the name to choose the right one - int countOfType = 0; - for (ResolvedMember annotationField : annotationFields) { - if (annotationField.getType().equals(annoFieldOfInterest)) { - countOfType++; - } - } - - // this block deals with an annotation that has actual values (i.e. not falling back to default values) - List<NameValuePair> nvps = annotation.getValues(); - for (NameValuePair nvp : nvps) { - // If multiple of the same type, match by name - if (countOfType > 1) { - if (!nvp.getNameString().equals(name)) { - continue; - } - } - ElementValue o = nvp.getValue(); - if (o.getElementValueType() != elementValueType) { - continue; - } - if (o instanceof EnumElementValue) { - EnumElementValue v = (EnumElementValue) o; - String s = v.getEnumTypeString(); - ResolvedType rt = toType.getWorld().resolve(UnresolvedType.forSignature(s)); - if (rt.equals(toType)) { - il.append(fact.createGetStatic(rt.getName(), v.getEnumValueString(), Type.getType(rt.getSignature()))); - foundValueInAnnotationUsage = true; - } - } else if (o instanceof SimpleElementValue) { - SimpleElementValue v = (SimpleElementValue) o; - switch (v.getElementValueType()) { - case ElementValue.PRIMITIVE_INT: - il.append(fact.createConstant(v.getValueInt())); - foundValueInAnnotationUsage = true; - break; - case ElementValue.STRING: - il.append(fact.createConstant(v.getValueString())); - foundValueInAnnotationUsage = true; - break; - default: - throw new IllegalStateException("NYI: Unsupported annotation value binding for " + o); - } - } - if (foundValueInAnnotationUsage) { - break; - } - } - // this block deals with default values - if (!foundValueInAnnotationUsage) { - for (ResolvedMember annotationField : annotationFields) { - if (countOfType > 1) { - if (!annotationField.getName().equals(name)) { - continue; - } - } - if (!annotationField.getType().getSignature().equals(annoFieldOfInterest.getSignature())) { - continue; - } - if (annotationField.getType().getSignature().equals("I")) { - int ivalue = Integer.parseInt(annotationField.getAnnotationDefaultValue()); - il.append(fact.createConstant(ivalue)); - foundValueInAnnotationUsage = true; - break; - } else if (annotationField.getType().getSignature().equals("Ljava/lang/String;")) { - String svalue = annotationField.getAnnotationDefaultValue(); - il.append(fact.createConstant(svalue)); - foundValueInAnnotationUsage = true; - break; - } else { - String dvalue = annotationField.getAnnotationDefaultValue(); - // form will be LBLAHBLAHBLAH;X where X is the field within X - String typename = dvalue.substring(0, dvalue.lastIndexOf(';') + 1); - String field = dvalue.substring(dvalue.lastIndexOf(';') + 1); - ResolvedType rt = toType.getWorld().resolve(UnresolvedType.forSignature(typename)); - il.append(fact.createGetStatic(rt.getName(), field, Type.getType(rt.getSignature()))); - foundValueInAnnotationUsage = true; - break; - } - } - } - } - if (foundValueInAnnotationUsage) { - break; - } - } - } - - @Override - public void insertLoad(InstructionList il, InstructionFactory fact) { - // Only possible to do annotation field value extraction at - // MethodExecution - if (annoAccessor.getKind() != Shadow.MethodExecution) { - return; - } - appendLoadAndConvert(il, fact, annoFieldOfInterest); - } - - @Override - public String toString() { - return super.toString(); - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java deleted file mode 100644 index 88a67d666..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/AnnotationAccessVar.java +++ /dev/null @@ -1,272 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005-2008 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: - * Andy Clement initial implementation - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.Shadow.Kind; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.ast.Var; - -/** - * Represents access to an annotation on an element, relating to some kinded pointcut. Depending on the kind of pointcut the element - * might be a field or a method and the code generators in here can retrieve the annotation from the element. - */ -public class AnnotationAccessVar extends BcelVar { - - private BcelShadow shadow; - private Kind kind; // What kind of shadow are we at? - private UnresolvedType containingType; // The type upon which we want to ask for 'member' - private Member member; // Holds the member that has the annotations (for method/field join points) - private boolean isWithin; // implies @within() or @withincode(). If false, that implies @annotation() - - public AnnotationAccessVar(BcelShadow shadow, Kind kind, ResolvedType annotationType, UnresolvedType theTargetIsStoredHere, - Member sig, boolean isWithin) { - super(annotationType, 0); - this.shadow = shadow; - this.kind = kind; - this.containingType = theTargetIsStoredHere; - this.member = sig; - this.isWithin = isWithin; - } - - public Kind getKind() { - return kind; - } - - @Override - public String toString() { - return "AnnotationAccessVar(" + getType() + ")"; - } - - @Override - public Instruction createLoad(InstructionFactory fact) { - throw new IllegalStateException("unimplemented"); - } - - @Override - public Instruction createStore(InstructionFactory fact) { - throw new IllegalStateException("unimplemented"); - } - - @Override - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - throw new IllegalStateException("unimplemented"); - } - - @Override - public void appendLoad(InstructionList il, InstructionFactory fact) { - il.append(createLoadInstructions(getType(), fact)); - } - - @Override - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - il.append(createLoadInstructions(toType, fact)); - } - - @Override - public void insertLoad(InstructionList il, InstructionFactory fact) { - il.insert(createLoadInstructions(getType(), fact)); - } - - private InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) { - - InstructionList il = new InstructionList(); - - Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS); - Type jlString = BcelWorld.makeBcelType(UnresolvedType.JL_STRING); - Type jlClassArray = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_CLASS_ARRAY); - Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_ANNOTATION); - - Instruction pushConstant = fact.createConstant(new ObjectType(toType.getName())); - - if (kind == Shadow.MethodCall || kind == Shadow.MethodExecution || kind == Shadow.PreInitialization - || kind == Shadow.Initialization || kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution - || kind == Shadow.AdviceExecution || - // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD - ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD)) { - - Type jlrMethod = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/reflect/Method;")); - Type jlAnnotation = BcelWorld.makeBcelType(UnresolvedType.forSignature("Ljava/lang/annotation/Annotation;")); - Type[] paramTypes = BcelWorld.makeBcelTypes(member.getParameterTypes()); - - // il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); - - if (kind == Shadow.MethodCall - || kind == Shadow.MethodExecution - || kind == Shadow.AdviceExecution - || - // annotations for fieldset/fieldget when an ITD is involved are stored against a METHOD - ((kind == Shadow.FieldGet || kind == Shadow.FieldSet) && member.getKind() == Member.METHOD) - || ((kind == Shadow.ConstructorCall || kind == Shadow.ConstructorExecution) && member.getKind() == Member.METHOD)) { - - // Need to look at the cached annotation before going to fetch it again - Field annotationCachingField = shadow.getEnclosingClass().getAnnotationCachingField(shadow, toType, isWithin); - - // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it - il.append(fact.createGetStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation)); - il.append(InstructionConstants.DUP); - InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); - il.append(ifNonNull); - il.append(InstructionConstants.POP); - il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); - - il.append(fact.createConstant(member.getName())); - buildArray(il, fact, jlClass, paramTypes, 1); - // OPTIMIZE cache result of getDeclaredMethod? - il.append(fact.createInvoke("java/lang/Class", "getDeclaredMethod", jlrMethod, - new Type[] { jlString, jlClassArray }, Constants.INVOKEVIRTUAL)); - il.append(pushConstant);// fact.createConstant(new ObjectType(toType.getName()))); - il.append(fact.createInvoke("java/lang/reflect/Method", "getAnnotation", jlaAnnotation, new Type[] { jlClass }, - Constants.INVOKEVIRTUAL)); - il.append(InstructionConstants.DUP); - il.append(fact.createPutStatic(shadow.getEnclosingClass().getName(), annotationCachingField.getName(), jlAnnotation)); - InstructionHandle ifNullElse = il.append(InstructionConstants.NOP); - ifNonNull.setTarget(ifNullElse); - - } else { // init/preinit/ctor-call/ctor-exec - il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); - buildArray(il, fact, jlClass, paramTypes, 1); - Type jlrCtor = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_CONSTRUCTOR); - // OPTIMIZE cache result of getDeclaredConstructor and getAnnotation? Might be able to use it again if someone else - // needs the same annotations? - il.append(fact.createInvoke("java/lang/Class", "getDeclaredConstructor", jlrCtor, new Type[] { jlClassArray }, - Constants.INVOKEVIRTUAL)); - il.append(pushConstant); - il.append(fact.createInvoke("java/lang/reflect/Constructor", "getAnnotation", jlaAnnotation, - new Type[] { jlClass }, Constants.INVOKEVIRTUAL)); - } - } else if (kind == Shadow.FieldSet || kind == Shadow.FieldGet) { - generateBytecodeToAccessAnnotationAtFieldGetSetShadow(toType, fact, il, pushConstant); - } else if (kind == Shadow.StaticInitialization || kind == Shadow.ExceptionHandler) { - il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); - il.append(pushConstant); - il.append(fact.createInvoke("java/lang/Class", "getAnnotation", jlaAnnotation, new Type[] { jlClass }, - Constants.INVOKEVIRTUAL)); - } else { - throw new RuntimeException("Don't understand this kind " + kind); - } - il.append(Utility.createConversion(fact, jlaAnnotation, BcelWorld.makeBcelType(toType))); - return il; - } - - /** - * At a FieldGet or FieldSet shadow, generate the bytecode to access the annotation for that field. The annotation is cached so - * the code checks that cached value before proceeding. - */ - private void generateBytecodeToAccessAnnotationAtFieldGetSetShadow(ResolvedType toType, InstructionFactory fact, - InstructionList il, Instruction pushConstantAnnotationType) { - Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS); - Type jlString = BcelWorld.makeBcelType(UnresolvedType.JL_STRING); - Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_ANNOTATION); - Type jlrField = BcelWorld.makeBcelType(UnresolvedType.JAVA_LANG_REFLECT_FIELD); - - LazyClassGen shadowEnclosingClass = shadow.getEnclosingClass(); - - // The annotation for the field of interest is cached, check cached value before fetching it - Field annotationCachingField = shadowEnclosingClass.getAnnotationCachingField(shadow, toType, isWithin); - String annotationCachingFieldName = annotationCachingField.getName(); - - // Basic idea here is to check if the cached field is null, if it is then initialize it, otherwise use it - il.append(fact.createGetStatic(shadowEnclosingClass.getName(), annotationCachingFieldName, jlaAnnotation)); - il.appendDUP(); - InstructionBranch ifNonNull = new InstructionBranch(Constants.IFNONNULL, null); - il.append(ifNonNull); - il.appendPOP(); - - // get the field of interest - il.append(fact.createConstant(BcelWorld.makeBcelType(containingType))); - il.append(fact.createConstant(member.getName())); - il.append(fact.createInvoke("java/lang/Class", "getDeclaredField", jlrField, new Type[] { jlString }, - Constants.INVOKEVIRTUAL)); - il.append(pushConstantAnnotationType); - il.append(fact.createInvoke("java/lang/reflect/Field", "getAnnotation", jlaAnnotation, new Type[] { jlClass }, - Constants.INVOKEVIRTUAL)); - il.appendDUP(); - il.append(fact.createPutStatic(shadowEnclosingClass.getName(), annotationCachingFieldName, jlaAnnotation)); - InstructionHandle ifNullElse = il.appendNOP(); - ifNonNull.setTarget(ifNullElse); - } - - private void buildArray(InstructionList il, InstructionFactory fact, Type arrayElementType, Type[] arrayEntries, int dim) { - il.append(fact.createConstant(Integer.valueOf(arrayEntries == null ? 0 : arrayEntries.length))); - il.append(fact.createNewArray(arrayElementType, (short) dim)); - if (arrayEntries == null) { - return; - } - for (int i = 0; i < arrayEntries.length; i++) { - il.append(InstructionFactory.createDup(1)); - il.append(fact.createConstant(Integer.valueOf(i))); - switch (arrayEntries[i].getType()) { - case Constants.T_ARRAY: - il.append(fact.createConstant(new ObjectType(arrayEntries[i].getSignature()))); // FIXME should be getName() and not - // getSignature()? - break; - case Constants.T_BOOLEAN: - il.append(fact.createGetStatic("java/lang/Boolean", "TYPE", arrayElementType)); - break; - case Constants.T_BYTE: - il.append(fact.createGetStatic("java/lang/Byte", "TYPE", arrayElementType)); - break; - case Constants.T_CHAR: - il.append(fact.createGetStatic("java/lang/Character", "TYPE", arrayElementType)); - break; - case Constants.T_INT: - il.append(fact.createGetStatic("java/lang/Integer", "TYPE", arrayElementType)); - break; - case Constants.T_LONG: - il.append(fact.createGetStatic("java/lang/Long", "TYPE", arrayElementType)); - break; - case Constants.T_DOUBLE: - il.append(fact.createGetStatic("java/lang/Double", "TYPE", arrayElementType)); - break; - case Constants.T_FLOAT: - il.append(fact.createGetStatic("java/lang/Float", "TYPE", arrayElementType)); - break; - case Constants.T_SHORT: - il.append(fact.createGetStatic("java/lang/Short", "TYPE", arrayElementType)); - break; - default: - il.append(fact.createConstant(arrayEntries[i])); - } - il.append(InstructionConstants.AASTORE); - } - } - - public Member getMember() { - return member; - } - - /** - * Return an object that can access a particular value of this annotation. - * - * @param valueType The type from the annotation that is of interest - * @param the formal name expressed in the pointcut, can be used to disambiguate - * @return a variable that represents access to that annotation value - */ - @Override - public Var getAccessorForValue(ResolvedType valueType, String formalName) { - return new AnnotationAccessFieldVar(this, valueType, formalName); - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/AspectInstanceVar.java b/weaver/src/org/aspectj/weaver/bcel/AspectInstanceVar.java deleted file mode 100644 index 37633b71f..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/AspectInstanceVar.java +++ /dev/null @@ -1,119 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2011 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: - * Andy Clement - SpringSource/vmware - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.weaver.ResolvedType; - -/** - * Used to represent a variable reference to an aspect instance. This is used to support the if pointcut usage of - * 'thisAspectInstance'. This variable does not have a slot, instead on requesting a reference we call aspectOf() on the aspect in - * question to retrieve it. For now it only works with singleton aspects. - */ -public class AspectInstanceVar extends BcelVar { - - public AspectInstanceVar(ResolvedType type) { - super(type, -1); - } - - // fact is used in the subtypes - public Instruction createLoad(InstructionFactory fact) { - - throw new IllegalStateException(); - // return InstructionFactory.createLoad(BcelWorld.makeBcelType(getType()), slot); - } - - public Instruction createStore(InstructionFactory fact) { - throw new IllegalStateException(); - // return InstructionFactory.createStore(BcelWorld.makeBcelType(getType()), slot); - } - - public void appendStore(InstructionList il, InstructionFactory fact) { - throw new IllegalStateException(); - // il.append(createStore(fact)); - } - - public void appendLoad(InstructionList il, InstructionFactory fact) { - throw new IllegalStateException(); - // il.append(createLoad(fact)); - } - - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - throw new IllegalStateException(); - // il.append(createLoad(fact)); - // Utility.appendConversion(il, fact, getType(), toType); - } - - public void insertLoad(InstructionList il, InstructionFactory fact) { - InstructionList loadInstructions = new InstructionList(); - loadInstructions.append(fact.createInvoke(getType().getName(), "aspectOf", "()" + getType().getSignature(), - Constants.INVOKESTATIC)); - il.insert(loadInstructions); - // throw new IllegalStateException(); - // il.insert(createLoad(fact)); - } - - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - throw new IllegalStateException(); - // InstructionList il = new InstructionList(); - // il.append(InstructionFactory.createLoad(BcelWorld.makeBcelType(getType()), oldSlot)); - // il.append(createStore(fact)); - // return il; - } - - // this is an array var - void appendConvertableArrayLoad(InstructionList il, InstructionFactory fact, int index, ResolvedType convertTo) { - throw new IllegalStateException(); - // ResolvedType convertFromType = getType().getResolvedComponentType(); - // appendLoad(il, fact); - // il.append(Utility.createConstant(fact, index)); - // il.append(InstructionFactory.createArrayLoad(BcelWorld.makeBcelType(convertFromType))); - // Utility.appendConversion(il, fact, convertFromType, convertTo); - } - - void appendConvertableArrayStore(InstructionList il, InstructionFactory fact, int index, BcelVar storee) { - throw new IllegalStateException(); - // ResolvedType convertToType = getType().getResolvedComponentType(); - // appendLoad(il, fact); - // il.append(Utility.createConstant(fact, index)); - // storee.appendLoad(il, fact); - // Utility.appendConversion(il, fact, storee.getType(), convertToType); - // il.append(InstructionFactory.createArrayStore(BcelWorld.makeBcelType(convertToType))); - } - - InstructionList createConvertableArrayStore(InstructionFactory fact, int index, BcelVar storee) { - throw new IllegalStateException(); - // InstructionList il = new InstructionList(); - // appendConvertableArrayStore(il, fact, index, storee); - // return il; - } - - InstructionList createConvertableArrayLoad(InstructionFactory fact, int index, ResolvedType convertTo) { - throw new IllegalStateException(); - // InstructionList il = new InstructionList(); - // appendConvertableArrayLoad(il, fact, index, convertTo); - // return il; - } - - public int getPositionInAroundState() { - throw new IllegalStateException(); - // return positionInAroundState; - } - - public void setPositionInAroundState(int positionInAroundState) { - throw new IllegalStateException(); - // this.positionInAroundState = positionInAroundState; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java b/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java deleted file mode 100644 index 2da044c11..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/AtAjAttributes.java +++ /dev/null @@ -1,2046 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.Constant; -import org.aspectj.apache.bcel.classfile.ConstantUtf8; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.LocalVariable; -import org.aspectj.apache.bcel.classfile.LocalVariableTable; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.Unknown; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; -import org.aspectj.apache.bcel.classfile.annotation.ClassElementValue; -import org.aspectj.apache.bcel.classfile.annotation.ElementValue; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.apache.bcel.classfile.annotation.RuntimeAnnos; -import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisAnnos; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.asm.AsmManager; -import org.aspectj.asm.IHierarchy; -import org.aspectj.asm.IProgramElement; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.BindingScope; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.MethodDelegateTypeMunger; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedPointcutDefinition; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.VersionedDataInputStream; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.World; -import org.aspectj.weaver.patterns.DeclareErrorOrWarning; -import org.aspectj.weaver.patterns.DeclareParents; -import org.aspectj.weaver.patterns.DeclareParentsMixin; -import org.aspectj.weaver.patterns.DeclarePrecedence; -import org.aspectj.weaver.patterns.FormalBinding; -import org.aspectj.weaver.patterns.IScope; -import org.aspectj.weaver.patterns.ParserException; -import org.aspectj.weaver.patterns.PatternParser; -import org.aspectj.weaver.patterns.PerCflow; -import org.aspectj.weaver.patterns.PerClause; -import org.aspectj.weaver.patterns.PerFromSuper; -import org.aspectj.weaver.patterns.PerObject; -import org.aspectj.weaver.patterns.PerSingleton; -import org.aspectj.weaver.patterns.PerTypeWithin; -import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.TypePattern; - -/** - * Annotation defined aspect reader. Reads the Java 5 annotations and turns them into AjAttributes - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ -public class AtAjAttributes { - - private final static List<AjAttribute> NO_ATTRIBUTES = Collections.emptyList(); - private final static String[] EMPTY_STRINGS = new String[0]; - private final static String VALUE = "value"; - private final static String ARGNAMES = "argNames"; - private final static String POINTCUT = "pointcut"; - private final static String THROWING = "throwing"; - private final static String RETURNING = "returning"; - private final static String STRING_DESC = "Ljava/lang/String;"; - private final static String ASPECTJ_ANNOTATION_PACKAGE = "org.aspectj.lang.annotation"; - private final static char PACKAGE_INITIAL_CHAR = ASPECTJ_ANNOTATION_PACKAGE.charAt(0); - - /** - * A struct that allows to add extra arguments without always breaking the API - */ - private static class AjAttributeStruct { - - /** - * The list of AjAttribute.XXX that we are populating from the @AJ read - */ - List<AjAttribute> ajAttributes = new ArrayList<AjAttribute>(); - - /** - * The resolved type (class) for which we are reading @AJ for (be it class, method, field annotations) - */ - final ResolvedType enclosingType; - - final ISourceContext context; - final IMessageHandler handler; - - public AjAttributeStruct(ResolvedType type, ISourceContext sourceContext, IMessageHandler messageHandler) { - enclosingType = type; - context = sourceContext; - handler = messageHandler; - } - } - - /** - * A struct when we read @AJ on method - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ - private static class AjAttributeMethodStruct extends AjAttributeStruct { - - // argument names used for formal binding - private String[] m_argumentNamesLazy = null; - public String unparsedArgumentNames = null; // Set only if discovered as - // argNames attribute of - // annotation - - final Method method; - final BcelMethod bMethod; - - public AjAttributeMethodStruct(Method method, BcelMethod bMethod, ResolvedType type, ISourceContext sourceContext, - IMessageHandler messageHandler) { - super(type, sourceContext, messageHandler); - this.method = method; - this.bMethod = bMethod; - } - - public String[] getArgumentNames() { - if (m_argumentNamesLazy == null) { - m_argumentNamesLazy = getMethodArgumentNames(method, unparsedArgumentNames, this); - } - return m_argumentNamesLazy; - } - } - - /** - * A struct when we read @AJ on field - */ - private static class AjAttributeFieldStruct extends AjAttributeStruct { - - final Field field; - - // final BcelField bField; - - public AjAttributeFieldStruct(Field field, BcelField bField, ResolvedType type, ISourceContext sourceContext, - IMessageHandler messageHandler) { - super(type, sourceContext, messageHandler); - this.field = field; - // this.bField = bField; - } - } - - /** - * Annotations are RuntimeVisible only. This allow us to not visit RuntimeInvisible ones. - * - * @param attribute - * @return true if runtime visible annotation - */ - public static boolean acceptAttribute(Attribute attribute) { - return (attribute instanceof RuntimeVisAnnos); - } - - /** - * Extract class level annotations and turn them into AjAttributes. - * - * @param javaClass - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes - */ - public static List<AjAttribute> readAj5ClassAttributes(AsmManager model, JavaClass javaClass, ReferenceType type, - ISourceContext context, IMessageHandler msgHandler, boolean isCodeStyleAspect) { - boolean ignoreThisClass = javaClass.getClassName().charAt(0) == PACKAGE_INITIAL_CHAR - && javaClass.getClassName().startsWith(ASPECTJ_ANNOTATION_PACKAGE); - if (ignoreThisClass) { - return NO_ATTRIBUTES; - } - boolean containsPointcut = false; - boolean containsAnnotationClassReference = false; - Constant[] cpool = javaClass.getConstantPool().getConstantPool(); - for (int i = 0; i < cpool.length; i++) { - Constant constant = cpool[i]; - if (constant != null && constant.getTag() == Constants.CONSTANT_Utf8) { - String constantValue = ((ConstantUtf8) constant).getValue(); - if (constantValue.length() > 28 && constantValue.charAt(1) == PACKAGE_INITIAL_CHAR) { - if (constantValue.startsWith("Lorg/aspectj/lang/annotation")) { - containsAnnotationClassReference = true; - if ("Lorg/aspectj/lang/annotation/DeclareAnnotation;".equals(constantValue)) { - msgHandler.handleMessage(new Message( - "Found @DeclareAnnotation while current release does not support it (see '" + type.getName() - + "')", IMessage.WARNING, null, type.getSourceLocation())); - } - if ("Lorg/aspectj/lang/annotation/Pointcut;".equals(constantValue)) { - containsPointcut = true; - } - } - - } - } - } - if (!containsAnnotationClassReference) { - return NO_ATTRIBUTES; - } - - AjAttributeStruct struct = new AjAttributeStruct(type, context, msgHandler); - Attribute[] attributes = javaClass.getAttributes(); - boolean hasAtAspectAnnotation = false; - boolean hasAtPrecedenceAnnotation = false; - - WeaverVersionInfo wvinfo = null; - for (int i = 0; i < attributes.length; i++) { - Attribute attribute = attributes[i]; - if (acceptAttribute(attribute)) { - RuntimeAnnos rvs = (RuntimeAnnos) attribute; - // we don't need to look for several attribute occurrences since - // it cannot happen as per JSR175 - if (!isCodeStyleAspect && !javaClass.isInterface()) { - hasAtAspectAnnotation = handleAspectAnnotation(rvs, struct); - // TODO AV - if put outside the if isCodeStyleAspect then we - // would enable mix style - hasAtPrecedenceAnnotation = handlePrecedenceAnnotation(rvs, struct); - } - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - for (int i = attributes.length - 1; i >= 0; i--) { - Attribute attribute = attributes[i]; - if (attribute.getName().equals(WeaverVersionInfo.AttributeName)) { - try { - VersionedDataInputStream s = new VersionedDataInputStream(new ByteArrayInputStream( - ((Unknown) attribute).getBytes()), null); - wvinfo = WeaverVersionInfo.read(s); - struct.ajAttributes.add(0, wvinfo); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - } - if (wvinfo == null) { - // If we are in here due to a resetState() call (presumably because of reweavable state processing), the - // original type delegate will have been set with a version but that version will be missing from - // the new set of attributes (looks like a bug where the version attribute was not included in the - // data compressed into the attribute). So rather than 'defaulting' to current, we should use one - // if it set on the delegate for the type. - ReferenceTypeDelegate delegate = type.getDelegate(); - if (delegate instanceof BcelObjectType) { - wvinfo = ((BcelObjectType) delegate).getWeaverVersionAttribute(); - if (wvinfo != null) { - if (wvinfo.getMajorVersion() != WeaverVersionInfo.WEAVER_VERSION_MAJOR_UNKNOWN) { - // use this one - struct.ajAttributes.add(0, wvinfo); - } else { - wvinfo = null; - } - } - } - if (wvinfo == null) { - struct.ajAttributes.add(0, wvinfo = new AjAttribute.WeaverVersionInfo()); - } - } - - // basic semantic check - if (hasAtPrecedenceAnnotation && !hasAtAspectAnnotation) { - msgHandler.handleMessage(new Message("Found @DeclarePrecedence on a non @Aspect type '" + type.getName() + "'", - IMessage.WARNING, null, type.getSourceLocation())); - // bypass what we have read - return NO_ATTRIBUTES; - } - - // the following block will not detect @Pointcut in non @Aspect types - // for optimization purpose - if (!(hasAtAspectAnnotation || isCodeStyleAspect) && !containsPointcut) { - return NO_ATTRIBUTES; - } - - // FIXME AV - turn on when ajcMightHaveAspect - // if (hasAtAspectAnnotation && type.isInterface()) { - // msgHandler.handleMessage( - // new Message( - // "Found @Aspect on an interface type '" + type.getName() + "'", - // IMessage.WARNING, - // null, - // type.getSourceLocation() - // ) - // ); - // // bypass what we have read - // return EMPTY_LIST; - // } - - // semantic check: @Aspect must be public - // FIXME AV - do we really want to enforce that? - // if (hasAtAspectAnnotation && !javaClass.isPublic()) { - // msgHandler.handleMessage( - // new Message( - // "Found @Aspect annotation on a non public class '" + - // javaClass.getClassName() + "'", - // IMessage.ERROR, - // null, - // type.getSourceLocation() - // ) - // ); - // return EMPTY_LIST; - // } - - // code style pointcuts are class attributes - // we need to gather the @AJ pointcut right now and not at method level - // annotation extraction time - // in order to be able to resolve the pointcut references later on - // we don't need to look in super class, the pointcut reference in the - // grammar will do it - - for (int i = 0; i < javaClass.getMethods().length; i++) { - Method method = javaClass.getMethods()[i]; - if (method.getName().startsWith(NameMangler.PREFIX)) { - continue; // already dealt with by ajc... - } - // FIXME alex optimize, this method struct will gets recreated for - // advice extraction - AjAttributeMethodStruct mstruct = null; - boolean processedPointcut = false; - Attribute[] mattributes = method.getAttributes(); - for (int j = 0; j < mattributes.length; j++) { - Attribute mattribute = mattributes[j]; - if (acceptAttribute(mattribute)) { - // TODO speed all this nonsense up rather than looking - // through all the annotations every time - // same for fields - mstruct = new AjAttributeMethodStruct(method, null, type, context, msgHandler); - processedPointcut = handlePointcutAnnotation((RuntimeAnnos) mattribute, mstruct); - if (!processedPointcut) { - processedPointcut = handleDeclareMixinAnnotation((RuntimeAnnos) mattribute, mstruct); - } - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - if (processedPointcut) { - struct.ajAttributes.addAll(mstruct.ajAttributes); - } - } - - // code style declare error / warning / implements / parents are field - // attributes - Field[] fs = javaClass.getFields(); - for (int i = 0; i < fs.length; i++) { - Field field = fs[i]; - if (field.getName().startsWith(NameMangler.PREFIX)) { - continue; // already dealt with by ajc... - } - // FIXME alex optimize, this method struct will gets recreated for - // advice extraction - AjAttributeFieldStruct fstruct = new AjAttributeFieldStruct(field, null, type, context, msgHandler); - Attribute[] fattributes = field.getAttributes(); - - for (int j = 0; j < fattributes.length; j++) { - Attribute fattribute = fattributes[j]; - if (acceptAttribute(fattribute)) { - RuntimeAnnos frvs = (RuntimeAnnos) fattribute; - if (handleDeclareErrorOrWarningAnnotation(model, frvs, fstruct) - || handleDeclareParentsAnnotation(frvs, fstruct)) { - // semantic check - must be in an @Aspect [remove if - // previous block bypassed in advance] - if (!type.isAnnotationStyleAspect() && !isCodeStyleAspect) { - msgHandler.handleMessage(new Message("Found @AspectJ annotations in a non @Aspect type '" - + type.getName() + "'", IMessage.WARNING, null, type.getSourceLocation())); - // go ahead - } - } - // there can only be one RuntimeVisible bytecode attribute - break; - } - } - struct.ajAttributes.addAll(fstruct.ajAttributes); - } - - return struct.ajAttributes; - } - - /** - * Extract method level annotations and turn them into AjAttributes. - * - * @param method - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes - */ - public static List<AjAttribute> readAj5MethodAttributes(Method method, BcelMethod bMethod, ResolvedType type, - ResolvedPointcutDefinition preResolvedPointcut, ISourceContext context, IMessageHandler msgHandler) { - if (method.getName().startsWith(NameMangler.PREFIX)) { - return Collections.emptyList(); // already dealt with by ajc... - } - - AjAttributeMethodStruct struct = new AjAttributeMethodStruct(method, bMethod, type, context, msgHandler); - Attribute[] attributes = method.getAttributes(); - - // we remember if we found one @AJ annotation for minimal semantic error - // reporting - // the real reporting beeing done thru AJDT and the compiler mapping @AJ - // to AjAtttribute - // or thru APT - // - // Note: we could actually skip the whole thing if type is not itself an - // @Aspect - // but then we would not see any warning. We do bypass for pointcut but - // not for advice since it would - // be too silent. - boolean hasAtAspectJAnnotation = false; - boolean hasAtAspectJAnnotationMustReturnVoid = false; - for (int i = 0; i < attributes.length; i++) { - Attribute attribute = attributes[i]; - try { - if (acceptAttribute(attribute)) { - RuntimeAnnos rvs = (RuntimeAnnos) attribute; - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid - || handleBeforeAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid - || handleAfterAnnotation(rvs, struct, preResolvedPointcut); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid - || handleAfterReturningAnnotation(rvs, struct, preResolvedPointcut, bMethod); - hasAtAspectJAnnotationMustReturnVoid = hasAtAspectJAnnotationMustReturnVoid - || handleAfterThrowingAnnotation(rvs, struct, preResolvedPointcut, bMethod); - hasAtAspectJAnnotation = hasAtAspectJAnnotation || handleAroundAnnotation(rvs, struct, preResolvedPointcut); - // there can only be one RuntimeVisible bytecode attribute - break; - } - } catch (ReturningFormalNotDeclaredInAdviceSignatureException e) { - msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.RETURNING_FORMAL_NOT_DECLARED_IN_ADVICE, - e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); - } catch (ThrownFormalNotDeclaredInAdviceSignatureException e) { - msgHandler.handleMessage(new Message(WeaverMessages.format(WeaverMessages.THROWN_FORMAL_NOT_DECLARED_IN_ADVICE, - e.getFormalName()), IMessage.ERROR, null, bMethod.getSourceLocation())); - } - } - hasAtAspectJAnnotation = hasAtAspectJAnnotation || hasAtAspectJAnnotationMustReturnVoid; - - // semantic check - must be in an @Aspect [remove if previous block - // bypassed in advance] - if (hasAtAspectJAnnotation && !type.isAspect()) { // isAnnotationStyleAspect()) - // { - msgHandler.handleMessage(new Message("Found @AspectJ annotations in a non @Aspect type '" + type.getName() + "'", - IMessage.WARNING, null, type.getSourceLocation())); - // go ahead - } - // semantic check - advice must be public - if (hasAtAspectJAnnotation && !struct.method.isPublic()) { - msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non public advice '" - + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation())); - // go ahead - } - - // semantic check - advice must not be static - if (hasAtAspectJAnnotation && struct.method.isStatic()) { - msgHandler.handleMessage(MessageUtil.error("Advice cannot be declared static '" + methodToString(struct.method) + "'", - type.getSourceLocation())); - // new Message( - // "Advice cannot be declared static '" + - // methodToString(struct.method) + "'", - // IMessage.ERROR, - // null, - // type.getSourceLocation() - // ) - // ); - // go ahead - } - - // semantic check for non around advice must return void - if (hasAtAspectJAnnotationMustReturnVoid && !Type.VOID.equals(struct.method.getReturnType())) { - msgHandler.handleMessage(new Message("Found @AspectJ annotation on a non around advice not returning void '" - + methodToString(struct.method) + "'", IMessage.ERROR, null, type.getSourceLocation())); - // go ahead - } - - return struct.ajAttributes; - } - - /** - * Extract field level annotations and turn them into AjAttributes. - * - * @param field - * @param type - * @param context - * @param msgHandler - * @return list of AjAttributes, always empty for now - */ - public static List<AjAttribute> readAj5FieldAttributes(Field field, BcelField bField, ResolvedType type, - ISourceContext context, IMessageHandler msgHandler) { - // Note: field annotation are for ITD and DEOW - processed at class - // level directly - return Collections.emptyList(); - } - - /** - * Read @Aspect - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAspectAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) { - AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.ASPECT_ANNOTATION); - if (aspect != null) { - // semantic check for inheritance (only one level up) - boolean extendsAspect = false; - if (!"java.lang.Object".equals(struct.enclosingType.getSuperclass().getName())) { - if (!struct.enclosingType.getSuperclass().isAbstract() && struct.enclosingType.getSuperclass().isAspect()) { - reportError("cannot extend a concrete aspect", struct); - return false; - } - extendsAspect = struct.enclosingType.getSuperclass().isAspect(); - } - - NameValuePair aspectPerClause = getAnnotationElement(aspect, VALUE); - final PerClause perClause; - if (aspectPerClause == null) { - // empty value means singleton unless inherited - if (!extendsAspect) { - perClause = new PerSingleton(); - } else { - perClause = new PerFromSuper(struct.enclosingType.getSuperclass().getPerClause().getKind()); - } - } else { - String perX = aspectPerClause.getValue().stringifyValue(); - if (perX == null || perX.length() <= 0) { - perClause = new PerSingleton(); - } else { - perClause = parsePerClausePointcut(perX, struct); - } - } - if (perClause == null) { - // could not parse it, ignore the aspect - return false; - } else { - perClause.setLocation(struct.context, -1, -1);// struct.context.getOffset(), - // struct.context.getOffset()+1);//FIXME - // AVASM - // Not setting version here - // struct.ajAttributes.add(new AjAttribute.WeaverVersionInfo()); - AjAttribute.Aspect aspectAttribute = new AjAttribute.Aspect(perClause); - struct.ajAttributes.add(aspectAttribute); - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - final IScope binding; - binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // // we can't resolve here since the perclause typically refers - // to pointcuts - // // defined in the aspect that we haven't told the - // BcelObjectType about yet. - // - // perClause.resolve(binding); - - // so we prepare to do it later... - aspectAttribute.setResolutionScope(binding); - return true; - } - } - return false; - } - - /** - * Read a perClause, returns null on failure and issue messages - * - * @param perClauseString like "pertarget(.....)" - * @param struct for which we are parsing the per clause - * @return a PerClause instance - */ - private static PerClause parsePerClausePointcut(String perClauseString, AjAttributeStruct struct) { - final String pointcutString; - Pointcut pointcut = null; - TypePattern typePattern = null; - final PerClause perClause; - if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOW.getName())) { - pointcutString = PerClause.KindAnnotationPrefix.PERCFLOW.extractPointcut(perClauseString); - pointcut = parsePointcut(pointcutString, struct, false); - perClause = new PerCflow(pointcut, false); - } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERCFLOWBELOW.getName())) { - pointcutString = PerClause.KindAnnotationPrefix.PERCFLOWBELOW.extractPointcut(perClauseString); - pointcut = parsePointcut(pointcutString, struct, false); - perClause = new PerCflow(pointcut, true); - } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTARGET.getName())) { - pointcutString = PerClause.KindAnnotationPrefix.PERTARGET.extractPointcut(perClauseString); - pointcut = parsePointcut(pointcutString, struct, false); - perClause = new PerObject(pointcut, false); - } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTHIS.getName())) { - pointcutString = PerClause.KindAnnotationPrefix.PERTHIS.extractPointcut(perClauseString); - pointcut = parsePointcut(pointcutString, struct, false); - perClause = new PerObject(pointcut, true); - } else if (perClauseString.startsWith(PerClause.KindAnnotationPrefix.PERTYPEWITHIN.getName())) { - pointcutString = PerClause.KindAnnotationPrefix.PERTYPEWITHIN.extractPointcut(perClauseString); - typePattern = parseTypePattern(pointcutString, struct); - perClause = new PerTypeWithin(typePattern); - } else if (perClauseString.equalsIgnoreCase(PerClause.SINGLETON.getName() + "()")) { - perClause = new PerSingleton(); - } else { - // could not parse the @AJ perclause - fallback to singleton and - // issue an error - reportError("@Aspect per clause cannot be read '" + perClauseString + "'", struct); - return null; - } - - if (!PerClause.SINGLETON.equals(perClause.getKind()) && !PerClause.PERTYPEWITHIN.equals(perClause.getKind()) - && pointcut == null) { - // we could not parse the pointcut - return null; - } - if (PerClause.PERTYPEWITHIN.equals(perClause.getKind()) && typePattern == null) { - // we could not parse the type pattern - return null; - } - return perClause; - } - - /** - * Read @DeclarePrecedence - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handlePrecedenceAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeStruct struct) { - AnnotationGen aspect = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPRECEDENCE_ANNOTATION); - if (aspect != null) { - NameValuePair precedence = getAnnotationElement(aspect, VALUE); - if (precedence != null) { - String precedencePattern = precedence.getValue().stringifyValue(); - PatternParser parser = new PatternParser(precedencePattern); - DeclarePrecedence ajPrecedence = parser.parseDominates(); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(ajPrecedence)); - return true; - } - } - return false; - } - - // /** - // * Read @DeclareImplements - // * - // * @param runtimeAnnotations - // * @param struct - // * @return true if found - // */ - // private static boolean - // handleDeclareImplementsAnnotation(RuntimeAnnotations runtimeAnnotations, - // AjAttributeFieldStruct - // struct) {//, ResolvedPointcutDefinition preResolvedPointcut) { - // Annotation deci = getAnnotation(runtimeAnnotations, - // AjcMemberMaker.DECLAREIMPLEMENTS_ANNOTATION); - // if (deci != null) { - // ElementNameValuePairGen deciPatternNVP = getAnnotationElement(deci, - // VALUE); - // String deciPattern = deciPatternNVP.getValue().stringifyValue(); - // if (deciPattern != null) { - // TypePattern typePattern = parseTypePattern(deciPattern, struct); - // ResolvedType fieldType = - // UnresolvedType.forSignature(struct.field.getSignature()).resolve(struct.enclosingType.getWorld()); - // if (fieldType.isPrimitiveType()) { - // return false; - // } else if (fieldType.isInterface()) { - // TypePattern parent = new - // ExactTypePattern(UnresolvedType.forSignature(struct.field.getSignature()), - // false, false); - // parent.resolve(struct.enclosingType.getWorld()); - // List parents = new ArrayList(1); - // parents.add(parent); - // //TODO kick ISourceLocation sl = struct.bField.getSourceLocation(); ?? - // struct.ajAttributes.add( - // new AjAttribute.DeclareAttribute( - // new DeclareParents( - // typePattern, - // parents, - // false - // ) - // ) - // ); - // return true; - // } else { - // reportError("@DeclareImplements: can only be used on field whose type is an interface", - // struct); - // return false; - // } - // } - // } - // return false; - // } - - /** - * Read @DeclareParents - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleDeclareParentsAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeFieldStruct struct) {// , - // ResolvedPointcutDefinition - // preResolvedPointcut) - // { - AnnotationGen decp = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREPARENTS_ANNOTATION); - if (decp != null) { - NameValuePair decpPatternNVP = getAnnotationElement(decp, VALUE); - String decpPattern = decpPatternNVP.getValue().stringifyValue(); - if (decpPattern != null) { - TypePattern typePattern = parseTypePattern(decpPattern, struct); - ResolvedType fieldType = UnresolvedType.forSignature(struct.field.getSignature()).resolve( - struct.enclosingType.getWorld()); - if (fieldType.isParameterizedOrRawType()) { - fieldType = fieldType.getGenericType(); - } - if (fieldType.isInterface()) { - TypePattern parent = parseTypePattern(fieldType.getName(), struct); - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - // first add the declare implements like - List<TypePattern> parents = new ArrayList<TypePattern>(1); - parents.add(parent); - DeclareParents dp = new DeclareParents(typePattern, parents, false); - dp.resolve(binding); // resolves the parent and child parts of the decp - - // resolve this so that we can use it for the - // MethodDelegateMungers below. - // eg. '@Coloured *' will change from a WildTypePattern to - // an 'AnyWithAnnotationTypePattern' after this resolution - typePattern = dp.getChild(); // this retrieves the resolved version - // TODO kick ISourceLocation sl = - // struct.bField.getSourceLocation(); ?? - // dp.setLocation(dp.getDeclaringType().getSourceContext(), - // dp.getDeclaringType().getSourceLocation().getOffset(), - // dp.getDeclaringType().getSourceLocation().getOffset()); - dp.setLocation(struct.context, -1, -1); // not ideal... - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp)); - - // do we have a defaultImpl=xxx.class (ie implementation) - String defaultImplClassName = null; - NameValuePair defaultImplNVP = getAnnotationElement(decp, "defaultImpl"); - if (defaultImplNVP != null) { - ClassElementValue defaultImpl = (ClassElementValue) defaultImplNVP.getValue(); - defaultImplClassName = UnresolvedType.forSignature(defaultImpl.getClassString()).getName(); - if (defaultImplClassName.equals("org.aspectj.lang.annotation.DeclareParents")) { - defaultImplClassName = null; - } else { - // check public no arg ctor - ResolvedType impl = struct.enclosingType.getWorld().resolve(defaultImplClassName, false); - ResolvedMember[] mm = impl.getDeclaredMethods(); - int implModifiers = impl.getModifiers(); - boolean defaultVisibilityImpl = !(Modifier.isPrivate(implModifiers) - || Modifier.isProtected(implModifiers) || Modifier.isPublic(implModifiers)); - boolean hasNoCtorOrANoArgOne = true; - ResolvedMember foundOneOfIncorrectVisibility = null; - for (int i = 0; i < mm.length; i++) { - ResolvedMember resolvedMember = mm[i]; - if (resolvedMember.getName().equals("<init>")) { - hasNoCtorOrANoArgOne = false; - - if (resolvedMember.getParameterTypes().length == 0) { - if (defaultVisibilityImpl) { // default visibility implementation - if (resolvedMember.isPublic() || resolvedMember.isDefault()) { - hasNoCtorOrANoArgOne = true; - } else { - foundOneOfIncorrectVisibility = resolvedMember; - } - } else if (Modifier.isPublic(implModifiers)) { // public - // implementation - if (resolvedMember.isPublic()) { - hasNoCtorOrANoArgOne = true; - } else { - foundOneOfIncorrectVisibility = resolvedMember; - } - } - } - } - if (hasNoCtorOrANoArgOne) { - break; - } - } - if (!hasNoCtorOrANoArgOne) { - if (foundOneOfIncorrectVisibility != null) { - reportError( - "@DeclareParents: defaultImpl=\"" - + defaultImplClassName - + "\" has a no argument constructor, but it is of incorrect visibility. It must be at least as visible as the type.", - struct); - } else { - reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName - + "\" has no public no-arg constructor", struct); - } - } - if (!fieldType.isAssignableFrom(impl)) { - reportError("@DeclareParents: defaultImpl=\"" + defaultImplClassName - + "\" does not implement the interface '" + fieldType.toString() + "'", struct); - } - } - - } - - // then iterate on field interface hierarchy (not object) - boolean hasAtLeastOneMethod = false; - Iterator<ResolvedMember> methodIterator = fieldType.getMethodsIncludingIntertypeDeclarations(false, true); - while (methodIterator.hasNext()) { - ResolvedMember method = methodIterator.next(); - if (method.isAbstract()) { - // moved to be detected at weave time if the target - // doesnt implement the methods - // if (defaultImplClassName == null) { - // // non marker interface with no default impl - // provided - // reportError("@DeclareParents: used with a non marker interface and no defaultImpl=\"...\" provided", - // struct); - // return false; - // } - hasAtLeastOneMethod = true; - // What we are saying here: - // We have this method 'method' and we want to put a - // forwarding method into a type that matches - // typePattern that should delegate to the version - // of the method in 'defaultImplClassName' - - // Now the method may be from a supertype but the - // declaring type of the method we pass into the - // type - // munger is what is used to determine the type of - // the field that hosts the delegate instance. - // So here we create a modified method with an - // alternative declaring type so that we lookup - // the right field. See pr164016. - MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, defaultImplClassName, typePattern); - mdtm.setFieldType(fieldType); - mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); - struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); - } - } - // successful so far, we thus need a bcel type munger to have - // a field hosting the mixin in the target type - if (hasAtLeastOneMethod && defaultImplClassName != null) { - ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, fieldType, struct.enclosingType); - struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger( - fieldHost, struct.enclosingType, typePattern))); - } - return true; - } else { - reportError("@DeclareParents: can only be used on a field whose type is an interface", struct); - return false; - } - } - } - return false; - } - - /** - * Return a nicely formatted method string, for example: int X.foo(java.lang.String) - */ - public static String getMethodForMessage(AjAttributeMethodStruct methodstructure) { - StringBuffer sb = new StringBuffer(); - sb.append("Method '"); - sb.append(methodstructure.method.getReturnType().toString()); - sb.append(" ").append(methodstructure.enclosingType).append(".").append(methodstructure.method.getName()); - sb.append("("); - Type[] args = methodstructure.method.getArgumentTypes(); - if (args != null) { - for (int t = 0; t < args.length; t++) { - if (t > 0) { - sb.append(","); - } - sb.append(args[t].toString()); - } - } - sb.append(")'"); - return sb.toString(); - } - - /** - * Process any @DeclareMixin annotation. - * - * Example Declaration <br> - * - * @DeclareMixin("Foo+") public I createImpl(Object o) { return new Impl(o); } - * - * <br> - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleDeclareMixinAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) { - AnnotationGen declareMixinAnnotation = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREMIXIN_ANNOTATION); - if (declareMixinAnnotation == null) { - // No annotation found - return false; - } - Method annotatedMethod = struct.method; - World world = struct.enclosingType.getWorld(); - NameValuePair declareMixinPatternNameValuePair = getAnnotationElement(declareMixinAnnotation, VALUE); - - // declareMixinPattern could be of the form "Bar*" or "A || B" or "Foo+" - String declareMixinPattern = declareMixinPatternNameValuePair.getValue().stringifyValue(); - TypePattern targetTypePattern = parseTypePattern(declareMixinPattern, struct); - - // Return value of the annotated method is the interface or class that the mixin delegate should have - ResolvedType methodReturnType = UnresolvedType.forSignature(annotatedMethod.getReturnType().getSignature()).resolve(world); - if (methodReturnType.isParameterizedOrRawType()) { - methodReturnType = methodReturnType.getGenericType(); - } - if (methodReturnType.isPrimitiveType()) { - reportError(getMethodForMessage(struct) + ": factory methods for a mixin cannot return void or a primitive type", - struct); - return false; - } - - if (annotatedMethod.getArgumentTypes().length > 1) { - reportError(getMethodForMessage(struct) + ": factory methods for a mixin can take a maximum of one parameter", struct); - return false; - } - - // The set of interfaces to be mixed in is either: - // supplied as a list in the 'Class[] interfaces' value in the annotation value - // supplied as just the interface return value of the annotated method - // supplied as just the class return value of the annotated method - NameValuePair interfaceListSpecified = getAnnotationElement(declareMixinAnnotation, "interfaces"); - - List<TypePattern> newParents = new ArrayList<TypePattern>(1); - List<ResolvedType> newInterfaceTypes = new ArrayList<ResolvedType>(1); - if (interfaceListSpecified != null) { - ArrayElementValue arrayOfInterfaceTypes = (ArrayElementValue) interfaceListSpecified.getValue(); - int numberOfTypes = arrayOfInterfaceTypes.getElementValuesArraySize(); - ElementValue[] theTypes = arrayOfInterfaceTypes.getElementValuesArray(); - for (int i = 0; i < numberOfTypes; i++) { - ClassElementValue interfaceType = (ClassElementValue) theTypes[i]; - // Check: needs to be resolvable - // TODO crappy replace required - ResolvedType ajInterfaceType = UnresolvedType.forSignature(interfaceType.getClassString().replace("/", ".")) - .resolve(world); - if (ajInterfaceType.isMissing() || !ajInterfaceType.isInterface()) { - reportError( - "Types listed in the 'interfaces' DeclareMixin annotation value must be valid interfaces. This is invalid: " - + ajInterfaceType.getName(), struct); // TODO better error location, use the method position - return false; - } - if (!ajInterfaceType.isAssignableFrom(methodReturnType)) { - reportError(getMethodForMessage(struct) + ": factory method does not return something that implements '" - + ajInterfaceType.getName() + "'", struct); - return false; - } - newInterfaceTypes.add(ajInterfaceType); - // Checking that it is a superinterface of the methods return value is done at weave time - TypePattern newParent = parseTypePattern(ajInterfaceType.getName(), struct); - newParents.add(newParent); - } - } else { - if (methodReturnType.isClass()) { - reportError( - getMethodForMessage(struct) - + ": factory methods for a mixin must either return an interface type or specify interfaces in the annotation and return a class", - struct); - return false; - } - // Use the method return type: this might be a class or an interface - TypePattern newParent = parseTypePattern(methodReturnType.getName(), struct); - newInterfaceTypes.add(methodReturnType); - newParents.add(newParent); - } - if (newParents.size() == 0) { - // Warning: did they foolishly put @DeclareMixin(value="Bar+",interfaces={}) - // TODO output warning - return false; - } - - // Create the declare parents that will add the interfaces to matching targets - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - // how do we mark this as a decp due to decmixin? - DeclareParents dp = new DeclareParentsMixin(targetTypePattern, newParents); - dp.resolve(binding); - targetTypePattern = dp.getChild(); - - dp.setLocation(struct.context, -1, -1); // not ideal... - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(dp)); - - // The factory method for building the implementation is the - // one attached to the annotation: - // Method implementationFactory = struct.method; - - boolean hasAtLeastOneMethod = false; - - for (Iterator<ResolvedType> iterator = newInterfaceTypes.iterator(); iterator.hasNext();) { - ResolvedType typeForDelegation = iterator.next(); - // TODO check for overlapping interfaces. Eg. A implements I, I extends J - if they specify interfaces={I,J} we dont - // want to do any methods twice - ResolvedMember[] methods = typeForDelegation.getMethodsWithoutIterator(true, false, false).toArray( - new ResolvedMember[0]); - for (int i = 0; i < methods.length; i++) { - ResolvedMember method = methods[i]; - if (method.isAbstract()) { - hasAtLeastOneMethod = true; - if (method.hasBackingGenericMember()) { - method = method.getBackingGenericMember(); - } - MethodDelegateTypeMunger mdtm = new MethodDelegateTypeMunger(method, struct.enclosingType, "", - targetTypePattern, struct.method.getName(), struct.method.getSignature()); - mdtm.setFieldType(methodReturnType); - mdtm.setSourceLocation(struct.enclosingType.getSourceLocation()); - struct.ajAttributes.add(new AjAttribute.TypeMunger(mdtm)); - } - } - } - // if any method delegate was created then a field to hold the delegate instance must also be added - if (hasAtLeastOneMethod) { - ResolvedMember fieldHost = AjcMemberMaker.itdAtDeclareParentsField(null, methodReturnType, struct.enclosingType); - struct.ajAttributes.add(new AjAttribute.TypeMunger(new MethodDelegateTypeMunger.FieldHostTypeMunger(fieldHost, - struct.enclosingType, targetTypePattern))); - } - return true; - } - - /** - * Read @Before - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleBeforeAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, - ResolvedPointcutDefinition preResolvedPointcut) { - AnnotationGen before = getAnnotation(runtimeAnnotations, AjcMemberMaker.BEFORE_ANNOTATION); - if (before != null) { - NameValuePair beforeAdvice = getAnnotationElement(before, VALUE); - if (beforeAdvice != null) { - // this/target/args binding - String argumentNames = getArgNamesValue(before); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfoException unreadableDebugInfoException) { - return false; - } - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - // pc.resolve(binding); - } else { - pc = parsePointcut(beforeAdvice.getValue().stringifyValue(), struct, false); - if (pc == null) { - return false;// parse error - } - pc = pc.resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), - struct.bMethod.getDeclarationOffset()); - struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Before, pc, extraArgument, sl.getOffset(), sl - .getOffset() + 1,// FIXME AVASM - struct.context)); - return true; - } - } - return false; - } - - /** - * Read @After - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, - ResolvedPointcutDefinition preResolvedPointcut) { - AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTER_ANNOTATION); - if (after != null) { - NameValuePair afterAdvice = getAnnotationElement(after, VALUE); - if (afterAdvice != null) { - // this/target/args binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - String argumentNames = getArgNamesValue(after); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfoException unreadableDebugInfoException) { - return false; - } - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = parsePointcut(afterAdvice.getValue().stringifyValue(), struct, false); - if (pc == null) { - return false;// parse error - } - pc.resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), - struct.bMethod.getDeclarationOffset()); - struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.After, pc, extraArgument, sl.getOffset(), sl - .getOffset() + 1,// FIXME AVASM - struct.context)); - return true; - } - } - return false; - } - - /** - * Read @AfterReturning - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterReturningAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, - ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod) - throws ReturningFormalNotDeclaredInAdviceSignatureException { - AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERRETURNING_ANNOTATION); - if (after != null) { - NameValuePair annValue = getAnnotationElement(after, VALUE); - NameValuePair annPointcut = getAnnotationElement(after, POINTCUT); - NameValuePair annReturned = getAnnotationElement(after, RETURNING); - - // extract the pointcut and returned type/binding - do some checks - String pointcut = null; - String returned = null; - if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) { - reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct); - return false; - } - if (annValue != null) { - pointcut = annValue.getValue().stringifyValue(); - } else { - pointcut = annPointcut.getValue().stringifyValue(); - } - if (isNullOrEmpty(pointcut)) { - reportError("@AfterReturning: either 'value' or 'poincut' must be provided, not both", struct); - return false; - } - if (annReturned != null) { - returned = annReturned.getValue().stringifyValue(); - if (isNullOrEmpty(returned)) { - returned = null; - } else { - // check that thrownFormal exists as the last parameter in - // the advice - String[] pNames = owningMethod.getParameterNames(); - if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(returned)) { - throw new ReturningFormalNotDeclaredInAdviceSignatureException(returned); - } - } - } - String argumentNames = getArgNamesValue(after); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - // this/target/args binding - // exclude the return binding from the pointcut binding since it is - // an extraArg binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = (returned == null ? extractBindings(struct) : extractBindings(struct, returned)); - } catch (UnreadableDebugInfoException unreadableDebugInfoException) { - return false; - } - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - // return binding - if (returned != null) { - extraArgument |= Advice.ExtraArgument; - } - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = parsePointcut(pointcut, struct, false); - if (pc == null) { - return false;// parse error - } - pc.resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), - struct.bMethod.getDeclarationOffset()); - struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterReturning, pc, extraArgument, sl.getOffset(), - sl.getOffset() + 1,// FIXME AVASM - struct.context)); - return true; - } - return false; - } - - /** - * Read @AfterThrowing - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAfterThrowingAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, - ResolvedPointcutDefinition preResolvedPointcut, BcelMethod owningMethod) - throws ThrownFormalNotDeclaredInAdviceSignatureException { - AnnotationGen after = getAnnotation(runtimeAnnotations, AjcMemberMaker.AFTERTHROWING_ANNOTATION); - if (after != null) { - NameValuePair annValue = getAnnotationElement(after, VALUE); - NameValuePair annPointcut = getAnnotationElement(after, POINTCUT); - NameValuePair annThrown = getAnnotationElement(after, THROWING); - - // extract the pointcut and throwned type/binding - do some checks - String pointcut = null; - String thrownFormal = null; - if ((annValue != null && annPointcut != null) || (annValue == null && annPointcut == null)) { - reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct); - return false; - } - if (annValue != null) { - pointcut = annValue.getValue().stringifyValue(); - } else { - pointcut = annPointcut.getValue().stringifyValue(); - } - if (isNullOrEmpty(pointcut)) { - reportError("@AfterThrowing: either 'value' or 'poincut' must be provided, not both", struct); - return false; - } - if (annThrown != null) { - thrownFormal = annThrown.getValue().stringifyValue(); - if (isNullOrEmpty(thrownFormal)) { - thrownFormal = null; - } else { - // check that thrownFormal exists as the last parameter in - // the advice - String[] pNames = owningMethod.getParameterNames(); - if (pNames == null || pNames.length == 0 || !Arrays.asList(pNames).contains(thrownFormal)) { - throw new ThrownFormalNotDeclaredInAdviceSignatureException(thrownFormal); - } - } - } - String argumentNames = getArgNamesValue(after); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - // this/target/args binding - // exclude the throwned binding from the pointcut binding since it - // is an extraArg binding - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = (thrownFormal == null ? extractBindings(struct) : extractBindings(struct, thrownFormal)); - } catch (UnreadableDebugInfoException unreadableDebugInfoException) { - return false; - } - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - // return binding - if (thrownFormal != null) { - extraArgument |= Advice.ExtraArgument; - } - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = parsePointcut(pointcut, struct, false); - if (pc == null) { - return false;// parse error - } - pc.resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), - struct.bMethod.getDeclarationOffset()); - struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.AfterThrowing, pc, extraArgument, sl.getOffset(), sl - .getOffset() + 1, struct.context)); - return true; - } - return false; - } - - /** - * Read @Around - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleAroundAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct, - ResolvedPointcutDefinition preResolvedPointcut) { - AnnotationGen around = getAnnotation(runtimeAnnotations, AjcMemberMaker.AROUND_ANNOTATION); - if (around != null) { - NameValuePair aroundAdvice = getAnnotationElement(around, VALUE); - if (aroundAdvice != null) { - // this/target/args binding - String argumentNames = getArgNamesValue(around); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - try { - bindings = extractBindings(struct); - } catch (UnreadableDebugInfoException unreadableDebugInfoException) { - return false; - } - IScope binding = new BindingScope(struct.enclosingType, struct.context, bindings); - - // joinpoint, staticJoinpoint binding - int extraArgument = extractExtraArgument(struct.method); - - Pointcut pc = null; - if (preResolvedPointcut != null) { - pc = preResolvedPointcut.getPointcut(); - } else { - pc = parsePointcut(aroundAdvice.getValue().stringifyValue(), struct, false); - if (pc == null) { - return false;// parse error - } - pc.resolve(binding); - } - setIgnoreUnboundBindingNames(pc, bindings); - - ISourceLocation sl = struct.context.makeSourceLocation(struct.bMethod.getDeclarationLineNumber(), - struct.bMethod.getDeclarationOffset()); - struct.ajAttributes.add(new AjAttribute.AdviceAttribute(AdviceKind.Around, pc, extraArgument, sl.getOffset(), sl - .getOffset() + 1,// FIXME AVASM - struct.context)); - return true; - } - } - return false; - } - - /** - * Read @Pointcut and handle the resolving in a lazy way to deal with pointcut references - * - * @param runtimeAnnotations - * @param struct - * @return true if a pointcut was handled - */ - private static boolean handlePointcutAnnotation(RuntimeAnnos runtimeAnnotations, AjAttributeMethodStruct struct) { - AnnotationGen pointcut = getAnnotation(runtimeAnnotations, AjcMemberMaker.POINTCUT_ANNOTATION); - if (pointcut == null) { - return false; - } - NameValuePair pointcutExpr = getAnnotationElement(pointcut, VALUE); - - // semantic check: the method must return void, or be - // "public static boolean" for if() support - if (!(Type.VOID.equals(struct.method.getReturnType()) || (Type.BOOLEAN.equals(struct.method.getReturnType()) - && struct.method.isStatic() && struct.method.isPublic()))) { - reportWarning("Found @Pointcut on a method not returning 'void' or not 'public static boolean'", struct); - // no need to stop - } - - // semantic check: the method must not throw anything - if (struct.method.getExceptionTable() != null) { - reportWarning("Found @Pointcut on a method throwing exception", struct); - // no need to stop - } - - String argumentNames = getArgNamesValue(pointcut); - if (argumentNames != null) { - struct.unparsedArgumentNames = argumentNames; - } - // this/target/args binding - final IScope binding; - try { - if (struct.method.isAbstract()) { - binding = null; - } else { - binding = new BindingScope(struct.enclosingType, struct.context, extractBindings(struct)); - } - } catch (UnreadableDebugInfoException e) { - return false; - } - - UnresolvedType[] argumentTypes = new UnresolvedType[struct.method.getArgumentTypes().length]; - for (int i = 0; i < argumentTypes.length; i++) { - argumentTypes[i] = UnresolvedType.forSignature(struct.method.getArgumentTypes()[i].getSignature()); - } - - Pointcut pc = null; - if (struct.method.isAbstract()) { - if ((pointcutExpr != null && isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) || pointcutExpr == null) { - // abstract pointcut - // leave pc = null - } else { - reportError("Found defined @Pointcut on an abstract method", struct); - return false;// stop - } - } else { - if (pointcutExpr == null || isNullOrEmpty(pointcutExpr.getValue().stringifyValue())) { - // the matches nothing pointcut (125475/125480) - perhaps not as - // cleanly supported as it could be. - } else { - // if (pointcutExpr != null) { - // use a LazyResolvedPointcutDefinition so that the pointcut is - // resolved lazily - // since for it to be resolved, we will need other pointcuts to - // be registered as well - pc = parsePointcut(pointcutExpr.getValue().stringifyValue(), struct, true); - if (pc == null) { - return false;// parse error - } - pc.setLocation(struct.context, -1, -1);// FIXME AVASM !! bMethod - // is null here.. - // } else { - // reportError("Found undefined @Pointcut on a non-abstract method", - // struct); - // return false; - // } - } - } - // do not resolve binding now but lazily - struct.ajAttributes.add(new AjAttribute.PointcutDeclarationAttribute(new LazyResolvedPointcutDefinition( - struct.enclosingType, struct.method.getModifiers(), struct.method.getName(), argumentTypes, UnresolvedType - .forSignature(struct.method.getReturnType().getSignature()), pc,// can - // be - // null - // for - // abstract - // pointcut - binding // can be null for abstract pointcut - ))); - return true; - } - - /** - * Read @DeclareError, @DeclareWarning - * - * @param runtimeAnnotations - * @param struct - * @return true if found - */ - private static boolean handleDeclareErrorOrWarningAnnotation(AsmManager model, RuntimeAnnos runtimeAnnotations, - AjAttributeFieldStruct struct) { - AnnotationGen error = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREERROR_ANNOTATION); - boolean hasError = false; - if (error != null) { - NameValuePair declareError = getAnnotationElement(error, VALUE); - if (declareError != null) { - if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) { - reportError("@DeclareError used on a non String constant field", struct); - return false; - } - Pointcut pc = parsePointcut(declareError.getValue().stringifyValue(), struct, false); - if (pc == null) { - hasError = false;// cannot parse pointcut - } else { - DeclareErrorOrWarning deow = new DeclareErrorOrWarning(true, pc, struct.field.getConstantValue().toString()); - setDeclareErrorOrWarningLocation(model, deow, struct); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); - hasError = true; - } - } - } - AnnotationGen warning = getAnnotation(runtimeAnnotations, AjcMemberMaker.DECLAREWARNING_ANNOTATION); - boolean hasWarning = false; - if (warning != null) { - NameValuePair declareWarning = getAnnotationElement(warning, VALUE); - if (declareWarning != null) { - if (!STRING_DESC.equals(struct.field.getSignature()) || struct.field.getConstantValue() == null) { - reportError("@DeclareWarning used on a non String constant field", struct); - return false; - } - Pointcut pc = parsePointcut(declareWarning.getValue().stringifyValue(), struct, false); - if (pc == null) { - hasWarning = false;// cannot parse pointcut - } else { - DeclareErrorOrWarning deow = new DeclareErrorOrWarning(false, pc, struct.field.getConstantValue().toString()); - setDeclareErrorOrWarningLocation(model, deow, struct); - struct.ajAttributes.add(new AjAttribute.DeclareAttribute(deow)); - return hasWarning = true; - } - } - } - return hasError || hasWarning; - } - - /** - * Sets the location for the declare error / warning using the corresponding IProgramElement in the structure model. This will - * only fix bug 120356 if compiled with -emacssym, however, it does mean that the cross references view in AJDT will show the - * correct information. - * - * Other possibilities for fix: 1. using the information in ajcDeclareSoft (if this is set correctly) which will fix the problem - * if compiled with ajc but not if compiled with javac. 2. creating an AjAttribute called FieldDeclarationLineNumberAttribute - * (much like MethodDeclarationLineNumberAttribute) which we can ask for the offset. This will again only fix bug 120356 when - * compiled with ajc. - * - * @param deow - * @param struct - */ - private static void setDeclareErrorOrWarningLocation(AsmManager model, DeclareErrorOrWarning deow, AjAttributeFieldStruct struct) { - IHierarchy top = (model == null ? null : model.getHierarchy()); - if (top != null && top.getRoot() != null) { - IProgramElement ipe = top.findElementForLabel(top.getRoot(), IProgramElement.Kind.FIELD, struct.field.getName()); - if (ipe != null && ipe.getSourceLocation() != null) { - ISourceLocation sourceLocation = ipe.getSourceLocation(); - int start = sourceLocation.getOffset(); - int end = start + struct.field.getName().length(); - deow.setLocation(struct.context, start, end); - return; - } - } - deow.setLocation(struct.context, -1, -1); - } - - /** - * Returns a readable representation of a method. Method.toString() is not suitable. - * - * @param method - * @return a readable representation of a method - */ - private static String methodToString(Method method) { - StringBuffer sb = new StringBuffer(); - sb.append(method.getName()); - sb.append(method.getSignature()); - return sb.toString(); - } - - /** - * Build the bindings for a given method (pointcut / advice) - * - * @param struct - * @return null if no debug info is available - */ - private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct) throws UnreadableDebugInfoException { - Method method = struct.method; - String[] argumentNames = struct.getArgumentNames(); - - // assert debug info was here - if (argumentNames.length != method.getArgumentTypes().length) { - reportError( - "Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)", - struct); - throw new UnreadableDebugInfoException(); - } - - List<FormalBinding> bindings = new ArrayList<FormalBinding>(); - for (int i = 0; i < argumentNames.length; i++) { - String argumentName = argumentNames[i]; - UnresolvedType argumentType = UnresolvedType.forSignature(method.getArgumentTypes()[i].getSignature()); - - // do not bind JoinPoint / StaticJoinPoint / - // EnclosingStaticJoinPoint - // TODO solve me : this means that the JP/SJP/ESJP cannot appear as - // binding - // f.e. when applying advice on advice etc - if ((AjcMemberMaker.TYPEX_JOINPOINT.equals(argumentType) - || AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.equals(argumentType) - || AjcMemberMaker.TYPEX_STATICJOINPOINT.equals(argumentType) - || AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.equals(argumentType) || AjcMemberMaker.AROUND_CLOSURE_TYPE - .equals(argumentType))) { - // continue;// skip - bindings.add(new FormalBinding.ImplicitFormalBinding(argumentType, argumentName, i)); - } else { - bindings.add(new FormalBinding(argumentType, argumentName, i)); - } - } - - return bindings.toArray(new FormalBinding[] {}); - } - - // FIXME alex deal with exclude index - private static FormalBinding[] extractBindings(AjAttributeMethodStruct struct, String excludeFormal) - throws UnreadableDebugInfoException { - FormalBinding[] bindings = extractBindings(struct); - // int excludeIndex = -1; - for (int i = 0; i < bindings.length; i++) { - FormalBinding binding = bindings[i]; - if (binding.getName().equals(excludeFormal)) { - // excludeIndex = i; - bindings[i] = new FormalBinding.ImplicitFormalBinding(binding.getType(), binding.getName(), binding.getIndex()); - break; - } - } - return bindings; - // - // if (excludeIndex >= 0) { - // FormalBinding[] bindingsFiltered = new - // FormalBinding[bindings.length-1]; - // int k = 0; - // for (int i = 0; i < bindings.length; i++) { - // if (i == excludeIndex) { - // ; - // } else { - // bindingsFiltered[k] = new FormalBinding(bindings[i].getType(), - // bindings[i].getName(), k); - // k++; - // } - // } - // return bindingsFiltered; - // } else { - // return bindings; - // } - } - - /** - * Compute the flag for the xxxJoinPoint extra argument - * - * @param method - * @return extra arg flag - */ - private static int extractExtraArgument(Method method) { - Type[] methodArgs = method.getArgumentTypes(); - String[] sigs = new String[methodArgs.length]; - for (int i = 0; i < methodArgs.length; i++) { - sigs[i] = methodArgs[i].getSignature(); - } - return extractExtraArgument(sigs); - } - - /** - * Compute the flag for the xxxJoinPoint extra argument - * - * @param argumentSignatures - * @return extra arg flag - */ - public static int extractExtraArgument(String[] argumentSignatures) { - int extraArgument = 0; - for (int i = 0; i < argumentSignatures.length; i++) { - if (AjcMemberMaker.TYPEX_JOINPOINT.getSignature().equals(argumentSignatures[i])) { - extraArgument |= Advice.ThisJoinPoint; - } else if (AjcMemberMaker.TYPEX_PROCEEDINGJOINPOINT.getSignature().equals(argumentSignatures[i])) { - extraArgument |= Advice.ThisJoinPoint; - } else if (AjcMemberMaker.TYPEX_STATICJOINPOINT.getSignature().equals(argumentSignatures[i])) { - extraArgument |= Advice.ThisJoinPointStaticPart; - } else if (AjcMemberMaker.TYPEX_ENCLOSINGSTATICJOINPOINT.getSignature().equals(argumentSignatures[i])) { - extraArgument |= Advice.ThisEnclosingJoinPointStaticPart; - } - } - return extraArgument; - } - - /** - * Returns the runtime (RV/RIV) annotation of type annotationType or null if no such annotation - * - * @param rvs - * @param annotationType - * @return annotation - */ - private static AnnotationGen getAnnotation(RuntimeAnnos rvs, UnresolvedType annotationType) { - final String annotationTypeName = annotationType.getName(); - for (AnnotationGen rv : rvs.getAnnotations()) { - if (annotationTypeName.equals(rv.getTypeName())) { - return rv; - } - } - return null; - } - - /** - * Returns the value of a given element of an annotation or null if not found Caution: Does not handles default value. - * - * @param annotation - * @param elementName - * @return annotation NVP - */ - private static NameValuePair getAnnotationElement(AnnotationGen annotation, String elementName) { - for (NameValuePair element : annotation.getValues()) { - if (elementName.equals(element.getNameString())) { - return element; - } - } - return null; - } - - /** - * Return the argNames set for an annotation or null if it is not specified. - */ - private static String getArgNamesValue(AnnotationGen anno) { - List<NameValuePair> elements = anno.getValues(); - for (NameValuePair element : elements) { - if (ARGNAMES.equals(element.getNameString())) { - return element.getValue().stringifyValue(); - } - } - return null; - } - - private static String lastbit(String fqname) { - int i = fqname.lastIndexOf("."); - if (i == -1) { - return fqname; - } else { - return fqname.substring(i + 1); - } - } - - /** - * Extract the method argument names. First we try the debug info attached to the method (the LocalVariableTable) - if we cannot - * find that we look to use the argNames value that may have been supplied on the associated annotation. If that fails we just - * don't know and return an empty string. - * - * @param method - * @param argNamesFromAnnotation - * @param methodStruct - * @return method argument names - */ - private static String[] getMethodArgumentNames(Method method, String argNamesFromAnnotation, - AjAttributeMethodStruct methodStruct) { - if (method.getArgumentTypes().length == 0) { - return EMPTY_STRINGS; - } - - final int startAtStackIndex = method.isStatic() ? 0 : 1; - final List<MethodArgument> arguments = new ArrayList<MethodArgument>(); - LocalVariableTable lt = method.getLocalVariableTable(); - if (lt != null) { - LocalVariable[] lvt = lt.getLocalVariableTable(); - for (int j = 0; j < lvt.length; j++) { - LocalVariable localVariable = lvt[j]; - if (localVariable != null) { // pr348488 - if (localVariable.getStartPC() == 0) { - if (localVariable.getIndex() >= startAtStackIndex) { - arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); - } - } - } else { - String typename = (methodStruct.enclosingType != null ? methodStruct.enclosingType.getName() : ""); - System.err.println("AspectJ: 348488 debug: unusual local variable table for method " + typename + "." - + method.getName()); - } - } - if (arguments.size() == 0) { - // The local variable table is causing us trouble, try the annotation value - // See 539121 for a jacoco variant of the cobertura issue below - if (argNamesFromAnnotation != null) { - String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct); - if (argNames.length != 0) { - return argNames; - } - } - // could be cobertura code where some extra bytecode has been stuffed in at the start of the method - // but the local variable table hasn't been repaired - for example: - // LocalVariable(start_pc = 6, length = 40, index = 0:com.example.ExampleAspect this) - // LocalVariable(start_pc = 6, length = 40, index = 1:org.aspectj.lang.ProceedingJoinPoint pjp) - // LocalVariable(start_pc = 6, length = 40, index = 2:int __cobertura__line__number__) - // LocalVariable(start_pc = 6, length = 40, index = 3:int __cobertura__branch__number__) - LocalVariable localVariable = lvt[0]; - if (localVariable != null) { // pr348488 - if (localVariable.getStartPC() != 0) { - // looks suspicious so let's use this information - for (int j = 0; j < lvt.length && arguments.size() < method.getArgumentTypes().length; j++) { - localVariable = lvt[j]; - if (localVariable.getIndex() >= startAtStackIndex) { - arguments.add(new MethodArgument(localVariable.getName(), localVariable.getIndex())); - } - } - } - } - } - } else { - if (argNamesFromAnnotation != null) { - String[] argNames = extractArgNamesFromAnnotationValue(method, argNamesFromAnnotation, methodStruct); - if (argNames != null) { - return argNames; - } - } - } - - if (arguments.size() != method.getArgumentTypes().length) { - return EMPTY_STRINGS; - } - - // sort by index - Collections.sort(arguments, new Comparator<MethodArgument>() { - public int compare(MethodArgument mo, MethodArgument mo1) { - if (mo.indexOnStack == mo1.indexOnStack) { - return 0; - } else if (mo.indexOnStack > mo1.indexOnStack) { - return 1; - } else { - return -1; - } - } - }); - String[] argumentNames = new String[arguments.size()]; - int i = 0; - for (MethodArgument methodArgument : arguments) { - argumentNames[i++] = methodArgument.name; - } - return argumentNames; - } - - private static String[] extractArgNamesFromAnnotationValue(Method method, String argNamesFromAnnotation, - AjAttributeMethodStruct methodStruct) { - StringTokenizer st = new StringTokenizer(argNamesFromAnnotation, " ,"); - List<String> args = new ArrayList<String>(); - while (st.hasMoreTokens()) { - args.add(st.nextToken()); - } - if (args.size() != method.getArgumentTypes().length) { - StringBuffer shortString = new StringBuffer().append(lastbit(method.getReturnType().toString())).append(" ") - .append(method.getName()); - if (method.getArgumentTypes().length > 0) { - shortString.append("("); - for (int i = 0; i < method.getArgumentTypes().length; i++) { - shortString.append(lastbit(method.getArgumentTypes()[i].toString())); - if ((i + 1) < method.getArgumentTypes().length) { - shortString.append(","); - } - - } - shortString.append(")"); - } - reportError("argNames annotation value does not specify the right number of argument names for the method '" - + shortString.toString() + "'", methodStruct); - return EMPTY_STRINGS; - } - return args.toArray(new String[] {}); - } - - /** - * A method argument, used for sorting by indexOnStack (ie order in signature) - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ - private static class MethodArgument { - String name; - int indexOnStack; - - public MethodArgument(String name, int indexOnStack) { - this.name = name; - this.indexOnStack = indexOnStack; - } - } - - /** - * LazyResolvedPointcutDefinition lazyly resolve the pointcut so that we have time to register all pointcut referenced before - * pointcut resolution happens - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ - public static class LazyResolvedPointcutDefinition extends ResolvedPointcutDefinition { - private final Pointcut m_pointcutUnresolved; // null for abstract - // pointcut - private final IScope m_binding; - - private Pointcut m_lazyPointcut = null; - - public LazyResolvedPointcutDefinition(UnresolvedType declaringType, int modifiers, String name, - UnresolvedType[] parameterTypes, UnresolvedType returnType, Pointcut pointcut, IScope binding) { - super(declaringType, modifiers, name, parameterTypes, returnType, Pointcut.makeMatchesNothing(Pointcut.RESOLVED)); - m_pointcutUnresolved = pointcut; - m_binding = binding; - } - - @Override - public Pointcut getPointcut() { - if (m_lazyPointcut == null && m_pointcutUnresolved == null) { - m_lazyPointcut = Pointcut.makeMatchesNothing(Pointcut.CONCRETE); - } - if (m_lazyPointcut == null && m_pointcutUnresolved != null) { - m_lazyPointcut = m_pointcutUnresolved.resolve(m_binding); - m_lazyPointcut.copyLocationFrom(m_pointcutUnresolved); - } - return m_lazyPointcut; - } - } - - /** - * Helper to test empty strings - * - * @param s - * @return true if empty or null - */ - private static boolean isNullOrEmpty(String s) { - return (s == null || s.length() <= 0); - } - - /** - * Set the pointcut bindings for which to ignore unbound issues, so that we can implicitly bind xxxJoinPoint for @AJ advices - * - * @param pointcut - * @param bindings - */ - private static void setIgnoreUnboundBindingNames(Pointcut pointcut, FormalBinding[] bindings) { - // register ImplicitBindings as to be ignored since unbound - // TODO is it likely to fail in a bad way if f.e. this(jp) etc ? - List<String> ignores = new ArrayList<String>(); - for (int i = 0; i < bindings.length; i++) { - FormalBinding formalBinding = bindings[i]; - if (formalBinding instanceof FormalBinding.ImplicitFormalBinding) { - ignores.add(formalBinding.getName()); - } - } - pointcut.m_ignoreUnboundBindingForNames = ignores.toArray(new String[ignores.size()]); - } - - /** - * A check exception when we cannot read debug info (needed for formal binding) - */ - private static class UnreadableDebugInfoException extends Exception { - } - - /** - * Report an error - * - * @param message - * @param location - */ - private static void reportError(String message, AjAttributeStruct location) { - if (!location.handler.isIgnoring(IMessage.ERROR)) { - location.handler.handleMessage(new Message(message, location.enclosingType.getSourceLocation(), true)); - } - } - - // private static void reportError(String message, IMessageHandler handler, ISourceLocation sourceLocation) { - // if (!handler.isIgnoring(IMessage.ERROR)) { - // handler.handleMessage(new Message(message, sourceLocation, true)); - // } - // } - - /** - * Report a warning - * - * @param message - * @param location - */ - private static void reportWarning(String message, AjAttributeStruct location) { - if (!location.handler.isIgnoring(IMessage.WARNING)) { - location.handler.handleMessage(new Message(message, location.enclosingType.getSourceLocation(), false)); - } - } - - /** - * Parse the given pointcut, return null on failure and issue an error - * - * @param pointcutString - * @param struct - * @param allowIf - * @return pointcut, unresolved - */ - private static Pointcut parsePointcut(String pointcutString, AjAttributeStruct struct, boolean allowIf) { - try { - PatternParser parser = new PatternParser(pointcutString, struct.context); - Pointcut pointcut = parser.parsePointcut(); - parser.checkEof(); - pointcut.check(null, struct.enclosingType.getWorld()); - if (!allowIf && pointcutString.indexOf("if()") >= 0 && hasIf(pointcut)) { - reportError("if() pointcut is not allowed at this pointcut location '" + pointcutString + "'", struct); - return null; - } - pointcut.setLocation(struct.context, -1, -1);// FIXME -1,-1 is not - // good enough - return pointcut; - } catch (ParserException e) { - reportError("Invalid pointcut '" + pointcutString + "': " + e.toString() - + (e.getLocation() == null ? "" : " at position " + e.getLocation().getStart()), struct); - return null; - } - } - - private static boolean hasIf(Pointcut pointcut) { - IfFinder visitor = new IfFinder(); - pointcut.accept(visitor, null); - return visitor.hasIf; - } - - /** - * Parse the given type pattern, return null on failure and issue an error - * - * @param patternString - * @param location - * @return type pattern - */ - private static TypePattern parseTypePattern(String patternString, AjAttributeStruct location) { - try { - TypePattern typePattern = new PatternParser(patternString).parseTypePattern(); - typePattern.setLocation(location.context, -1, -1);// FIXME -1,-1 is - // not good - // enough - return typePattern; - } catch (ParserException e) { - reportError("Invalid type pattern'" + patternString + "' : " + e.getLocation(), location); - return null; - } - } - - static class ThrownFormalNotDeclaredInAdviceSignatureException extends Exception { - - private final String formalName; - - public ThrownFormalNotDeclaredInAdviceSignatureException(String formalName) { - this.formalName = formalName; - } - - public String getFormalName() { - return formalName; - } - } - - static class ReturningFormalNotDeclaredInAdviceSignatureException extends Exception { - - private final String formalName; - - public ReturningFormalNotDeclaredInAdviceSignatureException(String formalName) { - this.formalName = formalName; - } - - public String getFormalName() { - return formalName; - } - } -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAccessForInlineMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelAccessForInlineMunger.java deleted file mode 100644 index b81f7ffb1..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelAccessForInlineMunger.java +++ /dev/null @@ -1,386 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Alexandre Vasseur initial implementation - *******************************************************************************/ -package org.aspectj.weaver.bcel; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.generic.FieldInstruction; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InvokeDynamic; -import org.aspectj.apache.bcel.generic.InvokeInstruction; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.UnresolvedType; - -/** - * Looks for all access to method or field that are not public within the body of the around advices and replace the invocations to - * a wrapper call so that the around advice can further be inlined. - * <p/> - * This munger is used for @AJ aspects for which inlining wrapper is not done at compile time. - * <p/> - * Specific state and logic is kept in the munger ala ITD so that call/get/set pointcuts can still be matched on the wrapped member - * thanks to the EffectiveSignature attribute. - * - * @author Alexandre Vasseur - * @author Andy Clement - */ -public class BcelAccessForInlineMunger extends BcelTypeMunger { - - private Map<String, ResolvedMember> inlineAccessors; - - private LazyClassGen aspectGen; - - /** - * The wrapper methods representing any created inlineAccessors - */ - private Set<LazyMethodGen> inlineAccessorMethodGens; - - public BcelAccessForInlineMunger(ResolvedType aspectType) { - super(null, aspectType); - if (aspectType.getWorld().isXnoInline()) { - throw new Error("This should not happen"); - } - } - - @Override - public boolean munge(BcelClassWeaver weaver) { - aspectGen = weaver.getLazyClassGen(); - inlineAccessors = new HashMap<String, ResolvedMember>(0); - inlineAccessorMethodGens = new HashSet<LazyMethodGen>(); - - // look for all @Around advices - for (LazyMethodGen methodGen : aspectGen.getMethodGens()) { - if (methodGen.hasAnnotation(UnresolvedType.forName("org/aspectj/lang/annotation/Around"))) { - openAroundAdvice(methodGen); - } - } - - // add the accessors - for (LazyMethodGen lazyMethodGen : inlineAccessorMethodGens) { - aspectGen.addMethodGen(lazyMethodGen); - } - - // flush some - inlineAccessorMethodGens = null; - // we keep m_inlineAccessorsResolvedMembers for shadow matching - - return true; - } - - /** - * Looks in the wrapper we have added so that we can find their effective signature if needed - */ - @Override - public ResolvedMember getMatchingSyntheticMember(Member member) { - ResolvedMember rm = inlineAccessors.get(member.getName());// + member.getSignature()); -// System.err.println("lookup for " + member.getName() + ":" + member.getSignature() + " = " -// + (rm == null ? "" : rm.getName())); - return rm; - } - - @Override - public ResolvedMember getSignature() { - return null; - } - - /** - * Match only the aspect for which we act - */ - @Override - public boolean matches(ResolvedType onType) { - return aspectType.equals(onType); - } - - /** - * Prepare the around advice, flag it as cannot be inlined if it can't be - */ - private void openAroundAdvice(LazyMethodGen aroundAdvice) { - InstructionHandle curr = aroundAdvice.getBody().getStart(); - InstructionHandle end = aroundAdvice.getBody().getEnd(); - ConstantPool cpg = aroundAdvice.getEnclosingClass().getConstantPool(); - InstructionFactory factory = aroundAdvice.getEnclosingClass().getFactory(); - - boolean realizedCannotInline = false; - while (curr != end) { - if (realizedCannotInline) { - // we know we cannot inline this advice so no need for futher handling - break; - } - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - - // open-up method call - if ((inst instanceof InvokeInstruction)) { - InvokeInstruction invoke = (InvokeInstruction) inst; - if (invoke instanceof InvokeDynamic) { - realizedCannotInline = true; - break; - } - ResolvedType callee = aspectGen.getWorld().resolve(UnresolvedType.forName(invoke.getClassName(cpg))); - - // look in the whole method list and not just declared for super calls and alike - List<ResolvedMember> methods = callee.getMethodsWithoutIterator(false, true, false); - for (ResolvedMember resolvedMember : methods) { - if (invoke.getName(cpg).equals(resolvedMember.getName()) - && invoke.getSignature(cpg).equals(resolvedMember.getSignature()) && !resolvedMember.isPublic()) { - if ("<init>".equals(invoke.getName(cpg))) { - // skipping open up for private constructor - // can occur when aspect new a private inner type - // too complex to handle new + dup + .. + invokespecial here. - aroundAdvice.setCanInline(false); - realizedCannotInline = true; - } else { - // specific handling for super.foo() calls, where foo is non public - ResolvedType memberType = aspectGen.getWorld().resolve(resolvedMember.getDeclaringType()); - if (!aspectType.equals(memberType) && memberType.isAssignableFrom(aspectType)) { - // old test was... - // if (aspectType.getSuperclass() != null - // && aspectType.getSuperclass().getName().equals(resolvedMember.getDeclaringType().getName())) { - ResolvedMember accessor = createOrGetInlineAccessorForSuperDispatch(resolvedMember); - InvokeInstruction newInst = factory.createInvoke(aspectType.getName(), accessor.getName(), - BcelWorld.makeBcelType(accessor.getReturnType()), - BcelWorld.makeBcelTypes(accessor.getParameterTypes()), Constants.INVOKEVIRTUAL); - curr.setInstruction(newInst); - } else { - ResolvedMember accessor = createOrGetInlineAccessorForMethod(resolvedMember); - InvokeInstruction newInst = factory.createInvoke(aspectType.getName(), accessor.getName(), - BcelWorld.makeBcelType(accessor.getReturnType()), - BcelWorld.makeBcelTypes(accessor.getParameterTypes()), Constants.INVOKESTATIC); - curr.setInstruction(newInst); - } - } - - break;// ok we found a matching callee member and swapped the instruction with the accessor - } - } - } else if (inst instanceof FieldInstruction) { - FieldInstruction invoke = (FieldInstruction) inst; - ResolvedType callee = aspectGen.getWorld().resolve(UnresolvedType.forName(invoke.getClassName(cpg))); - for (int i = 0; i < callee.getDeclaredJavaFields().length; i++) { - ResolvedMember resolvedMember = callee.getDeclaredJavaFields()[i]; - if (invoke.getName(cpg).equals(resolvedMember.getName()) - && invoke.getSignature(cpg).equals(resolvedMember.getSignature()) && !resolvedMember.isPublic()) { - final ResolvedMember accessor; - if ((inst.opcode == Constants.GETFIELD) || (inst.opcode == Constants.GETSTATIC)) { - accessor = createOrGetInlineAccessorForFieldGet(resolvedMember); - } else { - accessor = createOrGetInlineAccessorForFieldSet(resolvedMember); - } - InvokeInstruction newInst = factory.createInvoke(aspectType.getName(), accessor.getName(), - BcelWorld.makeBcelType(accessor.getReturnType()), - BcelWorld.makeBcelTypes(accessor.getParameterTypes()), Constants.INVOKESTATIC); - curr.setInstruction(newInst); - - break;// ok we found a matching callee member and swapped the instruction with the accessor - } - } - } - - curr = next; - } - - // no reason for not inlining this advice - // since it is used for @AJ advice that cannot be inlined by defauilt - // make sure we set inline to true since we have done this analysis - if (!realizedCannotInline) { - aroundAdvice.setCanInline(true); - } - } - - /** - * Find (or add if not yet created) an inline wrapper for a non public method call - */ - private ResolvedMember createOrGetInlineAccessorForMethod(ResolvedMember resolvedMember) { - String accessorName = NameMangler.inlineAccessMethodForMethod(resolvedMember.getName(), resolvedMember.getDeclaringType(), - aspectType); - String key = accessorName;// new StringBuilder(accessorName).append(resolvedMember.getSignature()).toString(); - ResolvedMember inlineAccessor = inlineAccessors.get(key); -// System.err.println(key + " accessor=" + inlineAccessor); - if (inlineAccessor == null) { - // add static method to aspect - inlineAccessor = AjcMemberMaker.inlineAccessMethodForMethod(aspectType, resolvedMember); - - // add new accessor method to aspect bytecode - InstructionFactory factory = aspectGen.getFactory(); - LazyMethodGen method = makeMethodGen(aspectGen, inlineAccessor); - method.makeSynthetic(); - List<AjAttribute> methodAttributes = new ArrayList<AjAttribute>(); - methodAttributes.add(new AjAttribute.AjSynthetic()); - methodAttributes.add(new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.MethodCall, false)); - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(0), aspectGen.getConstantPool())); - // flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(1), aspectGen.getConstantPool())); - - inlineAccessorMethodGens.add(method); - - InstructionList il = method.getBody(); - int register = 0; - for (int i = 0, max = inlineAccessor.getParameterTypes().length; i < max; i++) { - UnresolvedType ptype = inlineAccessor.getParameterTypes()[i]; - Type type = BcelWorld.makeBcelType(ptype); - il.append(InstructionFactory.createLoad(type, register)); - register += type.getSize(); - } - il.append(Utility.createInvoke(factory, Modifier.isStatic(resolvedMember.getModifiers()) ? Constants.INVOKESTATIC - : Constants.INVOKEVIRTUAL, resolvedMember)); - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(inlineAccessor.getReturnType()))); - - inlineAccessors.put(key, new BcelMethod(aspectGen.getBcelObjectType(), method.getMethod(), methodAttributes)); - } - return inlineAccessor; - } - - /** - * Add an inline wrapper for a non public super.method call - */ - private ResolvedMember createOrGetInlineAccessorForSuperDispatch(ResolvedMember resolvedMember) { - String accessor = NameMangler.superDispatchMethod(aspectType, resolvedMember.getName()); - - String key = accessor; - ResolvedMember inlineAccessor = inlineAccessors.get(key); - - if (inlineAccessor == null) { - // add super accessor method to class: - inlineAccessor = AjcMemberMaker.superAccessMethod(aspectType, resolvedMember); - - // add new accessor method to aspect bytecode - InstructionFactory factory = aspectGen.getFactory(); - LazyMethodGen method = makeMethodGen(aspectGen, inlineAccessor); - // flag it synthetic, AjSynthetic - method.makeSynthetic(); - List<AjAttribute> methodAttributes = new ArrayList<AjAttribute>(); - methodAttributes.add(new AjAttribute.AjSynthetic()); - methodAttributes.add(new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.MethodCall, false)); - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(0), aspectGen.getConstantPool())); - // flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(1), aspectGen.getConstantPool())); - - inlineAccessorMethodGens.add(method); - - InstructionList il = method.getBody(); - il.append(InstructionConstants.ALOAD_0); - int register = 1; - for (int i = 0; i < inlineAccessor.getParameterTypes().length; i++) { - UnresolvedType typeX = inlineAccessor.getParameterTypes()[i]; - Type type = BcelWorld.makeBcelType(typeX); - il.append(InstructionFactory.createLoad(type, register)); - register += type.getSize(); - } - il.append(Utility.createInvoke(factory, Constants.INVOKESPECIAL, resolvedMember)); - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(inlineAccessor.getReturnType()))); - - inlineAccessors.put(key, new BcelMethod(aspectGen.getBcelObjectType(), method.getMethod(), methodAttributes)); - } - return inlineAccessor; - } - - /** - * Add an inline wrapper for a non public field get - */ - private ResolvedMember createOrGetInlineAccessorForFieldGet(ResolvedMember resolvedMember) { - String accessor = NameMangler.inlineAccessMethodForFieldGet(resolvedMember.getName(), resolvedMember.getDeclaringType(), - aspectType); - String key = accessor; - ResolvedMember inlineAccessor = inlineAccessors.get(key); - - if (inlineAccessor == null) { - // add static method to aspect - inlineAccessor = AjcMemberMaker.inlineAccessMethodForFieldGet(aspectType, resolvedMember); - - // add new accessor method to aspect bytecode - InstructionFactory factory = aspectGen.getFactory(); - LazyMethodGen method = makeMethodGen(aspectGen, inlineAccessor); - // flag it synthetic, AjSynthetic - method.makeSynthetic(); - List<AjAttribute> methodAttributes = new ArrayList<AjAttribute>(); - methodAttributes.add(new AjAttribute.AjSynthetic()); - methodAttributes.add(new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.FieldGet, false)); - // flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(0), aspectGen.getConstantPool())); - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(1), aspectGen.getConstantPool())); - - inlineAccessorMethodGens.add(method); - - InstructionList il = method.getBody(); - if (Modifier.isStatic(resolvedMember.getModifiers())) { - // field accessed is static so no "this" as accessor sole parameter - } else { - il.append(InstructionConstants.ALOAD_0); - } - il.append(Utility.createGet(factory, resolvedMember)); - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(inlineAccessor.getReturnType()))); - - inlineAccessors.put(key, new BcelMethod(aspectGen.getBcelObjectType(), method.getMethod(), methodAttributes)); - } - return inlineAccessor; - } - - /** - * Add an inline wrapper for a non public field set - */ - private ResolvedMember createOrGetInlineAccessorForFieldSet(ResolvedMember resolvedMember) { - String accessor = NameMangler.inlineAccessMethodForFieldSet(resolvedMember.getName(), resolvedMember.getDeclaringType(), - aspectType); - String key = accessor; - ResolvedMember inlineAccessor = inlineAccessors.get(key); - - if (inlineAccessor == null) { - // add static method to aspect - inlineAccessor = AjcMemberMaker.inlineAccessMethodForFieldSet(aspectType, resolvedMember); - - // add new accessor method to aspect bytecode - InstructionFactory factory = aspectGen.getFactory(); - LazyMethodGen method = makeMethodGen(aspectGen, inlineAccessor); - // flag it synthetic, AjSynthetic - method.makeSynthetic(); - List<AjAttribute> methodAttributes = new ArrayList<AjAttribute>(); - methodAttributes.add(new AjAttribute.AjSynthetic()); - methodAttributes.add(new AjAttribute.EffectiveSignatureAttribute(resolvedMember, Shadow.FieldSet, false)); - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(0), aspectGen.getConstantPool())); - // flag the effective signature, so that we can deobfuscate the signature to apply method call pointcut - method.addAttribute(Utility.bcelAttribute(methodAttributes.get(1), aspectGen.getConstantPool())); - - inlineAccessorMethodGens.add(method); - - InstructionList il = method.getBody(); - if (Modifier.isStatic(resolvedMember.getModifiers())) { - // field accessed is static so sole parameter is field value to be set - il.append(InstructionFactory.createLoad(BcelWorld.makeBcelType(resolvedMember.getReturnType()), 0)); - } else { - il.append(InstructionConstants.ALOAD_0); - il.append(InstructionFactory.createLoad(BcelWorld.makeBcelType(resolvedMember.getReturnType()), 1)); - } - il.append(Utility.createSet(factory, resolvedMember)); - il.append(InstructionConstants.RETURN); - inlineAccessors.put(key, new BcelMethod(aspectGen.getBcelObjectType(), method.getMethod(), methodAttributes)); - } - return inlineAccessor; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java b/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java deleted file mode 100644 index d22b17d12..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java +++ /dev/null @@ -1,801 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.LocalVariable; -import org.aspectj.apache.bcel.classfile.LocalVariableTable; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.LineNumberTag; -import org.aspectj.apache.bcel.generic.LocalVariableTag; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.IEclipseSourceContext; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.Lint; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.World; -import org.aspectj.weaver.ast.Literal; -import org.aspectj.weaver.ast.Test; -import org.aspectj.weaver.patterns.ExactTypePattern; -import org.aspectj.weaver.patterns.ExposedState; -import org.aspectj.weaver.patterns.PerClause; -import org.aspectj.weaver.patterns.Pointcut; - -/** - * Advice implemented for BCEL - * - * @author Erik Hilsdale - * @author Jim Hugunin - * @author Andy Clement - */ -class BcelAdvice extends Advice { - - /** - * If a match is not entirely statically determinable, this captures the runtime test that must succeed in order for the advice - * to run. - */ - private Test runtimeTest; - private ExposedState exposedState; - private int containsInvokedynamic = 0;// 0 = dontknow, 1=no, 2=yes - - public BcelAdvice(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member adviceSignature, ResolvedType concreteAspect) { - super(attribute, pointcut, simplify(attribute.getKind(), adviceSignature)); - this.concreteAspect = concreteAspect; - } - - /** - * A heavyweight BcelMethod object is only required for around advice that will be inlined. For other kinds of advice it is - * possible to save some space. - */ - private static Member simplify(AdviceKind kind, Member adviceSignature) { - if (adviceSignature != null) { - UnresolvedType adviceDeclaringType = adviceSignature.getDeclaringType(); - // if it isnt around advice or it is but inlining is turned off then shrink it to a ResolvedMemberImpl - if (kind != AdviceKind.Around - || ((adviceDeclaringType instanceof ResolvedType) && ((ResolvedType) adviceDeclaringType).getWorld() - .isXnoInline())) { - if (adviceSignature instanceof BcelMethod) { - BcelMethod bm = (BcelMethod) adviceSignature; - if (bm.getMethod() != null && bm.getMethod().getAnnotations() != null) { - return adviceSignature; - } - ResolvedMemberImpl simplermember = new ResolvedMemberImpl(bm.getKind(), bm.getDeclaringType(), - bm.getModifiers(), bm.getReturnType(), bm.getName(), bm.getParameterTypes());// ,bm.getExceptions(),bm.getBackingGenericMember() - // ); - simplermember.setParameterNames(bm.getParameterNames()); - return simplermember; - } - } - } - return adviceSignature; - } - - @Override - public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) { - if (!world.areAllLintIgnored()) { - suppressLintWarnings(world); - } - ShadowMunger ret = super.concretize(fromType, world, clause); - if (!world.areAllLintIgnored()) { - clearLintSuppressions(world, this.suppressedLintKinds); - } - IfFinder ifinder = new IfFinder(); - ret.getPointcut().accept(ifinder, null); - boolean hasGuardTest = ifinder.hasIf && getKind() != AdviceKind.Around; - boolean isAround = getKind() == AdviceKind.Around; - if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { - if (!isAround && !hasGuardTest && world.getLint().noGuardForLazyTjp.isEnabled()) { - // can't build tjp lazily, no suitable test... - // ... only want to record it once against the advice(bug 133117) - world.getLint().noGuardForLazyTjp.signal("", getSourceLocation()); - } - } - return ret; - } - - @Override - public ShadowMunger parameterizeWith(ResolvedType declaringType, Map<String, UnresolvedType> typeVariableMap) { - Pointcut pc = getPointcut().parameterizeWith(typeVariableMap, declaringType.getWorld()); - - BcelAdvice ret = null; - Member adviceSignature = signature; - // allows for around advice where the return value is a type variable (see pr115250) - if (signature instanceof ResolvedMember && signature.getDeclaringType().isGenericType()) { - adviceSignature = ((ResolvedMember) signature).parameterizedWith(declaringType.getTypeParameters(), declaringType, - declaringType.isParameterizedType()); - } - ret = new BcelAdvice(this.attribute, pc, adviceSignature, this.concreteAspect); - return ret; - } - - @Override - public boolean match(Shadow shadow, World world) { - if (world.areAllLintIgnored()) { - return super.match(shadow, world); - } else { - suppressLintWarnings(world); - boolean ret = super.match(shadow, world); - clearLintSuppressions(world, this.suppressedLintKinds); - return ret; - } - } - - @Override - public void specializeOn(Shadow shadow) { - if (getKind() == AdviceKind.Around) { - ((BcelShadow) shadow).initializeForAroundClosure(); - } - - // XXX this case is just here for supporting lazy test code - if (getKind() == null) { - exposedState = new ExposedState(0); - return; - } - if (getKind().isPerEntry()) { - exposedState = new ExposedState(0); - } else if (getKind().isCflow()) { - exposedState = new ExposedState(nFreeVars); - } else if (getSignature() != null) { - exposedState = new ExposedState(getSignature()); - } else { - exposedState = new ExposedState(0); - return; // XXX this case is just here for supporting lazy test code - } - - World world = shadow.getIWorld(); - if (!world.areAllLintIgnored()) { - suppressLintWarnings(world); - } - exposedState.setConcreteAspect(concreteAspect); - runtimeTest = getPointcut().findResidue(shadow, exposedState); - if (!world.areAllLintIgnored()) { - clearLintSuppressions(world, this.suppressedLintKinds); - } - - // these initializations won't be performed by findResidue, but need to be - // so that the joinpoint is primed for weaving - if (getKind() == AdviceKind.PerThisEntry) { - shadow.getThisVar(); - } else if (getKind() == AdviceKind.PerTargetEntry) { - shadow.getTargetVar(); - } - - // make sure thisJoinPoint parameters are initialized - if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) { - ((BcelShadow) shadow).getThisJoinPointStaticPartVar(); - ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation()); - } - - if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { - boolean hasGuardTest = runtimeTest != Literal.TRUE && getKind() != AdviceKind.Around; - boolean isAround = getKind() == AdviceKind.Around; - ((BcelShadow) shadow).requireThisJoinPoint(hasGuardTest, isAround); - ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation()); - if (!hasGuardTest && world.getLint().multipleAdviceStoppingLazyTjp.isEnabled()) { - // collect up the problematic advice - ((BcelShadow) shadow).addAdvicePreventingLazyTjp(this); - } - } - - if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) { - ((BcelShadow) shadow).getThisEnclosingJoinPointStaticPartVar(); - ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation()); - } - } - - private boolean canInline(Shadow s) { - if (attribute.isProceedInInners()) { - return false; - } - // XXX this guard seems to only be needed for bad test cases - if (concreteAspect == null || concreteAspect.isMissing()) { - return false; - } - - if (concreteAspect.getWorld().isXnoInline()) { - return false; - } - // System.err.println("isWoven? " + ((BcelObjectType)concreteAspect).getLazyClassGen().getWeaverState()); - BcelObjectType boType = BcelWorld.getBcelObjectType(concreteAspect); - if (boType == null) { - // Could be a symptom that the aspect failed to build last build... return the default answer of false - return false; - } - // Need isJava8 check - // Does the advice contain invokedynamic... - if (boType.javaClass.getMajor() == Constants.MAJOR_1_8) { - if (containsInvokedynamic == 0) { - containsInvokedynamic = 1; - LazyMethodGen lmg = boType.getLazyClassGen().getLazyMethodGen(this.signature.getName(), this.signature.getSignature(), true); - // Check Java8 supertypes - ResolvedType searchType = concreteAspect; - while (lmg == null) { - searchType = searchType.getSuperclass(); - if (searchType == null) break; - ReferenceTypeDelegate rtd = ((ReferenceType)searchType).getDelegate(); - if (rtd instanceof BcelObjectType) { - BcelObjectType bot = (BcelObjectType)rtd; - if (bot.javaClass.getMajor() < Constants.MAJOR_1_8) { - break; - } - lmg = bot.getLazyClassGen().getLazyMethodGen(this.signature.getName(), this.signature.getSignature(), true); - } - } - if (lmg != null) { - InstructionList ilist = lmg.getBody(); - for (InstructionHandle src = ilist.getStart(); src != null; src = src.getNext()) { - if (src.getInstruction().opcode == Constants.INVOKEDYNAMIC) { - containsInvokedynamic = 2; - break; - } - } - } - } - } - if (containsInvokedynamic == 2) { - return false; - } - return boType.getLazyClassGen().isWoven(); - } - - private boolean aspectIsBroken() { - if (concreteAspect instanceof ReferenceType) { - ReferenceTypeDelegate rtDelegate = ((ReferenceType) concreteAspect).getDelegate(); - if (!(rtDelegate instanceof BcelObjectType)) { - return true; - } - } - return false; - } - - @Override - public boolean implementOn(Shadow s) { - hasMatchedAtLeastOnce = true; - - // pr263323 - if the aspect is broken then the delegate will not be usable for weaving - if (aspectIsBroken()) { - return false; - } - - BcelShadow shadow = (BcelShadow) s; - - // remove any unnecessary exceptions if the compiler option is set to - // error or warning and if this piece of advice throws exceptions - // (bug 129282). This may be expanded to include other compiler warnings - // at the moment it only deals with 'declared exception is not thrown' - if (!shadow.getWorld().isIgnoringUnusedDeclaredThrownException() && !getThrownExceptions().isEmpty()) { - Member member = shadow.getSignature(); - if (member instanceof BcelMethod) { - removeUnnecessaryProblems((BcelMethod) member, ((BcelMethod) member).getDeclarationLineNumber()); - } else { - // we're in a call shadow therefore need the line number of the - // declared method (which may be in a different type). However, - // we want to remove the problems from the CompilationResult - // held within the current type's EclipseSourceContext so need - // the enclosing shadow too - ResolvedMember resolvedMember = shadow.getSignature().resolve(shadow.getWorld()); - if (resolvedMember instanceof BcelMethod && shadow.getEnclosingShadow() instanceof BcelShadow) { - Member enclosingMember = shadow.getEnclosingShadow().getSignature(); - if (enclosingMember instanceof BcelMethod) { - removeUnnecessaryProblems((BcelMethod) enclosingMember, - ((BcelMethod) resolvedMember).getDeclarationLineNumber()); - } - } - } - } - - if (shadow.getIWorld().isJoinpointSynchronizationEnabled() && shadow.getKind() == Shadow.MethodExecution - && (s.getSignature().getModifiers() & Modifier.SYNCHRONIZED) != 0) { - shadow.getIWorld().getLint().advisingSynchronizedMethods.signal(new String[] { shadow.toString() }, - shadow.getSourceLocation(), new ISourceLocation[] { getSourceLocation() }); - } - - // FIXME AV - see #75442, this logic is not enough so for now comment it out until we fix the bug - // // callback for perObject AJC MightHaveAspect postMunge (#75442) - // if (getConcreteAspect() != null - // && getConcreteAspect().getPerClause() != null - // && PerClause.PEROBJECT.equals(getConcreteAspect().getPerClause().getKind())) { - // final PerObject clause; - // if (getConcreteAspect().getPerClause() instanceof PerFromSuper) { - // clause = (PerObject)((PerFromSuper) getConcreteAspect().getPerClause()).lookupConcretePerClause(getConcreteAspect()); - // } else { - // clause = (PerObject) getConcreteAspect().getPerClause(); - // } - // if (clause.isThis()) { - // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getThisVar().getType(), getConcreteAspect()); - // } else { - // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getTargetVar().getType(), getConcreteAspect()); - // } - // } - if (runtimeTest == Literal.FALSE) { // not usually allowed, except in one case (260384) - Member sig = shadow.getSignature(); - if (sig.getArity() == 0 && shadow.getKind() == Shadow.MethodCall && sig.getName().charAt(0) == 'c' - && sig.getReturnType().equals(ResolvedType.OBJECT) && sig.getName().equals("clone")) { - return false; - } - } - - if (getKind() == AdviceKind.Before) { - shadow.weaveBefore(this); - } else if (getKind() == AdviceKind.AfterReturning) { - shadow.weaveAfterReturning(this); - } else if (getKind() == AdviceKind.AfterThrowing) { - UnresolvedType catchType = hasExtraParameter() ? getExtraParameterType() : UnresolvedType.THROWABLE; - shadow.weaveAfterThrowing(this, catchType); - } else if (getKind() == AdviceKind.After) { - shadow.weaveAfter(this); - } else if (getKind() == AdviceKind.Around) { - // Note: under regular LTW the aspect is usually loaded after the first use of any class affected by it. - // This means that as long as the aspect has not been thru the LTW, it's woven state is unknown - // and thus canInline(s) will return false. - // To force inlining (test), ones can do Class aspect = FQNAspect.class in the clinit of the target class - // FIXME AV : for AJC compiled @AJ aspect (or any code style aspect), the woven state can never be known - // if the aspect belongs to a parent classloader. In that case the aspect will never be inlined. - // It might be dangerous to change that especially for @AJ aspect non compiled with AJC since if those - // are not weaved (f.e. use of some limited LTW etc) then they cannot be prepared for inlining. - // One solution would be to flag @AJ aspect with an annotation as "prepared" and query that one. - LazyClassGen enclosingClass = shadow.getEnclosingClass(); - if (enclosingClass != null && enclosingClass.isInterface() && shadow.getEnclosingMethod().getName().charAt(0) == '<') { - // Do not add methods with bodies to an interface (252198, 163005) - shadow.getWorld().getLint().cannotAdviseJoinpointInInterfaceWithAroundAdvice.signal(shadow.toString(), - shadow.getSourceLocation()); - return false; - } - if (!canInline(s)) { - shadow.weaveAroundClosure(this, hasDynamicTests()); - } else { - shadow.weaveAroundInline(this, hasDynamicTests()); - } - } else if (getKind() == AdviceKind.InterInitializer) { - shadow.weaveAfterReturning(this); - } else if (getKind().isCflow()) { - shadow.weaveCflowEntry(this, getSignature()); - } else if (getKind() == AdviceKind.PerThisEntry) { - shadow.weavePerObjectEntry(this, (BcelVar) shadow.getThisVar()); - } else if (getKind() == AdviceKind.PerTargetEntry) { - shadow.weavePerObjectEntry(this, (BcelVar) shadow.getTargetVar()); - } else if (getKind() == AdviceKind.Softener) { - shadow.weaveSoftener(this, ((ExactTypePattern) exceptionType).getType()); - } else if (getKind() == AdviceKind.PerTypeWithinEntry) { - // PTWIMPL Entry to ptw is the static initialization of a type that matched the ptw type pattern - shadow.weavePerTypeWithinAspectInitialization(this, shadow.getEnclosingType()); - } else { - throw new BCException("unimplemented kind: " + getKind()); - } - return true; - } - - private void removeUnnecessaryProblems(BcelMethod method, int problemLineNumber) { - ISourceContext sourceContext = method.getSourceContext(); - if (sourceContext instanceof IEclipseSourceContext) { - ((IEclipseSourceContext) sourceContext).removeUnnecessaryProblems(method, problemLineNumber); - } - } - - // ---- implementations - - private Collection<ResolvedType> collectCheckedExceptions(UnresolvedType[] excs) { - if (excs == null || excs.length == 0) { - return Collections.emptyList(); - } - - Collection<ResolvedType> ret = new ArrayList<ResolvedType>(); - World world = concreteAspect.getWorld(); - ResolvedType runtimeException = world.getCoreType(UnresolvedType.RUNTIME_EXCEPTION); - ResolvedType error = world.getCoreType(UnresolvedType.ERROR); - - for (int i = 0, len = excs.length; i < len; i++) { - ResolvedType t = world.resolve(excs[i], true); - if (t.isMissing()) { - world.getLint().cantFindType - .signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_EXCEPTION_TYPE, excs[i].getName()), - getSourceLocation()); - // IMessage msg = new Message( - // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_EXCEPTION_TYPE,excs[i].getName()), - // "",IMessage.ERROR,getSourceLocation(),null,null); - // world.getMessageHandler().handleMessage(msg); - } - if (!(runtimeException.isAssignableFrom(t) || error.isAssignableFrom(t))) { - ret.add(t); - } - } - - return ret; - } - - private Collection<ResolvedType> thrownExceptions = null; - - @Override - public Collection<ResolvedType> getThrownExceptions() { - if (thrownExceptions == null) { - // ??? can we really lump in Around here, how does this interact with Throwable - if (concreteAspect != null && concreteAspect.getWorld() != null && // null tests for test harness - (getKind().isAfter() || getKind() == AdviceKind.Before || getKind() == AdviceKind.Around)) { - World world = concreteAspect.getWorld(); - ResolvedMember m = world.resolve(signature); - if (m == null) { - thrownExceptions = Collections.emptyList(); - } else { - thrownExceptions = collectCheckedExceptions(m.getExceptions()); - } - } else { - thrownExceptions = Collections.emptyList(); - } - } - return thrownExceptions; - } - - /** - * The munger must not check for the advice exceptions to be declared by the shadow in the case of @AJ aspects so that around - * can throws Throwable - * - * @return - */ - @Override - public boolean mustCheckExceptions() { - if (getConcreteAspect() == null) { - return true; - } - return !getConcreteAspect().isAnnotationStyleAspect(); - } - - // only call me after prepare has been called - @Override - public boolean hasDynamicTests() { - // if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) { - // UnresolvedType extraParameterType = getExtraParameterType(); - // if (! extraParameterType.equals(UnresolvedType.OBJECT) - // && ! extraParameterType.isPrimitive()) - // return true; - // } - - return runtimeTest != null && !(runtimeTest == Literal.TRUE);// || pointcutTest == Literal.NO_TEST); - } - - /** - * get the instruction list for the really simple version of this advice. Is broken apart for other advice, but if you want it - * in one block, this is the method to call. - * - * @param s The shadow around which these instructions will eventually live. - * @param extraArgVar The var that will hold the return value or thrown exception for afterX advice - * @param ifNoAdvice The instructionHandle to jump to if the dynamic tests for this munger fails. - */ - InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) { - BcelShadow shadow = s; - InstructionFactory fact = shadow.getFactory(); - BcelWorld world = shadow.getWorld(); - - InstructionList il = new InstructionList(); - - // we test to see if we have the right kind of thing... - // after throwing does this just by the exception mechanism. - if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) { - UnresolvedType extraParameterType = getExtraParameterType(); - if (!extraParameterType.equals(UnresolvedType.OBJECT) && !extraParameterType.isPrimitiveType()) { - il.append(BcelRenderer.renderTest(fact, world, - Test.makeInstanceof(extraArgVar, getExtraParameterType().resolve(world)), null, ifNoAdvice, null)); - } - } - il.append(getAdviceArgSetup(shadow, extraArgVar, null)); - il.append(getNonTestAdviceInstructions(shadow)); - - InstructionHandle ifYesAdvice = il.getStart(); - il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice)); - - // If inserting instructions at the start of a method, we need a nice line number for this entry - // in the stack trace - if (shadow.getKind() == Shadow.MethodExecution && getKind() == AdviceKind.Before) { - int lineNumber = 0; - // Uncomment this code if you think we should use the method decl line number when it exists... - // // If the advised join point is in a class built by AspectJ, we can use the declaration line number - // boolean b = shadow.getEnclosingMethod().getMemberView().hasDeclarationLineNumberInfo(); - // if (b) { - // lineNumber = shadow.getEnclosingMethod().getMemberView().getDeclarationLineNumber(); - // } else { // If it wasn't, the best we can do is the line number of the first instruction in the method - lineNumber = shadow.getEnclosingMethod().getMemberView().getLineNumberOfFirstInstruction(); - // } - InstructionHandle start = il.getStart(); - if (lineNumber > 0) { - start.addTargeter(new LineNumberTag(lineNumber)); - } - // Fix up the local variables: find any that have a startPC of 0 and ensure they target the new start of the method - LocalVariableTable lvt = shadow.getEnclosingMethod().getMemberView().getMethod().getLocalVariableTable(); - if (lvt != null) { - LocalVariable[] lvTable = lvt.getLocalVariableTable(); - for (int i = 0; i < lvTable.length; i++) { - LocalVariable lv = lvTable[i]; - if (lv.getStartPC() == 0) { - start.addTargeter(new LocalVariableTag(lv.getSignature(), lv.getName(), lv.getIndex(), 0)); - } - } - } - } - - return il; - } - - public InstructionList getAdviceArgSetup(BcelShadow shadow, BcelVar extraVar, InstructionList closureInstantiation) { - InstructionFactory fact = shadow.getFactory(); - BcelWorld world = shadow.getWorld(); - InstructionList il = new InstructionList(); - - // if (targetAspectField != null) { - // il.append(fact.createFieldAccess( - // targetAspectField.getDeclaringType().getName(), - // targetAspectField.getName(), - // BcelWorld.makeBcelType(targetAspectField.getType()), - // Constants.GETSTATIC)); - // } - // - // System.err.println("BcelAdvice: " + exposedState); - - if (exposedState.getAspectInstance() != null) { - il.append(BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance())); - } - // pr121385 - boolean x = this.getDeclaringAspect().resolve(world).isAnnotationStyleAspect(); - final boolean isAnnotationStyleAspect = getConcreteAspect() != null && getConcreteAspect().isAnnotationStyleAspect() && x; - boolean previousIsClosure = false; - for (int i = 0, len = exposedState.size(); i < len; i++) { - if (exposedState.isErroneousVar(i)) { - continue; // Erroneous vars have already had error msgs reported! - } - BcelVar v = (BcelVar) exposedState.get(i); - - if (v == null) { - // if not @AJ aspect, go on with the regular binding handling - if (!isAnnotationStyleAspect) { - - } else { - // ATAJ: for @AJ aspects, handle implicit binding of xxJoinPoint - // if (getKind() == AdviceKind.Around) { - // previousIsClosure = true; - // il.append(closureInstantiation); - if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) { - // make sure we are in an around, since we deal with the closure, not the arg here - if (getKind() != AdviceKind.Around) { - previousIsClosure = false; - getConcreteAspect() - .getWorld() - .getMessageHandler() - .handleMessage( - new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg " - + i + " in " + toString() + ")", this.getSourceLocation(), true)); - // try to avoid verify error and pass in null - il.append(InstructionConstants.ACONST_NULL); - } else { - if (previousIsClosure) { - il.append(InstructionConstants.DUP); - } else { - previousIsClosure = true; - il.append(closureInstantiation.copy()); - } - } - } else if ("Lorg/aspectj/lang/JoinPoint$StaticPart;".equals(getSignature().getParameterTypes()[i] - .getSignature())) { - previousIsClosure = false; - if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) { - shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact); - } - } else if ("Lorg/aspectj/lang/JoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) { - previousIsClosure = false; - if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { - il.append(shadow.loadThisJoinPoint()); - } - } else if ("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".equals(getSignature().getParameterTypes()[i] - .getSignature())) { - previousIsClosure = false; - if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) { - shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact); - } - } else if (hasExtraParameter()) { - previousIsClosure = false; - extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world)); - } else { - previousIsClosure = false; - getConcreteAspect() - .getWorld() - .getMessageHandler() - .handleMessage( - new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg " + i - + " in " + toString() + ")", this.getSourceLocation(), true)); - // try to avoid verify error and pass in null - il.append(InstructionConstants.ACONST_NULL); - } - } - } else { - UnresolvedType desiredTy = getBindingParameterTypes()[i]; - v.appendLoadAndConvert(il, fact, desiredTy.resolve(world)); - } - } - - // ATAJ: for code style aspect, handles the extraFlag as usual ie not - // in the middle of the formal bindings but at the end, in a rock solid ordering - if (!isAnnotationStyleAspect) { - if (getKind() == AdviceKind.Around) { - il.append(closureInstantiation); - } else if (hasExtraParameter()) { - extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world)); - } - - // handle thisJoinPoint parameters - // these need to be in that same order as parameters in - // org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration - if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) { - shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact); - } - - if ((getExtraParameterFlags() & ThisJoinPoint) != 0) { - il.append(shadow.loadThisJoinPoint()); - } - - if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) { - shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact); - } - } - - return il; - } - - public InstructionList getNonTestAdviceInstructions(BcelShadow shadow) { - return new InstructionList(Utility.createInvoke(shadow.getFactory(), shadow.getWorld(), getOriginalSignature())); - } - - @Override - public Member getOriginalSignature() { - Member sig = getSignature(); - if (sig instanceof ResolvedMember) { - ResolvedMember rsig = (ResolvedMember) sig; - if (rsig.hasBackingGenericMember()) { - return rsig.getBackingGenericMember(); - } - } - return sig; - } - - public InstructionList getTestInstructions(BcelShadow shadow, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) { - // System.err.println("test: " + pointcutTest); - return BcelRenderer.renderTest(shadow.getFactory(), shadow.getWorld(), runtimeTest, sk, fk, next); - } - - public int compareTo(Object other) { - if (!(other instanceof BcelAdvice)) { - return 0; - } - BcelAdvice o = (BcelAdvice) other; - - // System.err.println("compareTo: " + this + ", " + o); - if (kind.getPrecedence() != o.kind.getPrecedence()) { - if (kind.getPrecedence() > o.kind.getPrecedence()) { - return +1; - } else { - return -1; - } - } - - if (kind.isCflow()) { - // System.err.println("sort: " + this + " innerCflowEntries " + innerCflowEntries); - // System.err.println(" " + o + " innerCflowEntries " + o.innerCflowEntries); - boolean isBelow = (kind == AdviceKind.CflowBelowEntry); - - if (this.innerCflowEntries.contains(o)) { - return isBelow ? +1 : -1; - } else if (o.innerCflowEntries.contains(this)) { - return isBelow ? -1 : +1; - } else { - return 0; - } - } - - if (kind.isPerEntry() || kind == AdviceKind.Softener) { - return 0; - } - - // System.out.println("compare: " + this + " with " + other); - World world = concreteAspect.getWorld(); - - int ret = concreteAspect.getWorld().compareByPrecedence(concreteAspect, o.concreteAspect); - if (ret != 0) { - return ret; - } - - ResolvedType declaringAspect = getDeclaringAspect().resolve(world); - ResolvedType o_declaringAspect = o.getDeclaringAspect().resolve(world); - - if (declaringAspect == o_declaringAspect) { - if (kind.isAfter() || o.kind.isAfter()) { - return this.getStart() < o.getStart() ? -1 : +1; - } else { - return this.getStart() < o.getStart() ? +1 : -1; - } - } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) { - return -1; - } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) { - return +1; - } else { - return 0; - } - } - - public BcelVar[] getExposedStateAsBcelVars(boolean isAround) { - // ATAJ aspect - if (isAround) { - // the closure instantiation has the same mapping as the extracted method from wich it is called - if (getConcreteAspect() != null && getConcreteAspect().isAnnotationStyleAspect()) { - return BcelVar.NONE; - } - } - - // System.out.println("vars: " + Arrays.asList(exposedState.vars)); - if (exposedState == null) { - return BcelVar.NONE; - } - int len = exposedState.vars.length; - BcelVar[] ret = new BcelVar[len]; - for (int i = 0; i < len; i++) { - ret[i] = (BcelVar) exposedState.vars[i]; - } - return ret; // (BcelVar[]) exposedState.vars; - } - - protected void suppressLintWarnings(World inWorld) { - if (suppressedLintKinds == null) { - if (signature instanceof BcelMethod) { - this.suppressedLintKinds = Utility.getSuppressedWarnings(signature.getAnnotations(), inWorld.getLint()); - } else { - this.suppressedLintKinds = Collections.emptyList(); - return; - } - } - inWorld.getLint().suppressKinds(suppressedLintKinds); - } - - protected void clearLintSuppressions(World inWorld, Collection<Lint.Kind> toClear) { - inWorld.getLint().clearSuppressions(toClear); - } - - /** - * For testing only - */ - public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature, int extraArgumentFlags, int start, int end, - ISourceContext sourceContext, ResolvedType concreteAspect) { - this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext), pointcut, signature, - concreteAspect); - thrownExceptions = Collections.emptyList(); // !!! interaction with unit tests - } - -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAnnotation.java b/weaver/src/org/aspectj/weaver/bcel/BcelAnnotation.java deleted file mode 100644 index 275eae512..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelAnnotation.java +++ /dev/null @@ -1,151 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008 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 - * - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; -import org.aspectj.apache.bcel.classfile.annotation.ElementValue; -import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.weaver.AbstractAnnotationAJ; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; - -/** - * Wraps a Bcel Annotation object and uses it to answer AnnotationAJ method calls. This is cheaper than translating all Bcel - * annotations into AnnotationAJ objects. - * - * @author AndyClement - */ -public class BcelAnnotation extends AbstractAnnotationAJ { - - private final AnnotationGen bcelAnnotation; - - public BcelAnnotation(AnnotationGen theBcelAnnotation, World world) { - super(UnresolvedType.forSignature(theBcelAnnotation.getTypeSignature()).resolve(world)); - this.bcelAnnotation = theBcelAnnotation; - } - - public BcelAnnotation(AnnotationGen theBcelAnnotation, ResolvedType resolvedAnnotationType) { - super(resolvedAnnotationType); - this.bcelAnnotation = theBcelAnnotation; - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - List<NameValuePair> nvPairs = bcelAnnotation.getValues(); - sb.append("Anno[" + getTypeSignature() + " " + (isRuntimeVisible() ? "rVis" : "rInvis")); - if (nvPairs.size() > 0) { - sb.append(" "); - int i = 0; - for (NameValuePair element : nvPairs) { - if (i > 0) { - sb.append(','); - } - sb.append(element.getNameString()).append("=").append(element.getValue().toString()); - i++; - } - } - sb.append("]"); - return sb.toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public Set<String> getTargets() { - if (!type.equals(UnresolvedType.AT_TARGET)) { - return Collections.emptySet(); - } - List<NameValuePair> values = bcelAnnotation.getValues(); - NameValuePair envp = values.get(0); - ArrayElementValue aev = (ArrayElementValue) envp.getValue(); - ElementValue[] evs = aev.getElementValuesArray(); - Set<String> targets = new HashSet<String>(); - for (int i = 0; i < evs.length; i++) { - EnumElementValue ev = (EnumElementValue) evs[i]; - targets.add(ev.getEnumValueString()); - } - return targets; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNameValuePair(String name, String value) { - return bcelAnnotation.hasNameValuePair(name, value); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean hasNamedValue(String name) { - return bcelAnnotation.hasNamedValue(name); - } - - /** - * {@inheritDoc} - */ - @Override - public String stringify() { - StringBuffer sb = new StringBuffer(); - sb.append("@").append(type.getClassName()); - List<NameValuePair> values = bcelAnnotation.getValues(); - if (values != null && values.size() != 0) { - sb.append("("); - for (NameValuePair nvPair : values) { - sb.append(nvPair.getNameString()).append("=").append(nvPair.getValue().stringifyValue()); - } - sb.append(")"); - } - return sb.toString(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isRuntimeVisible() { - return this.bcelAnnotation.isRuntimeVisible(); - } - - /** - * @return return the real bcel annotation being wrapped - */ - public AnnotationGen getBcelAnnotation() { - return bcelAnnotation; - } - - /** - * {@inheritDoc} - */ - public String getStringFormOfValue(String name) { - List<NameValuePair> annotationValues = this.bcelAnnotation.getValues(); - if (annotationValues == null || annotationValues.size() == 0) { - return null; - } else { - for (NameValuePair nvPair : annotationValues) { - if (nvPair.getNameString().equals(name)) { - return nvPair.getValue().stringifyValue(); - } - } - return null; - } - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java deleted file mode 100644 index 2640edd95..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java +++ /dev/null @@ -1,87 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedType; - -/** - * XXX Erik and I need to discuss this hierarchy. Having FieldRef extend Var is convenient, but hopefully there's a better design. - * - * This is always a static reference. - */ -public class BcelCflowAccessVar extends BcelVar { - - private Member stackField; - private int index; - - /** - * @param type The type to convert to from Object - * @param stackField the member containing the CFLOW_STACK_TYPE - * @param index yeah yeah - */ - public BcelCflowAccessVar(ResolvedType type, Member stackField, int index) { - super(type, 0); - this.stackField = stackField; - this.index = index; - } - - public String toString() { - return "BcelCflowAccessVar(" + getType() + " " + stackField + "." + index + ")"; - } - - public Instruction createLoad(InstructionFactory fact) { - throw new RuntimeException("unimplemented"); - } - - public Instruction createStore(InstructionFactory fact) { - throw new RuntimeException("unimplemented"); - } - - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - throw new RuntimeException("unimplemented"); - } - - public void appendLoad(InstructionList il, InstructionFactory fact) { - il.append(createLoadInstructions(getType(), fact)); - } - - public InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) { - InstructionList il = new InstructionList(); - - il.append(Utility.createGet(fact, stackField)); - il.append(Utility.createConstant(fact, index)); - il.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "get", Type.OBJECT, new Type[] { Type.INT }, - Constants.INVOKEVIRTUAL)); - il.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(toType))); - - return il; - - } - - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - il.append(createLoadInstructions(toType, fact)); - - } - - public void insertLoad(InstructionList il, InstructionFactory fact) { - il.insert(createLoadInstructions(getType(), fact)); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java deleted file mode 100644 index a70a5d8a9..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelCflowCounterFieldAdder.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - * (Andy Clement) - *******************************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; - -/** - * This type munger will modify a given class (see the munge() method) to include a field representing a CflowCounter object. - */ -public class BcelCflowCounterFieldAdder extends BcelTypeMunger { - private ResolvedMember cflowCounterField; - - public BcelCflowCounterFieldAdder(ResolvedMember cflowCounterField) { - super(null, (ResolvedType) cflowCounterField.getDeclaringType()); - this.cflowCounterField = cflowCounterField; - } - - public boolean munge(BcelClassWeaver weaver) { - LazyClassGen gen = weaver.getLazyClassGen(); - - // Only munge one type! - if (!gen.getType().equals(cflowCounterField.getDeclaringType())) - return false; - - // Create the field declaration. - // Something like: "public static final CflowCounter ajc$cflowCounter$0;" - FieldGen f = new FieldGen(cflowCounterField.getModifiers(), BcelWorld.makeBcelType(cflowCounterField.getReturnType()), - cflowCounterField.getName(), gen.getConstantPool()); - - gen.addField(f, getSourceLocation()); - - // Modify the ajc$preClinit() method to initialize it. - // Something like: "ajc$cflowCounter$0 = new CflowCounter();" - LazyMethodGen clinit = gen.getAjcPreClinit(); // StaticInitializer(); - InstructionList setup = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - - setup.append(fact.createNew(new ObjectType(NameMangler.CFLOW_COUNTER_TYPE))); - setup.append(InstructionFactory.createDup(1)); - setup.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "<init>", Type.VOID, new Type[0], Constants.INVOKESPECIAL)); - - setup.append(Utility.createSet(fact, cflowCounterField)); - clinit.getBody().insert(setup); - - return true; - } - - public ResolvedMember getMatchingSyntheticMember(Member member) { - return null; - } - - public ResolvedMember getSignature() { - return cflowCounterField; - } - - public boolean matches(ResolvedType onType) { - return onType.equals(cflowCounterField.getDeclaringType()); - } - - public boolean existsToSupportShadowMunging() { - return true; - } - - public String toString() { - return "(BcelTypeMunger: CflowField " + cflowCounterField.getDeclaringType().getName() + " " + cflowCounterField.getName() - + ")"; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java deleted file mode 100644 index 455edd174..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java +++ /dev/null @@ -1,77 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; - -public class BcelCflowStackFieldAdder extends BcelTypeMunger { - private ResolvedMember cflowStackField; - - public BcelCflowStackFieldAdder(ResolvedMember cflowStackField) { - super(null, (ResolvedType) cflowStackField.getDeclaringType()); - this.cflowStackField = cflowStackField; - } - - @Override - public boolean munge(BcelClassWeaver weaver) { - LazyClassGen gen = weaver.getLazyClassGen(); - if (!gen.getType().equals(cflowStackField.getDeclaringType())) { - return false; - } - FieldGen f = new FieldGen(cflowStackField.getModifiers(), BcelWorld.makeBcelType(cflowStackField.getReturnType()), - cflowStackField.getName(), gen.getConstantPool()); - gen.addField(f, getSourceLocation()); - - LazyMethodGen clinit = gen.getAjcPreClinit(); // StaticInitializer(); - InstructionList setup = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - - setup.append(fact.createNew(NameMangler.CFLOW_STACK_TYPE)); - setup.append(InstructionFactory.createDup(1)); - setup.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - - setup.append(Utility.createSet(fact, cflowStackField)); - clinit.getBody().insert(setup); - - return true; - } - - @Override - public ResolvedMember getMatchingSyntheticMember(Member member) { - return null; - } - - @Override - public ResolvedMember getSignature() { - return cflowStackField; - } - - @Override - public boolean matches(ResolvedType onType) { - return onType.equals(cflowStackField.getDeclaringType()); - } - - @Override - public boolean existsToSupportShadowMunging() { - return true; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java deleted file mode 100644 index 83919ed50..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java +++ /dev/null @@ -1,3377 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.BootstrapMethods; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.apache.bcel.generic.FieldInstruction; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionCP; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionLV; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionSelect; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.apache.bcel.generic.InvokeInstruction; -import org.aspectj.apache.bcel.generic.LineNumberTag; -import org.aspectj.apache.bcel.generic.LocalVariableTag; -import org.aspectj.apache.bcel.generic.MULTIANEWARRAY; -import org.aspectj.apache.bcel.generic.MethodGen; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.RET; -import org.aspectj.apache.bcel.generic.Tag; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.asm.AsmManager; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.bridge.WeaveMessage; -import org.aspectj.bridge.context.CompilationAndWeavingContext; -import org.aspectj.bridge.context.ContextToken; -import org.aspectj.util.PartialOrder; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.IClassWeaver; -import org.aspectj.weaver.IntMap; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MissingResolvedTypeWithKnownSignature; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.NewConstructorTypeMunger; -import org.aspectj.weaver.NewFieldTypeMunger; -import org.aspectj.weaver.NewMethodTypeMunger; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.UnresolvedTypeVariableReferenceType; -import org.aspectj.weaver.WeaverStateInfo; -import org.aspectj.weaver.World; -import org.aspectj.weaver.model.AsmRelationshipProvider; -import org.aspectj.weaver.patterns.DeclareAnnotation; -import org.aspectj.weaver.patterns.ExactTypePattern; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -class BcelClassWeaver implements IClassWeaver { - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelClassWeaver.class); - - public static boolean weave(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers, - List<ConcreteTypeMunger> typeMungers, List<ConcreteTypeMunger> lateTypeMungers, boolean inReweavableMode) { - BcelClassWeaver classWeaver = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers); - classWeaver.setReweavableMode(inReweavableMode); - boolean b = classWeaver.weave(); - return b; - } - - // -------------------------------------------- - - private final LazyClassGen clazz; - private final List<ShadowMunger> shadowMungers; - private final List<ConcreteTypeMunger> typeMungers; - private final List<ConcreteTypeMunger> lateTypeMungers; - - private List<ShadowMunger>[] indexedShadowMungers; - private boolean canMatchBodyShadows = false; - - private final BcelObjectType ty; // alias of clazz.getType() - private final BcelWorld world; // alias of ty.getWorld() - private final ConstantPool cpg; // alias of clazz.getConstantPoolGen() - private final InstructionFactory fact; // alias of clazz.getFactory(); - - private final List<LazyMethodGen> addedLazyMethodGens = new ArrayList<LazyMethodGen>(); - private final Set<ResolvedMember> addedDispatchTargets = new HashSet<ResolvedMember>(); - - private boolean inReweavableMode = false; - - private List<IfaceInitList> addedSuperInitializersAsList = null; - private final Map<ResolvedType, IfaceInitList> addedSuperInitializers = new HashMap<ResolvedType, IfaceInitList>(); - private final List<ConcreteTypeMunger> addedThisInitializers = new ArrayList<ConcreteTypeMunger>(); - private final List<ConcreteTypeMunger> addedClassInitializers = new ArrayList<ConcreteTypeMunger>(); - - private final Map<ResolvedMember, ResolvedMember> mapToAnnotationHolder = new HashMap<ResolvedMember, ResolvedMember>(); - - // private BcelShadow clinitShadow = null; - - /** - * This holds the initialization and pre-initialization shadows for this class that were actually matched by mungers (if no - * match, then we don't even create the shadows really). - */ - private final List<BcelShadow> initializationShadows = new ArrayList<BcelShadow>(); - - private BcelClassWeaver(BcelWorld world, LazyClassGen clazz, List<ShadowMunger> shadowMungers, - List<ConcreteTypeMunger> typeMungers, List<ConcreteTypeMunger> lateTypeMungers) { - super(); - this.world = world; - this.clazz = clazz; - this.shadowMungers = shadowMungers; - this.typeMungers = typeMungers; - this.lateTypeMungers = lateTypeMungers; - this.ty = clazz.getBcelObjectType(); - this.cpg = clazz.getConstantPool(); - this.fact = clazz.getFactory(); - - indexShadowMungers(); - - initializeSuperInitializerMap(ty.getResolvedTypeX()); - if (!checkedXsetForLowLevelContextCapturing) { - Properties p = world.getExtraConfiguration(); - if (p != null) { - String s = p.getProperty(World.xsetCAPTURE_ALL_CONTEXT, "false"); - captureLowLevelContext = s.equalsIgnoreCase("true"); - if (captureLowLevelContext) { - world.getMessageHandler().handleMessage( - MessageUtil.info("[" + World.xsetCAPTURE_ALL_CONTEXT - + "=true] Enabling collection of low level context for debug/crash messages")); - } - } - checkedXsetForLowLevelContextCapturing = true; - } - } - - private boolean canMatch(Shadow.Kind kind) { - return indexedShadowMungers[kind.getKey()] != null; - } - - // private void fastMatchShadowMungers(List shadowMungers, ArrayList - // mungers, Kind kind) { - // FastMatchInfo info = new FastMatchInfo(clazz.getType(), kind); - // for (Iterator i = shadowMungers.iterator(); i.hasNext();) { - // ShadowMunger munger = (ShadowMunger) i.next(); - // FuzzyBoolean fb = munger.getPointcut().fastMatch(info); - // WeaverMetrics.recordFastMatchResult(fb);// Could pass: - // munger.getPointcut().toString() - // if (fb.maybeTrue()) mungers.add(munger); - // } - // } - - private void initializeSuperInitializerMap(ResolvedType child) { - ResolvedType[] superInterfaces = child.getDeclaredInterfaces(); - for (int i = 0, len = superInterfaces.length; i < len; i++) { - if (ty.getResolvedTypeX().isTopmostImplementor(superInterfaces[i])) { - if (addSuperInitializer(superInterfaces[i])) { - initializeSuperInitializerMap(superInterfaces[i]); - } - } - } - } - - /** - * Process the shadow mungers into array 'buckets', each bucket represents a shadow kind and contains a list of shadowmungers - * that could potentially apply at that shadow kind. - */ - private void indexShadowMungers() { - // beware the annoying property that SHADOW_KINDS[i].getKey == (i+1) ! - indexedShadowMungers = new List[Shadow.MAX_SHADOW_KIND + 1]; - for (ShadowMunger shadowMunger : shadowMungers) { - int couldMatchKinds = shadowMunger.getPointcut().couldMatchKinds(); - for (Shadow.Kind kind : Shadow.SHADOW_KINDS) { - if (kind.isSet(couldMatchKinds)) { - byte k = kind.getKey(); - if (indexedShadowMungers[k] == null) { - indexedShadowMungers[k] = new ArrayList<ShadowMunger>(); - if (!kind.isEnclosingKind()) { - canMatchBodyShadows = true; - } - } - indexedShadowMungers[k].add(shadowMunger); - } - } - } - } - - private boolean addSuperInitializer(ResolvedType onType) { - if (onType.isRawType() || onType.isParameterizedType()) { - onType = onType.getGenericType(); - } - IfaceInitList l = addedSuperInitializers.get(onType); - if (l != null) { - return false; - } - l = new IfaceInitList(onType); - addedSuperInitializers.put(onType, l); - return true; - } - - public void addInitializer(ConcreteTypeMunger cm) { - NewFieldTypeMunger m = (NewFieldTypeMunger) cm.getMunger(); - ResolvedType onType = m.getSignature().getDeclaringType().resolve(world); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - - if (Modifier.isStatic(m.getSignature().getModifiers())) { - addedClassInitializers.add(cm); - } else { - if (onType == ty.getResolvedTypeX()) { - addedThisInitializers.add(cm); - } else { - IfaceInitList l = addedSuperInitializers.get(onType); - l.list.add(cm); - } - } - } - - private static class IfaceInitList implements PartialOrder.PartialComparable { - final ResolvedType onType; - List<ConcreteTypeMunger> list = new ArrayList<ConcreteTypeMunger>(); - - IfaceInitList(ResolvedType onType) { - this.onType = onType; - } - - public int compareTo(Object other) { - IfaceInitList o = (IfaceInitList) other; - if (onType.isAssignableFrom(o.onType)) { - return +1; - } else if (o.onType.isAssignableFrom(onType)) { - return -1; - } else { - return 0; - } - } - - public int fallbackCompareTo(Object other) { - return 0; - } - } - - // XXX this is being called, but the result doesn't seem to be being used - public boolean addDispatchTarget(ResolvedMember m) { - return addedDispatchTargets.add(m); - } - - public void addLazyMethodGen(LazyMethodGen gen) { - addedLazyMethodGens.add(gen); - } - - public void addOrReplaceLazyMethodGen(LazyMethodGen mg) { - if (alreadyDefined(clazz, mg)) { - return; - } - - for (Iterator<LazyMethodGen> i = addedLazyMethodGens.iterator(); i.hasNext();) { - LazyMethodGen existing = i.next(); - if (signaturesMatch(mg, existing)) { - if (existing.definingType == null) { - // this means existing was introduced on the class itself - return; - } else if (mg.definingType.isAssignableFrom(existing.definingType)) { - // existing is mg's subtype and dominates mg - return; - } else if (existing.definingType.isAssignableFrom(mg.definingType)) { - // mg is existing's subtype and dominates existing - i.remove(); - addedLazyMethodGens.add(mg); - return; - } else { - throw new BCException("conflict between: " + mg + " and " + existing); - } - } - } - addedLazyMethodGens.add(mg); - } - - private boolean alreadyDefined(LazyClassGen clazz, LazyMethodGen mg) { - for (Iterator<LazyMethodGen> i = clazz.getMethodGens().iterator(); i.hasNext();) { - LazyMethodGen existing = i.next(); - if (signaturesMatch(mg, existing)) { - if (!mg.isAbstract() && existing.isAbstract()) { - i.remove(); - return false; - } - return true; - } - } - return false; - } - - private boolean signaturesMatch(LazyMethodGen mg, LazyMethodGen existing) { - return mg.getName().equals(existing.getName()) && mg.getSignature().equals(existing.getSignature()); - } - - protected static LazyMethodGen makeBridgeMethod(LazyClassGen gen, ResolvedMember member) { - - // remove abstract modifier - int mods = member.getModifiers(); - if (Modifier.isAbstract(mods)) { - mods = mods - Modifier.ABSTRACT; - } - - LazyMethodGen ret = new LazyMethodGen(mods, BcelWorld.makeBcelType(member.getReturnType()), member.getName(), - BcelWorld.makeBcelTypes(member.getParameterTypes()), UnresolvedType.getNames(member.getExceptions()), gen); - - // 43972 : Static crosscutting makes interfaces unusable for javac - // ret.makeSynthetic(); - return ret; - } - - /** - * Create a single bridge method called 'theBridgeMethod' that bridges to 'whatToBridgeTo' - */ - private static void createBridgeMethod(BcelWorld world, LazyMethodGen whatToBridgeToMethodGen, LazyClassGen clazz, ResolvedMember theBridgeMethod) { - InstructionList body; - InstructionFactory fact; - int pos = 0; - - ResolvedMember whatToBridgeTo = whatToBridgeToMethodGen.getMemberView(); - - if (whatToBridgeTo == null) { - whatToBridgeTo = new ResolvedMemberImpl(Member.METHOD, whatToBridgeToMethodGen.getEnclosingClass().getType(), - whatToBridgeToMethodGen.getAccessFlags(), whatToBridgeToMethodGen.getName(), - whatToBridgeToMethodGen.getSignature()); - } - // The bridge method in this type will have the same signature as the one in the supertype - LazyMethodGen bridgeMethod = makeBridgeMethod(clazz, theBridgeMethod); - int newflags = bridgeMethod.getAccessFlags() | Constants.ACC_BRIDGE | Constants.ACC_SYNTHETIC ;// BRIDGE = 0x00000040 - - if ((newflags & 0x00000100) != 0) { - newflags = newflags - 0x100;// NATIVE = 0x00000100 - need to clear it - } - - bridgeMethod.setAccessFlags(newflags); - Type returnType = BcelWorld.makeBcelType(theBridgeMethod.getReturnType()); - Type[] paramTypes = BcelWorld.makeBcelTypes(theBridgeMethod.getParameterTypes()); - Type[] newParamTypes = whatToBridgeToMethodGen.getArgumentTypes(); - body = bridgeMethod.getBody(); - fact = clazz.getFactory(); - - if (!whatToBridgeToMethodGen.isStatic()) { - body.append(InstructionFactory.createThis()); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - if (!newParamTypes[i].equals(paramTypes[i])) { - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging: Cast " + newParamTypes[i] + " from " + paramTypes[i]); - } - body.append(fact.createCast(paramTypes[i], newParamTypes[i])); - } - pos += paramType.getSize(); - } - - body.append(Utility.createInvoke(fact, world, whatToBridgeTo)); - body.append(InstructionFactory.createReturn(returnType)); - clazz.addMethodGen(bridgeMethod); - } - - /** - * Weave a class and indicate through the return value whether the class was modified. - * - * @return true if the class was modified - */ - public boolean weave() { - if (clazz.isWoven() && !clazz.isReweavable()) { - if (world.getLint().nonReweavableTypeEncountered.isEnabled()) { - world.getLint().nonReweavableTypeEncountered.signal(clazz.getType().getName(), ty.getSourceLocation()); - } - // Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode()); - // if (!reportedProblems.contains(uniqueID)) { - // reportedProblems.add(uniqueID); - // world.getLint().elementAlreadyAnnotated.signal(new String[] { rm.toString(), - // world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.ALREADY_WOVEN, clazz.getType().getName()), - // ty.getSourceLocation(), null); - return false; - } - - Set<String> aspectsAffectingType = null; - if (inReweavableMode || clazz.getType().isAspect()) { - aspectsAffectingType = new HashSet<String>(); - } - - boolean isChanged = false; - - // we want to "touch" all aspects - if (clazz.getType().isAspect()) { - isChanged = true; - } - - WeaverStateInfo typeWeaverState = (world.isOverWeaving() ? getLazyClassGen().getType().getWeaverState() : null); - // start by munging all typeMungers - for (ConcreteTypeMunger o : typeMungers) { - if (!(o instanceof BcelTypeMunger)) { - // ???System.err.println("surprising: " + o); - continue; - } - BcelTypeMunger munger = (BcelTypeMunger) o; - - if (typeWeaverState != null && typeWeaverState.isAspectAlreadyApplied(munger.getAspectType())) { - continue; - } - boolean typeMungerAffectedType = munger.munge(this); - if (typeMungerAffectedType) { - isChanged = true; - if (inReweavableMode || clazz.getType().isAspect()) { - aspectsAffectingType.add(munger.getAspectType().getSignature()); - } - } - } - - // Weave special half type/half shadow mungers... - isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged; - isChanged = weaveDeclareAtField(clazz) || isChanged; - - // XXX do major sort of stuff - // sort according to: Major: type hierarchy - // within each list: dominates - // don't forget to sort addedThisInitialiers according to dominates - addedSuperInitializersAsList = new ArrayList<IfaceInitList>(addedSuperInitializers.values()); - addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList); - if (addedSuperInitializersAsList == null) { - throw new BCException("circularity in inter-types"); - } - - // this will create a static initializer if there isn't one - // this is in just as bad taste as NOPs - LazyMethodGen staticInit = clazz.getStaticInitializer(); - staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); - - // now go through each method, and match against each method. This - // sets up each method's {@link LazyMethodGen#matchedShadows} field, - // and it also possibly adds to {@link #initializationShadows}. - List<LazyMethodGen> methodGens = new ArrayList<LazyMethodGen>(clazz.getMethodGens()); - for (LazyMethodGen member : methodGens) { - if (!member.hasBody()) { - continue; - } - if (world.isJoinpointSynchronizationEnabled() && world.areSynchronizationPointcutsInUse() - && member.getMethod().isSynchronized()) { - transformSynchronizedMethod(member); - } - boolean shadowMungerMatched = match(member); - if (shadowMungerMatched) { - // For matching mungers, add their declaring aspects to the list - // that affected this type - if (inReweavableMode || clazz.getType().isAspect()) { - aspectsAffectingType.addAll(findAspectsForMungers(member)); - } - isChanged = true; - } - } - - // now we weave all but the initialization shadows - for (LazyMethodGen methodGen : methodGens) { - if (!methodGen.hasBody()) { - continue; - } - implement(methodGen); - } - - // if we matched any initialization shadows, we inline and weave - if (!initializationShadows.isEmpty()) { - // Repeat next step until nothing left to inline...cant go on - // infinetly as compiler will have detected and reported - // "Recursive constructor invocation" - List<LazyMethodGen> recursiveCtors = new ArrayList<LazyMethodGen>(); - while (inlineSelfConstructors(methodGens, recursiveCtors)) { - } - positionAndImplement(initializationShadows); - } - - // now proceed with late type mungers - if (lateTypeMungers != null) { - for (Iterator<ConcreteTypeMunger> i = lateTypeMungers.iterator(); i.hasNext();) { - BcelTypeMunger munger = (BcelTypeMunger) i.next(); - if (munger.matches(clazz.getType())) { - boolean typeMungerAffectedType = munger.munge(this); - if (typeMungerAffectedType) { - isChanged = true; - if (inReweavableMode || clazz.getType().isAspect()) { - aspectsAffectingType.add(munger.getAspectType().getSignature()); - } - } - } - } - } - - // FIXME AV - see #75442, for now this is not enough to fix the bug, - // comment that out until we really fix it - // // flush to save some memory - // PerObjectInterfaceTypeMunger.unregisterFromAsAdvisedBy(clazz.getType() - // ); - - // finally, if we changed, we add in the introduced methods. - if (isChanged) { - clazz.getOrCreateWeaverStateInfo(inReweavableMode); - weaveInAddedMethods(); - } - - if (inReweavableMode) { - WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo(true); - wsi.addAspectsAffectingType(aspectsAffectingType); - if (!world.isOverWeaving()) { - wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes()); - wsi.setReweavable(true); - } else { - wsi.markOverweavingInUse(); - } - } else { - clazz.getOrCreateWeaverStateInfo(false).setReweavable(false); - } - - // tidyup, reduce ongoing memory usage of BcelMethods that hang around - for (LazyMethodGen mg : methodGens) { - BcelMethod method = mg.getMemberView(); - if (method != null) { - method.wipeJoinpointSignatures(); - } - } - - return isChanged; - } - - // **************************** start of bridge method creation code - // ***************** - - // FIXASC tidy this lot up !! - // FIXASC refactor into ResolvedType or even ResolvedMember? - /** - * Check if a particular method is overriding another - refactored into this helper so it can be used from multiple places. - * @return method that is overriding if it - */ - private static ResolvedMember isOverriding(ResolvedType typeToCheck, ResolvedMember methodThatMightBeGettingOverridden, - String mname, String mrettype, int mmods, boolean inSamePackage, UnresolvedType[] methodParamsArray) { - // Check if we can be an override... - if (Modifier.isStatic(methodThatMightBeGettingOverridden.getModifiers())) { - // we can't be overriding a static method - return null; - } - if (Modifier.isPrivate(methodThatMightBeGettingOverridden.getModifiers())) { - // we can't be overriding a private method - return null; - } - if (!methodThatMightBeGettingOverridden.getName().equals(mname)) { - // names do not match (this will also skip <init> and <clinit>) - return null; - } - if (methodThatMightBeGettingOverridden.getParameterTypes().length != methodParamsArray.length) { - // not the same number of parameters - return null; - } - if (!isVisibilityOverride(mmods, methodThatMightBeGettingOverridden, inSamePackage)) { - // not override from visibility point of view - return null; - } - - if (typeToCheck.getWorld().forDEBUG_bridgingCode) { - System.err.println(" Bridging:seriously considering this might be getting overridden '" - + methodThatMightBeGettingOverridden + "'"); - } - - World w = typeToCheck.getWorld(); - - // Look at erasures of parameters (List<String> erased is List) - boolean sameParams = true; - for (int p = 0, max = methodThatMightBeGettingOverridden.getParameterTypes().length; p < max; p++) { - - UnresolvedType mtmbgoParameter = methodThatMightBeGettingOverridden.getParameterTypes()[p]; - UnresolvedType ptype = methodParamsArray[p]; - - if (mtmbgoParameter.isTypeVariableReference()) { - if (!mtmbgoParameter.resolve(w).isAssignableFrom(ptype.resolve(w))) { - sameParams = false; - } - } else { - // old condition: - boolean b = !methodThatMightBeGettingOverridden.getParameterTypes()[p].getErasureSignature().equals( - methodParamsArray[p].getErasureSignature()); - - UnresolvedType parameterType = methodThatMightBeGettingOverridden.getParameterTypes()[p]; - - // Collapse to first bound (isn't that the same as erasure! - if (parameterType instanceof UnresolvedTypeVariableReferenceType) { - parameterType = ((UnresolvedTypeVariableReferenceType) parameterType).getTypeVariable().getFirstBound(); - } - - if (b) { // !parameterType.resolve(w).equals(parameterType2.resolve(w))) { - sameParams = false; - } - } - // - // if (!ut.getErasureSignature().equals(ut2.getErasureSignature())) - // sameParams = false; - } - - // If the 'typeToCheck' represents a parameterized type then the method - // will be the parameterized form of the - // generic method in the generic type. So if the method was 'void - // m(List<T> lt, T t)' and the parameterized type here - // is I<String> then the method we are looking at will be 'void - // m(List<String> lt, String t)' which when erased - // is 'void m(List lt,String t)' - so if the parameters *do* match then - // there is a generic method we are - // overriding - - // FIXASC Why bother with the return type? If it is incompatible then the code has other problems! - if (sameParams) { - if (typeToCheck.isParameterizedType()) { - return methodThatMightBeGettingOverridden.getBackingGenericMember(); - } else if (!methodThatMightBeGettingOverridden.getReturnType().getErasureSignature().equals(mrettype)) { - // addressing the wierd situation from bug 147801 - // just check whether these things are in the right relationship - // for covariance... - ResolvedType superReturn = typeToCheck.getWorld().resolve( - UnresolvedType.forSignature(methodThatMightBeGettingOverridden.getReturnType().getErasureSignature())); - ResolvedType subReturn = typeToCheck.getWorld().resolve(UnresolvedType.forSignature(mrettype)); - if (superReturn.isAssignableFrom(subReturn)) { - return methodThatMightBeGettingOverridden; - } - // } else if (typeToCheck.isParameterizedType()) { - // return methodThatMightBeGettingOverridden.getBackingGenericMember(); - } else { - return methodThatMightBeGettingOverridden; - } - } - return null; - } - - /** - * Looks at the visibility modifiers between two methods, and knows whether they are from classes in the same package, and - * decides whether one overrides the other. - * - * @return true if there is an overrides rather than a 'hides' relationship - */ - static boolean isVisibilityOverride(int methodMods, ResolvedMember inheritedMethod, boolean inSamePackage) { - int inheritedModifiers = inheritedMethod.getModifiers(); - if (Modifier.isStatic(inheritedModifiers)) { - return false; - } - if (methodMods == inheritedModifiers) { - return true; - } - - if (Modifier.isPrivate(inheritedModifiers)) { - return false; - } - - boolean isPackageVisible = !Modifier.isPrivate(inheritedModifiers) && !Modifier.isProtected(inheritedModifiers) - && !Modifier.isPublic(inheritedModifiers); - if (isPackageVisible && !inSamePackage) { - return false; - } - - return true; - } - - /** - * This method recurses up a specified type looking for a method that overrides the one passed in. - * - * @return the method being overridden or null if none is found - */ - public static void checkForOverride(ResolvedType typeToCheck, String mname, String mparams, String mrettype, - int mmods, String mpkg, UnresolvedType[] methodParamsArray, List<ResolvedMember> overriddenMethodsCollector) { - - if (typeToCheck == null) { - return; - } - if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) { - return; // we just can't tell ! - } - - - if (typeToCheck.getWorld().forDEBUG_bridgingCode) { - System.err.println(" Bridging:checking for override of " + mname + " in " + typeToCheck); - } - - String packageName = typeToCheck.getPackageName(); - if (packageName == null) { - packageName = ""; - } - // used when looking at visibility rules - boolean inSamePackage = packageName.equals(mpkg); - - ResolvedMember[] methods = typeToCheck.getDeclaredMethods(); - for (int ii = 0; ii < methods.length; ii++) { - // the method we are going to check - ResolvedMember methodThatMightBeGettingOverridden = methods[ii]; - ResolvedMember isOverriding = isOverriding(typeToCheck, methodThatMightBeGettingOverridden, mname, mrettype, mmods, - inSamePackage, methodParamsArray); - if (isOverriding != null) { - overriddenMethodsCollector.add(isOverriding); - } - } - // was: List l = typeToCheck.getInterTypeMungers(); - List<ConcreteTypeMunger> l = (typeToCheck.isRawType() ? typeToCheck.getGenericType().getInterTypeMungers() : typeToCheck - .getInterTypeMungers()); - for (Iterator<ConcreteTypeMunger> iterator = l.iterator(); iterator.hasNext();) { - ConcreteTypeMunger o = iterator.next(); - // FIXME asc if its not a BcelTypeMunger then its an - // EclipseTypeMunger ... do I need to worry about that? - if (o instanceof BcelTypeMunger) { - BcelTypeMunger element = (BcelTypeMunger) o; - if (element.getMunger() instanceof NewMethodTypeMunger) { - if (typeToCheck.getWorld().forDEBUG_bridgingCode) { - System.err.println("Possible ITD candidate " + element); - } - ResolvedMember aMethod = element.getSignature(); - ResolvedMember isOverriding = isOverriding(typeToCheck, aMethod, mname, mrettype, mmods, inSamePackage, - methodParamsArray); - if (isOverriding != null) { - overriddenMethodsCollector.add(isOverriding); - } - } - } - } - - if (typeToCheck.equals(UnresolvedType.OBJECT)) { - return; - } - - ResolvedType superclass = typeToCheck.getSuperclass(); - checkForOverride(superclass, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector); - - ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - ResolvedType anInterface = interfaces[i]; - checkForOverride(anInterface, mname, mparams, mrettype, mmods, mpkg, methodParamsArray,overriddenMethodsCollector); - } - } - - /** - * We need to determine if any methods in this type require bridge methods - this method should only be called if necessary to - * do this calculation, i.e. we are on a 1.5 VM (where covariance/generics exist) and the type hierarchy for the specified class - * has changed (via decp/itd). - * - * See pr108101 - */ - public static boolean calculateAnyRequiredBridgeMethods(BcelWorld world, LazyClassGen clazz) { - world.ensureAdvancedConfigurationProcessed(); - - if (!world.isInJava5Mode()) { - return false; // just double check... the caller should have already - } - if (clazz.isInterface()) { - return false; // dont bother if we are an interface - } - - boolean didSomething = false; // set if we build any bridge methods - // So what methods do we have right now in this class? - List<LazyMethodGen> methods = clazz.getMethodGens(); - - // Keep a set of all methods from this type - it'll help us to check if bridge methods - // have already been created, we don't want to do it twice! - Set<String> methodsSet = new HashSet<String>(); - for (int i = 0; i < methods.size(); i++) { - LazyMethodGen aMethod = methods.get(i); - StringBuilder sb = new StringBuilder(aMethod.getName()); - sb.append(aMethod.getSignature()); - methodsSet.add(sb.toString()); // e.g. "foo(Ljava/lang/String;)V" - } - - // Now go through all the methods in this type - for (int i = 0; i < methods.size(); i++) { - // This is the local method that we *might* have to bridge to - LazyMethodGen bridgeToCandidate = methods.get(i); - if (bridgeToCandidate.isBridgeMethod()) { - continue; // Doh! - } - String name = bridgeToCandidate.getName(); - String psig = bridgeToCandidate.getParameterSignature(); - String rsig = bridgeToCandidate.getReturnType().getSignature(); - - // if (bridgeToCandidate.isAbstract()) continue; - if (bridgeToCandidate.isStatic()) { - continue; // ignore static methods - } - if (name.endsWith("init>")) { - continue; // Skip constructors and static initializers - } - - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging: Determining if we have to bridge to " + clazz.getName() + "." + name + "" + bridgeToCandidate.getSignature()); - } - - // Let's take a look at the superclass - ResolvedType theSuperclass = clazz.getSuperClass(); - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging: Checking supertype " + theSuperclass); - } - String pkgName = clazz.getPackageName(); - UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes()); - List<ResolvedMember> overriddenMethodsCollector = new ArrayList<ResolvedMember>(); - checkForOverride(theSuperclass, name, psig, rsig, bridgeToCandidate.getAccessFlags(), pkgName, bm, overriddenMethodsCollector); - if (overriddenMethodsCollector.size() != 0) { - for (ResolvedMember overriddenMethod: overriddenMethodsCollector) { - String key = new StringBuilder(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString(); // pr237419 - boolean alreadyHaveABridgeMethod = methodsSet.contains(key); - if (!alreadyHaveABridgeMethod) { - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging:bridging to '" + overriddenMethod + "'"); - } - createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod); - methodsSet.add(key); - didSomething = true; - } - } - } - - // Check superinterfaces - String[] interfaces = clazz.getInterfaceNames(); - for (int j = 0; j < interfaces.length; j++) { - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging:checking superinterface " + interfaces[j]); - } - ResolvedType interfaceType = world.resolve(interfaces[j]); - overriddenMethodsCollector.clear(); - checkForOverride(interfaceType, name, psig, rsig, bridgeToCandidate.getAccessFlags(), - clazz.getPackageName(), bm, overriddenMethodsCollector); - for (ResolvedMember overriddenMethod: overriddenMethodsCollector) { - String key = new StringBuffer().append(overriddenMethod.getName()).append(overriddenMethod.getSignatureErased()).toString(); // pr237419 - boolean alreadyHaveABridgeMethod = methodsSet.contains(key); - if (!alreadyHaveABridgeMethod) { - createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod); - methodsSet.add(key); - didSomething = true; - if (world.forDEBUG_bridgingCode) { - System.err.println("Bridging:bridging to " + overriddenMethod); - } - } - } - } - } - - return didSomething; - } - - // **************************** end of bridge method creation code ***************** - - /** - * Weave any declare @method/@ctor statements into the members of the supplied class - */ - private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) { - List<Integer> reportedProblems = new ArrayList<Integer>(); - - List<DeclareAnnotation> allDecams = world.getDeclareAnnotationOnMethods(); - if (allDecams.isEmpty()) { - return false; - } - - boolean isChanged = false; - - // deal with ITDs - List<ConcreteTypeMunger> itdMethodsCtors = getITDSubset(clazz, ResolvedTypeMunger.Method); - itdMethodsCtors.addAll(getITDSubset(clazz, ResolvedTypeMunger.Constructor)); - if (!itdMethodsCtors.isEmpty()) { - // Can't use the subset called 'decaMs' as it won't be right for - // ITDs... - isChanged = weaveAtMethodOnITDSRepeatedly(allDecams, itdMethodsCtors, reportedProblems); - } - - List<DeclareAnnotation> decaMs = getMatchingSubset(allDecams, clazz.getType()); - if (decaMs.isEmpty()) { - return false; // nothing to do - } - - Set<DeclareAnnotation> unusedDecams = new HashSet<DeclareAnnotation>(); - unusedDecams.addAll(decaMs); - - // These methods may have been targeted with declare annotation. Example: ITD on an interface - // where the top most implementor gets a real method. The top most implementor method - // is an 'addedLazyMethodGen' - if (addedLazyMethodGens!=null) { - for (LazyMethodGen method: addedLazyMethodGens) { - // They have no resolvedmember of their own, conjure one up for matching purposes - ResolvedMember resolvedmember = - new ResolvedMemberImpl(ResolvedMember.METHOD,method.getEnclosingClass().getType(),method.getAccessFlags(), - BcelWorld.fromBcel(method.getReturnType()),method.getName(), - BcelWorld.fromBcel(method.getArgumentTypes()),UnresolvedType.forNames(method.getDeclaredExceptions())); - resolvedmember.setAnnotationTypes(method.getAnnotationTypes()); - resolvedmember.setAnnotations(method.getAnnotations()); - - List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>(); - boolean modificationOccured = false; - for (DeclareAnnotation decam: decaMs) { - if (decam.matches(resolvedmember, world)) { - if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { - // remove the declare @method since don't want an error when the annotation is already there - unusedDecams.remove(decam); - continue; - } - - AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); - // create copy to get the annotation type into the right constant pool - AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); - method.addAnnotation(aj); - resolvedmember.addAnnotation(decam.getAnnotation()); - - AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), - clazz.getName(), resolvedmember, world.getModelAsAsmManager()); - reportMethodCtorWeavingMessage(clazz, resolvedmember, decam, method.getDeclarationLineNumber()); - isChanged = true; - modificationOccured = true; - unusedDecams.remove(decam); - } else if (!decam.isStarredAnnotationPattern()) { - // an annotation is specified that might be put on by a subsequent decaf - worthRetrying.add(decam); - } - } - - // Multiple secondary passes - while (!worthRetrying.isEmpty() && modificationOccured) { - modificationOccured = false; - // lets have another go - List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); - for (DeclareAnnotation decam : worthRetrying) { - if (decam.matches(resolvedmember, world)) { - if (doesAlreadyHaveAnnotation(resolvedmember, decam, reportedProblems,false)) { - // remove the declare @method since don't - // want an error when - // the annotation is already there - unusedDecams.remove(decam); - continue; // skip this one... - } - AnnotationGen a = ((BcelAnnotation) decam.getAnnotation()).getBcelAnnotation(); - // create copy to get the annotation type into the right constant pool - AnnotationAJ aj = new BcelAnnotation(new AnnotationGen(a, clazz.getConstantPool(), true),world); - method.addAnnotation(aj); - resolvedmember.addAnnotation(decam.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decam.getSourceLocation(), - clazz.getName(), resolvedmember, world.getModelAsAsmManager());// getMethod()); - isChanged = true; - modificationOccured = true; - forRemoval.add(decam); - unusedDecams.remove(decam); - } - } - worthRetrying.removeAll(forRemoval); - } - } - } - - - // deal with all the other methods... - List<LazyMethodGen> members = clazz.getMethodGens(); - if (!members.isEmpty()) { - for (int memberCounter = 0; memberCounter < members.size(); memberCounter++) { - LazyMethodGen mg = members.get(memberCounter); - if (!mg.getName().startsWith(NameMangler.PREFIX)) { - - // Single first pass - List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>(); - boolean modificationOccured = false; - List<AnnotationGen> annotationsToAdd = null; - for (DeclareAnnotation decaM : decaMs) { - - if (decaM.matches(mg.getMemberView(), world)) { - if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { - // remove the declare @method since don't want - // an error when the annotation is already there - unusedDecams.remove(decaM); - continue; // skip this one... - } - - if (annotationsToAdd == null) { - annotationsToAdd = new ArrayList<AnnotationGen>(); - } - AnnotationGen a = ((BcelAnnotation) decaM.getAnnotation()).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, clazz.getConstantPool(), true); - annotationsToAdd.add(ag); - mg.addAnnotation(decaM.getAnnotation()); - - AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decaM.getSourceLocation(), - clazz.getName(), mg.getMemberView(), world.getModelAsAsmManager());// getMethod()); - reportMethodCtorWeavingMessage(clazz, mg.getMemberView(), decaM, mg.getDeclarationLineNumber()); - isChanged = true; - modificationOccured = true; - // remove the declare @method since have matched - // against it - unusedDecams.remove(decaM); - } else { - if (!decaM.isStarredAnnotationPattern()) { - worthRetrying.add(decaM); // an annotation is - // specified that - // might be put on - // by a subsequent - // decaf - } - } - } - - // Multiple secondary passes - while (!worthRetrying.isEmpty() && modificationOccured) { - modificationOccured = false; - // lets have another go - List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); - for (DeclareAnnotation decaM : worthRetrying) { - if (decaM.matches(mg.getMemberView(), world)) { - if (doesAlreadyHaveAnnotation(mg.getMemberView(), decaM, reportedProblems,true)) { - // remove the declare @method since don't - // want an error when - // the annotation is already there - unusedDecams.remove(decaM); - continue; // skip this one... - } - - if (annotationsToAdd == null) { - annotationsToAdd = new ArrayList<AnnotationGen>(); - } - AnnotationGen a = ((BcelAnnotation) decaM.getAnnotation()).getBcelAnnotation(); - // create copy to get the annotation type into the right constant pool - AnnotationGen ag = new AnnotationGen(a, clazz.getConstantPool(), true); - annotationsToAdd.add(ag); - mg.addAnnotation(decaM.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationMethodRelationship(decaM.getSourceLocation(), - clazz.getName(), mg.getMemberView(), world.getModelAsAsmManager());// getMethod()); - isChanged = true; - modificationOccured = true; - forRemoval.add(decaM); - // remove the declare @method since have matched - // against it - unusedDecams.remove(decaM); - } - } - worthRetrying.removeAll(forRemoval); - } - if (annotationsToAdd != null) { - Method oldMethod = mg.getMethod(); - MethodGen myGen = new MethodGen(oldMethod, clazz.getClassName(), clazz.getConstantPool(), false); - for (AnnotationGen a : annotationsToAdd) { - myGen.addAnnotation(a); - } - Method newMethod = myGen.getMethod(); - members.set(memberCounter, new LazyMethodGen(newMethod, clazz)); - } - - } - } - checkUnusedDeclareAts(unusedDecams, false); - } - return isChanged; - } - - // TAG: WeavingMessage - private void reportMethodCtorWeavingMessage(LazyClassGen clazz, ResolvedMember member, DeclareAnnotation decaM, - int memberLineNumber) { - if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { - StringBuffer parmString = new StringBuffer("("); - UnresolvedType[] paramTypes = member.getParameterTypes(); - for (int i = 0; i < paramTypes.length; i++) { - UnresolvedType type = paramTypes[i]; - String s = org.aspectj.apache.bcel.classfile.Utility.signatureToString(type.getSignature()); - if (s.lastIndexOf('.') != -1) { - s = s.substring(s.lastIndexOf('.') + 1); - } - parmString.append(s); - if ((i + 1) < paramTypes.length) { - parmString.append(","); - } - } - parmString.append(")"); - String methodName = member.getName(); - StringBuffer sig = new StringBuffer(); - sig.append(org.aspectj.apache.bcel.classfile.Utility.accessToString(member.getModifiers())); - sig.append(" "); - sig.append(member.getReturnType().toString()); - sig.append(" "); - sig.append(member.getDeclaringType().toString()); - sig.append("."); - sig.append(methodName.equals("<init>") ? "new" : methodName); - sig.append(parmString); - - StringBuffer loc = new StringBuffer(); - if (clazz.getFileName() == null) { - loc.append("no debug info available"); - } else { - loc.append(clazz.getFileName()); - if (memberLineNumber != -1) { - loc.append(":" + memberLineNumber); - } - } - getWorld().getMessageHandler().handleMessage( - WeaveMessage.constructWeavingMessage( - WeaveMessage.WEAVEMESSAGE_ANNOTATES, - new String[] { sig.toString(), loc.toString(), decaM.getAnnotationString(), - methodName.startsWith("<init>") ? "constructor" : "method", decaM.getAspect().toString(), - Utility.beautifyLocation(decaM.getSourceLocation()) })); - } - } - - /** - * Looks through a list of declare annotation statements and only returns those that could possibly match on a field/method/ctor - * in type. - */ - private List<DeclareAnnotation> getMatchingSubset(List<DeclareAnnotation> declareAnnotations, ResolvedType type) { - List<DeclareAnnotation> subset = new ArrayList<DeclareAnnotation>(); - for (DeclareAnnotation da : declareAnnotations) { - if (da.couldEverMatch(type)) { - subset.add(da); - } - } - return subset; - } - - /** - * Get a subset of all the type mungers defined on this aspect - */ - private List<ConcreteTypeMunger> getITDSubset(LazyClassGen clazz, ResolvedTypeMunger.Kind wantedKind) { - List<ConcreteTypeMunger> subset = new ArrayList<ConcreteTypeMunger>(); - for (ConcreteTypeMunger typeMunger : clazz.getBcelObjectType().getTypeMungers()) { - if (typeMunger.getMunger().getKind() == wantedKind) { - subset.add(typeMunger); - } - } - return subset; - } - - public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz, ConcreteTypeMunger fieldMunger) { - NewFieldTypeMunger newFieldMunger = (NewFieldTypeMunger) fieldMunger.getMunger(); - ResolvedMember lookingFor = AjcMemberMaker.interFieldInitializer(newFieldMunger.getSignature(), clazz.getType()); - for (LazyMethodGen method : clazz.getMethodGens()) { - if (method.getName().equals(lookingFor.getName())) { - return method; - } - } - return null; - } - - // FIXME asc refactor this to neaten it up - public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz, ConcreteTypeMunger methodCtorMunger) { - ResolvedTypeMunger rtMunger = methodCtorMunger.getMunger(); - ResolvedMember lookingFor = null; - if (rtMunger instanceof NewMethodTypeMunger) { - NewMethodTypeMunger nftm = (NewMethodTypeMunger) rtMunger; - lookingFor = AjcMemberMaker.interMethodDispatcher(nftm.getSignature(), methodCtorMunger.getAspectType()); - } else if (rtMunger instanceof NewConstructorTypeMunger) { - NewConstructorTypeMunger nftm = (NewConstructorTypeMunger) rtMunger; - lookingFor = AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(), nftm.getSignature() - .getDeclaringType(), nftm.getSignature().getParameterTypes()); - } else { - throw new BCException("Not sure what this is: " + methodCtorMunger); - } - String name = lookingFor.getName(); - String paramSignature = lookingFor.getParameterSignature(); - for (LazyMethodGen member : clazz.getMethodGens()) { - if (member.getName().equals(name) && member.getParameterSignature().equals(paramSignature)) { - return member; - } - } - return null; - } - - /** - * Applies some set of declare @field constructs (List<DeclareAnnotation>) to some bunch of ITDfields (List<BcelTypeMunger>. It - * will iterate over the fields repeatedly until everything has been applied. - * - */ - private boolean weaveAtFieldRepeatedly(List<DeclareAnnotation> decaFs, List<ConcreteTypeMunger> itdFields, - List<Integer> reportedErrors) { - boolean isChanged = false; - for (Iterator<ConcreteTypeMunger> iter = itdFields.iterator(); iter.hasNext();) { - BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next(); - ResolvedMember itdIsActually = fieldMunger.getSignature(); - Set<DeclareAnnotation> worthRetrying = new LinkedHashSet<DeclareAnnotation>(); - boolean modificationOccured = false; - - for (Iterator<DeclareAnnotation> iter2 = decaFs.iterator(); iter2.hasNext();) { - DeclareAnnotation decaF = iter2.next(); - if (decaF.matches(itdIsActually, world)) { - if (decaF.isRemover()) { - LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger); - if (annotationHolder.hasAnnotation(decaF.getAnnotationType())) { - isChanged = true; - // something to remove - annotationHolder.removeAnnotation(decaF.getAnnotationType()); - AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), itdIsActually.getSourceLocation(), true); - } else { - worthRetrying.add(decaF); - } - } else { - - LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger); - if (doesAlreadyHaveAnnotation(annotationHolder, itdIsActually, decaF, reportedErrors)) { - continue; // skip this one... - } - annotationHolder.addAnnotation(decaF.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), itdIsActually.getSourceLocation(), false); - isChanged = true; - modificationOccured = true; - } - } else { - if (!decaF.isStarredAnnotationPattern()) { - worthRetrying.add(decaF); // an annotation is specified - // that might be put on by a - // subsequent decaf - } - } - } - - while (!worthRetrying.isEmpty() && modificationOccured) { - modificationOccured = false; - List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); - for (Iterator<DeclareAnnotation> iter2 = worthRetrying.iterator(); iter2.hasNext();) { - DeclareAnnotation decaF = iter2.next(); - if (decaF.matches(itdIsActually, world)) { - if (decaF.isRemover()) { - LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger); - if (annotationHolder.hasAnnotation(decaF.getAnnotationType())) { - isChanged = true; - // something to remove - annotationHolder.removeAnnotation(decaF.getAnnotationType()); - AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), itdIsActually.getSourceLocation(), true); - forRemoval.add(decaF); - } - } else { - LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, fieldMunger); - if (doesAlreadyHaveAnnotation(annotationHolder, itdIsActually, decaF, reportedErrors)) { - continue; // skip this one... - } - annotationHolder.addAnnotation(decaF.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), itdIsActually.getSourceLocation(), false); - isChanged = true; - modificationOccured = true; - forRemoval.add(decaF); - } - } - } - worthRetrying.removeAll(forRemoval); - } - } - return isChanged; - } - - /** - * Applies some set of declare @method/@ctor constructs (List<DeclareAnnotation>) to some bunch of ITDmembers - * (List<BcelTypeMunger>. It will iterate over the fields repeatedly until everything has been applied. - */ - private boolean weaveAtMethodOnITDSRepeatedly(List<DeclareAnnotation> decaMCs, - List<ConcreteTypeMunger> itdsForMethodAndConstructor, List<Integer> reportedErrors) { - boolean isChanged = false; - AsmManager asmManager = world.getModelAsAsmManager(); - for (ConcreteTypeMunger methodctorMunger : itdsForMethodAndConstructor) { - // for (Iterator iter = itdsForMethodAndConstructor.iterator(); iter.hasNext();) { - // BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next(); - ResolvedMember unMangledInterMethod = methodctorMunger.getSignature(); - List<DeclareAnnotation> worthRetrying = new ArrayList<DeclareAnnotation>(); - boolean modificationOccured = false; - - for (Iterator<DeclareAnnotation> iter2 = decaMCs.iterator(); iter2.hasNext();) { - DeclareAnnotation decaMC = iter2.next(); - if (decaMC.matches(unMangledInterMethod, world)) { - LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz, methodctorMunger); - if (annotationHolder == null - || doesAlreadyHaveAnnotation(annotationHolder, unMangledInterMethod, decaMC, reportedErrors)) { - continue; // skip this one... - } - annotationHolder.addAnnotation(decaMC.getAnnotation()); - isChanged = true; - AsmRelationshipProvider.addDeclareAnnotationRelationship(asmManager, decaMC.getSourceLocation(), - unMangledInterMethod.getSourceLocation(), false); - reportMethodCtorWeavingMessage(clazz, unMangledInterMethod, decaMC, -1); - modificationOccured = true; - } else { - // If an annotation is specified, it might be added by one of the other declare annotation statements - if (!decaMC.isStarredAnnotationPattern()) { - worthRetrying.add(decaMC); - } - } - } - - while (!worthRetrying.isEmpty() && modificationOccured) { - modificationOccured = false; - List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); - for (Iterator<DeclareAnnotation> iter2 = worthRetrying.iterator(); iter2.hasNext();) { - DeclareAnnotation decaMC = iter2.next(); - if (decaMC.matches(unMangledInterMethod, world)) { - LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz, methodctorMunger); - if (doesAlreadyHaveAnnotation(annotationHolder, unMangledInterMethod, decaMC, reportedErrors)) { - continue; // skip this one... - } - annotationHolder.addAnnotation(decaMC.getAnnotation()); - unMangledInterMethod.addAnnotation(decaMC.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationRelationship(asmManager, decaMC.getSourceLocation(), - unMangledInterMethod.getSourceLocation(), false); - isChanged = true; - modificationOccured = true; - forRemoval.add(decaMC); - } - worthRetrying.removeAll(forRemoval); - } - } - } - return isChanged; - } - - private boolean dontAddTwice(DeclareAnnotation decaF, AnnotationAJ[] dontAddMeTwice) { - for (AnnotationAJ ann : dontAddMeTwice) { - if (ann != null && decaF.getAnnotation().getTypeName().equals(ann.getTypeName())) { - return true; - } - } - return false; - } - - /** - * Remove an annotation from the supplied array, if it is in there. - */ - private AnnotationAJ[] removeFromAnnotationsArray(AnnotationAJ[] annotations,AnnotationAJ annotation) { - for (int i=0;i<annotations.length;i++) { - if (annotations[i] != null && annotation.getTypeName().equals(annotations[i].getTypeName())) { - // Remove it! - AnnotationAJ[] newArray = new AnnotationAJ[annotations.length-1]; - int index=0; - for (int j=0;j<annotations.length;j++) { - if (j!=i) { - newArray[index++]=annotations[j]; - } - } - return newArray; - } - } - return annotations; - } - - // BUGWARNING not getting enough warnings out on declare @field ? There is a potential problem here with warnings not - // coming out - this will occur if they are created on the second iteration round this loop. - // We currently deactivate error reporting for the second time round. A possible solution is to record what annotations - // were added by what decafs and check that to see if an error needs to be reported - this would be expensive so lets - // skip it for now - /** - * Weave any declare @field statements into the fields of the supplied class. This will attempt to apply them to the ITDs too. - * - * Interesting case relating to public ITDd fields. The annotations are really stored against the interfieldinit method in the - * aspect, but the public field is placed in the target type and then is processed in the 2nd pass over fields that occurs. I - * think it would be more expensive to avoid putting the annotation on that inserted public field than just to have it put there - * as well as on the interfieldinit method. - */ - private boolean weaveDeclareAtField(LazyClassGen clazz) { - List<Integer> reportedProblems = new ArrayList<Integer>(); - List<DeclareAnnotation> allDecafs = world.getDeclareAnnotationOnFields(); - if (allDecafs.isEmpty()) { - return false; - } - boolean typeIsChanged = false; - List<ConcreteTypeMunger> relevantItdFields = getITDSubset(clazz, ResolvedTypeMunger.Field); - if (relevantItdFields != null) { - typeIsChanged = weaveAtFieldRepeatedly(allDecafs, relevantItdFields, reportedProblems); - } - - List<DeclareAnnotation> decafs = getMatchingSubset(allDecafs, clazz.getType()); - if (decafs.isEmpty()) { - return typeIsChanged; - } - - List<BcelField> fields = clazz.getFieldGens(); - if (fields != null) { - Set<DeclareAnnotation> unusedDecafs = new HashSet<DeclareAnnotation>(); - unusedDecafs.addAll(decafs); - for (BcelField field : fields) { - if (!field.getName().startsWith(NameMangler.PREFIX)) { - // Single first pass - Set<DeclareAnnotation> worthRetrying = new LinkedHashSet<DeclareAnnotation>(); - boolean modificationOccured = false; - AnnotationAJ[] dontAddMeTwice = field.getAnnotations(); - - // go through all the declare @field statements - for (DeclareAnnotation decaf : decafs) { - if (decaf.getAnnotation() == null) { - return false; - } - if (decaf.matches(field, world)) { - if (decaf.isRemover()) { - AnnotationAJ annotation = decaf.getAnnotation(); - if (field.hasAnnotation(annotation.getType())) { - // something to remove - typeIsChanged = true; - field.removeAnnotation(annotation); - AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(), - decaf.getSourceLocation(), clazz.getName(), field, true); - reportFieldAnnotationWeavingMessage(clazz, field, decaf, true); - dontAddMeTwice = removeFromAnnotationsArray(dontAddMeTwice, annotation); - } else { - worthRetrying.add(decaf); - } - unusedDecafs.remove(decaf); - } else { - if (!dontAddTwice(decaf, dontAddMeTwice)) { - if (doesAlreadyHaveAnnotation(field, decaf, reportedProblems,true )) { - // remove the declare @field since don't want an error when the annotation is already there - unusedDecafs.remove(decaf); - continue; - } - field.addAnnotation(decaf.getAnnotation()); - } - AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(), - decaf.getSourceLocation(), clazz.getName(), field, false); - reportFieldAnnotationWeavingMessage(clazz, field, decaf, false); - typeIsChanged = true; - modificationOccured = true; - unusedDecafs.remove(decaf); - } - } else if (!decaf.isStarredAnnotationPattern() || decaf.isRemover()) { - worthRetrying.add(decaf); // an annotation is specified that might be put on by a subsequent decaf - } - } - - // Multiple secondary passes - while (!worthRetrying.isEmpty() && modificationOccured) { - modificationOccured = false; - // lets have another go with any remaining ones - List<DeclareAnnotation> forRemoval = new ArrayList<DeclareAnnotation>(); - for (Iterator<DeclareAnnotation> iter = worthRetrying.iterator(); iter.hasNext();) { - DeclareAnnotation decaF = iter.next(); - - if (decaF.matches(field, world)) { - if (decaF.isRemover()) { - AnnotationAJ annotation = decaF.getAnnotation(); - if (field.hasAnnotation(annotation.getType())) { - // something to remove - typeIsChanged = modificationOccured = true; - forRemoval.add(decaF); - field.removeAnnotation(annotation); - AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), clazz.getName(), field, true); - reportFieldAnnotationWeavingMessage(clazz, field, decaF, true); - } - } else { - // below code is for recursive things - unusedDecafs.remove(decaF); - if (doesAlreadyHaveAnnotation(field, decaF, reportedProblems,true)) { - continue; - } - field.addAnnotation(decaF.getAnnotation()); - AsmRelationshipProvider.addDeclareAnnotationFieldRelationship(world.getModelAsAsmManager(), - decaF.getSourceLocation(), clazz.getName(), field, false); - typeIsChanged = modificationOccured = true; - forRemoval.add(decaF); - } - } - } - worthRetrying.removeAll(forRemoval); - } - } - } - checkUnusedDeclareAts(unusedDecafs, true); - } - return typeIsChanged; - } - - // bug 99191 - put out an error message if the type doesn't exist - /** - * Report an error if the reason a "declare @method/ctor/field" was not used was because the member specified does not exist. - * This method is passed some set of declare statements that didn't match and a flag indicating whether the set contains declare @field - * or declare @method/ctor entries. - */ - private void checkUnusedDeclareAts(Set<DeclareAnnotation> unusedDecaTs, boolean isDeclareAtField) { - for (DeclareAnnotation declA : unusedDecaTs) { - - // Error if an exact type pattern was specified - boolean shouldCheck = declA.isExactPattern() || declA.getSignaturePattern().getExactDeclaringTypes().size() != 0; - - if (shouldCheck && declA.getKind() != DeclareAnnotation.AT_CONSTRUCTOR) { - if (declA.getSignaturePattern().isMatchOnAnyName()) { - shouldCheck = false; - } else { - List<ExactTypePattern> declaringTypePatterns = declA.getSignaturePattern().getExactDeclaringTypes(); - if (declaringTypePatterns.size() == 0) { - shouldCheck = false; - } else { - for (ExactTypePattern exactTypePattern : declaringTypePatterns) { - if (exactTypePattern.isIncludeSubtypes()) { - shouldCheck = false; - break; - } - } - } - } - } - if (shouldCheck) { - // Quickly check if an ITD supplies the 'missing' member - boolean itdMatch = false; - List<ConcreteTypeMunger> lst = clazz.getType().getInterTypeMungers(); - for (Iterator<ConcreteTypeMunger> iterator = lst.iterator(); iterator.hasNext() && !itdMatch;) { - ConcreteTypeMunger element = iterator.next(); - if (element.getMunger() instanceof NewFieldTypeMunger) { - NewFieldTypeMunger nftm = (NewFieldTypeMunger) element.getMunger(); - itdMatch = declA.matches(nftm.getSignature(), world); - } else if (element.getMunger() instanceof NewMethodTypeMunger) { - NewMethodTypeMunger nmtm = (NewMethodTypeMunger) element.getMunger(); - itdMatch = declA.matches(nmtm.getSignature(), world); - } else if (element.getMunger() instanceof NewConstructorTypeMunger) { - NewConstructorTypeMunger nctm = (NewConstructorTypeMunger) element.getMunger(); - itdMatch = declA.matches(nctm.getSignature(), world); - } - } - if (!itdMatch) { - IMessage message = null; - if (isDeclareAtField) { - message = new Message("The field '" + declA.getSignaturePattern().toString() + "' does not exist", - declA.getSourceLocation(), true); - } else { - message = new Message("The method '" + declA.getSignaturePattern().toString() + "' does not exist", - declA.getSourceLocation(), true); - } - world.getMessageHandler().handleMessage(message); - } - } - } - } - - // TAG: WeavingMessage - private void reportFieldAnnotationWeavingMessage(LazyClassGen clazz, BcelField theField, DeclareAnnotation decaf, - boolean isRemove) { - if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { - world.getMessageHandler().handleMessage( - WeaveMessage.constructWeavingMessage( - isRemove ? WeaveMessage.WEAVEMESSAGE_REMOVES_ANNOTATION : WeaveMessage.WEAVEMESSAGE_ANNOTATES, - new String[] { theField.getFieldAsIs().toString() + "' of type '" + clazz.getName(), - clazz.getFileName(), decaf.getAnnotationString(), "field", decaf.getAspect().toString(), - Utility.beautifyLocation(decaf.getSourceLocation()) })); - } - } - - /** - * Check if a resolved member (field/method/ctor) already has an annotation, if it does then put out a warning and return true - */ - private boolean doesAlreadyHaveAnnotation(ResolvedMember rm, DeclareAnnotation deca, List<Integer> reportedProblems, boolean reportError) { - if (rm.hasAnnotation(deca.getAnnotationType())) { - if (reportError && world.getLint().elementAlreadyAnnotated.isEnabled()) { - Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode()); - if (!reportedProblems.contains(uniqueID)) { - reportedProblems.add(uniqueID); - world.getLint().elementAlreadyAnnotated.signal(new String[] { rm.toString(), - deca.getAnnotationType().toString() }, rm.getSourceLocation(), - new ISourceLocation[] { deca.getSourceLocation() }); - } - } - return true; - } - return false; - } - - private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm, ResolvedMember itdfieldsig, DeclareAnnotation deca, - List<Integer> reportedProblems) { - if (rm != null && rm.hasAnnotation(deca.getAnnotationType())) { - if (world.getLint().elementAlreadyAnnotated.isEnabled()) { - Integer uniqueID = new Integer(rm.hashCode() * deca.hashCode()); - if (!reportedProblems.contains(uniqueID)) { - reportedProblems.add(uniqueID); - reportedProblems.add(new Integer(itdfieldsig.hashCode() * deca.hashCode())); - world.getLint().elementAlreadyAnnotated.signal(new String[] { itdfieldsig.toString(), - deca.getAnnotationType().toString() }, rm.getSourceLocation(), - new ISourceLocation[] { deca.getSourceLocation() }); - } - } - return true; - } - return false; - } - - private Set<String> findAspectsForMungers(LazyMethodGen mg) { - Set<String> aspectsAffectingType = new HashSet<String>(); - for (BcelShadow shadow : mg.matchedShadows) { - for (ShadowMunger munger : shadow.getMungers()) { - if (munger instanceof BcelAdvice) { - BcelAdvice bcelAdvice = (BcelAdvice) munger; - if (bcelAdvice.getConcreteAspect() != null) { - aspectsAffectingType.add(bcelAdvice.getConcreteAspect().getSignature()); - } - } else { - // It is a 'Checker' - we don't need to remember aspects - // that only contributed Checkers... - } - } - } - return aspectsAffectingType; - } - - private boolean inlineSelfConstructors(List<LazyMethodGen> methodGens, List<LazyMethodGen> recursiveCtors) { - boolean inlinedSomething = false; - List<LazyMethodGen> newRecursiveCtors = new ArrayList<LazyMethodGen>(); - for (LazyMethodGen methodGen : methodGens) { - if (!methodGen.getName().equals("<init>")) { - continue; - } - InstructionHandle ih = findSuperOrThisCall(methodGen); - if (ih != null && isThisCall(ih)) { - LazyMethodGen donor = getCalledMethod(ih); - if (donor.equals(methodGen)) { - newRecursiveCtors.add(donor); - } else { - if (!recursiveCtors.contains(donor)) { - inlineMethod(donor, methodGen, ih); - inlinedSomething = true; - } - } - } - } - recursiveCtors.addAll(newRecursiveCtors); - return inlinedSomething; - } - - private void positionAndImplement(List<BcelShadow> initializationShadows) { - for (BcelShadow s : initializationShadows) { - positionInitializationShadow(s); - // s.getEnclosingMethod().print(); - s.implement(); - } - } - - private void positionInitializationShadow(BcelShadow s) { - LazyMethodGen mg = s.getEnclosingMethod(); - InstructionHandle call = findSuperOrThisCall(mg); - InstructionList body = mg.getBody(); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - if (s.getKind() == Shadow.PreInitialization) { - // XXX assert first instruction is an ALOAD_0. - // a pre shadow goes from AFTER the first instruction (which we - // believe to - // be an ALOAD_0) to just before the call to super - r.associateWithTargets(Range.genStart(body, body.getStart().getNext()), Range.genEnd(body, call.getPrev())); - } else { - // assert s.getKind() == Shadow.Initialization - r.associateWithTargets(Range.genStart(body, call.getNext()), Range.genEnd(body)); - } - } - - private boolean isThisCall(InstructionHandle ih) { - InvokeInstruction inst = (InvokeInstruction) ih.getInstruction(); - return inst.getClassName(cpg).equals(clazz.getName()); - } - - /** - * inline a particular call in bytecode. - * - * @param donor the method we want to inline - * @param recipient the method containing the call we want to inline - * @param call the instructionHandle in recipient's body holding the call we want to inline. - */ - public static void inlineMethod(LazyMethodGen donor, LazyMethodGen recipient, InstructionHandle call) { - // assert recipient.contains(call) - - /* - * Implementation notes: - * - * We allocate two slots for every tempvar so we don't screw up longs and doubles which may share space. This could be - * conservatively avoided (no reference to a long/double instruction, don't do it) or packed later. Right now we don't - * bother to pack. - * - * Allocate a new var for each formal param of the inlined. Fill with stack contents. Then copy the inlined instructions in - * with the appropriate remap table. Any framelocs used by locals in inlined are reallocated to top of frame, - */ - final InstructionFactory fact = recipient.getEnclosingClass().getFactory(); - - IntMap frameEnv = new IntMap(); - - // this also sets up the initial environment - InstructionList argumentStores = genArgumentStores(donor, recipient, frameEnv, fact); - - InstructionList inlineInstructions = genInlineInstructions(donor, recipient, frameEnv, fact, false); - - inlineInstructions.insert(argumentStores); - - recipient.getBody().append(call, inlineInstructions); - Utility.deleteInstruction(call, recipient); - } - - // public BcelVar genTempVar(UnresolvedType typeX) { - // return new BcelVar(typeX.resolve(world), - // genTempVarIndex(typeX.getSize())); - // } - // - // private int genTempVarIndex(int size) { - // return enclosingMethod.allocateLocal(size); - // } - - /** - * Input method is a synchronized method, we remove the bit flag for synchronized and then insert a try..finally block - * - * Some jumping through firey hoops required - depending on the input code level (1.5 or not) we may or may not be able to use - * the LDC instruction that takes a class literal (doesnt on <1.5). - * - * FIXME asc Before promoting -Xjoinpoints:synchronization to be a standard option, this needs a bunch of tidying up - there is - * some duplication that can be removed. - */ - public static void transformSynchronizedMethod(LazyMethodGen synchronizedMethod) { - if (trace.isTraceEnabled()) { - trace.enter("transformSynchronizedMethod", synchronizedMethod); - } - // System.err.println("DEBUG: Transforming synchronized method: "+ - // synchronizedMethod.getName()); - final InstructionFactory fact = synchronizedMethod.getEnclosingClass().getFactory(); - InstructionList body = synchronizedMethod.getBody(); - InstructionList prepend = new InstructionList(); - Type enclosingClassType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType()); - - // STATIC METHOD TRANSFORMATION - if (synchronizedMethod.isStatic()) { - - // What to do here depends on the level of the class file! - // LDC can handle class literals in Java5 and above *sigh* - if (synchronizedMethod.getEnclosingClass().isAtLeastJava5()) { - // MONITORENTER logic: - // 0: ldc #2; //class C - // 2: dup - // 3: astore_0 - // 4: monitorenter - int slotForLockObject = synchronizedMethod.allocateLocal(enclosingClassType); - prepend.append(fact.createConstant(enclosingClassType)); - prepend.append(InstructionFactory.createDup(1)); - prepend.append(InstructionFactory.createStore(enclosingClassType, slotForLockObject)); - prepend.append(InstructionFactory.MONITORENTER); - - // MONITOREXIT logic: - - // We basically need to wrap the code from the method in a - // finally block that - // will ensure monitorexit is called. Content on the finally - // block seems to - // be always: - // - // E1: ALOAD_1 - // MONITOREXIT - // ATHROW - // - // so lets build that: - InstructionList finallyBlock = new InstructionList(); - finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class), slotForLockObject)); - finallyBlock.append(InstructionConstants.MONITOREXIT); - finallyBlock.append(InstructionConstants.ATHROW); - - // finally -> E1 - // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line - // 21) - // | LDC "hello" - // | INVOKEVIRTUAL java.io.PrintStream.println - // (Ljava/lang/String;)V - // | ALOAD_1 (line 20) - // | MONITOREXIT - // finally -> E1 - // GOTO L0 - // finally -> E1 - // | E1: ALOAD_1 - // | MONITOREXIT - // finally -> E1 - // ATHROW - // L0: RETURN (line 23) - - // search for 'returns' and make them jump to the - // aload_<n>,monitorexit - InstructionHandle walker = body.getStart(); - List<InstructionHandle> rets = new ArrayList<InstructionHandle>(); - while (walker != null) { - if (walker.getInstruction().isReturnInstruction()) { - rets.add(walker); - } - walker = walker.getNext(); - } - if (!rets.isEmpty()) { - // need to ensure targeters for 'return' now instead target - // the load instruction - // (so we never jump over the monitorexit logic) - - for (Iterator<InstructionHandle> iter = rets.iterator(); iter.hasNext();) { - InstructionHandle element = iter.next(); - InstructionList monitorExitBlock = new InstructionList(); - monitorExitBlock.append(InstructionFactory.createLoad(enclosingClassType, slotForLockObject)); - monitorExitBlock.append(InstructionConstants.MONITOREXIT); - // monitorExitBlock.append(Utility.copyInstruction(element - // .getInstruction())); - // element.setInstruction(InstructionFactory.createLoad( - // classType,slotForThis)); - InstructionHandle monitorExitBlockStart = body.insert(element, monitorExitBlock); - - // now move the targeters from the RET to the start of - // the monitorexit block - for (InstructionTargeter targeter : element.getTargetersCopy()) { - // what kinds are there? - if (targeter instanceof LocalVariableTag) { - // ignore - } else if (targeter instanceof LineNumberTag) { - // ignore - // } else if (targeter instanceof - // InstructionBranch && - // ((InstructionBranch)targeter).isGoto()) { - // // move it... - // targeter.updateTarget(element, - // monitorExitBlockStart); - } else if (targeter instanceof InstructionBranch) { - // move it - targeter.updateTarget(element, monitorExitBlockStart); - } else { - throw new BCException("Unexpected targeter encountered during transform: " + targeter); - } - } - } - } - - // now the magic, putting the finally block around the code - InstructionHandle finallyStart = finallyBlock.getStart(); - - InstructionHandle tryPosition = body.getStart(); - InstructionHandle catchPosition = body.getEnd(); - body.insert(body.getStart(), prepend); // now we can put the - // monitorenter stuff on - synchronizedMethod.getBody().append(finallyBlock); - synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null/* ==finally */, false); - synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false); - } else { - - // TRANSFORMING STATIC METHOD ON PRE JAVA5 - - // Hideous nightmare, class literal references prior to Java5 - - // YIKES! this is just the code for MONITORENTER ! - // 0: getstatic #59; //Field class$1:Ljava/lang/Class; - // 3: dup - // 4: ifnonnull 32 - // 7: pop - // try - // 8: ldc #61; //String java.lang.String - // 10: invokestatic #44; //Method - // java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; - // 13: dup - // catch - // 14: putstatic #59; //Field class$1:Ljava/lang/Class; - // 17: goto 32 - // 20: new #46; //class java/lang/NoClassDefFoundError - // 23: dup_x1 - // 24: swap - // 25: invokevirtual #52; //Method - // java/lang/Throwable.getMessage:()Ljava/lang/String; - // 28: invokespecial #54; //Method - // java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V - // 31: athrow - // 32: dup <-- partTwo (branch target) - // 33: astore_0 - // 34: monitorenter - // - // plus exceptiontable entry! - // 8 13 20 Class java/lang/ClassNotFoundException - Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType()); - Type clazzType = Type.getType(Class.class); - - InstructionList parttwo = new InstructionList(); - parttwo.append(InstructionFactory.createDup(1)); - int slotForThis = synchronizedMethod.allocateLocal(classType); - parttwo.append(InstructionFactory.createStore(clazzType, slotForThis)); // ? should be the real type ? String or - // something? - parttwo.append(InstructionFactory.MONITORENTER); - - String fieldname = synchronizedMethod.getEnclosingClass().allocateField("class$"); - FieldGen f = new FieldGen(Modifier.STATIC | Modifier.PRIVATE, Type.getType(Class.class), fieldname, - synchronizedMethod.getEnclosingClass().getConstantPool()); - synchronizedMethod.getEnclosingClass().addField(f, null); - - // 10: invokestatic #44; //Method - // java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; - // 13: dup - // 14: putstatic #59; //Field class$1:Ljava/lang/Class; - // 17: goto 32 - // 20: new #46; //class java/lang/NoClassDefFoundError - // 23: dup_x1 - // 24: swap - // 25: invokevirtual #52; //Method - // java/lang/Throwable.getMessage:()Ljava/lang/String; - // 28: invokespecial #54; //Method - // java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V - // 31: athrow - String name = synchronizedMethod.getEnclosingClass().getName(); - - prepend.append(fact.createGetStatic(name, fieldname, Type.getType(Class.class))); - prepend.append(InstructionFactory.createDup(1)); - prepend.append(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, parttwo.getStart())); - prepend.append(InstructionFactory.POP); - - prepend.append(fact.createConstant(name)); - InstructionHandle tryInstruction = prepend.getEnd(); - prepend.append(fact.createInvoke("java.lang.Class", "forName", clazzType, - new Type[] { Type.getType(String.class) }, Constants.INVOKESTATIC)); - InstructionHandle catchInstruction = prepend.getEnd(); - prepend.append(InstructionFactory.createDup(1)); - - prepend.append(fact.createPutStatic(synchronizedMethod.getEnclosingClass().getType().getName(), fieldname, - Type.getType(Class.class))); - prepend.append(InstructionFactory.createBranchInstruction(Constants.GOTO, parttwo.getStart())); - - // start of catch block - InstructionList catchBlockForLiteralLoadingFail = new InstructionList(); - catchBlockForLiteralLoadingFail.append(fact.createNew((ObjectType) Type.getType(NoClassDefFoundError.class))); - catchBlockForLiteralLoadingFail.append(InstructionFactory.createDup_1(1)); - catchBlockForLiteralLoadingFail.append(InstructionFactory.SWAP); - catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.Throwable", "getMessage", - Type.getType(String.class), new Type[] {}, Constants.INVOKEVIRTUAL)); - catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.NoClassDefFoundError", "<init>", Type.VOID, - new Type[] { Type.getType(String.class) }, Constants.INVOKESPECIAL)); - catchBlockForLiteralLoadingFail.append(InstructionFactory.ATHROW); - InstructionHandle catchBlockStart = catchBlockForLiteralLoadingFail.getStart(); - prepend.append(catchBlockForLiteralLoadingFail); - prepend.append(parttwo); - // MONITORENTER - // pseudocode: load up 'this' (var0), dup it, store it in a new - // local var (for use with monitorexit) and call - // monitorenter: - // ALOAD_0, DUP, ASTORE_<n>, MONITORENTER - // prepend.append(InstructionFactory.createLoad(classType,0)); - // prepend.append(InstructionFactory.createDup(1)); - // int slotForThis = - // synchronizedMethod.allocateLocal(classType); - // prepend.append(InstructionFactory.createStore(classType, - // slotForThis)); - // prepend.append(InstructionFactory.MONITORENTER); - - // MONITOREXIT - // here be dragons - - // We basically need to wrap the code from the method in a - // finally block that - // will ensure monitorexit is called. Content on the finally - // block seems to - // be always: - // - // E1: ALOAD_1 - // MONITOREXIT - // ATHROW - // - // so lets build that: - InstructionList finallyBlock = new InstructionList(); - finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class), slotForThis)); - finallyBlock.append(InstructionConstants.MONITOREXIT); - finallyBlock.append(InstructionConstants.ATHROW); - - // finally -> E1 - // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line - // 21) - // | LDC "hello" - // | INVOKEVIRTUAL java.io.PrintStream.println - // (Ljava/lang/String;)V - // | ALOAD_1 (line 20) - // | MONITOREXIT - // finally -> E1 - // GOTO L0 - // finally -> E1 - // | E1: ALOAD_1 - // | MONITOREXIT - // finally -> E1 - // ATHROW - // L0: RETURN (line 23) - // frameEnv.put(donorFramePos, thisSlot); - - // search for 'returns' and make them to the - // aload_<n>,monitorexit - InstructionHandle walker = body.getStart(); - List<InstructionHandle> rets = new ArrayList<InstructionHandle>(); - while (walker != null) { // !walker.equals(body.getEnd())) { - if (walker.getInstruction().isReturnInstruction()) { - rets.add(walker); - } - walker = walker.getNext(); - } - if (rets.size() > 0) { - // need to ensure targeters for 'return' now instead target - // the load instruction - // (so we never jump over the monitorexit logic) - - for (InstructionHandle ret : rets) { - // System.err.println("Adding monitor exit block at "+ - // element); - InstructionList monitorExitBlock = new InstructionList(); - monitorExitBlock.append(InstructionFactory.createLoad(classType, slotForThis)); - monitorExitBlock.append(InstructionConstants.MONITOREXIT); - // monitorExitBlock.append(Utility.copyInstruction(element - // .getInstruction())); - // element.setInstruction(InstructionFactory.createLoad( - // classType,slotForThis)); - InstructionHandle monitorExitBlockStart = body.insert(ret, monitorExitBlock); - - // now move the targeters from the RET to the start of - // the monitorexit block - for (InstructionTargeter targeter : ret.getTargetersCopy()) { - // what kinds are there? - if (targeter instanceof LocalVariableTag) { - // ignore - } else if (targeter instanceof LineNumberTag) { - // ignore - // } else if (targeter instanceof GOTO || - // targeter instanceof GOTO_W) { - // // move it... - // targeter.updateTarget(element, - // monitorExitBlockStart); - } else if (targeter instanceof InstructionBranch) { - // move it - targeter.updateTarget(ret, monitorExitBlockStart); - } else { - throw new BCException("Unexpected targeter encountered during transform: " + targeter); - } - } - } - } - // body = - // rewriteWithMonitorExitCalls(body,fact,true,slotForThis, - // classType); - // synchronizedMethod.setBody(body); - - // now the magic, putting the finally block around the code - InstructionHandle finallyStart = finallyBlock.getStart(); - - InstructionHandle tryPosition = body.getStart(); - InstructionHandle catchPosition = body.getEnd(); - body.insert(body.getStart(), prepend); // now we can put the - // monitorenter stuff on - - synchronizedMethod.getBody().append(finallyBlock); - synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null/* ==finally */, false); - synchronizedMethod.addExceptionHandler(tryInstruction, catchInstruction, catchBlockStart, - (ObjectType) Type.getType(ClassNotFoundException.class), true); - synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false); - } - } else { - - // TRANSFORMING NON STATIC METHOD - Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType()); - // MONITORENTER - // pseudocode: load up 'this' (var0), dup it, store it in a new - // local var (for use with monitorexit) and call - // monitorenter: - // ALOAD_0, DUP, ASTORE_<n>, MONITORENTER - prepend.append(InstructionFactory.createLoad(classType, 0)); - prepend.append(InstructionFactory.createDup(1)); - int slotForThis = synchronizedMethod.allocateLocal(classType); - prepend.append(InstructionFactory.createStore(classType, slotForThis)); - prepend.append(InstructionFactory.MONITORENTER); - // body.insert(body.getStart(),prepend); - - // MONITOREXIT - - // We basically need to wrap the code from the method in a finally - // block that - // will ensure monitorexit is called. Content on the finally block - // seems to - // be always: - // - // E1: ALOAD_1 - // MONITOREXIT - // ATHROW - // - // so lets build that: - InstructionList finallyBlock = new InstructionList(); - finallyBlock.append(InstructionFactory.createLoad(classType, slotForThis)); - finallyBlock.append(InstructionConstants.MONITOREXIT); - finallyBlock.append(InstructionConstants.ATHROW); - - // finally -> E1 - // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 21) - // | LDC "hello" - // | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V - // | ALOAD_1 (line 20) - // | MONITOREXIT - // finally -> E1 - // GOTO L0 - // finally -> E1 - // | E1: ALOAD_1 - // | MONITOREXIT - // finally -> E1 - // ATHROW - // L0: RETURN (line 23) - // frameEnv.put(donorFramePos, thisSlot); - - // search for 'returns' and make them to the aload_<n>,monitorexit - InstructionHandle walker = body.getStart(); - List<InstructionHandle> rets = new ArrayList<InstructionHandle>(); - while (walker != null) { // !walker.equals(body.getEnd())) { - if (walker.getInstruction().isReturnInstruction()) { - rets.add(walker); - } - walker = walker.getNext(); - } - if (!rets.isEmpty()) { - // need to ensure targeters for 'return' now instead target the - // load instruction - // (so we never jump over the monitorexit logic) - - for (Iterator<InstructionHandle> iter = rets.iterator(); iter.hasNext();) { - InstructionHandle element = iter.next(); - // System.err.println("Adding monitor exit block at "+element - // ); - InstructionList monitorExitBlock = new InstructionList(); - monitorExitBlock.append(InstructionFactory.createLoad(classType, slotForThis)); - monitorExitBlock.append(InstructionConstants.MONITOREXIT); - // monitorExitBlock.append(Utility.copyInstruction(element. - // getInstruction())); - // element.setInstruction(InstructionFactory.createLoad( - // classType,slotForThis)); - InstructionHandle monitorExitBlockStart = body.insert(element, monitorExitBlock); - - // now move the targeters from the RET to the start of the - // monitorexit block - for (InstructionTargeter targeter : element.getTargetersCopy()) { - // what kinds are there? - if (targeter instanceof LocalVariableTag) { - // ignore - } else if (targeter instanceof LineNumberTag) { - // ignore - // } else if (targeter instanceof GOTO || - // targeter instanceof GOTO_W) { - // // move it... - // targeter.updateTarget(element, - // monitorExitBlockStart); - } else if (targeter instanceof InstructionBranch) { - // move it - targeter.updateTarget(element, monitorExitBlockStart); - } else { - throw new BCException("Unexpected targeter encountered during transform: " + targeter); - } - } - } - } - - // now the magic, putting the finally block around the code - InstructionHandle finallyStart = finallyBlock.getStart(); - - InstructionHandle tryPosition = body.getStart(); - InstructionHandle catchPosition = body.getEnd(); - body.insert(body.getStart(), prepend); // now we can put the - // monitorenter stuff on - synchronizedMethod.getBody().append(finallyBlock); - synchronizedMethod.addExceptionHandler(tryPosition, catchPosition, finallyStart, null/* ==finally */, false); - synchronizedMethod.addExceptionHandler(finallyStart, finallyStart.getNext(), finallyStart, null, false); - // also the exception handling for the finally block jumps to itself - - // max locals will already have been modified in the allocateLocal() - // call - - // synchronized bit is removed on LazyMethodGen.pack() - } - - // gonna have to go through and change all aload_0s to load the var from - // a variable, - // going to add a new variable for the this var - - if (trace.isTraceEnabled()) { - trace.exit("transformSynchronizedMethod"); - } - } - - /** - * generate the instructions to be inlined. - * - * @param donor the method from which we will copy (and adjust frame and jumps) instructions. - * @param recipient the method the instructions will go into. Used to get the frame size so we can allocate new frame locations - * for locals in donor. - * @param frameEnv an environment to map from donor frame to recipient frame, initially populated with argument locations. - * @param fact an instruction factory for recipient - */ - static InstructionList genInlineInstructions(LazyMethodGen donor, LazyMethodGen recipient, IntMap frameEnv, - InstructionFactory fact, boolean keepReturns) { - InstructionList footer = new InstructionList(); - InstructionHandle end = footer.append(InstructionConstants.NOP); - - InstructionList ret = new InstructionList(); - InstructionList sourceList = donor.getBody(); - - Map<InstructionHandle, InstructionHandle> srcToDest = new HashMap<InstructionHandle, InstructionHandle>(); - ConstantPool donorCpg = donor.getEnclosingClass().getConstantPool(); - ConstantPool recipientCpg = recipient.getEnclosingClass().getConstantPool(); - - boolean isAcrossClass = donorCpg != recipientCpg; - BootstrapMethods bootstrapMethods = null; - // first pass: copy the instructions directly, populate the srcToDest - // map, - // fix frame instructions - for (InstructionHandle src = sourceList.getStart(); src != null; src = src.getNext()) { - Instruction fresh = Utility.copyInstruction(src.getInstruction()); - InstructionHandle dest; - - // OPTIMIZE optimize this stuff? - if (fresh.isConstantPoolInstruction()) { - // need to reset index to go to new constant pool. This is totally - // a computation leak... we're testing this LOTS of times. Sigh. - if (isAcrossClass) { - InstructionCP cpi = (InstructionCP) fresh; - cpi.setIndex(recipientCpg.addConstant(donorCpg.getConstant(cpi.getIndex()), donorCpg)); - } - // May need to copy bootstrapmethods across too. -// if (fresh instanceof InvokeDynamic) { -// InvokeDynamic id = (InvokeDynamic)fresh; -// ConstantInvokeDynamic cid = (ConstantInvokeDynamic)donorCpg.getConstant(src.getInstruction().getIndex()); -// int bmaIndex = cid.getBootstrapMethodAttrIndex(); -// if (bootstrapMethods == null) { -// Collection<Attribute> attributes = donor.getEnclosingClass().getAttributes(); -// if (attributes != null) { -// for (Attribute attribute: attributes) { -// if (attribute instanceof BootstrapMethods) { -// bootstrapMethods = (BootstrapMethods)attribute; -// } -// } -// } -// BootstrapMethods.BootstrapMethod bootstrapMethod = -// bootstrapMethods.getBootstrapMethods()[bmaIndex]; -// ConstantMethodHandle methodhandle = (ConstantMethodHandle)donorCpg.getConstant(bootstrapMethod.getBootstrapMethodRef()); -// int bootstrapMethodArguments[] = bootstrapMethod.getBootstrapArguments(); -// -// // Finally have all we need to build the new one... -// -// int newMethodHandleIndex = recipientCpg.addConstant(methodhandle, donorCpg); -// int[] newMethodArguments = new int[bootstrapMethodArguments.length]; -// for (int a=0; a<bootstrapMethodArguments.length; a++) { -// newMethodArguments[a] = recipientCpg.addConstant(donorCpg.getConstant(bootstrapMethodArguments[a]),donorCpg); -// } -// BootstrapMethods.BootstrapMethod newBootstrapMethod = -// new BootstrapMethods.BootstrapMethod(newMethodHandleIndex,newMethodArguments); -// -// Collection<Attribute> newAttributes = recipient.getEnclosingClass().getAttributes(); -// BootstrapMethods newBootstrapMethods = null; -// for (Attribute attr: newAttributes) { -// if (attr instanceof BootstrapMethods) { -// newBootstrapMethods = (BootstrapMethods)newBootstrapMethods; -// } -// } -// if (newBootstrapMethods == null) { -// newBootstrapMethods = -// new BootstrapMethods(recipientCpg.addUtf8("BootstrapMethods"), -// 2+newBootstrapMethod.getLength(), -// new BootstrapMethods.BootstrapMethod[] {newBootstrapMethod}, -// recipientCpg); -// recipient.getEnclosingClass().addAttribute(newBootstrapMethods); -// } -// TODO need to copy over lambda$0 support methods too... -// } -// -// } - } - if (src.getInstruction() == Range.RANGEINSTRUCTION) { - dest = ret.append(Range.RANGEINSTRUCTION); - } else if (fresh.isReturnInstruction()) { - if (keepReturns) { - dest = ret.append(fresh); - } else { - dest = ret.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end)); - } - } else if (fresh instanceof InstructionBranch) { - dest = ret.append((InstructionBranch) fresh); - } else if (fresh.isLocalVariableInstruction() || fresh instanceof RET) { - - // IndexedInstruction indexed = (IndexedInstruction) fresh; - int oldIndex = fresh.getIndex(); - int freshIndex; - if (!frameEnv.hasKey(oldIndex)) { - freshIndex = recipient.allocateLocal(2); - frameEnv.put(oldIndex, freshIndex); - } else { - freshIndex = frameEnv.get(oldIndex); - } - if (fresh instanceof RET) { - fresh.setIndex(freshIndex); - } else { - fresh = ((InstructionLV) fresh).setIndexAndCopyIfNecessary(freshIndex); - } - dest = ret.append(fresh); - } else { - dest = ret.append(fresh); - } - srcToDest.put(src, dest); - } - - // second pass: retarget branch instructions, copy ranges and tags - Map<Tag, Tag> tagMap = new HashMap<Tag, Tag>(); - Map<BcelShadow, BcelShadow> shadowMap = new HashMap<BcelShadow, BcelShadow>(); - for (InstructionHandle dest = ret.getStart(), src = sourceList.getStart(); dest != null; dest = dest.getNext(), src = src - .getNext()) { - Instruction inst = dest.getInstruction(); - - // retarget branches - if (inst instanceof InstructionBranch) { - InstructionBranch branch = (InstructionBranch) inst; - InstructionHandle oldTarget = branch.getTarget(); - InstructionHandle newTarget = srcToDest.get(oldTarget); - if (newTarget == null) { - // assert this is a GOTO - // this was a return instruction we previously replaced - } else { - branch.setTarget(newTarget); - if (branch instanceof InstructionSelect) { - InstructionSelect select = (InstructionSelect) branch; - InstructionHandle[] oldTargets = select.getTargets(); - for (int k = oldTargets.length - 1; k >= 0; k--) { - select.setTarget(k, srcToDest.get(oldTargets[k])); - } - } - } - } - - // copy over tags and range attributes - - Iterator<InstructionTargeter> tIter = src.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter old = tIter.next(); - if (old instanceof Tag) { - Tag oldTag = (Tag) old; - Tag fresh = tagMap.get(oldTag); - if (fresh == null) { - fresh = oldTag.copy(); - if (old instanceof LocalVariableTag) { - // LocalVariable - LocalVariableTag lvTag = (LocalVariableTag) old; - LocalVariableTag lvTagFresh = (LocalVariableTag) fresh; - if (lvTag.getSlot() == 0) { - fresh = new LocalVariableTag(lvTag.getRealType().getSignature(), "ajc$aspectInstance", - frameEnv.get(lvTag.getSlot()), 0); - } else { - // // Do not move it - when copying the code from the aspect to the affected target, 'this' is - // // going to change from aspect to affected type. So just fix the type - // System.out.println("For local variable tag at instruction " + src + " changing slot from " - // + lvTag.getSlot() + " > " + frameEnv.get(lvTag.getSlot())); - lvTagFresh.updateSlot(frameEnv.get(lvTag.getSlot())); - } - } - tagMap.put(oldTag, fresh); - } - dest.addTargeter(fresh); - } else if (old instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) old; - if (er.getStart() == src) { - ExceptionRange freshEr = new ExceptionRange(recipient.getBody(), er.getCatchType(), er.getPriority()); - freshEr.associateWithTargets(dest, srcToDest.get(er.getEnd()), srcToDest.get(er.getHandler())); - } - } else if (old instanceof ShadowRange) { - ShadowRange oldRange = (ShadowRange) old; - if (oldRange.getStart() == src) { - BcelShadow oldShadow = oldRange.getShadow(); - BcelShadow freshEnclosing = oldShadow.getEnclosingShadow() == null ? null : (BcelShadow) shadowMap - .get(oldShadow.getEnclosingShadow()); - BcelShadow freshShadow = oldShadow.copyInto(recipient, freshEnclosing); - ShadowRange freshRange = new ShadowRange(recipient.getBody()); - freshRange.associateWithShadow(freshShadow); - freshRange.associateWithTargets(dest, srcToDest.get(oldRange.getEnd())); - shadowMap.put(oldShadow, freshShadow); // oldRange, freshRange - // recipient.matchedShadows.add(freshShadow); - // XXX should go through the NEW copied shadow and - // update - // the thisVar, targetVar, and argsVar - // ??? Might want to also go through at this time and - // add - // "extra" vars to the shadow. - } - } - } - } - if (!keepReturns) { - ret.append(footer); - } - return ret; - } - - // static InstructionList rewriteWithMonitorExitCalls(InstructionList - // sourceList,InstructionFactory fact,boolean keepReturns,int - // monitorVarSlot,Type monitorVarType) - // { - // InstructionList footer = new InstructionList(); - // InstructionHandle end = footer.append(InstructionConstants.NOP); - // - // InstructionList newList = new InstructionList(); - // - // Map srcToDest = new HashMap(); - // - // // first pass: copy the instructions directly, populate the srcToDest - // map, - // // fix frame instructions - // for (InstructionHandle src = sourceList.getStart(); src != null; src = - // src.getNext()) { - // Instruction fresh = Utility.copyInstruction(src.getInstruction()); - // InstructionHandle dest; - // if (src.getInstruction() == Range.RANGEINSTRUCTION) { - // dest = newList.append(Range.RANGEINSTRUCTION); - // } else if (fresh.isReturnInstruction()) { - // if (keepReturns) { - // newList.append(InstructionFactory.createLoad(monitorVarType,monitorVarSlot - // )); - // newList.append(InstructionConstants.MONITOREXIT); - // dest = newList.append(fresh); - // } else { - // dest = - // newList.append(InstructionFactory.createBranchInstruction(Constants.GOTO, - // end)); - // } - // } else if (fresh instanceof InstructionBranch) { - // dest = newList.append((InstructionBranch) fresh); - // } else if ( - // fresh.isLocalVariableInstruction() || fresh instanceof RET) { - // //IndexedInstruction indexed = (IndexedInstruction) fresh; - // int oldIndex = fresh.getIndex(); - // int freshIndex; - // // if (!frameEnv.hasKey(oldIndex)) { - // // freshIndex = recipient.allocateLocal(2); - // // frameEnv.put(oldIndex, freshIndex); - // // } else { - // freshIndex = oldIndex;//frameEnv.get(oldIndex); - // // } - // if (fresh instanceof RET) { - // fresh.setIndex(freshIndex); - // } else { - // fresh = ((InstructionLV)fresh).setIndexAndCopyIfNecessary(freshIndex); - // } - // dest = newList.append(fresh); - // } else { - // dest = newList.append(fresh); - // } - // srcToDest.put(src, dest); - // } - // - // // second pass: retarget branch instructions, copy ranges and tags - // Map tagMap = new HashMap(); - // for (InstructionHandle dest = newList.getStart(), src = - // sourceList.getStart(); - // dest != null; - // dest = dest.getNext(), src = src.getNext()) { - // Instruction inst = dest.getInstruction(); - // - // // retarget branches - // if (inst instanceof InstructionBranch) { - // InstructionBranch branch = (InstructionBranch) inst; - // InstructionHandle oldTarget = branch.getTarget(); - // InstructionHandle newTarget = - // (InstructionHandle) srcToDest.get(oldTarget); - // if (newTarget == null) { - // // assert this is a GOTO - // // this was a return instruction we previously replaced - // } else { - // branch.setTarget(newTarget); - // if (branch instanceof InstructionSelect) { - // InstructionSelect select = (InstructionSelect) branch; - // InstructionHandle[] oldTargets = select.getTargets(); - // for (int k = oldTargets.length - 1; k >= 0; k--) { - // select.setTarget( - // k, - // (InstructionHandle) srcToDest.get(oldTargets[k])); - // } - // } - // } - // } - // - // //copy over tags and range attributes - // Iterator tIter = src.getTargeters().iterator(); - // - // while (tIter.hasNext()) { - // InstructionTargeter old = (InstructionTargeter)tIter.next(); - // if (old instanceof Tag) { - // Tag oldTag = (Tag) old; - // Tag fresh = (Tag) tagMap.get(oldTag); - // if (fresh == null) { - // fresh = oldTag.copy(); - // tagMap.put(oldTag, fresh); - // } - // dest.addTargeter(fresh); - // } else if (old instanceof ExceptionRange) { - // ExceptionRange er = (ExceptionRange) old; - // if (er.getStart() == src) { - // ExceptionRange freshEr = - // new ExceptionRange(newList/*recipient.getBody()*/,er.getCatchType(),er. - // getPriority()); - // freshEr.associateWithTargets( - // dest, - // (InstructionHandle)srcToDest.get(er.getEnd()), - // (InstructionHandle)srcToDest.get(er.getHandler())); - // } - // } - // /*else if (old instanceof ShadowRange) { - // ShadowRange oldRange = (ShadowRange) old; - // if (oldRange.getStart() == src) { - // BcelShadow oldShadow = oldRange.getShadow(); - // BcelShadow freshEnclosing = - // oldShadow.getEnclosingShadow() == null - // ? null - // : (BcelShadow) shadowMap.get(oldShadow.getEnclosingShadow()); - // BcelShadow freshShadow = - // oldShadow.copyInto(recipient, freshEnclosing); - // ShadowRange freshRange = new ShadowRange(recipient.getBody()); - // freshRange.associateWithShadow(freshShadow); - // freshRange.associateWithTargets( - // dest, - // (InstructionHandle) srcToDest.get(oldRange.getEnd())); - // shadowMap.put(oldRange, freshRange); - // //recipient.matchedShadows.add(freshShadow); - // // XXX should go through the NEW copied shadow and update - // // the thisVar, targetVar, and argsVar - // // ??? Might want to also go through at this time and add - // // "extra" vars to the shadow. - // } - // }*/ - // } - // } - // if (!keepReturns) newList.append(footer); - // return newList; - // } - - /** - * generate the argument stores in preparation for inlining. - * - * @param donor the method we will inline from. Used to get the signature. - * @param recipient the method we will inline into. Used to get the frame size so we can allocate fresh locations. - * @param frameEnv an empty environment we populate with a map from donor frame to recipient frame. - * @param fact an instruction factory for recipient - */ - private static InstructionList genArgumentStores(LazyMethodGen donor, LazyMethodGen recipient, IntMap frameEnv, - InstructionFactory fact) { - InstructionList ret = new InstructionList(); - - int donorFramePos = 0; - - // writing ret back to front because we're popping. - if (!donor.isStatic()) { - int targetSlot = recipient.allocateLocal(Type.OBJECT); - ret.insert(InstructionFactory.createStore(Type.OBJECT, targetSlot)); - frameEnv.put(donorFramePos, targetSlot); - donorFramePos += 1; - } - Type[] argTypes = donor.getArgumentTypes(); - for (int i = 0, len = argTypes.length; i < len; i++) { - Type argType = argTypes[i]; - int argSlot = recipient.allocateLocal(argType); - ret.insert(InstructionFactory.createStore(argType, argSlot)); - frameEnv.put(donorFramePos, argSlot); - donorFramePos += argType.getSize(); - } - return ret; - } - - /** - * get a called method: Assumes the called method is in this class, and the reference to it is exact (a la INVOKESPECIAL). - * - * @param ih The InvokeInstruction instructionHandle pointing to the called method. - */ - private LazyMethodGen getCalledMethod(InstructionHandle ih) { - InvokeInstruction inst = (InvokeInstruction) ih.getInstruction(); - - String methodName = inst.getName(cpg); - String signature = inst.getSignature(cpg); - - return clazz.getLazyMethodGen(methodName, signature); - } - - private void weaveInAddedMethods() { - Collections.sort(addedLazyMethodGens, new Comparator<LazyMethodGen>() { - public int compare(LazyMethodGen aa, LazyMethodGen bb) { - int i = aa.getName().compareTo(bb.getName()); - if (i != 0) { - return i; - } - return aa.getSignature().compareTo(bb.getSignature()); - } - }); - - for (LazyMethodGen addedMember : addedLazyMethodGens) { - clazz.addMethodGen(addedMember); - } - } - - // void addPerSingletonField(Member field) { - // ObjectType aspectType = (ObjectType) - // BcelWorld.makeBcelType(field.getReturnType()); - // String aspectName = field.getReturnType().getName(); - // - // LazyMethodGen clinit = clazz.getStaticInitializer(); - // InstructionList setup = new InstructionList(); - // InstructionFactory fact = clazz.getFactory(); - // - // setup.append(fact.createNew(aspectType)); - // setup.append(InstructionFactory.createDup(1)); - // setup.append(fact.createInvoke(aspectName, "<init>", Type.VOID, new - // Type[0], Constants.INVOKESPECIAL)); - // setup.append(fact.createFieldAccess(aspectName, field.getName(), - // aspectType, Constants.PUTSTATIC)); - // clinit.getBody().insert(setup); - // } - - /** - * Returns null if this is not a Java constructor, and then we won't weave into it at all - */ - private InstructionHandle findSuperOrThisCall(LazyMethodGen mg) { - int depth = 1; - InstructionHandle start = mg.getBody().getStart(); - while (true) { - if (start == null) { - return null; - } - - Instruction inst = start.getInstruction(); - if (inst.opcode == Constants.INVOKESPECIAL && ((InvokeInstruction) inst).getName(cpg).equals("<init>")) { - depth--; - if (depth == 0) { - return start; - } - } else if (inst.opcode == Constants.NEW) { - depth++; - } - start = start.getNext(); - } - } - - // ---- - - 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>")) { - return matchInit(mg, shadowAccumulator); - } else if (!shouldWeaveBody(mg)) { - return false; - } else { - if (startsAngly && mg.getName().equals("<clinit>")) { - // clinitShadow = - enclosingShadow = BcelShadow.makeStaticInitialization(world, mg); - // System.err.println(enclosingShadow); - } else if (mg.isAdviceMethod()) { - enclosingShadow = BcelShadow.makeAdviceExecution(world, mg); - } 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(); - - // Annotations for things with effective signatures are - // never stored in the effective - // signature itself - we have to hunt for them. Storing them - // in the effective signature - // would mean keeping two sets up to date (no way!!) - - fixParameterNamesForResolvedMember(rm, mg.getMemberView()); - fixAnnotationsForResolvedMember(rm, mg.getMemberView()); - - enclosingShadow = BcelShadow.makeShadowForMethod(world, mg, effective.getShadowKind(), rm); - } else { - return false; - } - } - - if (canMatchBodyShadows) { - for (InstructionHandle h = mg.getBody().getStart(); h != null; h = h.getNext()) { - match(mg, h, enclosingShadow, shadowAccumulator); - } - } - // FIXME asc change from string match if we can, rather brittle. - // this check actually prevents field-exec jps - if (canMatch(enclosingShadow.getKind()) - && !(mg.getName().charAt(0) == 'a' && mg.getName().startsWith("ajc$interFieldInit"))) { - if (match(enclosingShadow, shadowAccumulator)) { - enclosingShadow.init(); - } - } - mg.matchedShadows = shadowAccumulator; - return !shadowAccumulator.isEmpty(); - } - } - - private boolean matchInit(LazyMethodGen mg, List<BcelShadow> shadowAccumulator) { - BcelShadow enclosingShadow; - // XXX the enclosing join point is wrong for things before ignoreMe. - InstructionHandle superOrThisCall = findSuperOrThisCall(mg); - - // we don't walk bodies of things where it's a wrong constructor thingie - if (superOrThisCall == null) { - return false; - } - - enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall); - if (mg.getEffectiveSignature() != null) { - enclosingShadow.setMatchingSignature(mg.getEffectiveSignature().getEffectiveSignature()); - } - - // walk the body - boolean beforeSuperOrThisCall = true; - if (shouldWeaveBody(mg)) { - if (canMatchBodyShadows) { - for (InstructionHandle h = mg.getBody().getStart(); h != null; h = h.getNext()) { - if (h == superOrThisCall) { - beforeSuperOrThisCall = false; - continue; - } - match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator); - } - } - if (canMatch(Shadow.ConstructorExecution)) { - match(enclosingShadow, shadowAccumulator); - } - } - - // XXX we don't do pre-inits of interfaces - - // now add interface inits - if (!isThisCall(superOrThisCall)) { - InstructionHandle curr = enclosingShadow.getRange().getStart(); - for (Iterator<IfaceInitList> i = addedSuperInitializersAsList.iterator(); i.hasNext();) { - IfaceInitList l = i.next(); - - Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType); - - BcelShadow initShadow = BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig); - - // insert code in place - InstructionList inits = genInitInstructions(l.list, false); - if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) { - initShadow.initIfaceInitializer(curr); - initShadow.getRange().insert(inits, Range.OutsideBefore); - } - } - - // now we add our initialization code - InstructionList inits = genInitInstructions(addedThisInitializers, false); - enclosingShadow.getRange().insert(inits, Range.OutsideBefore); - } - - // actually, you only need to inline the self constructors that are - // in a particular group (partition the constructors into groups where - // members - // call or are called only by those in the group). Then only inline - // constructors - // in groups where at least one initialization jp matched. Future work. - boolean addedInitialization = match(BcelShadow.makeUnfinishedInitialization(world, mg), initializationShadows); - addedInitialization |= match(BcelShadow.makeUnfinishedPreinitialization(world, mg), initializationShadows); - mg.matchedShadows = shadowAccumulator; - return addedInitialization || !shadowAccumulator.isEmpty(); - } - - private boolean shouldWeaveBody(LazyMethodGen mg) { - if (mg.isBridgeMethod()) { - return false; - } - if (mg.isAjSynthetic()) { - return mg.getName().equals("<clinit>"); - } - AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature(); - if (a != null) { - return a.isWeaveBody(); - } - return true; - } - - /** - * first sorts the mungers, then gens the initializers in the right order - */ - private InstructionList genInitInstructions(List<ConcreteTypeMunger> list, boolean isStatic) { - list = PartialOrder.sort(list); - if (list == null) { - throw new BCException("circularity in inter-types"); - } - - InstructionList ret = new InstructionList(); - - for (ConcreteTypeMunger cmunger : list) { - NewFieldTypeMunger munger = (NewFieldTypeMunger) cmunger.getMunger(); - ResolvedMember initMethod = munger.getInitMethod(cmunger.getAspectType()); - if (!isStatic) { - ret.append(InstructionConstants.ALOAD_0); - } - ret.append(Utility.createInvoke(fact, world, initMethod)); - } - return ret; - } - - private void match(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List<BcelShadow> shadowAccumulator) { - Instruction i = ih.getInstruction(); - - // Exception handlers (pr230817) - if (canMatch(Shadow.ExceptionHandler) && !Range.isRangeHandle(ih)) { - Set<InstructionTargeter> targeters = ih.getTargetersCopy(); - // If in Java7 there may be overlapping exception ranges for multi catch - we should recognize that - for (InstructionTargeter t : targeters) { - if (t instanceof ExceptionRange) { - // assert t.getHandler() == ih - ExceptionRange er = (ExceptionRange) t; - if (er.getCatchType() == null) { - continue; - } - if (isInitFailureHandler(ih)) { - return; - } - if (!ih.getInstruction().isStoreInstruction() && ih.getInstruction().getOpcode() != Constants.NOP) { - // If using cobertura, the catch block stats with - // INVOKESTATIC rather than ASTORE, in order that the ranges - // for the methodcall and exceptionhandler shadows - // that occur at this same - // line, we need to modify the instruction list to - // split them - adding a - // NOP before the invokestatic that gets all the targeters - // that were aimed at the INVOKESTATIC - mg.getBody().insert(ih, InstructionConstants.NOP); - InstructionHandle newNOP = ih.getPrev(); - // what about a try..catch that starts at the start - // of the exception handler? need to only include - // certain targeters really. - er.updateTarget(ih, newNOP, mg.getBody()); - for (InstructionTargeter t2 : targeters) { - newNOP.addTargeter(t2); - } - ih.removeAllTargeters(); - match(BcelShadow.makeExceptionHandler(world, er, mg, newNOP, enclosingShadow), shadowAccumulator); - } else { - match(BcelShadow.makeExceptionHandler(world, er, mg, ih, enclosingShadow), shadowAccumulator); - } - } - } - } - - if ((i instanceof FieldInstruction) && (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))) { - FieldInstruction fi = (FieldInstruction) i; - - if (fi.opcode == Constants.PUTFIELD || fi.opcode == Constants.PUTSTATIC) { - // check for sets of constant fields. We first check the - // previous - // instruction. If the previous instruction is a LD_WHATEVER - // (push - // constant on the stack) then we must resolve the field to - // determine - // if it's final. If it is final, then we don't generate a - // shadow. - InstructionHandle prevHandle = ih.getPrev(); - Instruction prevI = prevHandle.getInstruction(); - if (Utility.isConstantPushInstruction(prevI)) { - Member field = BcelWorld.makeFieldJoinPointSignature(clazz, (FieldInstruction) i); - ResolvedMember resolvedField = field.resolve(world); - if (resolvedField == null) { - // we can't find the field, so it's not a join point. - } else if (Modifier.isFinal(resolvedField.getModifiers())) { - // it's final, so it's the set of a final constant, so - // it's - // not a join point according to 1.0.6 and 1.1. - } else { - if (canMatch(Shadow.FieldSet)) { - matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator); - } - } - } else { - if (canMatch(Shadow.FieldSet)) { - matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator); - } - } - } else { - if (canMatch(Shadow.FieldGet)) { - matchGetInstruction(mg, ih, enclosingShadow, shadowAccumulator); - } - } - } else if (i instanceof InvokeInstruction) { - InvokeInstruction ii = (InvokeInstruction) i; - if (ii.getMethodName(clazz.getConstantPool()).equals("<init>")) { - if (canMatch(Shadow.ConstructorCall)) { - match(BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow), shadowAccumulator); - } - } else if (ii.opcode == Constants.INVOKESPECIAL) { - String onTypeName = ii.getClassName(cpg); - if (onTypeName.equals(mg.getEnclosingClass().getName())) { - // we are private - matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator); - } else { - // we are a super call, and this is not a join point in - // AspectJ-1.{0,1} - } - } else { - if (ii.getOpcode()!=Constants.INVOKEDYNAMIC) { - matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator); - } - } - } else if (world.isJoinpointArrayConstructionEnabled() && i.isArrayCreationInstruction()) { - if (canMatch(Shadow.ConstructorCall)) { - if (i.opcode == Constants.ANEWARRAY) { - // ANEWARRAY arrayInstruction = (ANEWARRAY)i; - // ObjectType arrayType = i.getLoadClassType(clazz.getConstantPool()); - BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow); - match(ctorCallShadow, shadowAccumulator); - } else if (i.opcode == Constants.NEWARRAY) { - // NEWARRAY arrayInstruction = (NEWARRAY)i; - // Type arrayType = i.getType(); - BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow); - match(ctorCallShadow, shadowAccumulator); - } else if (i instanceof MULTIANEWARRAY) { - // MULTIANEWARRAY arrayInstruction = (MULTIANEWARRAY) i; - // ObjectType arrayType = arrayInstruction.getLoadClassType(clazz.getConstantPool()); - BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world, mg, ih, enclosingShadow); - match(ctorCallShadow, shadowAccumulator); - } - } - // see pr77166 if you are thinking about implementing this - // } else if (i instanceof AALOAD ) { - // AALOAD arrayLoad = (AALOAD)i; - // Type arrayType = arrayLoad.getType(clazz.getConstantPoolGen()); - // BcelShadow arrayLoadShadow = - // BcelShadow.makeArrayLoadCall(world,mg,ih,enclosingShadow); - // match(arrayLoadShadow,shadowAccumulator); - // } else if (i instanceof AASTORE) { - // // ... magic required - } else if (world.isJoinpointSynchronizationEnabled() - && ((i.getOpcode() == Constants.MONITORENTER) || (i.getOpcode() == Constants.MONITOREXIT))) { - // if (canMatch(Shadow.Monitoring)) { - if (i.getOpcode() == Constants.MONITORENTER) { - BcelShadow monitorEntryShadow = BcelShadow.makeMonitorEnter(world, mg, ih, enclosingShadow); - match(monitorEntryShadow, shadowAccumulator); - } else { - BcelShadow monitorExitShadow = BcelShadow.makeMonitorExit(world, mg, ih, enclosingShadow); - match(monitorExitShadow, shadowAccumulator); - } - // } - } - - } - - private boolean isInitFailureHandler(InstructionHandle ih) { - // Skip the astore_0 and aload_0 at the start of the handler and - // then check if the instruction following these is - // 'putstatic ajc$initFailureCause'. If it is then we are - // in the handler we created in AspectClinit.generatePostSyntheticCode() - InstructionHandle twoInstructionsAway = ih.getNext().getNext(); - if (twoInstructionsAway.getInstruction().opcode == Constants.PUTSTATIC) { - String name = ((FieldInstruction) twoInstructionsAway.getInstruction()).getFieldName(cpg); - if (name.equals(NameMangler.INITFAILURECAUSE_FIELD_NAME)) { - return true; - } - } - return false; - } - - private void matchSetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, - List<BcelShadow> shadowAccumulator) { - FieldInstruction fi = (FieldInstruction) ih.getInstruction(); - Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi); - - // synthetic fields are never join points - if (field.getName().startsWith(NameMangler.PREFIX)) { - return; - } - - ResolvedMember resolvedField = field.resolve(world); - if (resolvedField == null) { - // we can't find the field, so it's not a join point. - return; - } else if (Modifier.isFinal(resolvedField.getModifiers()) - && Utility.isConstantPushInstruction(ih.getPrev().getInstruction())) { - // it's the set of a final constant, so it's - // not a join point according to 1.0.6 and 1.1. - return; - } else if (resolvedField.isSynthetic()) { - // sets of synthetics aren't join points in 1.1 - return; - } else { - // Fix for bug 172107 (similar the "get" fix for bug 109728) - BcelShadow bs = BcelShadow.makeFieldSet(world, resolvedField, mg, ih, enclosingShadow); - String cname = fi.getClassName(cpg); - if (!resolvedField.getDeclaringType().getName().equals(cname)) { - bs.setActualTargetType(cname); - } - match(bs, shadowAccumulator); - } - } - - private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, - List<BcelShadow> shadowAccumulator) { - FieldInstruction fi = (FieldInstruction) ih.getInstruction(); - Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi); - - // synthetic fields are never join points - if (field.getName().startsWith(NameMangler.PREFIX)) { - return; - } - - ResolvedMember resolvedField = field.resolve(world); - if (resolvedField == null) { - // we can't find the field, so it's not a join point. - return; - } else if (resolvedField.isSynthetic()) { - // sets of synthetics aren't join points in 1.1 - return; - } else { - BcelShadow bs = BcelShadow.makeFieldGet(world, resolvedField, mg, ih, enclosingShadow); - String cname = fi.getClassName(cpg); - if (!resolvedField.getDeclaringType().getName().equals(cname)) { - bs.setActualTargetType(cname); - } - match(bs, shadowAccumulator); - } - } - - /** - * For some named resolved type, this method looks for a member with a particular name - it should only be used when you truly - * believe there is only one member with that name in the type as it returns the first one it finds. - */ - private ResolvedMember findResolvedMemberNamed(ResolvedType type, String methodName) { - ResolvedMember[] allMethods = type.getDeclaredMethods(); - for (int i = 0; i < allMethods.length; i++) { - ResolvedMember member = allMethods[i]; - if (member.getName().equals(methodName)) { - return member; - } - } - return null; - } - - /** - * Find the specified member in the specified type. - * - * @param type the type to search for the member - * @param methodName the name of the method to find - * @param params the method parameters that the discovered method should have - */ - private ResolvedMember findResolvedMemberNamed(ResolvedType type, String methodName, UnresolvedType[] params) { - ResolvedMember[] allMethods = type.getDeclaredMethods(); - List<ResolvedMember> candidates = new ArrayList<ResolvedMember>(); - for (int i = 0; i < allMethods.length; i++) { - ResolvedMember candidate = allMethods[i]; - if (candidate.getName().equals(methodName)) { - if (candidate.getArity() == params.length) { - candidates.add(candidate); - } - } - } - - if (candidates.size() == 0) { - return null; - } else if (candidates.size() == 1) { - return candidates.get(0); - } else { - // multiple candidates - for (ResolvedMember candidate : candidates) { - // These checks will break down with generics... but that would need two ITDs with the same name, same arity and - // generics - boolean allOK = true; - UnresolvedType[] candidateParams = candidate.getParameterTypes(); - for (int p = 0; p < candidateParams.length; p++) { - if (!candidateParams[p].getErasureSignature().equals(params[p].getErasureSignature())) { - allOK = false; - break; - } - } - if (allOK) { - return candidate; - } - } - } - return null; - } - - /** - * For a given resolvedmember, this will discover the real annotations for it. <b>Should only be used when the resolvedmember is - * the contents of an effective signature attribute, as thats the only time when the annotations aren't stored directly in the - * resolvedMember</b> - * - * @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing - * @param declaredSig the real sig 'blah.ajc$xxx' - */ - private void fixParameterNamesForResolvedMember(ResolvedMember rm, ResolvedMember declaredSig) { - - UnresolvedType memberHostType = declaredSig.getDeclaringType(); - String methodName = declaredSig.getName(); - String[] pnames = null; - if (rm.getKind() == Member.METHOD && !rm.isAbstract()) { - if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) { - ResolvedMember resolvedDooberry = world.resolve(declaredSig); - pnames = resolvedDooberry.getParameterNames(); - } else { - ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world), memberHostType).resolve(world); - ResolvedMember theRealMember = findResolvedMemberNamed(memberHostType.resolve(world), realthing.getName()); - if (theRealMember != null) { - pnames = theRealMember.getParameterNames(); - // static ITDs don't need any parameter shifting - if (pnames.length > 0 && pnames[0].equals("ajc$this_")) { - String[] pnames2 = new String[pnames.length - 1]; - System.arraycopy(pnames, 1, pnames2, 0, pnames2.length); - pnames = pnames2; - } - } - } - // i think ctors are missing from here... copy code from below... - } - rm.setParameterNames(pnames); - } - - /** - * For a given resolvedmember, this will discover the real annotations for it. <b>Should only be used when the resolvedmember is - * the contents of an effective signature attribute, as thats the only time when the annotations aren't stored directly in the - * resolvedMember</b> - * - * @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing - * @param declaredSig the real sig 'blah.ajc$xxx' - */ - private void fixAnnotationsForResolvedMember(ResolvedMember rm, ResolvedMember declaredSig) { - try { - UnresolvedType memberHostType = declaredSig.getDeclaringType(); - boolean containsKey = mapToAnnotationHolder.containsKey(rm); - ResolvedMember realAnnotationHolder = mapToAnnotationHolder.get(rm); - String methodName = declaredSig.getName(); - // FIXME asc shouldnt really rely on string names ! - if (!containsKey) { - if (rm.getKind() == Member.FIELD) { - if (methodName.startsWith("ajc$inlineAccessField")) { - realAnnotationHolder = world.resolve(rm); - } else { - ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm, memberHostType); - realAnnotationHolder = world.resolve(realthing); - } - } else if (rm.getKind() == Member.METHOD && !rm.isAbstract()) { - if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) { - realAnnotationHolder = world.resolve(declaredSig); - } else { - ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world), memberHostType).resolve(world); - realAnnotationHolder = findResolvedMemberNamed(memberHostType.resolve(world), realthing.getName(),realthing.getParameterTypes()); - if (realAnnotationHolder == null) { - throw new UnsupportedOperationException( - "Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified"); - } - } - } else if (rm.getKind() == Member.CONSTRUCTOR) { - ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(), rm.getParameterTypes()); - realAnnotationHolder = world.resolve(realThing); - // AMC temp guard for M4 - if (realAnnotationHolder == null) { - throw new UnsupportedOperationException("Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified"); - } - } - mapToAnnotationHolder.put(rm, realAnnotationHolder); - } - ResolvedType[] annotationTypes; - AnnotationAJ[] annotations; - if (realAnnotationHolder!=null) { - annotationTypes = realAnnotationHolder.getAnnotationTypes(); - annotations = realAnnotationHolder.getAnnotations(); - if (annotationTypes==null) { - annotationTypes = ResolvedType.EMPTY_ARRAY; - } - if (annotations==null) { - annotations = AnnotationAJ.EMPTY_ARRAY; - } - } else { - annotations = AnnotationAJ.EMPTY_ARRAY; - annotationTypes = ResolvedType.EMPTY_ARRAY; - } - rm.setAnnotations(annotations); - rm.setAnnotationTypes(annotationTypes); - } catch (UnsupportedOperationException ex) { - throw ex; - } catch (Throwable t) { - // FIXME asc remove this catch after more testing has confirmed the - // above stuff is OK - throw new BCException("Unexpectedly went bang when searching for annotations on " + rm, t); - } - } - - private void matchInvokeInstruction(LazyMethodGen mg, InstructionHandle ih, InvokeInstruction invoke, - BcelShadow enclosingShadow, List<BcelShadow> shadowAccumulator) { - String methodName = invoke.getName(cpg); - if (methodName.startsWith(NameMangler.PREFIX)) { - Member jpSig = world.makeJoinPointSignatureForMethodInvocation(clazz, invoke); - ResolvedMember declaredSig = jpSig.resolve(world); - // System.err.println(method + ", declaredSig: " +declaredSig); - if (declaredSig == null) { - return; - } - - if (declaredSig.getKind() == Member.FIELD) { - Shadow.Kind kind; - if (jpSig.getReturnType().equals(UnresolvedType.VOID)) { - kind = Shadow.FieldSet; - } else { - kind = Shadow.FieldGet; - } - - if (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet)) { - match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, kind, declaredSig), shadowAccumulator); - } - } else if (!declaredSig.getName().startsWith(NameMangler.PREFIX)) { - // 307147 - resolution above may have found the real method directly rather - // than needing to go through the effective signature attribute - if (canMatch(Shadow.MethodCall)) { - match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, Shadow.MethodCall, declaredSig), - shadowAccumulator); - } - } else { - AjAttribute.EffectiveSignatureAttribute effectiveSig = declaredSig.getEffectiveSignature(); - if (effectiveSig == null) { - return; - } - // System.err.println("call to inter-type member: " + - // effectiveSig); - if (effectiveSig.isWeaveBody()) { - return; - } - - ResolvedMember rm = effectiveSig.getEffectiveSignature(); - fixParameterNamesForResolvedMember(rm, declaredSig); - fixAnnotationsForResolvedMember(rm, declaredSig); // abracadabra - - if (canMatch(effectiveSig.getShadowKind())) { - match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, effectiveSig.getShadowKind(), rm), - shadowAccumulator); - } - } - } else { - if (canMatch(Shadow.MethodCall)) { - 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.length() > 4 - && s.charAt(4) == 'a' - && (s.equals("org.aspectj.runtime.internal.CFlowCounter") - || s.equals("org.aspectj.runtime.internal.CFlowStack") || s - .equals("org.aspectj.runtime.reflect.Factory"))) { - proceed = false; - } else { - if (methodName.equals("aspectOf")) { - proceed = false; - } - } - } - if (proceed) { - match(BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow), shadowAccumulator); - } - } - } - } - - // static ... so all worlds will share the config for the first one - // created... - private static boolean checkedXsetForLowLevelContextCapturing = false; - private static boolean captureLowLevelContext = false; - - private boolean match(BcelShadow shadow, List<BcelShadow> shadowAccumulator) { - // Duplicate blocks - one with context one without, seems faster than multiple 'ifs' - if (captureLowLevelContext) { - ContextToken shadowMatchToken = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.MATCHING_SHADOW, shadow); - boolean isMatched = false; - - Shadow.Kind shadowKind = shadow.getKind(); - List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()]; - - // System.out.println("Candidates " + candidateMungers); - if (candidateMungers != null) { - for (ShadowMunger munger : candidateMungers) { - - ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut()); - if (munger.match(shadow, world)) { - shadow.addMunger(munger); - isMatched = true; - if (shadow.getKind() == Shadow.StaticInitialization) { - clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation()); - } - } - CompilationAndWeavingContext.leavingPhase(mungerMatchToken); - } - - if (isMatched) { - shadowAccumulator.add(shadow); - } - } - CompilationAndWeavingContext.leavingPhase(shadowMatchToken); - return isMatched; - } else { - boolean isMatched = false; - - Shadow.Kind shadowKind = shadow.getKind(); - List<ShadowMunger> candidateMungers = indexedShadowMungers[shadowKind.getKey()]; - - // System.out.println("Candidates at " + shadowKind + " are " + candidateMungers); - if (candidateMungers != null) { - for (ShadowMunger munger : candidateMungers) { - if (munger.match(shadow, world)) { - shadow.addMunger(munger); - isMatched = true; - if (shadow.getKind() == Shadow.StaticInitialization) { - clazz.warnOnAddedStaticInitializer(shadow, munger.getSourceLocation()); - } - } - } - if (isMatched) { - shadowAccumulator.add(shadow); - } - } - return isMatched; - } - } - - // ---- - - private void implement(LazyMethodGen mg) { - List<BcelShadow> shadows = mg.matchedShadows; - if (shadows == null) { - return; - } - // We depend on a partial order such that inner shadows are earlier on - // the list than outer shadows. That's fine. This order is preserved if: - - // A preceeds B iff B.getStart() is LATER THAN A.getStart(). - - for (BcelShadow shadow : shadows) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.IMPLEMENTING_ON_SHADOW, - shadow); - shadow.implement(); - CompilationAndWeavingContext.leavingPhase(tok); - } - // int ii = - mg.getMaxLocals(); - mg.matchedShadows = null; - } - - // ---- - - public LazyClassGen getLazyClassGen() { - return clazz; - } - - public BcelWorld getWorld() { - return world; - } - - public void setReweavableMode(boolean mode) { - inReweavableMode = mode; - } - - public boolean getReweavableMode() { - return inReweavableMode; - } - - @Override - public String toString() { - return "BcelClassWeaver instance for : " + clazz; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolReader.java b/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolReader.java deleted file mode 100644 index 2deaf57c1..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolReader.java +++ /dev/null @@ -1,34 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 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: - * Andy Clement (SpringSource) - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.weaver.ConstantPoolReader; - -/** - * An implementation of the constant pool reader that speaks Bcel. - * - * @author Andy Clement - */ -public class BcelConstantPoolReader implements ConstantPoolReader { - - private ConstantPool constantPool; - - public BcelConstantPoolReader(ConstantPool constantPool) { - this.constantPool = constantPool; - } - - public String readUtf8(int cpIndex) { - return constantPool.getConstantUtf8(cpIndex).getValue(); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolWriter.java b/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolWriter.java deleted file mode 100644 index 634764901..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelConstantPoolWriter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 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: - * Andy Clement (SpringSource) - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.weaver.ConstantPoolWriter; - -/** - * An implementation of the constant pool writer that speaks Bcel. - * - * @author Andy Clement - */ -class BcelConstantPoolWriter implements ConstantPoolWriter { - - ConstantPool pool; - - public BcelConstantPoolWriter(ConstantPool pool) { - this.pool = pool; - } - - public int writeUtf8(String name) { - return pool.addUtf8(name); - } - -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelField.java b/weaver/src/org/aspectj/weaver/bcel/BcelField.java deleted file mode 100644 index c88e8519f..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelField.java +++ /dev/null @@ -1,307 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.util.List; - -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.classfile.Synthetic; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.util.GenericSignature; -import org.aspectj.util.GenericSignatureParser; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException; - -/** - * An AspectJ Field object that is backed by a Bcel Field object. - * - * @author PARC - * @author Andy Clement - */ -final class BcelField extends ResolvedMemberImpl { - - public static int AccSynthetic = 0x1000; - - private Field field; - private boolean isAjSynthetic; - private boolean isSynthetic = false; - private AnnotationAJ[] annotations; - private final World world; - private final BcelObjectType bcelObjectType; - private UnresolvedType genericFieldType = null; - private boolean unpackedGenericSignature = false; - private boolean annotationsOnFieldObjectAreOutOfDate = false; - - BcelField(BcelObjectType declaringType, Field field) { - super(FIELD, declaringType.getResolvedTypeX(), field.getModifiers(), field.getName(), field.getSignature()); - this.field = field; - this.world = declaringType.getResolvedTypeX().getWorld(); - this.bcelObjectType = declaringType; - unpackAttributes(world); - checkedExceptions = UnresolvedType.NONE; - } - - /** - * Constructs an instance that wrappers a Field object, but where we do not (yet) have a BcelObjectType - usually because the - * containing type (and this field) are being constructed at runtime (so there is no .class file to retrieve). - */ - BcelField(String declaringTypeName, Field field, World world) { - super(FIELD, UnresolvedType.forName(declaringTypeName), field.getModifiers(), field.getName(), field.getSignature()); - this.field = field; - this.world = world; - this.bcelObjectType = null; - unpackAttributes(world); - checkedExceptions = UnresolvedType.NONE; - } - - private void unpackAttributes(World world) { - Attribute[] attrs = field.getAttributes(); - if (attrs != null && attrs.length > 0) { - ISourceContext sourceContext = getSourceContext(world); - List<AjAttribute> as = Utility.readAjAttributes(getDeclaringType().getClassName(), attrs, sourceContext, world, - (bcelObjectType != null ? bcelObjectType.getWeaverVersionAttribute() : WeaverVersionInfo.CURRENT), - new BcelConstantPoolReader(field.getConstantPool())); - as.addAll(AtAjAttributes.readAj5FieldAttributes(field, this, world.resolve(getDeclaringType()), sourceContext, - world.getMessageHandler())); - - // FIXME this code has no effect!!!??? it is set to false immediately after the block - // for (AjAttribute a : as) { - // if (a instanceof AjAttribute.AjSynthetic) { - // isAjSynthetic = true; - // } else { - // throw new BCException("weird field attribute " + a); - // } - // } - } - isAjSynthetic = false; - - for (int i = attrs.length - 1; i >= 0; i--) { - if (attrs[i] instanceof Synthetic) { - isSynthetic = true; - } - } - // in 1.5, synthetic is a modifier, not an attribute - if ((field.getModifiers() & AccSynthetic) != 0) { - isSynthetic = true; - } - - } - - @Override - public boolean isAjSynthetic() { - return isAjSynthetic; - } - - @Override - public boolean isSynthetic() { - return isSynthetic; - } - - @Override - public boolean hasAnnotation(UnresolvedType ofType) { - ensureAnnotationTypesRetrieved(); - for (ResolvedType aType : annotationTypes) { - if (aType.equals(ofType)) { - return true; - } - } - return false; - } - - @Override - public ResolvedType[] getAnnotationTypes() { - ensureAnnotationTypesRetrieved(); - return annotationTypes; - } - - @Override - public AnnotationAJ[] getAnnotations() { - ensureAnnotationTypesRetrieved(); - return annotations; - } - - @Override - public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) { - ensureAnnotationTypesRetrieved(); - for (AnnotationAJ annotation : annotations) { - if (annotation.getTypeName().equals(ofType.getName())) { - return annotation; - } - } - return null; - } - - private void ensureAnnotationTypesRetrieved() { - if (annotationTypes == null) { - AnnotationGen annos[] = field.getAnnotations(); - if (annos.length == 0) { - annotationTypes = ResolvedType.EMPTY_ARRAY; - annotations = AnnotationAJ.EMPTY_ARRAY; - } else { - int annosCount = annos.length; - annotationTypes = new ResolvedType[annosCount]; - annotations = new AnnotationAJ[annosCount]; - for (int i = 0; i < annosCount; i++) { - AnnotationGen anno = annos[i]; - annotations[i] = new BcelAnnotation(anno, world); - annotationTypes[i] = annotations[i].getType(); - } - } - } - } - - @Override - public void addAnnotation(AnnotationAJ annotation) { - ensureAnnotationTypesRetrieved(); - int len = annotations.length; - AnnotationAJ[] ret = new AnnotationAJ[len + 1]; - System.arraycopy(annotations, 0, ret, 0, len); - ret[len] = annotation; - annotations = ret; - - ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1]; - System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len); - newAnnotationTypes[len] = annotation.getType(); - annotationTypes = newAnnotationTypes; - - annotationsOnFieldObjectAreOutOfDate = true; - } - - public void removeAnnotation(AnnotationAJ annotation) { - ensureAnnotationTypesRetrieved(); - - int len = annotations.length; - AnnotationAJ[] ret = new AnnotationAJ[len - 1]; - int p = 0; - for (AnnotationAJ anno : annotations) { - if (!anno.getType().equals(annotation.getType())) { - ret[p++] = anno; - } - } - annotations = ret; - - ResolvedType[] newAnnotationTypes = new ResolvedType[len - 1]; - p = 0; - for (ResolvedType anno : annotationTypes) { - if (!anno.equals(annotation.getType())) { - newAnnotationTypes[p++] = anno; - } - } - annotationTypes = newAnnotationTypes; - - annotationsOnFieldObjectAreOutOfDate = true; - } - - /** - * Unpack the generic signature attribute if there is one and we haven't already done so, then find the true field type of this - * field (eg. List<String>). - */ - @Override - public UnresolvedType getGenericReturnType() { - unpackGenericSignature(); - return genericFieldType; - } - - public Field getFieldAsIs() { - return field; - } - - public Field getField(ConstantPool cpool) { - if (!annotationsOnFieldObjectAreOutOfDate) { - return field; - } - FieldGen newFieldGen = new FieldGen(field, cpool); - newFieldGen.removeAnnotations(); - // List<AnnotationGen> alreadyHas = fg.getAnnotations(); - // if (annotations != null) { - // fg.removeAnnotations(); - for (AnnotationAJ annotation : annotations) { - newFieldGen.addAnnotation(new AnnotationGen(((BcelAnnotation) annotation).getBcelAnnotation(), cpool, true)); - } - // for (int i = 0; i < annotations.length; i++) { - // AnnotationAJ array_element = annotations[i]; - // boolean alreadyHasIt = false; - // for (AnnotationGen gen : alreadyHas) { - // if (gen.getTypeName().equals(array_element.getTypeName())) { - // alreadyHasIt = true; - // break; - // } - // } - // if (!alreadyHasIt) { - // fg.addAnnotation(new AnnotationGen(((BcelAnnotation) array_element).getBcelAnnotation(), cpg, true)); - // // } - // // } - // } - field = newFieldGen.getField(); - annotationsOnFieldObjectAreOutOfDate = false; // we are now correct again - return field; - } - - private void unpackGenericSignature() { - if (unpackedGenericSignature) { - return; - } - if (!world.isInJava5Mode()) { - this.genericFieldType = getReturnType(); - return; - } - unpackedGenericSignature = true; - String gSig = field.getGenericSignature(); - if (gSig != null) { - // get from generic - GenericSignature.FieldTypeSignature fts = new GenericSignatureParser().parseAsFieldSignature(gSig); - GenericSignature.ClassSignature genericTypeSig = bcelObjectType.getGenericClassTypeSignature(); - - GenericSignature.FormalTypeParameter[] parentFormals = bcelObjectType.getAllFormals(); - GenericSignature.FormalTypeParameter[] typeVars = ((genericTypeSig == null) ? new GenericSignature.FormalTypeParameter[0] - : genericTypeSig.formalTypeParameters); - GenericSignature.FormalTypeParameter[] formals = new GenericSignature.FormalTypeParameter[parentFormals.length - + typeVars.length]; - // put method formal in front of type formals for overriding in - // lookup - System.arraycopy(typeVars, 0, formals, 0, typeVars.length); - System.arraycopy(parentFormals, 0, formals, typeVars.length, parentFormals.length); - - try { - genericFieldType = BcelGenericSignatureToTypeXConverter.fieldTypeSignature2TypeX(fts, formals, world); - } catch (GenericSignatureFormatException e) { - // development bug, fail fast with good info - throw new IllegalStateException("While determing the generic field type of " + this.toString() - + " with generic signature " + gSig + " the following error was detected: " + e.getMessage()); - } - } else { - genericFieldType = getReturnType(); - } - } - - @Override - public void evictWeavingState() { - if (field != null) { - unpackGenericSignature(); - unpackAttributes(world); - ensureAnnotationTypesRetrieved(); - // this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT; - field = null; - } - } -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java b/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java deleted file mode 100644 index a5a2a79ec..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java +++ /dev/null @@ -1,100 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.weaver.ResolvedType; - -/** - * XXX Erik and I need to discuss this hierarchy. Having FieldRef extend Var is convenient, but hopefully there's a better design. - * - * This is always a static reference. - */ -public class BcelFieldRef extends BcelVar { - - private String className, fieldName; - - public BcelFieldRef(ResolvedType type, String className, String fieldName) { - super(type, 0); - this.className = className; - this.fieldName = fieldName; - } - - public String toString() { - return "BcelFieldRef(" + getType() + " " + className + "." + fieldName + ")"; - } - - // public int getSlot() { return slot; } - - public Instruction createLoad(InstructionFactory fact) { - return fact.createFieldAccess(className, fieldName, BcelWorld.makeBcelType(getType()), Constants.GETSTATIC); - } - - public Instruction createStore(InstructionFactory fact) { - return fact.createFieldAccess(className, fieldName, BcelWorld.makeBcelType(getType()), Constants.PUTSTATIC); - } - - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - throw new RuntimeException("unimplemented"); - } - - // this is an array var - // void appendConvertableArrayLoad( - // InstructionList il, - // InstructionFactory fact, - // int index, - // ResolvedType convertTo) - // { - // ResolvedType convertFromType = getType().getResolvedComponentType(); - // appendLoad(il, fact); - // il.append(Utility.createConstant(fact, index)); - // il.append(fact.createArrayLoad(BcelWorld.makeBcelType(convertFromType))); - // Utility.appendConversion(il, fact, convertFromType, convertTo); - // } - // - // void appendConvertableArrayStore( - // InstructionList il, - // InstructionFactory fact, - // int index, - // BcelFieldRef storee) - // { - // ResolvedType convertToType = getType().getResolvedComponentType(); - // appendLoad(il, fact); - // il.append(Utility.createConstant(fact, index)); - // storee.appendLoad(il, fact); - // Utility.appendConversion(il, fact, storee.getType(), convertToType); - // il.append(fact.createArrayStore(BcelWorld.makeBcelType(convertToType))); - // } - // - // InstructionList createConvertableArrayStore( - // InstructionFactory fact, - // int index, - // BcelFieldRef storee) - // { - // InstructionList il = new InstructionList(); - // appendConvertableArrayStore(il, fact, index, storee); - // return il; - // } - // InstructionList createConvertableArrayLoad( - // InstructionFactory fact, - // int index, - // ResolvedType convertTo) - // { - // InstructionList il = new InstructionList(); - // appendConvertableArrayLoad(il, fact, index, convertTo); - // return il; - // } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java b/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java deleted file mode 100644 index 9b4c90cbc..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelGenericSignatureToTypeXConverter.java +++ /dev/null @@ -1,278 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Adrian Colyer Initial implementation - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import java.util.HashMap; -import java.util.Map; - -import org.aspectj.util.GenericSignature; -import org.aspectj.util.GenericSignature.SimpleClassTypeSignature; -import org.aspectj.weaver.BoundedReferenceType; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.TypeFactory; -import org.aspectj.weaver.TypeVariable; -import org.aspectj.weaver.TypeVariableReferenceType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -/** - * A utility class that assists in unpacking constituent parts of generic signature attributes and returning their equivalents in - * UnresolvedType world. - */ -public class BcelGenericSignatureToTypeXConverter { - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelGenericSignatureToTypeXConverter.class); - - public static ResolvedType classTypeSignature2TypeX(GenericSignature.ClassTypeSignature aClassTypeSignature, - GenericSignature.FormalTypeParameter[] typeParams, World world) throws GenericSignatureFormatException { - Map<GenericSignature.FormalTypeParameter, ReferenceType> typeMap = new HashMap<GenericSignature.FormalTypeParameter, ReferenceType>(); - ResolvedType ret = classTypeSignature2TypeX(aClassTypeSignature, typeParams, world, typeMap); - fixUpCircularDependencies(ret, typeMap); - return ret; - } - - private static ResolvedType classTypeSignature2TypeX(GenericSignature.ClassTypeSignature aClassTypeSignature, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - // class type sig consists of an outer type, and zero or more nested types - // the fully qualified name is outer-type.nested-type1.nested-type2.... - // each type in the hierarchy may have type arguments - - // first build the 'raw type' signature - StringBuffer sig = new StringBuffer(); - sig.append(aClassTypeSignature.outerType.identifier.replace(';', ' ').trim()); - for (int i = 0; i < aClassTypeSignature.nestedTypes.length; i++) { - sig.append("$"); - sig.append(aClassTypeSignature.nestedTypes[i].identifier.replace(';', ' ').trim()); - } - sig.append(";"); - - // now look for any type parameters. - // I *think* we only need to worry about the 'right-most' type... - SimpleClassTypeSignature innerType = aClassTypeSignature.outerType; - if (aClassTypeSignature.nestedTypes.length > 0) { - innerType = aClassTypeSignature.nestedTypes[aClassTypeSignature.nestedTypes.length - 1]; - } - if (innerType.typeArguments.length > 0) { - // we have to create a parameterized type - // type arguments may be array types, class types, or typevariable types - ResolvedType theBaseType = UnresolvedType.forSignature(sig.toString()).resolve(world); - - // Sometimes we may find that when the code is being load-time woven that the types have changed. - // Perhaps an old form of a library jar is being used - this can mean we discover right here - // that a type is not parameterizable (is that a word?). I think in these cases it is ok to - // just return with what we know (the base type). (see pr152848) - if (!(theBaseType.isGenericType() || theBaseType.isRawType())) { - if (trace.isTraceEnabled()) { - trace.event("classTypeSignature2TypeX: this type is not a generic type:", null, new Object[] { theBaseType }); - } - return theBaseType; - } - - ResolvedType[] typeArgumentTypes = new ResolvedType[innerType.typeArguments.length]; - for (int i = 0; i < typeArgumentTypes.length; i++) { - typeArgumentTypes[i] = typeArgument2TypeX(innerType.typeArguments[i], typeParams, world, - inProgressTypeVariableResolutions); - } - return TypeFactory.createParameterizedType(theBaseType, typeArgumentTypes, world); - - // world.resolve(UnresolvedType.forParameterizedTypes( - // UnresolvedType.forSignature(sig.toString()).resolve(world), - // typeArgumentTypes)); - } else { - // we have a non-parameterized type - return world.resolve(UnresolvedType.forSignature(sig.toString())); - } - } - - public static ResolvedType fieldTypeSignature2TypeX(GenericSignature.FieldTypeSignature aFieldTypeSignature, - GenericSignature.FormalTypeParameter[] typeParams, World world) throws GenericSignatureFormatException { - Map<GenericSignature.FormalTypeParameter, ReferenceType> typeMap = new HashMap<GenericSignature.FormalTypeParameter, ReferenceType>(); - ResolvedType ret = fieldTypeSignature2TypeX(aFieldTypeSignature, typeParams, world, typeMap); - fixUpCircularDependencies(ret, typeMap); - return ret; - } - - private static ResolvedType fieldTypeSignature2TypeX(GenericSignature.FieldTypeSignature aFieldTypeSignature, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - if (aFieldTypeSignature.isClassTypeSignature()) { - return classTypeSignature2TypeX((GenericSignature.ClassTypeSignature) aFieldTypeSignature, typeParams, world, - inProgressTypeVariableResolutions); - } else if (aFieldTypeSignature.isArrayTypeSignature()) { - int dims = 0; - GenericSignature.TypeSignature ats = aFieldTypeSignature; - while (ats instanceof GenericSignature.ArrayTypeSignature) { - dims++; - ats = ((GenericSignature.ArrayTypeSignature) ats).typeSig; - } - return world.resolve(UnresolvedType.makeArray( - typeSignature2TypeX(ats, typeParams, world, inProgressTypeVariableResolutions), dims)); - } else if (aFieldTypeSignature.isTypeVariableSignature()) { - ResolvedType rtx = typeVariableSignature2TypeX((GenericSignature.TypeVariableSignature) aFieldTypeSignature, - typeParams, world, inProgressTypeVariableResolutions); - return rtx; - } else { - throw new GenericSignatureFormatException("Cant understand field type signature: " + aFieldTypeSignature); - } - } - - public static TypeVariable formalTypeParameter2TypeVariable(GenericSignature.FormalTypeParameter aFormalTypeParameter, - GenericSignature.FormalTypeParameter[] typeParams, World world) throws GenericSignatureFormatException { - Map<GenericSignature.FormalTypeParameter, ReferenceType> typeMap = new HashMap<GenericSignature.FormalTypeParameter, ReferenceType>(); - return formalTypeParameter2TypeVariable(aFormalTypeParameter, typeParams, world, typeMap); - } - - private static TypeVariable formalTypeParameter2TypeVariable(GenericSignature.FormalTypeParameter aFormalTypeParameter, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - UnresolvedType upperBound = fieldTypeSignature2TypeX(aFormalTypeParameter.classBound, typeParams, world, - inProgressTypeVariableResolutions); - UnresolvedType[] ifBounds = new UnresolvedType[aFormalTypeParameter.interfaceBounds.length]; - for (int i = 0; i < ifBounds.length; i++) { - ifBounds[i] = fieldTypeSignature2TypeX(aFormalTypeParameter.interfaceBounds[i], typeParams, world, - inProgressTypeVariableResolutions); - } - return new TypeVariable(aFormalTypeParameter.identifier, upperBound, ifBounds); - } - - private static ResolvedType typeArgument2TypeX(GenericSignature.TypeArgument aTypeArgument, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - if (aTypeArgument.isWildcard) { - return UnresolvedType.SOMETHING.resolve(world); - } - if (aTypeArgument.isMinus) { - UnresolvedType bound = fieldTypeSignature2TypeX(aTypeArgument.signature, typeParams, world, - inProgressTypeVariableResolutions); - ResolvedType resolvedBound = world.resolve(bound); - if (resolvedBound.isMissing()) { - world.getLint().cantFindType.signal("Unable to find type (for bound): " + resolvedBound.getName(), null); - resolvedBound = world.resolve(UnresolvedType.OBJECT); - } - ReferenceType rBound = (ReferenceType) resolvedBound; - return new BoundedReferenceType(rBound, false, world); - } else if (aTypeArgument.isPlus) { - UnresolvedType bound = fieldTypeSignature2TypeX(aTypeArgument.signature, typeParams, world, - inProgressTypeVariableResolutions); - ResolvedType resolvedBound = world.resolve(bound); - if (resolvedBound.isMissing()) { - world.getLint().cantFindType.signal("Unable to find type (for bound): " + resolvedBound.getName(), null); - resolvedBound = world.resolve(UnresolvedType.OBJECT); - } - ReferenceType rBound = (ReferenceType) resolvedBound; - return new BoundedReferenceType(rBound, true, world); - } else { - return fieldTypeSignature2TypeX(aTypeArgument.signature, typeParams, world, inProgressTypeVariableResolutions); - } - } - - public static ResolvedType typeSignature2TypeX(GenericSignature.TypeSignature aTypeSig, - GenericSignature.FormalTypeParameter[] typeParams, World world) throws GenericSignatureFormatException { - Map<GenericSignature.FormalTypeParameter, ReferenceType> typeMap = new HashMap<GenericSignature.FormalTypeParameter, ReferenceType>(); - ResolvedType ret = typeSignature2TypeX(aTypeSig, typeParams, world, typeMap); - fixUpCircularDependencies(ret, typeMap); - return ret; - } - - private static ResolvedType typeSignature2TypeX(GenericSignature.TypeSignature aTypeSig, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - if (aTypeSig.isBaseType()) { - return world.resolve(UnresolvedType.forSignature(((GenericSignature.BaseTypeSignature) aTypeSig).toString())); - } else { - return fieldTypeSignature2TypeX((GenericSignature.FieldTypeSignature) aTypeSig, typeParams, world, - inProgressTypeVariableResolutions); - } - } - - private static ResolvedType typeVariableSignature2TypeX(GenericSignature.TypeVariableSignature aTypeVarSig, - GenericSignature.FormalTypeParameter[] typeParams, World world, - Map<GenericSignature.FormalTypeParameter, ReferenceType> inProgressTypeVariableResolutions) - throws GenericSignatureFormatException { - GenericSignature.FormalTypeParameter typeVarBounds = null; - for (int i = 0; i < typeParams.length; i++) { - if (typeParams[i].identifier.equals(aTypeVarSig.typeVariableName)) { - typeVarBounds = typeParams[i]; - break; - } - } - if (typeVarBounds == null) { - // blowing up here breaks the situation with ITDs where the type variable is mentioned in the - // declaring type and used somewhere in the signature. Temporary change to allow it to return just a - // 'dumb' typevariablereference. - return new TypeVariableReferenceType(new TypeVariable(aTypeVarSig.typeVariableName), world); - // throw new GenericSignatureFormatException("Undeclared type variable in signature: " + aTypeVarSig.typeVariableName); - } - if (inProgressTypeVariableResolutions.containsKey(typeVarBounds)) { - return inProgressTypeVariableResolutions.get(typeVarBounds); - } - inProgressTypeVariableResolutions.put(typeVarBounds, new FTPHolder(typeVarBounds, world)); - ReferenceType ret = new TypeVariableReferenceType(formalTypeParameter2TypeVariable(typeVarBounds, typeParams, world, - inProgressTypeVariableResolutions), world); - inProgressTypeVariableResolutions.put(typeVarBounds, ret); - return ret; - } - - private static void fixUpCircularDependencies(ResolvedType aTypeX, - Map<GenericSignature.FormalTypeParameter, ReferenceType> typeVariableResolutions) { - if (!(aTypeX instanceof ReferenceType)) { - return; - } - - ReferenceType rt = (ReferenceType) aTypeX; - TypeVariable[] typeVars = rt.getTypeVariables(); - if (typeVars != null) { - for (int i = 0; i < typeVars.length; i++) { - if (typeVars[i].getUpperBound() instanceof FTPHolder) { - GenericSignature.FormalTypeParameter key = ((FTPHolder) typeVars[i].getUpperBound()).ftpToBeSubstituted; - typeVars[i].setUpperBound(typeVariableResolutions.get(key)); - } - } - } - } - - private static class FTPHolder extends ReferenceType { - public GenericSignature.FormalTypeParameter ftpToBeSubstituted; - - public FTPHolder(GenericSignature.FormalTypeParameter ftp, World world) { - super("Ljava/lang/Object;", world); - this.ftpToBeSubstituted = ftp; - } - - public String toString() { - return "placeholder for TypeVariable of " + ftpToBeSubstituted.toString(); - } - - public ResolvedType resolve(World world) { - return this; - } - - public boolean isCacheable() { - return false; - } - } - - public static class GenericSignatureFormatException extends Exception { - public GenericSignatureFormatException(String explanation) { - super(explanation); - } - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java deleted file mode 100644 index d1e60e1c7..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java +++ /dev/null @@ -1,714 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import org.aspectj.apache.bcel.classfile.AnnotationDefault; -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.ExceptionTable; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.LineNumber; -import org.aspectj.apache.bcel.classfile.LineNumberTable; -import org.aspectj.apache.bcel.classfile.LocalVariable; -import org.aspectj.apache.bcel.classfile.LocalVariableTable; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.SourceLocation; -import org.aspectj.util.GenericSignature; -import org.aspectj.util.GenericSignature.TypeVariableSignature; -import org.aspectj.util.GenericSignatureParser; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.MemberKind; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedPointcutDefinition; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.TypeVariable; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException; - -//public final -class BcelMethod extends ResolvedMemberImpl { - - private final static String ASPECTJ_ANNOTATION_PACKAGE = "org.aspectj.lang.annotation"; - private final static char PACKAGE_INITIAL_CHAR = ASPECTJ_ANNOTATION_PACKAGE.charAt(0); - - private Method method; - - // these fields are not set for many BcelMethods... - private ShadowMunger associatedShadowMunger; - private ResolvedPointcutDefinition preResolvedPointcut; // used when ajc has pre-resolved the pointcut of some @Advice - private AjAttribute.EffectiveSignatureAttribute effectiveSignature; - - private AjAttribute.MethodDeclarationLineNumberAttribute declarationLineNumber; - private final BcelObjectType bcelObjectType; - - private int bitflags; - private static final int KNOW_IF_SYNTHETIC = 0x0001; - private static final int PARAMETER_NAMES_INITIALIZED = 0x0002; - private static final int CAN_BE_PARAMETERIZED = 0x0004; - private static final int UNPACKED_GENERIC_SIGNATURE = 0x0008; - private static final int IS_AJ_SYNTHETIC = 0x0040; - private static final int IS_SYNTHETIC = 0x0080; - private static final int IS_SYNTHETIC_INVERSE = 0x7f7f; // all bits but - // IS_SYNTHETIC (and - // topmost bit) - private static final int HAS_ANNOTATIONS = 0x0400; - private static final int HAVE_DETERMINED_ANNOTATIONS = 0x0800; - - // genericized version of return and parameter types - private UnresolvedType genericReturnType = null; - private UnresolvedType[] genericParameterTypes = null; - - BcelMethod(BcelObjectType declaringType, Method method) { - super(method.getName().equals("<init>") ? CONSTRUCTOR : (method.getName().equals("<clinit>") ? STATIC_INITIALIZATION - : METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature()); - this.method = method; - sourceContext = declaringType.getResolvedTypeX().getSourceContext(); - bcelObjectType = declaringType; - unpackJavaAttributes(); - unpackAjAttributes(bcelObjectType.getWorld()); - } - - /** - * This constructor expects to be passed the attributes, rather than deserializing them. - */ - BcelMethod(BcelObjectType declaringType, Method method, List<AjAttribute> attributes) { - super(method.getName().equals("<init>") ? CONSTRUCTOR : (method.getName().equals("<clinit>") ? STATIC_INITIALIZATION - : METHOD), declaringType.getResolvedTypeX(), method.getModifiers(), method.getName(), method.getSignature()); - this.method = method; - sourceContext = declaringType.getResolvedTypeX().getSourceContext(); - bcelObjectType = declaringType; - unpackJavaAttributes(); - processAttributes(bcelObjectType.getWorld(), attributes); - } - - // ---- - - private void unpackJavaAttributes() { - ExceptionTable exnTable = method.getExceptionTable(); - checkedExceptions = (exnTable == null) ? UnresolvedType.NONE : UnresolvedType.forNames(exnTable.getExceptionNames()); - } - - @Override - public String[] getParameterNames() { - determineParameterNames(); - return super.getParameterNames(); - } - - public int getLineNumberOfFirstInstruction() { - LineNumberTable lnt = method.getLineNumberTable(); - if (lnt == null) { - return -1; - } - LineNumber[] lns = lnt.getLineNumberTable(); - if (lns == null || lns.length == 0) { - return -1; - } - return lns[0].getLineNumber(); - } - - public void determineParameterNames() { - if ((bitflags & PARAMETER_NAMES_INITIALIZED) != 0) { - return; - } - bitflags |= PARAMETER_NAMES_INITIALIZED; - LocalVariableTable varTable = method.getLocalVariableTable(); - int len = getArity(); - if (varTable == null) { - // do we have an annotation with the argNames value specified... - AnnotationAJ[] annos = getAnnotations(); - if (annos != null && annos.length != 0) { - AnnotationAJ[] axs = getAnnotations(); - for (int i = 0; i < axs.length; i++) { - AnnotationAJ annotationX = axs[i]; - String typename = annotationX.getTypeName(); - if (typename.charAt(0) == PACKAGE_INITIAL_CHAR) { - if (typename.equals("org.aspectj.lang.annotation.Pointcut") - || typename.equals("org.aspectj.lang.annotation.Before") - || typename.equals("org.aspectj.lang.annotation.Around") - || typename.startsWith("org.aspectj.lang.annotation.After")) { - AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); - if (a != null) { - List<NameValuePair> values = a.getValues(); - for (NameValuePair nvPair : values) { - if (nvPair.getNameString().equals("argNames")) { - String argNames = nvPair.getValue().stringifyValue(); - StringTokenizer argNameTokenizer = new StringTokenizer(argNames, " ,"); - List<String> argsList = new ArrayList<String>(); - while (argNameTokenizer.hasMoreTokens()) { - argsList.add(argNameTokenizer.nextToken()); - } - int requiredCount = getParameterTypes().length; - while (argsList.size() < requiredCount) { - argsList.add("arg" + argsList.size()); - } - setParameterNames(argsList.toArray(new String[] {})); - return; - } - } - } - } - } - } - } - setParameterNames(Utility.makeArgNames(len)); - } else { - UnresolvedType[] paramTypes = getParameterTypes(); - String[] paramNames = new String[len]; - int index = Modifier.isStatic(modifiers) ? 0 : 1; - for (int i = 0; i < len; i++) { - LocalVariable lv = varTable.getLocalVariable(index); - if (lv == null) { - paramNames[i] = "arg" + i; - } else { - paramNames[i] = lv.getName(); - } - index += paramTypes[i].getSize(); - } - setParameterNames(paramNames); - } - } - - private void unpackAjAttributes(World world) { - associatedShadowMunger = null; - ResolvedType resolvedDeclaringType = getDeclaringType().resolve(world); - WeaverVersionInfo wvinfo = bcelObjectType.getWeaverVersionAttribute(); - List<AjAttribute> as = Utility.readAjAttributes(resolvedDeclaringType.getClassName(), method.getAttributes(), - resolvedDeclaringType.getSourceContext(), world, wvinfo, new BcelConstantPoolReader(method.getConstantPool())); - processAttributes(world, as); - as = AtAjAttributes.readAj5MethodAttributes(method, this, resolvedDeclaringType, preResolvedPointcut, - resolvedDeclaringType.getSourceContext(), world.getMessageHandler()); - processAttributes(world, as); - } - - private void processAttributes(World world, List<AjAttribute> as) { - for (AjAttribute attr : as) { - if (attr instanceof AjAttribute.MethodDeclarationLineNumberAttribute) { - declarationLineNumber = (AjAttribute.MethodDeclarationLineNumberAttribute) attr; - } else if (attr instanceof AjAttribute.AdviceAttribute) { - associatedShadowMunger = ((AjAttribute.AdviceAttribute) attr).reify(this, world, (ResolvedType) getDeclaringType()); - } else if (attr instanceof AjAttribute.AjSynthetic) { - bitflags |= IS_AJ_SYNTHETIC; - } else if (attr instanceof AjAttribute.EffectiveSignatureAttribute) { - effectiveSignature = (AjAttribute.EffectiveSignatureAttribute) attr; - } else if (attr instanceof AjAttribute.PointcutDeclarationAttribute) { - // this is an @AspectJ annotated advice method, with pointcut pre-resolved by ajc - preResolvedPointcut = ((AjAttribute.PointcutDeclarationAttribute) attr).reify(); - } else { - throw new BCException("weird method attribute " + attr); - } - } - } - - // - // // for testing - if we have this attribute, return it - will return null - // if - // // it doesnt know anything - // public AjAttribute[] getAttributes(String name) { - // List results = new ArrayList(); - // List l = Utility.readAjAttributes(getDeclaringType().getClassName(), - // method.getAttributes(), - // getSourceContext(bcelObjectType.getWorld()), bcelObjectType.getWorld(), - // bcelObjectType.getWeaverVersionAttribute()); - // for (Iterator iter = l.iterator(); iter.hasNext();) { - // AjAttribute element = (AjAttribute) iter.next(); - // if (element.getNameString().equals(name)) - // results.add(element); - // } - // if (results.size() > 0) { - // return (AjAttribute[]) results.toArray(new AjAttribute[] {}); - // } - // return null; - // } - - @Override - public String getAnnotationDefaultValue() { - Attribute[] attrs = method.getAttributes(); - for (int i = 0; i < attrs.length; i++) { - Attribute attribute = attrs[i]; - if (attribute.getName().equals("AnnotationDefault")) { - AnnotationDefault def = (AnnotationDefault) attribute; - return def.getElementValue().stringifyValue(); - } - } - return null; - } - - // for testing - use with the method above - public String[] getAttributeNames(boolean onlyIncludeAjOnes) { - Attribute[] as = method.getAttributes(); - List<String> names = new ArrayList<String>(); - // String[] strs = new String[as.length]; - for (int j = 0; j < as.length; j++) { - if (!onlyIncludeAjOnes || as[j].getName().startsWith(AjAttribute.AttributePrefix)) { - names.add(as[j].getName()); - } - } - return names.toArray(new String[] {}); - } - - @Override - public boolean isAjSynthetic() { - return (bitflags & IS_AJ_SYNTHETIC) != 0; - } - - @Override - public ShadowMunger getAssociatedShadowMunger() { - return associatedShadowMunger; - } - - @Override - public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { - return effectiveSignature; - } - - public boolean hasDeclarationLineNumberInfo() { - return declarationLineNumber != null; - } - - public int getDeclarationLineNumber() { - if (declarationLineNumber != null) { - return declarationLineNumber.getLineNumber(); - } else { - return -1; - } - } - - public int getDeclarationOffset() { - if (declarationLineNumber != null) { - return declarationLineNumber.getOffset(); - } else { - return -1; - } - } - - @Override - public ISourceLocation getSourceLocation() { - ISourceLocation ret = super.getSourceLocation(); - if ((ret == null || ret.getLine() == 0) && hasDeclarationLineNumberInfo()) { - // lets see if we can do better - ISourceContext isc = getSourceContext(); - if (isc != null) { - ret = isc.makeSourceLocation(getDeclarationLineNumber(), getDeclarationOffset()); - } else { - ret = new SourceLocation(null, getDeclarationLineNumber()); - } - } - return ret; - } - - @Override - public MemberKind getKind() { - if (associatedShadowMunger != null) { - return ADVICE; - } else { - return super.getKind(); - } - } - - @Override - public boolean hasAnnotation(UnresolvedType ofType) { - ensureAnnotationsRetrieved(); - for (ResolvedType aType : annotationTypes) { - if (aType.equals(ofType)) { - return true; - } - } - return false; - } - - @Override - public AnnotationAJ[] getAnnotations() { - ensureAnnotationsRetrieved(); - if ((bitflags & HAS_ANNOTATIONS) != 0) { - return annotations; - } else { - return AnnotationAJ.EMPTY_ARRAY; - } - } - - @Override - public ResolvedType[] getAnnotationTypes() { - ensureAnnotationsRetrieved(); - return annotationTypes; - } - - @Override - public AnnotationAJ getAnnotationOfType(UnresolvedType ofType) { - ensureAnnotationsRetrieved(); - if ((bitflags & HAS_ANNOTATIONS) == 0) { - return null; - } - for (int i = 0; i < annotations.length; i++) { - if (annotations[i].getTypeName().equals(ofType.getName())) { - return annotations[i]; - } - } - return null; - } - - @Override - public void addAnnotation(AnnotationAJ annotation) { - ensureAnnotationsRetrieved(); - if ((bitflags & HAS_ANNOTATIONS) == 0) { - annotations = new AnnotationAJ[1]; - annotations[0] = annotation; - annotationTypes = new ResolvedType[1]; - annotationTypes[0] = annotation.getType(); - } else { - // Add it to the set of annotations - int len = annotations.length; - AnnotationAJ[] ret = new AnnotationAJ[len + 1]; - System.arraycopy(annotations, 0, ret, 0, len); - ret[len] = annotation; - annotations = ret; - ResolvedType[] newAnnotationTypes = new ResolvedType[len + 1]; - System.arraycopy(annotationTypes, 0, newAnnotationTypes, 0, len); - newAnnotationTypes[len] = annotation.getType(); - annotationTypes = newAnnotationTypes; - } - bitflags |= HAS_ANNOTATIONS; - } - - public void removeAnnotation(ResolvedType annotationType) { - ensureAnnotationsRetrieved(); - if ((bitflags & HAS_ANNOTATIONS) == 0) { - // nothing to do, why did we get called? - } else { - int len = annotations.length; - if (len == 1) { - bitflags &= ~HAS_ANNOTATIONS; - annotations = null; - annotationTypes = null; - return; - } - AnnotationAJ[] ret = new AnnotationAJ[len - 1]; - int p = 0; - for (AnnotationAJ annotation : annotations) { - if (!annotation.getType().equals(annotationType)) { - ret[p++] = annotation; - } - } - annotations = ret; - - ResolvedType[] newAnnotationTypes = new ResolvedType[len - 1]; - p = 0; - for (AnnotationAJ annotation : annotations) { - if (!annotation.getType().equals(annotationType)) { - newAnnotationTypes[p++] = annotationType; - } - } - annotationTypes = newAnnotationTypes; - } - bitflags |= HAS_ANNOTATIONS; - } - - public static final AnnotationAJ[] NO_PARAMETER_ANNOTATIONS = new AnnotationAJ[] {}; - - public void addParameterAnnotation(int param, AnnotationAJ anno) { - ensureParameterAnnotationsRetrieved(); - if (parameterAnnotations == NO_PARAMETER_ANNOTATIONXS) { - // First time we've added any, so lets set up the array - parameterAnnotations = new AnnotationAJ[getArity()][]; - for (int i = 0; i < getArity(); i++) { - parameterAnnotations[i] = NO_PARAMETER_ANNOTATIONS; - } - } - int existingCount = parameterAnnotations[param].length; - if (existingCount == 0) { - AnnotationAJ[] annoArray = new AnnotationAJ[1]; - annoArray[0] = anno; - parameterAnnotations[param] = annoArray; - } else { - AnnotationAJ[] newAnnoArray = new AnnotationAJ[existingCount + 1]; - System.arraycopy(parameterAnnotations[param], 0, newAnnoArray, 0, existingCount); - newAnnoArray[existingCount] = anno; - parameterAnnotations[param] = newAnnoArray; - } - } - - private void ensureAnnotationsRetrieved() { - if (method == null) { - return; // must be ok, we have evicted it - } - if ((bitflags & HAVE_DETERMINED_ANNOTATIONS) != 0) { - return; - } - bitflags |= HAVE_DETERMINED_ANNOTATIONS; - AnnotationGen annos[] = method.getAnnotations(); - if (annos.length == 0) { - annotationTypes = ResolvedType.NONE; - annotations = AnnotationAJ.EMPTY_ARRAY; - } else { - int annoCount = annos.length; - annotationTypes = new ResolvedType[annoCount]; - annotations = new AnnotationAJ[annoCount]; - for (int i = 0; i < annoCount; i++) { - AnnotationGen annotation = annos[i]; - annotations[i] = new BcelAnnotation(annotation, bcelObjectType.getWorld()); - annotationTypes[i] = annotations[i].getType(); - } - bitflags |= HAS_ANNOTATIONS; - } - } - - private void ensureParameterAnnotationsRetrieved() { - if (method == null) { - return; // must be ok, we have evicted it - } - AnnotationGen[][] pAnns = method.getParameterAnnotations(); - if (parameterAnnotationTypes == null || pAnns.length != parameterAnnotationTypes.length) { - if (pAnns == Method.NO_PARAMETER_ANNOTATIONS) { - parameterAnnotationTypes = BcelMethod.NO_PARAMETER_ANNOTATION_TYPES; - parameterAnnotations = BcelMethod.NO_PARAMETER_ANNOTATIONXS; - } else { - AnnotationGen annos[][] = method.getParameterAnnotations(); - parameterAnnotations = new AnnotationAJ[annos.length][]; - parameterAnnotationTypes = new ResolvedType[annos.length][]; - for (int i = 0; i < annos.length; i++) { - AnnotationGen[] annosOnThisParam = annos[i]; - if (annos[i].length == 0) { - parameterAnnotations[i] = AnnotationAJ.EMPTY_ARRAY; - parameterAnnotationTypes[i] = ResolvedType.NONE; - } else { - parameterAnnotations[i] = new AnnotationAJ[annosOnThisParam.length]; - parameterAnnotationTypes[i] = new ResolvedType[annosOnThisParam.length]; - for (int j = 0; j < annosOnThisParam.length; j++) { - parameterAnnotations[i][j] = new BcelAnnotation(annosOnThisParam[j], bcelObjectType.getWorld()); - parameterAnnotationTypes[i][j] = bcelObjectType.getWorld().resolve( - UnresolvedType.forSignature(annosOnThisParam[j].getTypeSignature())); - } - } - } - } - } - } - - @Override - public AnnotationAJ[][] getParameterAnnotations() { - ensureParameterAnnotationsRetrieved(); - return parameterAnnotations; - } - - @Override - public ResolvedType[][] getParameterAnnotationTypes() { - ensureParameterAnnotationsRetrieved(); - return parameterAnnotationTypes; - } - - /** - * A method can be parameterized if it has one or more generic parameters. A generic parameter (type variable parameter) is - * identified by the prefix "T" - */ - @Override - public boolean canBeParameterized() { - unpackGenericSignature(); - return (bitflags & CAN_BE_PARAMETERIZED) != 0; - } - - @Override - public UnresolvedType[] getGenericParameterTypes() { - unpackGenericSignature(); - return genericParameterTypes; - } - - /** - * Return the parameterized/generic return type or the normal return type if the method is not generic. - */ - @Override - public UnresolvedType getGenericReturnType() { - unpackGenericSignature(); - return genericReturnType; - } - - /** For testing only */ - public Method getMethod() { - return method; - } - - private void unpackGenericSignature() { - if ((bitflags & UNPACKED_GENERIC_SIGNATURE) != 0) { - return; - } - bitflags |= UNPACKED_GENERIC_SIGNATURE; - if (!bcelObjectType.getWorld().isInJava5Mode()) { - genericReturnType = getReturnType(); - genericParameterTypes = getParameterTypes(); - return; - } - String gSig = method.getGenericSignature(); - if (gSig != null) { - GenericSignature.MethodTypeSignature mSig = new GenericSignatureParser().parseAsMethodSignature(gSig);// method - // . - // getGenericSignature - // ()); - if (mSig.formalTypeParameters.length > 0) { - // generic method declaration - bitflags |= CAN_BE_PARAMETERIZED; - } - - typeVariables = new TypeVariable[mSig.formalTypeParameters.length]; - for (int i = 0; i < typeVariables.length; i++) { - GenericSignature.FormalTypeParameter methodFtp = mSig.formalTypeParameters[i]; - try { - typeVariables[i] = BcelGenericSignatureToTypeXConverter.formalTypeParameter2TypeVariable(methodFtp, - mSig.formalTypeParameters, bcelObjectType.getWorld()); - } catch (GenericSignatureFormatException e) { - // this is a development bug, so fail fast with good info - throw new IllegalStateException("While getting the type variables for method " + this.toString() - + " with generic signature " + mSig + " the following error condition was detected: " + e.getMessage()); - } - } - - GenericSignature.FormalTypeParameter[] parentFormals = bcelObjectType.getAllFormals(); - GenericSignature.FormalTypeParameter[] formals = new GenericSignature.FormalTypeParameter[parentFormals.length - + mSig.formalTypeParameters.length]; - // put method formal in front of type formals for overriding in - // lookup - System.arraycopy(mSig.formalTypeParameters, 0, formals, 0, mSig.formalTypeParameters.length); - System.arraycopy(parentFormals, 0, formals, mSig.formalTypeParameters.length, parentFormals.length); - GenericSignature.TypeSignature returnTypeSignature = mSig.returnType; - try { - genericReturnType = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(returnTypeSignature, formals, - bcelObjectType.getWorld()); - } catch (GenericSignatureFormatException e) { - // development bug, fail fast with good info - throw new IllegalStateException("While determing the generic return type of " + this.toString() - + " with generic signature " + gSig + " the following error was detected: " + e.getMessage()); - } - GenericSignature.TypeSignature[] paramTypeSigs = mSig.parameters; - if (paramTypeSigs.length == 0) { - genericParameterTypes = UnresolvedType.NONE; - } else { - genericParameterTypes = new UnresolvedType[paramTypeSigs.length]; - } - for (int i = 0; i < paramTypeSigs.length; i++) { - try { - genericParameterTypes[i] = BcelGenericSignatureToTypeXConverter.typeSignature2TypeX(paramTypeSigs[i], formals, - bcelObjectType.getWorld()); - } catch (GenericSignatureFormatException e) { - // development bug, fail fast with good info - throw new IllegalStateException("While determining the generic parameter types of " + this.toString() - + " with generic signature " + gSig + " the following error was detected: " + e.getMessage()); - } - if (paramTypeSigs[i] instanceof TypeVariableSignature) { - bitflags |= CAN_BE_PARAMETERIZED; - } - } - } else { - genericReturnType = getReturnType(); - genericParameterTypes = getParameterTypes(); - } - } - - @Override - public void evictWeavingState() { - if (method != null) { - unpackGenericSignature(); - unpackJavaAttributes(); - ensureAnnotationsRetrieved(); - ensureParameterAnnotationsRetrieved(); - determineParameterNames(); - // this.sourceContext = SourceContextImpl.UNKNOWN_SOURCE_CONTEXT; - method = null; - } - } - - @Override - public boolean isSynthetic() { - if ((bitflags & KNOW_IF_SYNTHETIC) == 0) { - workOutIfSynthetic(); - } - return (bitflags & IS_SYNTHETIC) != 0;// isSynthetic; - } - - // Pre Java5 synthetic is an attribute 'Synthetic', post Java5 it is a - // modifier (4096 or 0x1000) - private void workOutIfSynthetic() { - if ((bitflags & KNOW_IF_SYNTHETIC) != 0) { - return; - } - bitflags |= KNOW_IF_SYNTHETIC; - JavaClass jc = bcelObjectType.getJavaClass(); - bitflags &= IS_SYNTHETIC_INVERSE; // unset the bit - if (jc == null) { - return; // what the hell has gone wrong? - } - if (jc.getMajor() < 49/* Java5 */) { - // synthetic is an attribute - String[] synthetics = getAttributeNames(false); - if (synthetics != null) { - for (int i = 0; i < synthetics.length; i++) { - if (synthetics[i].equals("Synthetic")) { - bitflags |= IS_SYNTHETIC; - break; - } - } - } - } else { - // synthetic is a modifier (4096) - if ((modifiers & 4096) != 0) { - bitflags |= IS_SYNTHETIC; - } - } - } - - /** - * Returns whether or not the given object is equivalent to the current one. Returns true if - * getMethod().getCode().getCodeString() are equal. Allows for different line number tables. - */ - // bug 154054: is similar to equals(Object) however - // doesn't require implementing equals in Method and Code - // which proved expensive. Currently used within - // CrosscuttingMembers.replaceWith() to decide if we need - // to do a full build - @Override - public boolean isEquivalentTo(Object other) { - if (!(other instanceof BcelMethod)) { - return false; - } - BcelMethod o = (BcelMethod) other; - return getMethod().getCode().getCodeString().equals(o.getMethod().getCode().getCodeString()); - } - - /** - * Return true if the method represents the default constructor. Hard to determine this from bytecode, but the existence of the - * MethodDeclarationLineNumber attribute should tell us. - * - * @return true if this BcelMethod represents the default constructor - */ - @Override - public boolean isDefaultConstructor() { - boolean mightBe = !hasDeclarationLineNumberInfo() && name.equals("<init>") && parameterTypes.length == 0; - if (mightBe) { - // TODO would be nice to do a check to see if the file was compiled with javac or ajc? - // maybe by checking the constant pool for aspectj strings? - return true; - } else { - return false; - } - } - -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java deleted file mode 100644 index 710eb6dc7..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java +++ /dev/null @@ -1,1023 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 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 - * RonBodkin/AndyClement optimizations for memory consumption/speed - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.PrintStream; -import java.lang.ref.WeakReference; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.AttributeUtils; -import org.aspectj.apache.bcel.classfile.ConstantClass; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.EnclosingMethod; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.classfile.InnerClass; -import org.aspectj.apache.bcel.classfile.InnerClasses; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.Signature; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.EnumElementValue; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.asm.AsmManager; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.util.GenericSignature; -import org.aspectj.util.GenericSignature.FormalTypeParameter; -import org.aspectj.weaver.AbstractReferenceTypeDelegate; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.AnnotationTargetKind; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.BindingScope; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedPointcutDefinition; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.SourceContextImpl; -import org.aspectj.weaver.TypeVariable; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverStateInfo; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.BcelGenericSignatureToTypeXConverter.GenericSignatureFormatException; -import org.aspectj.weaver.patterns.Declare; -import org.aspectj.weaver.patterns.DeclareErrorOrWarning; -import org.aspectj.weaver.patterns.DeclarePrecedence; -import org.aspectj.weaver.patterns.FormalBinding; -import org.aspectj.weaver.patterns.IScope; -import org.aspectj.weaver.patterns.PerClause; - -public class BcelObjectType extends AbstractReferenceTypeDelegate { - public JavaClass javaClass; - private boolean artificial; // Was the BcelObject built from an artificial set of bytes? Or from the real ondisk stuff? - private LazyClassGen lazyClassGen = null; // set lazily if it's an aspect - - private int modifiers; - private String className; - - private String superclassSignature; - private String superclassName; - private String[] interfaceSignatures; - - private ResolvedMember[] fields = null; - private ResolvedMember[] methods = null; - private ResolvedType[] annotationTypes = null; - private AnnotationAJ[] annotations = null; - private TypeVariable[] typeVars = null; - private String retentionPolicy; - private AnnotationTargetKind[] annotationTargetKinds; - - // Aspect related stuff (pointcuts *could* be in a java class) - private AjAttribute.WeaverVersionInfo wvInfo = AjAttribute.WeaverVersionInfo.UNKNOWN; - private ResolvedPointcutDefinition[] pointcuts = null; - private ResolvedMember[] privilegedAccess = null; - private WeaverStateInfo weaverState = null; - private PerClause perClause = null; - private List<ConcreteTypeMunger> typeMungers = Collections.emptyList(); - private List<Declare> declares = Collections.emptyList(); - - private GenericSignature.FormalTypeParameter[] formalsForResolution = null; - private String declaredSignature = null; - - private boolean hasBeenWoven = false; - private boolean isGenericType = false; - private boolean isInterface; - private boolean isEnum; - private boolean isAnnotation; - private boolean isAnonymous; - private boolean isNested; - private boolean isObject = false; // set upon construction - private boolean isAnnotationStyleAspect = false;// set upon construction - private boolean isCodeStyleAspect = false; // not redundant with field - // above! - - private WeakReference<ResolvedType> superTypeReference = new WeakReference<ResolvedType>(null); - private WeakReference<ResolvedType[]> superInterfaceReferences = new WeakReference<ResolvedType[]>(null); - - private int bitflag = 0x0000; - - // discovery bits - private static final int DISCOVERED_ANNOTATION_RETENTION_POLICY = 0x0001; - private static final int UNPACKED_GENERIC_SIGNATURE = 0x0002; - private static final int UNPACKED_AJATTRIBUTES = 0x0004; // see note(1) - // below - private static final int DISCOVERED_ANNOTATION_TARGET_KINDS = 0x0008; - private static final int DISCOVERED_DECLARED_SIGNATURE = 0x0010; - private static final int DISCOVERED_WHETHER_ANNOTATION_STYLE = 0x0020; - - private static final int ANNOTATION_UNPACK_IN_PROGRESS = 0x0100; - - private static final String[] NO_INTERFACE_SIGS = new String[] {}; - - /* - * Notes: note(1): in some cases (perclause inheritance) we encounter unpacked state when calling getPerClause - * - * note(2): A BcelObjectType is 'damaged' if it has been modified from what was original constructed from the bytecode. This - * currently happens if the parents are modified or an annotation is added - ideally BcelObjectType should be immutable but - * that's a bigger piece of work. XXX - */ - - BcelObjectType(ReferenceType resolvedTypeX, JavaClass javaClass, boolean artificial, boolean exposedToWeaver) { - super(resolvedTypeX, exposedToWeaver); - this.javaClass = javaClass; - this.artificial = artificial; - initializeFromJavaclass(); - - // ATAJ: set the delegate right now for @AJ pointcut, else it is done - // too late to lookup - // @AJ pc refs annotation in class hierarchy - resolvedTypeX.setDelegate(this); - - ISourceContext sourceContext = resolvedTypeX.getSourceContext(); - if (sourceContext == SourceContextImpl.UNKNOWN_SOURCE_CONTEXT) { - sourceContext = new SourceContextImpl(this); - setSourceContext(sourceContext); - } - - // this should only ever be java.lang.Object which is - // the only class in Java-1.4 with no superclasses - isObject = (javaClass.getSuperclassNameIndex() == 0); - ensureAspectJAttributesUnpacked(); - // if (sourceContext instanceof SourceContextImpl) { - // ((SourceContextImpl)sourceContext).setSourceFileName(javaClass. - // getSourceFileName()); - // } - setSourcefilename(javaClass.getSourceFileName()); - } - - // repeat initialization - public void setJavaClass(JavaClass newclass, boolean artificial) { - this.javaClass = newclass; - this.artificial = artificial; - resetState(); - initializeFromJavaclass(); - } - - @Override - public boolean isCacheable() { - return true; - } - - private void initializeFromJavaclass() { - isInterface = javaClass.isInterface(); - isEnum = javaClass.isEnum(); - isAnnotation = javaClass.isAnnotation(); - isAnonymous = javaClass.isAnonymous(); - isNested = javaClass.isNested(); - modifiers = javaClass.getModifiers(); - superclassName = javaClass.getSuperclassName(); - className = javaClass.getClassName(); - cachedGenericClassTypeSignature = null; - } - - // --- getters - - // Java related - public boolean isInterface() { - return isInterface; - } - - public boolean isEnum() { - return isEnum; - } - - public boolean isAnnotation() { - return isAnnotation; - } - - public boolean isAnonymous() { - return isAnonymous; - } - - public boolean isNested() { - return isNested; - } - - public int getModifiers() { - return modifiers; - } - - /** - * Must take into account generic signature - */ - public ResolvedType getSuperclass() { - if (isObject) { - return null; - } - ResolvedType supertype = superTypeReference.get(); - if (supertype == null) { - ensureGenericSignatureUnpacked(); - if (superclassSignature == null) { - if (superclassName == null) { - superclassName = javaClass.getSuperclassName(); - } - superclassSignature = getResolvedTypeX().getWorld().resolve(UnresolvedType.forName(superclassName)).getSignature(); - } - World world = getResolvedTypeX().getWorld(); - supertype = world.resolve(UnresolvedType.forSignature(superclassSignature)); - superTypeReference = new WeakReference<ResolvedType>(supertype); - } - return supertype; - } - - public World getWorld() { - return getResolvedTypeX().getWorld(); - } - - /** - * Retrieves the declared interfaces - this allows for the generic signature on a type. If specified then the generic signature - * is used to work out the types - this gets around the results of erasure when the class was originally compiled. - */ - public ResolvedType[] getDeclaredInterfaces() { - - ResolvedType[] cachedInterfaceTypes = superInterfaceReferences.get(); - if (cachedInterfaceTypes == null) { - ensureGenericSignatureUnpacked(); - ResolvedType[] interfaceTypes = null; - if (interfaceSignatures == null) { - String[] names = javaClass.getInterfaceNames(); - if (names.length == 0) { - interfaceSignatures = NO_INTERFACE_SIGS; - interfaceTypes = ResolvedType.NONE; - } else { - interfaceSignatures = new String[names.length]; - interfaceTypes = new ResolvedType[names.length]; - for (int i = 0, len = names.length; i < len; i++) { - interfaceTypes[i] = getResolvedTypeX().getWorld().resolve(UnresolvedType.forName(names[i])); - interfaceSignatures[i] = interfaceTypes[i].getSignature(); - } - } - } else { - interfaceTypes = new ResolvedType[interfaceSignatures.length]; - for (int i = 0, len = interfaceSignatures.length; i < len; i++) { - interfaceTypes[i] = getResolvedTypeX().getWorld().resolve(UnresolvedType.forSignature(interfaceSignatures[i])); - } - } - superInterfaceReferences = new WeakReference<ResolvedType[]>(interfaceTypes); - return interfaceTypes; - } else { - return cachedInterfaceTypes; - } - } - - public ResolvedMember[] getDeclaredMethods() { - ensureGenericSignatureUnpacked(); - if (methods == null) { - Method[] ms = javaClass.getMethods(); - ResolvedMember[] newMethods = new ResolvedMember[ms.length]; - for (int i = ms.length - 1; i >= 0; i--) { - newMethods[i] = new BcelMethod(this, ms[i]); - } - methods = newMethods; - } - return methods; - } - - public ResolvedMember[] getDeclaredFields() { - ensureGenericSignatureUnpacked(); - if (fields == null) { - Field[] fs = javaClass.getFields(); - ResolvedMember[] newfields = new ResolvedMember[fs.length]; - for (int i = 0, len = fs.length; i < len; i++) { - newfields[i] = new BcelField(this, fs[i]); - } - fields = newfields; - } - return fields; - } - - public TypeVariable[] getTypeVariables() { - if (!isGeneric()) { - return TypeVariable.NONE; - } - - if (typeVars == null) { - GenericSignature.ClassSignature classSig = getGenericClassTypeSignature(); - typeVars = new TypeVariable[classSig.formalTypeParameters.length]; - for (int i = 0; i < typeVars.length; i++) { - GenericSignature.FormalTypeParameter ftp = classSig.formalTypeParameters[i]; - try { - typeVars[i] = BcelGenericSignatureToTypeXConverter.formalTypeParameter2TypeVariable(ftp, - classSig.formalTypeParameters, getResolvedTypeX().getWorld()); - } catch (GenericSignatureFormatException e) { - // this is a development bug, so fail fast with good info - throw new IllegalStateException("While getting the type variables for type " + this.toString() - + " with generic signature " + classSig + " the following error condition was detected: " - + e.getMessage()); - } - } - } - return typeVars; - } - - public Collection<ConcreteTypeMunger> getTypeMungers() { - return typeMungers; - } - - public Collection<Declare> getDeclares() { - return declares; - } - - public Collection<ResolvedMember> getPrivilegedAccesses() { - if (privilegedAccess == null) { - return Collections.emptyList(); - } - return Arrays.asList(privilegedAccess); - } - - public ResolvedMember[] getDeclaredPointcuts() { - return pointcuts; - } - - public boolean isAspect() { - return perClause != null; - } - - /** - * Check if the type is an @AJ aspect (no matter if used from an LTW point of view). Such aspects are annotated with @Aspect - * - * @return true for @AJ aspect - */ - public boolean isAnnotationStyleAspect() { - if ((bitflag & DISCOVERED_WHETHER_ANNOTATION_STYLE) == 0) { - bitflag |= DISCOVERED_WHETHER_ANNOTATION_STYLE; - isAnnotationStyleAspect = !isCodeStyleAspect && hasAnnotation(AjcMemberMaker.ASPECT_ANNOTATION); - } - return isAnnotationStyleAspect; - } - - /** - * Process any org.aspectj.weaver attributes stored against the class. - */ - private void ensureAspectJAttributesUnpacked() { - if ((bitflag & UNPACKED_AJATTRIBUTES) != 0) { - return; - } - bitflag |= UNPACKED_AJATTRIBUTES; - IMessageHandler msgHandler = getResolvedTypeX().getWorld().getMessageHandler(); - // Pass in empty list that can store things for readAj5 to process - List<AjAttribute> l = null; - try { - l = Utility.readAjAttributes(className, javaClass.getAttributes(), getResolvedTypeX().getSourceContext(), - getResolvedTypeX().getWorld(), AjAttribute.WeaverVersionInfo.UNKNOWN, - new BcelConstantPoolReader(javaClass.getConstantPool())); - } catch (RuntimeException re) { - throw new RuntimeException("Problem processing attributes in " + javaClass.getFileName(), re); - } - List<ResolvedPointcutDefinition> pointcuts = new ArrayList<ResolvedPointcutDefinition>(); - typeMungers = new ArrayList<ConcreteTypeMunger>(); - declares = new ArrayList<Declare>(); - processAttributes(l, pointcuts, false); - ReferenceType type = getResolvedTypeX(); - AsmManager asmManager = ((BcelWorld) type.getWorld()).getModelAsAsmManager(); - l = AtAjAttributes.readAj5ClassAttributes(asmManager, javaClass, type, type.getSourceContext(), msgHandler, - isCodeStyleAspect); - AjAttribute.Aspect deferredAspectAttribute = processAttributes(l, pointcuts, true); - - if (pointcuts.size() == 0) { - this.pointcuts = ResolvedPointcutDefinition.NO_POINTCUTS; - } else { - this.pointcuts = pointcuts.toArray(new ResolvedPointcutDefinition[pointcuts.size()]); - } - - resolveAnnotationDeclares(l); - - if (deferredAspectAttribute != null) { - // we can finally process the aspect and its associated perclause... - perClause = deferredAspectAttribute.reifyFromAtAspectJ(this.getResolvedTypeX()); - } - if (isAspect() && !Modifier.isAbstract(getModifiers()) && isGeneric()) { - msgHandler.handleMessage(MessageUtil.error("The generic aspect '" + getResolvedTypeX().getName() - + "' must be declared abstract", getResolvedTypeX().getSourceLocation())); - } - - } - - private AjAttribute.Aspect processAttributes(List<AjAttribute> attributeList, List<ResolvedPointcutDefinition> pointcuts, - boolean fromAnnotations) { - AjAttribute.Aspect deferredAspectAttribute = null; - for (AjAttribute a : attributeList) { - if (a instanceof AjAttribute.Aspect) { - if (fromAnnotations) { - deferredAspectAttribute = (AjAttribute.Aspect) a; - } else { - perClause = ((AjAttribute.Aspect) a).reify(this.getResolvedTypeX()); - isCodeStyleAspect = true; - } - } else if (a instanceof AjAttribute.PointcutDeclarationAttribute) { - pointcuts.add(((AjAttribute.PointcutDeclarationAttribute) a).reify()); - } else if (a instanceof AjAttribute.WeaverState) { - weaverState = ((AjAttribute.WeaverState) a).reify(); - } else if (a instanceof AjAttribute.TypeMunger) { - typeMungers.add(((AjAttribute.TypeMunger) a).reify(getResolvedTypeX().getWorld(), getResolvedTypeX())); - } else if (a instanceof AjAttribute.DeclareAttribute) { - declares.add(((AjAttribute.DeclareAttribute) a).getDeclare()); - } else if (a instanceof AjAttribute.PrivilegedAttribute) { - AjAttribute.PrivilegedAttribute privAttribute = (AjAttribute.PrivilegedAttribute) a; - privilegedAccess = privAttribute.getAccessedMembers(); - } else if (a instanceof AjAttribute.SourceContextAttribute) { - if (getResolvedTypeX().getSourceContext() instanceof SourceContextImpl) { - AjAttribute.SourceContextAttribute sca = (AjAttribute.SourceContextAttribute) a; - ((SourceContextImpl) getResolvedTypeX().getSourceContext()).configureFromAttribute(sca.getSourceFileName(), - sca.getLineBreaks()); - - setSourcefilename(sca.getSourceFileName()); - } - } else if (a instanceof AjAttribute.WeaverVersionInfo) { - // Set the weaver version used to build this type - wvInfo = (AjAttribute.WeaverVersionInfo) a; - } else { - throw new BCException("bad attribute " + a); - } - } - return deferredAspectAttribute; - } - - /** - * Extra processing step needed because declares that come from annotations are not pre-resolved. We can't do the resolution - * until *after* the pointcuts have been resolved. - */ - private void resolveAnnotationDeclares(List<AjAttribute> attributeList) { - FormalBinding[] bindings = new org.aspectj.weaver.patterns.FormalBinding[0]; - IScope bindingScope = new BindingScope(getResolvedTypeX(), getResolvedTypeX().getSourceContext(), bindings); - for (Iterator<AjAttribute> iter = attributeList.iterator(); iter.hasNext();) { - AjAttribute a = iter.next(); - if (a instanceof AjAttribute.DeclareAttribute) { - Declare decl = (((AjAttribute.DeclareAttribute) a).getDeclare()); - if (decl instanceof DeclareErrorOrWarning) { - decl.resolve(bindingScope); - } else if (decl instanceof DeclarePrecedence) { - ((DeclarePrecedence) decl).setScopeForResolution(bindingScope); - } - } - } - } - - public PerClause getPerClause() { - ensureAspectJAttributesUnpacked(); - return perClause; - } - - public JavaClass getJavaClass() { - return javaClass; - } - - /** - * @return true if built from bytes obtained from somewhere. False if built from bytes retrieved from disk. - */ - public boolean isArtificial() { - return artificial; - } - - public void resetState() { - if (javaClass == null) { - // we might store the classname and allow reloading? - // At this point we are relying on the world to not evict if it - // might want to reweave multiple times - throw new BCException("can't weave evicted type"); - } - - bitflag = 0x0000; - - this.annotationTypes = null; - this.annotations = null; - this.interfaceSignatures = null; - this.superclassSignature = null; - this.superclassName = null; - this.fields = null; - this.methods = null; - this.pointcuts = null; - this.perClause = null; - this.weaverState = null; - this.lazyClassGen = null; - hasBeenWoven = false; - - isObject = (javaClass.getSuperclassNameIndex() == 0); - isAnnotationStyleAspect = false; - ensureAspectJAttributesUnpacked(); - } - - public void finishedWith() { - // memory usage experiments.... - // this.interfaces = null; - // this.superClass = null; - // this.fields = null; - // this.methods = null; - // this.pointcuts = null; - // this.perClause = null; - // this.weaverState = null; - // this.lazyClassGen = null; - // this next line frees up memory, but need to understand incremental - // implications - // before leaving it in. - // getResolvedTypeX().setSourceContext(null); - } - - public WeaverStateInfo getWeaverState() { - return weaverState; - } - - void setWeaverState(WeaverStateInfo weaverState) { - this.weaverState = weaverState; - } - - public void printWackyStuff(PrintStream out) { - if (typeMungers.size() > 0) { - out.println(" TypeMungers: " + typeMungers); - } - if (declares.size() > 0) { - out.println(" declares: " + declares); - } - } - - /** - * Return the lazyClassGen associated with this type. For aspect types, this value will be cached, since it is used to inline - * advice. For non-aspect types, this lazyClassGen is always newly constructed. - */ - public LazyClassGen getLazyClassGen() { - LazyClassGen ret = lazyClassGen; - if (ret == null) { - // System.err.println("creating lazy class gen for: " + this); - ret = new LazyClassGen(this); - // ret.print(System.err); - // System.err.println("made LCG from : " + - // this.getJavaClass().getSuperclassName ); - if (isAspect()) { - lazyClassGen = ret; - } - } - return ret; - } - - public boolean isSynthetic() { - return getResolvedTypeX().isSynthetic(); - } - - public AjAttribute.WeaverVersionInfo getWeaverVersionAttribute() { - return wvInfo; - } - - // -- annotation related - - public ResolvedType[] getAnnotationTypes() { - ensureAnnotationsUnpacked(); - return annotationTypes; - } - - public AnnotationAJ[] getAnnotations() { - ensureAnnotationsUnpacked(); - return annotations; - } - - public boolean hasAnnotations() { - ensureAnnotationsUnpacked(); - return annotations.length != 0; - } - - public boolean hasAnnotation(UnresolvedType ofType) { - // Due to re-entrancy we may be in the middle of unpacking the annotations already... in which case use this slow - // alternative until the stack unwinds itself - if (isUnpackingAnnotations()) { - AnnotationGen annos[] = javaClass.getAnnotations(); - if (annos == null || annos.length == 0) { - return false; - } else { - String lookingForSignature = ofType.getSignature(); - for (int a = 0; a < annos.length; a++) { - AnnotationGen annotation = annos[a]; - if (lookingForSignature.equals(annotation.getTypeSignature())) { - return true; - } - } - } - return false; - } - ensureAnnotationsUnpacked(); - for (int i = 0, max = annotationTypes.length; i < max; i++) { - UnresolvedType ax = annotationTypes[i]; - if (ax == null) { - throw new RuntimeException("Annotation entry " + i + " on type " + this.getResolvedTypeX().getName() + " is null!"); - } - if (ax.equals(ofType)) { - return true; - } - } - return false; - } - - public boolean isAnnotationWithRuntimeRetention() { - return (getRetentionPolicy() == null ? false : getRetentionPolicy().equals("RUNTIME")); - } - - public String getRetentionPolicy() { - if ((bitflag & DISCOVERED_ANNOTATION_RETENTION_POLICY) == 0) { - bitflag |= DISCOVERED_ANNOTATION_RETENTION_POLICY; - retentionPolicy = null; // null means we have no idea - if (isAnnotation()) { - ensureAnnotationsUnpacked(); - for (int i = annotations.length - 1; i >= 0; i--) { - AnnotationAJ ax = annotations[i]; - if (ax.getTypeName().equals(UnresolvedType.AT_RETENTION.getName())) { - List<NameValuePair> values = ((BcelAnnotation) ax).getBcelAnnotation().getValues(); - for (Iterator<NameValuePair> it = values.iterator(); it.hasNext();) { - NameValuePair element = it.next(); - EnumElementValue v = (EnumElementValue) element.getValue(); - retentionPolicy = v.getEnumValueString(); - return retentionPolicy; - } - } - } - } - } - return retentionPolicy; - } - - public boolean canAnnotationTargetType() { - AnnotationTargetKind[] targetKinds = getAnnotationTargetKinds(); - if (targetKinds == null) { - return true; - } - for (int i = 0; i < targetKinds.length; i++) { - if (targetKinds[i].equals(AnnotationTargetKind.TYPE)) { - return true; - } - } - return false; - } - - public AnnotationTargetKind[] getAnnotationTargetKinds() { - if ((bitflag & DISCOVERED_ANNOTATION_TARGET_KINDS) != 0) { - return annotationTargetKinds; - } - bitflag |= DISCOVERED_ANNOTATION_TARGET_KINDS; - annotationTargetKinds = null; // null means we have no idea or the - // @Target annotation hasn't been used - List<AnnotationTargetKind> targetKinds = new ArrayList<AnnotationTargetKind>(); - if (isAnnotation()) { - AnnotationAJ[] annotationsOnThisType = getAnnotations(); - for (int i = 0; i < annotationsOnThisType.length; i++) { - AnnotationAJ a = annotationsOnThisType[i]; - if (a.getTypeName().equals(UnresolvedType.AT_TARGET.getName())) { - Set<String> targets = a.getTargets(); - if (targets != null) { - for (String targetKind : targets) { - if (targetKind.equals("ANNOTATION_TYPE")) { - targetKinds.add(AnnotationTargetKind.ANNOTATION_TYPE); - } else if (targetKind.equals("CONSTRUCTOR")) { - targetKinds.add(AnnotationTargetKind.CONSTRUCTOR); - } else if (targetKind.equals("FIELD")) { - targetKinds.add(AnnotationTargetKind.FIELD); - } else if (targetKind.equals("LOCAL_VARIABLE")) { - targetKinds.add(AnnotationTargetKind.LOCAL_VARIABLE); - } else if (targetKind.equals("METHOD")) { - targetKinds.add(AnnotationTargetKind.METHOD); - } else if (targetKind.equals("PACKAGE")) { - targetKinds.add(AnnotationTargetKind.PACKAGE); - } else if (targetKind.equals("PARAMETER")) { - targetKinds.add(AnnotationTargetKind.PARAMETER); - } else if (targetKind.equals("TYPE")) { - targetKinds.add(AnnotationTargetKind.TYPE); - } - } - } - } - } - if (!targetKinds.isEmpty()) { - annotationTargetKinds = new AnnotationTargetKind[targetKinds.size()]; - return targetKinds.toArray(annotationTargetKinds); - } - } - return annotationTargetKinds; - } - - // --- unpacking methods - - private boolean isUnpackingAnnotations() { - return (bitflag & ANNOTATION_UNPACK_IN_PROGRESS) != 0; - } - - private void ensureAnnotationsUnpacked() { - if (isUnpackingAnnotations()) { - throw new BCException("Re-entered weaver instance whilst unpacking annotations on " + this.className); - } - if (annotationTypes == null) { - try { - bitflag |= ANNOTATION_UNPACK_IN_PROGRESS; - AnnotationGen annos[] = javaClass.getAnnotations(); - if (annos == null || annos.length == 0) { - annotationTypes = ResolvedType.NONE; - annotations = AnnotationAJ.EMPTY_ARRAY; - } else { - World w = getResolvedTypeX().getWorld(); - annotationTypes = new ResolvedType[annos.length]; - annotations = new AnnotationAJ[annos.length]; - for (int i = 0; i < annos.length; i++) { - AnnotationGen annotation = annos[i]; - String typeSignature = annotation.getTypeSignature(); - ResolvedType rType = w.resolve(UnresolvedType.forSignature(typeSignature)); - if (rType == null) { - throw new RuntimeException("Whilst unpacking annotations on '" + getResolvedTypeX().getName() - + "', failed to resolve type '" + typeSignature + "'"); - } - annotationTypes[i] = rType; - annotations[i] = new BcelAnnotation(annotation, rType); - } - } - } finally { - bitflag &= ~ANNOTATION_UNPACK_IN_PROGRESS; - } - } - } - - // --- - - public String getDeclaredGenericSignature() { - ensureGenericInfoProcessed(); - return declaredSignature; - } - - private void ensureGenericSignatureUnpacked() { - if ((bitflag & UNPACKED_GENERIC_SIGNATURE) != 0) { - return; - } - bitflag |= UNPACKED_GENERIC_SIGNATURE; - if (!getResolvedTypeX().getWorld().isInJava5Mode()) { - return; - } - GenericSignature.ClassSignature cSig = getGenericClassTypeSignature(); - if (cSig != null) { - formalsForResolution = cSig.formalTypeParameters; - if (isNested()) { - // we have to find any type variables from the outer type before - // proceeding with resolution. - GenericSignature.FormalTypeParameter[] extraFormals = getFormalTypeParametersFromOuterClass(); - if (extraFormals.length > 0) { - List<FormalTypeParameter> allFormals = new ArrayList<FormalTypeParameter>(); - for (int i = 0; i < formalsForResolution.length; i++) { - allFormals.add(formalsForResolution[i]); - } - for (int i = 0; i < extraFormals.length; i++) { - allFormals.add(extraFormals[i]); - } - formalsForResolution = new GenericSignature.FormalTypeParameter[allFormals.size()]; - allFormals.toArray(formalsForResolution); - } - } - GenericSignature.ClassTypeSignature superSig = cSig.superclassSignature; - try { - // this.superClass = - // BcelGenericSignatureToTypeXConverter.classTypeSignature2TypeX( - // superSig, formalsForResolution, - // getResolvedTypeX().getWorld()); - - ResolvedType rt = BcelGenericSignatureToTypeXConverter.classTypeSignature2TypeX(superSig, formalsForResolution, - getResolvedTypeX().getWorld()); - this.superclassSignature = rt.getSignature(); - this.superclassName = rt.getName(); - - } catch (GenericSignatureFormatException e) { - // development bug, fail fast with good info - throw new IllegalStateException("While determining the generic superclass of " + this.className - + " with generic signature " + getDeclaredGenericSignature() + " the following error was detected: " - + e.getMessage()); - } - // this.interfaces = new - // ResolvedType[cSig.superInterfaceSignatures.length]; - if (cSig.superInterfaceSignatures.length == 0) { - this.interfaceSignatures = NO_INTERFACE_SIGS; - } else { - this.interfaceSignatures = new String[cSig.superInterfaceSignatures.length]; - for (int i = 0; i < cSig.superInterfaceSignatures.length; i++) { - try { - // this.interfaces[i] = - // BcelGenericSignatureToTypeXConverter. - // classTypeSignature2TypeX( - // cSig.superInterfaceSignatures[i], - // formalsForResolution, - // getResolvedTypeX().getWorld()); - this.interfaceSignatures[i] = BcelGenericSignatureToTypeXConverter.classTypeSignature2TypeX( - cSig.superInterfaceSignatures[i], formalsForResolution, getResolvedTypeX().getWorld()) - .getSignature(); - } catch (GenericSignatureFormatException e) { - // development bug, fail fast with good info - throw new IllegalStateException("While determing the generic superinterfaces of " + this.className - + " with generic signature " + getDeclaredGenericSignature() - + " the following error was detected: " + e.getMessage()); - } - } - } - } - if (isGeneric()) { - // update resolved typex to point at generic type not raw type. - ReferenceType genericType = (ReferenceType) this.resolvedTypeX.getGenericType(); - // genericType.setSourceContext(this.resolvedTypeX.getSourceContext()); - // Can be null if unpacking whilst building the bcel delegate (in call hierarchy from BcelWorld.addSourceObjectType() - // line 453) - see 317139 - if (genericType != null) { - genericType.setStartPos(this.resolvedTypeX.getStartPos()); - this.resolvedTypeX = genericType; - } - } - } - - public GenericSignature.FormalTypeParameter[] getAllFormals() { - ensureGenericSignatureUnpacked(); - if (formalsForResolution == null) { - return new GenericSignature.FormalTypeParameter[0]; - } else { - return formalsForResolution; - } - } - - public ResolvedType getOuterClass() { - if (!isNested()) { - throw new IllegalStateException("Can't get the outer class of non-nested type: " + className); - } - - // try finding outer class name from InnerClasses attribute assigned to this class - for (Attribute attr : javaClass.getAttributes()) { - if (attr instanceof InnerClasses) { - // search for InnerClass entry that has current class as inner and some other class as outer - InnerClass[] innerClss = ((InnerClasses) attr).getInnerClasses(); - ConstantPool cpool = javaClass.getConstantPool(); - for (InnerClass innerCls : innerClss) { - - // skip entries that miss any necessary component, 0 index means "undefined", from JVM Spec 2nd ed. par. 4.7.5 - if (innerCls.getInnerClassIndex() == 0 || innerCls.getOuterClassIndex() == 0) { - continue; - } - - // resolve inner class name, check if it matches current class name - ConstantClass innerClsInfo = (ConstantClass) cpool.getConstant(innerCls.getInnerClassIndex()); - - // class names in constant pool use '/' instead of '.', from JVM Spec 2nd ed. par. 4.2 - String innerClsName = cpool.getConstantUtf8(innerClsInfo.getNameIndex()).getValue().replace('/', '.'); - - if (innerClsName.compareTo(className) == 0) { - // resolve outer class name - ConstantClass outerClsInfo = (ConstantClass) cpool.getConstant(innerCls.getOuterClassIndex()); - - // class names in constant pool use '/' instead of '.', from JVM Spec 2nd ed. par. 4.2 - String outerClsName = cpool.getConstantUtf8(outerClsInfo.getNameIndex()).getValue().replace('/', '.'); - - UnresolvedType outer = UnresolvedType.forName(outerClsName); - return outer.resolve(getResolvedTypeX().getWorld()); - } - } - } - } - - for (Attribute attr : javaClass.getAttributes()) { // bug339300 - ConstantPool cpool = javaClass.getConstantPool(); - if (attr instanceof EnclosingMethod) { - EnclosingMethod enclosingMethodAttribute = (EnclosingMethod) attr; - if (enclosingMethodAttribute.getEnclosingClassIndex() != 0) { - ConstantClass outerClassInfo = enclosingMethodAttribute.getEnclosingClass(); - String outerClassName = cpool.getConstantUtf8(outerClassInfo.getNameIndex()).getValue().replace('/', '.'); - UnresolvedType outer = UnresolvedType.forName(outerClassName); - return outer.resolve(getResolvedTypeX().getWorld()); - } - } - } - - // try finding outer class name by assuming standard class name mangling convention of javac for this class - int lastDollar = className.lastIndexOf('$'); - if (lastDollar == -1) { - // Is this class damaged/obfuscated? Why did we think it was nested but couldn't find the parent using - // the attributes above. For now just ignore it... I wonder when ignoring this will come back to bite! - return null; - } - String superClassName = className.substring(0, lastDollar); - UnresolvedType outer = UnresolvedType.forName(superClassName); - return outer.resolve(getResolvedTypeX().getWorld()); - } - - private void ensureGenericInfoProcessed() { - if ((bitflag & DISCOVERED_DECLARED_SIGNATURE) != 0) { - return; - } - bitflag |= DISCOVERED_DECLARED_SIGNATURE; - Signature sigAttr = AttributeUtils.getSignatureAttribute(javaClass.getAttributes()); - declaredSignature = (sigAttr == null ? null : sigAttr.getSignature()); - if (declaredSignature != null) { - isGenericType = (declaredSignature.charAt(0) == '<'); - } - } - - public boolean isGeneric() { - ensureGenericInfoProcessed(); - return isGenericType; - } - - @Override - public String toString() { - return (javaClass == null ? "BcelObjectType" : "BcelObjectTypeFor:" + className); - } - - // --- state management - - public void evictWeavingState() { - // Can't chuck all this away - if (getResolvedTypeX().getWorld().couldIncrementalCompileFollow()) { - return; - } - - if (javaClass != null) { - // Force retrieval of any lazy information - ensureAnnotationsUnpacked(); - ensureGenericInfoProcessed(); - - getDeclaredInterfaces(); - getDeclaredFields(); - getDeclaredMethods(); - // The lazyClassGen is preserved for aspects - it exists to enable - // around advice - // inlining since the method will need 'injecting' into the affected - // class. If - // XnoInline is on, we can chuck away the lazyClassGen since it - // won't be required - // later. - if (getResolvedTypeX().getWorld().isXnoInline()) { - lazyClassGen = null; - } - - // discard expensive bytecode array containing reweavable info - if (weaverState != null) { - weaverState.setReweavable(false); - weaverState.setUnwovenClassFileData(null); - } - for (int i = methods.length - 1; i >= 0; i--) { - methods[i].evictWeavingState(); - } - for (int i = fields.length - 1; i >= 0; i--) { - fields[i].evictWeavingState(); - } - javaClass = null; - this.artificial = true; - // setSourceContext(SourceContextImpl.UNKNOWN_SOURCE_CONTEXT); // - // bit naughty - // interfaces=null; // force reinit - may get us the right - // instances! - // superClass=null; - } - } - - public void weavingCompleted() { - hasBeenWoven = true; - if (getResolvedTypeX().getWorld().isRunMinimalMemory()) { - evictWeavingState(); - } - if (getSourceContext() != null && !getResolvedTypeX().isAspect()) { - getSourceContext().tidy(); - } - } - - public boolean hasBeenWoven() { - return hasBeenWoven; - } - - @Override - public boolean copySourceContext() { - return false; - } - - public void setExposedToWeaver(boolean b) { - exposedToWeaver = b; - } - - @Override - public int getCompilerVersion() { - return wvInfo.getMajorVersion(); - } - - public void ensureConsistent() { - superTypeReference.clear(); - superInterfaceReferences.clear(); - } - - public boolean isWeavable() { - return true; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java deleted file mode 100644 index b8ede0a9a..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelPerClauseAspectAdder.java +++ /dev/null @@ -1,560 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.ReferenceType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.patterns.PerClause; - -/** - * Adds aspectOf(), hasAspect() etc to the annotation defined aspects - * - * @author Alexandre Vasseur - * @author Andy Clement - */ -public class BcelPerClauseAspectAdder extends BcelTypeMunger { - - private final PerClause.Kind kind; - - private boolean hasGeneratedInner = false; - - public BcelPerClauseAspectAdder(ResolvedType aspect, PerClause.Kind kind) { - super(null, aspect); - this.kind = kind; - if (kind == PerClause.SINGLETON || kind == PerClause.PERTYPEWITHIN || kind == PerClause.PERCFLOW) { - // no inner needed - hasGeneratedInner = true; - } - } - - public boolean munge(BcelClassWeaver weaver) { - LazyClassGen gen = weaver.getLazyClassGen(); - - doAggressiveInner(gen); - - // Only munge the aspect type - if (!gen.getType().equals(aspectType)) { - return false; - } - - return doMunge(gen, true); - } - - public boolean forceMunge(LazyClassGen gen, boolean checkAlreadyThere) { - doAggressiveInner(gen); - return doMunge(gen, checkAlreadyThere); - } - - private void doAggressiveInner(LazyClassGen gen) { - // agressively generate the inner interface if any - // Note: we do so because of the bug #75442 that leads to have this interface implemented by all classes and not - // only those matched by the per clause, which fails under LTW since the very first class - // gets weaved and impl this interface that is still not defined. - if (!hasGeneratedInner) { - if (kind == PerClause.PEROBJECT) {// redundant test - see constructor, but safer - // inner class - UnresolvedType interfaceTypeX = AjcMemberMaker.perObjectInterfaceType(aspectType); - LazyClassGen interfaceGen = new LazyClassGen(interfaceTypeX.getName(), "java.lang.Object", null, - Constants.ACC_INTERFACE + Constants.ACC_PUBLIC + Constants.ACC_ABSTRACT, new String[0], getWorld()); - interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceGet(aspectType))); - interfaceGen.addMethodGen(makeMethodGen(interfaceGen, AjcMemberMaker.perObjectInterfaceSet(aspectType))); - // not really an inner class of it but that does not matter, we pass back to the LTW - gen.addGeneratedInner(interfaceGen); - } - hasGeneratedInner = true; - } - } - - private boolean doMunge(LazyClassGen gen, boolean checkAlreadyThere) { - if (checkAlreadyThere && hasPerClauseMembersAlready(gen)) { - return false; - } - - generatePerClauseMembers(gen); - - if (kind == PerClause.SINGLETON) { - generatePerSingletonAspectOfMethod(gen); - generatePerSingletonHasAspectMethod(gen); - generatePerSingletonAjcClinitMethod(gen); - } else if (kind == PerClause.PEROBJECT) { - generatePerObjectAspectOfMethod(gen); - generatePerObjectHasAspectMethod(gen); - generatePerObjectBindMethod(gen); - // these will be added by the PerObjectInterface munger that affects the type - pr144602 - // generatePerObjectGetSetMethods(gen); - } else if (kind == PerClause.PERCFLOW) { - generatePerCflowAspectOfMethod(gen); - generatePerCflowHasAspectMethod(gen); - generatePerCflowPushMethod(gen); - generatePerCflowAjcClinitMethod(gen); - } else if (kind == PerClause.PERTYPEWITHIN) { - generatePerTWAspectOfMethod(gen); - generatePerTWHasAspectMethod(gen); - generatePerTWGetInstanceMethod(gen); - generatePerTWCreateAspectInstanceMethod(gen); - generatePerTWGetWithinTypeNameMethod(gen); - } else { - throw new Error("should not happen - not such kind " + kind.getName()); - } - return true; - } - - public ResolvedMember getMatchingSyntheticMember(Member member) { - return null; - } - - public ResolvedMember getSignature() { - return null; - } - - public boolean matches(ResolvedType onType) { - // cannot always do the right thing because may need to eagerly generate ajcMightHaveAspect interface for LTW (says Alex) - if (hasGeneratedInner) { // pr237419 - not always going to generate the marker interface - return aspectType.equals(onType); - } else { - return true; - } - } - - private boolean hasPerClauseMembersAlready(LazyClassGen classGen) { - ResolvedMember[] methods = classGen.getBcelObjectType().getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - ResolvedMember method = methods[i]; - if ("aspectOf".equals(method.getName())) { - if ("()".equals(method.getParameterSignature()) && (kind == PerClause.SINGLETON || kind == PerClause.PERCFLOW)) { - return true; - } else if ("(Ljava/lang/Object;)".equals(method.getParameterSignature()) && kind == PerClause.PEROBJECT) { - return true; - } else if ("(Ljava/lang/Class;)".equals(method.getParameterSignature()) && kind == PerClause.PERTYPEWITHIN) { - return true; - } - } - } - return false; - } - - private void generatePerClauseMembers(LazyClassGen classGen) { - // FIXME Alex handle when field already there - or handle it with / similar to isAnnotationDefinedAspect() - // for that use aspectType and iterate on the fields. - - // FIXME Alex percflowX is not using this one but AJ code style does generate it so.. - ResolvedMember failureFieldInfo = AjcMemberMaker.initFailureCauseField(aspectType); - if (kind == PerClause.SINGLETON) { - classGen.addField(makeFieldGen(classGen, failureFieldInfo), null); - } - - if (kind == PerClause.SINGLETON) { - ResolvedMember perSingletonFieldInfo = AjcMemberMaker.perSingletonField(aspectType); - classGen.addField(makeFieldGen(classGen, perSingletonFieldInfo), null); - // pr144602 - don't need to do this, PerObjectInterface munger will do it - // } else if (kind == PerClause.PEROBJECT) { - // ResolvedMember perObjectFieldInfo = AjcMemberMaker.perObjectField(aspectType, aspectType); - // classGen.addField(makeFieldGen(classGen, perObjectFieldInfo).(), null); - // // if lazy generation of the inner interface MayHaveAspect works on LTW (see previous note) - // // it should be done here. - } else if (kind == PerClause.PERCFLOW) { - ResolvedMember perCflowFieldInfo = AjcMemberMaker.perCflowField(aspectType); - classGen.addField(makeFieldGen(classGen, perCflowFieldInfo), null); - } else if (kind == PerClause.PERTYPEWITHIN) { - ResolvedMember perTypeWithinForField = AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType); - classGen.addField(makeFieldGen(classGen, perTypeWithinForField), null); - } - } - - private void generatePerSingletonAspectOfMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perSingletonAspectOfMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); - InstructionBranch ifNotNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); - il.append(ifNotNull); - il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); - il.append(InstructionConstants.DUP); - il.append(InstructionFactory.PUSH(classGen.getConstantPool(), aspectType.getName())); - il.append(Utility.createGet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); - il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, new Type[] { - Type.STRING, new ObjectType("java.lang.Throwable") }, Constants.INVOKESPECIAL)); - il.append(InstructionConstants.ATHROW); - InstructionHandle ifElse = il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); - il.append(InstructionFactory.createReturn(Type.OBJECT)); - ifNotNull.setTarget(ifElse); - } - - private void generatePerSingletonHasAspectMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perSingletonHasAspectMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(Utility.createGet(factory, AjcMemberMaker.perSingletonField(aspectType))); - InstructionBranch ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); - il.append(ifNull); - il.append(InstructionFactory.PUSH(classGen.getConstantPool(), true)); - il.append(InstructionFactory.createReturn(Type.INT)); - InstructionHandle ifElse = il.append(InstructionFactory.PUSH(classGen.getConstantPool(), false)); - il.append(InstructionFactory.createReturn(Type.INT)); - ifNull.setTarget(ifElse); - } - - private void generatePerSingletonAjcClinitMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.ajcPostClinitMethod(aspectType)); - flagAsSynthetic(method, true); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(factory.createNew(aspectType.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - il.append(Utility.createSet(factory, AjcMemberMaker.perSingletonField(aspectType))); - il.append(InstructionFactory.createReturn(Type.VOID)); - - // patch <clinit> to delegate to ajc$postClinit at the end - LazyMethodGen clinit = classGen.getStaticInitializer(); - il = new InstructionList(); - InstructionHandle tryStart = il.append(factory.createInvoke(aspectType.getName(), NameMangler.AJC_POST_CLINIT_NAME, - Type.VOID, Type.NO_ARGS, Constants.INVOKESTATIC)); - InstructionBranch tryEnd = InstructionFactory.createBranchInstruction(Constants.GOTO, null); - il.append(tryEnd); - InstructionHandle handler = il.append(InstructionConstants.ASTORE_0); - il.append(InstructionConstants.ALOAD_0); - il.append(Utility.createSet(factory, AjcMemberMaker.initFailureCauseField(aspectType))); - il.append(InstructionFactory.createReturn(Type.VOID)); - tryEnd.setTarget(il.getEnd()); - - // replace the original "return" with a "nop" - // TODO AV - a bit odd, looks like Bcel alters bytecode and has a IMPDEP1 in its representation - if (clinit.getBody().getEnd().getInstruction().opcode == Constants.IMPDEP1) { - clinit.getBody().getEnd().getPrev().setInstruction(InstructionConstants.NOP); - } - clinit.getBody().getEnd().setInstruction(InstructionConstants.NOP); - clinit.getBody().append(il); - - clinit.addExceptionHandler(tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Throwable"), false); - } - - private void generatePerObjectAspectOfMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - ReferenceType interfaceType = (ReferenceType) BcelWorld.makeBcelType(AjcMemberMaker.perObjectInterfaceType(aspectType)); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perObjectAspectOfMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createInstanceOf(interfaceType)); - InstructionBranch ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); - il.append(ifEq); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createCheckCast(interfaceType)); - il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); - il.append(InstructionConstants.DUP); - InstructionBranch ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); - il.append(ifNull); - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(aspectType))); - InstructionHandle ifNullElse = il.append(InstructionConstants.POP); - ifNull.setTarget(ifNullElse); - InstructionHandle ifEqElse = il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); - ifEq.setTarget(ifEqElse); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, Type.NO_ARGS, - Constants.INVOKESPECIAL)); - il.append(InstructionConstants.ATHROW); - } - - private void generatePerObjectHasAspectMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - ReferenceType interfaceType = (ReferenceType) BcelWorld.makeBcelType(AjcMemberMaker.perObjectInterfaceType(aspectType)); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perObjectHasAspectMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createInstanceOf(interfaceType)); - InstructionBranch ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); - il.append(ifEq); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createCheckCast(interfaceType)); - il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); - InstructionBranch ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); - il.append(ifNull); - il.append(InstructionConstants.ICONST_1); - il.append(InstructionFactory.createReturn(Type.INT)); - InstructionHandle ifEqElse = il.append(InstructionConstants.ICONST_0); - ifEq.setTarget(ifEqElse); - ifNull.setTarget(ifEqElse); - il.append(InstructionFactory.createReturn(Type.INT)); - } - - private void generatePerObjectBindMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - ReferenceType interfaceType = (ReferenceType) BcelWorld.makeBcelType(AjcMemberMaker.perObjectInterfaceType(aspectType)); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perObjectBind(aspectType)); - flagAsSynthetic(method, true); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createInstanceOf(interfaceType)); - InstructionBranch ifEq = InstructionFactory.createBranchInstruction(Constants.IFEQ, null); - il.append(ifEq); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createCheckCast(interfaceType)); - il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceGet(aspectType))); - InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); - il.append(ifNonNull); - il.append(InstructionConstants.ALOAD_0); - il.append(factory.createCheckCast(interfaceType)); - il.append(factory.createNew(aspectType.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - il.append(Utility.createInvoke(factory, Constants.INVOKEINTERFACE, AjcMemberMaker.perObjectInterfaceSet(aspectType))); - InstructionHandle end = il.append(InstructionFactory.createReturn(Type.VOID)); - ifEq.setTarget(end); - ifNonNull.setTarget(end); - } - - // private void generatePerObjectGetSetMethods(LazyClassGen classGen) { - // InstructionFactory factory = classGen.getFactory(); - // - // LazyMethodGen methodGet = makeMethodGen(classGen, AjcMemberMaker.perObjectInterfaceGet(aspectType)); - // flagAsSynthetic(methodGet, true); - // classGen.addMethodGen(methodGet); - // InstructionList ilGet = methodGet.getBody(); - // ilGet = new InstructionList(); - // ilGet.append(InstructionConstants.ALOAD_0); - // ilGet.append(Utility.createGet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); - // ilGet.append(InstructionFactory.createReturn(Type.OBJECT)); - // - // LazyMethodGen methodSet = makeMethodGen(classGen, AjcMemberMaker.perObjectInterfaceSet(aspectType)); - // flagAsSynthetic(methodSet, true); - // classGen.addMethodGen(methodSet); - // InstructionList ilSet = methodSet.getBody(); - // ilSet = new InstructionList(); - // ilSet.append(InstructionConstants.ALOAD_0); - // ilSet.append(InstructionConstants.ALOAD_1); - // ilSet.append(Utility.createSet(factory, AjcMemberMaker.perObjectField(aspectType, aspectType))); - // ilSet.append(InstructionFactory.createReturn(Type.VOID)); - // } - - private void generatePerCflowAspectOfMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perCflowAspectOfMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(Utility.createGet(factory, AjcMemberMaker.perCflowField(aspectType))); - il.append(Utility.createInvoke(factory, Constants.INVOKEVIRTUAL, AjcMemberMaker.cflowStackPeekInstance())); - il.append(factory.createCheckCast((ReferenceType) BcelWorld.makeBcelType(aspectType))); - il.append(InstructionFactory.createReturn(Type.OBJECT)); - } - - private void generatePerCflowHasAspectMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perCflowHasAspectMethod(aspectType)); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(Utility.createGet(factory, AjcMemberMaker.perCflowField(aspectType))); - il.append(Utility.createInvoke(factory, Constants.INVOKEVIRTUAL, AjcMemberMaker.cflowStackIsValid())); - il.append(InstructionFactory.createReturn(Type.INT)); - } - - private void generatePerCflowPushMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perCflowPush(aspectType)); - flagAsSynthetic(method, true); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(Utility.createGet(factory, AjcMemberMaker.perCflowField(aspectType))); - il.append(factory.createNew(aspectType.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - il.append(Utility.createInvoke(factory, Constants.INVOKEVIRTUAL, AjcMemberMaker.cflowStackPushInstance())); - il.append(InstructionFactory.createReturn(Type.VOID)); - } - - private void generatePerCflowAjcClinitMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - - LazyMethodGen method = classGen.getAjcPreClinit(); // Creates a clinit if there isn't one - - InstructionList il = new InstructionList(); - il.append(factory.createNew(AjcMemberMaker.CFLOW_STACK_TYPE.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(AjcMemberMaker.CFLOW_STACK_TYPE.getName(), "<init>", Type.VOID, Type.NO_ARGS, - Constants.INVOKESPECIAL)); - il.append(Utility.createSet(factory, AjcMemberMaker.perCflowField(aspectType))); - method.getBody().insert(il); - } - - private void generatePerTWAspectOfMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinAspectOfMethod(aspectType, classGen.getWorld() - .isInJava5Mode())); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); - - il.append(Utility.createInvoke(factory, Constants.INVOKESTATIC, AjcMemberMaker.perTypeWithinGetInstance(aspectType))); - il.append(InstructionConstants.ASTORE_1); - il.append(InstructionConstants.ALOAD_1); - InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); - il.append(ifNonNull); - il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); - il.append(InstructionConstants.DUP); - il.append(InstructionFactory.PUSH(classGen.getConstantPool(), aspectType.getName())); - il.append(InstructionConstants.ACONST_NULL); - il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, new Type[] { - Type.STRING, new ObjectType("java.lang.Throwable") }, Constants.INVOKESPECIAL)); - il.append(InstructionConstants.ATHROW); - InstructionHandle ifElse = il.append(InstructionConstants.ALOAD_1); - ifNonNull.setTarget(ifElse); - il.append(InstructionFactory.createReturn(Type.OBJECT)); - - InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); - il.append(factory.createNew(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION.getName(), "<init>", Type.VOID, Type.NO_ARGS, - Constants.INVOKESPECIAL)); - il.append(InstructionConstants.ATHROW); - - method.addExceptionHandler(tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false); - } - - // Create 'public String getWithinTypeName() { return ajc$withinType;}' - private void generatePerTWGetWithinTypeNameMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetWithinTypeNameMethod(aspectType, classGen - .getWorld().isInJava5Mode())); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - // 0: aload_0 - // 1: getfield #14; //Field ajc$withinType:Ljava/lang/String; - // 4: areturn - InstructionList il = method.getBody(); - il.append(InstructionConstants.ALOAD_0); - il.append(Utility.createGet(factory, AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType))); - il.append(InstructionConstants.ARETURN); - } - - private void generatePerTWHasAspectMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinHasAspectMethod(aspectType, classGen.getWorld() - .isInJava5Mode())); - flagAsSynthetic(method, false); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); - il.append(Utility.createInvoke(factory, Constants.INVOKESTATIC, AjcMemberMaker.perTypeWithinGetInstance(aspectType))); - InstructionBranch ifNull = InstructionFactory.createBranchInstruction(Constants.IFNULL, null); - il.append(ifNull); - il.append(InstructionConstants.ICONST_1); - il.append(InstructionConstants.IRETURN); - InstructionHandle ifElse = il.append(InstructionConstants.ICONST_0); - ifNull.setTarget(ifElse); - il.append(InstructionConstants.IRETURN); - - InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); - il.append(InstructionConstants.ICONST_0); - il.append(InstructionConstants.IRETURN); - - method.addExceptionHandler(tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false); - } - - private void generatePerTWGetInstanceMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinGetInstance(aspectType)); - flagAsSynthetic(method, true); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - InstructionHandle tryStart = il.append(InstructionConstants.ALOAD_0); - il.append(InstructionFactory.PUSH(factory.getConstantPool(), NameMangler.perTypeWithinLocalAspectOf(aspectType))); - il.append(InstructionConstants.ACONST_NULL);// Class[] for "getDeclaredMethod" - il.append(factory.createInvoke("java/lang/Class", "getDeclaredMethod", Type.getType("Ljava/lang/reflect/Method;"), - new Type[] { Type.getType("Ljava/lang/String;"), Type.getType("[Ljava/lang/Class;") }, Constants.INVOKEVIRTUAL)); - il.append(InstructionConstants.ACONST_NULL);// Object for "invoke", static method - il.append(InstructionConstants.ACONST_NULL);// Object[] for "invoke", no arg - il.append(factory.createInvoke("java/lang/reflect/Method", "invoke", Type.OBJECT, new Type[] { - Type.getType("Ljava/lang/Object;"), Type.getType("[Ljava/lang/Object;") }, Constants.INVOKEVIRTUAL)); - il.append(factory.createCheckCast((ReferenceType) BcelWorld.makeBcelType(aspectType))); - il.append(InstructionConstants.ARETURN); - - InstructionHandle handler = il.append(InstructionConstants.ASTORE_1); - il.append(InstructionConstants.ACONST_NULL); - il.append(InstructionConstants.ARETURN); - - method.addExceptionHandler(tryStart, handler.getPrev(), handler, new ObjectType("java.lang.Exception"), false); - } - - private void generatePerTWCreateAspectInstanceMethod(LazyClassGen classGen) { - InstructionFactory factory = classGen.getFactory(); - LazyMethodGen method = makeMethodGen(classGen, AjcMemberMaker.perTypeWithinCreateAspectInstance(aspectType)); - flagAsSynthetic(method, true); - classGen.addMethodGen(method); - - InstructionList il = method.getBody(); - il.append(factory.createNew(aspectType.getName())); - il.append(InstructionConstants.DUP); - il.append(factory.createInvoke(aspectType.getName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - il.append(InstructionConstants.ASTORE_1); - il.append(InstructionConstants.ALOAD_1); - il.append(InstructionConstants.ALOAD_0); - il.append(Utility.createSet(factory, AjcMemberMaker.perTypeWithinWithinTypeField(aspectType, aspectType))); - il.append(InstructionConstants.ALOAD_1); - il.append(InstructionConstants.ARETURN); - } - - /** - * Add standard Synthetic (if wished) and AjSynthetic (always) attributes - * - * @param methodGen - * @param makeJavaSynthetic true if standard Synthetic attribute must be set as well (invisible to user) - */ - private static void flagAsSynthetic(LazyMethodGen methodGen, boolean makeJavaSynthetic) { - if (makeJavaSynthetic) { - methodGen.makeSynthetic(); - } - methodGen.addAttribute(Utility - .bcelAttribute(new AjAttribute.AjSynthetic(), methodGen.getEnclosingClass().getConstantPool())); - } - - // public boolean isLateTypeMunger() { - // return true; - // } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java deleted file mode 100644 index e1f99439f..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java +++ /dev/null @@ -1,270 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.lang.reflect.Modifier; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.ReferenceType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MemberImpl; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.ast.And; -import org.aspectj.weaver.ast.Call; -import org.aspectj.weaver.ast.CallExpr; -import org.aspectj.weaver.ast.Expr; -import org.aspectj.weaver.ast.FieldGet; -import org.aspectj.weaver.ast.FieldGetCall; -import org.aspectj.weaver.ast.HasAnnotation; -import org.aspectj.weaver.ast.IExprVisitor; -import org.aspectj.weaver.ast.ITestVisitor; -import org.aspectj.weaver.ast.Instanceof; -import org.aspectj.weaver.ast.Literal; -import org.aspectj.weaver.ast.Not; -import org.aspectj.weaver.ast.Or; -import org.aspectj.weaver.ast.Test; -import org.aspectj.weaver.ast.Var; -import org.aspectj.weaver.internal.tools.MatchingContextBasedTest; - -// we generate right to left, btw. -public final class BcelRenderer implements ITestVisitor, IExprVisitor { - - private InstructionList instructions; - private InstructionFactory fact; - private BcelWorld world; - - InstructionHandle sk, fk, next = null; - - private BcelRenderer(InstructionFactory fact, BcelWorld world) { - super(); - this.fact = fact; - this.world = world; - this.instructions = new InstructionList(); - } - - // ---- renderers - - public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e) { - BcelRenderer renderer = new BcelRenderer(fact, world); - e.accept(renderer); - return renderer.instructions; - } - - public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e, Type desiredType) { - BcelRenderer renderer = new BcelRenderer(fact, world); - e.accept(renderer); - InstructionList il = renderer.instructions; - il.append(Utility.createConversion(fact, BcelWorld.makeBcelType(e.getType()), desiredType)); - return il; - } - - public static InstructionList renderExprs(InstructionFactory fact, BcelWorld world, Expr[] es) { - BcelRenderer renderer = new BcelRenderer(fact, world); - for (int i = es.length - 1; i >= 0; i--) { - es[i].accept(renderer); - } - return renderer.instructions; - } - - /* - * Get the instructions representing this test. - * - * @param e test to render - * - * @param sk instructionHandle to jump to if our rendered check succeeds (typically start of advice) - * - * @param fk instructionHandle to jump to if our rendered check fails (typically after end of advice) - * - * @param next instructionHandle that will follow this generated code. Passing in null will generate one unnecessary GOTO - * instruction. - * - * @returns the instruction list representing this expression - */ - public static InstructionList renderTest(InstructionFactory fact, BcelWorld world, Test e, InstructionHandle sk, - InstructionHandle fk, InstructionHandle next) { - BcelRenderer renderer = new BcelRenderer(fact, world); - renderer.recur(e, sk, fk, next); - return renderer.instructions; - } - - // ---- recurrers - - private void recur(Test e, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) { - this.sk = sk; - this.fk = fk; - this.next = next; - e.accept(this); - } - - // ---- test visitors - - public void visit(And e) { - InstructionHandle savedFk = fk; - recur(e.getRight(), sk, fk, next); - InstructionHandle ning = instructions.getStart(); - recur(e.getLeft(), ning, savedFk, ning); - } - - public void visit(Or e) { - InstructionHandle savedSk = sk; - recur(e.getRight(), sk, fk, next); - recur(e.getLeft(), savedSk, instructions.getStart(), instructions.getStart()); - } - - public void visit(Not e) { - recur(e.getBody(), fk, sk, next); - } - - public void visit(Instanceof i) { - instructions.insert(createJumpBasedOnBooleanOnStack()); - instructions.insert(Utility.createInstanceof(fact, (ReferenceType) BcelWorld.makeBcelType(i.getType()))); - i.getVar().accept(this); - } - - public void visit(HasAnnotation hasAnnotation) { - // in Java: - // foo.class.isAnnotationPresent(annotationClass); - // in bytecode: - - // ifnull? skip to the end if it is as getClass() will fail (see pr 257833) - - // load var onto the stack (done for us later) - // invokevirtual java/lang/Object.getClass:()Ljava/lang/Class - // ldc_w annotationClass - // invokevirtual java/lang/Class.isAnnotationPresent:(Ljava/lang/Class;)Z - InstructionList il = new InstructionList(); - - // If it is null jump past the advice call - il.append(InstructionFactory.createBranchInstruction(Constants.IFNULL, fk)); - - // Load up the var again - il.append(((BcelVar) hasAnnotation.getVar()).createLoad(fact)); - - Member getClass = MemberImpl.method(UnresolvedType.OBJECT, 0, UnresolvedType.JL_CLASS, "getClass", UnresolvedType.NONE); - il.append(Utility.createInvoke(fact, world, getClass)); - // aload annotationClass - il.append(fact.createConstant(new ObjectType(hasAnnotation.getAnnotationType().getName()))); - // int annClassIndex = fact.getConstantPool().addClass(hasAnnotation.getAnnotationType().getSignature()); - // il.append(new LDC_W(annClassIndex)); - Member isAnnotationPresent = MemberImpl.method(UnresolvedType.JL_CLASS, 0, UnresolvedType.BOOLEAN, "isAnnotationPresent", - new UnresolvedType[] { UnresolvedType.JL_CLASS }); - il.append(Utility.createInvoke(fact, world, isAnnotationPresent)); - il.append(createJumpBasedOnBooleanOnStack()); - instructions.insert(il); - hasAnnotation.getVar().accept(this); - } - - /* - * (non-Javadoc) - * - * @see org.aspectj.weaver.ast.ITestVisitor#visit(org.aspectj.weaver.internal.tools.MatchingContextBasedTest) - */ - public void visit(MatchingContextBasedTest matchingContextTest) { - throw new UnsupportedOperationException("matching context extension not supported in bytecode weaving"); - } - - private InstructionList createJumpBasedOnBooleanOnStack() { - InstructionList il = new InstructionList(); - if (sk == fk) { - // don't bother generating if it doesn't matter - if (sk != next) { - il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk)); - } - return il; - } - - if (fk == next) { - il.insert(InstructionFactory.createBranchInstruction(Constants.IFNE, sk)); - } else if (sk == next) { - il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk)); - } else { - il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk)); - il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk)); - } - return il; - } - - public void visit(Literal literal) { - if (literal == Literal.FALSE) { - throw new BCException("visiting a false expression"); - } - } - - public void visit(Call call) { - Member method = call.getMethod(); - // assert method.isStatic() - Expr[] args = call.getArgs(); - InstructionList callIl = new InstructionList(); - for (int i = 0, len = args.length; i < len; i++) { - // XXX only correct for static method calls - Type desiredType = BcelWorld.makeBcelType(method.getParameterTypes()[i]); - Expr arg = args[i]; - // if arg is null it is because we couldn't bind it properly, for example see 162135 - if (arg == null) { - InstructionList iList = new InstructionList(); - iList.append(InstructionFactory.createNull(desiredType)); - callIl.append(iList); - } else { - callIl.append(renderExpr(fact, world, arg, desiredType)); - } - } - // System.out.println("rendered args: " + callIl); - callIl.append(Utility.createInvoke(fact, world, method)); - callIl.append(createJumpBasedOnBooleanOnStack()); - instructions.insert(callIl); - } - - public void visit(FieldGetCall fieldGetCall) { - Member field = fieldGetCall.getField(); - Member method = fieldGetCall.getMethod(); - InstructionList il = new InstructionList(); - il.append(Utility.createGet(fact, field)); - // assert !method.isStatic() - Expr[] args = fieldGetCall.getArgs(); - // System.out.println("args: " + Arrays.asList(args)); - il.append(renderExprs(fact, world, args)); - // System.out.println("rendered args: " + callIl); - il.append(Utility.createInvoke(fact, world, method)); - il.append(createJumpBasedOnBooleanOnStack()); - instructions.insert(il); - } - - // ---- expr visitors - - public void visit(Var var) { - BcelVar bvar = (BcelVar) var; - bvar.insertLoad(instructions, fact); - } - - public void visit(FieldGet fieldGet) { - Member field = fieldGet.getField(); - // assert field.isStatic() - instructions.insert(Utility.createGet(fact, field)); - } - - public void visit(CallExpr call) { - Member method = call.getMethod(); - // assert method.isStatic() - Expr[] args = call.getArgs(); - InstructionList callIl = renderExprs(fact, world, args); - callIl.append(Utility.createInvoke(fact, world, method)); - instructions.insert(callIl); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java deleted file mode 100644 index c93a0f26e..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java +++ /dev/null @@ -1,3425 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.generic.ArrayType; -import org.aspectj.apache.bcel.generic.FieldInstruction; -import org.aspectj.apache.bcel.generic.INVOKEINTERFACE; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionLV; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.apache.bcel.generic.InvokeInstruction; -import org.aspectj.apache.bcel.generic.LineNumberTag; -import org.aspectj.apache.bcel.generic.LocalVariableTag; -import org.aspectj.apache.bcel.generic.MULTIANEWARRAY; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.TargetLostException; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.IntMap; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MemberImpl; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.NewConstructorTypeMunger; -import org.aspectj.weaver.NewFieldTypeMunger; -import org.aspectj.weaver.NewMethodTypeMunger; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.World; -import org.aspectj.weaver.ast.Var; -import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; -import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.NotPointcut; -import org.aspectj.weaver.patterns.OrPointcut; -import org.aspectj.weaver.patterns.ThisOrTargetPointcut; - -/* - * Some fun implementation stuff: - * - * * expressionKind advice is non-execution advice - * * may have a target. - * * if the body is extracted, it will be extracted into - * a static method. The first argument to the static - * method is the target - * * advice may expose a this object, but that's the advice's - * consideration, not ours. This object will NOT be cached in another - * local, but will always come from frame zero. - * - * * non-expressionKind advice is execution advice - * * may have a this. - * * target is same as this, and is exposed that way to advice - * (i.e., target will not be cached, will always come from frame zero) - * * if the body is extracted, it will be extracted into a method - * with same static/dynamic modifier as enclosing method. If non-static, - * target of callback call will be this. - * - * * because of these two facts, the setup of the actual arguments (including - * possible target) callback method is the same for both kinds of advice: - * push the targetVar, if it exists (it will not exist for advice on static - * things), then push all the argVars. - * - * Protected things: - * - * * the above is sufficient for non-expressionKind advice for protected things, - * since the target will always be this. - * - * * For expressionKind things, we have to modify the signature of the callback - * method slightly. For non-static expressionKind things, we modify - * the first argument of the callback method NOT to be the type specified - * by the method/field signature (the owner), but rather we type it to - * the currentlyEnclosing type. We are guaranteed this will be fine, - * since the verifier verifies that the target is a subtype of the currently - * enclosingType. - * - * Worries: - * - * * ConstructorCalls will be weirder than all of these, since they - * supposedly don't have a target (according to AspectJ), but they clearly - * do have a target of sorts, just one that needs to be pushed on the stack, - * dupped, and not touched otherwise until the constructor runs. - * - * @author Jim Hugunin - * @author Erik Hilsdale - * - */ - -public class BcelShadow extends Shadow { - - private static final String[] NoDeclaredExceptions = new String[0]; - - private ShadowRange range; - private final BcelWorld world; - private final LazyMethodGen enclosingMethod; - - // TESTING this will tell us if the optimisation succeeded *on the last shadow processed* - public static boolean appliedLazyTjpOptimization; - - // Some instructions have a target type that will vary - // from the signature (pr109728) (1.4 declaring type issue) - private String actualInstructionTargetType; - - /** - * This generates an unassociated shadow, rooted in a particular method but not rooted to any particular point in the code. It - * should be given to a rooted ShadowRange in the {@link ShadowRange#associateWithShadow(BcelShadow)} method. - */ - public BcelShadow(BcelWorld world, Kind kind, Member signature, LazyMethodGen enclosingMethod, BcelShadow enclosingShadow) { - super(kind, signature, enclosingShadow); - this.world = world; - this.enclosingMethod = enclosingMethod; - } - - // ---- copies all state, including Shadow's mungers... - - public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) { - BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing); - if (mungers.size() > 0) { - List<ShadowMunger> src = mungers; - if (s.mungers == Collections.EMPTY_LIST) { - s.mungers = new ArrayList<ShadowMunger>(); - } - List<ShadowMunger> dest = s.mungers; - for (Iterator<ShadowMunger> i = src.iterator(); i.hasNext();) { - dest.add(i.next()); - } - } - return s; - } - - // ---- overridden behaviour - - @Override - public World getIWorld() { - return world; - } - - // see comment in deleteNewAndDup - // } else if (inst.opcode == Constants.DUP_X2) { - // // This code seen in the wild (by Brad): - // // 40: new #12; //class java/lang/StringBuffer - // // STACK: STRINGBUFFER - // // 43: dup - // // STACK: STRINGBUFFER/STRINGBUFFER - // // 44: aload_0 - // // STACK: STRINGBUFFER/STRINGBUFFER/THIS - // // 45: dup_x2 - // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/THIS - // // 46: getfield #36; //Field value:Ljava/lang/String; - // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING<value> - // // 49: invokestatic #37; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; - // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING - // // 52: invokespecial #19; //Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V - // // STACK: THIS/STRINGBUFFER - // // 55: aload_1 - // // STACK: THIS/STRINGBUFFER/LOCAL1 - // // 56: invokevirtual #22; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer; - // // STACK: THIS/STRINGBUFFER - // // 59: invokevirtual #34; //Method java/lang/StringBuffer.toString:()Ljava/lang/String; - // // STACK: THIS/STRING - // // 62: putfield #36; //Field value:Ljava/lang/String; - // // STACK: <empty> - // // 65: return - // - // // if we attempt to match on the ctor call to StringBuffer.<init> then we get into trouble. - // // if we simply delete the new/dup pair without fixing up the dup_x2 then the dup_x2 will fail due to there - // // not being 3 elements on the stack for it to work with. The fix *in this situation* is to change it to - // // a simple 'dup' - // - // // this fix is *not* very clean - but a general purpose decent solution will take much longer and this - // // bytecode sequence has only been seen once in the wild. - // ih.setInstruction(InstructionConstants.DUP); - - /** - * The new/dup (or new/dup_x1/swap) are removed and will be readded later (after the advice call) by the caller of this method. - * The groovy compiler produces unusual code where the new/dup isn't visible (when making a this() call from an existing ctor), - * an aload_0 is used to load the uninitialized object (as an example see the ctors in grails.util.BuildSettings). - * - * @return true if managed to remove them - */ - private boolean deleteNewAndDup() { - final ConstantPool cpool = getEnclosingClass().getConstantPool(); - int depth = 1; - InstructionHandle ih = range.getStart(); - - // Go back from where we are looking for 'NEW' that takes us to a stack depth of 0. INVOKESPECIAL <init> - while (ih != null) { - Instruction inst = ih.getInstruction(); - if (inst.opcode == Constants.INVOKESPECIAL && ((InvokeInstruction) inst).getName(cpool).equals("<init>")) { - depth++; - } else if (inst.opcode == Constants.NEW) { - depth--; - if (depth == 0) { - break; - } - // need a testcase to show this can really happen in a modern compiler - removed due to 315398 - moved this out to - // comment proceeding this method: - - } - ih = ih.getPrev(); - } - if (ih == null) { - return false; - } - // now IH points to the NEW. We're followed by the DUP, and that is followed - // by the actual instruction we care about. - InstructionHandle newHandle = ih; - InstructionHandle endHandle = newHandle.getNext(); - InstructionHandle nextHandle; - if (endHandle.getInstruction().opcode == Constants.DUP) { - nextHandle = endHandle.getNext(); - retargetFrom(newHandle, nextHandle); - retargetFrom(endHandle, nextHandle); - } else if (endHandle.getInstruction().opcode == Constants.DUP_X1) { - InstructionHandle dupHandle = endHandle; - endHandle = endHandle.getNext(); - nextHandle = endHandle.getNext(); - boolean skipEndRepositioning = false; - if (endHandle.getInstruction().opcode == Constants.SWAP) { - } else if (endHandle.getInstruction().opcode == Constants.IMPDEP1) { - skipEndRepositioning = true; // pr186884 - } else { - // XXX see next XXX comment - throw new RuntimeException("Unhandled kind of new " + endHandle); - } - // Now make any jumps to the 'new', the 'dup' or the 'end' now target the nextHandle - retargetFrom(newHandle, nextHandle); - retargetFrom(dupHandle, nextHandle); - if (!skipEndRepositioning) { - retargetFrom(endHandle, nextHandle); - } - } else { - endHandle = newHandle; - nextHandle = endHandle.getNext(); - retargetFrom(newHandle, nextHandle); - // add a POP here... we found a NEW w/o a dup or anything else, so - // we must be in statement context. - getRange().insert(InstructionConstants.POP, Range.OutsideAfter); - } - // assert (dupHandle.getInstruction() instanceof DUP); - - try { - range.getBody().delete(newHandle, endHandle); - } catch (TargetLostException e) { - throw new BCException("shouldn't happen"); - } - return true; - } - - private void retargetFrom(InstructionHandle old, InstructionHandle fresh) { - for (InstructionTargeter targeter : old.getTargetersCopy()) { - if (targeter instanceof ExceptionRange) { - ExceptionRange it = (ExceptionRange) targeter; - it.updateTarget(old, fresh, it.getBody()); - } else { - targeter.updateTarget(old, fresh); - } - } - } - - // records advice that is stopping us doing the lazyTjp optimization - private List<BcelAdvice> badAdvice = null; - - public void addAdvicePreventingLazyTjp(BcelAdvice advice) { - if (badAdvice == null) { - badAdvice = new ArrayList<BcelAdvice>(); - } - badAdvice.add(advice); - } - - @Override - protected void prepareForMungers() { - // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap, - // and store all our arguments on the frame. - - // ??? This is a bit of a hack (for the Java langauge). We do this because - // we sometime add code "outsideBefore" when dealing with weaving join points. We only - // do this for exposing state that is on the stack. It turns out to just work for - // everything except for constructor calls and exception handlers. If we were to clean - // this up, every ShadowRange would have three instructionHandle points, the start of - // the arg-setup code, the start of the running code, and the end of the running code. - boolean deletedNewAndDup = true; - if (getKind() == ConstructorCall) { - if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { - deletedNewAndDup = deleteNewAndDup(); // no new/dup for new array construction - } - initializeArgVars(); - } else if (getKind() == PreInitialization) { // pr74952 - ShadowRange range = getRange(); - range.insert(InstructionConstants.NOP, Range.InsideAfter); - } else if (getKind() == ExceptionHandler) { - - ShadowRange range = getRange(); - InstructionList body = range.getBody(); - InstructionHandle start = range.getStart(); - - // Create a store instruction to put the value from the top of the - // stack into a local variable slot. This is a trimmed version of - // what is in initializeArgVars() (since there is only one argument - // at a handler jp and only before advice is supported) (pr46298) - argVars = new BcelVar[1]; - // int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); - UnresolvedType tx = getArgType(0); - argVars[0] = genTempVar(tx, "ajc$arg0"); - InstructionHandle insertedInstruction = range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore); - - // Now the exception range starts just after our new instruction. - // The next bit of code changes the exception range to point at - // the store instruction - for (InstructionTargeter t : start.getTargetersCopy()) { - if (t instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) t; - er.updateTarget(start, insertedInstruction, body); - } - } - } - - // now we ask each munger to request our state - isThisJoinPointLazy = true;// world.isXlazyTjp(); // lazy is default now - - badAdvice = null; - for (ShadowMunger munger : mungers) { - munger.specializeOn(this); - } - - initializeThisJoinPoint(); - - if (thisJoinPointVar != null && !isThisJoinPointLazy && badAdvice != null && badAdvice.size() > 1) { - // something stopped us making it a lazy tjp - // can't build tjp lazily, no suitable test... - int valid = 0; - for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) { - BcelAdvice element = iter.next(); - ISourceLocation sLoc = element.getSourceLocation(); - if (sLoc != null && sLoc.getLine() > 0) { - valid++; - } - } - if (valid != 0) { - ISourceLocation[] badLocs = new ISourceLocation[valid]; - int i = 0; - for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) { - BcelAdvice element = iter.next(); - ISourceLocation sLoc = element.getSourceLocation(); - if (sLoc != null) { - badLocs[i++] = sLoc; - } - } - world.getLint().multipleAdviceStoppingLazyTjp - .signal(new String[] { this.toString() }, getSourceLocation(), badLocs); - } - } - badAdvice = null; - - // If we are an expression kind, we require our target/arguments on the stack - // before we do our actual thing. However, they may have been removed - // from the stack as the shadowMungers have requested state. - // if any of our shadowMungers requested either the arguments or target, - // the munger will have added code - // to pop the target/arguments into temporary variables, represented by - // targetVar and argVars. In such a case, we must make sure to re-push the - // values. - - // If we are nonExpressionKind, we don't expect arguments on the stack - // so this is moot. If our argVars happen to be null, then we know that - // no ShadowMunger has squirrelled away our arguments, so they're still - // on the stack. - InstructionFactory fact = getFactory(); - if (getKind().argsOnStack() && argVars != null) { - - // Special case first (pr46298). If we are an exception handler and the instruction - // just after the shadow is a POP then we should remove the pop. The code - // above which generated the store instruction has already cleared the stack. - // We also don't generate any code for the arguments in this case as it would be - // an incorrect aload. - if (getKind() == ExceptionHandler && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) { - // easier than deleting it ... - range.getEnd().getNext().setInstruction(InstructionConstants.NOP); - } else { - range.insert(BcelRenderer.renderExprs(fact, world, argVars), Range.InsideBefore); - if (targetVar != null) { - range.insert(BcelRenderer.renderExpr(fact, world, targetVar), Range.InsideBefore); - } - if (getKind() == ConstructorCall) { - if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) { - if (deletedNewAndDup) { // if didnt delete them, dont insert any! - range.insert(InstructionFactory.createDup(1), Range.InsideBefore); - range.insert(fact.createNew((ObjectType) BcelWorld.makeBcelType(getSignature().getDeclaringType())), - Range.InsideBefore); - } - } - } - } - } - } - - // ---- getters - - public ShadowRange getRange() { - return range; - } - - public void setRange(ShadowRange range) { - this.range = range; - } - - private int sourceline = -1; - - public int getSourceLine() { - // if the kind of join point for which we are a shadow represents - // a method or constructor execution, then the best source line is - // the one from the enclosingMethod declarationLineNumber if available. - if (sourceline != -1) { - return sourceline; - } - Kind kind = getKind(); - if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution) - || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) { - if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { - sourceline = getEnclosingMethod().getDeclarationLineNumber(); - return sourceline; - } - } - - if (range == null) { - if (getEnclosingMethod().hasBody()) { - sourceline = Utility.getSourceLine(getEnclosingMethod().getBody().getStart()); - return sourceline; - } else { - sourceline = 0; - return sourceline; - } - } - sourceline = Utility.getSourceLine(range.getStart()); - if (sourceline < 0) { - sourceline = 0; - } - return sourceline; - } - - @Override - public ResolvedType getEnclosingType() { - return getEnclosingClass().getType(); - } - - public LazyClassGen getEnclosingClass() { - return enclosingMethod.getEnclosingClass(); - } - - public BcelWorld getWorld() { - return world; - } - - // ---- factory methods - - public static BcelShadow makeConstructorExecution(BcelWorld world, LazyMethodGen enclosingMethod, - InstructionHandle justBeforeStart) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, ConstructorExecution, world.makeJoinPointSignatureFromMethod(enclosingMethod, - Member.CONSTRUCTOR), enclosingMethod, null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, justBeforeStart.getNext()), Range.genEnd(body)); - return s; - } - - public static BcelShadow makeStaticInitialization(BcelWorld world, LazyMethodGen enclosingMethod) { - InstructionList body = enclosingMethod.getBody(); - // move the start past ajc$preClinit - InstructionHandle clinitStart = body.getStart(); - if (clinitStart.getInstruction() instanceof InvokeInstruction) { - InvokeInstruction ii = (InvokeInstruction) clinitStart.getInstruction(); - if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_PRE_CLINIT_NAME)) { - clinitStart = clinitStart.getNext(); - } - } - - InstructionHandle clinitEnd = body.getEnd(); - - // XXX should move the end before the postClinit, but the return is then tricky... - // if (clinitEnd.getInstruction() instanceof InvokeInstruction) { - // InvokeInstruction ii = (InvokeInstruction)clinitEnd.getInstruction(); - // if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_POST_CLINIT_NAME)) { - // clinitEnd = clinitEnd.getPrev(); - // } - // } - - BcelShadow s = new BcelShadow(world, StaticInitialization, world.makeJoinPointSignatureFromMethod(enclosingMethod, - Member.STATIC_INITIALIZATION), enclosingMethod, null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, clinitStart), Range.genEnd(body, clinitEnd)); - return s; - } - - /** - * Make the shadow for an exception handler. Currently makes an empty shadow that only allows before advice to be woven into it. - */ - - public static BcelShadow makeExceptionHandler(BcelWorld world, ExceptionRange exceptionRange, LazyMethodGen enclosingMethod, - InstructionHandle startOfHandler, BcelShadow enclosingShadow) { - InstructionList body = enclosingMethod.getBody(); - UnresolvedType catchType = exceptionRange.getCatchType(); - UnresolvedType inType = enclosingMethod.getEnclosingClass().getType(); - - ResolvedMemberImpl sig = MemberImpl.makeExceptionHandlerSignature(inType, catchType); - sig.setParameterNames(new String[] { findHandlerParamName(startOfHandler) }); - - BcelShadow s = new BcelShadow(world, ExceptionHandler, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - InstructionHandle start = Range.genStart(body, startOfHandler); - InstructionHandle end = Range.genEnd(body, start); - - r.associateWithTargets(start, end); - exceptionRange.updateTarget(startOfHandler, start, body); - return s; - } - - private static String findHandlerParamName(InstructionHandle startOfHandler) { - if (startOfHandler.getInstruction().isStoreInstruction() && startOfHandler.getNext() != null) { - int slot = startOfHandler.getInstruction().getIndex(); - // System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index); - Iterator<InstructionTargeter> tIter = startOfHandler.getNext().getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter targeter = tIter.next(); - if (targeter instanceof LocalVariableTag) { - LocalVariableTag t = (LocalVariableTag) targeter; - if (t.getSlot() == slot) { - return t.getName(); - } - } - } - } - - return "<missing>"; - } - - /** create an init join point associated w/ an interface in the body of a constructor */ - - public static BcelShadow makeIfaceInitialization(BcelWorld world, LazyMethodGen constructor, - Member interfaceConstructorSignature) { - // this call marks the instruction list as changed - constructor.getBody(); - // UnresolvedType inType = constructor.getEnclosingClass().getType(); - BcelShadow s = new BcelShadow(world, Initialization, interfaceConstructorSignature, constructor, null); - // s.fallsThrough = true; - // ShadowRange r = new ShadowRange(body); - // r.associateWithShadow(s); - // InstructionHandle start = Range.genStart(body, handle); - // InstructionHandle end = Range.genEnd(body, handle); - // - // r.associateWithTargets(start, end); - return s; - } - - public void initIfaceInitializer(InstructionHandle end) { - final InstructionList body = enclosingMethod.getBody(); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(this); - InstructionHandle nop = body.insert(end, InstructionConstants.NOP); - - r.associateWithTargets(Range.genStart(body, nop), Range.genEnd(body, nop)); - } - - // public static BcelShadow makeIfaceConstructorExecution( - // BcelWorld world, - // LazyMethodGen constructor, - // InstructionHandle next, - // Member interfaceConstructorSignature) - // { - // // final InstructionFactory fact = constructor.getEnclosingClass().getFactory(); - // InstructionList body = constructor.getBody(); - // // UnresolvedType inType = constructor.getEnclosingClass().getType(); - // BcelShadow s = - // new BcelShadow( - // world, - // ConstructorExecution, - // interfaceConstructorSignature, - // constructor, - // null); - // s.fallsThrough = true; - // ShadowRange r = new ShadowRange(body); - // r.associateWithShadow(s); - // // ??? this may or may not work - // InstructionHandle start = Range.genStart(body, next); - // //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP)); - // InstructionHandle end = Range.genStart(body, next); - // //body.append(start, fact.NOP); - // - // r.associateWithTargets(start, end); - // return s; - // } - - /** - * Create an initialization join point associated with a constructor, but not with any body of code yet. If this is actually - * matched, it's range will be set when we inline self constructors. - * - * @param constructor The constructor starting this initialization. - */ - public static BcelShadow makeUnfinishedInitialization(BcelWorld world, LazyMethodGen constructor) { - BcelShadow ret = new BcelShadow(world, Initialization, world.makeJoinPointSignatureFromMethod(constructor, - Member.CONSTRUCTOR), constructor, null); - if (constructor.getEffectiveSignature() != null) { - ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature()); - } - return ret; - } - - public static BcelShadow makeUnfinishedPreinitialization(BcelWorld world, LazyMethodGen constructor) { - BcelShadow ret = new BcelShadow(world, PreInitialization, world.makeJoinPointSignatureFromMethod(constructor, - Member.CONSTRUCTOR), constructor, null); - if (constructor.getEffectiveSignature() != null) { - ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature()); - } - return ret; - } - - public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod, boolean lazyInit) { - if (!lazyInit) { - return makeMethodExecution(world, enclosingMethod); - } - - BcelShadow s = new BcelShadow(world, MethodExecution, enclosingMethod.getMemberView(), enclosingMethod, null); - - return s; - } - - public void init() { - if (range != null) { - return; - } - - final InstructionList body = enclosingMethod.getBody(); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(this); - r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); - } - - public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod) { - return makeShadowForMethod(world, enclosingMethod, MethodExecution, enclosingMethod.getMemberView()); - } - - public static BcelShadow makeShadowForMethod(BcelWorld world, LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(// OPTIMIZE this occurs lots of times for all jp kinds... - Range.genStart(body), Range.genEnd(body)); - return s; - } - - public static BcelShadow makeAdviceExecution(BcelWorld world, LazyMethodGen enclosingMethod) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, AdviceExecution, - world.makeJoinPointSignatureFromMethod(enclosingMethod, Member.ADVICE), enclosingMethod, null); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); - return s; - } - - // constructor call shadows are <em>initially</em> just around the - // call to the constructor. If ANY advice gets put on it, we move - // the NEW instruction inside the join point, which involves putting - // all the arguments in temps. - public static BcelShadow makeConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, - BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - - Member sig = world.makeJoinPointSignatureForMethodInvocation(enclosingMethod.getEnclosingClass(), - (InvokeInstruction) callHandle.getInstruction()); - - BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - public static BcelShadow makeArrayConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod, - InstructionHandle arrayInstruction, BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForArrayConstruction(enclosingMethod.getEnclosingClass(), arrayInstruction); - BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, arrayInstruction), Range.genEnd(body, arrayInstruction)); - retargetAllBranches(arrayInstruction, r.getStart()); - return s; - } - - public static BcelShadow makeMonitorEnter(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction, - BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForMonitorEnter(enclosingMethod.getEnclosingClass(), monitorInstruction); - BcelShadow s = new BcelShadow(world, SynchronizationLock, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction)); - retargetAllBranches(monitorInstruction, r.getStart()); - return s; - } - - public static BcelShadow makeMonitorExit(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction, - BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - Member sig = world.makeJoinPointSignatureForMonitorExit(enclosingMethod.getEnclosingClass(), monitorInstruction); - BcelShadow s = new BcelShadow(world, SynchronizationUnlock, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction)); - retargetAllBranches(monitorInstruction, r.getStart()); - return s; - } - - // see pr77166 - // public static BcelShadow makeArrayLoadCall( - // BcelWorld world, - // LazyMethodGen enclosingMethod, - // InstructionHandle arrayInstruction, - // BcelShadow enclosingShadow) - // { - // final InstructionList body = enclosingMethod.getBody(); - // Member sig = world.makeJoinPointSignatureForArrayLoad(enclosingMethod.getEnclosingClass(),arrayInstruction); - // BcelShadow s = - // new BcelShadow( - // world, - // MethodCall, - // sig, - // enclosingMethod, - // enclosingShadow); - // ShadowRange r = new ShadowRange(body); - // r.associateWithShadow(s); - // r.associateWithTargets( - // Range.genStart(body, arrayInstruction), - // Range.genEnd(body, arrayInstruction)); - // retargetAllBranches(arrayInstruction, r.getStart()); - // return s; - // } - - public static BcelShadow makeMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, - BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, MethodCall, world.makeJoinPointSignatureForMethodInvocation( - enclosingMethod.getEnclosingClass(), (InvokeInstruction) callHandle.getInstruction()), enclosingMethod, - enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - public static BcelShadow makeShadowForMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle, - BcelShadow enclosingShadow, Kind kind, ResolvedMember sig) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle)); - retargetAllBranches(callHandle, r.getStart()); - return s; - } - - public static BcelShadow makeFieldGet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod, - InstructionHandle getHandle, BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, FieldGet, field, - // BcelWorld.makeFieldSignature( - // enclosingMethod.getEnclosingClass(), - // (FieldInstruction) getHandle.getInstruction()), - enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, getHandle), Range.genEnd(body, getHandle)); - retargetAllBranches(getHandle, r.getStart()); - return s; - } - - public static BcelShadow makeFieldSet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod, - InstructionHandle setHandle, BcelShadow enclosingShadow) { - final InstructionList body = enclosingMethod.getBody(); - BcelShadow s = new BcelShadow(world, FieldSet, field, - // BcelWorld.makeFieldJoinPointSignature( - // enclosingMethod.getEnclosingClass(), - // (FieldInstruction) setHandle.getInstruction()), - enclosingMethod, enclosingShadow); - ShadowRange r = new ShadowRange(body); - r.associateWithShadow(s); - r.associateWithTargets(Range.genStart(body, setHandle), Range.genEnd(body, setHandle)); - retargetAllBranches(setHandle, r.getStart()); - return s; - } - - public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) { - for (InstructionTargeter source : from.getTargetersCopy()) { - if (source instanceof InstructionBranch) { - source.updateTarget(from, to); - } - } - } - - // // ---- type access methods - // private ObjectType getTargetBcelType() { - // return (ObjectType) BcelWorld.makeBcelType(getTargetType()); - // } - // private Type getArgBcelType(int arg) { - // return BcelWorld.makeBcelType(getArgType(arg)); - // } - - // ---- kinding - - /** - * If the end of my range has no real instructions following then my context needs a return at the end. - */ - public boolean terminatesWithReturn() { - return getRange().getRealNext() == null; - } - - /** - * Is arg0 occupied with the value of this - */ - public boolean arg0HoldsThis() { - if (getKind().isEnclosingKind()) { - return !Modifier.isStatic(getSignature().getModifiers()); - } else if (enclosingShadow == null) { - // XXX this is mostly right - // this doesn't do the right thing for calls in the pre part of introduced constructors. - return !enclosingMethod.isStatic(); - } else { - return ((BcelShadow) enclosingShadow).arg0HoldsThis(); - } - } - - // ---- argument getting methods - - private BcelVar thisVar = null; - private BcelVar targetVar = null; - private BcelVar[] argVars = null; - private Map<ResolvedType, AnnotationAccessVar> kindedAnnotationVars = null; - private Map<ResolvedType, TypeAnnotationAccessVar> thisAnnotationVars = null; - private Map<ResolvedType, TypeAnnotationAccessVar> targetAnnotationVars = null; - // private Map/* <UnresolvedType,BcelVar> */[] argAnnotationVars = null; - private Map<ResolvedType, AnnotationAccessVar> withinAnnotationVars = null; - private Map<ResolvedType, AnnotationAccessVar> withincodeAnnotationVars = null; - private boolean allArgVarsInitialized = false; - - @Override - public Var getThisVar() { - if (!hasThis()) { - throw new IllegalStateException("no this"); - } - initializeThisVar(); - return thisVar; - } - - @Override - public Var getThisAnnotationVar(UnresolvedType forAnnotationType) { - if (!hasThis()) { - throw new IllegalStateException("no this"); - } - initializeThisAnnotationVars(); // FIXME asc Why bother with this if we always return one? - // Even if we can't find one, we have to return one as we might have this annotation at runtime - Var v = thisAnnotationVars.get(forAnnotationType); - if (v == null) { - v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getThisVar()); - } - return v; - } - - @Override - public Var getTargetVar() { - if (!hasTarget()) { - throw new IllegalStateException("no target"); - } - initializeTargetVar(); - return targetVar; - } - - @Override - public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) { - if (!hasTarget()) { - throw new IllegalStateException("no target"); - } - initializeTargetAnnotationVars(); // FIXME asc why bother with this if we always return one? - Var v = targetAnnotationVars.get(forAnnotationType); - // Even if we can't find one, we have to return one as we might have this annotation at runtime - if (v == null) { - v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getTargetVar()); - } - return v; - } - - @Override - public Var getArgVar(int i) { - ensureInitializedArgVar(i); - return argVars[i]; - } - - @Override - public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) { - return new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getArgVar(i)); - // initializeArgAnnotationVars(); - // - // Var v = (Var) argAnnotationVars[i].get(forAnnotationType); - // if (v == null) { - // v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getArgVar(i)); - // } - // return v; - } - - @Override - public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) { - initializeKindedAnnotationVars(); - return kindedAnnotationVars.get(forAnnotationType); - } - - @Override - public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) { - initializeWithinAnnotationVars(); - return withinAnnotationVars.get(forAnnotationType); - } - - @Override - public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) { - initializeWithinCodeAnnotationVars(); - return withincodeAnnotationVars.get(forAnnotationType); - } - - // reflective thisJoinPoint support - private BcelVar thisJoinPointVar = null; - private boolean isThisJoinPointLazy; - private int lazyTjpConsumers = 0; - private BcelVar thisJoinPointStaticPartVar = null; - - // private BcelVar thisEnclosingJoinPointStaticPartVar = null; - - @Override - public final Var getThisJoinPointStaticPartVar() { - return getThisJoinPointStaticPartBcelVar(); - } - - @Override - public final Var getThisEnclosingJoinPointStaticPartVar() { - return getThisEnclosingJoinPointStaticPartBcelVar(); - } - - public void requireThisJoinPoint(boolean hasGuardTest, boolean isAround) { - if (!isAround) { - if (!hasGuardTest) { - isThisJoinPointLazy = false; - } else { - lazyTjpConsumers++; - } - } - // if (!hasGuardTest) { - // isThisJoinPointLazy = false; - // } else { - // lazyTjpConsumers++; - // } - if (thisJoinPointVar == null) { - thisJoinPointVar = genTempVar(UnresolvedType.forName("org.aspectj.lang.JoinPoint")); - } - } - - @Override - public Var getThisJoinPointVar() { - requireThisJoinPoint(false, false); - return thisJoinPointVar; - } - - void initializeThisJoinPoint() { - if (thisJoinPointVar == null) { - return; - } - - if (isThisJoinPointLazy) { - isThisJoinPointLazy = checkLazyTjp(); - } - - if (isThisJoinPointLazy) { - appliedLazyTjpOptimization = true; - createThisJoinPoint(); // make sure any state needed is initialized, but throw the instructions out - - if (lazyTjpConsumers == 1) { - return; // special case only one lazyTjpUser - } - - InstructionFactory fact = getFactory(); - InstructionList il = new InstructionList(); - il.append(InstructionConstants.ACONST_NULL); - il.append(thisJoinPointVar.createStore(fact)); - range.insert(il, Range.OutsideBefore); - } else { - appliedLazyTjpOptimization = false; - InstructionFactory fact = getFactory(); - InstructionList il = createThisJoinPoint(); - il.append(thisJoinPointVar.createStore(fact)); - range.insert(il, Range.OutsideBefore); - } - } - - private boolean checkLazyTjp() { - // check for around advice - for (Iterator<ShadowMunger> i = mungers.iterator(); i.hasNext();) { - ShadowMunger munger = i.next(); - if (munger instanceof Advice) { - if (((Advice) munger).getKind() == AdviceKind.Around) { - if (munger.getSourceLocation() != null) { // do we know enough to bother reporting? - if (world.getLint().canNotImplementLazyTjp.isEnabled()) { - world.getLint().canNotImplementLazyTjp.signal(new String[] { toString() }, getSourceLocation(), - new ISourceLocation[] { munger.getSourceLocation() }); - } - } - return false; - } - } - } - - return true; - } - - InstructionList loadThisJoinPoint() { - InstructionFactory fact = getFactory(); - InstructionList il = new InstructionList(); - - if (isThisJoinPointLazy) { - // If we're lazy, build the join point right here. - il.append(createThisJoinPoint()); - - // Does someone else need it? If so, store it for later retrieval - if (lazyTjpConsumers > 1) { - il.append(thisJoinPointVar.createStore(fact)); - - InstructionHandle end = il.append(thisJoinPointVar.createLoad(fact)); - - il.insert(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, end)); - il.insert(thisJoinPointVar.createLoad(fact)); - } - } else { - // If not lazy, its already been built and stored, just retrieve it - thisJoinPointVar.appendLoad(il, fact); - } - - return il; - } - - InstructionList createThisJoinPoint() { - InstructionFactory fact = getFactory(); - InstructionList il = new InstructionList(); - - BcelVar staticPart = getThisJoinPointStaticPartBcelVar(); - staticPart.appendLoad(il, fact); - if (hasThis()) { - ((BcelVar) getThisVar()).appendLoad(il, fact); - } else { - il.append(InstructionConstants.ACONST_NULL); - } - if (hasTarget()) { - ((BcelVar) getTargetVar()).appendLoad(il, fact); - } else { - il.append(InstructionConstants.ACONST_NULL); - } - - switch (getArgCount()) { - case 0: - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { - LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); - break; - case 1: - ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { - LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); - break; - case 2: - ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - ((BcelVar) getArgVar(1)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT)); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { - LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC)); - break; - default: - il.append(makeArgsObjectArray()); - il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] { - LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1) }, Constants.INVOKESTATIC)); - break; - } - - return il; - } - - public BcelVar getThisJoinPointStaticPartBcelVar() { - return getThisJoinPointStaticPartBcelVar(false); - } - - @Override - public BcelVar getThisAspectInstanceVar(ResolvedType aspectType) { - return new AspectInstanceVar(aspectType); - } - - /** - * Get the Var for the xxxxJpStaticPart, xxx = this or enclosing - * - * @param isEnclosingJp true to have the enclosingJpStaticPart - * @return - */ - public BcelVar getThisJoinPointStaticPartBcelVar(final boolean isEnclosingJp) { - if (thisJoinPointStaticPartVar == null) { - Field field = getEnclosingClass().getTjpField(this, isEnclosingJp); - ResolvedType sjpType = null; - if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have different jpsp types in 1.2 - sjpType = world.getCoreType(UnresolvedType.JOINPOINT_STATICPART); - } else { - sjpType = isEnclosingJp ? world.getCoreType(UnresolvedType.JOINPOINT_ENCLOSINGSTATICPART) : world - .getCoreType(UnresolvedType.JOINPOINT_STATICPART); - } - thisJoinPointStaticPartVar = new BcelFieldRef(sjpType, getEnclosingClass().getClassName(), field.getName()); - // getEnclosingClass().warnOnAddedStaticInitializer(this,munger.getSourceLocation()); - } - return thisJoinPointStaticPartVar; - } - - /** - * Get the Var for the enclosingJpStaticPart - * - * @return - */ - public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() { - if (enclosingShadow == null) { - // the enclosing of an execution is itself - return getThisJoinPointStaticPartBcelVar(true); - } else { - return ((BcelShadow) enclosingShadow).getThisJoinPointStaticPartBcelVar(true); - } - } - - // ??? need to better understand all the enclosing variants - @Override - public Member getEnclosingCodeSignature() { - if (getKind().isEnclosingKind()) { - return getSignature(); - } else if (getKind() == Shadow.PreInitialization) { - // PreInit doesn't enclose code but its signature - // is correctly the signature of the ctor. - return getSignature(); - } else if (enclosingShadow == null) { - return getEnclosingMethod().getMemberView(); - } else { - return enclosingShadow.getSignature(); - } - } - - public Member getRealEnclosingCodeSignature() { - return enclosingMethod.getMemberView(); - } - - // public Member getEnclosingCodeSignatureForModel() { - // if (getKind().isEnclosingKind()) { - // return getSignature(); - // } else if (getKind() == Shadow.PreInitialization) { - // // PreInit doesn't enclose code but its signature - // // is correctly the signature of the ctor. - // return getSignature(); - // } else if (enclosingShadow == null) { - // return getEnclosingMethod().getMemberView(); - // } else { - // if (enclosingShadow.getKind() == Shadow.MethodExecution && enclosingMethod.getEffectiveSignature() != null) { - // - // } else { - // return enclosingShadow.getSignature(); - // } - // } - // } - - private InstructionList makeArgsObjectArray() { - InstructionFactory fact = getFactory(); - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - final InstructionList il = new InstructionList(); - int alen = getArgCount(); - il.append(Utility.createConstant(fact, alen)); - il.append(fact.createNewArray(Type.OBJECT, (short) 1)); - arrayVar.appendStore(il, fact); - - int stateIndex = 0; - for (int i = 0, len = getArgCount(); i < len; i++) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar) getArgVar(i)); - stateIndex++; - } - arrayVar.appendLoad(il, fact); - return il; - } - - // ---- initializing var tables - - /* - * initializing this is doesn't do anything, because this is protected from side-effects, so we don't need to copy its location - */ - - private void initializeThisVar() { - if (thisVar != null) { - return; - } - thisVar = new BcelVar(getThisType().resolve(world), 0); - thisVar.setPositionInAroundState(0); - } - - public void initializeTargetVar() { - InstructionFactory fact = getFactory(); - if (targetVar != null) { - return; - } - if (getKind().isTargetSameAsThis()) { - if (hasThis()) { - initializeThisVar(); - } - targetVar = thisVar; - } else { - initializeArgVars(); // gotta pop off the args before we find the target - UnresolvedType type = getTargetType(); - type = ensureTargetTypeIsCorrect(type); - targetVar = genTempVar(type, "ajc$target"); - range.insert(targetVar.createStore(fact), Range.OutsideBefore); - targetVar.setPositionInAroundState(hasThis() ? 1 : 0); - } - } - - /* - * PR 72528 This method double checks the target type under certain conditions. The Java 1.4 compilers seem to take calls to - * clone methods on array types and create bytecode that looks like clone is being called on Object. If we advise a clone call - * with around advice we extract the call into a helper method which we can then refer to. Because the type in the bytecode for - * the call to clone is Object we create a helper method with an Object parameter - this is not correct as we have lost the fact - * that the actual type is an array type. If we don't do the check below we will create code that fails java verification. This - * method checks for the peculiar set of conditions and if they are true, it has a sneak peek at the code before the call to see - * what is on the stack. - */ - public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) { - - Member msig = getSignature(); - if (msig.getArity() == 0 && getKind() == MethodCall && msig.getName().charAt(0) == 'c' && tx.equals(ResolvedType.OBJECT) - && msig.getReturnType().equals(ResolvedType.OBJECT) && msig.getName().equals("clone")) { - - // Lets go back through the code from the start of the shadow - InstructionHandle searchPtr = range.getStart().getPrev(); - while (Range.isRangeHandle(searchPtr) || searchPtr.getInstruction().isStoreInstruction()) { // ignore this instruction - - // it doesnt give us the - // info we want - searchPtr = searchPtr.getPrev(); - } - - // A load instruction may tell us the real type of what the clone() call is on - if (searchPtr.getInstruction().isLoadInstruction()) { - LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr, searchPtr.getInstruction().getIndex()); - if (lvt != null) { - return UnresolvedType.forSignature(lvt.getType()); - } - } - // A field access instruction may tell us the real type of what the clone() call is on - if (searchPtr.getInstruction() instanceof FieldInstruction) { - FieldInstruction si = (FieldInstruction) searchPtr.getInstruction(); - Type t = si.getFieldType(getEnclosingClass().getConstantPool()); - return BcelWorld.fromBcel(t); - } - // A new array instruction obviously tells us it is an array type ! - if (searchPtr.getInstruction().opcode == Constants.ANEWARRAY) { - // ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction(); - // Type t = ana.getType(getEnclosingClass().getConstantPool()); - // Just use a standard java.lang.object array - that will work fine - return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, 1)); - } - // A multi new array instruction obviously tells us it is an array type ! - if (searchPtr.getInstruction() instanceof MULTIANEWARRAY) { - MULTIANEWARRAY ana = (MULTIANEWARRAY) searchPtr.getInstruction(); - // Type t = ana.getType(getEnclosingClass().getConstantPool()); - // t = new ArrayType(t,ana.getDimensions()); - // Just use a standard java.lang.object array - that will work fine - return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, ana.getDimensions())); - } - throw new BCException("Can't determine real target of clone() when processing instruction " - + searchPtr.getInstruction() + ". Perhaps avoid selecting clone with your pointcut?"); - } - return tx; - } - - public void ensureInitializedArgVar(int argNumber) { - if (allArgVarsInitialized || (argVars != null && argVars[argNumber] != null)) { - return; - } - InstructionFactory fact = getFactory(); - int len = getArgCount(); - if (argVars == null) { - argVars = new BcelVar[len]; - } - - // Need to initialize argument i - int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); - - if (getKind().argsOnStack()) { - // Let's just do them all now since they are on the stack - // we move backwards because we're popping off the stack - for (int i = len - 1; i >= 0; i--) { - UnresolvedType type = getArgType(i); - BcelVar tmp = genTempVar(type, "ajc$arg" + i); - range.insert(tmp.createStore(getFactory()), Range.OutsideBefore); - int position = i; - position += positionOffset; - tmp.setPositionInAroundState(position); - argVars[i] = tmp; - } - allArgVarsInitialized = true; - } else { - int index = 0; - if (arg0HoldsThis()) { - index++; - } - boolean allInited = true; - for (int i = 0; i < len; i++) { - UnresolvedType type = getArgType(i); - if (i == argNumber) { - argVars[argNumber] = genTempVar(type, "ajc$arg" + argNumber); - range.insert(argVars[argNumber].createCopyFrom(fact, index), Range.OutsideBefore); - argVars[argNumber].setPositionInAroundState(argNumber + positionOffset); - } - allInited = allInited && argVars[i] != null; - index += type.getSize(); - } - if (allInited && (argNumber + 1) == len) { - allArgVarsInitialized = true; - } - } - } - - /** - * Initialize all the available arguments at the shadow. This means creating a copy of them that we can then use for advice - * calls (the copy ensures we are not affected by other advice changing the values). This method initializes all arguments - * whereas the method ensureInitializedArgVar will only ensure a single argument is setup. - */ - public void initializeArgVars() { - if (allArgVarsInitialized) { - return; - } - InstructionFactory fact = getFactory(); - int len = getArgCount(); - if (argVars == null) { - argVars = new BcelVar[len]; - } - int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0); - - if (getKind().argsOnStack()) { - // we move backwards because we're popping off the stack - for (int i = len - 1; i >= 0; i--) { - UnresolvedType type = getArgType(i); - BcelVar tmp = genTempVar(type, "ajc$arg" + i); - range.insert(tmp.createStore(getFactory()), Range.OutsideBefore); - int position = i; - position += positionOffset; - tmp.setPositionInAroundState(position); - argVars[i] = tmp; - } - } else { - int index = 0; - if (arg0HoldsThis()) { - index++; - } - - for (int i = 0; i < len; i++) { - UnresolvedType type = getArgType(i); - if (argVars[i] == null) { - BcelVar tmp = genTempVar(type, "ajc$arg" + i); - range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore); - argVars[i] = tmp; - tmp.setPositionInAroundState(i + positionOffset); - } - index += type.resolve(world).getSize(); - } - } - allArgVarsInitialized = true; - - } - - public void initializeForAroundClosure() { - initializeArgVars(); - if (hasTarget()) { - initializeTargetVar(); - } - if (hasThis()) { - initializeThisVar(); - // System.out.println("initialized: " + this + " thisVar = " + thisVar); - } - } - - public void initializeThisAnnotationVars() { - if (thisAnnotationVars != null) { - return; - } - thisAnnotationVars = new HashMap<ResolvedType, TypeAnnotationAccessVar>(); - // populate.. - } - - public void initializeTargetAnnotationVars() { - if (targetAnnotationVars != null) { - return; - } - if (getKind().isTargetSameAsThis()) { - if (hasThis()) { - initializeThisAnnotationVars(); - } - targetAnnotationVars = thisAnnotationVars; - } else { - targetAnnotationVars = new HashMap<ResolvedType, TypeAnnotationAccessVar>(); - ResolvedType[] rtx = this.getTargetType().resolve(world).getAnnotationTypes(); // what about annotations we havent - // gotten yet but we will get in - // subclasses? - for (int i = 0; i < rtx.length; i++) { - ResolvedType typeX = rtx[i]; - targetAnnotationVars.put(typeX, new TypeAnnotationAccessVar(typeX, (BcelVar) getTargetVar())); - } - // populate. - } - } - - // public void initializeArgAnnotationVars() { - // if (argAnnotationVars != null) { - // return; - // } - // int numArgs = getArgCount(); - // argAnnotationVars = new Map[numArgs]; - // for (int i = 0; i < argAnnotationVars.length; i++) { - // argAnnotationVars[i] = new HashMap(); - // // FIXME asc just delete this logic - we always build the Var on demand, as we don't know at weave time - // // what the full set of annotations could be (due to static/dynamic type differences...) - // } - // } - - protected ResolvedMember getRelevantMember(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) { - if (foundMember != null) { - return foundMember; - } - - foundMember = getSignature().resolve(world); - if (foundMember == null && relevantMember != null) { - foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); - } - - // check the ITD'd dooberries - List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers(); - for (ConcreteTypeMunger typeMunger : mungers) { - if (typeMunger.getMunger() instanceof NewMethodTypeMunger || typeMunger.getMunger() instanceof NewConstructorTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - if (fakerm.getName().equals(getSignature().getName()) - && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { - if (foundMember.getKind() == ResolvedMember.CONSTRUCTOR) { - foundMember = AjcMemberMaker.interConstructor(relevantType, foundMember, typeMunger.getAspectType()); - } else { - foundMember = AjcMemberMaker.interMethod(foundMember, typeMunger.getAspectType(), false); - // ResolvedMember o = AjcMemberMaker.interMethodBody(fakerm, typeMunger.getAspectType()); - // // Object os = o.getAnnotations(); - // ResolvedMember foundMember2 = findMethod(typeMunger.getAspectType(), o); - // Object os2 = foundMember2.getAnnotations(); - // int stop = 1; - // foundMember = foundMember2; - // foundMember = AjcMemberMaker.interMethod(foundMember, typeMunger.getAspectType()); - } - // in the above.. what about if it's on an Interface? Can that happen? - // then the last arg of the above should be true - return foundMember; - } - } - } - return foundMember; - } - - protected ResolvedType[] getAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) { - if (foundMember == null) { - // check the ITD'd dooberries - List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers(); - for (Iterator<ConcreteTypeMunger> iter = mungers.iterator(); iter.hasNext();) { - Object munger = iter.next(); - ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) munger; - if (typeMunger.getMunger() instanceof NewMethodTypeMunger - || typeMunger.getMunger() instanceof NewConstructorTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - // if (fakerm.hasAnnotations()) - - ResolvedMember ajcMethod = (getSignature().getKind() == ResolvedMember.CONSTRUCTOR ? AjcMemberMaker - .postIntroducedConstructor(typeMunger.getAspectType(), fakerm.getDeclaringType(), - fakerm.getParameterTypes()) : AjcMemberMaker.interMethodDispatcher(fakerm, - typeMunger.getAspectType())); - // AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType())); - ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod); - if (fakerm.getName().equals(getSignature().getName()) - && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) { - relevantType = typeMunger.getAspectType(); - foundMember = rmm; - return foundMember.getAnnotationTypes(); - } - } - } - // didn't find in ITDs, look in supers - foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember); - if (foundMember == null) { - throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType); - } - } - return foundMember.getAnnotationTypes(); - } - - /** - * By determining what "kind" of shadow we are, we can find out the annotations on the appropriate element (method, field, - * constructor, type). Then create one BcelVar entry in the map for each annotation, keyed by annotation type. - */ - public void initializeKindedAnnotationVars() { - if (kindedAnnotationVars != null) { - return; - } - kindedAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>(); - - ResolvedType[] annotations = null; - Member shadowSignature = getSignature(); - Member annotationHolder = getSignature(); - ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world); - - if (relevantType.isRawType() || relevantType.isParameterizedType()) { - relevantType = relevantType.getGenericType(); - } - - // Determine the annotations that are of interest - if (getKind() == Shadow.StaticInitialization) { - annotations = relevantType.resolve(world).getAnnotationTypes(); - } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) { - ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(), getSignature()); - annotations = getAnnotations(foundMember, shadowSignature, relevantType); - annotationHolder = getRelevantMember(foundMember, shadowSignature, relevantType); - relevantType = annotationHolder.getDeclaringType().resolve(world); - } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) { - annotationHolder = findField(relevantType.getDeclaredFields(), getSignature()); - - if (annotationHolder == null) { - // check the ITD'd dooberries - List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers(); - for (ConcreteTypeMunger typeMunger : mungers) { - if (typeMunger.getMunger() instanceof NewFieldTypeMunger) { - ResolvedMember fakerm = typeMunger.getSignature(); - // if (fakerm.hasAnnotations()) - ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType()); - ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod); - if (fakerm.equals(getSignature())) { - relevantType = typeMunger.getAspectType(); - annotationHolder = rmm; - } - } - } - } - annotations = ((ResolvedMember) annotationHolder).getAnnotationTypes(); - - } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution - || getKind() == Shadow.AdviceExecution) { - - ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(), getSignature()); - annotations = getAnnotations(foundMember, shadowSignature, relevantType); - annotationHolder = getRelevantMember(foundMember, annotationHolder, relevantType); - UnresolvedType ut = annotationHolder.getDeclaringType(); - relevantType = ut.resolve(world); - - } else if (getKind() == Shadow.ExceptionHandler) { - relevantType = getSignature().getParameterTypes()[0].resolve(world); - annotations = relevantType.getAnnotationTypes(); - - } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) { - ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(), getSignature()); - annotations = found.getAnnotationTypes(); - } - - if (annotations == null) { - // We can't have recognized the shadow - should blow up now to be on the safe side - throw new BCException("Could not discover annotations for shadow: " + getKind()); - } - - for (ResolvedType annotationType : annotations) { - AnnotationAccessVar accessVar = new AnnotationAccessVar(this, getKind(), annotationType.resolve(world), relevantType, - annotationHolder, false); - kindedAnnotationVars.put(annotationType, accessVar); - } - } - - private ResolvedMember findMethod2(ResolvedMember members[], Member sig) { - String signatureName = sig.getName(); - String parameterSignature = sig.getParameterSignature(); - for (ResolvedMember member : members) { - if (member.getName().equals(signatureName) && member.getParameterSignature().equals(parameterSignature)) { - return member; - } - } - return null; - } - - private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) { - ResolvedMember decMethods[] = aspectType.getDeclaredMethods(); - for (int i = 0; i < decMethods.length; i++) { - ResolvedMember member = decMethods[i]; - if (member.equals(ajcMethod)) { - return member; - } - } - return null; - } - - private ResolvedMember findField(ResolvedMember[] members, Member lookingFor) { - for (int i = 0; i < members.length; i++) { - ResolvedMember member = members[i]; - if (member.getName().equals(getSignature().getName()) && member.getType().equals(getSignature().getType())) { - return member; - } - } - return null; - } - - public void initializeWithinAnnotationVars() { - if (withinAnnotationVars != null) { - return; - } - withinAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>(); - - ResolvedType[] annotations = getEnclosingType().resolve(world).getAnnotationTypes(); - for (int i = 0; i < annotations.length; i++) { - ResolvedType ann = annotations[i]; - Kind k = Shadow.StaticInitialization; - withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null, true)); - } - } - - public void initializeWithinCodeAnnotationVars() { - if (withincodeAnnotationVars != null) { - return; - } - withincodeAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>(); - - // For some shadow we are interested in annotations on the method containing that shadow. - ResolvedType[] annotations = getEnclosingMethod().getMemberView().getAnnotationTypes(); - for (int i = 0; i < annotations.length; i++) { - ResolvedType ann = annotations[i]; - Kind k = (getEnclosingMethod().getMemberView().getKind() == Member.CONSTRUCTOR ? Shadow.ConstructorExecution - : Shadow.MethodExecution); - withincodeAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), - getEnclosingCodeSignature(), true)); - } - } - - // ---- weave methods - - void weaveBefore(BcelAdvice munger) { - range.insert(munger.getAdviceInstructions(this, null, range.getRealStart()), Range.InsideBefore); - } - - public void weaveAfter(BcelAdvice munger) { - weaveAfterThrowing(munger, UnresolvedType.THROWABLE); - weaveAfterReturning(munger); - } - - /** - * The basic strategy here is to add a set of instructions at the end of the shadow range that dispatch the advice, and then - * return whatever the shadow was going to return anyway. - * - * To achieve this, we note all the return statements in the advice, and replace them with code that: 1) stores the return value - * on top of the stack in a temp var 2) jumps to the start of our advice block 3) restores the return value at the end of the - * advice block before ultimately returning - * - * We also need to bind the return value into a returning parameter, if the advice specified one. - */ - public void weaveAfterReturning(BcelAdvice munger) { - List<InstructionHandle> returns = findReturnInstructions(); - boolean hasReturnInstructions = !returns.isEmpty(); - - // list of instructions that handle the actual return from the join point - InstructionList retList = new InstructionList(); - - // variable that holds the return value - BcelVar returnValueVar = null; - - if (hasReturnInstructions) { - returnValueVar = generateReturnInstructions(returns, retList); - } else { - // we need at least one instruction, as the target for jumps - retList.append(InstructionConstants.NOP); - } - - // list of instructions for dispatching to the advice itself - InstructionList advice = getAfterReturningAdviceDispatchInstructions(munger, retList.getStart()); - - if (hasReturnInstructions) { - InstructionHandle gotoTarget = advice.getStart(); - for (Iterator<InstructionHandle> i = returns.iterator(); i.hasNext();) { - InstructionHandle ih = i.next(); - retargetReturnInstruction(munger.hasExtraParameter(), returnValueVar, gotoTarget, ih); - } - } - - range.append(advice); - range.append(retList); - } - - /** - * @return a list of all the return instructions in the range of this shadow - */ - private List<InstructionHandle> findReturnInstructions() { - List<InstructionHandle> returns = new ArrayList<InstructionHandle>(); - for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { - if (ih.getInstruction().isReturnInstruction()) { - returns.add(ih); - } - } - return returns; - } - - /** - * Given a list containing all the return instruction handles for this shadow, finds the last return instruction and copies it, - * making this the ultimate return. If the shadow has a non-void return type, we also create a temporary variable to hold the - * return value, and load the value from this var before returning (see pr148007 for why we do this - it works around a JRockit - * bug, and is also closer to what javac generates) - * - * Sometimes the 'last return' isnt the right one - some rogue code can include the real return from the body of a subroutine - * that exists at the end of the method. In this case the last return is RETURN but that may not be correct for a method with a - * non-void return type... pr151673 - * - * @param returns list of all the return instructions in the shadow - * @param returnInstructions instruction list into which the return instructions should be generated - * @return the variable holding the return value, if needed - */ - private BcelVar generateReturnInstructions(List<InstructionHandle> returns, InstructionList returnInstructions) { - BcelVar returnValueVar = null; - if (this.hasANonVoidReturnType()) { - // Find the last *correct* return - this is a method with a non-void return type - // so ignore RETURN - Instruction newReturnInstruction = null; - int i = returns.size() - 1; - while (newReturnInstruction == null && i >= 0) { - InstructionHandle ih = returns.get(i); - if (ih.getInstruction().opcode != Constants.RETURN) { - newReturnInstruction = Utility.copyInstruction(ih.getInstruction()); - } - i--; - } - returnValueVar = genTempVar(this.getReturnType()); - returnValueVar.appendLoad(returnInstructions, getFactory()); - returnInstructions.append(newReturnInstruction); - } else { - InstructionHandle lastReturnHandle = returns.get(returns.size() - 1); - Instruction newReturnInstruction = Utility.copyInstruction(lastReturnHandle.getInstruction()); - returnInstructions.append(newReturnInstruction); - } - return returnValueVar; - } - - /** - * @return true, iff this shadow returns a value - */ - private boolean hasANonVoidReturnType() { - return !this.getReturnType().equals(UnresolvedType.VOID); - } - - /** - * Get the list of instructions used to dispatch to the after advice - * - * @param munger - * @param firstInstructionInReturnSequence - * @return - */ - private InstructionList getAfterReturningAdviceDispatchInstructions(BcelAdvice munger, - InstructionHandle firstInstructionInReturnSequence) { - InstructionList advice = new InstructionList(); - - BcelVar tempVar = null; - if (munger.hasExtraParameter()) { - tempVar = insertAdviceInstructionsForBindingReturningParameter(advice); - } - advice.append(munger.getAdviceInstructions(this, tempVar, firstInstructionInReturnSequence)); - return advice; - } - - /** - * If the after() returning(Foo f) form is used, bind the return value to the parameter. If the shadow returns void, bind null. - * - * @param advice - * @return - */ - private BcelVar insertAdviceInstructionsForBindingReturningParameter(InstructionList advice) { - BcelVar tempVar; - UnresolvedType tempVarType = getReturnType(); - if (tempVarType.equals(UnresolvedType.VOID)) { - tempVar = genTempVar(UnresolvedType.OBJECT); - advice.append(InstructionConstants.ACONST_NULL); - tempVar.appendStore(advice, getFactory()); - } else { - tempVar = genTempVar(tempVarType); - advice.append(InstructionFactory.createDup(tempVarType.getSize())); - tempVar.appendStore(advice, getFactory()); - } - return tempVar; - } - - /** - * Helper method for weaveAfterReturning - * - * Each return instruction in the method body is retargeted by calling this method. The return instruction is replaced by up to - * three instructions: 1) if the shadow returns a value, and that value is bound to an after returning parameter, then we DUP - * the return value on the top of the stack 2) if the shadow returns a value, we store it in the returnValueVar (it will be - * retrieved from here when we ultimately return after the advice dispatch) 3) if the return was the last instruction, we add a - * NOP (it will fall through to the advice dispatch), otherwise we add a GOTO that branches to the supplied gotoTarget (start of - * the advice dispatch) - */ - private void retargetReturnInstruction(boolean hasReturningParameter, BcelVar returnValueVar, InstructionHandle gotoTarget, - InstructionHandle returnHandle) { - // pr148007, work around JRockit bug - // replace ret with store into returnValueVar, followed by goto if not - // at the end of the instruction list... - InstructionList newInstructions = new InstructionList(); - if (returnValueVar != null) { - if (hasReturningParameter) { - // we have to dup the return val before consuming it... - newInstructions.append(InstructionFactory.createDup(this.getReturnType().getSize())); - } - // store the return value into this var - returnValueVar.appendStore(newInstructions, getFactory()); - } - if (!isLastInstructionInRange(returnHandle, range)) { - newInstructions.append(InstructionFactory.createBranchInstruction(Constants.GOTO, gotoTarget)); - } - if (newInstructions.isEmpty()) { - newInstructions.append(InstructionConstants.NOP); - } - Utility.replaceInstruction(returnHandle, newInstructions, enclosingMethod); - } - - private boolean isLastInstructionInRange(InstructionHandle ih, ShadowRange aRange) { - return ih.getNext() == aRange.getEnd(); - } - - public void weaveAfterThrowing(BcelAdvice munger, UnresolvedType catchType) { - // a good optimization would be not to generate anything here - // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even - // a shadow, inside me). - if (getRange().getStart().getNext() == getRange().getEnd()) { - return; - } - InstructionFactory fact = getFactory(); - InstructionList handler = new InstructionList(); - BcelVar exceptionVar = genTempVar(catchType); - exceptionVar.appendStore(handler, fact); - - // pr62642 - // I will now jump through some firey BCEL hoops to generate a trivial bit of code: - // if (exc instanceof ExceptionInInitializerError) - // throw (ExceptionInInitializerError)exc; - if (this.getEnclosingMethod().getName().equals("<clinit>")) { - ResolvedType eiieType = world.resolve("java.lang.ExceptionInInitializerError"); - ObjectType eiieBcelType = (ObjectType) BcelWorld.makeBcelType(eiieType); - InstructionList ih = new InstructionList(InstructionConstants.NOP); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createInstanceOf(eiieBcelType)); - InstructionBranch bi = InstructionFactory.createBranchInstruction(Constants.IFEQ, ih.getStart()); - handler.append(bi); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createCheckCast(eiieBcelType)); - handler.append(InstructionConstants.ATHROW); - handler.append(ih); - } - - InstructionList endHandler = new InstructionList(exceptionVar.createLoad(fact)); - handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart())); - handler.append(endHandler); - handler.append(InstructionConstants.ATHROW); - InstructionHandle handlerStart = handler.getStart(); - - if (isFallsThrough()) { - InstructionHandle jumpTarget = handler.append(InstructionConstants.NOP); - handler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); - } - InstructionHandle protectedEnd = handler.getStart(); - range.insert(handler, Range.InsideAfter); - - enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart, - (ObjectType) BcelWorld.makeBcelType(catchType), // ???Type.THROWABLE, - // high priority if our args are on the stack - getKind().hasHighPriorityExceptions()); - } - - // ??? this shares a lot of code with the above weaveAfterThrowing - // ??? would be nice to abstract that to say things only once - public void weaveSoftener(BcelAdvice munger, UnresolvedType catchType) { - // a good optimization would be not to generate anything here - // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even - // a shadow, inside me). - if (getRange().getStart().getNext() == getRange().getEnd()) { - return; - } - - InstructionFactory fact = getFactory(); - InstructionList handler = new InstructionList(); - InstructionList rtExHandler = new InstructionList(); - BcelVar exceptionVar = genTempVar(catchType); - - handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE)); - handler.append(InstructionFactory.createDup(1)); - handler.append(exceptionVar.createLoad(fact)); - handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>", Type.VOID, new Type[] { Type.THROWABLE }, - Constants.INVOKESPECIAL)); // ??? special - handler.append(InstructionConstants.ATHROW); - - // ENH 42737 - exceptionVar.appendStore(rtExHandler, fact); - // aload_1 - rtExHandler.append(exceptionVar.createLoad(fact)); - // instanceof class java/lang/RuntimeException - rtExHandler.append(fact.createInstanceOf(new ObjectType("java.lang.RuntimeException"))); - // ifeq go to new SOFT_EXCEPTION_TYPE instruction - rtExHandler.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, handler.getStart())); - // aload_1 - rtExHandler.append(exceptionVar.createLoad(fact)); - // athrow - rtExHandler.append(InstructionFactory.ATHROW); - - InstructionHandle handlerStart = rtExHandler.getStart(); - - if (isFallsThrough()) { - InstructionHandle jumpTarget = range.getEnd();// handler.append(fact.NOP); - rtExHandler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget)); - } - - rtExHandler.append(handler); - - InstructionHandle protectedEnd = rtExHandler.getStart(); - range.insert(rtExHandler, Range.InsideAfter); - - enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart, - (ObjectType) BcelWorld.makeBcelType(catchType), - // high priority if our args are on the stack - getKind().hasHighPriorityExceptions()); - } - - public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) { - final InstructionFactory fact = getFactory(); - - InstructionList entryInstructions = new InstructionList(); - InstructionList entrySuccessInstructions = new InstructionList(); - onVar.appendLoad(entrySuccessInstructions, fact); - - entrySuccessInstructions - .append(Utility.createInvoke(fact, world, AjcMemberMaker.perObjectBind(munger.getConcreteAspect()))); - - InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(), - range.getRealStart(), entrySuccessInstructions.getStart()); - - entryInstructions.append(testInstructions); - entryInstructions.append(entrySuccessInstructions); - - range.insert(entryInstructions, Range.InsideBefore); - } - - // PTWIMPL Create static initializer to call the aspect factory - /** - * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf() - */ - public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger, UnresolvedType t) { - ResolvedType tResolved = t.resolve(world); - if (tResolved.isInterface()) { - return; // Don't initialize statics in interfaces - } - ResolvedType aspectRT = munger.getConcreteAspect(); - BcelWorld.getBcelObjectType(aspectRT); - - // Although matched, if the visibility rules prevent the aspect from seeing this type, don't - // insert any code (easier to do it here than try to affect the matching logic, unfortunately) - if (!(tResolved.canBeSeenBy(aspectRT) || aspectRT.isPrivilegedAspect())) { - return; - } - - final InstructionFactory fact = getFactory(); - - InstructionList entryInstructions = new InstructionList(); - InstructionList entrySuccessInstructions = new InstructionList(); - - String aspectname = munger.getConcreteAspect().getName(); - - String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect()); - entrySuccessInstructions.append(InstructionFactory.PUSH(fact.getConstantPool(), t.getName())); - - entrySuccessInstructions.append(fact.createInvoke(aspectname, "ajc$createAspectInstance", new ObjectType(aspectname), - new Type[] { new ObjectType("java.lang.String") }, Constants.INVOKESTATIC)); - entrySuccessInstructions.append(fact.createPutStatic(t.getName(), ptwField, new ObjectType(aspectname))); - - entryInstructions.append(entrySuccessInstructions); - - range.insert(entryInstructions, Range.InsideBefore); - } - - public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) { - final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || munger.getKind() == AdviceKind.PerCflowEntry; - if (!isPer && getKind() == PreInitialization) { - return; - } - final Type objectArrayType = new ArrayType(Type.OBJECT, 1); - final InstructionFactory fact = getFactory(); - - final BcelVar testResult = genTempVar(UnresolvedType.BOOLEAN); - - InstructionList entryInstructions = new InstructionList(); - { - InstructionList entrySuccessInstructions = new InstructionList(); - - if (munger.hasDynamicTests()) { - entryInstructions.append(Utility.createConstant(fact, 0)); - testResult.appendStore(entryInstructions, fact); - - entrySuccessInstructions.append(Utility.createConstant(fact, 1)); - testResult.appendStore(entrySuccessInstructions, fact); - } - - if (isPer) { - entrySuccessInstructions.append(fact.createInvoke(munger.getConcreteAspect().getName(), - NameMangler.PERCFLOW_PUSH_METHOD, Type.VOID, new Type[] {}, Constants.INVOKESTATIC)); - } else { - BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars(false); - - if (cflowStateVars.length == 0) { - // This should be getting managed by a counter - lets make sure. - if (!cflowField.getType().getName().endsWith("CFlowCounter")) { - throw new RuntimeException("Incorrectly attempting counter operation on stacked cflow"); - } - entrySuccessInstructions.append(Utility.createGet(fact, cflowField)); - // arrayVar.appendLoad(entrySuccessInstructions, fact); - entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "inc", Type.VOID, - new Type[] {}, Constants.INVOKEVIRTUAL)); - } else { - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - - int alen = cflowStateVars.length; - entrySuccessInstructions.append(Utility.createConstant(fact, alen)); - entrySuccessInstructions.append(fact.createNewArray(Type.OBJECT, (short) 1)); - arrayVar.appendStore(entrySuccessInstructions, fact); - - for (int i = 0; i < alen; i++) { - arrayVar.appendConvertableArrayStore(entrySuccessInstructions, fact, i, cflowStateVars[i]); - } - - entrySuccessInstructions.append(Utility.createGet(fact, cflowField)); - arrayVar.appendLoad(entrySuccessInstructions, fact); - - entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, - new Type[] { objectArrayType }, Constants.INVOKEVIRTUAL)); - } - } - - InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(), - range.getRealStart(), entrySuccessInstructions.getStart()); - entryInstructions.append(testInstructions); - entryInstructions.append(entrySuccessInstructions); - } - - BcelAdvice exitAdvice = new BcelAdvice(null, null, null, 0, 0, 0, null, munger.getConcreteAspect()) { - @Override - public InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) { - InstructionList exitInstructions = new InstructionList(); - if (munger.hasDynamicTests()) { - testResult.appendLoad(exitInstructions, fact); - exitInstructions.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, ifNoAdvice)); - } - exitInstructions.append(Utility.createGet(fact, cflowField)); - if (munger.getKind() != AdviceKind.PerCflowEntry && munger.getKind() != AdviceKind.PerCflowBelowEntry - && munger.getExposedStateAsBcelVars(false).length == 0) { - exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "dec", Type.VOID, new Type[] {}, - Constants.INVOKEVIRTUAL)); - } else { - exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "pop", Type.VOID, new Type[] {}, - Constants.INVOKEVIRTUAL)); - } - return exitInstructions; - } - }; -// if (getKind() == PreInitialization) { -// weaveAfterReturning(exitAdvice); -// } -// else { - weaveAfter(exitAdvice); -// } - - range.insert(entryInstructions, Range.InsideBefore); - } - - /* - * Implementation notes: - * - * AroundInline still extracts the instructions of the original shadow into an extracted method. This allows inlining of even - * that advice that doesn't call proceed or calls proceed more than once. - * - * It extracts the instructions of the original shadow into a method. - * - * Then it extracts the instructions of the advice into a new method defined on this enclosing class. This new method can then - * be specialized as below. - * - * Then it searches in the instructions of the advice for any call to the proceed method. - * - * At such a call, there is stuff on the stack representing the arguments to proceed. Pop these into the frame. - * - * Now build the stack for the call to the extracted method, taking values either from the join point state or from the new - * frame locs from proceed. Now call the extracted method. The right return value should be on the stack, so no cast is - * necessary. - * - * If only one call to proceed is made, we can re-inline the original shadow. We are not doing that presently. - * - * If the body of the advice can be determined to not alter the stack, or if this shadow doesn't care about the stack, i.e. - * method-execution, then the new method for the advice can also be re-lined. We are not doing that presently. - */ - public void weaveAroundInline(BcelAdvice munger, boolean hasDynamicTest) { - // !!! THIS BLOCK OF CODE SHOULD BE IN A METHOD CALLED weaveAround(...); - Member mungerSig = munger.getSignature(); - // Member originalSig = mungerSig; // If mungerSig is on a parameterized type, originalSig is the member on the generic type - if (mungerSig instanceof ResolvedMember) { - ResolvedMember rm = (ResolvedMember) mungerSig; - if (rm.hasBackingGenericMember()) { - mungerSig = rm.getBackingGenericMember(); - } - } - ResolvedType declaringAspectType = world.resolve(mungerSig.getDeclaringType(), true); - if (declaringAspectType.isMissing()) { - world.getLint().cantFindType.signal( - new String[] { WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE, - declaringAspectType.getClassName()) }, getSourceLocation(), - new ISourceLocation[] { munger.getSourceLocation() }); - } - - // ??? might want some checks here to give better errors - ResolvedType rt = (declaringAspectType.isParameterizedType() ? declaringAspectType.getGenericType() : declaringAspectType); - BcelObjectType ot = BcelWorld.getBcelObjectType(rt); - LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig); - if (!adviceMethod.getCanInline()) { - weaveAroundClosure(munger, hasDynamicTest); - return; - } - - // specific test for @AJ proceedInInners - if (isAnnotationStylePassingProceedingJoinPointOutOfAdvice(munger, hasDynamicTest, adviceMethod)) { - return; - } - - // We can't inline around methods if they have around advice on them, this - // is because the weaving will extract the body and hence the proceed call. - - // TODO should consider optimizations to recognize simple cases that don't require body extraction - - enclosingMethod.setCanInline(false); - - LazyClassGen shadowClass = getEnclosingClass(); - - // Extract the shadow into a new method. For example: - // "private static final void method_aroundBody0(M, M, String, org.aspectj.lang.JoinPoint)" - // Parameters are: this if there is one, target if there is one and its different to this, then original arguments - // at the shadow, then tjp - String extractedShadowMethodName = NameMangler.aroundShadowMethodName(getSignature(), shadowClass.getNewGeneratedNameTag()); - List<String> parameterNames = new ArrayList<String>(); - boolean shadowClassIsInterface = shadowClass.isInterface(); - LazyMethodGen extractedShadowMethod = extractShadowInstructionsIntoNewMethod(extractedShadowMethodName, - shadowClassIsInterface?Modifier.PUBLIC:Modifier.PRIVATE, - munger.getSourceLocation(), parameterNames,shadowClassIsInterface); - - List<BcelVar> argsToCallLocalAdviceMethodWith = new ArrayList<BcelVar>(); - List<BcelVar> proceedVarList = new ArrayList<BcelVar>(); - int extraParamOffset = 0; - - // Create the extra parameters that are needed for passing to proceed - // This code is very similar to that found in makeCallToCallback and should - // be rationalized in the future - - if (thisVar != null) { - argsToCallLocalAdviceMethodWith.add(thisVar); - proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset)); - extraParamOffset += thisVar.getType().getSize(); - } - - if (targetVar != null && targetVar != thisVar) { - argsToCallLocalAdviceMethodWith.add(targetVar); - proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset)); - extraParamOffset += targetVar.getType().getSize(); - } - for (int i = 0, len = getArgCount(); i < len; i++) { - argsToCallLocalAdviceMethodWith.add(argVars[i]); - proceedVarList.add(new BcelVar(argVars[i].getType(), extraParamOffset)); - extraParamOffset += argVars[i].getType().getSize(); - } - if (thisJoinPointVar != null) { - argsToCallLocalAdviceMethodWith.add(thisJoinPointVar); - proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset)); - extraParamOffset += thisJoinPointVar.getType().getSize(); - } - - // We use the munger signature here because it allows for any parameterization of the mungers pointcut that - // may have occurred ie. if the pointcut is p(T t) in the super aspect and that has become p(Foo t) in the sub aspect - // then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be - // 'Object' - since it represents the advice method in the superaspect which uses the erasure of the type variable p(Object - // t) - see pr174449. - - Type[] adviceParameterTypes = BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes()); - - // forces initialization ... dont like this but seems to be required for some tests to pass, I think that means there - // is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have - // time right now to discover which - adviceMethod.getArgumentTypes(); - - Type[] extractedMethodParameterTypes = extractedShadowMethod.getArgumentTypes(); - - Type[] parameterTypes = new Type[extractedMethodParameterTypes.length + adviceParameterTypes.length + 1]; - int parameterIndex = 0; - System.arraycopy(extractedMethodParameterTypes, 0, parameterTypes, parameterIndex, extractedMethodParameterTypes.length); - parameterIndex += extractedMethodParameterTypes.length; - parameterTypes[parameterIndex++] = BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType()); - System.arraycopy(adviceParameterTypes, 0, parameterTypes, parameterIndex, adviceParameterTypes.length); - - // Extract the advice into a new method. This will go in the same type as the shadow - // name will be something like foo_aroundBody1$advice - String localAdviceMethodName = NameMangler.aroundAdviceMethodName(getSignature(), shadowClass.getNewGeneratedNameTag()); - int localAdviceMethodModifiers = Modifier.PRIVATE | (world.useFinal() & !shadowClassIsInterface ? Modifier.FINAL : 0) | Modifier.STATIC; - LazyMethodGen localAdviceMethod = new LazyMethodGen(localAdviceMethodModifiers, BcelWorld.makeBcelType(mungerSig.getReturnType()), localAdviceMethodName, parameterTypes, - NoDeclaredExceptions, shadowClass); - - // Doesnt work properly, so leave it out: - // String aspectFilename = adviceMethod.getEnclosingClass().getInternalFileName(); - // String shadowFilename = shadowClass.getInternalFileName(); - // if (!aspectFilename.equals(shadowFilename)) { - // localAdviceMethod.fromFilename = aspectFilename; - // shadowClass.addInlinedSourceFileInfo(aspectFilename, adviceMethod.highestLineNumber); - // } - - shadowClass.addMethodGen(localAdviceMethod); - - // create a map that will move all slots in advice method forward by extraParamOffset - // in order to make room for the new proceed-required arguments that are added at - // the beginning of the parameter list - int nVars = adviceMethod.getMaxLocals() + extraParamOffset; - IntMap varMap = IntMap.idMap(nVars); - for (int i = extraParamOffset; i < nVars; i++) { - varMap.put(i - extraParamOffset, i); - } - - final InstructionFactory fact = getFactory(); - - localAdviceMethod.getBody().insert( - BcelClassWeaver.genInlineInstructions(adviceMethod, localAdviceMethod, varMap, fact, true)); - - localAdviceMethod.setMaxLocals(nVars); - - // the shadow is now empty. First, create a correct call - // to the around advice. This includes both the call (which may involve - // value conversion of the advice arguments) and the return - // (which may involve value conversion of the return value). Right now - // we push a null for the unused closure. It's sad, but there it is. - - InstructionList advice = new InstructionList(); - // InstructionHandle adviceMethodInvocation; - { - for (Iterator<BcelVar> i = argsToCallLocalAdviceMethodWith.iterator(); i.hasNext();) { - BcelVar var = i.next(); - var.appendLoad(advice, fact); - } - // ??? we don't actually need to push NULL for the closure if we take care - boolean isAnnoStyleConcreteAspect = munger.getConcreteAspect().isAnnotationStyleAspect(); - boolean isAnnoStyleDeclaringAspect = munger.getDeclaringAspect() != null ? munger.getDeclaringAspect().resolve(world) - .isAnnotationStyleAspect() : false; - - InstructionList iList = null; - if (isAnnoStyleConcreteAspect && isAnnoStyleDeclaringAspect) { - iList = this.loadThisJoinPoint(); - iList.append(Utility.createConversion(getFactory(), LazyClassGen.tjpType, LazyClassGen.proceedingTjpType)); - } else { - iList = new InstructionList(InstructionConstants.ACONST_NULL); - } - advice.append(munger.getAdviceArgSetup(this, null, iList)); - // adviceMethodInvocation = - advice.append(Utility.createInvoke(fact, localAdviceMethod)); // (fact, getWorld(), munger.getSignature())); - advice.append(Utility.createConversion(getFactory(), BcelWorld.makeBcelType(mungerSig.getReturnType()), - extractedShadowMethod.getReturnType(), world.isInJava5Mode())); - if (!isFallsThrough()) { - advice.append(InstructionFactory.createReturn(extractedShadowMethod.getReturnType())); - } - } - - // now, situate the call inside the possible dynamic tests, - // and actually add the whole mess to the shadow - if (!hasDynamicTest) { - range.append(advice); - } else { - InstructionList afterThingie = new InstructionList(InstructionConstants.NOP); - InstructionList callback = makeCallToCallback(extractedShadowMethod); - if (terminatesWithReturn()) { - callback.append(InstructionFactory.createReturn(extractedShadowMethod.getReturnType())); - } else { - // InstructionHandle endNop = range.insert(fact.NOP, Range.InsideAfter); - advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO, afterThingie.getStart())); - } - range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); - range.append(advice); - range.append(callback); - range.append(afterThingie); - } - - // now search through the advice, looking for a call to PROCEED. - // Then we replace the call to proceed with some argument setup, and a - // call to the extracted method. - - // inlining support for code style aspects - if (!munger.getDeclaringType().isAnnotationStyleAspect()) { - String proceedName = NameMangler.proceedMethodName(munger.getSignature().getName()); - - InstructionHandle curr = localAdviceMethod.getBody().getStart(); - InstructionHandle end = localAdviceMethod.getBody().getEnd(); - ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst.opcode == Constants.INVOKESTATIC) && proceedName.equals(((InvokeInstruction) inst).getMethodName(cpg))) { - - localAdviceMethod.getBody().append(curr, - getRedoneProceedCall(fact, extractedShadowMethod, munger, localAdviceMethod, proceedVarList)); - Utility.deleteInstruction(curr, localAdviceMethod); - } - curr = next; - } - // and that's it. - } else { - // ATAJ inlining support for @AJ aspects - // [TODO document @AJ code rule: don't manipulate 2 jps proceed at the same time.. in an advice body] - InstructionHandle curr = localAdviceMethod.getBody().getStart(); - InstructionHandle end = localAdviceMethod.getBody().getEnd(); - ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst instanceof INVOKEINTERFACE) && "proceed".equals(((INVOKEINTERFACE) inst).getMethodName(cpg))) { - final boolean isProceedWithArgs; - if (((INVOKEINTERFACE) inst).getArgumentTypes(cpg).length == 1) { - // proceed with args as a boxed Object[] - isProceedWithArgs = true; - } else { - isProceedWithArgs = false; - } - InstructionList insteadProceedIl = getRedoneProceedCallForAnnotationStyle(fact, extractedShadowMethod, munger, - localAdviceMethod, proceedVarList, isProceedWithArgs); - localAdviceMethod.getBody().append(curr, insteadProceedIl); - Utility.deleteInstruction(curr, localAdviceMethod); - } - curr = next; - } - } - - // if (parameterNames.size() == 0) { - // On return we have inserted the advice body into the local advice method. We have remapped all the local variables - // that were referenced in the advice as we did the copy, and so the local variable table for localAdviceMethod is - // now lacking any information about all the initial variables. - InstructionHandle start = localAdviceMethod.getBody().getStart(); - InstructionHandle end = localAdviceMethod.getBody().getEnd(); - - // Find the real start and end - while (start.getInstruction().opcode == Constants.IMPDEP1) { - start = start.getNext(); - } - while (end.getInstruction().opcode == Constants.IMPDEP1) { - end = end.getPrev(); - } - Type[] args = localAdviceMethod.getArgumentTypes(); - int argNumber = 0; - for (int slot = 0; slot < extraParamOffset; argNumber++) { // slot will increase by the argument size each time - String argumentName = null; - if (argNumber >= args.length || parameterNames.size() == 0 || argNumber >= parameterNames.size()) { - // this should be unnecessary as I think all known joinpoints and helper methods - // propagate the parameter names around correctly - but just in case let us do this - // rather than fail. If a bug is raised reporting unknown as a local variable name - // then investigate the joinpoint giving rise to the ResolvedMember and why it has - // no parameter names specified - argumentName = new StringBuffer("unknown").append(argNumber).toString(); - } else { - argumentName = parameterNames.get(argNumber); - } - String argumentSignature = args[argNumber].getSignature(); - LocalVariableTag lvt = new LocalVariableTag(argumentSignature, argumentName, slot, 0); - start.addTargeter(lvt); - end.addTargeter(lvt); - slot += args[argNumber].getSize(); - } - } - - /** - * Check if the advice method passes a pjp parameter out via an invoke instruction - if so we can't risk inlining. - */ - private boolean isAnnotationStylePassingProceedingJoinPointOutOfAdvice(BcelAdvice munger, boolean hasDynamicTest, - LazyMethodGen adviceMethod) { - if (munger.getConcreteAspect().isAnnotationStyleAspect()) { - // if we can't find one proceed() we suspect that the call - // is happening in an inner class so we don't inline it. - // Note: for code style, this is done at Aspect compilation time. - boolean canSeeProceedPassedToOther = false; - InstructionHandle curr = adviceMethod.getBody().getStart(); - InstructionHandle end = adviceMethod.getBody().getEnd(); - ConstantPool cpg = adviceMethod.getEnclosingClass().getConstantPool(); - while (curr != end) { - InstructionHandle next = curr.getNext(); - Instruction inst = curr.getInstruction(); - if ((inst instanceof InvokeInstruction) - && ((InvokeInstruction) inst).getSignature(cpg).indexOf("Lorg/aspectj/lang/ProceedingJoinPoint;") > 0) { - // we may want to refine to exclude stuff returning jp ? - // does code style skip inline if i write dump(thisJoinPoint) ? - canSeeProceedPassedToOther = true;// we see one pjp passed around - dangerous - break; - } - curr = next; - } - if (canSeeProceedPassedToOther) { - // remember this decision to avoid re-analysis - adviceMethod.setCanInline(false); - weaveAroundClosure(munger, hasDynamicTest); - return true; - } - } - return false; - } - - private InstructionList getRedoneProceedCall(InstructionFactory fact, LazyMethodGen callbackMethod, BcelAdvice munger, - LazyMethodGen localAdviceMethod, List<BcelVar> argVarList) { - InstructionList ret = new InstructionList(); - // we have on stack all the arguments for the ADVICE call. - // we have in frame somewhere all the arguments for the non-advice call. - - BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true); - IntMap proceedMap = makeProceedArgumentMap(adviceVars); - - // System.out.println(proceedMap + " for " + this); - // System.out.println(argVarList); - - ResolvedType[] proceedParamTypes = world.resolve(munger.getSignature().getParameterTypes()); - // remove this*JoinPoint* as arguments to proceed - if (munger.getBaseParameterCount() + 1 < proceedParamTypes.length) { - int len = munger.getBaseParameterCount() + 1; - ResolvedType[] newTypes = new ResolvedType[len]; - System.arraycopy(proceedParamTypes, 0, newTypes, 0, len); - proceedParamTypes = newTypes; - } - - // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - BcelVar[] proceedVars = Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); - - Type[] stateTypes = callbackMethod.getArgumentTypes(); - // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - - for (int i = 0, len = stateTypes.length; i < len; i++) { - Type stateType = stateTypes[i]; - ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); - if (proceedMap.hasKey(i)) { - // throw new RuntimeException("unimplemented"); - proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); - } else { - argVarList.get(i).appendLoad(ret, fact); - } - } - - ret.append(Utility.createInvoke(fact, callbackMethod)); - ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), - BcelWorld.makeBcelType(munger.getSignature().getReturnType()), world.isInJava5Mode())); - return ret; - } - - // private static boolean bindsThisOrTarget(Pointcut pointcut) { - // ThisTargetFinder visitor = new ThisTargetFinder(); - // pointcut.accept(visitor, null); - // return visitor.bindsThisOrTarget; - // } - - // private static class ThisTargetFinder extends IdentityPointcutVisitor { - // boolean bindsThisOrTarget = false; - // - // public Object visit(ThisOrTargetPointcut node, Object data) { - // if (node.isBinding()) { - // bindsThisOrTarget = true; - // } - // return node; - // } - // - // public Object visit(AndPointcut node, Object data) { - // if (!bindsThisOrTarget) node.getLeft().accept(this, data); - // if (!bindsThisOrTarget) node.getRight().accept(this, data); - // return node; - // } - // - // public Object visit(NotPointcut node, Object data) { - // if (!bindsThisOrTarget) node.getNegatedPointcut().accept(this, data); - // return node; - // } - // - // public Object visit(OrPointcut node, Object data) { - // if (!bindsThisOrTarget) node.getLeft().accept(this, data); - // if (!bindsThisOrTarget) node.getRight().accept(this, data); - // return node; - // } - // } - - /** - * Annotation style handling for inlining. - * - * Note: The proceedingjoinpoint is already on the stack (since the user was calling pjp.proceed(...) - * - * The proceed map is ignored (in terms of argument repositioning) since we have a fixed expected format for annotation style. - * The aim here is to change the proceed() call into a call to the xxx_aroundBody0 method. - * - * - */ - private InstructionList getRedoneProceedCallForAnnotationStyle(InstructionFactory fact, LazyMethodGen callbackMethod, - BcelAdvice munger, LazyMethodGen localAdviceMethod, List<BcelVar> argVarList, boolean isProceedWithArgs) { - InstructionList ret = new InstructionList(); - - // store the Object[] array on stack if proceed with args - if (isProceedWithArgs) { - - // STORE the Object[] into a local variable - Type objectArrayType = Type.OBJECT_ARRAY; - int theObjectArrayLocalNumber = localAdviceMethod.allocateLocal(objectArrayType); - ret.append(InstructionFactory.createStore(objectArrayType, theObjectArrayLocalNumber)); - - // STORE the ProceedingJoinPoint instance into a local variable - Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); - int pjpLocalNumber = localAdviceMethod.allocateLocal(proceedingJpType); - ret.append(InstructionFactory.createStore(proceedingJpType, pjpLocalNumber)); - - // Aim here initially is to determine whether the user will have provided a new - // this/target in the object array and consume them if they have, leaving us the rest of - // the arguments to process as regular arguments to the invocation at the original join point - - boolean pointcutBindsThis = bindsThis(munger); - boolean pointcutBindsTarget = bindsTarget(munger); - boolean targetIsSameAsThis = getKind().isTargetSameAsThis(); - - int nextArgumentToProvideForCallback = 0; - - if (hasThis()) { - if (!(pointcutBindsTarget && targetIsSameAsThis)) { - if (pointcutBindsThis) { - // they have supplied new this as first entry in object array, consume it - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, 0)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0])); - } else { - // use local variable 0 - ret.append(InstructionFactory.createALOAD(0)); - } - nextArgumentToProvideForCallback++; - } - } - - if (hasTarget()) { - if (pointcutBindsTarget) { - if (getKind().isTargetSameAsThis()) { - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, pointcutBindsThis ? 1 : 0)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0])); - } else { - int position = (hasThis() && pointcutBindsThis)? 1 : 0; - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility.createConstant(fact, position)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[nextArgumentToProvideForCallback])); - } - nextArgumentToProvideForCallback++; - } else { - if (getKind().isTargetSameAsThis()) { - // ret.append(new ALOAD(0)); - } else { - ret.append(InstructionFactory.createLoad(localAdviceMethod.getArgumentTypes()[0], hasThis() ? 1 : 0)); - nextArgumentToProvideForCallback++; - } - } - } - - // Where to start in the object array in order to pick up arguments - int indexIntoObjectArrayForArguments = (pointcutBindsThis ? 1 : 0) + (pointcutBindsTarget ? 1 : 0); - - int len = callbackMethod.getArgumentTypes().length; - for (int i = nextArgumentToProvideForCallback; i < len; i++) { - Type stateType = callbackMethod.getArgumentTypes()[i]; - BcelWorld.fromBcel(stateType).resolve(world); - if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { - ret.append(new InstructionLV(Constants.ALOAD, pjpLocalNumber)); - } else { - ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber)); - ret.append(Utility - .createConstant(fact, i - nextArgumentToProvideForCallback + indexIntoObjectArrayForArguments)); - ret.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - ret.append(Utility.createConversion(fact, Type.OBJECT, stateType)); - } - } - - } else { - Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;"); - int localJp = localAdviceMethod.allocateLocal(proceedingJpType); - ret.append(InstructionFactory.createStore(proceedingJpType, localJp)); - - int idx = 0; - for (int i = 0, len = callbackMethod.getArgumentTypes().length; i < len; i++) { - Type stateType = callbackMethod.getArgumentTypes()[i]; - /* ResolvedType stateTypeX = */ - BcelWorld.fromBcel(stateType).resolve(world); - if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { - ret.append(InstructionFactory.createALOAD(localJp));// from localAdvice signature - // } else if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(stateType.getSignature())) { - // //FIXME ALEX? - // ret.append(new ALOAD(localJp));// from localAdvice signature - // // ret.append(fact.createCheckCast( - // // (ReferenceType) BcelWorld.makeBcelType(stateTypeX) - // // )); - // // cast ? - // - idx++; - } else { - ret.append(InstructionFactory.createLoad(stateType, idx)); - idx += stateType.getSize(); - } - } - } - - // do the callback invoke - ret.append(Utility.createInvoke(fact, callbackMethod)); - - // box it again. Handles cases where around advice does return something else than Object - if (!UnresolvedType.OBJECT.equals(munger.getSignature().getReturnType())) { - ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT)); - } - ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), - BcelWorld.makeBcelType(munger.getSignature().getReturnType()), world.isInJava5Mode())); - - return ret; - - // - // - // - // if (proceedMap.hasKey(i)) { - // ret.append(new ALOAD(i)); - // //throw new RuntimeException("unimplemented"); - // //proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); - // } else { - // //((BcelVar) argVarList.get(i)).appendLoad(ret, fact); - // //ret.append(new ALOAD(i)); - // if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) { - // ret.append(new ALOAD(i)); - // } else { - // ret.append(new ALOAD(i)); - // } - // } - // } - // - // ret.append(Utility.createInvoke(fact, callbackMethod)); - // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), - // BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); - // - // //ret.append(new ACONST_NULL());//will be POPed - // if (true) return ret; - // - // - // - // // we have on stack all the arguments for the ADVICE call. - // // we have in frame somewhere all the arguments for the non-advice call. - // - // BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(); - // IntMap proceedMap = makeProceedArgumentMap(adviceVars); - // - // System.out.println(proceedMap + " for " + this); - // System.out.println(argVarList); - // - // ResolvedType[] proceedParamTypes = - // world.resolve(munger.getSignature().getParameterTypes()); - // // remove this*JoinPoint* as arguments to proceed - // if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) { - // int len = munger.getBaseParameterCount()+1; - // ResolvedType[] newTypes = new ResolvedType[len]; - // System.arraycopy(proceedParamTypes, 0, newTypes, 0, len); - // proceedParamTypes = newTypes; - // } - // - // //System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - // BcelVar[] proceedVars = - // Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod); - // - // Type[] stateTypes = callbackMethod.getArgumentTypes(); - // // System.out.println("stateTypes: " + Arrays.asList(stateTypes)); - // - // for (int i=0, len=stateTypes.length; i < len; i++) { - // Type stateType = stateTypes[i]; - // ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); - // if (proceedMap.hasKey(i)) { - // //throw new RuntimeException("unimplemented"); - // proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); - // } else { - // ((BcelVar) argVarList.get(i)).appendLoad(ret, fact); - // } - // } - // - // ret.append(Utility.createInvoke(fact, callbackMethod)); - // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), - // BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); - // return ret; - } - - private boolean bindsThis(BcelAdvice munger) { - UsesThisVisitor utv = new UsesThisVisitor(); - munger.getPointcut().accept(utv, null); - return utv.usesThis; - } - - private boolean bindsTarget(BcelAdvice munger) { - UsesTargetVisitor utv = new UsesTargetVisitor(); - munger.getPointcut().accept(utv, null); - return utv.usesTarget; - } - - private static class UsesThisVisitor extends AbstractPatternNodeVisitor { - boolean usesThis = false; - - @Override - public Object visit(ThisOrTargetPointcut node, Object data) { - if (node.isThis() && node.isBinding()) { - usesThis = true; - } - return node; - } - - @Override - public Object visit(AndPointcut node, Object data) { - if (!usesThis) { - node.getLeft().accept(this, data); - } - if (!usesThis) { - node.getRight().accept(this, data); - } - return node; - } - - @Override - public Object visit(NotPointcut node, Object data) { - if (!usesThis) { - node.getNegatedPointcut().accept(this, data); - } - return node; - } - - @Override - public Object visit(OrPointcut node, Object data) { - if (!usesThis) { - node.getLeft().accept(this, data); - } - if (!usesThis) { - node.getRight().accept(this, data); - } - return node; - } - } - - private static class UsesTargetVisitor extends AbstractPatternNodeVisitor { - boolean usesTarget = false; - - @Override - public Object visit(ThisOrTargetPointcut node, Object data) { - if (!node.isThis() && node.isBinding()) { - usesTarget = true; - } - return node; - } - - @Override - public Object visit(AndPointcut node, Object data) { - if (!usesTarget) { - node.getLeft().accept(this, data); - } - if (!usesTarget) { - node.getRight().accept(this, data); - } - return node; - } - - @Override - public Object visit(NotPointcut node, Object data) { - if (!usesTarget) { - node.getNegatedPointcut().accept(this, data); - } - return node; - } - - @Override - public Object visit(OrPointcut node, Object data) { - if (!usesTarget) { - node.getLeft().accept(this, data); - } - if (!usesTarget) { - node.getRight().accept(this, data); - } - return node; - } - } - - public void weaveAroundClosure(BcelAdvice munger, boolean hasDynamicTest) { - InstructionFactory fact = getFactory(); - - enclosingMethod.setCanInline(false); - - int linenumber = getSourceLine(); - // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD! - - // callbackMethod will be something like: "static final void m_aroundBody0(I)" - boolean shadowClassIsInterface = getEnclosingClass().isInterface(); - LazyMethodGen callbackMethod = extractShadowInstructionsIntoNewMethod( - NameMangler.aroundShadowMethodName(getSignature(), getEnclosingClass().getNewGeneratedNameTag()), shadowClassIsInterface?Modifier.PUBLIC:0, - munger.getSourceLocation(), new ArrayList<String>(),shadowClassIsInterface); - - BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true); - - String closureClassName = NameMangler.makeClosureClassName(getEnclosingClass().getType(), getEnclosingClass() - .getNewGeneratedNameTag()); - - Member constructorSig = new MemberImpl(Member.CONSTRUCTOR, UnresolvedType.forName(closureClassName), 0, "<init>", - "([Ljava/lang/Object;)V"); - - BcelVar closureHolder = null; - - // This is not being used currently since getKind() == preinitializaiton - // cannot happen in around advice - if (getKind() == PreInitialization) { - closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE); - } - - InstructionList closureInstantiation = makeClosureInstantiation(constructorSig, closureHolder); - - /* LazyMethodGen constructor = */ - makeClosureClassAndReturnConstructor(closureClassName, callbackMethod, makeProceedArgumentMap(adviceVars)); - - InstructionList returnConversionCode; - if (getKind() == PreInitialization) { - returnConversionCode = new InstructionList(); - - BcelVar stateTempVar = genTempVar(UnresolvedType.OBJECTARRAY); - closureHolder.appendLoad(returnConversionCode, fact); - - returnConversionCode.append(Utility.createInvoke(fact, world, AjcMemberMaker.aroundClosurePreInitializationGetter())); - stateTempVar.appendStore(returnConversionCode, fact); - - Type[] stateTypes = getSuperConstructorParameterTypes(); - - returnConversionCode.append(InstructionConstants.ALOAD_0); // put "this" back on the stack - for (int i = 0, len = stateTypes.length; i < len; i++) { - UnresolvedType bcelTX = BcelWorld.fromBcel(stateTypes[i]); - ResolvedType stateRTX = world.resolve(bcelTX, true); - if (stateRTX.isMissing()) { - world.getLint().cantFindType.signal( - new String[] { WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT, - bcelTX.getClassName()) }, getSourceLocation(), - new ISourceLocation[] { munger.getSourceLocation() }); - // IMessage msg = new Message( - // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName()), - // "",IMessage.ERROR,getSourceLocation(),null, - // new ISourceLocation[]{ munger.getSourceLocation()}); - // world.getMessageHandler().handleMessage(msg); - } - stateTempVar.appendConvertableArrayLoad(returnConversionCode, fact, i, stateRTX); - } - } else { - // pr226201 - Member mungerSignature = munger.getSignature(); - if (munger.getSignature() instanceof ResolvedMember) { - if (((ResolvedMember) mungerSignature).hasBackingGenericMember()) { - mungerSignature = ((ResolvedMember) mungerSignature).getBackingGenericMember(); - } - } - UnresolvedType returnType = mungerSignature.getReturnType(); - returnConversionCode = Utility.createConversion(getFactory(), BcelWorld.makeBcelType(returnType), - callbackMethod.getReturnType(), world.isInJava5Mode()); - if (!isFallsThrough()) { - returnConversionCode.append(InstructionFactory.createReturn(callbackMethod.getReturnType())); - } - } - - // initialize the bit flags for this shadow - int bitflags = 0x000000; - if (getKind().isTargetSameAsThis()) { - bitflags |= 0x010000; - } - if (hasThis()) { - bitflags |= 0x001000; - } - if (bindsThis(munger)) { - bitflags |= 0x000100; - } - if (hasTarget()) { - bitflags |= 0x000010; - } - if (bindsTarget(munger)) { - bitflags |= 0x000001; - } - - // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance - if (munger.getConcreteAspect() != null && munger.getConcreteAspect().isAnnotationStyleAspect() - && munger.getDeclaringAspect() != null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { - // stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int - closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags))); - closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(), - new MemberImpl(Member.METHOD, UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"), - Modifier.PUBLIC, "linkClosureAndJoinPoint", String.format("%s%s", "(I)", "Lorg/aspectj/lang/ProceedingJoinPoint;")))); - } - - InstructionList advice = new InstructionList(); - advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation)); - - // invoke the advice - advice.append(munger.getNonTestAdviceInstructions(this)); - advice.append(returnConversionCode); - if (getKind() == Shadow.MethodExecution && linenumber > 0) { - advice.getStart().addTargeter(new LineNumberTag(linenumber)); - } - - if (!hasDynamicTest) { - range.append(advice); - } else { - InstructionList callback = makeCallToCallback(callbackMethod); - InstructionList postCallback = new InstructionList(); - if (terminatesWithReturn()) { - callback.append(InstructionFactory.createReturn(callbackMethod.getReturnType())); - } else { - advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO, - postCallback.append(InstructionConstants.NOP))); - } - range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); - range.append(advice); - range.append(callback); - range.append(postCallback); - } - } - - // exposed for testing - InstructionList makeCallToCallback(LazyMethodGen callbackMethod) { - InstructionFactory fact = getFactory(); - InstructionList callback = new InstructionList(); - if (thisVar != null) { - callback.append(InstructionConstants.ALOAD_0); - } - if (targetVar != null && targetVar != thisVar) { - callback.append(BcelRenderer.renderExpr(fact, world, targetVar)); - } - callback.append(BcelRenderer.renderExprs(fact, world, argVars)); - // remember to render tjps - if (thisJoinPointVar != null) { - callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar)); - } - callback.append(Utility.createInvoke(fact, callbackMethod)); - return callback; - } - - /** side-effect-free */ - private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) { - - // LazyMethodGen constructor) { - InstructionFactory fact = getFactory(); - BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY); - // final Type objectArrayType = new ArrayType(Type.OBJECT, 1); - final InstructionList il = new InstructionList(); - int alen = getArgCount() + (thisVar == null ? 0 : 1) + ((targetVar != null && targetVar != thisVar) ? 1 : 0) - + (thisJoinPointVar == null ? 0 : 1); - il.append(Utility.createConstant(fact, alen)); - il.append(fact.createNewArray(Type.OBJECT, (short) 1)); - arrayVar.appendStore(il, fact); - - int stateIndex = 0; - if (thisVar != null) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar); - thisVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - if (targetVar != null && targetVar != thisVar) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar); - targetVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - for (int i = 0, len = getArgCount(); i < len; i++) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]); - argVars[i].setPositionInAroundState(stateIndex); - stateIndex++; - } - if (thisJoinPointVar != null) { - arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar); - thisJoinPointVar.setPositionInAroundState(stateIndex); - stateIndex++; - } - il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName()))); - il.append(InstructionConstants.DUP); - arrayVar.appendLoad(il, fact); - il.append(Utility.createInvoke(fact, world, constructor)); - if (getKind() == PreInitialization) { - il.append(InstructionConstants.DUP); - holder.appendStore(il, fact); - } - return il; - } - - private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) { - // System.err.println("coming in with " + Arrays.asList(adviceArgs)); - - IntMap ret = new IntMap(); - for (int i = 0, len = adviceArgs.length; i < len; i++) { - BcelVar v = adviceArgs[i]; - if (v == null) { - continue; // XXX we don't know why this is required - } - int pos = v.getPositionInAroundState(); - if (pos >= 0) { // need this test to avoid args bound via cflow - ret.put(pos, i); - } - } - // System.err.println("returning " + ret); - - return ret; - } - - /** - * - * @param callbackMethod the method we will call back to when our run method gets called. - * @param proceedMap A map from state position to proceed argument position. May be non covering on state position. - */ - private LazyMethodGen makeClosureClassAndReturnConstructor(String closureClassName, LazyMethodGen callbackMethod, - IntMap proceedMap) { - String superClassName = "org.aspectj.runtime.internal.AroundClosure"; - Type objectArrayType = new ArrayType(Type.OBJECT, 1); - - LazyClassGen closureClass = new LazyClassGen(closureClassName, superClassName, getEnclosingClass().getFileName(), - Modifier.PUBLIC, new String[] {}, getWorld()); - closureClass.setMajorMinor(getEnclosingClass().getMajor(), getEnclosingClass().getMinor()); - InstructionFactory fact = new InstructionFactory(closureClass.getConstantPool()); - - // constructor - LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, "<init>", new Type[] { objectArrayType }, - new String[] {}, closureClass); - InstructionList cbody = constructor.getBody(); - cbody.append(InstructionFactory.createLoad(Type.OBJECT, 0)); - cbody.append(InstructionFactory.createLoad(objectArrayType, 1)); - cbody.append(fact - .createInvoke(superClassName, "<init>", Type.VOID, new Type[] { objectArrayType }, Constants.INVOKESPECIAL)); - cbody.append(InstructionFactory.createReturn(Type.VOID)); - - closureClass.addMethodGen(constructor); - - // Create the 'Object run(Object[])' method - LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC, Type.OBJECT, "run", new Type[] { objectArrayType }, - new String[] {}, closureClass); - InstructionList mbody = runMethod.getBody(); - BcelVar proceedVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), 1); - // int proceedVarIndex = 1; - BcelVar stateVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1)); - // int stateVarIndex = runMethod.allocateLocal(1); - mbody.append(InstructionFactory.createThis()); - mbody.append(fact.createGetField(superClassName, "state", objectArrayType)); - mbody.append(stateVar.createStore(fact)); - // mbody.append(fact.createStore(objectArrayType, stateVarIndex)); - - Type[] stateTypes = callbackMethod.getArgumentTypes(); - - for (int i = 0, len = stateTypes.length; i < len; i++) { - ResolvedType resolvedStateType = BcelWorld.fromBcel(stateTypes[i]).resolve(world); - if (proceedMap.hasKey(i)) { - mbody.append(proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i), resolvedStateType)); - } else { - mbody.append(stateVar.createConvertableArrayLoad(fact, i, resolvedStateType)); - } - } - - mbody.append(Utility.createInvoke(fact, callbackMethod)); - - if (getKind() == PreInitialization) { - mbody.append(Utility.createSet(fact, AjcMemberMaker.aroundClosurePreInitializationField())); - mbody.append(InstructionConstants.ACONST_NULL); - } else { - mbody.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT)); - } - mbody.append(InstructionFactory.createReturn(Type.OBJECT)); - - closureClass.addMethodGen(runMethod); - - // class - getEnclosingClass().addGeneratedInner(closureClass); - - return constructor; - } - - // ---- extraction methods - - /** - * Extract the instructions in the shadow to a new method. - * - * @param extractedMethodName name for the new method - * @param extractedMethodVisibilityModifier visibility modifiers for the new method - * @param adviceSourceLocation source location of the advice affecting the shadow - * @param beingPlacedInInterface is this new method going into an interface - */ - LazyMethodGen extractShadowInstructionsIntoNewMethod(String extractedMethodName, int extractedMethodVisibilityModifier, - ISourceLocation adviceSourceLocation, List<String> parameterNames, boolean beingPlacedInInterface) { - // LazyMethodGen.assertGoodBody(range.getBody(), extractedMethodName); - if (!getKind().allowsExtraction()) { - throw new BCException("Attempt to extract method from a shadow kind (" + getKind() - + ") that does not support this operation"); - } - LazyMethodGen newMethod = createShadowMethodGen(extractedMethodName, extractedMethodVisibilityModifier, parameterNames, beingPlacedInInterface); - IntMap remapper = makeRemap(); - range.extractInstructionsInto(newMethod, remapper, (getKind() != PreInitialization) && isFallsThrough()); - if (getKind() == PreInitialization) { - addPreInitializationReturnCode(newMethod, getSuperConstructorParameterTypes()); - } - getEnclosingClass().addMethodGen(newMethod, adviceSourceLocation); - return newMethod; - } - - private void addPreInitializationReturnCode(LazyMethodGen extractedMethod, Type[] superConstructorTypes) { - InstructionList body = extractedMethod.getBody(); - final InstructionFactory fact = getFactory(); - - BcelVar arrayVar = new BcelVar(world.getCoreType(UnresolvedType.OBJECTARRAY), extractedMethod.allocateLocal(1)); - - int len = superConstructorTypes.length; - - body.append(Utility.createConstant(fact, len)); - - body.append(fact.createNewArray(Type.OBJECT, (short) 1)); - arrayVar.appendStore(body, fact); - - for (int i = len - 1; i >= 0; i++) { - // convert thing on top of stack to object - body.append(Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT)); - // push object array - arrayVar.appendLoad(body, fact); - // swap - body.append(InstructionConstants.SWAP); - // do object array store. - body.append(Utility.createConstant(fact, i)); - body.append(InstructionConstants.SWAP); - body.append(InstructionFactory.createArrayStore(Type.OBJECT)); - } - arrayVar.appendLoad(body, fact); - body.append(InstructionConstants.ARETURN); - } - - private Type[] getSuperConstructorParameterTypes() { - // assert getKind() == PreInitialization - InstructionHandle superCallHandle = getRange().getEnd().getNext(); - InvokeInstruction superCallInstruction = (InvokeInstruction) superCallHandle.getInstruction(); - return superCallInstruction.getArgumentTypes(getEnclosingClass().getConstantPool()); - } - - /** - * make a map from old frame location to new frame location. Any unkeyed frame location picks out a copied local - */ - private IntMap makeRemap() { - IntMap ret = new IntMap(5); - int reti = 0; - if (thisVar != null) { - ret.put(0, reti++); // thisVar guaranteed to be 0 - } - if (targetVar != null && targetVar != thisVar) { - ret.put(targetVar.getSlot(), reti++); - } - for (int i = 0, len = argVars.length; i < len; i++) { - ret.put(argVars[i].getSlot(), reti); - reti += argVars[i].getType().getSize(); - } - if (thisJoinPointVar != null) { - ret.put(thisJoinPointVar.getSlot(), reti++); - } - // we not only need to put the arguments, we also need to remap their - // aliases, which we so helpfully put into temps at the beginning of this join - // point. - if (!getKind().argsOnStack()) { - int oldi = 0; - int newi = 0; - // if we're passing in a this and we're not argsOnStack we're always - // passing in a target too - if (arg0HoldsThis()) { - ret.put(0, 0); - oldi++; - newi += 1; - } - // assert targetVar == thisVar - for (int i = 0; i < getArgCount(); i++) { - UnresolvedType type = getArgType(i); - ret.put(oldi, newi); - oldi += type.getSize(); - newi += type.getSize(); - } - } - - // System.err.println("making remap for : " + this); - // if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot()); - // if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot()); - // System.err.println(ret); - - return ret; - } - - /** - * The new method always static. It may take some extra arguments: this, target. If it's argsOnStack, then it must take both - * this/target If it's argsOnFrame, it shares this and target. ??? rewrite this to do less array munging, please - */ - private LazyMethodGen createShadowMethodGen(String newMethodName, int visibilityModifier, List<String> parameterNames, boolean beingPlacedInInterface) { - Type[] shadowParameterTypes = BcelWorld.makeBcelTypes(getArgTypes()); - int modifiers = (world.useFinal() && !beingPlacedInInterface ? Modifier.FINAL : 0) | Modifier.STATIC | visibilityModifier; - if (targetVar != null && targetVar != thisVar) { - UnresolvedType targetType = getTargetType(); - targetType = ensureTargetTypeIsCorrect(targetType); - // see pr109728,pr229910 - this fixes the case when the declaring class is sometype 'X' but the (gs)etfield - // in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally - // mentioned in the fieldget instruction as the method parameter and *not* the type upon which the - // field is declared because when the instructions are extracted into the new around body, - // they will still refer to the subtype. - if ((getKind() == FieldGet || getKind() == FieldSet) && getActualTargetType() != null - && !getActualTargetType().equals(targetType.getName())) { - targetType = UnresolvedType.forName(getActualTargetType()).resolve(world); - } - ResolvedMember resolvedMember = getSignature().resolve(world); - - // pr230075, pr197719 - if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) - && !samePackage(resolvedMember.getDeclaringType().getPackageName(), getEnclosingType().getPackageName()) - && !resolvedMember.getName().equals("clone")) { - if (!hasThis()) { // pr197719 - static accessor has been created to handle the call - if (Modifier.isStatic(enclosingMethod.getAccessFlags()) && enclosingMethod.getName().startsWith("access$")) { - targetType = BcelWorld.fromBcel(enclosingMethod.getArgumentTypes()[0]); - } - } else { - if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) { - throw new BCException("bad bytecode"); - } - targetType = getThisType(); - } - } - parameterNames.add("target"); - // There is a 'target' and it is not the same as 'this', so add it to the parameter list - shadowParameterTypes = addTypeToFront(BcelWorld.makeBcelType(targetType), shadowParameterTypes); - } - - if (thisVar != null) { - UnresolvedType thisType = getThisType(); - parameterNames.add(0, "ajc$this"); - shadowParameterTypes = addTypeToFront(BcelWorld.makeBcelType(thisType), shadowParameterTypes); - } - - if (this.getKind() == Shadow.FieldSet || this.getKind() == Shadow.FieldGet) { - parameterNames.add(getSignature().getName()); - } else { - String[] pnames = getSignature().getParameterNames(world); - if (pnames != null) { - for (int i = 0; i < pnames.length; i++) { - if (i == 0 && pnames[i].equals("this")) { - parameterNames.add("ajc$this"); - } else { - parameterNames.add(pnames[i]); - } - } - } - } - - // We always want to pass down thisJoinPoint in case we have already woven - // some advice in here. If we only have a single piece of around advice on a - // join point, it is unnecessary to accept (and pass) tjp. - if (thisJoinPointVar != null) { - parameterNames.add("thisJoinPoint"); - shadowParameterTypes = addTypeToEnd(LazyClassGen.tjpType, shadowParameterTypes); - } - - UnresolvedType returnType; - if (getKind() == PreInitialization) { - returnType = UnresolvedType.OBJECTARRAY; - } else { - if (getKind() == ConstructorCall) { - returnType = getSignature().getDeclaringType(); - } else if (getKind() == FieldSet) { - returnType = UnresolvedType.VOID; - } else { - returnType = getSignature().getReturnType().resolve(world); - // returnType = getReturnType(); // for this and above lines, see pr137496 - } - } - return new LazyMethodGen(modifiers, BcelWorld.makeBcelType(returnType), newMethodName, shadowParameterTypes, - NoDeclaredExceptions, getEnclosingClass()); - } - - private boolean samePackage(String p1, String p2) { - if (p1 == null) { - return p2 == null; - } - if (p2 == null) { - return false; - } - return p1.equals(p2); - } - - private Type[] addTypeToFront(Type type, Type[] types) { - int len = types.length; - Type[] ret = new Type[len + 1]; - ret[0] = type; - System.arraycopy(types, 0, ret, 1, len); - return ret; - } - - private Type[] addTypeToEnd(Type type, Type[] types) { - int len = types.length; - Type[] ret = new Type[len + 1]; - ret[len] = type; - System.arraycopy(types, 0, ret, 0, len); - return ret; - } - - public BcelVar genTempVar(UnresolvedType utype) { - ResolvedType rtype = utype.resolve(world); - return new BcelVar(rtype, genTempVarIndex(rtype.getSize())); - } - - // public static final boolean CREATE_TEMP_NAMES = true; - - public BcelVar genTempVar(UnresolvedType typeX, String localName) { - BcelVar tv = genTempVar(typeX); - - // if (CREATE_TEMP_NAMES) { - // for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { - // if (Range.isRangeHandle(ih)) continue; - // ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot())); - // } - // } - return tv; - } - - // eh doesn't think we need to garbage collect these (64K is a big number...) - private int genTempVarIndex(int size) { - return enclosingMethod.allocateLocal(size); - } - - public InstructionFactory getFactory() { - return getEnclosingClass().getFactory(); - } - - @Override - public ISourceLocation getSourceLocation() { - int sourceLine = getSourceLine(); - if (sourceLine == 0 || sourceLine == -1) { - // Thread.currentThread().dumpStack(); - // System.err.println(this + ": " + range); - return getEnclosingClass().getType().getSourceLocation(); - } else { - // For staticinitialization, if we have a nice offset, don't build a new source loc - if (getKind() == Shadow.StaticInitialization && getEnclosingClass().getType().getSourceLocation().getOffset() != 0) { - return getEnclosingClass().getType().getSourceLocation(); - } else { - int offset = 0; - Kind kind = getKind(); - if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution) - || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) { - if (getEnclosingMethod().hasDeclaredLineNumberInfo()) { - offset = getEnclosingMethod().getDeclarationOffset(); - } - } - return getEnclosingClass().getType().getSourceContext().makeSourceLocation(sourceLine, offset); - } - } - } - - public Shadow getEnclosingShadow() { - return enclosingShadow; - } - - public LazyMethodGen getEnclosingMethod() { - return enclosingMethod; - } - - public boolean isFallsThrough() { - return !terminatesWithReturn(); - } - - public void setActualTargetType(String className) { - this.actualInstructionTargetType = className; - } - - public String getActualTargetType() { - return actualInstructionTargetType; - } -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java deleted file mode 100644 index b92760fe9..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java +++ /dev/null @@ -1,2116 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 @AspectJ ITDs - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.ClassFormatException; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Signature; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InvokeInstruction; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.asm.AsmManager; -import org.aspectj.asm.IProgramElement; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.bridge.WeaveMessage; -import org.aspectj.bridge.context.CompilationAndWeavingContext; -import org.aspectj.bridge.context.ContextToken; -import org.aspectj.weaver.AjcMemberMaker; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.AnnotationOnTypeMunger; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MemberUtils; -import org.aspectj.weaver.MethodDelegateTypeMunger; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.NewConstructorTypeMunger; -import org.aspectj.weaver.NewFieldTypeMunger; -import org.aspectj.weaver.NewMemberClassTypeMunger; -import org.aspectj.weaver.NewMethodTypeMunger; -import org.aspectj.weaver.NewParentTypeMunger; -import org.aspectj.weaver.PerObjectInterfaceTypeMunger; -import org.aspectj.weaver.PrivilegedAccessMunger; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.TypeVariableReference; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.WeaverStateInfo; -import org.aspectj.weaver.World; -import org.aspectj.weaver.model.AsmRelationshipProvider; -import org.aspectj.weaver.patterns.DeclareAnnotation; -import org.aspectj.weaver.patterns.Pointcut; - -public class BcelTypeMunger extends ConcreteTypeMunger { - - public BcelTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType) { - super(munger, aspectType); - } - - @Override - public String toString() { - return "(BcelTypeMunger " + getMunger() + ")"; - } - - @Override - public boolean shouldOverwrite() { - return false; - } - - public boolean munge(BcelClassWeaver weaver) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MUNGING_WITH, this); - boolean changed = false; - boolean worthReporting = true; - - if (weaver.getWorld().isOverWeaving()) { - WeaverStateInfo typeWeaverState = weaver.getLazyClassGen().getType().getWeaverState(); - if (typeWeaverState != null && typeWeaverState.isAspectAlreadyApplied(getAspectType())) { - return false; - } - } - - if (munger.getKind() == ResolvedTypeMunger.Field) { - changed = mungeNewField(weaver, (NewFieldTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.Method) { - changed = mungeNewMethod(weaver, (NewMethodTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.InnerClass) { - changed = mungeNewMemberType(weaver, (NewMemberClassTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.MethodDelegate2) { - changed = mungeMethodDelegate(weaver, (MethodDelegateTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.FieldHost) { - changed = mungeFieldHost(weaver, (MethodDelegateTypeMunger.FieldHostTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) { - changed = mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger) munger); - worthReporting = false; - } else if (munger.getKind() == ResolvedTypeMunger.PerTypeWithinInterface) { - // PTWIMPL Transform the target type (add the aspect instance field) - changed = mungePerTypeWithinTransformer(weaver); - worthReporting = false; - } else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) { - changed = mungePrivilegedAccess(weaver, (PrivilegedAccessMunger) munger); - worthReporting = false; - } else if (munger.getKind() == ResolvedTypeMunger.Constructor) { - changed = mungeNewConstructor(weaver, (NewConstructorTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.Parent) { - changed = mungeNewParent(weaver, (NewParentTypeMunger) munger); - } else if (munger.getKind() == ResolvedTypeMunger.AnnotationOnType) { - changed = mungeNewAnnotationOnType(weaver, (AnnotationOnTypeMunger) munger); - worthReporting = false; - } else { - throw new RuntimeException("unimplemented"); - } - - if (changed && munger.changesPublicSignature()) { - WeaverStateInfo info = weaver.getLazyClassGen().getOrCreateWeaverStateInfo(weaver.getReweavableMode()); - info.addConcreteMunger(this); - } - - if (changed && worthReporting) { - ResolvedType declaringAspect = null; - AsmManager model = ((BcelWorld) getWorld()).getModelAsAsmManager(); - if (model != null) { - if (munger instanceof NewParentTypeMunger) { - NewParentTypeMunger nptMunger = (NewParentTypeMunger) munger; - declaringAspect = nptMunger.getDeclaringType(); - if (declaringAspect.isParameterizedOrGenericType()) { - declaringAspect = declaringAspect.getRawType(); - } - ResolvedType thisAspect = getAspectType(); - AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, thisAspect); - - // Add a relationship on the actual declaring aspect too - if (!thisAspect.equals(declaringAspect)) { - // Might be the case the declaring aspect is generic and thisAspect is parameterizing it. In that case - // record the actual parameterizations - - ResolvedType target = weaver.getLazyClassGen().getType(); - ResolvedType newParent = nptMunger.getNewParent(); - IProgramElement thisAspectNode = model.getHierarchy().findElementForType(thisAspect.getPackageName(), - thisAspect.getClassName()); - Map<String, List<String>> declareParentsMap = thisAspectNode.getDeclareParentsMap(); - if (declareParentsMap == null) { - declareParentsMap = new HashMap<String, List<String>>(); - thisAspectNode.setDeclareParentsMap(declareParentsMap); - } - String tname = target.getName(); - String pname = newParent.getName(); - List<String> newparents = declareParentsMap.get(tname); - if (newparents == null) { - newparents = new ArrayList<String>(); - declareParentsMap.put(tname, newparents); - } - newparents.add(pname); - AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, declaringAspect); - } - } else { - declaringAspect = getAspectType(); - AsmRelationshipProvider.addRelationship(model, weaver.getLazyClassGen().getType(), munger, declaringAspect); - } - } - } - - // TAG: WeavingMessage - if (changed && worthReporting && munger != null && !weaver.getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { - String tName = weaver.getLazyClassGen().getType().getSourceLocation().getSourceFile().getName(); - if (tName.indexOf("no debug info available") != -1) { - tName = "no debug info available"; - } else { - tName = getShortname(weaver.getLazyClassGen().getType().getSourceLocation().getSourceFile().getPath()); - } - String fName = getShortname(getAspectType().getSourceLocation().getSourceFile().getPath()); - if (munger.getKind().equals(ResolvedTypeMunger.Parent)) { - // This message could come out of AjLookupEnvironment.addParent - // if doing parents munging at compile time only... - NewParentTypeMunger parentTM = (NewParentTypeMunger) munger; - if (parentTM.isMixin()) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_MIXIN, new String[] { - parentTM.getNewParent().getName(), fName, weaver.getLazyClassGen().getType().getName(), - tName }, weaver.getLazyClassGen().getClassName(), getAspectType().getName())); - } else { - if (parentTM.getNewParent().isInterface()) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSIMPLEMENTS, - new String[] { weaver.getLazyClassGen().getType().getName(), tName, - parentTM.getNewParent().getName(), fName }, weaver.getLazyClassGen() - .getClassName(), getAspectType().getName())); - } else { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_DECLAREPARENTSEXTENDS, - new String[] { weaver.getLazyClassGen().getType().getName(), tName, - parentTM.getNewParent().getName(), fName })); - // TAG: WeavingMessage DECLARE PARENTS: EXTENDS - // reportDeclareParentsMessage(WeaveMessage. - // WEAVEMESSAGE_DECLAREPARENTSEXTENDS,sourceType,parent); - - } - } - } else if (munger.getKind().equals(ResolvedTypeMunger.FieldHost)) { - // hidden - } else { - ResolvedMember declaredSig = munger.getSignature(); - String fromString = fName + ":'" + declaredSig + "'"; - // if (declaredSig==null) declaredSig= munger.getSignature(); - String kindString = munger.getKind().toString().toLowerCase(); - if (kindString.equals("innerclass")) { - kindString = "member class"; - fromString = fName; - } - weaver.getWorld() - .getMessageHandler() - .handleMessage( - WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ITD, new String[] { - weaver.getLazyClassGen().getType().getName(), tName, kindString, getAspectType().getName(), - fromString }, weaver.getLazyClassGen().getClassName(), getAspectType().getName())); - } - } - - CompilationAndWeavingContext.leavingPhase(tok); - return changed; - } - - private String getShortname(String path) { - int takefrom = path.lastIndexOf('/'); - if (takefrom == -1) { - takefrom = path.lastIndexOf('\\'); - } - return path.substring(takefrom + 1); - } - - private boolean mungeNewAnnotationOnType(BcelClassWeaver weaver, AnnotationOnTypeMunger munger) { - // FIXME asc this has already been done up front, need to do it here too? - try { - BcelAnnotation anno = (BcelAnnotation) munger.getNewAnnotation(); - weaver.getLazyClassGen().addAnnotation(anno.getBcelAnnotation()); - } catch (ClassCastException cce) { - throw new IllegalStateException("DiagnosticsFor318237: The typemunger "+munger+" contains an annotation of type "+ - munger.getNewAnnotation().getClass().getName()+" when it should be a BcelAnnotation",cce); - } - return true; - } - - /** - * For a long time, AspectJ did not allow binary weaving of declare parents. This restriction is now lifted but could do with - * more testing! - */ - private boolean mungeNewParent(BcelClassWeaver weaver, NewParentTypeMunger typeTransformer) { - LazyClassGen newParentTarget = weaver.getLazyClassGen(); - ResolvedType newParent = typeTransformer.getNewParent(); - - boolean performChange = true; - performChange = enforceDecpRule1_abstractMethodsImplemented(weaver, typeTransformer.getSourceLocation(), newParentTarget, - newParent); - performChange = enforceDecpRule2_cantExtendFinalClass(weaver, typeTransformer.getSourceLocation(), newParentTarget, - newParent) && performChange; - - List<ResolvedMember> methods = newParent.getMethodsWithoutIterator(false, true, false); - for (ResolvedMember method : methods) { - if (!method.getName().equals("<init>")) { - LazyMethodGen subMethod = findMatchingMethod(newParentTarget, method); - // FIXME asc is this safe for all bridge methods? - if (subMethod != null && !subMethod.isBridgeMethod()) { - if (!(subMethod.isSynthetic() && method.isSynthetic())) { - if (!(subMethod.isStatic() && subMethod.getName().startsWith("access$"))) { - // ignore generated accessors - performChange = enforceDecpRule3_visibilityChanges(weaver, newParent, method, subMethod) - && performChange; - performChange = enforceDecpRule4_compatibleReturnTypes(weaver, method, subMethod) && performChange; - performChange = enforceDecpRule5_cantChangeFromStaticToNonstatic(weaver, - typeTransformer.getSourceLocation(), method, subMethod) - && performChange; - } - } - } - } - } - if (!performChange) { - // A rule was violated and an error message already reported - return false; - } - - if (newParent.isClass()) { - // Changing the supertype - if (!attemptToModifySuperCalls(weaver, newParentTarget, newParent)) { - return false; - } - newParentTarget.setSuperClass(newParent); - } else { - // Add a new interface - newParentTarget.addInterface(newParent, getSourceLocation()); - } - return true; - } - - /** - * Rule 1: For the declare parents to be allowed, the target type must override and implement inherited abstract methods (if the - * type is not declared abstract) - */ - private boolean enforceDecpRule1_abstractMethodsImplemented(BcelClassWeaver weaver, ISourceLocation mungerLoc, - LazyClassGen newParentTarget, ResolvedType newParent) { - // Ignore abstract classes or interfaces - if (newParentTarget.isAbstract() || newParentTarget.isInterface()) { - return true; - } - boolean ruleCheckingSucceeded = true; - List<ResolvedMember> newParentMethods = newParent.getMethodsWithoutIterator(false, true, false); - for (ResolvedMember newParentMethod : newParentMethods) { - String newParentMethodName = newParentMethod.getName(); - // Ignore abstract ajc$interField prefixed methods - if (newParentMethod.isAbstract() && !newParentMethodName.startsWith("ajc$interField")) { - ResolvedMember discoveredImpl = null; - List<ResolvedMember> targetMethods = newParentTarget.getType().getMethodsWithoutIterator(false, true, false); - for (ResolvedMember targetMethod : targetMethods) { - if (!targetMethod.isAbstract() && targetMethod.getName().equals(newParentMethodName)) { - String newParentMethodSig = newParentMethod.getParameterSignature(); // ([TT;) - String targetMethodSignature = targetMethod.getParameterSignature(); // ([Ljava/lang/Object;) - // could be a match - if (targetMethodSignature.equals(newParentMethodSig)) { - discoveredImpl = targetMethod; - } else { - // Does the erasure match? In which case a bridge method will be created later to - // satisfy the abstract method - if (targetMethod.hasBackingGenericMember() - && targetMethod.getBackingGenericMember().getParameterSignature().equals(newParentMethodSig)) { - discoveredImpl = targetMethod; - } else if (newParentMethod.hasBackingGenericMember()) { - if (newParentMethod.getBackingGenericMember().getParameterSignature().equals(targetMethodSignature)) { // newParentMethod.getBackingGenericMember().getParameterSignature gives: (Pjava/util/List<TI;>;) targetMethodSignature= (Ljava/util/List;) - discoveredImpl = targetMethod; - } else if (targetMethod instanceof BcelMethod) { - // BcelMethod does not have backing generic member set (need to investigate why). For now, special case here: - UnresolvedType[] targetMethodGenericParameterTypes = targetMethod.getGenericParameterTypes(); - if (targetMethodGenericParameterTypes !=null) { - StringBuilder b = new StringBuilder("("); - for (UnresolvedType p: targetMethodGenericParameterTypes) { - b.append(p.getSignature()); - } - b.append(')'); - if (b.toString().equals(newParentMethodSig)) { - discoveredImpl = targetMethod; - } - } - } - } - } - if (discoveredImpl != null) { - break; - } - } - } - if (discoveredImpl == null) { - // didnt find a valid implementation, lets check the - // ITDs on this type to see if they satisfy it - boolean satisfiedByITD = false; - for (ConcreteTypeMunger m : newParentTarget.getType().getInterTypeMungersIncludingSupers()) { - if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.Method) { - ResolvedMember sig = m.getSignature(); - if (!Modifier.isAbstract(sig.getModifiers())) { - // If the ITD shares a type variable with some target type, we need to tailor it - // for that type - if (m.isTargetTypeParameterized()) { - ResolvedType genericOnType = getWorld().resolve(sig.getDeclaringType()).getGenericType(); - ResolvedType actualOccurrence = newParent.discoverActualOccurrenceOfTypeInHierarchy(genericOnType); - if (actualOccurrence == null) { - // Handle the case where the ITD is onto the type targeted by the declare parents (PR478003) - actualOccurrence = newParentTarget.getType().discoverActualOccurrenceOfTypeInHierarchy(genericOnType); - } - m = m.parameterizedFor(actualOccurrence); - // possible sig change when type parameters filled in - sig = m.getSignature(); - } - if (ResolvedType.matches( - AjcMemberMaker.interMethod(sig, m.getAspectType(), - sig.getDeclaringType().resolve(weaver.getWorld()).isInterface()), newParentMethod)) { - satisfiedByITD = true; - } - } - } else if (m.getMunger() != null && m.getMunger().getKind() == ResolvedTypeMunger.MethodDelegate2) { - // AV - that should be enough, no need to check more - satisfiedByITD = true; - } - } - if (!satisfiedByITD) { - error(weaver, - "The type " + newParentTarget.getName() + " must implement the inherited abstract method " - + newParentMethod.getDeclaringType() + "." + newParentMethodName - + newParentMethod.getParameterSignature(), newParentTarget.getType().getSourceLocation(), - new ISourceLocation[] { newParentMethod.getSourceLocation(), mungerLoc }); - ruleCheckingSucceeded = false; - } - } - } - } - return ruleCheckingSucceeded; - } - - /** - * Rule 2. Can't extend final types - */ - private boolean enforceDecpRule2_cantExtendFinalClass(BcelClassWeaver weaver, ISourceLocation transformerLoc, - LazyClassGen targetType, ResolvedType newParent) { - if (newParent.isFinal()) { - error(weaver, "Cannot make type " + targetType.getName() + " extend final class " + newParent.getName(), targetType - .getType().getSourceLocation(), new ISourceLocation[] { transformerLoc }); - return false; - } - return true; - } - - /** - * Rule 3. Can't narrow visibility of methods when overriding - */ - private boolean enforceDecpRule3_visibilityChanges(BcelClassWeaver weaver, ResolvedType newParent, ResolvedMember superMethod, - LazyMethodGen subMethod) { - boolean cont = true; - if (Modifier.isPublic(superMethod.getModifiers())) { - if (subMethod.isProtected() || subMethod.isDefault() || subMethod.isPrivate()) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod - + "' from " + newParent.getName(), superMethod.getSourceLocation())); - cont = false; - } - } else if (Modifier.isProtected(superMethod.getModifiers())) { - if (subMethod.isDefault() || subMethod.isPrivate()) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod - + "' from " + newParent.getName(), superMethod.getSourceLocation())); - cont = false; - } - } else if (superMethod.isDefault()) { - if (subMethod.isPrivate()) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error("Cannot reduce the visibility of the inherited method '" + superMethod - + "' from " + newParent.getName(), superMethod.getSourceLocation())); - cont = false; - } - } - return cont; - } - - /** - * Rule 4. Can't have incompatible return types - */ - private boolean enforceDecpRule4_compatibleReturnTypes(BcelClassWeaver weaver, ResolvedMember superMethod, - LazyMethodGen subMethod) { - boolean cont = true; - String superReturnTypeSig = superMethod.getGenericReturnType().getSignature(); // eg. Pjava/util/Collection<LFoo;> - String subReturnTypeSig = subMethod.getGenericReturnTypeSignature(); - superReturnTypeSig = superReturnTypeSig.replace('.', '/'); - subReturnTypeSig = subReturnTypeSig.replace('.', '/'); - if (!superReturnTypeSig.equals(subReturnTypeSig)) { - // Check for covariance - ResolvedType subType = weaver.getWorld().resolve(subMethod.getReturnType()); - ResolvedType superType = weaver.getWorld().resolve(superMethod.getReturnType()); - if (!superType.isAssignableFrom(subType)) { - weaver.getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error("The return type is incompatible with " + superMethod.getDeclaringType() + "." - + superMethod.getName() + superMethod.getParameterSignature(), - subMethod.getSourceLocation())); - // this just might be a better error message... - // "The return type '"+subReturnTypeSig+ - // "' is incompatible with the overridden method " - // +superMethod.getDeclaringType()+"."+ - // superMethod.getName()+superMethod.getParameterSignature()+ - // " which returns '"+superReturnTypeSig+"'", - cont = false; - } - } - return cont; - } - - /** - * Rule5. Method overrides can't change the staticality (word?) - you can't override and make an instance method static or - * override and make a static method an instance method. - */ - private boolean enforceDecpRule5_cantChangeFromStaticToNonstatic(BcelClassWeaver weaver, ISourceLocation mungerLoc, - ResolvedMember superMethod, LazyMethodGen subMethod) { - boolean superMethodStatic = Modifier.isStatic(superMethod.getModifiers()); - if (superMethodStatic && !subMethod.isStatic()) { - error(weaver, "This instance method " + subMethod.getName() + subMethod.getParameterSignature() - + " cannot override the static method from " + superMethod.getDeclaringType().getName(), - subMethod.getSourceLocation(), new ISourceLocation[] { mungerLoc }); - return false; - } else if (!superMethodStatic && subMethod.isStatic()) { - error(weaver, "The static method " + subMethod.getName() + subMethod.getParameterSignature() - + " cannot hide the instance method from " + superMethod.getDeclaringType().getName(), - subMethod.getSourceLocation(), new ISourceLocation[] { mungerLoc }); - return false; - } - return true; - } - - public void error(BcelClassWeaver weaver, String text, ISourceLocation primaryLoc, ISourceLocation[] extraLocs) { - IMessage msg = new Message(text, primaryLoc, true, extraLocs); - weaver.getWorld().getMessageHandler().handleMessage(msg); - } - - /** - * Search the specified type for a particular method - do not use the return value in the comparison as it is not considered for - * overriding. - */ - private LazyMethodGen findMatchingMethod(LazyClassGen type, ResolvedMember searchMethod) { - String searchName = searchMethod.getName(); - String searchSig = searchMethod.getParameterSignature(); - for (LazyMethodGen method : type.getMethodGens()) { - if (method.getName().equals(searchName) && method.getParameterSignature().equals(searchSig)) { - return method; - } - } - return null; - } - - /** - * The main part of implementing declare parents extends. Modify super ctor calls to target the new type. - */ - public boolean attemptToModifySuperCalls(BcelClassWeaver weaver, LazyClassGen newParentTarget, ResolvedType newParent) { - ResolvedType currentParentType = newParentTarget.getSuperClass(); - if (currentParentType.getGenericType() != null) { - currentParentType = currentParentType.getGenericType(); - } - String currentParent = currentParentType.getName(); - if (newParent.getGenericType() != null) { - newParent = newParent.getGenericType(); // target new super calls at - } - // the generic type if its raw or parameterized - List<LazyMethodGen> mgs = newParentTarget.getMethodGens(); - - // Look for ctors to modify - for (LazyMethodGen aMethod : mgs) { - if (LazyMethodGen.isConstructor(aMethod)) { - InstructionList insList = aMethod.getBody(); - InstructionHandle handle = insList.getStart(); - while (handle != null) { - if (handle.getInstruction().opcode == Constants.INVOKESPECIAL) { - ConstantPool cpg = newParentTarget.getConstantPool(); - InvokeInstruction invokeSpecial = (InvokeInstruction) handle.getInstruction(); - if (invokeSpecial.getClassName(cpg).equals(currentParent) - && invokeSpecial.getMethodName(cpg).equals("<init>")) { - // System.err.println("Transforming super call '<init>" + invokeSpecial.getSignature(cpg) + "'"); - - // 1. Check there is a ctor in the new parent with - // the same signature - ResolvedMember newCtor = getConstructorWithSignature(newParent, invokeSpecial.getSignature(cpg)); - - if (newCtor == null) { - - // 2. Check ITDCs to see if the necessary ctor is provided that way - boolean satisfiedByITDC = false; - for (Iterator<ConcreteTypeMunger> ii = newParentTarget.getType() - .getInterTypeMungersIncludingSupers().iterator(); ii.hasNext() && !satisfiedByITDC;) { - ConcreteTypeMunger m = ii.next(); - if (m.getMunger() instanceof NewConstructorTypeMunger) { - if (m.getSignature().getSignature().equals(invokeSpecial.getSignature(cpg))) { - satisfiedByITDC = true; - } - } - } - - if (!satisfiedByITDC) { - String csig = createReadableCtorSig(newParent, cpg, invokeSpecial); - weaver.getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error( - "Unable to modify hierarchy for " + newParentTarget.getClassName() - + " - the constructor " + csig + " is missing", - this.getSourceLocation())); - return false; - } - } - - int idx = cpg.addMethodref(newParent.getName(), invokeSpecial.getMethodName(cpg), - invokeSpecial.getSignature(cpg)); - invokeSpecial.setIndex(idx); - } - } - handle = handle.getNext(); - } - } - } - return true; - } - - /** - * Creates a nice signature for the ctor, something like "(int,Integer,String)" - */ - private String createReadableCtorSig(ResolvedType newParent, ConstantPool cpg, InvokeInstruction invokeSpecial) { - StringBuffer sb = new StringBuffer(); - Type[] ctorArgs = invokeSpecial.getArgumentTypes(cpg); - sb.append(newParent.getClassName()); - sb.append("("); - for (int i = 0; i < ctorArgs.length; i++) { - String argtype = ctorArgs[i].toString(); - if (argtype.lastIndexOf(".") != -1) { - sb.append(argtype.substring(argtype.lastIndexOf(".") + 1)); - } else { - sb.append(argtype); - } - if (i + 1 < ctorArgs.length) { - sb.append(","); - } - } - sb.append(")"); - return sb.toString(); - } - - private ResolvedMember getConstructorWithSignature(ResolvedType type, String searchSig) { - for (ResolvedMember method : type.getDeclaredJavaMethods()) { - if (MemberUtils.isConstructor(method)) { - if (method.getSignature().equals(searchSig)) { - return method; - } - } - } - return null; - } - - private boolean mungePrivilegedAccess(BcelClassWeaver weaver, PrivilegedAccessMunger munger) { - LazyClassGen gen = weaver.getLazyClassGen(); - ResolvedMember member = munger.getMember(); - - ResolvedType onType = weaver.getWorld().resolve(member.getDeclaringType(), munger.getSourceLocation()); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - - // System.out.println("munging: " + gen + " with " + member); - if (onType.equals(gen.getType())) { - if (member.getKind() == Member.FIELD) { - // System.out.println("matched: " + gen); - addFieldGetter(gen, member, - AjcMemberMaker.privilegedAccessMethodForFieldGet(aspectType, member, munger.shortSyntax)); - addFieldSetter(gen, member, - AjcMemberMaker.privilegedAccessMethodForFieldSet(aspectType, member, munger.shortSyntax)); - return true; - } else if (member.getKind() == Member.METHOD) { - addMethodDispatch(gen, member, AjcMemberMaker.privilegedAccessMethodForMethod(aspectType, member)); - return true; - } else if (member.getKind() == Member.CONSTRUCTOR) { - for (Iterator<LazyMethodGen> i = gen.getMethodGens().iterator(); i.hasNext();) { - LazyMethodGen m = i.next(); - if (m.getMemberView() != null && m.getMemberView().getKind() == Member.CONSTRUCTOR) { - // m.getMemberView().equals(member)) { - m.forcePublic(); - // return true; - } - } - return true; - // throw new BCException("no match for " + member + " in " + - // gen); - } else if (member.getKind() == Member.STATIC_INITIALIZATION) { - gen.forcePublic(); - return true; - } else { - throw new RuntimeException("unimplemented"); - } - } - return false; - } - - private void addFieldGetter(LazyClassGen gen, ResolvedMember field, ResolvedMember accessMethod) { - LazyMethodGen mg = makeMethodGen(gen, accessMethod); - InstructionList il = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - if (Modifier.isStatic(field.getModifiers())) { - il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), BcelWorld.makeBcelType(field.getType()), - Constants.GETSTATIC)); - } else { - il.append(InstructionConstants.ALOAD_0); - il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), BcelWorld.makeBcelType(field.getType()), - Constants.GETFIELD)); - } - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(field.getType()))); - mg.getBody().insert(il); - - gen.addMethodGen(mg, getSignature().getSourceLocation()); - } - - private void addFieldSetter(LazyClassGen gen, ResolvedMember field, ResolvedMember accessMethod) { - LazyMethodGen mg = makeMethodGen(gen, accessMethod); - InstructionList il = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - Type fieldType = BcelWorld.makeBcelType(field.getType()); - - if (Modifier.isStatic(field.getModifiers())) { - il.append(InstructionFactory.createLoad(fieldType, 0)); - il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), fieldType, Constants.PUTSTATIC)); - } else { - il.append(InstructionConstants.ALOAD_0); - il.append(InstructionFactory.createLoad(fieldType, 1)); - il.append(fact.createFieldAccess(gen.getClassName(), field.getName(), fieldType, Constants.PUTFIELD)); - } - il.append(InstructionFactory.createReturn(Type.VOID)); - mg.getBody().insert(il); - - gen.addMethodGen(mg, getSignature().getSourceLocation()); - } - - private void addMethodDispatch(LazyClassGen gen, ResolvedMember method, ResolvedMember accessMethod) { - LazyMethodGen mg = makeMethodGen(gen, accessMethod); - InstructionList il = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - Type[] paramTypes = BcelWorld.makeBcelTypes(method.getParameterTypes()); - - int pos = 0; - - if (!Modifier.isStatic(method.getModifiers())) { - il.append(InstructionConstants.ALOAD_0); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - il.append(InstructionFactory.createLoad(paramType, pos)); - pos += paramType.getSize(); - } - il.append(Utility.createInvoke(fact, (BcelWorld) aspectType.getWorld(), method)); - il.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(method.getReturnType()))); - - mg.getBody().insert(il); - - gen.addMethodGen(mg); - } - - protected LazyMethodGen makeMethodGen(LazyClassGen gen, ResolvedMember member) { - try { - Type returnType = BcelWorld.makeBcelType(member.getReturnType()); - Type[] parameterTypes = BcelWorld.makeBcelTypes(member.getParameterTypes()); - LazyMethodGen ret = new LazyMethodGen(member.getModifiers(), returnType, - member.getName(), parameterTypes, UnresolvedType.getNames(member - .getExceptions()), gen); - - // 43972 : Static crosscutting makes interfaces unusable for javac - // ret.makeSynthetic(); - return ret; - } catch (ClassFormatException cfe) { - throw new RuntimeException("Problem with makeMethodGen for method "+member.getName()+" in type "+gen.getName()+" ret="+member.getReturnType(),cfe); - } - } - - protected FieldGen makeFieldGen(LazyClassGen gen, ResolvedMember member) { - return new FieldGen(member.getModifiers(), BcelWorld.makeBcelType(member.getReturnType()), member.getName(), - gen.getConstantPool()); - } - - private boolean mungePerObjectInterface(BcelClassWeaver weaver, PerObjectInterfaceTypeMunger munger) { - // System.err.println("Munging perobject ["+munger+"] onto "+weaver. - // getLazyClassGen().getClassName()); - LazyClassGen gen = weaver.getLazyClassGen(); - - if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) { - FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perObjectField(gen.getType(), aspectType)); - - gen.addField(fg, getSourceLocation()); - - Type fieldType = BcelWorld.makeBcelType(aspectType); - LazyMethodGen mg = new LazyMethodGen(Modifier.PUBLIC, fieldType, NameMangler.perObjectInterfaceGet(aspectType), - new Type[0], new String[0], gen); - InstructionList il = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - il.append(InstructionConstants.ALOAD_0); - il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETFIELD)); - il.append(InstructionFactory.createReturn(fieldType)); - mg.getBody().insert(il); - - gen.addMethodGen(mg); - - LazyMethodGen mg1 = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, NameMangler.perObjectInterfaceSet(aspectType), - - new Type[] { fieldType, }, new String[0], gen); - InstructionList il1 = new InstructionList(); - il1.append(InstructionConstants.ALOAD_0); - il1.append(InstructionFactory.createLoad(fieldType, 1)); - il1.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.PUTFIELD)); - il1.append(InstructionFactory.createReturn(Type.VOID)); - mg1.getBody().insert(il1); - - gen.addMethodGen(mg1); - - gen.addInterface(munger.getInterfaceType().resolve(weaver.getWorld()), getSourceLocation()); - - return true; - } else { - return false; - } - } - - // PTWIMPL Add field to hold aspect instance and an accessor - private boolean mungePerTypeWithinTransformer(BcelClassWeaver weaver) { - LazyClassGen gen = weaver.getLazyClassGen(); - - // if (couldMatch(gen.getBcelObjectType(), munger.getTestPointcut())) { - - // Add (to the target type) the field that will hold the aspect instance - // e.g ajc$com_blah_SecurityAspect$ptwAspectInstance - FieldGen fg = makeFieldGen(gen, AjcMemberMaker.perTypeWithinField(gen.getType(), aspectType)); - gen.addField(fg, getSourceLocation()); - if (!gen.getType().canBeSeenBy(aspectType) && aspectType.isPrivilegedAspect()) { - gen.forcePublic(); - } - // Add an accessor for this new field, the - // ajc$<aspectname>$localAspectOf() method - // e.g. - // "public com_blah_SecurityAspect ajc$com_blah_SecurityAspect$localAspectOf()" - Type fieldType = BcelWorld.makeBcelType(aspectType); - LazyMethodGen mg = new LazyMethodGen(Modifier.PUBLIC | Modifier.STATIC, fieldType, - NameMangler.perTypeWithinLocalAspectOf(aspectType), new Type[0], new String[0], gen); - InstructionList il = new InstructionList(); - // PTWIMPL ?? Should check if it is null and throw - // NoAspectBoundException - InstructionFactory fact = gen.getFactory(); - il.append(fact.createFieldAccess(gen.getClassName(), fg.getName(), fieldType, Constants.GETSTATIC)); - il.append(InstructionFactory.createReturn(fieldType)); - mg.getBody().insert(il); - gen.addMethodGen(mg); - return true; - // } else { - // return false; - // } - } - - // ??? Why do we have this method? I thought by now we would know if it - // matched or not - private boolean couldMatch(BcelObjectType bcelObjectType, Pointcut pointcut) { - return !bcelObjectType.isInterface(); - } - - private boolean mungeNewMemberType(BcelClassWeaver classWeaver, NewMemberClassTypeMunger munger) { - World world = classWeaver.getWorld(); - ResolvedType onType = world.resolve(munger.getTargetType()); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - return onType.equals(classWeaver.getLazyClassGen().getType()); - } - - private boolean mungeNewMethod(BcelClassWeaver classWeaver, NewMethodTypeMunger munger) { - World world = classWeaver.getWorld(); - - // Resolving it will sort out the tvars - ResolvedMember unMangledInterMethod = munger.getSignature().resolve(world); - - // do matching on the unMangled one, but actually add them to the mangled method - ResolvedMember interMethodBody = munger.getDeclaredInterMethodBody(aspectType, world); - ResolvedMember interMethodDispatcher = munger.getDeclaredInterMethodDispatcher(aspectType, world); - ResolvedMember memberHoldingAnyAnnotations = interMethodDispatcher; - LazyClassGen classGen = classWeaver.getLazyClassGen(); - - ResolvedType onType = world.resolve(unMangledInterMethod.getDeclaringType(), munger.getSourceLocation()); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - - // Simple checks, can't ITD on annotations or enums - if (onType.isAnnotation()) { - signalError(WeaverMessages.ITDM_ON_ANNOTATION_NOT_ALLOWED, classWeaver, onType); - return false; - } - - if (onType.isEnum()) { - signalError(WeaverMessages.ITDM_ON_ENUM_NOT_ALLOWED, classWeaver, onType); - return false; - } - - boolean mungingInterface = classGen.isInterface(); - boolean onInterface = onType.isInterface(); - - if (onInterface - && classGen.getLazyMethodGen(unMangledInterMethod.getName(), unMangledInterMethod.getSignature(), true) != null) { - // this is ok, we could be providing the default implementation of a - // method - // that the target has already declared - return false; - } - - // If we are processing the intended ITD target type (might be an interface) - if (onType.equals(classGen.getType())) { - ResolvedMember mangledInterMethod = AjcMemberMaker.interMethod(unMangledInterMethod, aspectType, onInterface); - - LazyMethodGen newMethod = makeMethodGen(classGen, mangledInterMethod); - if (mungingInterface) { - // we want the modifiers of the ITD to be used for all *implementors* of the - // interface, but the method itself we add to the interface must be public abstract - newMethod.setAccessFlags(Modifier.PUBLIC | Modifier.ABSTRACT); - } - - // pr98901 - // For copying the annotations across, we have to discover the real - // member in the aspect which is holding them. - if (classWeaver.getWorld().isInJava5Mode()) { - AnnotationAJ annotationsOnRealMember[] = null; - ResolvedType toLookOn = aspectType; - if (aspectType.isRawType()) { - toLookOn = aspectType.getGenericType(); - } - ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, memberHoldingAnyAnnotations, false); - // 266602 - consider it missing to mean that the corresponding aspect had errors - if (realMember == null) { - // signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver); - // throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType); - } else { - annotationsOnRealMember = realMember.getAnnotations(); - } - Set<ResolvedType> addedAnnotations = new HashSet<ResolvedType>(); - if (annotationsOnRealMember != null) { - for (AnnotationAJ anno : annotationsOnRealMember) { - AnnotationGen a = ((BcelAnnotation) anno).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, classGen.getConstantPool(), true); - newMethod.addAnnotation(new BcelAnnotation(ag, classWeaver.getWorld())); - addedAnnotations.add(anno.getType()); - } - } - if (realMember != null) { - copyOverParameterAnnotations(newMethod, realMember); - } - // the code below was originally added to cope with the case where an aspect declares an annotation on an ITD - // declared within itself (an unusual situation). However, it also addresses the case where we may not find the - // annotation on the real representation of the ITD. This can happen in a load-time weaving situation where - // we couldn't add the annotation in time - and so here we recheck the declare annotations. Not quite ideal but - // works. pr288635 - List<DeclareAnnotation> allDecams = world.getDeclareAnnotationOnMethods(); - for (DeclareAnnotation declareAnnotationMC : allDecams) { - if (declareAnnotationMC.matches(unMangledInterMethod, world)) { - // && newMethod.getEnclosingClass().getType() == aspectType) { - AnnotationAJ annotation = declareAnnotationMC.getAnnotation(); - if (!addedAnnotations.contains(annotation.getType())) { - newMethod.addAnnotation(annotation); - } - } - } - } - - // If it doesn't target an interface and there is a body (i.e. it isnt abstract) - if (!onInterface && !Modifier.isAbstract(mangledInterMethod.getModifiers())) { - InstructionList body = newMethod.getBody(); - InstructionFactory fact = classGen.getFactory(); - int pos = 0; - - if (!Modifier.isStatic(unMangledInterMethod.getModifiers())) { - body.append(InstructionFactory.createThis()); - pos++; - } - Type[] paramTypes = BcelWorld.makeBcelTypes(mangledInterMethod.getParameterTypes()); - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - pos += paramType.getSize(); - } - body.append(Utility.createInvoke(fact, classWeaver.getWorld(), interMethodBody)); - body.append(InstructionFactory.createReturn(BcelWorld.makeBcelType(mangledInterMethod.getReturnType()))); - - if (classWeaver.getWorld().isInJava5Mode()) { // Don't need bridge - // methods if not in - // 1.5 mode. - createAnyBridgeMethodsForCovariance(classWeaver, munger, unMangledInterMethod, onType, classGen, paramTypes); - } - - } else { - // ??? this is okay - // if (!(mg.getBody() == null)) throw new - // RuntimeException("bas"); - } - - if (world.isInJava5Mode()) { - String basicSignature = mangledInterMethod.getSignature(); - String genericSignature = ((ResolvedMemberImpl) mangledInterMethod).getSignatureForAttribute(); - if (!basicSignature.equals(genericSignature)) { - // Add a signature attribute to it - newMethod.addAttribute(createSignatureAttribute(classGen.getConstantPool(), genericSignature)); - } - } - // XXX make sure to check that we set exceptions properly on this - // guy. - classWeaver.addLazyMethodGen(newMethod); - classWeaver.getLazyClassGen().warnOnAddedMethod(newMethod.getMethod(), getSignature().getSourceLocation()); - - addNeededSuperCallMethods(classWeaver, onType, munger.getSuperMethodsCalled()); - - return true; - - } else if (onInterface && !Modifier.isAbstract(unMangledInterMethod.getModifiers())) { - - // This means the 'gen' should be the top most implementor - // - if it is *not* then something went wrong after we worked - // out that it was the top most implementor (see pr49657) - if (!classGen.getType().isTopmostImplementor(onType)) { - ResolvedType rtx = classGen.getType().getTopmostImplementor(onType); - if (rtx == null) { - // pr302460 - // null means there is something wrong with what we are looking at - ResolvedType rt = classGen.getType(); - if (rt.isInterface()) { - ISourceLocation sloc = munger.getSourceLocation(); - classWeaver - .getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error( - "ITD target " - + rt.getName() - + " is an interface but has been incorrectly determined to be the topmost implementor of " - + onType.getName() + ". ITD is " + this.getSignature(), sloc)); - } - if (!onType.isAssignableFrom(rt)) { - ISourceLocation sloc = munger.getSourceLocation(); - classWeaver - .getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error( - "ITD target " + rt.getName() + " doesn't appear to implement " + onType.getName() - + " why did we consider it the top most implementor? ITD is " - + this.getSignature(), sloc)); - } - } else if (!rtx.isExposedToWeaver()) { - ISourceLocation sLoc = munger.getSourceLocation(); - classWeaver - .getWorld() - .getMessageHandler() - .handleMessage( - MessageUtil.error(WeaverMessages.format(WeaverMessages.ITD_NON_EXPOSED_IMPLEMENTOR, rtx, - getAspectType().getName()), (sLoc == null ? getAspectType().getSourceLocation() : sLoc))); - } else { - // XXX what does this state mean? - // We have incorrectly identified what is the top most - // implementor and its not because - // a type wasn't exposed to the weaver - } - return false; - } else { - - ResolvedMember mangledInterMethod = AjcMemberMaker.interMethod(unMangledInterMethod, aspectType, false); - - LazyMethodGen mg = makeMethodGen(classGen, mangledInterMethod); - - // From 98901#29 - need to copy annotations across - if (classWeaver.getWorld().isInJava5Mode()) { - AnnotationAJ annotationsOnRealMember[] = null; - ResolvedType toLookOn = aspectType; - if (aspectType.isRawType()) { - toLookOn = aspectType.getGenericType(); - } - ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, memberHoldingAnyAnnotations, false); - if (realMember == null) { - throw new BCException("Couldn't find ITD holder member '" + memberHoldingAnyAnnotations + "' on aspect " - + aspectType); - } - annotationsOnRealMember = realMember.getAnnotations(); - - if (annotationsOnRealMember != null) { - for (AnnotationAJ annotationX : annotationsOnRealMember) { - AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, classWeaver.getLazyClassGen().getConstantPool(), true); - mg.addAnnotation(new BcelAnnotation(ag, classWeaver.getWorld())); - } - } - - copyOverParameterAnnotations(mg, realMember); - } - - if (mungingInterface) { - // we want the modifiers of the ITD to be used for all - // *implementors* of the - // interface, but the method itself we add to the interface - // must be public abstract - mg.setAccessFlags(Modifier.PUBLIC | Modifier.ABSTRACT); - } - - Type[] paramTypes = BcelWorld.makeBcelTypes(mangledInterMethod.getParameterTypes()); - Type returnType = BcelWorld.makeBcelType(mangledInterMethod.getReturnType()); - - InstructionList body = mg.getBody(); - InstructionFactory fact = classGen.getFactory(); - int pos = 0; - - if (!Modifier.isStatic(mangledInterMethod.getModifiers())) { - body.append(InstructionFactory.createThis()); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - pos += paramType.getSize(); - } - - body.append(Utility.createInvoke(fact, classWeaver.getWorld(), interMethodBody)); - Type t = BcelWorld.makeBcelType(interMethodBody.getReturnType()); - if (!t.equals(returnType)) { - body.append(fact.createCast(t, returnType)); - } - body.append(InstructionFactory.createReturn(returnType)); - mg.definingType = onType; - - if (world.isInJava5Mode()) { - String basicSignature = mangledInterMethod.getSignature(); - String genericSignature = ((ResolvedMemberImpl) mangledInterMethod).getSignatureForAttribute(); - if (!basicSignature.equals(genericSignature)) { - // Add a signature attribute to it - mg.addAttribute(createSignatureAttribute(classGen.getConstantPool(), genericSignature)); - } - } - - classWeaver.addOrReplaceLazyMethodGen(mg); - - addNeededSuperCallMethods(classWeaver, onType, munger.getSuperMethodsCalled()); - - // Work out if we need a bridge method for the new method added to the topmostimplementor. - - // Check if the munger being processed is a parameterized form of the original munger - createBridgeIfNecessary(classWeaver, munger, unMangledInterMethod, classGen); - - return true; - } - } else { - return false; - } - } - - private void createBridgeIfNecessary(BcelClassWeaver classWeaver, NewMethodTypeMunger munger, - ResolvedMember unMangledInterMethod, LazyClassGen classGen) { - if (munger.getDeclaredSignature() != null) { - boolean needsbridging = false; - ResolvedMember mungerSignature = munger.getSignature(); - ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null, - mungerSignature.getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases()); - if (!toBridgeTo.getReturnType().getErasureSignature().equals(mungerSignature.getReturnType().getErasureSignature())) { - needsbridging = true; - } - UnresolvedType[] originalParams = toBridgeTo.getParameterTypes(); - UnresolvedType[] newParams = mungerSignature.getParameterTypes(); - for (int ii = 0; ii < originalParams.length; ii++) { - if (!originalParams[ii].getErasureSignature().equals(newParams[ii].getErasureSignature())) { - needsbridging = true; - } - } - if (needsbridging) { - createBridge(classWeaver, unMangledInterMethod, classGen, toBridgeTo); - } - } - } - - private void copyOverParameterAnnotations(LazyMethodGen receiverMethod, ResolvedMember donorMethod) { - AnnotationAJ[][] pAnnos = donorMethod.getParameterAnnotations(); - if (pAnnos != null) { - int offset = receiverMethod.isStatic() ? 0 : 1; - int param = 0; - for (int i = offset; i < pAnnos.length; i++) { - AnnotationAJ[] annosOnParam = pAnnos[i]; - if (annosOnParam != null) { - for (AnnotationAJ anno : annosOnParam) { - receiverMethod.addParameterAnnotation(param, anno); - } - } - param++; - } - } - } - - private void createBridge(BcelClassWeaver weaver, ResolvedMember unMangledInterMethod, LazyClassGen classGen, - ResolvedMember toBridgeTo) { - Type[] paramTypes; - Type returnType; - InstructionList body; - InstructionFactory fact; - int pos; - ResolvedMember bridgerMethod = AjcMemberMaker.bridgerToInterMethod(unMangledInterMethod, classGen.getType()); - ResolvedMember bridgingSetter = AjcMemberMaker.interMethodBridger(toBridgeTo, aspectType, false); // pr250493 - - LazyMethodGen bridgeMethod = makeMethodGen(classGen, bridgingSetter); - paramTypes = BcelWorld.makeBcelTypes(bridgingSetter.getParameterTypes()); - Type[] bridgingToParms = BcelWorld.makeBcelTypes(unMangledInterMethod.getParameterTypes()); - returnType = BcelWorld.makeBcelType(bridgingSetter.getReturnType()); - body = bridgeMethod.getBody(); - fact = classGen.getFactory(); - pos = 0; - if (!Modifier.isStatic(bridgingSetter.getModifiers())) { - body.append(InstructionFactory.createThis()); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - if (!bridgingSetter.getParameterTypes()[i].getErasureSignature().equals( - unMangledInterMethod.getParameterTypes()[i].getErasureSignature())) { - // System.err.println("Putting in cast from "+ - // paramType+" to "+bridgingToParms[i]); - body.append(fact.createCast(paramType, bridgingToParms[i])); - } - pos += paramType.getSize(); - } - - body.append(Utility.createInvoke(fact, weaver.getWorld(), bridgerMethod)); - body.append(InstructionFactory.createReturn(returnType)); - classGen.addMethodGen(bridgeMethod); - // mg.definingType = onType; - } - - /** - * Helper method to create a signature attribute based on a string signature: e.g. "Ljava/lang/Object;LI<Ljava/lang/Double;>;" - */ - private Signature createSignatureAttribute(ConstantPool cp, String signature) { - int nameIndex = cp.addUtf8("Signature"); - int sigIndex = cp.addUtf8(signature); - return new Signature(nameIndex, 2, sigIndex, cp); - } - - /** - * Create any bridge method required because of covariant returns being used. This method is used in the case where an ITD is - * applied to some type and it may be in an override relationship with a method from the supertype - but due to covariance there - * is a mismatch in return values. Example of when required: Super defines: Object m(String s) Sub defines: String m(String s) - * then we need a bridge method in Sub called 'Object m(String s)' that forwards to 'String m(String s)' - */ - private void createAnyBridgeMethodsForCovariance(BcelClassWeaver weaver, NewMethodTypeMunger munger, - ResolvedMember unMangledInterMethod, ResolvedType onType, LazyClassGen gen, Type[] paramTypes) { - // PERFORMANCE BOTTLENECK? Might need investigating, method analysis - // between types in a hierarchy just seems expensive... - // COVARIANCE BRIDGING - // Algorithm: Step1. Check in this type - has someone already created - // the bridge method? - // Step2. Look above us - do we 'override' a method and yet differ in - // return type (i.e. covariance) - // Step3. Create a forwarding bridge method - // ResolvedType superclass = onType.getSuperclass(); - boolean quitRightNow = false; - - String localMethodName = unMangledInterMethod.getName(); - String erasedSig = unMangledInterMethod.getSignatureErased(); // will be something like (LSuperB;)LFoo; - String localParameterSig = erasedSig.substring(0,erasedSig.lastIndexOf(')')+1);//unMangledInterMethod.getParameterSignature(); - // getParameterSignatureErased() does not include parens, which we do need. - String localReturnTypeESig = unMangledInterMethod.getReturnType().getErasureSignature(); - - // Step1 - boolean alreadyDone = false; // Compiler might have done it - ResolvedMember[] localMethods = onType.getDeclaredMethods(); - for (int i = 0; i < localMethods.length; i++) { - ResolvedMember member = localMethods[i]; - if (member.getName().equals(localMethodName)) { - // Check the params - if (member.getParameterSignature().equals(localParameterSig)) { - alreadyDone = true; - } - } - } - - // Step2 - if (!alreadyDone) { - // Use the iterator form of 'getMethods()' so we do as little work as necessary - ResolvedType supertype = onType.getSuperclass(); - if (supertype != null) { - for (Iterator<ResolvedMember> iter = supertype.getMethods(true, true); iter.hasNext() && !quitRightNow;) { - ResolvedMember aMethod = iter.next(); - if (aMethod.getName().equals(localMethodName) && aMethod.getParameterSignature().equals(localParameterSig)) { - // check the return types, if they are different we need a - // bridging method. - if (!aMethod.getReturnType().getErasureSignature().equals(localReturnTypeESig) - && !Modifier.isPrivate(aMethod.getModifiers())) { - // Step3 - createBridgeMethod(weaver.getWorld(), munger, unMangledInterMethod, gen, paramTypes, aMethod); - quitRightNow = true; - } - } - } - } - } - } - - /** - * Create a bridge method for a particular munger. - * - * @param world - * @param munger - * @param unMangledInterMethod the method to bridge 'to' that we have already created in the 'subtype' - * @param clazz the class in which to put the bridge method - * @param paramTypes Parameter types for the bridge method, passed in as an optimization since the caller is likely to have - * already created them. - * @param theBridgeMethod - */ - private void createBridgeMethod(BcelWorld world, NewMethodTypeMunger munger, ResolvedMember unMangledInterMethod, - LazyClassGen clazz, Type[] paramTypes, ResolvedMember theBridgeMethod) { - InstructionList body; - InstructionFactory fact; - int pos = 0; - - // The bridge method in this type will have the same signature as the one in the supertype - LazyMethodGen bridgeMethod = makeMethodGen(clazz, theBridgeMethod); - bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040 /* BRIDGE = 0x00000040 */); - // UnresolvedType[] newParams = munger.getSignature().getParameterTypes(); - Type returnType = BcelWorld.makeBcelType(theBridgeMethod.getReturnType()); - body = bridgeMethod.getBody(); - fact = clazz.getFactory(); - - if (!Modifier.isStatic(unMangledInterMethod.getModifiers())) { - body.append(InstructionFactory.createThis()); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - // if (!bridgingSetter.getParameterTypes()[i].getErasureSignature(). - // equals - // (unMangledInterMethod.getParameterTypes()[i].getErasureSignature - // ())) { - // System.err.println("Putting in cast from "+paramType+" to "+ - // bridgingToParms[i]); - // body.append(fact.createCast(paramType,bridgingToParms[i])); - // } - pos += paramType.getSize(); - } - - body.append(Utility.createInvoke(fact, world, unMangledInterMethod)); - body.append(InstructionFactory.createReturn(returnType)); - clazz.addMethodGen(bridgeMethod); - } - - // Unlike toString() on a member, this does not include the declaring type - private String stringifyMember(ResolvedMember member) { - StringBuffer buf = new StringBuffer(); - buf.append(member.getReturnType().getName()); - buf.append(' '); - buf.append(member.getName()); - if (member.getKind() != Member.FIELD) { - buf.append("("); - UnresolvedType[] params = member.getParameterTypes(); - if (params.length != 0) { - buf.append(params[0]); - for (int i = 1, len = params.length; i < len; i++) { - buf.append(", "); - buf.append(params[i].getName()); - } - } - buf.append(")"); - } - return buf.toString(); - } - - private boolean mungeMethodDelegate(BcelClassWeaver weaver, MethodDelegateTypeMunger munger) { - World world = weaver.getWorld(); - - LazyClassGen gen = weaver.getLazyClassGen(); - if (gen.getType().isAnnotation() || gen.getType().isEnum()) { - // don't signal error as it could be a consequence of a wild type pattern - return false; - } - - ResolvedMember introduced = munger.getSignature(); - - ResolvedType fromType = world.resolve(introduced.getDeclaringType(), munger.getSourceLocation()); - if (fromType.isRawType()) { - fromType = fromType.getGenericType(); - } - - boolean shouldApply = munger.matches(weaver.getLazyClassGen().getType(), aspectType); - - if (shouldApply) { - Type bcelReturnType = BcelWorld.makeBcelType(introduced.getReturnType()); - - // If no implementation class was specified, the intention was that - // the types matching the pattern - // already implemented the interface, let's check that now! - if (munger.getImplClassName() == null && !munger.specifiesDelegateFactoryMethod()) { - boolean isOK = false; - List<LazyMethodGen> existingMethods = gen.getMethodGens(); - for (LazyMethodGen m : existingMethods) { - if (m.getName().equals(introduced.getName()) - && m.getParameterSignature().equals(introduced.getParameterSignature()) - && m.getReturnType().equals(bcelReturnType)) { - isOK = true; - } - } - if (!isOK) { - // the class does not implement this method, they needed to - // supply a default impl class - IMessage msg = new Message("@DeclareParents: No defaultImpl was specified but the type '" + gen.getName() - + "' does not implement the method '" + stringifyMember(introduced) + "' defined on the interface '" - + introduced.getDeclaringType() + "'", weaver.getLazyClassGen().getType().getSourceLocation(), true, - new ISourceLocation[] { munger.getSourceLocation() }); - weaver.getWorld().getMessageHandler().handleMessage(msg); - return false; - } - - return true; - } - - LazyMethodGen mg = new LazyMethodGen(introduced.getModifiers() - Modifier.ABSTRACT, bcelReturnType, - introduced.getName(), BcelWorld.makeBcelTypes(introduced.getParameterTypes()), - BcelWorld.makeBcelTypesAsClassNames(introduced.getExceptions()), gen); - - // annotation copy from annotation on ITD interface - if (weaver.getWorld().isInJava5Mode()) { - AnnotationAJ annotationsOnRealMember[] = null; - ResolvedType toLookOn = weaver.getWorld().lookupOrCreateName(introduced.getDeclaringType()); - if (fromType.isRawType()) { - toLookOn = fromType.getGenericType(); - } - // lookup the method - ResolvedMember[] ms = toLookOn.getDeclaredJavaMethods(); - for (ResolvedMember m : ms) { - if (introduced.getName().equals(m.getName()) && introduced.getSignature().equals(m.getSignature())) { - annotationsOnRealMember = m.getAnnotations(); - break; - } - } - if (annotationsOnRealMember != null) { - for (AnnotationAJ anno : annotationsOnRealMember) { - AnnotationGen a = ((BcelAnnotation) anno).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); - mg.addAnnotation(new BcelAnnotation(ag, weaver.getWorld())); - } - } - } - - InstructionList body = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - - // getfield - body.append(InstructionConstants.ALOAD_0); - body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); - InstructionBranch ifNonNull = InstructionFactory.createBranchInstruction(Constants.IFNONNULL, null); - body.append(ifNonNull); - - // Create and store a new instance - body.append(InstructionConstants.ALOAD_0); // 'this' is where we'll store the field value - - // TODO for non-static case, call aspectOf() then call the factory method on the retval - // TODO decide whether the value can really be cached - - // locate the aspect and call the static method in it - if (munger.specifiesDelegateFactoryMethod()) { - ResolvedMember rm = munger.getDelegateFactoryMethod(weaver.getWorld()); - - // Check the method parameter is compatible with the type of the instance to be passed - if (rm.getArity() != 0) { - ResolvedType parameterType = rm.getParameterTypes()[0].resolve(weaver.getWorld()); - if (!parameterType.isAssignableFrom(weaver.getLazyClassGen().getType())) { - signalError("For mixin factory method '" + rm + "': Instance type '" + weaver.getLazyClassGen().getType() - + "' is not compatible with factory parameter type '" + parameterType + "'", weaver); - return false; - } - } - if (Modifier.isStatic(rm.getModifiers())) { - if (rm.getArity() != 0) { - body.append(InstructionConstants.ALOAD_0); - } - body.append(fact.createInvoke(rm.getDeclaringType().getName(), rm.getName(), rm.getSignature(), - Constants.INVOKESTATIC)); - body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); - } else { - // Need to call aspectOf() to obtain the aspect instance then call the factory method upon that - UnresolvedType theAspect = munger.getAspect(); - body.append(fact.createInvoke(theAspect.getName(), "aspectOf", "()" + theAspect.getSignature(), - Constants.INVOKESTATIC)); - if (rm.getArity() != 0) { - body.append(InstructionConstants.ALOAD_0); - } - body.append(fact.createInvoke(rm.getDeclaringType().getName(), rm.getName(), rm.getSignature(), - Constants.INVOKEVIRTUAL)); - body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); - } - } else { - body.append(fact.createNew(munger.getImplClassName())); - body.append(InstructionConstants.DUP); - body.append(fact.createInvoke(munger.getImplClassName(), "<init>", Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL)); - body.append(Utility.createSet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); - } - - // if not null use the instance we've got - InstructionHandle ifNonNullElse = body.append(InstructionConstants.ALOAD_0); - ifNonNull.setTarget(ifNonNullElse); - body.append(Utility.createGet(fact, munger.getDelegate(weaver.getLazyClassGen().getType()))); - - // args - int pos = 0; - if (!Modifier.isStatic(introduced.getModifiers())) { // skip 'this' (?? can this really - // happen) - // body.append(InstructionFactory.createThis()); - pos++; - } - Type[] paramTypes = BcelWorld.makeBcelTypes(introduced.getParameterTypes()); - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - pos += paramType.getSize(); - } - body.append(Utility.createInvoke(fact, Constants.INVOKEINTERFACE, introduced)); - body.append(InstructionFactory.createReturn(bcelReturnType)); - - mg.getBody().append(body); - weaver.addLazyMethodGen(mg); - weaver.getLazyClassGen().warnOnAddedMethod(mg.getMethod(), getSignature().getSourceLocation()); - return true; - } - return false; - } - - private boolean mungeFieldHost(BcelClassWeaver weaver, MethodDelegateTypeMunger.FieldHostTypeMunger munger) { - LazyClassGen gen = weaver.getLazyClassGen(); - if (gen.getType().isAnnotation() || gen.getType().isEnum()) { - // don't signal error as it could be a consequence of a wild type - // pattern - return false; - } - // boolean shouldApply = - munger.matches(weaver.getLazyClassGen().getType(), aspectType); // why - // do - // this? - ResolvedMember host = AjcMemberMaker.itdAtDeclareParentsField(weaver.getLazyClassGen().getType(), munger.getSignature() - .getType(), aspectType); - FieldGen field = makeFieldGen(weaver.getLazyClassGen(), host); - field.setModifiers(field.getModifiers() | BcelField.AccSynthetic); - weaver.getLazyClassGen().addField(field, null); - return true; - } - - private ResolvedMember getRealMemberForITDFromAspect(ResolvedType aspectType, ResolvedMember lookingFor, boolean isCtorRelated) { - World world = aspectType.getWorld(); - boolean debug = false; - if (debug) { - System.err.println("Searching for a member on type: " + aspectType); - System.err.println("Member we are looking for: " + lookingFor); - } - - ResolvedMember aspectMethods[] = aspectType.getDeclaredMethods(); - UnresolvedType[] lookingForParams = lookingFor.getParameterTypes(); - - ResolvedMember realMember = null; - for (int i = 0; realMember == null && i < aspectMethods.length; i++) { - ResolvedMember member = aspectMethods[i]; - if (member.getName().equals(lookingFor.getName())) { - UnresolvedType[] memberParams = member.getGenericParameterTypes(); - if (memberParams.length == lookingForParams.length) { - if (debug) { - System.err.println("Reviewing potential candidates: " + member); - } - boolean matchOK = true; - // If not related to a ctor ITD then the name is enough to - // confirm we have the - // right one. If it is ctor related we need to check the - // params all match, although - // only the erasure. - if (isCtorRelated) { - for (int j = 0; j < memberParams.length && matchOK; j++) { - ResolvedType pMember = memberParams[j].resolve(world); - ResolvedType pLookingFor = lookingForParams[j].resolve(world); - - if (pMember.isTypeVariableReference()) { - pMember = ((TypeVariableReference) pMember).getTypeVariable().getFirstBound().resolve(world); - } - if (pMember.isParameterizedType() || pMember.isGenericType()) { - pMember = pMember.getRawType().resolve(aspectType.getWorld()); - } - - if (pLookingFor.isTypeVariableReference()) { - pLookingFor = ((TypeVariableReference) pLookingFor).getTypeVariable().getFirstBound() - .resolve(world); - } - if (pLookingFor.isParameterizedType() || pLookingFor.isGenericType()) { - pLookingFor = pLookingFor.getRawType().resolve(world); - } - - if (debug) { - System.err.println("Comparing parameter " + j + " member=" + pMember + " lookingFor=" - + pLookingFor); - } - if (!pMember.equals(pLookingFor)) { - matchOK = false; - } - } - } - if (matchOK) { - realMember = member; - } - } - } - } - if (debug && realMember == null) { - System.err.println("Didn't find a match"); - } - return realMember; - } - - private void addNeededSuperCallMethods(BcelClassWeaver weaver, ResolvedType onType, Set<ResolvedMember> neededSuperCalls) { - LazyClassGen gen = weaver.getLazyClassGen(); - for (ResolvedMember superMethod: neededSuperCalls) { - if (weaver.addDispatchTarget(superMethod)) { - // System.err.println("super type: " + superMethod.getDeclaringType() + ", " + gen.getType()); - boolean isSuper = !superMethod.getDeclaringType().equals(gen.getType()); - String dispatchName; - if (isSuper) { - dispatchName = NameMangler.superDispatchMethod(onType, superMethod.getName()); - } else { - dispatchName = NameMangler.protectedDispatchMethod(onType, superMethod.getName()); - } - superMethod = superMethod.resolve(weaver.getWorld()); - LazyMethodGen dispatcher = makeDispatcher(gen, dispatchName, superMethod, weaver.getWorld(), isSuper); - weaver.addLazyMethodGen(dispatcher); - } - } - } - - private void signalError(String msgid, BcelClassWeaver weaver, UnresolvedType onType) { - IMessage msg = MessageUtil.error(WeaverMessages.format(msgid, onType.getName()), getSourceLocation()); - weaver.getWorld().getMessageHandler().handleMessage(msg); - } - - // private void signalWarning(String msgString, BcelClassWeaver weaver) { - // IMessage msg = MessageUtil.warn(msgString, getSourceLocation()); - // weaver.getWorld().getMessageHandler().handleMessage(msg); - // } - - private void signalError(String msgString, BcelClassWeaver weaver) { - IMessage msg = MessageUtil.error(msgString, getSourceLocation()); - weaver.getWorld().getMessageHandler().handleMessage(msg); - } - - private boolean mungeNewConstructor(BcelClassWeaver weaver, NewConstructorTypeMunger newConstructorTypeMunger) { - - final LazyClassGen currentClass = weaver.getLazyClassGen(); - final InstructionFactory fact = currentClass.getFactory(); - - ResolvedMember newConstructorMember = newConstructorTypeMunger.getSyntheticConstructor(); - ResolvedType onType = newConstructorMember.getDeclaringType().resolve(weaver.getWorld()); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - - if (onType.isAnnotation()) { - signalError(WeaverMessages.ITDC_ON_ANNOTATION_NOT_ALLOWED, weaver, onType); - return false; - } - - if (onType.isEnum()) { - signalError(WeaverMessages.ITDC_ON_ENUM_NOT_ALLOWED, weaver, onType); - return false; - } - - if (!onType.equals(currentClass.getType())) { - return false; - } - - ResolvedMember explicitConstructor = newConstructorTypeMunger.getExplicitConstructor(); - // int declaredParameterCount = - // newConstructorTypeMunger.getDeclaredParameterCount(); - LazyMethodGen mg = makeMethodGen(currentClass, newConstructorMember); - mg.setEffectiveSignature(newConstructorTypeMunger.getSignature(), Shadow.ConstructorExecution, true); - - // pr98901 - // For copying the annotations across, we have to discover the real - // member in the aspect - // which is holding them. - if (weaver.getWorld().isInJava5Mode()) { - - ResolvedMember interMethodDispatcher = AjcMemberMaker.postIntroducedConstructor(aspectType, onType, - newConstructorTypeMunger.getSignature().getParameterTypes()); - AnnotationAJ annotationsOnRealMember[] = null; - ResolvedMember realMember = getRealMemberForITDFromAspect(aspectType, interMethodDispatcher, true); - // 266602 - consider it missing to mean that the corresponding aspect had errors - if (realMember == null) { - // signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver); - // throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType); - } else { - annotationsOnRealMember = realMember.getAnnotations(); - } - if (annotationsOnRealMember != null) { - for (int i = 0; i < annotationsOnRealMember.length; i++) { - AnnotationAJ annotationX = annotationsOnRealMember[i]; - AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); - mg.addAnnotation(new BcelAnnotation(ag, weaver.getWorld())); - } - } - // the below loop fixes the very special (and very stupid) - // case where an aspect declares an annotation - // on an ITD it declared on itself. - List<DeclareAnnotation> allDecams = weaver.getWorld().getDeclareAnnotationOnMethods(); - for (Iterator<DeclareAnnotation> i = allDecams.iterator(); i.hasNext();) { - DeclareAnnotation decaMC = i.next(); - if (decaMC.matches(explicitConstructor, weaver.getWorld()) && mg.getEnclosingClass().getType() == aspectType) { - mg.addAnnotation(decaMC.getAnnotation()); - } - } - } - - // Might have to remove the default constructor - b275032 - // TODO could have tagged the type munger when the fact we needed to do this was detected earlier - if (mg.getArgumentTypes().length == 0) { - LazyMethodGen toRemove = null; - for (LazyMethodGen object : currentClass.getMethodGens()) { - if (object.getName().equals("<init>") && object.getArgumentTypes().length == 0) { - toRemove = object; - } - } - if (toRemove != null) { - currentClass.removeMethodGen(toRemove); - } - } - - currentClass.addMethodGen(mg); - // weaver.addLazyMethodGen(freshConstructor); - - InstructionList body = mg.getBody(); - - // add to body: push arts for call to pre, from actual args starting at - // 1 (skipping this), going to - // declared argcount + 1 - UnresolvedType[] declaredParams = newConstructorTypeMunger.getSignature().getParameterTypes(); - Type[] paramTypes = mg.getArgumentTypes(); - int frameIndex = 1; - for (int i = 0, len = declaredParams.length; i < len; i++) { - body.append(InstructionFactory.createLoad(paramTypes[i], frameIndex)); - frameIndex += paramTypes[i].getSize(); - } - // do call to pre - Member preMethod = AjcMemberMaker.preIntroducedConstructor(aspectType, onType, declaredParams); - body.append(Utility.createInvoke(fact, null, preMethod)); - - // create a local, and store return pre stuff into it. - int arraySlot = mg.allocateLocal(1); - body.append(InstructionFactory.createStore(Type.OBJECT, arraySlot)); - - // put this on the stack - body.append(InstructionConstants.ALOAD_0); - - // unpack pre args onto stack - UnresolvedType[] superParamTypes = explicitConstructor.getParameterTypes(); - - for (int i = 0, len = superParamTypes.length; i < len; i++) { - body.append(InstructionFactory.createLoad(Type.OBJECT, arraySlot)); - body.append(Utility.createConstant(fact, i)); - body.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(superParamTypes[i]))); - } - - // call super/this - - body.append(Utility.createInvoke(fact, null, explicitConstructor)); - - // put this back on the stack - - body.append(InstructionConstants.ALOAD_0); - - // unpack params onto stack - Member postMethod = AjcMemberMaker.postIntroducedConstructor(aspectType, onType, declaredParams); - UnresolvedType[] postParamTypes = postMethod.getParameterTypes(); - - for (int i = 1, len = postParamTypes.length; i < len; i++) { - body.append(InstructionFactory.createLoad(Type.OBJECT, arraySlot)); - body.append(Utility.createConstant(fact, superParamTypes.length + i - 1)); - body.append(InstructionFactory.createArrayLoad(Type.OBJECT)); - body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(postParamTypes[i]))); - } - - // call post - body.append(Utility.createInvoke(fact, null, postMethod)); - - // don't forget to return!! - body.append(InstructionConstants.RETURN); - - addNeededSuperCallMethods(weaver, onType, munger.getSuperMethodsCalled()); - - return true; - } - - private static LazyMethodGen makeDispatcher(LazyClassGen onGen, String dispatchName, ResolvedMember superMethod, - BcelWorld world, boolean isSuper) { - Type[] paramTypes = BcelWorld.makeBcelTypes(superMethod.getParameterTypes()); - Type returnType = BcelWorld.makeBcelType(superMethod.getReturnType()); - - int modifiers = Modifier.PUBLIC; - if (onGen.isInterface()) { - modifiers |= Modifier.ABSTRACT; - } - - LazyMethodGen mg = new LazyMethodGen(modifiers, returnType, dispatchName, paramTypes, UnresolvedType.getNames(superMethod - .getExceptions()), onGen); - InstructionList body = mg.getBody(); - - if (onGen.isInterface()) { - return mg; - } - - // assert (!superMethod.isStatic()) - InstructionFactory fact = onGen.getFactory(); - int pos = 0; - - body.append(InstructionFactory.createThis()); - pos++; - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - pos += paramType.getSize(); - } - if (isSuper) { - body.append(Utility.createSuperInvoke(fact, world, superMethod)); - } else { - body.append(Utility.createInvoke(fact, world, superMethod)); - } - body.append(InstructionFactory.createReturn(returnType)); - - return mg; - } - - private boolean mungeNewField(BcelClassWeaver weaver, NewFieldTypeMunger munger) { - /* ResolvedMember initMethod = */munger.getInitMethod(aspectType); - LazyClassGen gen = weaver.getLazyClassGen(); - ResolvedMember field = munger.getSignature(); - - ResolvedType onType = weaver.getWorld().resolve(field.getDeclaringType(), munger.getSourceLocation()); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - - boolean onInterface = onType.isInterface(); - - if (onType.isAnnotation()) { - signalError(WeaverMessages.ITDF_ON_ANNOTATION_NOT_ALLOWED, weaver, onType); - return false; - } - - if (onType.isEnum()) { - signalError(WeaverMessages.ITDF_ON_ENUM_NOT_ALLOWED, weaver, onType); - return false; - } - - ResolvedMember interMethodBody = munger.getInitMethod(aspectType); - - AnnotationAJ annotationsOnRealMember[] = null; - // pr98901 - // For copying the annotations across, we have to discover the real - // member in the aspect - // which is holding them. - if (weaver.getWorld().isInJava5Mode()) { - // the below line just gets the method with the same name in - // aspectType.getDeclaredMethods(); - ResolvedType toLookOn = aspectType; - if (aspectType.isRawType()) { - toLookOn = aspectType.getGenericType(); - } - ResolvedMember realMember = getRealMemberForITDFromAspect(toLookOn, interMethodBody, false); - if (realMember == null) { - // signalWarning("Unable to apply any annotations attached to " + munger.getSignature(), weaver); - // throw new BCException("Couldn't find ITD init member '" + interMethodBody + "' on aspect " + aspectType); - } else { - annotationsOnRealMember = realMember.getAnnotations(); - } - } - - if (onType.equals(gen.getType())) { - if (onInterface) { - ResolvedMember itdfieldGetter = AjcMemberMaker.interFieldInterfaceGetter(field, onType, aspectType); - LazyMethodGen mg = makeMethodGen(gen, itdfieldGetter); - gen.addMethodGen(mg); - - LazyMethodGen mg1 = makeMethodGen(gen, AjcMemberMaker.interFieldInterfaceSetter(field, onType, aspectType)); - gen.addMethodGen(mg1); - } else { - weaver.addInitializer(this); - ResolvedMember newField = AjcMemberMaker.interFieldClassField(field, aspectType, - munger.version == NewFieldTypeMunger.VersionTwo); - FieldGen fg = makeFieldGen(gen, newField); - - if (annotationsOnRealMember != null) { - for (int i = 0; i < annotationsOnRealMember.length; i++) { - AnnotationAJ annotationX = annotationsOnRealMember[i]; - AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); - fg.addAnnotation(ag); - } - } - - if (weaver.getWorld().isInJava5Mode()) { - String basicSignature = field.getSignature(); - String genericSignature = field.getReturnType().resolve(weaver.getWorld()).getSignatureForAttribute(); - // String genericSignature = - // ((ResolvedMemberImpl)field).getSignatureForAttribute(); - if (!basicSignature.equals(genericSignature)) { - // Add a signature attribute to it - fg.addAttribute(createSignatureAttribute(gen.getConstantPool(), genericSignature)); - } - } - gen.addField(fg, getSourceLocation()); - - } - return true; - } else if (onInterface && gen.getType().isTopmostImplementor(onType)) { - // we know that we can't be static since we don't allow statics on interfaces - if (Modifier.isStatic(field.getModifiers())) { - throw new RuntimeException("unimplemented"); - } - - boolean alreadyExists = false; - // only need to check for version 2 style mungers - if (munger.version==NewFieldTypeMunger.VersionTwo) { - for (BcelField fieldgen: gen.getFieldGens()) { - if (fieldgen.getName().equals(field.getName())) { - alreadyExists=true; - break; - } - } - } - - // FieldGen fg = makeFieldGen(gen, AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType)); - ResolvedMember newField = AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType, munger.version == NewFieldTypeMunger.VersionTwo); - String fieldName = newField.getName(); - - Type fieldType = BcelWorld.makeBcelType(field.getType()); - if (!alreadyExists) { - weaver.addInitializer(this); - FieldGen fg = makeFieldGen(gen,newField); - if (annotationsOnRealMember != null) { - for (int i = 0; i < annotationsOnRealMember.length; i++) { - AnnotationAJ annotationX = annotationsOnRealMember[i]; - AnnotationGen a = ((BcelAnnotation) annotationX).getBcelAnnotation(); - AnnotationGen ag = new AnnotationGen(a, weaver.getLazyClassGen().getConstantPool(), true); - fg.addAnnotation(ag); - } - } - - if (weaver.getWorld().isInJava5Mode()) { - String basicSignature = field.getSignature(); - String genericSignature = field.getReturnType().resolve(weaver.getWorld()).getSignatureForAttribute(); - // String genericSignature = - // ((ResolvedMemberImpl)field).getSignatureForAttribute(); - if (!basicSignature.equals(genericSignature)) { - // Add a signature attribute to it - fg.addAttribute(createSignatureAttribute(gen.getConstantPool(), genericSignature)); - } - } - gen.addField(fg, getSourceLocation()); - } - // this uses a shadow munger to add init method to constructors - // weaver.getShadowMungers().add(makeInitCallShadowMunger(initMethod) - // ); - - ResolvedMember itdfieldGetter = AjcMemberMaker.interFieldInterfaceGetter(field, gen.getType()/* onType */, aspectType); - LazyMethodGen mg = makeMethodGen(gen, itdfieldGetter); - InstructionList il = new InstructionList(); - InstructionFactory fact = gen.getFactory(); - if (Modifier.isStatic(field.getModifiers())) { - il.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.GETSTATIC)); - } else { - il.append(InstructionConstants.ALOAD_0); - il.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.GETFIELD)); - } - il.append(InstructionFactory.createReturn(fieldType)); - mg.getBody().insert(il); - - gen.addMethodGen(mg); - - // Check if we need bridge methods for the field getter and setter - if (munger.getDeclaredSignature() != null) { // is this munger a - // parameterized - // form of some - // original munger? - ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null, - munger.getSignature().getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases()); - boolean needsbridging = false; - if (!toBridgeTo.getReturnType().getErasureSignature() - .equals(munger.getSignature().getReturnType().getErasureSignature())) { - needsbridging = true; - } - if (needsbridging) { - ResolvedMember bridgingGetter = AjcMemberMaker.interFieldInterfaceGetter(toBridgeTo, gen.getType(), aspectType); - createBridgeMethodForITDF(weaver, gen, itdfieldGetter, bridgingGetter); - } - } - - ResolvedMember itdfieldSetter = AjcMemberMaker.interFieldInterfaceSetter(field, gen.getType(), aspectType); - LazyMethodGen mg1 = makeMethodGen(gen, itdfieldSetter); - InstructionList il1 = new InstructionList(); - if (Modifier.isStatic(field.getModifiers())) { - il1.append(InstructionFactory.createLoad(fieldType, 0)); - il1.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.PUTSTATIC)); - } else { - il1.append(InstructionConstants.ALOAD_0); - il1.append(InstructionFactory.createLoad(fieldType, 1)); - il1.append(fact.createFieldAccess(gen.getClassName(), fieldName, fieldType, Constants.PUTFIELD)); - } - il1.append(InstructionFactory.createReturn(Type.VOID)); - mg1.getBody().insert(il1); - - gen.addMethodGen(mg1); - - if (munger.getDeclaredSignature() != null) { - ResolvedMember toBridgeTo = munger.getDeclaredSignature().parameterizedWith(null, - munger.getSignature().getDeclaringType().resolve(getWorld()), false, munger.getTypeVariableAliases()); - boolean needsbridging = false; - if (!toBridgeTo.getReturnType().getErasureSignature() - .equals(munger.getSignature().getReturnType().getErasureSignature())) { - needsbridging = true; - } - if (needsbridging) { - ResolvedMember bridgingSetter = AjcMemberMaker.interFieldInterfaceSetter(toBridgeTo, gen.getType(), aspectType); - createBridgeMethodForITDF(weaver, gen, itdfieldSetter, bridgingSetter); - } - } - - return true; - } else { - return false; - } - } - - // FIXME asc combine with other createBridge.. method in this class, avoid - // the duplication... - private void createBridgeMethodForITDF(BcelClassWeaver weaver, LazyClassGen gen, ResolvedMember itdfieldSetter, - ResolvedMember bridgingSetter) { - InstructionFactory fact; - LazyMethodGen bridgeMethod = makeMethodGen(gen, bridgingSetter); - bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040); // BRIDGE = 0x00000040 - Type[] paramTypes = BcelWorld.makeBcelTypes(bridgingSetter.getParameterTypes()); - Type[] bridgingToParms = BcelWorld.makeBcelTypes(itdfieldSetter.getParameterTypes()); - Type returnType = BcelWorld.makeBcelType(bridgingSetter.getReturnType()); - InstructionList body = bridgeMethod.getBody(); - fact = gen.getFactory(); - int pos = 0; - - if (!Modifier.isStatic(bridgingSetter.getModifiers())) { - body.append(InstructionFactory.createThis()); - pos++; - } - for (int i = 0, len = paramTypes.length; i < len; i++) { - Type paramType = paramTypes[i]; - body.append(InstructionFactory.createLoad(paramType, pos)); - if (!bridgingSetter.getParameterTypes()[i].getErasureSignature().equals( - itdfieldSetter.getParameterTypes()[i].getErasureSignature())) { - body.append(fact.createCast(paramType, bridgingToParms[i])); - } - pos += paramType.getSize(); - } - - body.append(Utility.createInvoke(fact, weaver.getWorld(), itdfieldSetter)); - body.append(InstructionFactory.createReturn(returnType)); - gen.addMethodGen(bridgeMethod); - } - - @Override - public ConcreteTypeMunger parameterizedFor(ResolvedType target) { - return new BcelTypeMunger(munger.parameterizedFor(target), aspectType); - } - - @Override - public ConcreteTypeMunger parameterizeWith(Map<String, UnresolvedType> m, World w) { - return new BcelTypeMunger(munger.parameterizeWith(m, w), aspectType); - } - - /** - * Returns a list of type variable aliases used in this munger. For example, if the ITD is 'int I<A,B>.m(List<A> las,List<B> - * lbs) {}' then this returns a list containing the strings "A" and "B". - */ - public List<String> getTypeVariableAliases() { - return munger.getTypeVariableAliases(); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof BcelTypeMunger)) { - return false; - } - BcelTypeMunger o = (BcelTypeMunger) other; - return ((o.getMunger() == null) ? (getMunger() == null) : o.getMunger().equals(getMunger())) - && ((o.getAspectType() == null) ? (getAspectType() == null) : o.getAspectType().equals(getAspectType())); - // && (AsmManager.getDefault().getHandleProvider().dependsOnLocation() ? ((o.getSourceLocation() == null) ? - // (getSourceLocation() == null) - // : o.getSourceLocation().equals(getSourceLocation())) - // : true); // pr134471 - remove when handles are improved - // to be independent of location - - } - - private volatile int hashCode = 0; - - @Override - public int hashCode() { - if (hashCode == 0) { - int result = 17; - result = 37 * result + ((getMunger() == null) ? 0 : getMunger().hashCode()); - result = 37 * result + ((getAspectType() == null) ? 0 : getAspectType().hashCode()); - hashCode = result; - } - return hashCode; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelVar.java b/weaver/src/org/aspectj/weaver/bcel/BcelVar.java deleted file mode 100644 index ce45fdf12..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelVar.java +++ /dev/null @@ -1,117 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ast.Var; - -public class BcelVar extends Var { - - private int positionInAroundState = -1; - - private int slot; - - public BcelVar(ResolvedType type, int slot) { - super(type); - this.slot = slot; - } - - public String toString() { - return "BcelVar(" + getType() + " " + slot + ((positionInAroundState != -1) ? (" " + positionInAroundState) : "") + - - ")"; - } - - public int getSlot() { - return slot; - } - - // fact is used in the subtypes - public Instruction createLoad(InstructionFactory fact) { - return InstructionFactory.createLoad(BcelWorld.makeBcelType(getType()), slot); - } - - public Instruction createStore(InstructionFactory fact) { - return InstructionFactory.createStore(BcelWorld.makeBcelType(getType()), slot); - } - - public void appendStore(InstructionList il, InstructionFactory fact) { - il.append(createStore(fact)); - } - - public void appendLoad(InstructionList il, InstructionFactory fact) { - il.append(createLoad(fact)); - } - - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - il.append(createLoad(fact)); - Utility.appendConversion(il, fact, getType(), toType); - } - - public void insertLoad(InstructionList il, InstructionFactory fact) { - il.insert(createLoad(fact)); - } - - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - InstructionList il = new InstructionList(); - il.append(InstructionFactory.createLoad(BcelWorld.makeBcelType(getType()), oldSlot)); - il.append(createStore(fact)); - return il; - } - - // this is an array var - void appendConvertableArrayLoad(InstructionList il, InstructionFactory fact, int index, ResolvedType convertTo) { - ResolvedType convertFromType = getType().getResolvedComponentType(); - appendLoad(il, fact); - il.append(Utility.createConstant(fact, index)); - il.append(InstructionFactory.createArrayLoad(BcelWorld.makeBcelType(convertFromType))); - Utility.appendConversion(il, fact, convertFromType, convertTo); - } - - void appendConvertableArrayStore(InstructionList il, InstructionFactory fact, int index, BcelVar storee) { - ResolvedType convertToType = getType().getResolvedComponentType(); - appendLoad(il, fact); - il.append(Utility.createConstant(fact, index)); - storee.appendLoad(il, fact); - Utility.appendConversion(il, fact, storee.getType(), convertToType); - il.append(InstructionFactory.createArrayStore(BcelWorld.makeBcelType(convertToType))); - } - - InstructionList createConvertableArrayStore(InstructionFactory fact, int index, BcelVar storee) { - InstructionList il = new InstructionList(); - appendConvertableArrayStore(il, fact, index, storee); - return il; - } - - InstructionList createConvertableArrayLoad(InstructionFactory fact, int index, ResolvedType convertTo) { - InstructionList il = new InstructionList(); - appendConvertableArrayLoad(il, fact, index, convertTo); - return il; - } - - public int getPositionInAroundState() { - return positionInAroundState; - } - - public void setPositionInAroundState(int positionInAroundState) { - this.positionInAroundState = positionInAroundState; - } - - // random useful fields - - public static final BcelVar[] NONE = new BcelVar[] {}; - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeakClassLoaderReference.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeakClassLoaderReference.java deleted file mode 100644 index aac294fa4..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeakClassLoaderReference.java +++ /dev/null @@ -1,49 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008 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: - * Andy Clement initial implementation - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.util.ClassLoaderReference; -import org.aspectj.weaver.WeakClassLoaderReference; - -/** - * Wraps a reference to a classloader inside a WeakReference. This should be used where we do not want the existence of a - * classloader reference to prevent garbage collection of that classloader (and possibly an associated weaver instance in the case - * of load time weaving). - * <p> - * In more detail:<br> - * When load time weaving, the class Aj maintains a WeakHashMap from the classloader instance to a weaver instance. The aim is that - * the weaver is around as long as the classloader is and should the classloader be dereferenced then the weaver can also be garbage - * collected. The problem is that if there are many references to the classloader from within the weaver, these are considered hard - * references and cause the classloader to be long lived - even if the user of the classloader has dereferenced it in their code. - * The solution is that the weaver should use instances of WeakClassLoaderReference objects - so that when the users hard reference - * to the classloader goes, nothing in the weaver will cause it to hang around. There is a big assertion here that the - * WeakClassLoaderReference instances will not 'lose' their ClassLoader references until the top level ClassLoader reference is - * null'd. This means there is no need to check for the null case on get() in this WeakReference logic below, because we shouldn't - * be using this weaver if its associated ClassLoader has been collected. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=210470 - * - * - * @author Andy Clement - */ -public class BcelWeakClassLoaderReference extends WeakClassLoaderReference implements ClassLoaderReference { - - public BcelWeakClassLoaderReference(ClassLoader loader) { - super(loader); - } - - public boolean equals(Object obj) { - if (!(obj instanceof BcelWeakClassLoaderReference)) - return false; - BcelWeakClassLoaderReference other = (BcelWeakClassLoaderReference) obj; - return (other.hashcode == hashcode); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java deleted file mode 100644 index f83a79379..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ /dev/null @@ -1,2043 +0,0 @@ -/* ******************************************************************* - * 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 - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.Attributes.Name; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -import org.aspectj.apache.bcel.classfile.ClassParser; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.asm.AsmManager; -import org.aspectj.asm.IProgramElement; -import org.aspectj.asm.internal.AspectJElementHierarchy; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.bridge.SourceLocation; -import org.aspectj.bridge.WeaveMessage; -import org.aspectj.bridge.context.CompilationAndWeavingContext; -import org.aspectj.bridge.context.ContextToken; -import org.aspectj.util.FileUtil; -import org.aspectj.util.FuzzyBoolean; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.AnnotationOnTypeMunger; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.CompressingDataOutputStream; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.CrosscuttingMembersSet; -import org.aspectj.weaver.CustomMungerFactory; -import org.aspectj.weaver.IClassFileProvider; -import org.aspectj.weaver.IUnwovenClassFile; -import org.aspectj.weaver.IWeaveRequestor; -import org.aspectj.weaver.NewParentTypeMunger; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.WeaverStateInfo; -import org.aspectj.weaver.World; -import org.aspectj.weaver.model.AsmRelationshipProvider; -import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.BindingPattern; -import org.aspectj.weaver.patterns.BindingTypePattern; -import org.aspectj.weaver.patterns.ConcreteCflowPointcut; -import org.aspectj.weaver.patterns.DeclareAnnotation; -import org.aspectj.weaver.patterns.DeclareParents; -import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning; -import org.aspectj.weaver.patterns.FastMatchInfo; -import org.aspectj.weaver.patterns.IfPointcut; -import org.aspectj.weaver.patterns.KindedPointcut; -import org.aspectj.weaver.patterns.NameBindingPointcut; -import org.aspectj.weaver.patterns.NotPointcut; -import org.aspectj.weaver.patterns.OrPointcut; -import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.PointcutRewriter; -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"; - public static final String SYNTHETIC_CLASS_POSTFIX = "$ajc"; - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWeaver.class); - - private transient final BcelWorld world; - private final CrosscuttingMembersSet xcutSet; - - private boolean inReweavableMode = false; - - private transient List<UnwovenClassFile> addedClasses = new ArrayList<UnwovenClassFile>(); - private transient List<String> deletedTypenames = new ArrayList<String>(); - - // These four are setup by prepareForWeave - private transient List<ShadowMunger> shadowMungerList = null; - private transient List<ConcreteTypeMunger> typeMungerList = null; - private transient List<ConcreteTypeMunger> lateTypeMungerList = null; - private transient List<DeclareParents> declareParentsList = null; - - private Manifest manifest = null; - private boolean needToReweaveWorld = false; - - private boolean isBatchWeave = true; - - private ZipOutputStream zipOutputStream; - private CustomMungerFactory customMungerFactory; - - public BcelWeaver(BcelWorld world) { - super(); - if (trace.isTraceEnabled()) { - trace.enter("<init>", this, world); - } - this.world = world; - this.xcutSet = world.getCrosscuttingMembersSet(); - if (trace.isTraceEnabled()) { - trace.exit("<init>"); - } - } - - /** - * Add the given aspect to the weaver. The type is resolved to support DOT for static inner classes as well as DOLLAR - * - * @param aspectName - * @return aspect - */ - public ResolvedType addLibraryAspect(String aspectName) { - if (trace.isTraceEnabled()) { - trace.enter("addLibraryAspect", this, aspectName); - } - - // 1 - resolve as is - UnresolvedType unresolvedT = UnresolvedType.forName(aspectName); - unresolvedT.setNeedsModifiableDelegate(true); - ResolvedType type = world.resolve(unresolvedT, true); - if (type.isMissing()) { - // fallback on inner class lookup mechanism - String fixedName = aspectName; - int hasDot = fixedName.lastIndexOf('.'); - while (hasDot > 0) { - // System.out.println("BcelWeaver.addLibraryAspect " + fixedName); - char[] fixedNameChars = fixedName.toCharArray(); - fixedNameChars[hasDot] = '$'; - fixedName = new String(fixedNameChars); - hasDot = fixedName.lastIndexOf('.'); - UnresolvedType ut = UnresolvedType.forName(fixedName); - ut.setNeedsModifiableDelegate(true); - type = world.resolve(ut, true); - if (!type.isMissing()) { - break; - } - } - } - - // System.out.println("type: " + type + " for " + aspectName); - if (type.isAspect()) { - // Bug 119657 ensure we use the unwoven aspect - WeaverStateInfo wsi = type.getWeaverState(); - if (wsi != null && wsi.isReweavable()) { - BcelObjectType classType = getClassType(type.getName()); - JavaClass wovenJavaClass = classType.getJavaClass(); - byte[] bytes = wsi.getUnwovenClassFileData(wovenJavaClass.getBytes()); - JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(), bytes); - world.storeClass(unwovenJavaClass); - classType.setJavaClass(unwovenJavaClass, true); - // classType.setJavaClass(Utility.makeJavaClass(classType. - // getJavaClass().getFileName(), - // wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes( - // )))); - } - - // TODO AV - happens to reach that a lot of time: for each type - // flagged reweavable X for each aspect in the weaverstate - // => mainly for nothing for LTW - pbly for something in incremental - // build... - xcutSet.addOrReplaceAspect(type); - if (trace.isTraceEnabled()) { - trace.exit("addLibraryAspect", type); - } - if (type.getSuperclass().isAspect()) { - // If the supertype includes ITDs and the user has not included - // that aspect in the aop.xml, they will - // not get picked up, which can give unusual behaviour! See bug - // 223094 - // This change causes us to pick up the super aspect regardless - // of what was said in the aop.xml - giving - // predictable behaviour. If the user also supplied it, there - // will be no problem other than the second - // addition overriding the first - addLibraryAspect(type.getSuperclass().getName()); - } - return type; - } else { - if (type.isMissing()) { - // May not be found if not visible to the classloader that can see the aop.xml during LTW - IMessage message = new Message("The specified aspect '"+aspectName+"' cannot be found", null, true); - world.getMessageHandler().handleMessage(message); - } else { - IMessage message = new Message("Cannot register '"+aspectName+"' because the type found with that name is not an aspect", null, true); - world.getMessageHandler().handleMessage(message); - } - return null; - } - } - - /** - * - * @param inFile directory containing classes or zip/jar class archive - */ - public void addLibraryJarFile(File inFile) throws IOException { - List<ResolvedType> addedAspects = null; - if (inFile.isDirectory()) { - addedAspects = addAspectsFromDirectory(inFile); - } else { - addedAspects = addAspectsFromJarFile(inFile); - } - for (ResolvedType addedAspect : addedAspects) { - xcutSet.addOrReplaceAspect(addedAspect); - } - } - - private List<ResolvedType> addAspectsFromJarFile(File inFile) throws FileNotFoundException, IOException { - ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); // ??? buffered - List<ResolvedType> addedAspects = new ArrayList<ResolvedType>(); - try { - while (true) { - ZipEntry entry = inStream.getNextEntry(); - if (entry == null) { - break; - } - - if (entry.isDirectory() || !entry.getName().endsWith(".class")) { - continue; - } - - // FIXME ASC performance? of this alternative soln. - int size = (int) entry.getSize(); - ClassParser parser = new ClassParser(new ByteArrayInputStream(FileUtil.readAsByteArray(inStream)), entry.getName()); - JavaClass jc = parser.parse(); - inStream.closeEntry(); - - ResolvedType type = world.addSourceObjectType(jc, false).getResolvedTypeX(); - type.setBinaryPath(inFile.getAbsolutePath()); - if (type.isAspect()) { - addedAspects.add(type); - } else { - world.demote(type); - } - - } - } finally { - inStream.close(); - } - return addedAspects; - } - - /** - * 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(directory, new FileFilter() { - public boolean accept(File pathname) { - return pathname.getName().endsWith(".class"); - } - }); - 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; - } - - /** - * 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 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) { - binaryPath = dir.getAbsolutePath(); - } else { - binaryPath = name.substring(0, end - 1); - } - type.setBinaryPath(binaryPath); - if (type.isAspect()) { - return type; - } else { - // immediately demote the type we just added since it will have - // have been stuffed into the permanent map (assumed to be - // an aspect) - world.demote(type); - return null; - } - } - - // // The ANT copy task should be used to copy resources across. - // private final static boolean - // CopyResourcesFromInpathDirectoriesToOutput=false; - - /** - * Add any .class files in the directory to the outdir. Anything other than .class files in the directory (or its - * subdirectories) are considered resources and are also copied. - * - */ - public List<UnwovenClassFile> addDirectoryContents(File inFile, File outDir) throws IOException { - List<UnwovenClassFile> addedClassFiles = new ArrayList<UnwovenClassFile>(); - - // Get a list of all files (i.e. everything that isnt a directory) - File[] files = FileUtil.listFiles(inFile, new FileFilter() { - public boolean accept(File f) { - boolean accept = !f.isDirectory(); - return accept; - } - }); - - // For each file, add it either as a real .class file or as a resource - for (int i = 0; i < files.length; i++) { - addedClassFiles.add(addClassFile(files[i], inFile, outDir)); - } - - return addedClassFiles; - } - - /** - * Adds all class files in the jar - */ - public List<UnwovenClassFile> addJarFile(File inFile, File outDir, boolean canBeDirectory) { - // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")"); - List<UnwovenClassFile> addedClassFiles = new ArrayList<UnwovenClassFile>(); - needToReweaveWorld = true; - JarFile inJar = null; - - try { - // Is this a directory we are looking at? - if (inFile.isDirectory() && canBeDirectory) { - addedClassFiles.addAll(addDirectoryContents(inFile, outDir)); - } else { - - inJar = new JarFile(inFile); - try { - addManifest(inJar.getManifest()); - Enumeration entries = inJar.entries(); - - while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry) entries.nextElement(); - InputStream inStream = inJar.getInputStream(entry); - - byte[] bytes = FileUtil.readAsByteArray(inStream); - String filename = entry.getName(); - // System.out.println("? addJarFile() filename='" + filename - // + "'"); - UnwovenClassFile classFile = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes); - - if (filename.endsWith(".class")) { - ReferenceType type = this.addClassFile(classFile, false); - StringBuffer sb = new StringBuffer(); - sb.append(inFile.getAbsolutePath()); - sb.append("!"); - sb.append(entry.getName()); - type.setBinaryPath(sb.toString()); - addedClassFiles.add(classFile); - } - // else if (!entry.isDirectory()) { - // - // /* bug-44190 Copy meta-data */ - // addResource(filename,classFile); - // } - - inStream.close(); - } - } finally { - inJar.close(); - } - inJar.close(); - } - } catch (FileNotFoundException ex) { - IMessage message = new Message("Could not find input jar file " + inFile.getPath() + ", ignoring", new SourceLocation( - inFile, 0), false); - world.getMessageHandler().handleMessage(message); - } catch (IOException ex) { - IMessage message = new Message("Could not read input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")", - new SourceLocation(inFile, 0), true); - world.getMessageHandler().handleMessage(message); - } finally { - if (inJar != null) { - try { - inJar.close(); - } catch (IOException ex) { - IMessage message = new Message("Could not close input jar file " + inFile.getPath() + "(" + ex.getMessage() - + ")", new SourceLocation(inFile, 0), true); - world.getMessageHandler().handleMessage(message); - } - } - } - - return addedClassFiles; - } - - public boolean needToReweaveWorld() { - return needToReweaveWorld; - } - - /** - * Should be addOrReplace - */ - public ReferenceType addClassFile(UnwovenClassFile classFile, boolean fromInpath) { - addedClasses.add(classFile); - ReferenceType type = world.addSourceObjectType(classFile.getJavaClass(), false).getResolvedTypeX(); - if (fromInpath) { - type.setBinaryPath(classFile.getFilename()); - } - return type; - } - - public UnwovenClassFile addClassFile(File classFile, File inPathDir, File outDir) throws IOException { - FileInputStream fis = new FileInputStream(classFile); - byte[] bytes = FileUtil.readAsByteArray(fis); - // String relativePath = files[i].getPath(); - - // ASSERT: - // files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath() - // or we are in trouble... - String filename = classFile.getAbsolutePath().substring(inPathDir.getAbsolutePath().length() + 1); - UnwovenClassFile ucf = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes); - if (filename.endsWith(".class")) { - // System.err.println( - // "BCELWeaver: processing class from input directory "+classFile); - StringBuffer sb = new StringBuffer(); - sb.append(inPathDir.getAbsolutePath()); - sb.append("!"); - sb.append(filename); - ReferenceType type = this.addClassFile(ucf, false); - type.setBinaryPath(sb.toString()); - } - fis.close(); - return ucf; - } - - public void deleteClassFile(String typename) { - deletedTypenames.add(typename); - world.deleteSourceObjectType(UnresolvedType.forName(typename)); - } - - // ---- weave preparation - - public void setIsBatchWeave(boolean b) { - isBatchWeave = b; - } - - public void prepareForWeave() { - if (trace.isTraceEnabled()) { - trace.enter("prepareForWeave", this); - } - needToReweaveWorld = xcutSet.hasChangedSinceLastReset(); - - // update mungers - for (Iterator<UnwovenClassFile> i = addedClasses.iterator(); i.hasNext();) { - UnwovenClassFile jc = i.next(); - String name = jc.getClassName(); - ResolvedType type = world.resolve(name); - // No overweaving guard. If you have one then when overweaving is on the - // addOrReplaceAspect will not be called when the aspect delegate changes from - // EclipseSourceType to BcelObjectType. This will mean the mungers - // are not picked up. - if (type.isAspect()) { - needToReweaveWorld |= xcutSet.addOrReplaceAspect(type); - } - } - - for (Iterator<String> i = deletedTypenames.iterator(); i.hasNext();) { - String name = i.next(); - if (xcutSet.deleteAspect(UnresolvedType.forName(name))) { - needToReweaveWorld = true; - } - } - - shadowMungerList = xcutSet.getShadowMungers(); - // world.debug("shadow mungers=" + shadowMungerList); - rewritePointcuts(shadowMungerList); - // Sometimes an error occurs during rewriting pointcuts (for example, if - // ambiguous bindings - // are detected) - we ought to fail the prepare when this happens - // because continuing with - // inconsistent pointcuts could lead to problems - typeMungerList = xcutSet.getTypeMungers(); - lateTypeMungerList = xcutSet.getLateTypeMungers(); - declareParentsList = xcutSet.getDeclareParents(); - - addCustomMungers(); - - // The ordering here used to be based on a string compare on toString() - // for the two mungers - - // that breaks for the @AJ style where advice names aren't - // programmatically generated. So we - // have changed the sorting to be based on source location in the file - - // this is reliable, in - // the case of source locations missing, we assume they are 'sorted' - - // i.e. the order in - // which they were added to the collection is correct, this enables the - // @AJ stuff to work properly. - - // When @AJ processing starts filling in source locations for mungers, - // this code may need - // a bit of alteration... - - Collections.sort(shadowMungerList, new Comparator<ShadowMunger>() { - public int compare(ShadowMunger sm1, ShadowMunger sm2) { - if (sm1.getSourceLocation() == null) { - return (sm2.getSourceLocation() == null ? 0 : 1); - } - if (sm2.getSourceLocation() == null) { - return -1; - } - - return (sm2.getSourceLocation().getOffset() - sm1.getSourceLocation().getOffset()); - } - }); - - if (inReweavableMode) { - world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.REWEAVABLE_MODE), null, null); - } - - if (trace.isTraceEnabled()) { - trace.exit("prepareForWeave"); - } - } - - private void addCustomMungers() { - if (customMungerFactory != null) { - for (Iterator<UnwovenClassFile> i = addedClasses.iterator(); i.hasNext();) { - UnwovenClassFile jc = i.next(); - String name = jc.getClassName(); - ResolvedType type = world.resolve(name); - if (type.isAspect()) { - Collection<ShadowMunger> shadowMungers = customMungerFactory.createCustomShadowMungers(type); - if (shadowMungers != null) { - shadowMungerList.addAll(shadowMungers); - } - Collection<ConcreteTypeMunger> typeMungers = customMungerFactory.createCustomTypeMungers(type); - if (typeMungers != null) { - typeMungerList.addAll(typeMungers); - } - } - } - } - } - - public void setCustomMungerFactory(CustomMungerFactory factory) { - customMungerFactory = factory; - } - - /* - * Rewrite all of the pointcuts in the world into their most efficient form for subsequent matching. Also ensure that if - * pc1.equals(pc2) then pc1 == pc2 (for non-binding pcds) by making references all point to the same instance. Since pointcuts - * 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) { - PointcutRewriter rewriter = new PointcutRewriter(); - for (ShadowMunger munger : shadowMungers) { - Pointcut p = munger.getPointcut(); - Pointcut newP = rewriter.rewrite(p); - // validateBindings now whilst we still have around the pointcut - // that resembles what the user actually wrote in their program - // text. - if (munger instanceof Advice) { - Advice advice = (Advice) munger; - if (advice.getSignature() != null) { - final int numFormals; - final String names[]; - // If the advice is being concretized in a @AJ aspect *and* - // the advice was declared in - // an @AJ aspect (it could have been inherited from a code - // style aspect) then - // evaluate the alternative set of formals. pr125699 - if ((advice.getConcreteAspect().isAnnotationStyleAspect() && advice.getDeclaringAspect() != null && advice - .getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) - || advice.isAnnotationStyle()) { - numFormals = advice.getBaseParameterCount(); - int numArgs = advice.getSignature().getParameterTypes().length; - if (numFormals > 0) { - names = advice.getSignature().getParameterNames(world); - validateBindings(newP, p, numArgs, names); - } - } else { - numFormals = advice.getBaseParameterCount(); - if (numFormals > 0) { - names = advice.getBaseParameterNames(world); - validateBindings(newP, p, numFormals, names); - } - } - } - } - newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames; - munger.setPointcut(newP); - } - // now that we have optimized individual pointcuts, optimize - // across the set of pointcuts.... - // Use a map from key based on pc equality, to value based on - // pc identity. - Map<Pointcut, Pointcut> pcMap = new HashMap<Pointcut, Pointcut>(); - for (ShadowMunger munger: shadowMungers) { - Pointcut p = munger.getPointcut(); - Pointcut newP = shareEntriesFromMap(p, pcMap); - newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames; - munger.setPointcut(newP); - } - } - - private Pointcut shareEntriesFromMap(Pointcut p, Map<Pointcut, Pointcut> pcMap) { - // some things cant be shared... - if (p instanceof NameBindingPointcut) { - return p; - } - if (p instanceof IfPointcut) { - return p; - } - if (p instanceof ConcreteCflowPointcut) { - return p; - } - if (p instanceof AndPointcut) { - AndPointcut apc = (AndPointcut) p; - Pointcut left = shareEntriesFromMap(apc.getLeft(), pcMap); - Pointcut right = shareEntriesFromMap(apc.getRight(), pcMap); - return new AndPointcut(left, right); - } else if (p instanceof OrPointcut) { - OrPointcut opc = (OrPointcut) p; - Pointcut left = shareEntriesFromMap(opc.getLeft(), pcMap); - Pointcut right = shareEntriesFromMap(opc.getRight(), pcMap); - return new OrPointcut(left, right); - } else if (p instanceof NotPointcut) { - NotPointcut npc = (NotPointcut) p; - Pointcut not = shareEntriesFromMap(npc.getNegatedPointcut(), pcMap); - return new NotPointcut(not); - } else { - // primitive pcd - if (pcMap.containsKey(p)) { // based on equality - return pcMap.get(p); // same instance (identity) - } else { - pcMap.put(p, p); - return p; - } - } - } - - // userPointcut is the pointcut that the user wrote in the program text. - // dnfPointcut is the same pointcut rewritten in DNF - // numFormals is the number of formal parameters in the pointcut - // if numFormals > 0 then every branch of a disjunction must bind each - // formal once and only once. - // in addition, the left and right branches of a disjunction must hold on - // join point kinds in common. - private void validateBindings(Pointcut dnfPointcut, Pointcut userPointcut, int numFormals, String[] names) { - if (numFormals == 0) { - return; // nothing to check - } - if (dnfPointcut.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) { - return; // cant have problems if you dont match! - } - if (dnfPointcut instanceof OrPointcut) { - OrPointcut orBasedDNFPointcut = (OrPointcut) dnfPointcut; - Pointcut[] leftBindings = new Pointcut[numFormals]; - Pointcut[] rightBindings = new Pointcut[numFormals]; - validateOrBranch(orBasedDNFPointcut, userPointcut, numFormals, names, leftBindings, rightBindings); - } else { - Pointcut[] bindings = new Pointcut[numFormals]; - validateSingleBranch(dnfPointcut, userPointcut, numFormals, names, bindings); - } - } - - private void validateOrBranch(OrPointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] leftBindings, - Pointcut[] rightBindings) { - Pointcut left = pc.getLeft(); - Pointcut right = pc.getRight(); - if (left instanceof OrPointcut) { - Pointcut[] newRightBindings = new Pointcut[numFormals]; - validateOrBranch((OrPointcut) left, userPointcut, numFormals, names, leftBindings, newRightBindings); - } else { - if (left.couldMatchKinds() != Shadow.NO_SHADOW_KINDS_BITS) { - validateSingleBranch(left, userPointcut, numFormals, names, leftBindings); - } - } - if (right instanceof OrPointcut) { - Pointcut[] newLeftBindings = new Pointcut[numFormals]; - validateOrBranch((OrPointcut) right, userPointcut, numFormals, names, newLeftBindings, rightBindings); - } else { - if (right.couldMatchKinds() != Shadow.NO_SHADOW_KINDS_BITS) { - validateSingleBranch(right, userPointcut, numFormals, names, rightBindings); - } - } - int kindsInCommon = left.couldMatchKinds() & right.couldMatchKinds(); - if (kindsInCommon != Shadow.NO_SHADOW_KINDS_BITS && couldEverMatchSameJoinPoints(left, right)) { - // we know that every branch binds every formal, so there is no - // ambiguity if each branch binds it in exactly the same way... - List<String> ambiguousNames = new ArrayList<String>(); - for (int i = 0; i < numFormals; i++) { - if (leftBindings[i] == null) { - if (rightBindings[i] != null) { - ambiguousNames.add(names[i]); - } - } else if (!leftBindings[i].equals(rightBindings[i])) { - ambiguousNames.add(names[i]); - } - } - if (!ambiguousNames.isEmpty()) { - raiseAmbiguityInDisjunctionError(userPointcut, ambiguousNames); - } - } - } - - // pc is a pointcut that does not contain any disjunctions - // check that every formal is bound (negation doesn't count). - // we know that numFormals > 0 or else we would not be called - private void validateSingleBranch(Pointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] bindings) { - boolean[] foundFormals = new boolean[numFormals]; - for (int i = 0; i < foundFormals.length; i++) { - foundFormals[i] = false; - } - validateSingleBranchRecursion(pc, userPointcut, foundFormals, names, bindings); - for (int i = 0; i < foundFormals.length; i++) { - if (!foundFormals[i]) { - boolean ignore = false; - // ATAJ soften the unbound error for implicit bindings like - // JoinPoint in @AJ style - for (int j = 0; j < userPointcut.m_ignoreUnboundBindingForNames.length; j++) { - if (names[i] != null && names[i].equals(userPointcut.m_ignoreUnboundBindingForNames[j])) { - ignore = true; - break; - } - } - if (!ignore) { - raiseUnboundFormalError(names[i], userPointcut); - } - } - } - } - - // each formal must appear exactly once - private void validateSingleBranchRecursion(Pointcut pc, Pointcut userPointcut, boolean[] foundFormals, String[] names, - Pointcut[] bindings) { - if (pc instanceof NotPointcut) { - // nots can only appear at leaves in DNF - NotPointcut not = (NotPointcut) pc; - if (not.getNegatedPointcut() instanceof NameBindingPointcut) { - NameBindingPointcut nnbp = (NameBindingPointcut) not.getNegatedPointcut(); - if (!nnbp.getBindingAnnotationTypePatterns().isEmpty() && !nnbp.getBindingTypePatterns().isEmpty()) { - raiseNegationBindingError(userPointcut); - } - } - } else if (pc instanceof AndPointcut) { - AndPointcut and = (AndPointcut) pc; - validateSingleBranchRecursion(and.getLeft(), userPointcut, foundFormals, names, bindings); - validateSingleBranchRecursion(and.getRight(), userPointcut, foundFormals, names, bindings); - } else if (pc instanceof NameBindingPointcut) { - List<BindingTypePattern> bindingTypePatterns = ((NameBindingPointcut) pc).getBindingTypePatterns(); - for (BindingTypePattern bindingTypePattern: bindingTypePatterns) { - int index = bindingTypePattern.getFormalIndex(); - bindings[index] = pc; - if (foundFormals[index]) { - raiseAmbiguousBindingError(names[index], userPointcut); - } else { - foundFormals[index] = true; - } - } - List<BindingPattern> bindingAnnotationTypePatterns = ((NameBindingPointcut) pc).getBindingAnnotationTypePatterns(); - for (BindingPattern bindingAnnotationTypePattern: bindingAnnotationTypePatterns) { - int index = bindingAnnotationTypePattern.getFormalIndex(); - bindings[index] = pc; - if (foundFormals[index]) { - raiseAmbiguousBindingError(names[index], userPointcut); - } else { - foundFormals[index] = true; - } - } - } else if (pc instanceof ConcreteCflowPointcut) { - ConcreteCflowPointcut cfp = (ConcreteCflowPointcut) pc; - int[] slots = cfp.getUsedFormalSlots(); - for (int i = 0; i < slots.length; i++) { - bindings[slots[i]] = cfp; - if (foundFormals[slots[i]]) { - raiseAmbiguousBindingError(names[slots[i]], userPointcut); - } else { - foundFormals[slots[i]] = true; - } - } - } - } - - // By returning false from this method, we are allowing binding of the same - // variable on either side of an or. - // Be conservative :- have to consider overriding, varargs, autoboxing, - // the effects of itds (on within for example), interfaces, the fact that - // join points can have multiple signatures and so on. - private boolean couldEverMatchSameJoinPoints(Pointcut left, Pointcut right) { - - if (left instanceof OrPointcut) { - OrPointcut leftOrPointcut = (OrPointcut) left; - if (couldEverMatchSameJoinPoints(leftOrPointcut.getLeft(), right)) { - return true; - } - if (couldEverMatchSameJoinPoints(leftOrPointcut.getRight(), right)) { - return true; - } - return false; - } - - if (right instanceof OrPointcut) { - OrPointcut rightOrPointcut = (OrPointcut) right; - if (couldEverMatchSameJoinPoints(left, rightOrPointcut.getLeft())) { - return true; - } - if (couldEverMatchSameJoinPoints(left, rightOrPointcut.getRight())) { - return true; - } - return false; - } - - // look for withins - WithinPointcut leftWithin = (WithinPointcut) findFirstPointcutIn(left, WithinPointcut.class); - WithinPointcut rightWithin = (WithinPointcut) findFirstPointcutIn(right, WithinPointcut.class); - if ((leftWithin != null) && (rightWithin != null)) { - if (!leftWithin.couldEverMatchSameJoinPointsAs(rightWithin)) { - return false; - } - } - // look for kinded - KindedPointcut leftKind = (KindedPointcut) findFirstPointcutIn(left, KindedPointcut.class); - KindedPointcut rightKind = (KindedPointcut) findFirstPointcutIn(right, KindedPointcut.class); - if ((leftKind != null) && (rightKind != null)) { - if (!leftKind.couldEverMatchSameJoinPointsAs(rightKind)) { - return false; - } - } - return true; - } - - private Pointcut findFirstPointcutIn(Pointcut toSearch, Class toLookFor) { - if (toSearch instanceof NotPointcut) { - return null; - } - if (toLookFor.isInstance(toSearch)) { - return toSearch; - } - if (toSearch instanceof AndPointcut) { - AndPointcut apc = (AndPointcut) toSearch; - Pointcut left = findFirstPointcutIn(apc.getLeft(), toLookFor); - if (left != null) { - return left; - } - return findFirstPointcutIn(apc.getRight(), toLookFor); - } - return null; - } - - /** - * @param userPointcut - */ - private void raiseNegationBindingError(Pointcut userPointcut) { - world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.NEGATION_DOESNT_ALLOW_BINDING), userPointcut - .getSourceContext().makeSourceLocation(userPointcut), null); - } - - private void raiseAmbiguousBindingError(String name, Pointcut pointcut) { - world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING, name), pointcut - .getSourceContext().makeSourceLocation(pointcut), null); - } - - /** - * @param userPointcut - */ - private void raiseAmbiguityInDisjunctionError(Pointcut userPointcut, List<String> names) { - StringBuffer formalNames = new StringBuffer(names.get(0).toString()); - for (int i = 1; i < names.size(); i++) { - formalNames.append(", "); - formalNames.append(names.get(i)); - } - world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING_IN_OR, formalNames), userPointcut - .getSourceContext().makeSourceLocation(userPointcut), null); - } - - /** - * @param name - * @param userPointcut - */ - private void raiseUnboundFormalError(String name, Pointcut userPointcut) { - world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL, name), - userPointcut.getSourceLocation(), null); - } - - public void addManifest(Manifest newManifest) { - // System.out.println("? addManifest() newManifest=" + newManifest); - if (manifest == null) { - manifest = newManifest; - } - } - - 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(); - attributes.put(Name.MANIFEST_VERSION, WEAVER_MANIFEST_VERSION); - attributes.put(CREATED_BY, WEAVER_CREATED_BY); - } - - return manifest; - } - - // ---- weaving - - // FOR TESTING - public Collection<String> weave(File file) throws IOException { - OutputStream os = FileUtil.makeOutputStream(file); - this.zipOutputStream = new ZipOutputStream(os); - prepareForWeave(); - Collection<String> c = weave(new IClassFileProvider() { - - public boolean isApplyAtAspectJMungersOnly() { - return false; - } - - public Iterator<UnwovenClassFile> getClassFileIterator() { - return addedClasses.iterator(); - } - - public IWeaveRequestor getRequestor() { - return new IWeaveRequestor() { - public void acceptResult(IUnwovenClassFile result) { - try { - writeZipEntry(result.getFilename(), result.getBytes()); - } catch (IOException ex) { - } - } - - public void processingReweavableState() { - } - - public void addingTypeMungers() { - } - - public void weavingAspects() { - } - - public void weavingClasses() { - } - - public void weaveCompleted() { - } - }; - } - }); - // /* BUG 40943*/ - // dumpResourcesToOutJar(); - zipOutputStream.close(); // this flushes and closes the acutal file - return c; - } - - private Set<IProgramElement> candidatesForRemoval = null; - - // variation of "weave" that sources class files from an external source. - public Collection<String> weave(IClassFileProvider input) throws IOException { - if (trace.isTraceEnabled()) { - trace.enter("weave", this, input); - } - ContextToken weaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING, ""); - Collection<String> wovenClassNames = new ArrayList<String>(); - IWeaveRequestor requestor = input.getRequestor(); - - if (world.getModel() != null && world.isMinimalModel()) { - candidatesForRemoval = new HashSet<IProgramElement>(); - } - if (world.getModel() != null && !isBatchWeave) { - AsmManager manager = world.getModelAsAsmManager(); - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - // remove all relationships where this file being woven is - // the target of the relationship - manager.removeRelationshipsTargettingThisType(classFile.getClassName()); - } - } - - // Go through the types and ensure any 'damaged' during compile time are - // repaired prior to weaving - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (theType != null) { - theType.ensureConsistent(); - } - } - } - - // special case for AtAspectJMungerOnly - see #113587 - if (input.isApplyAtAspectJMungersOnly()) { - ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, ""); - requestor.weavingAspects(); - // ContextToken aspectToken = - CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (theType.isAnnotationStyleAspect()) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType == null) { - throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); - } - LazyClassGen clazz = classType.getLazyClassGen(); - BcelPerClauseAspectAdder selfMunger = new BcelPerClauseAspectAdder(theType, theType.getPerClause().getKind()); - selfMunger.forceMunge(clazz, true); - classType.finishedWith(); - UnwovenClassFile[] newClasses = getClassFilesFor(clazz); - for (int news = 0; news < newClasses.length; news++) { - requestor.acceptResult(newClasses[news]); - } - wovenClassNames.add(classFile.getClassName()); - } - } - } - requestor.weaveCompleted(); - CompilationAndWeavingContext.leavingPhase(atAspectJMungersOnly); - return wovenClassNames; - } - - requestor.processingReweavableState(); - ContextToken reweaveToken = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, ""); - prepareToProcessReweavableState(); - // clear all state from files we'll be reweaving - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - BcelObjectType classType = getClassType(className); - - // null return from getClassType() means the delegate is an eclipse - // source type - so - // there *cant* be any reweavable state... (he bravely claimed...) - if (classType != null) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, className); - processReweavableStateIfPresent(className, classType); - CompilationAndWeavingContext.leavingPhase(tok); - } - } - } - - CompilationAndWeavingContext.leavingPhase(reweaveToken); - - ContextToken typeMungingToken = CompilationAndWeavingContext.enteringPhase( - CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, ""); - requestor.addingTypeMungers(); - - // We process type mungers in two groups, first mungers that change the - // type - // hierarchy, then 'normal' ITD type mungers. - - // Process the types in a predictable order (rather than the order - // encountered). - // For class A, the order is superclasses of A then superinterfaces of A - // (and this mechanism is applied recursively) - List<String> typesToProcess = new ArrayList<String>(); - for (Iterator<UnwovenClassFile> iter = input.getClassFileIterator(); iter.hasNext();) { - UnwovenClassFile clf = iter.next(); - if (clf.shouldBeWoven()) { - typesToProcess.add(clf.getClassName()); - } - } - while (typesToProcess.size() > 0) { - weaveParentsFor(typesToProcess, typesToProcess.get(0), null); - } - - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - addNormalTypeMungers(className); - } - } - - CompilationAndWeavingContext.leavingPhase(typeMungingToken); - - requestor.weavingAspects(); - ContextToken aspectToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); - // first weave into aspects - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (theType.isAspect()) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType == null) { - - // Sometimes.. if the Bcel Delegate couldn't be found then a - // problem occurred at compile time - on - // a previous compiler run. In this case I assert the - // delegate will still be an EclipseSourceType - // and we can ignore the problem here (the original compile - // error will be reported again from - // the eclipse source type) - pr113531 - ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); - if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) { - continue; - } - - throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); - } - weaveAndNotify(classFile, classType, requestor); - wovenClassNames.add(className); - } - } - } - - CompilationAndWeavingContext.leavingPhase(aspectToken); - - requestor.weavingClasses(); - ContextToken classToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_CLASSES, ""); - // then weave into non-aspects - for (Iterator<UnwovenClassFile> i = input.getClassFileIterator(); i.hasNext();) { - UnwovenClassFile classFile = i.next(); - if (classFile.shouldBeWoven()) { - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (!theType.isAspect()) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType == null) { - - // bug 119882 - see above comment for bug 113531 - ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); - - // TODO urgh - put a method on the interface to check this, - // string compare is hideous - if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) { - continue; - } - - throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); - } - weaveAndNotify(classFile, classType, requestor); - wovenClassNames.add(className); - } - } - } - CompilationAndWeavingContext.leavingPhase(classToken); - - addedClasses.clear(); - deletedTypenames.clear(); - - requestor.weaveCompleted(); - CompilationAndWeavingContext.leavingPhase(weaveToken); - if (trace.isTraceEnabled()) { - trace.exit("weave", wovenClassNames); - } - if (world.getModel() != null && world.isMinimalModel()) { - candidatesForRemoval.clear(); - } - return wovenClassNames; - } - - public void allWeavingComplete() { - warnOnUnmatchedAdvice(); - } - - /** - * In 1.5 mode and with XLint:adviceDidNotMatch enabled, put out messages for any mungers that did not match anything. - */ - private void warnOnUnmatchedAdvice() { - - class AdviceLocation { - private final int lineNo; - private final UnresolvedType inAspect; - - public AdviceLocation(BcelAdvice advice) { - this.lineNo = advice.getSourceLocation().getLine(); - this.inAspect = advice.getDeclaringAspect(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof AdviceLocation)) { - return false; - } - AdviceLocation other = (AdviceLocation) obj; - if (this.lineNo != other.lineNo) { - return false; - } - if (!this.inAspect.equals(other.inAspect)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return 37 + 17 * lineNo + 17 * inAspect.hashCode(); - } - } - - // FIXME asc Should be factored out into Xlint code and done - // automatically for all xlint messages, ideally. - // if a piece of advice hasn't matched anywhere and we are in -1.5 mode, - // put out a warning - if (world.isInJava5Mode() && world.getLint().adviceDidNotMatch.isEnabled()) { - List l = world.getCrosscuttingMembersSet().getShadowMungers(); - Set<AdviceLocation> alreadyWarnedLocations = new HashSet<AdviceLocation>(); - - for (Iterator iter = l.iterator(); iter.hasNext();) { - ShadowMunger element = (ShadowMunger) iter.next(); - // This will stop us incorrectly reporting deow checkers: - if (element instanceof BcelAdvice) { - BcelAdvice ba = (BcelAdvice) element; - if (ba.getKind() == AdviceKind.CflowEntry || ba.getKind() == AdviceKind.CflowBelowEntry) { - continue; - } - if (!ba.hasMatchedSomething()) { - // Because we implement some features of AJ itself by - // creating our own kind of mungers, you sometimes - // find that ba.getSignature() is not a BcelMethod - for - // example it might be a cflow entry munger. - if (ba.getSignature() != null) { - // check we haven't already warned on this advice and line - // (cflow creates multiple mungers for the same advice) - AdviceLocation loc = new AdviceLocation(ba); - if (alreadyWarnedLocations.contains(loc)) { - continue; - } else { - alreadyWarnedLocations.add(loc); - } - - if (!(ba.getSignature() instanceof BcelMethod) - || !Utility.isSuppressing(ba.getSignature(), "adviceDidNotMatch")) { - world.getLint().adviceDidNotMatch.signal(ba.getDeclaringAspect().toString(), new SourceLocation( - element.getSourceLocation().getSourceFile(), element.getSourceLocation().getLine())); - } - } - } - } - } - } - } - - /** - * 'typeToWeave' is one from the 'typesForWeaving' list. This routine ensures we process supertypes (classes/interfaces) of - * 'typeToWeave' that are in the 'typesForWeaving' list before 'typeToWeave' itself. 'typesToWeave' is then removed from the - * 'typesForWeaving' list. - * - * Note: Future gotcha in here ... when supplying partial hierarchies, this algorithm may break down. If you have a hierarchy - * A>B>C and only give A and C to the weaver, it may choose to weave them in either order - but you'll probably have other - * problems if you are supplying partial hierarchies like that ! - */ - private void weaveParentsFor(List<String> typesForWeaving, String typeToWeave, ResolvedType resolvedTypeToWeave) { - if (resolvedTypeToWeave == null) { - // resolve it if the caller could not pass in the resolved type - resolvedTypeToWeave = world.resolve(typeToWeave); - } - ResolvedType superclassType = resolvedTypeToWeave.getSuperclass(); - String superclassTypename = (superclassType == null ? null : superclassType.getName()); - - // PR336654 added the 'typesForWeaving.contains(superclassTypename)' clause. - // Without it we can delete all type mungers on the parents and yet we only - // add back in the declare parents related ones, not the regular ITDs. - if (superclassType != null && !superclassType.isTypeHierarchyComplete() && superclassType.isExposedToWeaver() - && typesForWeaving.contains(superclassTypename)) { - weaveParentsFor(typesForWeaving, superclassTypename, superclassType); - } - - ResolvedType[] interfaceTypes = resolvedTypeToWeave.getDeclaredInterfaces(); - for (ResolvedType resolvedSuperInterface : interfaceTypes) { - if (!resolvedSuperInterface.isTypeHierarchyComplete()) { - String interfaceTypename = resolvedSuperInterface.getName(); - if (resolvedSuperInterface.isExposedToWeaver()) { // typesForWeaving.contains(interfaceTypename)) { - weaveParentsFor(typesForWeaving, interfaceTypename, resolvedSuperInterface); - } - } - } - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_PARENTS, - resolvedTypeToWeave.getName()); - // If A was processed before B (and was declared 'class A implements B') then there is no need to complete B again, it - // will have been done whilst processing A. - if (!resolvedTypeToWeave.isTypeHierarchyComplete()) { - weaveParentTypeMungers(resolvedTypeToWeave); - } - CompilationAndWeavingContext.leavingPhase(tok); - typesForWeaving.remove(typeToWeave); - resolvedTypeToWeave.tagAsTypeHierarchyComplete(); - } - - public void prepareToProcessReweavableState() { - } - - public void processReweavableStateIfPresent(String className, BcelObjectType classType) { - // If the class is marked reweavable, check any aspects around when it - // was built are in this world - WeaverStateInfo wsi = classType.getWeaverState(); - // System.out.println(">> processReweavableStateIfPresent " + className + " wsi=" + wsi); - if (wsi != null && wsi.isReweavable()) { // Check all necessary types - // are around! - world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.PROCESSING_REWEAVABLE, className, classType - .getSourceLocation().getSourceFile()), null, null); - Set<String> aspectsPreviouslyInWorld = wsi.getAspectsAffectingType(); - // keep track of them just to ensure unique missing aspect error - // reporting - Set<String> alreadyConfirmedReweavableState = new HashSet<String>(); - for (String requiredTypeSignature : aspectsPreviouslyInWorld) { - // for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) { - // String requiredTypeName = (String) iter.next(); - if (!alreadyConfirmedReweavableState.contains(requiredTypeSignature)) { - ResolvedType rtx = world.resolve(UnresolvedType.forSignature(requiredTypeSignature), true); - boolean exists = !rtx.isMissing(); - if (!world.isOverWeaving()) { - if (!exists) { - world.getLint().missingAspectForReweaving.signal(new String[] { rtx.getName(), className }, - classType.getSourceLocation(), null); - // world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.MISSING_REWEAVABLE_TYPE, - // requiredTypeName, className), classType.getSourceLocation(), null); - } else { - // weaved in aspect that are not declared in aop.xml - // trigger an error for now - // may cause headhache for LTW and packaged lib - // without aop.xml in - // see #104218 - if (!xcutSet.containsAspect(rtx)) { - world.showMessage(IMessage.ERROR, WeaverMessages.format( - WeaverMessages.REWEAVABLE_ASPECT_NOT_REGISTERED, rtx.getName(), className), null, null); - } else if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { - world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.VERIFIED_REWEAVABLE_TYPE, - rtx.getName(), rtx.getSourceLocation().getSourceFile()), null, null); - } - alreadyConfirmedReweavableState.add(requiredTypeSignature); - } - } - } - } - // old: - // classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass - // ().getFileName(), wsi.getUnwovenClassFileData())); - // new: reweavable default with clever diff - if (!world.isOverWeaving()) { - byte[] ucfd = wsi.getUnwovenClassFileData(); - if (ucfd.length == 0) { - // Size 0 indicates the class was previously overwoven, so you need to be overweaving now! - world.getMessageHandler().handleMessage( - MessageUtil.error( - WeaverMessages.format(WeaverMessages.MUST_KEEP_OVERWEAVING_ONCE_START, - className))); -// onType.getName(), annoX.getTypeName(), annoX.getValidTargets()), -// decA.getSourceLocation())); - } else { - byte[] bytes = wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()); - JavaClass newJavaClass = Utility.makeJavaClass(classType.getJavaClass().getFileName(), bytes); - classType.setJavaClass(newJavaClass, true); - classType.getResolvedTypeX().ensureConsistent(); - } - } - // } else { - // classType.resetState(); - } - } - - private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType, IWeaveRequestor requestor) throws IOException { - trace.enter("weaveAndNotify", this, new Object[] { classFile, classType, requestor }); - - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_TYPE, classType - .getResolvedTypeX().getName()); - LazyClassGen clazz = weaveWithoutDump(classFile, classType); - classType.finishedWith(); - // clazz is null if the classfile was unchanged by weaving... - if (clazz != null) { - UnwovenClassFile[] newClasses = getClassFilesFor(clazz); - // OPTIMIZE can we avoid using the string name at all in - // UnwovenClassFile instances? - // Copy the char[] across as it means the - // WeaverAdapter.removeFromMap() can be fast! - if (newClasses[0].getClassName().equals(classFile.getClassName())) { - newClasses[0].setClassNameAsChars(classFile.getClassNameAsChars()); - } - for (int i = 0; i < newClasses.length; i++) { - requestor.acceptResult(newClasses[i]); - } - } else { - requestor.acceptResult(classFile); - } - classType.weavingCompleted(); - CompilationAndWeavingContext.leavingPhase(tok); - - trace.exit("weaveAndNotify"); - } - - /** - * helper method - will return NULL if the underlying delegate is an EclipseSourceType and not a BcelObjectType - */ - public BcelObjectType getClassType(String forClass) { - return BcelWorld.getBcelObjectType(world.resolve(forClass)); - } - - public void addParentTypeMungers(String typeName) { - weaveParentTypeMungers(world.resolve(typeName)); - } - - public void addNormalTypeMungers(String typeName) { - weaveNormalTypeMungers(world.resolve(typeName)); - } - - public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) { - List<UnwovenClassFile.ChildClass> childClasses = clazz.getChildClasses(world); - UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()]; - ret[0] = new UnwovenClassFile(clazz.getFileName(), clazz.getClassName(), clazz.getJavaClassBytesIncludingReweavable(world)); - int index = 1; - for (Iterator<UnwovenClassFile.ChildClass> iter = childClasses.iterator(); iter.hasNext();) { - UnwovenClassFile.ChildClass element = iter.next(); - UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes); - ret[index++] = childClass; - } - return ret; - } - - /** - * Weaves new parents and annotations onto a type ("declare parents" and "declare @type") - * - * Algorithm: 1. First pass, do parents then do annotations. During this pass record: - any parent mungers that don't match but - * have a non-wild annotation type pattern - any annotation mungers that don't match 2. Multiple subsequent passes which go over - * the munger lists constructed in the first pass, repeatedly applying them until nothing changes. FIXME asc confirm that - * algorithm is optimal ?? - */ - public void weaveParentTypeMungers(ResolvedType onType) { - if (onType.isRawType() || onType.isParameterizedType()) { - onType = onType.getGenericType(); - } - onType.clearInterTypeMungers(); - - List<DeclareParents> decpToRepeat = new ArrayList<DeclareParents>(); - - boolean aParentChangeOccurred = false; - boolean anAnnotationChangeOccurred = false; - // First pass - apply all decp mungers - for (DeclareParents decp : declareParentsList) { - boolean typeChanged = applyDeclareParents(decp, onType); - if (typeChanged) { - aParentChangeOccurred = true; - } else { - decpToRepeat.add(decp); - } - } - - // Still first pass - apply all dec @type mungers - for (DeclareAnnotation decA : xcutSet.getDeclareAnnotationOnTypes()) { - boolean typeChanged = applyDeclareAtType(decA, onType, true); - if (typeChanged) { - anAnnotationChangeOccurred = true; - } - } - - while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) { - anAnnotationChangeOccurred = aParentChangeOccurred = false; - List<DeclareParents> decpToRepeatNextTime = new ArrayList<DeclareParents>(); - for (Iterator<DeclareParents> iter = decpToRepeat.iterator(); iter.hasNext();) { - DeclareParents decp = iter.next(); - boolean typeChanged = applyDeclareParents(decp, onType); - if (typeChanged) { - aParentChangeOccurred = true; - } else { - decpToRepeatNextTime.add(decp); - } - } - - for (DeclareAnnotation decA : xcutSet.getDeclareAnnotationOnTypes()) { - boolean typeChanged = applyDeclareAtType(decA, onType, false); - if (typeChanged) { - anAnnotationChangeOccurred = true; - } - } - decpToRepeat = decpToRepeatNextTime; - } - } - - /** - * Apply a declare @type - return true if we change the type - */ - private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType, boolean reportProblems) { - boolean didSomething = false; - if (decA.matches(onType)) { - AnnotationAJ theAnnotation = decA.getAnnotation(); - // can be null for broken code! - if (theAnnotation == null) { - return false; - } - if (onType.hasAnnotation(theAnnotation.getType())) { - // Could put out a lint here for an already annotated type ... - // if (reportProblems) { - // world.getLint().elementAlreadyAnnotated.signal( - // new - // String[]{onType.toString(),decA.getAnnotationTypeX().toString - // ()}, - // onType.getSourceLocation(),new - // ISourceLocation[]{decA.getSourceLocation()}); - // } - return false; - } - - AnnotationAJ annoX = decA.getAnnotation(); - - // check the annotation is suitable for the target - boolean problemReported = verifyTargetIsOK(decA, onType, annoX, reportProblems); - - if (!problemReported) { - AsmRelationshipProvider.addDeclareAnnotationRelationship(world.getModelAsAsmManager(), decA.getSourceLocation(), - onType.getSourceLocation(), false); - // TAG: WeavingMessage - if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { - getWorld().getMessageHandler().handleMessage( - WeaveMessage.constructWeavingMessage( - WeaveMessage.WEAVEMESSAGE_ANNOTATES, - new String[] { onType.toString(), Utility.beautifyLocation(onType.getSourceLocation()), - decA.getAnnotationString(), "type", decA.getAspect().toString(), - Utility.beautifyLocation(decA.getSourceLocation()) })); - } - didSomething = true; - ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX); - newAnnotationTM.setSourceLocation(decA.getSourceLocation()); - onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM, decA.getAspect().resolve(world)), false); - decA.copyAnnotationTo(onType); - } - } - return didSomething; - } - - /** - * Checks for an @target() on the annotation and if found ensures it allows the annotation to be attached to the target type - * that matched. - */ - private boolean verifyTargetIsOK(DeclareAnnotation decA, ResolvedType onType, AnnotationAJ annoX, boolean outputProblems) { - boolean problemReported = false; - if (annoX.specifiesTarget()) { - if ((onType.isAnnotation() && !annoX.allowedOnAnnotationType()) || (!annoX.allowedOnRegularType())) { - if (outputProblems) { - if (decA.isExactPattern()) { - world.getMessageHandler().handleMessage( - MessageUtil.error( - WeaverMessages.format(WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION, - onType.getName(), annoX.getTypeName(), annoX.getValidTargets()), - decA.getSourceLocation())); - } else { - if (world.getLint().invalidTargetForAnnotation.isEnabled()) { - world.getLint().invalidTargetForAnnotation.signal(new String[] { onType.getName(), annoX.getTypeName(), - annoX.getValidTargets() }, decA.getSourceLocation(), - new ISourceLocation[] { onType.getSourceLocation() }); - } - } - } - problemReported = true; - } - } - return problemReported; - } - - /** - * Apply a single declare parents - return true if we change the type - */ - private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) { - boolean didSomething = false; - List<ResolvedType> newParents = p.findMatchingNewParents(onType, true); - if (!newParents.isEmpty()) { - didSomething = true; - BcelWorld.getBcelObjectType(onType); - // System.err.println("need to do declare parents for: " + onType); - for (ResolvedType newParent : newParents) { - // We set it here so that the imminent matching for ITDs can - // succeed - we still haven't done the necessary changes to the class file - // itself (like transform super calls) - that is done in - // BcelTypeMunger.mungeNewParent() - // classType.addParent(newParent); - onType.addParent(newParent); - NewParentTypeMunger newParentMunger = new NewParentTypeMunger(newParent, p.getDeclaringType()); - if (p.isMixin()) { - newParentMunger.setIsMixin(true); - } - newParentMunger.setSourceLocation(p.getSourceLocation()); - onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, xcutSet.findAspectDeclaringParents(p)), false); - } - } - return didSomething; - } - - public void weaveNormalTypeMungers(ResolvedType onType) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, - onType.getName()); - if (onType.isRawType() || onType.isParameterizedType()) { - onType = onType.getGenericType(); - } - for (ConcreteTypeMunger m : typeMungerList) { - if (!m.isLateMunger() && m.matches(onType)) { - onType.addInterTypeMunger(m, false); - } - } - CompilationAndWeavingContext.leavingPhase(tok); - } - - // exposed for ClassLoader dynamic weaving - public LazyClassGen weaveWithoutDump(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { - return weave(classFile, classType, false); - } - - // FOR TESTING - LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { - LazyClassGen ret = weave(classFile, classType, true); - return ret; - } - - private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException { - - try { - if (classType.isSynthetic()) { // Don't touch synthetic classes - if (dump) { - dumpUnchanged(classFile); - } - return null; - } - ReferenceType resolvedClassType = classType.getResolvedTypeX(); - - if (world.isXmlConfigured() && world.getXmlConfiguration().excludesType(resolvedClassType)) { - if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { - world.getMessageHandler().handleMessage( - MessageUtil.info("Type '" + resolvedClassType.getName() - + "' not woven due to exclusion via XML weaver exclude section")); - - } - if (dump) { - dumpUnchanged(classFile); - } - return null; - } - - List<ShadowMunger> shadowMungers = fastMatch(shadowMungerList, resolvedClassType); - List<ConcreteTypeMunger> typeMungers = classType.getResolvedTypeX().getInterTypeMungers(); - - resolvedClassType.checkInterTypeMungers(); - - // Decide if we need to do actual weaving for this class - boolean mightNeedToWeave = shadowMungers.size() > 0 || typeMungers.size() > 0 || classType.isAspect() - || world.getDeclareAnnotationOnMethods().size() > 0 || world.getDeclareAnnotationOnFields().size() > 0; - - // May need bridge methods if on 1.5 and something in our hierarchy is - // affected by ITDs - boolean mightNeedBridgeMethods = world.isInJava5Mode() && !classType.isInterface() - && resolvedClassType.getInterTypeMungersIncludingSupers().size() > 0; - - LazyClassGen clazz = null; - if (mightNeedToWeave || mightNeedBridgeMethods) { - clazz = classType.getLazyClassGen(); - // System.err.println("got lazy gen: " + clazz + ", " + - // clazz.getWeaverState()); - try { - boolean isChanged = false; - - if (mightNeedToWeave) { - isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers, lateTypeMungerList, - inReweavableMode); - } - - checkDeclareTypeErrorOrWarning(world, classType); - - if (mightNeedBridgeMethods) { - isChanged = BcelClassWeaver.calculateAnyRequiredBridgeMethods(world, clazz) || isChanged; - } - - if (isChanged) { - if (dump) { - dump(classFile, clazz); - } - return clazz; - } - } catch (RuntimeException re) { - String classDebugInfo = null; - try { - classDebugInfo = clazz.toLongString(); - } catch (Throwable e) { - new RuntimeException("Crashed whilst crashing with this exception: " + e, e).printStackTrace(); - // recover from crash whilst producing debug string - classDebugInfo = clazz.getClassName(); - } - String messageText = "trouble in: \n" + classDebugInfo; - getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); - } catch (Error re) { - String classDebugInfo = null; - try { - classDebugInfo = clazz.toLongString(); - } catch (OutOfMemoryError oome) { - System.err.println("Ran out of memory creating debug info for an error"); - re.printStackTrace(System.err); - // recover from crash whilst producing debug string - classDebugInfo = clazz.getClassName(); - } catch (Throwable e) { - // recover from crash whilst producing debug string - classDebugInfo = clazz.getClassName(); - } - String messageText = "trouble in: \n" + classDebugInfo; - getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); - } - } else { - checkDeclareTypeErrorOrWarning(world, classType); - } - // this is very odd return behavior trying to keep everyone happy - - // can we remove it from the model now? we know it contains no relationship endpoints... - AsmManager model = world.getModelAsAsmManager(); - if (world.isMinimalModel() && model != null && !classType.isAspect()) { - AspectJElementHierarchy hierarchy = (AspectJElementHierarchy) model.getHierarchy(); - String pkgname = classType.getResolvedTypeX().getPackageName(); - String tname = classType.getResolvedTypeX().getSimpleBaseName(); - IProgramElement typeElement = hierarchy.findElementForType(pkgname, tname); - if (typeElement != null && hasInnerType(typeElement)) { - // Cannot remove it right now (has inner type), schedule it - // for possible deletion later if all inner types are - // removed - candidatesForRemoval.add(typeElement); - } - if (typeElement != null && !hasInnerType(typeElement)) { - IProgramElement parent = typeElement.getParent(); - // parent may have children: PACKAGE DECL, IMPORT-REFERENCE, TYPE_DECL - if (parent != null) { - // if it was the only type we should probably remove - // the others too. - parent.removeChild(typeElement); - if (parent.getKind().isSourceFile()) { - removeSourceFileIfNoMoreTypeDeclarationsInside(hierarchy, typeElement, parent); - } else { - hierarchy.forget(null, typeElement); - // At this point, the child has been removed. We - // should now check if the parent is in our - // 'candidatesForRemoval' set. If it is then that - // means we were going to remove it but it had a - // child. Now we can check if it still has a child - - // if it doesn't it can also be removed! - - walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(hierarchy, tname, parent); - } - - } - } - } - - if (dump) { - dumpUnchanged(classFile); - return clazz; - } else { - // ATAJ: the class was not weaved, but since it gets there early it - // may have new generated inner classes - // attached to it to support LTW perX aspectOf support (see - // BcelPerClauseAspectAdder) - // that aggressively defines the inner <aspect>$mayHaveAspect - // interface. - if (clazz != null && !clazz.getChildClasses(world).isEmpty()) { - return clazz; - } - return null; - } - } finally { - world.demote(); - } - } - - private void walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(AspectJElementHierarchy hierarchy, String tname, - IProgramElement typeThatHasChildRemoved) { - // typeThatHasChildRemoved might be a source file, type or a method/ctor - // - for a method/ctor find the type/sourcefile - while (typeThatHasChildRemoved != null - && !(typeThatHasChildRemoved.getKind().isType() || typeThatHasChildRemoved.getKind().isSourceFile())) { - // this will take us 'up' through methods that contain anonymous - // inner classes - typeThatHasChildRemoved = typeThatHasChildRemoved.getParent(); - } - // now typeThatHasChildRemoved points to the type or sourcefile that has - // had something removed - if (candidatesForRemoval.contains(typeThatHasChildRemoved) && !hasInnerType(typeThatHasChildRemoved)) { - // now we can get rid of it - IProgramElement parent = typeThatHasChildRemoved.getParent(); - if (parent != null) { - parent.removeChild(typeThatHasChildRemoved); - candidatesForRemoval.remove(typeThatHasChildRemoved); - if (parent.getKind().isSourceFile()) { - removeSourceFileIfNoMoreTypeDeclarationsInside(hierarchy, typeThatHasChildRemoved, parent); - // System.out.println("Removed on second pass: " + - // typeThatHasChildRemoved.getName()); - } else { - // System.out.println("On later pass, parent of type " + - // typeThatHasChildRemoved.getName() - // + " was found not to be a sourcefile, recursing up..."); - walkUpRemovingEmptyTypesAndPossiblyEmptySourceFile(hierarchy, tname, parent); - } - } - } - } - - private void removeSourceFileIfNoMoreTypeDeclarationsInside(AspectJElementHierarchy hierarchy, IProgramElement typeElement, - IProgramElement sourceFileNode) { - IProgramElement compilationUnit = sourceFileNode; - boolean anyOtherTypeDeclarations = false; - for (IProgramElement child : compilationUnit.getChildren()) { - IProgramElement.Kind k = child.getKind(); - if (k.isType()) { - anyOtherTypeDeclarations = true; - break; - } - } - // If the compilation unit node contained no - // other types, there is no need to keep it - if (!anyOtherTypeDeclarations) { - IProgramElement cuParent = compilationUnit.getParent(); - if (cuParent != null) { - compilationUnit.setParent(null); - cuParent.removeChild(compilationUnit); - } - // need to update some caches and structures too? - hierarchy.forget(sourceFileNode, typeElement); - } else { - hierarchy.forget(null, typeElement); - } - } - - // ---- writing - - // TODO could be smarter - really only matters if inner type has been woven, but there is a chance we haven't woven it *yet* - private boolean hasInnerType(IProgramElement typeNode) { - for (IProgramElement child : typeNode.getChildren()) { - IProgramElement.Kind kind = child.getKind(); - if (kind.isType()) { - return true; - } - // if (kind == IProgramElement.Kind.ASPECT) { - // return true; - // } - if (kind.isType() || kind == IProgramElement.Kind.METHOD || kind == IProgramElement.Kind.CONSTRUCTOR) { - boolean b = hasInnerType(child); - if (b) { - return b; - } - } - } - return false; - } - - private void checkDeclareTypeErrorOrWarning(BcelWorld world2, BcelObjectType classType) { - List<DeclareTypeErrorOrWarning> dteows = world.getDeclareTypeEows(); - for (DeclareTypeErrorOrWarning dteow : dteows) { - if (dteow.getTypePattern().matchesStatically(classType.getResolvedTypeX())) { - if (dteow.isError()) { - world.getMessageHandler().handleMessage( - MessageUtil.error(dteow.getMessage(), classType.getResolvedTypeX().getSourceLocation())); - } else { - world.getMessageHandler().handleMessage( - MessageUtil.warn(dteow.getMessage(), classType.getResolvedTypeX().getSourceLocation())); - } - } - } - } - - private void dumpUnchanged(UnwovenClassFile classFile) throws IOException { - if (zipOutputStream != null) { - writeZipEntry(getEntryName(classFile.getJavaClass().getClassName()), classFile.getBytes()); - } else { - classFile.writeUnchangedBytes(); - } - } - - private String getEntryName(String className) { - // XXX what does bcel's getClassName do for inner names - return className.replace('.', '/') + ".class"; - } - - private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException { - if (zipOutputStream != null) { - String mainClassName = classFile.getJavaClass().getClassName(); - writeZipEntry(getEntryName(mainClassName), clazz.getJavaClass(world).getBytes()); - List<UnwovenClassFile.ChildClass> childClasses = clazz.getChildClasses(world); - if (!childClasses.isEmpty()) { - for (Iterator<UnwovenClassFile.ChildClass> i = childClasses.iterator(); i.hasNext();) { - UnwovenClassFile.ChildClass c = i.next(); - writeZipEntry(getEntryName(mainClassName + "$" + c.name), c.bytes); - } - } - } else { - classFile.writeWovenBytes(clazz.getJavaClass(world).getBytes(), clazz.getChildClasses(world)); - } - } - - private void writeZipEntry(String name, byte[] bytes) throws IOException { - ZipEntry newEntry = new ZipEntry(name); // ??? get compression scheme - // right - - zipOutputStream.putNextEntry(newEntry); - zipOutputStream.write(bytes); - zipOutputStream.closeEntry(); - } - - /** - * Perform a fast match of the specified list of shadowmungers against the specified type. A subset of those that might match is - * returned. - * - * @param list list of all shadow mungers that might match - * @param type the target type - * @return a list of shadow mungers that might match with those that cannot (according to fast match rules) removed - */ - private List<ShadowMunger> fastMatch(List<ShadowMunger> list, ResolvedType type) { - if (list == null) { - return Collections.emptyList(); - } - boolean isOverweaving = world.isOverWeaving(); - WeaverStateInfo typeWeaverState = (isOverweaving ? type.getWeaverState() : null); - - // here we do the coarsest grained fast match with no kind constraints - // this will remove all obvious non-matches and see if we need to do any - // weaving - FastMatchInfo info = new FastMatchInfo(type, null, world); - - List<ShadowMunger> result = new ArrayList<ShadowMunger>(); - - if (world.areInfoMessagesEnabled() && world.isTimingEnabled()) { - for (ShadowMunger munger : list) { - if (typeWeaverState != null) { // will only be null if overweaving is ON and there is weaverstate - ResolvedType declaringAspect = munger.getDeclaringType(); - if (typeWeaverState.isAspectAlreadyApplied(declaringAspect)) { - continue; - } - } - Pointcut pointcut = munger.getPointcut(); - long starttime = System.nanoTime(); - FuzzyBoolean fb = pointcut.fastMatch(info); - long endtime = System.nanoTime(); - world.recordFastMatch(pointcut, endtime - starttime); - if (fb.maybeTrue()) { - result.add(munger); - } - } - } else { - for (ShadowMunger munger : list) { - if (typeWeaverState != null) { // will only be null if overweaving is ON and there is weaverstate - ResolvedType declaringAspect = munger.getConcreteAspect();// getDeclaringType(); - if (typeWeaverState.isAspectAlreadyApplied(declaringAspect)) { - continue; - } - } - Pointcut pointcut = munger.getPointcut(); - FuzzyBoolean fb = pointcut.fastMatch(info); - if (fb.maybeTrue()) { - result.add(munger); - } - } - } - return result; - } - - public void setReweavableMode(boolean xNotReweavable) { - inReweavableMode = !xNotReweavable; - WeaverStateInfo.setReweavableModeDefaults(!xNotReweavable, false, true); - } - - public boolean isReweavable() { - return inReweavableMode; - } - - public World getWorld() { - return world; - } - - public void tidyUp() { - if (trace.isTraceEnabled()) { - trace.enter("tidyUp", this); - } - shadowMungerList = null; // setup by prepareForWeave - typeMungerList = null; // setup by prepareForWeave - lateTypeMungerList = null; // setup by prepareForWeave - declareParentsList = null; // setup by prepareForWeave - if (trace.isTraceEnabled()) { - trace.exit("tidyUp"); - } - } - - public void write(CompressingDataOutputStream dos) throws IOException { - xcutSet.write(dos); - } - - // only called for testing - public void setShadowMungers(List<ShadowMunger> shadowMungers) { - shadowMungerList = shadowMungers; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeavingSupport.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeavingSupport.java deleted file mode 100644 index 120df80c2..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeavingSupport.java +++ /dev/null @@ -1,71 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008 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: - * Andy Clement initial implementation - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.ConcreteTypeMunger; -import org.aspectj.weaver.IWeavingSupport; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.ast.Var; -import org.aspectj.weaver.patterns.PerClause; -import org.aspectj.weaver.patterns.Pointcut; - -/** - * Bcel implementation of the weaving support required in a BcelWorld which will actually modify bytecode. - * - * @author Andy Clement - */ -public class BcelWeavingSupport implements IWeavingSupport { - - public Advice createAdviceMunger(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member signature, - ResolvedType concreteAspect) { - // System.err.println("concrete advice: " + signature + " context " + - // sourceContext); - return new BcelAdvice(attribute, pointcut, signature, concreteAspect); - } - - public ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField) { - return new BcelCflowStackFieldAdder(cflowField); - } - - public ConcreteTypeMunger makeCflowCounterFieldAdder(ResolvedMember cflowField) { - return new BcelCflowCounterFieldAdder(cflowField); - } - - /** - * Register a munger for perclause @AJ aspect so that we add aspectOf(..) to them as needed - * - * @param aspect - * @param kind - * @return munger - */ - public ConcreteTypeMunger makePerClauseAspect(ResolvedType aspect, PerClause.Kind kind) { - return new BcelPerClauseAspectAdder(aspect, kind); - } - - public Var makeCflowAccessVar(ResolvedType formalType, Member cflowField, int arrayIndex) { - return new BcelCflowAccessVar(formalType, cflowField, arrayIndex); - } - - public ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedType aspectType) { - return new BcelTypeMunger(munger, aspectType); - } - - public ConcreteTypeMunger createAccessForInlineMunger(ResolvedType aspect) { - return new BcelAccessForInlineMunger(aspect); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java deleted file mode 100644 index 4ade1e125..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java +++ /dev/null @@ -1,1329 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 perClause support for @AJ aspects - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.ClassParser; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.generic.FieldInstruction; -import org.aspectj.apache.bcel.generic.INVOKEINTERFACE; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InvokeInstruction; -import org.aspectj.apache.bcel.generic.MULTIANEWARRAY; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.apache.bcel.util.ClassLoaderReference; -import org.aspectj.apache.bcel.util.ClassLoaderRepository; -import org.aspectj.apache.bcel.util.ClassPath; -import org.aspectj.apache.bcel.util.NonCachingClassLoaderRepository; -import org.aspectj.apache.bcel.util.Repository; -import org.aspectj.asm.AsmManager; -import org.aspectj.asm.IRelationship; -import org.aspectj.asm.internal.CharOperation; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.bridge.WeaveMessage; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.AnnotationOnTypeMunger; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.Checker; -import org.aspectj.weaver.ICrossReferenceHandler; -import org.aspectj.weaver.IWeavingSupport; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MemberImpl; -import org.aspectj.weaver.MemberKind; -import org.aspectj.weaver.NewParentTypeMunger; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedMemberImpl; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; -import org.aspectj.weaver.loadtime.definition.Definition; -import org.aspectj.weaver.loadtime.definition.DocumentParser; -import org.aspectj.weaver.model.AsmRelationshipProvider; -import org.aspectj.weaver.patterns.DeclareAnnotation; -import org.aspectj.weaver.patterns.DeclareParents; -import org.aspectj.weaver.patterns.ParserException; -import org.aspectj.weaver.patterns.PatternParser; -import org.aspectj.weaver.patterns.TypePattern; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -public class BcelWorld extends World implements Repository { - - private final ClassPathManager classPath; - protected Repository delegate; - private BcelWeakClassLoaderReference loaderRef; - private final BcelWeavingSupport bcelWeavingSupport = new BcelWeavingSupport(); - private boolean isXmlConfiguredWorld = false; - private WeavingXmlConfig xmlConfiguration; - private List<TypeDelegateResolver> typeDelegateResolvers; - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWorld.class); - - public BcelWorld() { - this(""); - } - - public BcelWorld(String cp) { - this(makeDefaultClasspath(cp), IMessageHandler.THROW, null); - } - - public IRelationship.Kind determineRelKind(ShadowMunger munger) { - AdviceKind ak = ((Advice) munger).getKind(); - if (ak.getKey() == AdviceKind.Before.getKey()) { - return IRelationship.Kind.ADVICE_BEFORE; - } else if (ak.getKey() == AdviceKind.After.getKey()) { - return IRelationship.Kind.ADVICE_AFTER; - } else if (ak.getKey() == AdviceKind.AfterThrowing.getKey()) { - return IRelationship.Kind.ADVICE_AFTERTHROWING; - } else if (ak.getKey() == AdviceKind.AfterReturning.getKey()) { - return IRelationship.Kind.ADVICE_AFTERRETURNING; - } else if (ak.getKey() == AdviceKind.Around.getKey()) { - return IRelationship.Kind.ADVICE_AROUND; - } else if (ak.getKey() == AdviceKind.CflowEntry.getKey() || ak.getKey() == AdviceKind.CflowBelowEntry.getKey() - || ak.getKey() == AdviceKind.InterInitializer.getKey() || ak.getKey() == AdviceKind.PerCflowEntry.getKey() - || ak.getKey() == AdviceKind.PerCflowBelowEntry.getKey() || ak.getKey() == AdviceKind.PerThisEntry.getKey() - || ak.getKey() == AdviceKind.PerTargetEntry.getKey() || ak.getKey() == AdviceKind.Softener.getKey() - || ak.getKey() == AdviceKind.PerTypeWithinEntry.getKey()) { - // System.err.println("Dont want a message about this: "+ak); - return null; - } - throw new RuntimeException("Shadow.determineRelKind: What the hell is it? " + ak); - } - - @Override - public void reportMatch(ShadowMunger munger, Shadow shadow) { - if (getCrossReferenceHandler() != null) { - getCrossReferenceHandler().addCrossReference(munger.getSourceLocation(), // What is being applied - shadow.getSourceLocation(), // Where is it being applied - determineRelKind(munger).getName(), // What kind of advice? - ((Advice) munger).hasDynamicTests() // Is a runtime test being stuffed in the code? - ); - } - - if (!getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { - reportWeavingMessage(munger, shadow); - } - - if (getModel() != null) { - AsmRelationshipProvider.addAdvisedRelationship(getModelAsAsmManager(), shadow, munger); - } - } - - /* - * Report a message about the advice weave that has occurred. Some messing about to make it pretty ! This code is just asking - * for an NPE to occur ... - */ - private void reportWeavingMessage(ShadowMunger munger, Shadow shadow) { - Advice advice = (Advice) munger; - AdviceKind aKind = advice.getKind(); - // Only report on interesting advice kinds ... - if (aKind == null || advice.getConcreteAspect() == null) { - // We suspect someone is programmatically driving the weaver - // (e.g. IdWeaveTestCase in the weaver testcases) - return; - } - if (!(aKind.equals(AdviceKind.Before) || aKind.equals(AdviceKind.After) || aKind.equals(AdviceKind.AfterReturning) - || aKind.equals(AdviceKind.AfterThrowing) || aKind.equals(AdviceKind.Around) || aKind.equals(AdviceKind.Softener))) { - return; - } - - // synchronized blocks are implemented with multiple monitor_exit instructions in the bytecode - // (one for normal exit from the method, one for abnormal exit), we only want to tell the user - // once we have advised the end of the sync block, even though under the covers we will have - // woven both exit points - if (shadow.getKind() == Shadow.SynchronizationUnlock) { - if (advice.lastReportedMonitorExitJoinpointLocation == null) { - // this is the first time through, let's continue... - advice.lastReportedMonitorExitJoinpointLocation = shadow.getSourceLocation(); - } else { - if (areTheSame(shadow.getSourceLocation(), advice.lastReportedMonitorExitJoinpointLocation)) { - // Don't report it again! - advice.lastReportedMonitorExitJoinpointLocation = null; - return; - } - // hmmm, this means some kind of nesting is going on, urgh - advice.lastReportedMonitorExitJoinpointLocation = shadow.getSourceLocation(); - } - } - - String description = advice.getKind().toString(); - String advisedType = shadow.getEnclosingType().getName(); - String advisingType = advice.getConcreteAspect().getName(); - Message msg = null; - if (advice.getKind().equals(AdviceKind.Softener)) { - msg = WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_SOFTENS, new String[] { advisedType, - beautifyLocation(shadow.getSourceLocation()), advisingType, beautifyLocation(munger.getSourceLocation()) }, - advisedType, advisingType); - } else { - boolean runtimeTest = advice.hasDynamicTests(); - String joinPointDescription = shadow.toString(); - msg = WeaveMessage - .constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ADVISES, - new String[] { joinPointDescription, advisedType, beautifyLocation(shadow.getSourceLocation()), - description, advisingType, beautifyLocation(munger.getSourceLocation()), - (runtimeTest ? " [with runtime test]" : "") }, advisedType, advisingType); - // Boolean.toString(runtimeTest)}); - } - getMessageHandler().handleMessage(msg); - } - - private boolean areTheSame(ISourceLocation locA, ISourceLocation locB) { - if (locA == null) { - return locB == null; - } - if (locB == null) { - return false; - } - if (locA.getLine() != locB.getLine()) { - return false; - } - File fA = locA.getSourceFile(); - File fB = locA.getSourceFile(); - if (fA == null) { - return fB == null; - } - if (fB == null) { - return false; - } - return fA.getName().equals(fB.getName()); - } - - /* - * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave). - */ - private String beautifyLocation(ISourceLocation isl) { - StringBuffer nice = new StringBuffer(); - if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().indexOf("no debug info available") != -1) { - nice.append("no debug info available"); - } else { - // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa - int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/'); - if (takeFrom == -1) { - takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\'); - } - int binary = isl.getSourceFile().getPath().lastIndexOf('!'); - if (binary != -1 && binary < takeFrom) { - // we have been woven by a binary aspect - String pathToBinaryLoc = isl.getSourceFile().getPath().substring(0, binary + 1); - if (pathToBinaryLoc.indexOf(".jar") != -1) { - // only want to add the extra info if we're from a jar file - int lastSlash = pathToBinaryLoc.lastIndexOf('/'); - if (lastSlash == -1) { - lastSlash = pathToBinaryLoc.lastIndexOf('\\'); - } - nice.append(pathToBinaryLoc.substring(lastSlash + 1)); - } - } - nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1)); - if (isl.getLine() != 0) { - nice.append(":").append(isl.getLine()); - } - // if it's a binary file then also want to give the file name - if (isl.getSourceFileName() != null) { - nice.append("(from " + isl.getSourceFileName() + ")"); - } - } - return nice.toString(); - } - - private static List<String> makeDefaultClasspath(String cp) { - List<String> classPath = new ArrayList<String>(); - classPath.addAll(getPathEntries(cp)); - classPath.addAll(getPathEntries(ClassPath.getClassPath())); - return classPath; - - } - - private static List<String> getPathEntries(String s) { - List<String> ret = new ArrayList<String>(); - StringTokenizer tok = new StringTokenizer(s, File.pathSeparator); - while (tok.hasMoreTokens()) { - ret.add(tok.nextToken()); - } - return ret; - } - - public BcelWorld(List classPath, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { - // this.aspectPath = new ClassPathManager(aspectPath, handler); - this.classPath = new ClassPathManager(classPath, handler); - setMessageHandler(handler); - setCrossReferenceHandler(xrefHandler); - // Tell BCEL to use us for resolving any classes - delegate = this; - } - - public BcelWorld(ClassPathManager cpm, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { - classPath = cpm; - setMessageHandler(handler); - setCrossReferenceHandler(xrefHandler); - // Tell BCEL to use us for resolving any classes - delegate = this; - } - - /** - * Build a World from a ClassLoader, for LTW support - * - * @param loader - * @param handler - * @param xrefHandler - */ - public BcelWorld(ClassLoader loader, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { - classPath = null; - loaderRef = new BcelWeakClassLoaderReference(loader); - setMessageHandler(handler); - setCrossReferenceHandler(xrefHandler); - // Tell BCEL to use us for resolving any classes - // delegate = getClassLoaderRepositoryFor(loader); - } - - public void ensureRepositorySetup() { - if (delegate == null) { - delegate = getClassLoaderRepositoryFor(loaderRef); - } - } - - public Repository getClassLoaderRepositoryFor(ClassLoaderReference loader) { - if (bcelRepositoryCaching) { - return new ClassLoaderRepository(loader); - } else { - return new NonCachingClassLoaderRepository(loader); - } - } - - public void addPath(String name) { - classPath.addPath(name, this.getMessageHandler()); - } - - // ---- various interactions with bcel - - public static Type makeBcelType(UnresolvedType type) { - return Type.getType(type.getErasureSignature()); - } - - static Type[] makeBcelTypes(UnresolvedType[] types) { - Type[] ret = new Type[types.length]; - for (int i = 0, len = types.length; i < len; i++) { - ret[i] = makeBcelType(types[i]); - } - return ret; - } - - public static Type[] makeBcelTypes(String[] types) { - if (types == null || types.length==0 ) { - return null; - } - Type[] ret = new Type[types.length]; - for (int i=0, len=types.length; i<len; i++) { - ret[i] = makeBcelType(types[i]); - } - return ret; - } - - public static Type makeBcelType(String type) { - return Type.getType(type); - } - - - static String[] makeBcelTypesAsClassNames(UnresolvedType[] types) { - String[] ret = new String[types.length]; - for (int i = 0, len = types.length; i < len; i++) { - ret[i] = types[i].getName(); - } - return ret; - } - - public static UnresolvedType fromBcel(Type t) { - return UnresolvedType.forSignature(t.getSignature()); - } - - static UnresolvedType[] fromBcel(Type[] ts) { - UnresolvedType[] ret = new UnresolvedType[ts.length]; - for (int i = 0, len = ts.length; i < len; i++) { - ret[i] = fromBcel(ts[i]); - } - return ret; - } - - public ResolvedType resolve(Type t) { - return resolve(fromBcel(t)); - } - - @Override - protected ReferenceTypeDelegate resolveDelegate(ReferenceType ty) { - String name = ty.getName(); - ensureAdvancedConfigurationProcessed(); - JavaClass jc = lookupJavaClass(classPath, name); - if (jc == null) { - // Anyone else to ask? - if (typeDelegateResolvers != null) { - for (TypeDelegateResolver tdr : typeDelegateResolvers) { - ReferenceTypeDelegate delegate = tdr.getDelegate(ty); - if (delegate != null) { - return delegate; - } - } - } - return null; - } else { - return buildBcelDelegate(ty, jc, false, false); - } - } - - public BcelObjectType buildBcelDelegate(ReferenceType type, JavaClass jc, boolean artificial, boolean exposedToWeaver) { - BcelObjectType ret = new BcelObjectType(type, jc, artificial, exposedToWeaver); - return ret; - } - - private JavaClass lookupJavaClass(ClassPathManager classPath, String name) { - if (classPath == null) { - try { - ensureRepositorySetup(); - JavaClass jc = delegate.loadClass(name); - if (trace.isTraceEnabled()) { - trace.event("lookupJavaClass", this, new Object[] { name, jc }); - } - return jc; - } catch (ClassNotFoundException e) { - if (trace.isTraceEnabled()) { - trace.error("Unable to find class '" + name + "' in repository", e); - } - return null; - } - } - - ClassPathManager.ClassFile file = null; - try { - file = classPath.find(UnresolvedType.forName(name)); - if (file == null) { - return null; - } - ClassParser parser = new ClassParser(file.getInputStream(), file.getPath()); - JavaClass jc = parser.parse(); - return jc; - } catch (IOException ioe) { - if (trace.isTraceEnabled()) { - trace.error("IOException whilst processing class",ioe); - } - return null; - } finally { - if (file != null) { - file.close(); - } - } - } - - public BcelObjectType addSourceObjectType(JavaClass jc, boolean artificial) { - return addSourceObjectType(jc.getClassName(), jc, artificial); - } - - public BcelObjectType addSourceObjectType(String classname, JavaClass jc, boolean artificial) { - BcelObjectType ret = null; - if (!jc.getClassName().equals(classname)) { - throw new RuntimeException(jc.getClassName() + "!=" + classname); - } - String signature = UnresolvedType.forName(jc.getClassName()).getSignature(); - - ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature); - - if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) { - // what on earth is it then? See pr 112243 - StringBuffer exceptionText = new StringBuffer(); - exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); - exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]"); - throw new BCException(exceptionText.toString()); - } - - ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap; - - if (referenceTypeFromTypeMap == null) { - if (jc.isGeneric() && isInJava5Mode()) { - ReferenceType rawType = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); - ret = buildBcelDelegate(rawType, jc, artificial, true); - ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature, - ret.getDeclaredGenericSignature()), this); - rawType.setDelegate(ret); - genericRefType.setDelegate(ret); - rawType.setGenericType(genericRefType); - typeMap.put(signature, rawType); - } else { - referenceTypeFromTypeMap = new ReferenceType(signature, this); - ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); - typeMap.put(signature, referenceTypeFromTypeMap); - } - } else { - ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); - } - return ret; - } - - public BcelObjectType addSourceObjectType(String classname, byte[] bytes, boolean artificial) { - BcelObjectType retval = null; - String signature = UnresolvedType.forName(classname).getSignature(); - ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature); - - if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) { - // what on earth is it then? See pr 112243 - StringBuffer exceptionText = new StringBuffer(); - exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); - exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]"); - throw new BCException(exceptionText.toString()); - } - - ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap; - - if (referenceTypeFromTypeMap == null) { - JavaClass jc = Utility.makeJavaClass(classname, bytes); - if (jc.isGeneric() && isInJava5Mode()) { - referenceTypeFromTypeMap = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); - retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); - ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature, - retval.getDeclaredGenericSignature()), this); - referenceTypeFromTypeMap.setDelegate(retval); - genericRefType.setDelegate(retval); - referenceTypeFromTypeMap.setGenericType(genericRefType); - typeMap.put(signature, referenceTypeFromTypeMap); - } else { - referenceTypeFromTypeMap = new ReferenceType(signature, this); - retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); - typeMap.put(signature, referenceTypeFromTypeMap); - } - } else { - ReferenceTypeDelegate existingDelegate = referenceTypeFromTypeMap.getDelegate(); - if (!(existingDelegate instanceof BcelObjectType)) { - throw new IllegalStateException("For " + classname + " should be BcelObjectType, but is " + existingDelegate.getClass()); - } - retval = (BcelObjectType) existingDelegate; - // Note1: If the type is already exposed to the weaver (retval.isExposedToWeaver()) then this is likely - // to be a hotswap reweave so build a new delegate, don't accidentally use the old data. - // Note2: Also seen when LTW and another agent precedes the AspectJ agent. Earlier in LTW - // a type is resolved (and ends up in the typemap but not exposed to the weaver at that time) - // then later LTW actually is attempted on this type. We end up here with different - // bytes to the current delegate if the earlier agent has modified them. See PR488216 -// if (retval.isArtificial() || retval.isExposedToWeaver()) { - retval = buildBcelDelegate(referenceTypeFromTypeMap, Utility.makeJavaClass(classname, bytes), artificial, true); -// } - } - return retval; - } - - void deleteSourceObjectType(UnresolvedType ty) { - typeMap.remove(ty.getSignature()); - } - - public static Member makeFieldJoinPointSignature(LazyClassGen cg, FieldInstruction fi) { - ConstantPool cpg = cg.getConstantPool(); - return MemberImpl.field(fi.getClassName(cpg), - (fi.opcode == Constants.GETSTATIC || fi.opcode == Constants.PUTSTATIC) ? Modifier.STATIC : 0, fi.getName(cpg), - fi.getSignature(cpg)); - } - - public Member makeJoinPointSignatureFromMethod(LazyMethodGen mg, MemberKind kind) { - Member ret = mg.getMemberView(); - if (ret == null) { - int mods = mg.getAccessFlags(); - if (mg.getEnclosingClass().isInterface()) { - mods |= Modifier.INTERFACE; - } - return new ResolvedMemberImpl(kind, UnresolvedType.forName(mg.getClassName()), mods, fromBcel(mg.getReturnType()), - mg.getName(), fromBcel(mg.getArgumentTypes())); - } else { - return ret; - } - - } - - public Member makeJoinPointSignatureForMonitorEnter(LazyClassGen cg, InstructionHandle h) { - return MemberImpl.monitorEnter(); - } - - public Member makeJoinPointSignatureForMonitorExit(LazyClassGen cg, InstructionHandle h) { - return MemberImpl.monitorExit(); - } - - public Member makeJoinPointSignatureForArrayConstruction(LazyClassGen cg, InstructionHandle handle) { - Instruction i = handle.getInstruction(); - ConstantPool cpg = cg.getConstantPool(); - Member retval = null; - - if (i.opcode == Constants.ANEWARRAY) { - // ANEWARRAY arrayInstruction = (ANEWARRAY)i; - Type ot = i.getType(cpg); - UnresolvedType ut = fromBcel(ot); - ut = UnresolvedType.makeArray(ut, 1); - retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", new ResolvedType[] { INT }); - } else if (i instanceof MULTIANEWARRAY) { - MULTIANEWARRAY arrayInstruction = (MULTIANEWARRAY) i; - UnresolvedType ut = null; - short dimensions = arrayInstruction.getDimensions(); - ObjectType ot = arrayInstruction.getLoadClassType(cpg); - if (ot != null) { - ut = fromBcel(ot); - ut = UnresolvedType.makeArray(ut, dimensions); - } else { - Type t = arrayInstruction.getType(cpg); - ut = fromBcel(t); - } - ResolvedType[] parms = new ResolvedType[dimensions]; - for (int ii = 0; ii < dimensions; ii++) { - parms[ii] = INT; - } - retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", parms); - - } else if (i.opcode == Constants.NEWARRAY) { - // NEWARRAY arrayInstruction = (NEWARRAY)i; - Type ot = i.getType(); - UnresolvedType ut = fromBcel(ot); - retval = MemberImpl.method(ut, Modifier.PUBLIC, UnresolvedType.VOID, "<init>", new ResolvedType[] { INT }); - } else { - throw new BCException("Cannot create array construction signature for this non-array instruction:" + i); - } - return retval; - } - - public Member makeJoinPointSignatureForMethodInvocation(LazyClassGen cg, InvokeInstruction ii) { - ConstantPool cpg = cg.getConstantPool(); - String name = ii.getName(cpg); - String declaring = ii.getClassName(cpg); - UnresolvedType declaringType = null; - - String signature = ii.getSignature(cpg); - - // 307147 - if (name.startsWith("ajc$privMethod$")) { - // The invoke is on a privileged accessor. These may be created for different - // kinds of target, not necessarily just private methods. In bug 307147 it is - // for a private method. This code is identifying the particular case in 307147 - try { - declaringType = UnresolvedType.forName(declaring); - String typeNameAsFoundInAccessorName = declaringType.getName().replace('.', '_'); - int indexInAccessorName = name.lastIndexOf(typeNameAsFoundInAccessorName); - if (indexInAccessorName != -1) { - String methodName = name.substring(indexInAccessorName+typeNameAsFoundInAccessorName.length()+1); - ResolvedType resolvedDeclaringType = declaringType.resolve(this); - ResolvedMember[] methods = resolvedDeclaringType.getDeclaredMethods(); - for (ResolvedMember method: methods) { - if (method.getName().equals(methodName) && method.getSignature().equals(signature) && Modifier.isPrivate(method.getModifiers())) { - return method; - } - } - } - } catch (Exception e) { - // Remove this once confident above code isn't having unexpected side effects - // Added 1.8.7 - e.printStackTrace(); - } - } - - int modifier = (ii instanceof INVOKEINTERFACE) ? Modifier.INTERFACE - : (ii.opcode == Constants.INVOKESTATIC) ? Modifier.STATIC : (ii.opcode == Constants.INVOKESPECIAL && !name - .equals("<init>")) ? Modifier.PRIVATE : 0; - - // in Java 1.4 and after, static method call of super class within - // subclass method appears - // as declared by the subclass in the bytecode - but they are not - // see #104212 - if (ii.opcode == Constants.INVOKESTATIC) { - ResolvedType appearsDeclaredBy = resolve(declaring); - // look for the method there - for (Iterator<ResolvedMember> iterator = appearsDeclaredBy.getMethods(true, true); iterator.hasNext();) { - ResolvedMember method = iterator.next(); - if (Modifier.isStatic(method.getModifiers())) { - if (name.equals(method.getName()) && signature.equals(method.getSignature())) { - // we found it - declaringType = method.getDeclaringType(); - break; - } - } - } - } - - if (declaringType == null) { - if (declaring.charAt(0) == '[') { - declaringType = UnresolvedType.forSignature(declaring); - } else { - declaringType = UnresolvedType.forName(declaring); - } - } - return MemberImpl.method(declaringType, modifier, name, signature); - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("BcelWorld("); - // buf.append(shadowMungerMap); - buf.append(")"); - return buf.toString(); - } - - /** - * Retrieve a bcel delegate for an aspect - this will return NULL if the delegate is an EclipseSourceType and not a - * BcelObjectType - this happens quite often when incrementally compiling. - */ - public static BcelObjectType getBcelObjectType(ResolvedType concreteAspect) { - if (concreteAspect == null) { - return null; - } - if (!(concreteAspect instanceof ReferenceType)) { // Might be Missing - return null; - } - ReferenceTypeDelegate rtDelegate = ((ReferenceType) concreteAspect).getDelegate(); - if (rtDelegate instanceof BcelObjectType) { - return (BcelObjectType) rtDelegate; - } else { - return null; - } - } - - public void tidyUp() { - // At end of compile, close any open files so deletion of those archives - // is possible - classPath.closeArchives(); - typeMap.report(); - typeMap.demote(true); - // ResolvedType.resetPrimitives(); - } - - // / The repository interface methods - - @Override - public JavaClass findClass(String className) { - return lookupJavaClass(classPath, className); - } - - @Override - public JavaClass loadClass(String className) throws ClassNotFoundException { - return lookupJavaClass(classPath, className); - } - - @Override - public void storeClass(JavaClass clazz) { - // doesn't need to do anything - } - - @Override - public void removeClass(JavaClass clazz) { - throw new RuntimeException("Not implemented"); - } - - @Override - public JavaClass loadClass(Class clazz) throws ClassNotFoundException { - throw new RuntimeException("Not implemented"); - } - - @Override - public void clear() { - delegate.clear(); - // throw new RuntimeException("Not implemented"); - } - - /** - * The aim of this method is to make sure a particular type is 'ok'. Some operations on the delegate for a type modify it and - * this method is intended to undo that... see pr85132 - */ - @Override - public void validateType(UnresolvedType type) { - ResolvedType result = typeMap.get(type.getSignature()); - if (result == null) { - return; // We haven't heard of it yet - } - if (!result.isExposedToWeaver()) { - return; // cant need resetting - } - result.ensureConsistent(); - // If we want to rebuild it 'from scratch' then: - // ClassParser cp = new ClassParser(new - // ByteArrayInputStream(newbytes),new String(cs)); - // try { - // rt.setDelegate(makeBcelObjectType(rt,cp.parse(),true)); - // } catch (ClassFormatException e) { - // e.printStackTrace(); - // } catch (IOException e) { - // e.printStackTrace(); - // } - } - - /** - * Apply a single declare parents - return true if we change the type - */ - private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) { - boolean didSomething = false; - List<ResolvedType> newParents = p.findMatchingNewParents(onType, true); - if (!newParents.isEmpty()) { - didSomething = true; - BcelObjectType classType = BcelWorld.getBcelObjectType(onType); - // System.err.println("need to do declare parents for: " + onType); - for (ResolvedType newParent : newParents) { - // We set it here so that the imminent matching for ITDs can - // succeed - we still haven't done the necessary changes to the class file - // itself (like transform super calls) - that is done in - // BcelTypeMunger.mungeNewParent() - // classType.addParent(newParent); - onType.addParent(newParent); - ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent, p.getDeclaringType()); - newParentMunger.setSourceLocation(p.getSourceLocation()); - onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, getCrosscuttingMembersSet() - .findAspectDeclaringParents(p)), false); - } - } - return didSomething; - } - - /** - * Apply a declare @type - return true if we change the type - */ - private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType, boolean reportProblems) { - boolean didSomething = false; - if (decA.matches(onType)) { - - if (onType.hasAnnotation(decA.getAnnotation().getType())) { - // already has it - return false; - } - - AnnotationAJ annoX = decA.getAnnotation(); - - // check the annotation is suitable for the target - boolean isOK = checkTargetOK(decA, onType, annoX); - - if (isOK) { - didSomething = true; - ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX); - newAnnotationTM.setSourceLocation(decA.getSourceLocation()); - onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM, decA.getAspect().resolve(this)), false); - decA.copyAnnotationTo(onType); - } - } - return didSomething; - } - - /** - * Apply the specified declare @field construct to any matching fields in the specified type. - * @param deca the declare annotation targeting fields - * @param type the type to check for members matching the declare annotation - * @return true if something matched and the type was modified - */ - private boolean applyDeclareAtField(DeclareAnnotation deca, ResolvedType type) { - boolean changedType = false; - ResolvedMember[] fields = type.getDeclaredFields(); - for (ResolvedMember field: fields) { - if (deca.matches(field, this)) { - AnnotationAJ anno = deca.getAnnotation(); - if (!field.hasAnnotation(anno.getType())) { - field.addAnnotation(anno); - changedType=true; - } - } - } - return changedType; - } - - /** - * Checks for an @target() on the annotation and if found ensures it allows the annotation to be attached to the target type - * that matched. - */ - private boolean checkTargetOK(DeclareAnnotation decA, ResolvedType onType, AnnotationAJ annoX) { - if (annoX.specifiesTarget()) { - if ((onType.isAnnotation() && !annoX.allowedOnAnnotationType()) || (!annoX.allowedOnRegularType())) { - return false; - } - } - return true; - } - - // Hmmm - very similar to the code in BcelWeaver.weaveParentTypeMungers - - // this code - // doesn't need to produce errors/warnings though as it won't really be - // weaving. - protected void weaveInterTypeDeclarations(ResolvedType onType) { - - List<DeclareParents> declareParentsList = getCrosscuttingMembersSet().getDeclareParents(); - if (onType.isRawType()) { - onType = onType.getGenericType(); - } - onType.clearInterTypeMungers(); - - List<DeclareParents> decpToRepeat = new ArrayList<DeclareParents>(); - - boolean aParentChangeOccurred = false; - boolean anAnnotationChangeOccurred = false; - // First pass - apply all decp mungers - for (Iterator<DeclareParents> i = declareParentsList.iterator(); i.hasNext();) { - DeclareParents decp = i.next(); - boolean typeChanged = applyDeclareParents(decp, onType); - if (typeChanged) { - aParentChangeOccurred = true; - } else { // Perhaps it would have matched if a 'dec @type' had - // modified the type - if (!decp.getChild().isStarAnnotation()) { - decpToRepeat.add(decp); - } - } - } - - // Still first pass - apply all dec @type mungers - for (DeclareAnnotation decA : getCrosscuttingMembersSet().getDeclareAnnotationOnTypes()) { - boolean typeChanged = applyDeclareAtType(decA, onType, true); - if (typeChanged) { - anAnnotationChangeOccurred = true; - } - } - - // apply declare @field - for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnFields()) { - if (applyDeclareAtField(deca,onType)) { - anAnnotationChangeOccurred = true; - } - } - - while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) { - anAnnotationChangeOccurred = aParentChangeOccurred = false; - List<DeclareParents> decpToRepeatNextTime = new ArrayList<DeclareParents>(); - for (DeclareParents decp: decpToRepeat) { - if (applyDeclareParents(decp, onType)) { - aParentChangeOccurred = true; - } else { - decpToRepeatNextTime.add(decp); - } - } - - for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnTypes()) { - if (applyDeclareAtType(deca, onType, false)) { - anAnnotationChangeOccurred = true; - } - } - - for (DeclareAnnotation deca: getCrosscuttingMembersSet().getDeclareAnnotationOnFields()) { - if (applyDeclareAtField(deca, onType)) { - anAnnotationChangeOccurred = true; - } - } - decpToRepeat = decpToRepeatNextTime; - } - - } - - @Override - public IWeavingSupport getWeavingSupport() { - return bcelWeavingSupport; - } - - @Override - public void reportCheckerMatch(Checker checker, Shadow shadow) { - IMessage iMessage = new Message(checker.getMessage(shadow), shadow.toString(), checker.isError() ? IMessage.ERROR - : IMessage.WARNING, shadow.getSourceLocation(), null, new ISourceLocation[] { checker.getSourceLocation() }, true, - 0, -1, -1); - - getMessageHandler().handleMessage(iMessage); - - if (getCrossReferenceHandler() != null) { - getCrossReferenceHandler() - .addCrossReference( - checker.getSourceLocation(), - shadow.getSourceLocation(), - (checker.isError() ? IRelationship.Kind.DECLARE_ERROR.getName() : IRelationship.Kind.DECLARE_WARNING - .getName()), false); - - } - - if (getModel() != null) { - AsmRelationshipProvider.addDeclareErrorOrWarningRelationship(getModelAsAsmManager(), shadow, checker); - } - - } - - public AsmManager getModelAsAsmManager() { - return (AsmManager) getModel(); // For now... always an AsmManager in a bcel environment - } - - void raiseError(String message) { - getMessageHandler().handleMessage(MessageUtil.error(message)); - } - - /** - * These are aop.xml files that can be used to alter the aspects that actually apply from those passed in - and also their scope - * of application to other files in the system. - * - * @param xmlFiles list of File objects representing any aop.xml files passed in to configure the build process - */ - public void setXmlFiles(List<File> xmlFiles) { - if (!isXmlConfiguredWorld && !xmlFiles.isEmpty()) { - raiseError("xml configuration files only supported by the compiler when -xmlConfigured option specified"); - return; - } - if (!xmlFiles.isEmpty()) { - xmlConfiguration = new WeavingXmlConfig(this, WeavingXmlConfig.MODE_COMPILE); - } - for (File xmlfile : xmlFiles) { - try { - Definition d = DocumentParser.parse(xmlfile.toURI().toURL()); - xmlConfiguration.add(d); - } catch (MalformedURLException e) { - raiseError("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :" + e.getMessage()); - } catch (Exception e) { - raiseError("Unexpected problem processing XML config file '" + xmlfile.getName() + "' :" + e.getMessage()); - } - } - } - - /** - * Add a scoped aspects where the scoping was defined in an aop.xml file and this world is being used in a LTW configuration - */ - public void addScopedAspect(String name, String scope) { - this.isXmlConfiguredWorld = true; - if (xmlConfiguration == null) { - xmlConfiguration = new WeavingXmlConfig(this, WeavingXmlConfig.MODE_LTW); - } - xmlConfiguration.addScopedAspect(name, scope); - } - - public void setXmlConfigured(boolean b) { - this.isXmlConfiguredWorld = b; - } - - @Override - public boolean isXmlConfigured() { - return isXmlConfiguredWorld && xmlConfiguration != null; - } - - public WeavingXmlConfig getXmlConfiguration() { - return xmlConfiguration; - } - - @Override - public boolean isAspectIncluded(ResolvedType aspectType) { - if (!isXmlConfigured()) { - return true; - } - return xmlConfiguration.specifiesInclusionOfAspect(aspectType.getName()); - } - - @Override - public TypePattern getAspectScope(ResolvedType declaringType) { - return xmlConfiguration.getScopeFor(declaringType.getName()); - } - - @Override - public boolean hasUnsatisfiedDependency(ResolvedType aspectType) { - String aspectName = aspectType.getName(); - - if (aspectType.hasAnnotations()) { - AnnotationAJ[] annos = aspectType.getAnnotations(); - for (AnnotationAJ anno: annos) { - if (anno.getTypeName().equals("org.aspectj.lang.annotation.RequiredTypes")) { - String values = anno.getStringFormOfValue("value"); // Example: "[A,org.foo.Bar]" - if (values != null && values.length() > 2) { - values = values.substring(1,values.length()-1); - StringTokenizer tokenizer = new StringTokenizer(values,","); - boolean anythingMissing = false; - while (tokenizer.hasMoreElements()) { - String requiredTypeName = tokenizer.nextToken(); - ResolvedType rt = resolve(UnresolvedType.forName(requiredTypeName)); - if (rt.isMissing()) { - if (!getMessageHandler().isIgnoring(IMessage.INFO)) { - getMessageHandler().handleMessage( - MessageUtil.info("deactivating aspect '" + aspectName + "' as it requires type '" - + requiredTypeName + "' which cannot be found on the classpath")); - } - anythingMissing = true; - if (aspectRequiredTypes == null) { - aspectRequiredTypes = new HashMap<String,String>(); - } - // Record that it has an invalid type reference - aspectRequiredTypes.put(aspectName,requiredTypeName); - } - } - if (anythingMissing) { - return true; - } - else { - return false; - } - } - else { - // no value specified for annotation - return false; - } - } - } - } - if (aspectRequiredTypes == null) { - // no aspects require anything, so there can be no unsatisfied dependencies - return false; - } - if (!aspectRequiredTypesProcessed.contains(aspectName)) { - String requiredTypeName = aspectRequiredTypes.get(aspectName); - if (requiredTypeName==null) { - aspectRequiredTypesProcessed.add(aspectName); - return false; - } else { - ResolvedType rt = resolve(UnresolvedType.forName(requiredTypeName)); - if (!rt.isMissing()) { - aspectRequiredTypesProcessed.add(aspectName); - aspectRequiredTypes.remove(aspectName); - return false; - } else { - if (!getMessageHandler().isIgnoring(IMessage.INFO)) { - getMessageHandler().handleMessage( - MessageUtil.info("deactivating aspect '" + aspectName + "' as it requires type '" - + requiredTypeName + "' which cannot be found on the classpath")); - } - aspectRequiredTypesProcessed.add(aspectName); - return true; - } - } - } - return aspectRequiredTypes.containsKey(aspectName); - } - - private List<String> aspectRequiredTypesProcessed = new ArrayList<String>(); - private Map<String, String> aspectRequiredTypes = null; - - public void addAspectRequires(String aspectClassName, String requiredType) { - if (aspectRequiredTypes == null) { - aspectRequiredTypes = new HashMap<String, String>(); - } - aspectRequiredTypes.put(aspectClassName,requiredType); - } - - /** - * A WeavingXmlConfig is initially a collection of definitions from XML files - once the world is ready and weaving is running - * it will initialize and transform those definitions into an optimized set of values (eg. resolve type patterns and string - * names to real entities). It can then answer questions quickly: (1) is this aspect included in the weaving? (2) Is there a - * scope specified for this aspect and does it include type X? - * - */ - static class WeavingXmlConfig { - - final static int MODE_COMPILE = 1; - final static int MODE_LTW = 2; - - private int mode; - - private boolean initialized = false; // Lazily done - private List<Definition> definitions = new ArrayList<Definition>(); - - private List<String> resolvedIncludedAspects = new ArrayList<String>(); - private Map<String, TypePattern> scopes = new HashMap<String, TypePattern>(); - - // these are not set for LTW mode (exclusion of these fast match patterns is handled before the weaver/world are used) - private List<String> includedFastMatchPatterns = Collections.emptyList(); - private List<TypePattern> includedPatterns = Collections.emptyList(); - private List<String> excludedFastMatchPatterns = Collections.emptyList(); - private List<TypePattern> excludedPatterns = Collections.emptyList(); - - private BcelWorld world; - - public WeavingXmlConfig(BcelWorld bcelWorld, int mode) { - this.world = bcelWorld; - this.mode = mode; - } - - public void add(Definition d) { - definitions.add(d); - } - - public void addScopedAspect(String aspectName, String scope) { - ensureInitialized(); - resolvedIncludedAspects.add(aspectName); - try { - TypePattern scopePattern = new PatternParser(scope).parseTypePattern(); - scopePattern.resolve(world); - scopes.put(aspectName, scopePattern); - if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { - world.getMessageHandler().handleMessage( - MessageUtil.info("Aspect '" + aspectName + "' is scoped to apply against types matching pattern '" - + scopePattern.toString() + "'")); - } - } catch (Exception e) { - world.getMessageHandler().handleMessage( - MessageUtil.error("Unable to parse scope as type pattern. Scope was '" + scope + "': " + e.getMessage())); - } - } - - public void ensureInitialized() { - if (!initialized) { - try { - resolvedIncludedAspects = new ArrayList<String>(); - // Process the definitions into something more optimal - for (Definition definition : definitions) { - List<String> aspectNames = definition.getAspectClassNames(); - for (String name : aspectNames) { - resolvedIncludedAspects.add(name); - // TODO check for existence? - // ResolvedType resolvedAspect = resolve(UnresolvedType.forName(name)); - // if (resolvedAspect.isMissing()) { - // // ERROR - // } else { - // resolvedIncludedAspects.add(resolvedAspect); - // } - String scope = definition.getScopeForAspect(name); - if (scope != null) { - // Resolve the type pattern - try { - TypePattern scopePattern = new PatternParser(scope).parseTypePattern(); - scopePattern.resolve(world); - scopes.put(name, scopePattern); - if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) { - world.getMessageHandler().handleMessage( - MessageUtil.info("Aspect '" + name - + "' is scoped to apply against types matching pattern '" - + scopePattern.toString() + "'")); - } - } catch (Exception e) { - // TODO definitions should remember which file they came from, for inclusion in this message - world.getMessageHandler().handleMessage( - MessageUtil.error("Unable to parse scope as type pattern. Scope was '" + scope + "': " - + e.getMessage())); - } - } - } - try { - List<String> includePatterns = definition.getIncludePatterns(); - if (includePatterns.size() > 0) { - includedPatterns = new ArrayList<TypePattern>(); - includedFastMatchPatterns = new ArrayList<String>(); - } - for (String includePattern : includePatterns) { - if (includePattern.endsWith("..*")) { - // from 'blah.blah.blah..*' leave the 'blah.blah.blah.' - includedFastMatchPatterns.add(includePattern.substring(0, includePattern.length() - 2)); - } else { - TypePattern includedPattern = new PatternParser(includePattern).parseTypePattern(); - includedPatterns.add(includedPattern); - } - } - List<String> excludePatterns = definition.getExcludePatterns(); - if (excludePatterns.size() > 0) { - excludedPatterns = new ArrayList<TypePattern>(); - excludedFastMatchPatterns = new ArrayList<String>(); - } - for (String excludePattern : excludePatterns) { - if (excludePattern.endsWith("..*")) { - // from 'blah.blah.blah..*' leave the 'blah.blah.blah.' - excludedFastMatchPatterns.add(excludePattern.substring(0, excludePattern.length() - 2)); - } else { - TypePattern excludedPattern = new PatternParser(excludePattern).parseTypePattern(); - excludedPatterns.add(excludedPattern); - } - } - } catch (ParserException pe) { - // TODO definitions should remember which file they came from, for inclusion in this message - world.getMessageHandler().handleMessage( - MessageUtil.error("Unable to parse type pattern: " + pe.getMessage())); - - } - } - } finally { - initialized = true; - } - } - } - - public boolean specifiesInclusionOfAspect(String name) { - ensureInitialized(); - return resolvedIncludedAspects.contains(name); - } - - public TypePattern getScopeFor(String name) { - return scopes.get(name); - } - - // Can't quite follow the same rules for exclusion as used for loadtime weaving: - // "The set of types to be woven are those types matched by at least one weaver include element and not matched by any - // weaver - // exclude element. If there are no weaver include statements then all non-excluded types are included." - // Since if the weaver is seeing it during this kind of build, the type is implicitly included. So all we should check - // for is exclusion - public boolean excludesType(ResolvedType type) { - if (mode == MODE_LTW) { - return false; - } - String typename = type.getName(); - boolean excluded = false; - for (String excludedPattern : excludedFastMatchPatterns) { - if (typename.startsWith(excludedPattern)) { - excluded = true; - break; - } - } - if (!excluded) { - for (TypePattern excludedPattern : excludedPatterns) { - if (excludedPattern.matchesStatically(type)) { - excluded = true; - break; - } - } - } - return excluded; - } - - } - - @Override - public TypeMap getTypeMap() { - return typeMap; - } - - @Override - public boolean isLoadtimeWeaving() { - return false; - } - - public void addTypeDelegateResolver(TypeDelegateResolver typeDelegateResolver) { - if (typeDelegateResolvers == null) { - typeDelegateResolvers = new ArrayList<TypeDelegateResolver>(); - } - typeDelegateResolvers.add(typeDelegateResolver); - } - - @Override - public void classWriteEvent(char[][] compoundName) { - typeMap.classWriteEvent(new String(CharOperation.concatWith(compoundName, '.'))); - } - - /** - * Force demote a type. - */ - public void demote(ResolvedType type) { - typeMap.demote(type); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java b/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java deleted file mode 100644 index f8a36ba98..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java +++ /dev/null @@ -1,579 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002, 2017 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: - * Palo Alto Research Center, Incorporated (PARC). - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.util.LangUtil; -import org.aspectj.util.SoftHashMap; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -/** - * @author Andy Clement - * @author Mario Ivankovits - */ -public class ClassPathManager { - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(ClassPathManager.class); - - private static int maxOpenArchives = -1; - - private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$ - - private static final int MAXOPEN_DEFAULT = 1000; - - private List<Entry> entries; - - // In order to control how many open files we have, we maintain a list. - // The max number is configured through the property: - // org.aspectj.weaver.openarchives - // and it defaults to 1000 - private List<ZipFile> openArchives = new ArrayList<ZipFile>(); - - static { - String openzipsString = getSystemPropertyWithoutSecurityException("org.aspectj.weaver.openarchives", - Integer.toString(MAXOPEN_DEFAULT)); - maxOpenArchives = Integer.parseInt(openzipsString); - if (maxOpenArchives < 20) { - maxOpenArchives = 1000; - } - } - - public ClassPathManager(List<String> classpath, IMessageHandler handler) { - if (trace.isTraceEnabled()) { - trace.enter("<init>", this, new Object[] { classpath==null?"null":classpath.toString(), handler }); - } - entries = new ArrayList<Entry>(); - for (String classpathEntry: classpath) { - addPath(classpathEntry,handler); - } - if (trace.isTraceEnabled()) { - trace.exit("<init>"); - } - } - - protected ClassPathManager() { - } - - public void addPath(String name, IMessageHandler handler) { - File f = new File(name); - String lc = name.toLowerCase(); - if (!f.isDirectory()) { - if (!f.isFile()) { - if (!lc.endsWith(".jar") || lc.endsWith(".zip")) { - // heuristic-only: ending with .jar or .zip means probably a - // zip file - MessageUtil.info(handler, WeaverMessages.format(WeaverMessages.ZIPFILE_ENTRY_MISSING, name)); - } else { - MessageUtil.info(handler, WeaverMessages.format(WeaverMessages.DIRECTORY_ENTRY_MISSING, name)); - } - return; - } - try { - if (lc.endsWith(LangUtil.JRT_FS)) { // Java9 - entries.add(new JImageEntry()); - } else { - entries.add(new ZipFileEntry(f)); - } - } catch (IOException ioe) { - MessageUtil.warn(handler, - WeaverMessages.format(WeaverMessages.ZIPFILE_ENTRY_INVALID, name, ioe.getMessage())); - return; - } - } else { - entries.add(new DirEntry(f)); - } - } - - public ClassFile find(UnresolvedType type) { - if (trace.isTraceEnabled()) { - trace.enter("find", this, type); - } - String name = type.getName(); - for (Iterator<Entry> i = entries.iterator(); i.hasNext();) { - Entry entry = i.next(); - try { - ClassFile ret = entry.find(name); - if (trace.isTraceEnabled()) { - trace.event("searching for "+type+" in "+entry.toString()); - } - if (ret != null) { - if (trace.isTraceEnabled()) { - trace.exit("find", ret); - } - return ret; - } - } catch (IOException ioe) { - // this is NOT an error: it's valid to have missing classpath entries - if (trace.isTraceEnabled()) { - trace.error("Removing classpath entry for "+entry,ioe); - } - i.remove(); - } - } - if (trace.isTraceEnabled()) { - trace.exit("find", null); - } - return null; - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(); - boolean start = true; - for (Iterator<Entry> i = entries.iterator(); i.hasNext();) { - if (start) { - start = false; - } else { - buf.append(File.pathSeparator); - } - buf.append(i.next()); - } - return buf.toString(); - } - - public abstract static class ClassFile { - public abstract InputStream getInputStream() throws IOException; - public abstract String getPath(); - public abstract void close(); - } - - abstract static class Entry { - public abstract ClassFile find(String name) throws IOException; - } - - static class ByteBasedClassFile extends ClassFile { - - private byte[] bytes; - private ByteArrayInputStream bais; - private String path; - - public ByteBasedClassFile(byte[] bytes, String path) { - this.bytes = bytes; - this.path = path; - } - - @Override - public InputStream getInputStream() throws IOException { - this.bais = new ByteArrayInputStream(bytes); - return this.bais; - } - - @Override - public String getPath() { - return this.path; - } - - @Override - public void close() { - if (this.bais!=null) { - try { - this.bais.close(); - } catch (IOException e) { - } - this.bais = null; - } - } - - } - - static class FileClassFile extends ClassFile { - private File file; - private FileInputStream fis; - - public FileClassFile(File file) { - this.file = file; - } - - @Override - public InputStream getInputStream() throws IOException { - fis = new FileInputStream(file); - return fis; - } - - @Override - public void close() { - try { - if (fis != null) - fis.close(); - } catch (IOException ioe) { - throw new BCException("Can't close class file : " + file.getName(), ioe); - } finally { - fis = null; - } - } - - @Override - public String getPath() { - return file.getPath(); - } - } - - class DirEntry extends Entry { - private String dirPath; - - public DirEntry(File dir) { - this.dirPath = dir.getPath(); - } - - public DirEntry(String dirPath) { - this.dirPath = dirPath; - } - - @Override - public ClassFile find(String name) { - File f = new File(dirPath + File.separator + name.replace('.', File.separatorChar) + ".class"); - if (f.isFile()) - return new FileClassFile(f); - else - return null; - } - - @Override - public String toString() { - return dirPath; - } - } - - static class ZipEntryClassFile extends ClassFile { - private ZipEntry entry; - private ZipFileEntry zipFile; - private InputStream is; - - public ZipEntryClassFile(ZipFileEntry zipFile, ZipEntry entry) { - this.zipFile = zipFile; - this.entry = entry; - } - - @Override - public InputStream getInputStream() throws IOException { - is = zipFile.getZipFile().getInputStream(entry); - return is; - } - - @Override - public void close() { - try { - if (is != null) - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - is = null; - } - } - - @Override - public String getPath() { - return entry.getName(); - } - - } - - /** - * Maintains a shared package cache for java runtime image. This maps packages (for example: - * java/lang) to a starting root position in the filesystem (for example: /modules/java.base/java/lang). - * When searching for a type we work out the package name, use it to find where in the filesystem - * to start looking then run from there. Once found we do cache what we learn to make subsequent - * lookups of that type even faster. Maintaining just a package cache rather than complete type cache - * helps reduce memory usage but still gives reasonably fast lookup performance. - */ - static class JImageEntry extends Entry { - - private static FileSystem fs = null; - - private final static Map<String, Path> fileCache = new SoftHashMap<String, Path>(); - - private final static Map<String, Path> packageCache = new HashMap<String, Path>(); - - private static boolean packageCacheInitialized = false; - - public JImageEntry() { - if (fs == null) { - try { - fs = FileSystems.getFileSystem(JRT_URI); - } catch (Throwable t) { - throw new IllegalStateException("Unexpectedly unable to initialize a JRT filesystem", t); - } - } - buildPackageMap(); - } - - class PackageCacheBuilderVisitor extends SimpleFileVisitor<Path> { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (file.getNameCount() > 3 && file.toString().endsWith(".class")) { - int fnc = file.getNameCount(); - if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class - Path packagePath = file.subpath(2, fnc-1); // e.g. java/lang - String packagePathString = packagePath.toString(); - packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang - } - } - return FileVisitResult.CONTINUE; - } - } - - /** - * Create a map from package names to the specific directory of the package members in the filesystem. - */ - private synchronized void buildPackageMap() { - if (!packageCacheInitialized) { - packageCacheInitialized = true; - Iterable<java.nio.file.Path> roots = fs.getRootDirectories(); - PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor(); - try { - for (java.nio.file.Path path : roots) { - Files.walkFileTree(path, visitor); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - class TypeIdentifier extends SimpleFileVisitor<Path> { - - // What are we looking for? - private String name; - - // If set, where did we find it? - public Path found; - - // Basic metric count of how many files we checked before finding it - public int filesSearchedCount; - - public TypeIdentifier(String name) { - this.name = name; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - filesSearchedCount++; - if (file.getNameCount() > 2 && file.toString().endsWith(".class")) { - int fnc = file.getNameCount(); - Path filePath = file.subpath(2, fnc); - String filePathString = filePath.toString(); - if (filePathString.equals(name)) { - fileCache.put(filePathString, file); - found = file; - return FileVisitResult.TERMINATE; - } - } - return FileVisitResult.CONTINUE; - } - } - - private Path searchForFileAndCache(final Path startPath, final String name) { - TypeIdentifier locator = new TypeIdentifier(name); - try { - Files.walkFileTree(startPath, locator); - } catch (IOException e) { - throw new RuntimeException(e); - } - return locator.found; - } - - @Override - public ClassFile find(String name) throws IOException { - String fileName = name.replace('.', '/') + ".class"; - Path file = fileCache.get(fileName); - if (file == null) { - // Check the packages map to see if we know about this package - int idx = fileName.lastIndexOf('/'); - if (idx == -1) { - // Package not here - return null; - } - Path packageStart = null; - String packageName = null; - if (idx !=-1 ) { - packageName = fileName.substring(0, idx); - packageStart = packageCache.get(packageName); - if (packageStart != null) { - file = searchForFileAndCache(packageStart, fileName); - } - } - } - if (file == null) { - return null; - } - byte[] bs = Files.readAllBytes(file); - ClassFile cf = new ByteBasedClassFile(bs, fileName); - return cf; - } - - static Map<String, Path> getPackageCache() { - return packageCache; - } - - static Map<String, Path> getFileCache() { - return fileCache; - } - - } - - class ZipFileEntry extends Entry { - private File file; - private ZipFile zipFile; - - public ZipFileEntry(File file) throws IOException { - this.file = file; - } - - public ZipFileEntry(ZipFile zipFile) { - this.zipFile = zipFile; - } - - public ZipFile getZipFile() { - return zipFile; - } - - @Override - public ClassFile find(String name) throws IOException { - ensureOpen(); - String key = name.replace('.', '/') + ".class"; - ZipEntry entry = zipFile.getEntry(key); - if (entry != null) - return new ZipEntryClassFile(this, entry); - else - return null; // This zip will be closed when necessary... - } - - public List<ZipEntryClassFile> getAllClassFiles() throws IOException { - ensureOpen(); - List<ZipEntryClassFile> ret = new ArrayList<ZipEntryClassFile>(); - for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements();) { - ZipEntry entry = e.nextElement(); - String name = entry.getName(); - if (hasClassExtension(name)) - ret.add(new ZipEntryClassFile(this, entry)); - } - // if (ret.isEmpty()) close(); - return ret; - } - - private void ensureOpen() throws IOException { - if (zipFile != null && openArchives.contains(zipFile)) { - if (isReallyOpen()) - return; - } - if (openArchives.size() >= maxOpenArchives) { - closeSomeArchives(openArchives.size() / 10); // Close 10% of - // those open - } - zipFile = new ZipFile(file); - if (!isReallyOpen()) { - throw new FileNotFoundException("Can't open archive: " + file.getName() + " (size() check failed)"); - } - openArchives.add(zipFile); - } - - private boolean isReallyOpen() { - try { - zipFile.size(); // this will fail if the file has been closed - // for - // some reason; - return true; - } catch (IllegalStateException ex) { - // this means the zip file is closed... - return false; - } - - } - - public void closeSomeArchives(int n) { - for (int i = n - 1; i >= 0; i--) { - ZipFile zf = openArchives.get(i); - try { - zf.close(); - } catch (IOException e) { - e.printStackTrace(); - } - openArchives.remove(i); - } - } - - public void close() { - if (zipFile == null) - return; - try { - openArchives.remove(zipFile); - zipFile.close(); - } catch (IOException ioe) { - throw new BCException("Can't close archive: " + file.getName(), ioe); - } finally { - zipFile = null; - } - } - - @Override - public String toString() { - return file.getName(); - } - } - - /* private */static boolean hasClassExtension(String name) { - return name.toLowerCase().endsWith((".class")); - } - - public void closeArchives() { - for (Entry entry : entries) { - if (entry instanceof ZipFileEntry) { - ((ZipFileEntry) entry).close(); - } - openArchives.clear(); - } - } - - // Copes with the security manager - private static String getSystemPropertyWithoutSecurityException(String aPropertyName, String aDefaultValue) { - try { - return System.getProperty(aPropertyName, aDefaultValue); - } catch (SecurityException ex) { - return aDefaultValue; - } - } - - // Mainly exposed for testing - public List<Entry> getEntries() { - return entries; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java b/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java deleted file mode 100644 index 5e74627c3..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java +++ /dev/null @@ -1,151 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.weaver.UnresolvedType; - -/** - * exceptionRanges are set initially to be low priority. The various setPriority methods should be used accordingly. The priority is - * used when we pack the exception table into a method... the exception table should be sorted from high to low priority. Exceptions - * we generate for advice is either high priority (higher than anything coming from the original method... most kinds of - * non-execution advice) or low priority (lower than anything coming from the original method, for execution advice). - * - * <p> - * ??? This does not account for handler, or any other "statement-level" advice. When such statement level advice happens, we may - * want to go to a float level, so we can set the priority of advice to be lower than anything it encloses, and higher than anything - * enclosing it. - */ - -/* - * we're actually using the fact that we're an instruction targeter, for the handler - */ -public final class ExceptionRange extends Range { - - private InstructionHandle handler; - private final UnresolvedType exceptionType; - private final int priority; - - // ---- initialization - - /** - * After this constructor is called, this range is not well situated unless {@link #associateWithTargets} is called - * - * XXX priority should be fixed - */ - public ExceptionRange(InstructionList body, UnresolvedType exceptionType, int priority) { - super(body); - this.exceptionType = exceptionType; - this.priority = priority; - } - - /** - * @param insideExisting - */ - public ExceptionRange(InstructionList body, UnresolvedType exceptionType, boolean insideExisting) { - this(body, exceptionType, insideExisting ? Integer.MAX_VALUE : -1); - } - - public void associateWithTargets(InstructionHandle start, InstructionHandle end, InstructionHandle handler) { - // assert body.contains(start) && body.contains(end) && body.contains(handler) - this.start = start; - this.end = end; - this.handler = handler; - start.addTargeter(this); - end.addTargeter(this); - handler.addTargeter(this); - } - - // ---- - - public InstructionHandle getHandler() { - return handler; - } - - public UnresolvedType getCatchType() { - return exceptionType; - } - - public int getPriority() { - return priority; - } - - // ---- from object - - public String toString() { - String str; - if (exceptionType == null) { - str = "finally"; - } else { - str = "catch " + exceptionType; - } - // if (priority >= 0 && priority < Integer.MAX_VALUE) { - // str += " (priority " + priority + ")"; - // } - return str; - } - - public boolean equals(Object other) { - if (!(other instanceof ExceptionRange)) - return false; - ExceptionRange o = (ExceptionRange) other; - return o.getStart() == getStart() && o.getEnd() == getEnd() && o.handler == handler - && ((o.exceptionType == null) ? (exceptionType == null) : o.exceptionType.equals(exceptionType)) - && o.priority == priority; - } - - private volatile int hashCode = 0; - - public int hashCode() { - if (hashCode == 0) { - int ret = 17; - ret = 37 * ret + getStart().hashCode(); - ret = 37 * ret + getEnd().hashCode(); - ret = 37 * ret + handler.hashCode(); - ret = 37 * ret + ((exceptionType == null) ? 0 : exceptionType.hashCode()); - ret = 37 * ret + priority; - hashCode = ret; - } - return hashCode; - } - - public void updateTarget(InstructionHandle oldIh, InstructionHandle newIh, InstructionList newBody) { - super.updateTarget(oldIh, newIh, newBody); - // we're guaranteed that start, end, and handler are distinct instruction handles. - if (oldIh == handler) { - handler = newIh; - } - } - - public static boolean isExceptionStart(InstructionHandle ih) { - if (!isRangeHandle(ih)) - return false; - Range r = getRange(ih); - if (!(r instanceof ExceptionRange)) - return false; - ExceptionRange er = (ExceptionRange) r; - return er.getStart() == ih; - } - - public static boolean isExceptionEnd(InstructionHandle ih) { - if (!isRangeHandle(ih)) - return false; - Range r = getRange(ih); - if (!(r instanceof ExceptionRange)) - return false; - ExceptionRange er = (ExceptionRange) r; - return er.getEnd() == ih; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/ExtensibleURLClassLoader.java b/weaver/src/org/aspectj/weaver/bcel/ExtensibleURLClassLoader.java deleted file mode 100644 index 3480b8172..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/ExtensibleURLClassLoader.java +++ /dev/null @@ -1,113 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2004 IBM Corporation - * 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: - * Matthew Webster, Adrian Colyer, - * Martin Lippert initial implementation - * Andy Clement - * Roy Varghese - Bug 473555 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.CodeSource; - -import org.aspectj.util.FileUtil; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.UnresolvedType; - -public abstract class ExtensibleURLClassLoader extends URLClassLoader { - - private ClassPathManager classPath; - - public ExtensibleURLClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - - // System.err.println("? ExtensibleURLClassLoader.<init>() path=" + WeavingAdaptor.makeClasspath(urls)); - try { - classPath = new ClassPathManager(FileUtil.makeClasspath(urls), null); - } catch (ExceptionInInitializerError ex) { - ex.printStackTrace(System.out); - throw ex; - } - } - - protected void addURL(URL url) { - super.addURL(url); // amc - this call was missing and is needed in - // WeavingURLClassLoader chains - classPath.addPath(url.getPath(), null); - } - - protected Class findClass(String name) throws ClassNotFoundException { - // System.err.println("? ExtensibleURLClassLoader.findClass(" + name + ")"); - try { - byte[] bytes = getBytes(name); - if (bytes != null) { - return defineClass(name, bytes); - } else { - throw new ClassNotFoundException(name); - } - } catch (IOException ex) { - throw new ClassNotFoundException(name); - } - } - - protected Class defineClass(String name, byte[] b, CodeSource cs) throws IOException { - // System.err.println("? ExtensibleURLClassLoader.defineClass(" + name + ",[" + b.length + "])"); - return defineClass(name, b, 0, b.length, cs); - } - - protected byte[] getBytes(String name) throws IOException { - byte[] b = null; - UnresolvedType unresolvedType = null; - try { - unresolvedType = UnresolvedType.forName(name); - } catch (BCException bce) { - if (bce.getMessage().indexOf("nameToSignature") == -1) { - bce.printStackTrace(System.err); - } - return null; - } - ClassPathManager.ClassFile classFile = classPath.find(unresolvedType); - if (classFile != null) { - try { - b = FileUtil.readAsByteArray(classFile.getInputStream()); - } finally { - classFile.close(); - } - } - return b; - } - - private Class defineClass(String name, byte[] bytes /* ClassPathManager.ClassFile classFile */) throws IOException { - String packageName = getPackageName(name); - if (packageName != null) { - Package pakkage = getPackage(packageName); - if (pakkage == null) { - definePackage(packageName, null, null, null, null, null, null, null); - } - } - - return defineClass(name, bytes, null); - } - - private String getPackageName(String className) { - int offset = className.lastIndexOf('.'); - return (offset == -1) ? null : className.substring(0, offset); - } - - @Override - public void close() throws IOException { - super.close(); - classPath.closeArchives(); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/FakeAnnotation.java b/weaver/src/org/aspectj/weaver/bcel/FakeAnnotation.java deleted file mode 100644 index 4194e66e9..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/FakeAnnotation.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Andy Clement - *******************************************************************************/ -package org.aspectj.weaver.bcel; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.List; - -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; - -/** - * For implementing declare @type interacting with declare @parents during compilation - we need to be able to add an annotation to - * 'binary type binding' (this is how types are seen during incremental compilation). Unlike a SourceTypeBinding - a - * BinaryTypeBinding does not allow easy interaction with its annotations - so what we do is take the eclipse annotation, suck out - * the name/signature and visibility and put that information in a 'FakeAnnotation'. The FakeAnnotation is attached to the BCEL - * delegate for the binary type binding - this will allow type resolution to succeed correctly. The FakeAnnotation never makes it to - * disk, since the weaver does the job properly, attaching a real annotation. - */ -public class FakeAnnotation extends AnnotationGen { - - private String name; - private String sig; - private boolean isRuntimeVisible; - - public FakeAnnotation(String name, String sig, boolean isRuntimeVisible) { - super(null, null, true, null); - this.name = name; - this.sig = sig; - this.isRuntimeVisible = isRuntimeVisible; - } - - public String getTypeName() { - return name; - } - - public String getTypeSignature() { - return sig; - } - - public void addElementNameValuePair(NameValuePair evp) { - // doesnt need to know about name/value pairs - } - - public void dump(DataOutputStream dos) throws IOException { - // should be serialized - } - - public int getTypeIndex() { - return 0; - } - - public List getValues() { - return null; - } - - public boolean isRuntimeVisible() { - return isRuntimeVisible; - } - - protected void setIsRuntimeVisible(boolean b) { - } - - public String toShortString() { - return "@" + this.name; - } - - public String toString() { - return this.name; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/IfFinder.java b/weaver/src/org/aspectj/weaver/bcel/IfFinder.java deleted file mode 100644 index c66aa8939..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/IfFinder.java +++ /dev/null @@ -1,56 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2006 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: - * Andy Clement initial implementation - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor; -import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.IfPointcut; -import org.aspectj.weaver.patterns.NotPointcut; -import org.aspectj.weaver.patterns.OrPointcut; - -/** - * Look for an if() pointcut - */ -class IfFinder extends AbstractPatternNodeVisitor { - boolean hasIf = false; - - public Object visit(IfPointcut node, Object data) { - if (node.alwaysFalse() || node.alwaysTrue()) { - // IfFalse / IfTrue - } else { - hasIf = true; - } - return node; - } - - public Object visit(AndPointcut node, Object data) { - if (!hasIf) - node.getLeft().accept(this, data); - if (!hasIf) - node.getRight().accept(this, data); - return node; - } - - public Object visit(NotPointcut node, Object data) { - if (!hasIf) - node.getNegatedPointcut().accept(this, data); - return node; - } - - public Object visit(OrPointcut node, Object data) { - if (!hasIf) - node.getLeft().accept(this, data); - if (!hasIf) - node.getRight().accept(this, data); - return node; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java deleted file mode 100644 index 83189e1d4..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ /dev/null @@ -1,1940 +0,0 @@ -/* ******************************************************************* - * 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 - * Andy Clement 6Jul05 generics - signature attribute - * Abraham Nevado - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.Vector; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Field; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.Signature; -import org.aspectj.apache.bcel.classfile.Synthetic; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.generic.BasicType; -import org.aspectj.apache.bcel.generic.ClassGen; -import org.aspectj.apache.bcel.generic.FieldGen; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.SourceLocation; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverState; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.MemberKind; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.RuntimeVersion; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.SignatureUtils; -import org.aspectj.weaver.TypeVariable; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.UnresolvedType.TypeKind; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.WeaverStateInfo; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.asm.AsmDetector; -import org.aspectj.weaver.bcel.asm.StackMapAdder; - -/** - * Lazy lazy lazy. We don't unpack the underlying class unless necessary. Things like new methods and annotations accumulate in here - * until they must be written out, don't add them to the underlying MethodGen! Things are slightly different if this represents an - * Aspect. - */ -public final class LazyClassGen { - - private static final Type[] ARRAY_7STRING_INT = new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, - Type.STRING, Type.STRING, Type.INT }; - - private static final Type[] ARRAY_8STRING_INT = new Type[] { Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, - Type.STRING, Type.STRING, Type.STRING, Type.INT }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_METHOD = new Type[] { - Type.STRING, Type.INT, Type.STRING, Type.CLASS, Type.CLASS_ARRAY, Type.STRING_ARRAY, Type.CLASS_ARRAY, Type.CLASS, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_CONSTRUCTOR = new Type[] { - Type.STRING, Type.INT, Type.CLASS, Type.CLASS_ARRAY, Type.STRING_ARRAY, Type.CLASS_ARRAY, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_CATCHCLAUSE = new Type[] { - Type.STRING, Type.CLASS, Type.CLASS, Type.STRING, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_FIELD = new Type[] { - Type.STRING, Type.INT, Type.STRING, Type.CLASS, Type.CLASS, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_INITIALIZER = new Type[] { - Type.STRING, Type.INT, Type.CLASS, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_MONITOR = new Type[] { - Type.STRING, Type.CLASS, Type.INT - }; - - private static final Type[] PARAMSIGNATURE_MAKESJP_ADVICE = new Type[] { - Type.STRING, Type.INT, Type.STRING, Type.CLASS, Type.CLASS_ARRAY, Type.STRING_ARRAY, - Type.CLASS_ARRAY, Type.CLASS, Type.INT - }; - - - - - - private static final int ACC_SYNTHETIC = 0x1000; - - private static final String[] NO_STRINGS = new String[0]; - - int highestLineNumber = 0; // ---- JSR 45 info - - private final SortedMap<String, InlinedSourceFileInfo> inlinedFiles = new TreeMap<String, InlinedSourceFileInfo>(); - - private boolean regenerateGenericSignatureAttribute = false; - - private BcelObjectType myType; // XXX is not set for types we create - private ClassGen myGen; - private final ConstantPool cp; - private final World world; - private final String packageName = null; - - private final List<BcelField> fields = new ArrayList<BcelField>(); - private final List<LazyMethodGen> methodGens = new ArrayList<LazyMethodGen>(); - private final List<LazyClassGen> classGens = new ArrayList<LazyClassGen>(); - private final List<AnnotationGen> annotations = new ArrayList<AnnotationGen>(); - private int childCounter = 0; - - private final InstructionFactory fact; - - private boolean isSerializable = false; - private boolean hasSerialVersionUIDField = false; - private boolean serialVersionUIDRequiresInitialization = false; - private long calculatedSerialVersionUID; - private boolean hasClinit = false; - - private ResolvedType[] extraSuperInterfaces = null; - private ResolvedType superclass = null; - - // --- - - static class InlinedSourceFileInfo { - int highestLineNumber; - int offset; // calculated - - InlinedSourceFileInfo(int highestLineNumber) { - this.highestLineNumber = highestLineNumber; - } - } - - void addInlinedSourceFileInfo(String fullpath, int highestLineNumber) { - Object o = inlinedFiles.get(fullpath); - if (o != null) { - InlinedSourceFileInfo info = (InlinedSourceFileInfo) o; - if (info.highestLineNumber < highestLineNumber) { - info.highestLineNumber = highestLineNumber; - } - } else { - inlinedFiles.put(fullpath, new InlinedSourceFileInfo(highestLineNumber)); - } - } - - void calculateSourceDebugExtensionOffsets() { - int i = roundUpToHundreds(highestLineNumber); - for (InlinedSourceFileInfo element : inlinedFiles.values()) { - element.offset = i; - i = roundUpToHundreds(i + element.highestLineNumber); - } - } - - private static int roundUpToHundreds(int i) { - return ((i / 100) + 1) * 100; - } - - int getSourceDebugExtensionOffset(String fullpath) { - return inlinedFiles.get(fullpath).offset; - } - - // private Unknown getSourceDebugExtensionAttribute() { - // int nameIndex = cp.addUtf8("SourceDebugExtension"); - // String data = getSourceDebugExtensionString(); - // //System.err.println(data); - // byte[] bytes = Utility.stringToUTF(data); - // int length = bytes.length; - // - // return new Unknown(nameIndex, length, bytes, cp); - // } - - // private LazyClassGen() {} - // public static void main(String[] args) { - // LazyClassGen m = new LazyClassGen(); - // m.highestLineNumber = 37; - // m.inlinedFiles.put("boo/baz/foo.java", new InlinedSourceFileInfo( 83)); - // m.inlinedFiles.put("boo/barz/foo.java", new InlinedSourceFileInfo(292)); - // m.inlinedFiles.put("boo/baz/moo.java", new InlinedSourceFileInfo(128)); - // m.calculateSourceDebugExtensionOffsets(); - // System.err.println(m.getSourceDebugExtensionString()); - // } - - // For the entire pathname, we're using package names. This is probably - // wrong. - // private String getSourceDebugExtensionString() { - // StringBuffer out = new StringBuffer(); - // String myFileName = getFileName(); - // // header section - // out.append("SMAP\n"); - // out.append(myFileName); - // out.append("\nAspectJ\n"); - // // stratum section - // out.append("*S AspectJ\n"); - // // file section - // out.append("*F\n"); - // out.append("1 "); - // out.append(myFileName); - // out.append("\n"); - // int i = 2; - // for (Iterator iter = inlinedFiles.keySet().iterator(); iter.hasNext();) { - // String element = (String) iter.next(); - // int ii = element.lastIndexOf('/'); - // if (ii == -1) { - // out.append(i++); out.append(' '); - // out.append(element); out.append('\n'); - // } else { - // out.append("+ "); out.append(i++); out.append(' '); - // out.append(element.substring(ii+1)); out.append('\n'); - // out.append(element); out.append('\n'); - // } - // } - // // emit line section - // out.append("*L\n"); - // out.append("1#1,"); - // out.append(highestLineNumber); - // out.append(":1,1\n"); - // i = 2; - // for (Iterator iter = inlinedFiles.values().iterator(); iter.hasNext();) { - // InlinedSourceFileInfo element = (InlinedSourceFileInfo) iter.next(); - // out.append("1#"); - // out.append(i++); out.append(','); - // out.append(element.highestLineNumber); out.append(":"); - // out.append(element.offset + 1); out.append(",1\n"); - // } - // // end section - // out.append("*E\n"); - // // and finish up... - // return out.toString(); - // } - - // ---- end JSR45-related stuff - - /** Emit disassembled class and newline to out */ - public static void disassemble(String path, String name, PrintStream out) throws IOException { - if (null == out) { - return; - } - // out.println("classPath: " + classPath); - - BcelWorld world = new BcelWorld(path); - - UnresolvedType ut = UnresolvedType.forName(name); - ut.setNeedsModifiableDelegate(true); - LazyClassGen clazz = new LazyClassGen(BcelWorld.getBcelObjectType(world.resolve(ut))); - clazz.print(out); - out.println(); - } - - public String getNewGeneratedNameTag() { - return new Integer(childCounter++).toString(); - } - - // ---- - - public LazyClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces, - World world) { - myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces); - cp = myGen.getConstantPool(); - fact = new InstructionFactory(myGen, cp); - regenerateGenericSignatureAttribute = true; - this.world = world; - } - - public void setMajorMinor(int major, int minor) { - myGen.setMajor(major); - myGen.setMinor(minor); - } - - public int getMajor() { - return myGen.getMajor(); - } - - public int getMinor() { - return myGen.getMinor(); - } - - // Non child type, so it comes from a real type in the world. - public LazyClassGen(BcelObjectType myType) { - myGen = new ClassGen(myType.getJavaClass()); - cp = myGen.getConstantPool(); - fact = new InstructionFactory(myGen, cp); - this.myType = myType; - world = myType.getResolvedTypeX().getWorld(); - - /* Does this class support serialization */ - if (implementsSerializable(getType())) { - isSerializable = true; - - // ResolvedMember[] fields = getType().getDeclaredFields(); - // for (int i = 0; i < fields.length; i++) { - // ResolvedMember field = fields[i]; - // if (field.getName().equals("serialVersionUID") - // && field.isStatic() && field.getType().equals(UnresolvedType.LONG)) - // { - // hasSerialVersionUIDField = true; - // } - // } - hasSerialVersionUIDField = hasSerialVersionUIDField(getType()); - - ResolvedMember[] methods = getType().getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - ResolvedMember method = methods[i]; - if (method.getName().equals("<clinit>")) { - if (method.getKind() != Member.STATIC_INITIALIZATION) { - throw new RuntimeException("qui?"); - } - hasClinit = true; - } - } - - // Do we need to calculate an SUID and add it? - if (!getType().isInterface() && !hasSerialVersionUIDField && world.isAddSerialVerUID()) { - calculatedSerialVersionUID = myGen.getSUID(); - FieldGen fg = new FieldGen(Constants.ACC_PRIVATE | Constants.ACC_FINAL | Constants.ACC_STATIC, BasicType.LONG, - "serialVersionUID", getConstantPool()); - addField(fg); - hasSerialVersionUIDField = true; - serialVersionUIDRequiresInitialization = true; - // warn about what we've done? - if (world.getLint().calculatingSerialVersionUID.isEnabled()) { - world.getLint().calculatingSerialVersionUID.signal( - new String[] { getClassName(), Long.toString(calculatedSerialVersionUID) + "L" }, null, null); - } - } - } - - ResolvedMember[] methods = myType.getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - addMethodGen(new LazyMethodGen((BcelMethod) methods[i], this)); - } - - // Method[] methods = myGen.getMethods(); - // for (int i = 0; i < methods.length; i++) { - // addMethodGen(new LazyMethodGen(methods[i], this)); - // } - - ResolvedMember[] fields = myType.getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - this.fields.add((BcelField) fields[i]); - } - } - - public static boolean hasSerialVersionUIDField(ResolvedType type) { - - ResolvedMember[] fields = type.getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - ResolvedMember field = fields[i]; - if (field.getName().equals("serialVersionUID") && Modifier.isStatic(field.getModifiers()) - && field.getType().equals(UnresolvedType.LONG)) { - return true; - } - } - - return false; - } - - // public void addAttribute(Attribute i) { - // myGen.addAttribute(i); - // } - - // ---- - - public String getInternalClassName() { - return getConstantPool().getConstantString_CONSTANTClass(myGen.getClassNameIndex()); - // getConstantPool().getConstantString( - // myGen.getClassNameIndex(), - // Constants.CONSTANT_Class); - - } - - public String getInternalFileName() { - String str = getInternalClassName(); - int index = str.lastIndexOf('/'); - if (index == -1) { - return getFileName(); - } else { - return str.substring(0, index + 1) + getFileName(); - } - } - - /** - * Returns the packagename - if its the default package we return an empty string - */ - public String getPackageName() { - if (packageName != null) { - return packageName; - } - String str = getInternalClassName(); - int index = str.indexOf("<"); - if (index != -1) { - str = str.substring(0, index); // strip off the generics guff - } - index = str.lastIndexOf("/"); - if (index == -1) { - return ""; - } - return str.substring(0, index).replace('/', '.'); - } - - public void addMethodGen(LazyMethodGen gen) { - // assert gen.getClassName() == super.getClassName(); - methodGens.add(gen); - if (highestLineNumber < gen.highestLineNumber) { - highestLineNumber = gen.highestLineNumber; - } - } - - public boolean removeMethodGen(LazyMethodGen gen) { - return methodGens.remove(gen); - } - - public void addMethodGen(LazyMethodGen gen, ISourceLocation sourceLocation) { - addMethodGen(gen); - if (!gen.getMethod().isPrivate()) { - warnOnAddedMethod(gen.getMethod(), sourceLocation); - } - } - - public void errorOnAddedField(FieldGen field, ISourceLocation sourceLocation) { - if (isSerializable && !hasSerialVersionUIDField) { - getWorld().getLint().serialVersionUIDBroken.signal( - new String[] { myType.getResolvedTypeX().getName(), field.getName() }, sourceLocation, null); - } - } - - public void warnOnAddedInterface(String name, ISourceLocation sourceLocation) { - warnOnModifiedSerialVersionUID(sourceLocation, "added interface " + name); - } - - public void warnOnAddedMethod(Method method, ISourceLocation sourceLocation) { - warnOnModifiedSerialVersionUID(sourceLocation, "added non-private method " + method.getName()); - } - - public void warnOnAddedStaticInitializer(Shadow shadow, ISourceLocation sourceLocation) { - if (!hasClinit) { - warnOnModifiedSerialVersionUID(sourceLocation, "added static initializer"); - } - } - - public void warnOnModifiedSerialVersionUID(ISourceLocation sourceLocation, String reason) { - if (isSerializable && !hasSerialVersionUIDField) { - getWorld().getLint().needsSerialVersionUIDField.signal(new String[] { myType.getResolvedTypeX().getName().toString(), - reason }, sourceLocation, null); - } - } - - public World getWorld() { - return world; - } - - public List<LazyMethodGen> getMethodGens() { - return methodGens; // ???Collections.unmodifiableList(methodGens); - } - - public List<BcelField> getFieldGens() { - return fields; - } - - public boolean fieldExists(String name) { -// Field[] allFields = myGen.getFields(); -// if (allFields!=null) { -// for (int i=0;i<allFields.length;i++) { -// Field f = allFields[i]; -// if (f.getName().equals(name)) { -// return f; -// } -// } -// } - for (BcelField f: fields) { - if (f.getName().equals(name)) { - return true; - } - } - return false; - } - - private void writeBack(BcelWorld world) { - if (getConstantPool().getSize() > Short.MAX_VALUE) { - reportClassTooBigProblem(); - return; - } - - if (annotations.size() > 0) { - for (AnnotationGen element : annotations) { - myGen.addAnnotation(element); - } - // Attribute[] annAttributes = - // org.aspectj.apache.bcel.classfile.Utility.getAnnotationAttributes( - // getConstantPool(),annotations); - // for (int i = 0; i < annAttributes.length; i++) { - // Attribute attribute = annAttributes[i]; - // System.err.println("Adding attribute for "+attribute); - // myGen.addAttribute(attribute); - // } - } - - // Add a weaver version attribute to the file being produced (if - // necessary...) - if (!myGen.hasAttribute("org.aspectj.weaver.WeaverVersion")) { - myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverVersionInfo(), getConstantPool())); - } - - // see 389678: TODO more finessing possible here? - if (world.isOverWeaving()) { - if (myGen.hasAttribute(WeaverState.AttributeName) && myType!=null && myType.getWeaverState() != null) { - myGen.removeAttribute(myGen.getAttribute(WeaverState.AttributeName)); - myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverState(myType.getWeaverState()), getConstantPool())); - } - } else { - if (!myGen.hasAttribute(WeaverState.AttributeName) && myType != null && myType.getWeaverState() != null) { - myGen.addAttribute(Utility.bcelAttribute(new AjAttribute.WeaverState(myType.getWeaverState()), getConstantPool())); - } - } - - // FIXME ATAJ needed only for slow Aspects.aspectOf() - keep or remove - // make a lot of test fail since the test compare weaved class file - // based on some test data as text files... - // if (!myGen.isInterface()) { - // addAjClassField(); - // } - - addAjcInitializers(); - - // 17Feb05 - ASC - Skip this for now - it crashes IBM 1.4.2 jvms - // (pr80430). Will be revisited when contents - // of attribute are confirmed to be correct. - boolean sourceDebugExtensionSupportSwitchedOn = false; - - if (sourceDebugExtensionSupportSwitchedOn) { - calculateSourceDebugExtensionOffsets(); - } - - int len = methodGens.size(); - myGen.setMethods(Method.NoMethods); - - for (LazyMethodGen gen : methodGens) { - // we skip empty clinits - if (isEmptyClinit(gen)) { - continue; - } - myGen.addMethod(gen.getMethod()); - } - - len = fields.size(); - myGen.setFields(Field.NoFields); - for (int i = 0; i < len; i++) { - BcelField gen = fields.get(i); - myGen.addField(gen.getField(cp)); - } - - if (sourceDebugExtensionSupportSwitchedOn) { - if (inlinedFiles.size() != 0) { - if (hasSourceDebugExtensionAttribute(myGen)) { - world.showMessage(IMessage.WARNING, WeaverMessages.format(WeaverMessages.OVERWRITE_JSR45, getFileName()), null, - null); - } - // myGen.addAttribute(getSourceDebugExtensionAttribute()); - } - } - - fixupGenericSignatureAttribute(); - } - - /** - * When working with Java generics, a signature attribute is attached to the type which indicates how it was declared. This - * routine ensures the signature attribute for the class we are about to write out is correct. Basically its responsibilities - * are: - * <ol> - * <li> - * Checking whether the attribute needs changing (ie. did weaving change the type hierarchy) - if it did, remove the old - * attribute - * <li> - * Check if we need an attribute at all, are we generic? are our supertypes parameterized/generic? - * <li> - * Build the new attribute which includes all typevariable, supertype and superinterface information - * </ol> - */ - private void fixupGenericSignatureAttribute() { - - if (getWorld() != null && !getWorld().isInJava5Mode()) { - return; - } - - // TODO asc generics Temporarily assume that types we generate dont need - // a signature attribute (closure/etc).. will need - // revisiting no doubt... - // if (myType == null) { - // return; - // } - - // 1. Has anything changed that would require us to modify this - // attribute? - if (!regenerateGenericSignatureAttribute) { - return; - } - - // 2. Find the old attribute - Signature sigAttr = null; - if (myType != null) { // if null, this is a type built from scratch, it - // won't already have a sig attribute - sigAttr = (Signature) myGen.getAttribute("Signature"); - } - - // 3. Do we need an attribute? - boolean needAttribute = false; - // If we had one before, we definetly still need one as types can't be - // 'removed' from the hierarchy - if (sigAttr != null) { - needAttribute = true; - } - - // check the interfaces - if (!needAttribute) { - if (myType != null) { - ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces(); - for (int i = 0; i < interfaceRTXs.length; i++) { - ResolvedType typeX = interfaceRTXs[i]; - if (typeX.isGenericType() || typeX.isParameterizedType()) { - needAttribute = true; - } - } - if (extraSuperInterfaces != null) { - for (int i = 0; i < extraSuperInterfaces.length; i++) { - ResolvedType interfaceType = extraSuperInterfaces[i]; - if (interfaceType.isGenericType() || interfaceType.isParameterizedType()) { - needAttribute = true; - } - } - } - } - - if (myType == null) { - ResolvedType superclassRTX = superclass; - if (superclassRTX != null) { - if (superclassRTX.isGenericType() || superclassRTX.isParameterizedType()) { - needAttribute = true; - } - } - } else { - // check the supertype - ResolvedType superclassRTX = getSuperClass(); - if (superclassRTX.isGenericType() || superclassRTX.isParameterizedType()) { - needAttribute = true; - } - } - } - - if (needAttribute) { - StringBuffer signature = new StringBuffer(); - // first, the type variables... - if (myType != null) { - TypeVariable[] tVars = myType.getTypeVariables(); - if (tVars.length > 0) { - signature.append("<"); - for (int i = 0; i < tVars.length; i++) { - TypeVariable variable = tVars[i]; - signature.append(variable.getSignatureForAttribute()); - } - signature.append(">"); - } - } - // now the supertype - String supersig = getSuperClass().getSignatureForAttribute(); - signature.append(supersig); - if (myType != null) { - ResolvedType[] interfaceRTXs = myType.getDeclaredInterfaces(); - for (int i = 0; i < interfaceRTXs.length; i++) { - String s = interfaceRTXs[i].getSignatureForAttribute(); - signature.append(s); - } - if (extraSuperInterfaces != null) { - for (int i = 0; i < extraSuperInterfaces.length; i++) { - String s = extraSuperInterfaces[i].getSignatureForAttribute(); - signature.append(s); - } - } - } - if (sigAttr != null) { - myGen.removeAttribute(sigAttr); - } - myGen.addAttribute(createSignatureAttribute(signature.toString())); - } - } - - /** - * Helper method to create a signature attribute based on a string signature: e.g. "Ljava/lang/Object;LI<Ljava/lang/Double;>;" - */ - private Signature createSignatureAttribute(String signature) { - int nameIndex = cp.addUtf8("Signature"); - int sigIndex = cp.addUtf8(signature); - return new Signature(nameIndex, 2, sigIndex, cp); - } - - /** - * - */ - private void reportClassTooBigProblem() { - // PR 59208 - // we've generated a class that is just toooooooooo big (you've been - // generating programs - // again haven't you? come on, admit it, no-one writes classes this big - // by hand). - // create an empty myGen so that we can give back a return value that - // doesn't upset the - // rest of the process. - myGen = new ClassGen(myGen.getClassName(), myGen.getSuperclassName(), myGen.getFileName(), myGen.getModifiers(), - myGen.getInterfaceNames()); - // raise an error against this compilation unit. - getWorld().showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.CLASS_TOO_BIG, this.getClassName()), - new SourceLocation(new File(myGen.getFileName()), 0), null); - } - - private static boolean hasSourceDebugExtensionAttribute(ClassGen gen) { - return gen.hasAttribute("SourceDebugExtension"); - } - - public JavaClass getJavaClass(BcelWorld world) { - writeBack(world); - return myGen.getJavaClass(); - } - - public byte[] getJavaClassBytesIncludingReweavable(BcelWorld world) { - writeBack(world); - byte[] wovenClassFileData = myGen.getJavaClass().getBytes(); - // At 1.6 stackmaps are optional, whilst at 1.7 and later they - // are required (unless turning off the verifier) - if ((myGen.getMajor() == Constants.MAJOR_1_6 && world.shouldGenerateStackMaps()) || myGen.getMajor() > Constants.MAJOR_1_6) { - if (!AsmDetector.isAsmAround) { - throw new BCException("Unable to find Asm for stackmap generation (Looking for 'aj.org.objectweb.asm.ClassReader'). Stackmap generation for woven code is required to avoid verify errors on a Java 1.7 or higher runtime"); - }; - wovenClassFileData = StackMapAdder.addStackMaps(world, wovenClassFileData); - } - - WeaverStateInfo wsi = myType.getWeaverState();// getOrCreateWeaverStateInfo(); - if (wsi != null && wsi.isReweavable() && !world.isOverWeaving()) { // && !reweavableDataInserted - // reweavableDataInserted = true; - return wsi.replaceKeyWithDiff(wovenClassFileData); - } else { - return wovenClassFileData; - } - } - - public void addGeneratedInner(LazyClassGen newClass) { - classGens.add(newClass); - } - - public void addInterface(ResolvedType newInterface, ISourceLocation sourceLocation) { - regenerateGenericSignatureAttribute = true; - - if (extraSuperInterfaces == null) { - extraSuperInterfaces = new ResolvedType[1]; - extraSuperInterfaces[0] = newInterface; - } else { - ResolvedType[] x = new ResolvedType[extraSuperInterfaces.length + 1]; - System.arraycopy(extraSuperInterfaces, 0, x, 1, extraSuperInterfaces.length); - x[0] = newInterface; - extraSuperInterfaces = x; - } - myGen.addInterface(newInterface.getRawName()); - if (!newInterface.equals(UnresolvedType.SERIALIZABLE)) { - warnOnAddedInterface(newInterface.getName(), sourceLocation); - } - } - - public void setSuperClass(ResolvedType newSuperclass) { - regenerateGenericSignatureAttribute = true; - superclass = newSuperclass; - // myType.addParent(typeX); // used for the attribute - if (newSuperclass.getGenericType() != null) { - newSuperclass = newSuperclass.getGenericType(); - } - myGen.setSuperclassName(newSuperclass.getName()); // used in the real - // class data - } - - // public String getSuperClassname() { - // return myGen.getSuperclassName(); - // } - - public ResolvedType getSuperClass() { - if (superclass != null) { - return superclass; - } - return myType.getSuperclass(); - } - - public String[] getInterfaceNames() { - return myGen.getInterfaceNames(); - } - - // non-recursive, may be a bug, ha ha. - private List<LazyClassGen> getClassGens() { - List<LazyClassGen> ret = new ArrayList<LazyClassGen>(); - ret.add(this); - ret.addAll(classGens); - return ret; - } - - public List<UnwovenClassFile.ChildClass> getChildClasses(BcelWorld world) { - if (classGens.isEmpty()) { - return Collections.emptyList(); - } - List<UnwovenClassFile.ChildClass> ret = new ArrayList<UnwovenClassFile.ChildClass>(); - for (LazyClassGen clazz : classGens) { - byte[] bytes = clazz.getJavaClass(world).getBytes(); - String name = clazz.getName(); - int index = name.lastIndexOf('$'); - // XXX this could be bad, check use of dollar signs. - name = name.substring(index + 1); - ret.add(new UnwovenClassFile.ChildClass(name, bytes)); - } - return ret; - } - - @Override - public String toString() { - return toShortString(); - } - - public String toShortString() { - String s = org.aspectj.apache.bcel.classfile.Utility.accessToString(myGen.getModifiers(), true); - if (!s.equals("")) { - s += " "; - } - s += org.aspectj.apache.bcel.classfile.Utility.classOrInterface(myGen.getModifiers()); - s += " "; - s += myGen.getClassName(); - return s; - } - - public String toLongString() { - ByteArrayOutputStream s = new ByteArrayOutputStream(); - print(new PrintStream(s)); - return new String(s.toByteArray()); - } - - public void print() { - print(System.out); - } - - public void print(PrintStream out) { - List<LazyClassGen> classGens = getClassGens(); - for (Iterator<LazyClassGen> iter = classGens.iterator(); iter.hasNext();) { - LazyClassGen element = iter.next(); - element.printOne(out); - if (iter.hasNext()) { - out.println(); - } - } - } - - private void printOne(PrintStream out) { - out.print(toShortString()); - out.print(" extends "); - out.print(org.aspectj.apache.bcel.classfile.Utility.compactClassName(myGen.getSuperclassName(), false)); - - int size = myGen.getInterfaces().length; - - if (size > 0) { - out.print(" implements "); - for (int i = 0; i < size; i++) { - out.print(myGen.getInterfaceNames()[i]); - if (i < size - 1) { - out.print(", "); - } - } - } - out.print(":"); - out.println(); - // XXX make sure to pass types correctly around, so this doesn't happen. - if (myType != null) { - myType.printWackyStuff(out); - } - Field[] fields = myGen.getFields(); - for (int i = 0, len = fields.length; i < len; i++) { - out.print(" "); - out.println(fields[i]); - } - List<LazyMethodGen> methodGens = getMethodGens(); - for (Iterator<LazyMethodGen> iter = methodGens.iterator(); iter.hasNext();) { - LazyMethodGen gen = iter.next(); - // we skip empty clinits - if (isEmptyClinit(gen)) { - continue; - } - gen.print(out, (myType != null ? myType.getWeaverVersionAttribute() : WeaverVersionInfo.UNKNOWN)); - if (iter.hasNext()) { - out.println(); - } - } - // out.println(" ATTRIBS: " + Arrays.asList(myGen.getAttributes())); - - out.println("end " + toShortString()); - } - - private boolean isEmptyClinit(LazyMethodGen gen) { - - if (!gen.getName().equals("<clinit>")) { - return false; - } - // System.err.println("checking clinig: " + gen); - InstructionHandle start = gen.getBody().getStart(); - while (start != null) { - if (Range.isRangeHandle(start) || (start.getInstruction().opcode == Constants.RETURN)) { - start = start.getNext(); - } else { - return false; - } - } - - return true; - } - - public ConstantPool getConstantPool() { - return cp; - } - - public String getName() { - return myGen.getClassName(); - } - - public boolean isWoven() { - return myType.getWeaverState() != null; - } - - public boolean isReweavable() { - if (myType.getWeaverState() == null) { - return true; - } - return myType.getWeaverState().isReweavable(); - } - - public Set<String> getAspectsAffectingType() { - if (myType.getWeaverState() == null) { - return null; - } - return myType.getWeaverState().getAspectsAffectingType(); - } - - public WeaverStateInfo getOrCreateWeaverStateInfo(boolean inReweavableMode) { - WeaverStateInfo ret = myType.getWeaverState(); - if (ret != null) { - return ret; - } - ret = new WeaverStateInfo(inReweavableMode); - myType.setWeaverState(ret); - return ret; - } - - public InstructionFactory getFactory() { - return fact; - } - - public LazyMethodGen getStaticInitializer() { - for (LazyMethodGen gen : methodGens) { - // OPTIMIZE persist kind of member into the gen object? for clinit - if (gen.getName().equals("<clinit>")) { - return gen; - } - } - LazyMethodGen clinit = new LazyMethodGen(Modifier.STATIC, Type.VOID, "<clinit>", new Type[0], NO_STRINGS, this); - clinit.getBody().insert(InstructionConstants.RETURN); - methodGens.add(clinit); - 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() { - if (this.isInterface()) { - throw new IllegalStateException(); - } - for (LazyMethodGen methodGen : methodGens) { - if (methodGen.getName().equals(NameMangler.AJC_PRE_CLINIT_NAME)) { - return methodGen; - } - } - 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; - } - - /** - * factory method for building multiple extended clinit methods. Constructs a new clinit method that invokes the previous one - * and then returns it. The index is used as a name suffix. - * - * @param previousPreClinit - * @param i - */ - public LazyMethodGen createExtendedAjcPreClinit(LazyMethodGen previousPreClinit, int i) { - LazyMethodGen ajcPreClinit = new LazyMethodGen(Modifier.PRIVATE | Modifier.STATIC, Type.VOID, - NameMangler.AJC_PRE_CLINIT_NAME + i, Type.NO_ARGS, NO_STRINGS, this); - ajcPreClinit.getBody().insert(InstructionConstants.RETURN); - methodGens.add(ajcPreClinit); - previousPreClinit.getBody().insert(Utility.createInvoke(fact, ajcPreClinit)); - return ajcPreClinit; - } - - // - - // reflective thisJoinPoint support - private Map<BcelShadow, Field> tjpFields = new HashMap<BcelShadow, Field>(); - Map<CacheKey, Field> annotationCachingFieldCache = new HashMap<CacheKey, Field>(); - private int tjpFieldsCounter = -1; // -1 means not yet initialized - private int annoFieldsCounter = 0; - public static final ObjectType proceedingTjpType = new ObjectType("org.aspectj.lang.ProceedingJoinPoint"); - public static final ObjectType tjpType = new ObjectType("org.aspectj.lang.JoinPoint"); - public static final ObjectType staticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$StaticPart"); - public static final ObjectType typeForAnnotation = new ObjectType("java.lang.annotation.Annotation"); - public static final ObjectType enclosingStaticTjpType = new ObjectType("org.aspectj.lang.JoinPoint$EnclosingStaticPart"); - private static final ObjectType sigType = new ObjectType("org.aspectj.lang.Signature"); - // private static final ObjectType slType = - // new ObjectType("org.aspectj.lang.reflect.SourceLocation"); - private static final ObjectType factoryType = new ObjectType("org.aspectj.runtime.reflect.Factory"); - private static final ObjectType classType = new ObjectType("java.lang.Class"); - - public Field getTjpField(BcelShadow shadow, final boolean isEnclosingJp) { - Field tjpField = tjpFields.get(shadow); - if (tjpField != null) { - return tjpField; - } - - int modifiers = Modifier.STATIC; - - // J9: Can't always be final on Java 9 because it is set outside of clinit - // But must be final in interface - if (shadow.getEnclosingClass().isInterface()) { - modifiers |= Modifier.FINAL; - } - - // XXX - Do we ever inline before or after advice? If we do, then we - // better include them in the check below. (or just change it to - // shadow.getEnclosingMethod().getCanInline()) - - // If the enclosing method is around advice, we could inline the join - // point that has led to this shadow. If we do that then the TJP we are - // creating here must be PUBLIC so it is visible to the type in which the - // advice is inlined. (PR71377) - LazyMethodGen encMethod = shadow.getEnclosingMethod(); - boolean shadowIsInAroundAdvice = false; - if (encMethod != null && encMethod.getName().startsWith(NameMangler.PREFIX + "around")) { - shadowIsInAroundAdvice = true; - } - - if (getType().isInterface() || shadowIsInAroundAdvice) { - modifiers |= Modifier.PUBLIC; - } else { - modifiers |= Modifier.PRIVATE; - } - ObjectType jpType = null; - // Did not have different static joinpoint types in 1.2 - if (world.isTargettingAspectJRuntime12()) { - jpType = staticTjpType; - } else { - jpType = isEnclosingJp ? enclosingStaticTjpType : staticTjpType; - } - if (tjpFieldsCounter == -1) { - // not yet initialized, do it now - if (!world.isOverWeaving()) { - tjpFieldsCounter = 0; - } else { - List<BcelField> existingFields = getFieldGens(); - if (existingFields == null) { - tjpFieldsCounter = 0; - } else { - BcelField lastField = null; - // OPTIMIZE: go from last to first? - for (BcelField field : existingFields) { - if (field.getName().startsWith("ajc$tjp_")) { - lastField = field; - } - } - if (lastField == null) { - tjpFieldsCounter = 0; - } else { - tjpFieldsCounter = Integer.parseInt(lastField.getName().substring(8)) + 1; - // System.out.println("tjp counter starting at " + tjpFieldsCounter); - } - } - } - } - if (!isInterface() && world.isTransientTjpFields()) { - modifiers|=Modifier.TRANSIENT; - } - FieldGen fGen = new FieldGen(modifiers, jpType, "ajc$tjp_" + tjpFieldsCounter++, getConstantPool()); - addField(fGen); - tjpField = fGen.getField(); - tjpFields.put(shadow, tjpField); - return tjpField; - } - - /** - * Create a field in the type containing the shadow where the annotation retrieved during binding can be stored - for later fast - * access. - * - * @param shadow the shadow at which the @annotation result is being cached - * @return a field - */ - public Field getAnnotationCachingField(BcelShadow shadow, ResolvedType toType, boolean isWithin) { - // Multiple annotation types at a shadow. A different field would be required for each - CacheKey cacheKey = new CacheKey(shadow, toType, isWithin); - Field field = annotationCachingFieldCache.get(cacheKey); - // System.out.println(field + " for shadow " + shadow); - if (field == null) { - // private static Annotation ajc$anno$<nnn> - StringBuilder sb = new StringBuilder(); - sb.append(NameMangler.ANNOTATION_CACHE_FIELD_NAME); - sb.append(annoFieldsCounter++); - FieldGen annotationCacheField = new FieldGen(Modifier.PRIVATE | Modifier.STATIC, typeForAnnotation, sb.toString(), cp); - addField(annotationCacheField); - field = annotationCacheField.getField(); - annotationCachingFieldCache.put(cacheKey, field); - } - return field; - } - - static class CacheKey { - private Object key; - private ResolvedType annotationType; - - // If the annotation is being accessed via @annotation on a shadow then we can use the shadows toString() (so two shadows - // the same share a variable), but if it is @withincode() or @within() we can't share them (as the shadows may look the same - // but be occurring 'within' different things). In the within cases we continue to use the shadow itself as the key. - CacheKey(BcelShadow shadow, ResolvedType annotationType, boolean isWithin) { - this.key = isWithin ? shadow : shadow.toString(); - this.annotationType = annotationType; - } - - @Override - public int hashCode() { - return key.hashCode() * 37 + annotationType.hashCode(); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof CacheKey)) { - return false; - } - CacheKey oCacheKey = (CacheKey) other; - return key.equals(oCacheKey.key) && annotationType.equals(oCacheKey.annotationType); - } - } - - // FIXME ATAJ needed only for slow Aspects.aspectOf - keep or remove - // private void addAjClassField() { - // // Andy: Why build it again?? - // Field ajClassField = new FieldGen( - // Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC, - // classType, - // "aj$class", - // getConstantPool()).getField(); - // addField(ajClassField); - // - // InstructionList il = new InstructionList(); - // il.append(new PUSH(getConstantPool(), getClassName())); - // il.append(fact.createInvoke("java.lang.Class", "forName", classType, - // new Type[] {Type.STRING}, Constants.INVOKESTATIC)); - // il.append(fact.createFieldAccess(getClassName(), ajClassField.getName(), - // classType, Constants.PUTSTATIC)); - // - // getStaticInitializer().getBody().insert(il); - // } - - private void addAjcInitializers() { - if (tjpFields.size() == 0 && !serialVersionUIDRequiresInitialization) { - return; - } - InstructionList[] il = null; - - if (tjpFields.size() > 0) { - il = initializeAllTjps(); - } - - if (serialVersionUIDRequiresInitialization) { - InstructionList[] ilSVUID = new InstructionList[1]; - ilSVUID[0] = new InstructionList(); - ilSVUID[0].append(InstructionFactory.PUSH(getConstantPool(), calculatedSerialVersionUID)); - ilSVUID[0].append(getFactory().createFieldAccess(getClassName(), "serialVersionUID", BasicType.LONG, - Constants.PUTSTATIC)); - if (il == null) { - il = ilSVUID; - } else { - InstructionList[] newIl = new InstructionList[il.length + ilSVUID.length]; - System.arraycopy(il, 0, newIl, 0, il.length); - System.arraycopy(ilSVUID, 0, newIl, il.length, ilSVUID.length); - il = newIl; - } - } - - LazyMethodGen prevMethod; - LazyMethodGen nextMethod = null; - if (this.isInterface()) { // Cannot sneak stuff into another static method in an interface - prevMethod = getStaticInitializer(); - } else { - prevMethod = getAjcPreClinit(); - } - for (int counter = 1; counter <= il.length; counter++) { - if (il.length > counter) { - nextMethod = createExtendedAjcPreClinit(prevMethod, counter); - } - prevMethod.getBody().insert(il[counter - 1]); - prevMethod = nextMethod; - } - } - - private InstructionList initInstructionList() { - InstructionList list = new InstructionList(); - InstructionFactory fact = getFactory(); - - // make a new factory - list.append(fact.createNew(factoryType)); - list.append(InstructionFactory.createDup(1)); - - list.append(InstructionFactory.PUSH(getConstantPool(), getFileName())); - - // load the current Class object - // XXX check that this works correctly for inners/anonymous - list.append(fact.PUSHCLASS(cp, myGen.getClassName())); - // XXX do we need to worry about the fact the theorectically this could - // throw - // a ClassNotFoundException - - list.append(fact.createInvoke(factoryType.getClassName(), "<init>", Type.VOID, new Type[] { Type.STRING, classType }, - Constants.INVOKESPECIAL)); - - list.append(InstructionFactory.createStore(factoryType, 0)); - return list; - } - - private InstructionList[] initializeAllTjps() { - Vector<InstructionList> lists = new Vector<InstructionList>(); - - InstructionList list = initInstructionList(); - lists.add(list); - - List<Map.Entry<BcelShadow, Field>> entries = new ArrayList<Map.Entry<BcelShadow, Field>>(tjpFields.entrySet()); - Collections.sort(entries, new Comparator<Map.Entry<BcelShadow, Field>>() { - @Override - public int compare(Map.Entry<BcelShadow, Field> a, Map.Entry<BcelShadow, Field> b) { - return (a.getValue()).getName().compareTo((b.getValue()).getName()); - } - }); - - long estimatedSize = 0; - for (Iterator<Map.Entry<BcelShadow, Field>> i = entries.iterator(); i.hasNext();) { - Map.Entry<BcelShadow, Field> entry = i.next(); - if (estimatedSize > Constants.MAX_CODE_SIZE) { - estimatedSize = 0; - list = initInstructionList(); - lists.add(list); - } - estimatedSize += entry.getValue().getSignature().getBytes().length; - initializeTjp(fact, list, entry.getValue(), entry.getKey()); - } - InstructionList listArrayModel[] = new InstructionList[1]; - return lists.toArray(listArrayModel); - } - - private void initializeTjp(InstructionFactory fact, InstructionList list, Field field, BcelShadow shadow) { - if (world.getTargetAspectjRuntimeLevel() == RuntimeVersion.V1_9) { - initializeTjpOptimal(fact, list, field, shadow); - return; - } - boolean fastSJP = false; - // avoid fast SJP if it is for an enclosing joinpoint - boolean isFastSJPAvailable = shadow.getWorld().isTargettingRuntime1_6_10() - && !enclosingStaticTjpType.equals(field.getType()); - - Member sig = shadow.getSignature(); - - // load the factory - list.append(InstructionFactory.createLoad(factoryType, 0)); - - // load the kind - list.append(InstructionFactory.PUSH(getConstantPool(), shadow.getKind().getName())); - - // create the signature - if (world.isTargettingAspectJRuntime12() || !isFastSJPAvailable || !sig.getKind().equals(Member.METHOD)) { - list.append(InstructionFactory.createLoad(factoryType, 0)); - } - - String signatureMakerName = SignatureUtils.getSignatureMakerName(sig); - ObjectType signatureType = new ObjectType(SignatureUtils.getSignatureType(sig)); - UnresolvedType[] exceptionTypes = null; - if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have optimized factory methods in 1.2 - list.append(InstructionFactory.PUSH(cp, SignatureUtils.getSignatureString(sig, shadow.getWorld()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1, - Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.METHOD)) { - BcelWorld w = shadow.getWorld(); - - // For methods, push the parts of the signature on. - list.append(InstructionFactory.PUSH(cp, makeString(sig.getModifiers(w)))); - list.append(InstructionFactory.PUSH(cp, sig.getName())); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterTypes()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterNames(w)))); - exceptionTypes = sig.getExceptions(w); - if (isFastSJPAvailable && exceptionTypes.length == 0) { - fastSJP = true; - } else { - list.append(InstructionFactory.PUSH(cp, makeString(exceptionTypes))); - } - list.append(InstructionFactory.PUSH(cp, makeString(sig.getReturnType()))); - // And generate a call to the variant of makeMethodSig() that takes the strings - if (isFastSJPAvailable) { - fastSJP = true; - } else { - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY7, - Constants.INVOKEVIRTUAL)); - } - - } else if (sig.getKind().equals(Member.MONITORENTER)) { - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1, - Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.MONITOREXIT)) { - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1, - Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.HANDLER)) { - BcelWorld w = shadow.getWorld(); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterTypes()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterNames(w)))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY3, - Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.CONSTRUCTOR)) { - BcelWorld w = shadow.getWorld(); - if (w.isJoinpointArrayConstructionEnabled() && sig.getDeclaringType().isArray()) { - // its the magical new jp - list.append(InstructionFactory.PUSH(cp, makeString(Modifier.PUBLIC))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterTypes()))); - list.append(InstructionFactory.PUSH(cp, "")); // sig.getParameterNames? - list.append(InstructionFactory.PUSH(cp, ""));// sig.getExceptions? - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY5, - Constants.INVOKEVIRTUAL)); - } else { - list.append(InstructionFactory.PUSH(cp, makeString(sig.getModifiers(w)))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterTypes()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterNames(w)))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getExceptions(w)))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY5, - Constants.INVOKEVIRTUAL)); - } - } else if (sig.getKind().equals(Member.FIELD)) { - BcelWorld w = shadow.getWorld(); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getModifiers(w)))); - list.append(InstructionFactory.PUSH(cp, sig.getName())); - // see pr227401 - UnresolvedType dType = sig.getDeclaringType(); - if (dType.getTypekind() == TypeKind.PARAMETERIZED || dType.getTypekind() == TypeKind.GENERIC) { - dType = sig.getDeclaringType().resolve(world).getGenericType(); - } - list.append(InstructionFactory.PUSH(cp, makeString(dType))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getReturnType()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY4, - Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.ADVICE)) { - BcelWorld w = shadow.getWorld(); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getModifiers(w)))); - list.append(InstructionFactory.PUSH(cp, sig.getName())); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterTypes()))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getParameterNames(w)))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getExceptions(w)))); - list.append(InstructionFactory.PUSH(cp, makeString((sig.getReturnType())))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, new Type[] { Type.STRING, - Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING, Type.STRING }, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.STATIC_INITIALIZATION)) { - BcelWorld w = shadow.getWorld(); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getModifiers(w)))); - list.append(InstructionFactory.PUSH(cp, makeString(sig.getDeclaringType()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY2, - Constants.INVOKEVIRTUAL)); - } else { - // TODO looks like this block is unused code - list.append(InstructionFactory.PUSH(cp, SignatureUtils.getSignatureString(sig, shadow.getWorld()))); - list.append(fact.createInvoke(factoryType.getClassName(), signatureMakerName, signatureType, Type.STRINGARRAY1, - Constants.INVOKEVIRTUAL)); - } - - // XXX should load source location from shadow - list.append(Utility.createConstant(fact, shadow.getSourceLine())); - - final String factoryMethod; - - // TAG:SUPPORTING12: We didn't have makeESJP() in 1.2 - if (world.isTargettingAspectJRuntime12()) { - list.append(fact.createInvoke(factoryType.getClassName(), "makeSJP", staticTjpType, new Type[] { Type.STRING, sigType, - Type.INT }, Constants.INVOKEVIRTUAL)); - - // put it in the field - list.append(fact.createFieldAccess(getClassName(), field.getName(), staticTjpType, Constants.PUTSTATIC)); - - } else { - if (staticTjpType.equals(field.getType())) { - factoryMethod = "makeSJP"; - } else if (enclosingStaticTjpType.equals(field.getType())) { - factoryMethod = "makeESJP"; - } else { - throw new Error("should not happen"); - } - - if (fastSJP) { - if (exceptionTypes != null && exceptionTypes.length != 0) { - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), ARRAY_8STRING_INT, - Constants.INVOKEVIRTUAL)); - } else { - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), ARRAY_7STRING_INT, - Constants.INVOKEVIRTUAL)); - } - } else { - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), new Type[] { Type.STRING, - sigType, Type.INT }, Constants.INVOKEVIRTUAL)); - } - - // put it in the field - list.append(fact.createFieldAccess(getClassName(), field.getName(), field.getType(), Constants.PUTSTATIC)); - } - } - - public String getFactoryMethod(Field field, BcelShadow shadow) { - StringBuilder b = new StringBuilder(); - b.append("make"); - MemberKind kind = shadow.getSignature().getKind(); - if (kind.equals(Member.METHOD)) { - b.append("Method"); - } else if (kind.equals(Member.CONSTRUCTOR)) { - b.append("Constructor"); - } else if (kind.equals(Member.HANDLER)) { - b.append("CatchClause"); - } else if (kind.equals(Member.FIELD)) { - b.append("Field"); - } else if (kind.equals(Member.STATIC_INITIALIZATION)) { - b.append("Initializer"); - } else if (kind.equals(Member.MONITORENTER)) { - b.append("Lock"); - } else if (kind.equals(Member.MONITOREXIT)) { - b.append("Unlock"); - } else if (kind.equals(Member.ADVICE)) { - b.append("Advice"); - } else { - throw new IllegalStateException(kind.toString()); - } - if (staticTjpType.equals(field.getType())) { - b.append("SJP"); - } else if (enclosingStaticTjpType.equals(field.getType())) { - b.append("ESJP"); - } - return b.toString(); - } - - /** - * Generate optimal joinpoint initialization code. - * - * As of version 1.9.1 the runtime includes new factory methods for joinpoints that take classes, not strings - * and using them requires different code generation. Using these instead of the old ones means we can avoid - * deferred classloading for these types. By using the LDC instruction that loads classes, it also means - * anything modifying woven code and changing type names will also pick up on these references. - */ - private void initializeTjpOptimal(InstructionFactory fact, InstructionList list, Field field, BcelShadow shadow) { - list.append(InstructionFactory.createLoad(factoryType, 0)); - pushString(list, shadow.getKind().getName()); - String factoryMethod = getFactoryMethod(field, shadow); - Member sig = shadow.getSignature(); - BcelWorld w = shadow.getWorld(); - - if (sig.getKind().equals(Member.METHOD)) { - pushInt(list, sig.getModifiers(w)); - pushString(list, sig.getName()); - pushClass(list, sig.getDeclaringType()); - pushClasses(list, sig.getParameterTypes()); - pushStrings(list, sig.getParameterNames(w)); - pushClasses(list, sig.getExceptions(w)); - pushClass(list, sig.getReturnType()); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_METHOD, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.CONSTRUCTOR)) { - if (w.isJoinpointArrayConstructionEnabled() && sig.getDeclaringType().isArray()) { - pushInt(list, Modifier.PUBLIC); - pushClass(list, sig.getDeclaringType()); - pushClasses(list, sig.getParameterTypes()); - pushStrings(list, null); - pushClasses(list, null); - } else { - pushInt(list, sig.getModifiers(w)); - pushClass(list, sig.getDeclaringType()); - pushClasses(list, sig.getParameterTypes()); - pushStrings(list, sig.getParameterNames(w)); - pushClasses(list, sig.getExceptions(w)); - } - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_CONSTRUCTOR, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.HANDLER)) { - pushClass(list, sig.getDeclaringType()); - pushClass(list, sig.getParameterTypes()[0]); - String pname = null; - String[] pnames = sig.getParameterNames(w); - if (pnames != null && pnames.length>0) { - pname = pnames[0]; - } - pushString(list, pname); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_CATCHCLAUSE, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.FIELD)) { - pushInt(list, sig.getModifiers(w)); - pushString(list, sig.getName()); - // see pr227401 - UnresolvedType dType = sig.getDeclaringType(); - if (dType.getTypekind() == TypeKind.PARAMETERIZED || dType.getTypekind() == TypeKind.GENERIC) { - dType = sig.getDeclaringType().resolve(world).getGenericType(); - } - pushClass(list, dType); - pushClass(list, sig.getReturnType()); - pushInt(list,shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_FIELD, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.STATIC_INITIALIZATION)) { - pushInt(list, sig.getModifiers(w)); - pushClass(list, sig.getDeclaringType()); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_INITIALIZER, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.MONITORENTER)) { - pushClass(list, sig.getDeclaringType()); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_MONITOR, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.MONITOREXIT)) { - pushClass(list, sig.getDeclaringType()); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_MONITOR, Constants.INVOKEVIRTUAL)); - } else if (sig.getKind().equals(Member.ADVICE)) { - pushInt(list, sig.getModifiers(w)); - pushString(list, sig.getName()); - pushClass(list, sig.getDeclaringType()); - pushClasses(list, sig.getParameterTypes()); - pushStrings(list, sig.getParameterNames(w)); - pushClasses(list, sig.getExceptions(w)); - pushClass(list, sig.getReturnType()); - pushInt(list, shadow.getSourceLine()); - list.append(fact.createInvoke(factoryType.getClassName(), factoryMethod, field.getType(), - PARAMSIGNATURE_MAKESJP_ADVICE, Constants.INVOKEVIRTUAL)); - } else { - throw new IllegalStateException("not sure what to do: "+shadow); - } - list.append(fact.createFieldAccess(getClassName(), field.getName(), field.getType(), Constants.PUTSTATIC)); - } - - private void pushStrings(InstructionList list, String[] strings) { - // Build an array loaded with the strings - if (strings == null || strings.length == 0) { - list.append(InstructionFactory.ACONST_NULL); - } else { - list.append(InstructionFactory.PUSH(cp, strings.length)); - list.append(fact.createNewArray(Type.STRING, (short)1)); - for (int s=0;s<strings.length;s++) { - list.append(InstructionFactory.DUP); - list.append(InstructionFactory.PUSH(cp, s)); - list.append(InstructionFactory.PUSH(cp, strings[s])); - list.append(InstructionFactory.AASTORE); - } - } - } - - private void pushClass(InstructionList list, UnresolvedType type) { - if (type.isPrimitiveType()) { - if (type.getSignature().equals("I")) { - list.append(fact.createGetStatic("java/lang/Integer","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("D")) { - list.append(fact.createGetStatic("java/lang/Double","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("S")) { - list.append(fact.createGetStatic("java/lang/Short","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("J")) { - list.append(fact.createGetStatic("java/lang/Long","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("F")) { - list.append(fact.createGetStatic("java/lang/Float","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("C")) { - list.append(fact.createGetStatic("java/lang/Character","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("B")) { - list.append(fact.createGetStatic("java/lang/Byte","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("Z")) { - list.append(fact.createGetStatic("java/lang/Boolean","TYPE", Type.CLASS)); - } else if (type.getSignature().equals("V")) { - list.append(InstructionFactory.ACONST_NULL); - } - return; - } - String classString = makeLdcClassString(type); - if (classString == null) { - list.append(InstructionFactory.ACONST_NULL); - } else { - list.append(fact.PUSHCLASS(cp, classString)); - } - } - - private void pushClasses(InstructionList list, UnresolvedType[] types) { - // Build an array loaded with the class objects - if (types == null || types.length == 0) { - list.append(InstructionFactory.ACONST_NULL); - } else { - list.append(InstructionFactory.PUSH(cp, types.length)); - list.append(fact.createNewArray(Type.CLASS, (short)1)); - for (int t=0;t<types.length;t++) { - list.append(InstructionFactory.DUP); - list.append(InstructionFactory.PUSH(cp, t)); - pushClass(list, types[t]); - list.append(InstructionFactory.AASTORE); - } - } - } - - private final void pushString(InstructionList list, String string) { - list.append(InstructionFactory.PUSH(cp, string)); - } - - private final void pushInt(InstructionList list, int value) { - list.append(InstructionFactory.PUSH(cp, value)); - } - - protected String makeString(int i) { - return Integer.toString(i, 16); // ??? expensive - } - - protected String makeString(UnresolvedType t) { - // this is the inverse of the odd behavior for Class.forName w/ arrays - if (t.isArray()) { - // this behavior matches the string used by the eclipse compiler for - // Foo.class literals - return t.getSignature().replace('/', '.'); - } else { - if (t.isParameterizedType()) { - return t.getRawType().getName(); - } else { - return t.getName(); - } - } - } - - protected String makeLdcClassString(UnresolvedType type) { - if (type.isVoid() || type.isPrimitiveType()) { - return null; - } - if (type.isArray()) { - return type.getSignature(); - } else { - if (type.isParameterizedType()) { - type = type.getRawType(); - } - String signature = type.getSignature(); - if (signature.length() ==1 ) { - return signature; - } - return signature.substring(1,signature.length()-1); - } - } - - protected String makeString(UnresolvedType[] types) { - if (types == null) { - return ""; - } - StringBuilder buf = new StringBuilder(); - for (int i = 0, len = types.length; i < len; i++) { - if (i > 0) { - buf.append(':'); - } - buf.append(makeString(types[i])); - } - return buf.toString(); - } - - protected String makeString(String[] names) { - if (names == null) { - return ""; - } - StringBuilder buf = new StringBuilder(); - for (int i = 0, len = names.length; i < len; i++) { - if (i > 0) { - buf.append(':'); - } - buf.append(names[i]); - } - return buf.toString(); - } - - public ResolvedType getType() { - if (myType == null) { - return null; - } - return myType.getResolvedTypeX(); - } - - public BcelObjectType getBcelObjectType() { - return myType; - } - - public String getFileName() { - return myGen.getFileName(); - } - - // for *new* fields - private void addField(FieldGen field) { - makeSyntheticAndTransientIfNeeded(field); - BcelField bcelField = null; - if (getBcelObjectType() != null) { - bcelField = new BcelField(getBcelObjectType(), field.getField()); - } else { - bcelField = new BcelField(getName(), field.getField(), world); - } - fields.add(bcelField); - // myGen.addField(field.getField()); - } - - private void makeSyntheticAndTransientIfNeeded(FieldGen field) { - if (field.getName().startsWith(NameMangler.PREFIX) && !field.getName().startsWith("ajc$interField$") - && !field.getName().startsWith("ajc$instance$")) { - // it's an aj added field - // first do transient - if (!field.isStatic()) { - field.setModifiers(field.getModifiers() | Constants.ACC_TRANSIENT); - } - // then do synthetic - if (getWorld().isInJava5Mode()) { - // add the synthetic modifier flag - field.setModifiers(field.getModifiers() | ACC_SYNTHETIC); - } - if (!hasSyntheticAttribute(field.getAttributes())) { - // belt and braces, do the attribute even on Java 5 in addition - // to the modifier flag - // Attribute[] oldAttrs = field.getAttributes(); - // Attribute[] newAttrs = new Attribute[oldAttrs.length + 1]; - // System.arraycopy(oldAttrs, 0, newAttrs, 0, oldAttrs.length); - ConstantPool cpg = myGen.getConstantPool(); - int index = cpg.addUtf8("Synthetic"); - Attribute synthetic = new Synthetic(index, 0, new byte[0], cpg); - field.addAttribute(synthetic); - // newAttrs[newAttrs.length - 1] = synthetic; - // field.setAttributes(newAttrs); - } - } - } - - private boolean hasSyntheticAttribute(List<Attribute> attributes) { - for (int i = 0; i < attributes.size(); i++) { - if ((attributes.get(i)).getName().equals("Synthetic")) { - return true; - } - } - return false; - } - - public void addField(FieldGen field, ISourceLocation sourceLocation) { - addField(field); - if (!(field.isPrivate() && (field.isStatic() || field.isTransient()))) { - errorOnAddedField(field, sourceLocation); - } - } - - public String getClassName() { - return myGen.getClassName(); - } - - public boolean isInterface() { - return myGen.isInterface(); - } - - public boolean isAbstract() { - return myGen.isAbstract(); - } - - public LazyMethodGen getLazyMethodGen(Member m) { - return getLazyMethodGen(m.getName(), m.getSignature(), false); - } - - public LazyMethodGen getLazyMethodGen(String name, String signature) { - return getLazyMethodGen(name, signature, false); - } - - public LazyMethodGen getLazyMethodGen(String name, String signature, boolean allowMissing) { - for (LazyMethodGen gen : methodGens) { - if (gen.getName().equals(name) && gen.getSignature().equals(signature)) { - return gen; - } - } - - if (!allowMissing) { - throw new BCException("Class " + this.getName() + " does not have a method " + name + " with signature " + signature); - } - - return null; - } - - public void forcePublic() { - myGen.setModifiers(Utility.makePublic(myGen.getModifiers())); - } - - public boolean hasAnnotation(UnresolvedType t) { - - // annotations on the real thing - AnnotationGen agens[] = myGen.getAnnotations(); - if (agens == null) { - return false; - } - for (int i = 0; i < agens.length; i++) { - AnnotationGen gen = agens[i]; - if (t.equals(UnresolvedType.forSignature(gen.getTypeSignature()))) { - return true; - } - } - - // annotations added during this weave - - return false; - } - - public void addAnnotation(AnnotationGen a) { - if (!hasAnnotation(UnresolvedType.forSignature(a.getTypeSignature()))) { - annotations.add(new AnnotationGen(a, getConstantPool(), true)); - } - } - - public void addAttribute(AjAttribute attribute) { - myGen.addAttribute(Utility.bcelAttribute(attribute, getConstantPool())); - } - - public void addAttribute(Attribute attribute) { - myGen.addAttribute(attribute); - } - - public Collection<Attribute> getAttributes() { - return myGen.getAttributes(); - } - - // this test is like asking: - // if - // (UnresolvedType.SERIALIZABLE.resolve(getType().getWorld()).isAssignableFrom - // (getType())) { - // only we don't do that because this forces us to find all the supertypes - // of the type, - // and if one of them is missing we fail, and it's not worth failing just to - // put out - // a warning message! - private boolean implementsSerializable(ResolvedType aType) { - if (aType.getSignature().equals(UnresolvedType.SERIALIZABLE.getSignature())) { - return true; - } - - ResolvedType[] interfaces = aType.getDeclaredInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - if (interfaces[i].isMissing()) { - continue; - } - if (implementsSerializable(interfaces[i])) { - return true; - } - } - ResolvedType superType = aType.getSuperclass(); - if (superType != null && !superType.isMissing()) { - return implementsSerializable(superType); - } - return false; - } - - public boolean isAtLeastJava5() { - return (myGen.getMajor() >= Constants.MAJOR_1_5); - } - - /** - * Return the next available field name with the specified 'prefix', e.g. for prefix 'class$' where class$0, class$1 exist then - * return class$2 - */ - public String allocateField(String prefix) { - int highestAllocated = -1; - List<BcelField> fs = getFieldGens(); - for (BcelField field : fs) { - if (field.getName().startsWith(prefix)) { - try { - int num = Integer.parseInt(field.getName().substring(prefix.length())); - if (num > highestAllocated) { - highestAllocated = num; - } - } catch (NumberFormatException nfe) { - // something wrong with the number on the end of that - // field... - } - } - } - return prefix + Integer.toString(highestAllocated + 1); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java deleted file mode 100644 index 2655a3456..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ /dev/null @@ -1,1870 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Set; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.Method; -import org.aspectj.apache.bcel.classfile.Synthetic; -import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen; -import org.aspectj.apache.bcel.generic.BranchHandle; -import org.aspectj.apache.bcel.generic.ClassGenException; -import org.aspectj.apache.bcel.generic.CodeExceptionGen; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionSelect; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.apache.bcel.generic.LineNumberTag; -import org.aspectj.apache.bcel.generic.LocalVariableTag; -import org.aspectj.apache.bcel.generic.MethodGen; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Tag; -import org.aspectj.apache.bcel.generic.TargetLostException; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.MemberImpl; -import org.aspectj.weaver.NameMangler; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.WeaverMessages; -import org.aspectj.weaver.World; -import org.aspectj.weaver.tools.Traceable; - -/** - * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the low-level Method objects. It converts - * through {@link MethodGen} to create and to serialize, but that's it. - * - * <p> - * At any rate, there are two ways to create LazyMethodGens. One is from a method, which does work through MethodGen to do the - * correct thing. The other is the creation of a completely empty LazyMethodGen, and it is used when we're constructing code from - * scratch. - * - * <p> - * We stay away from targeters for rangey things like Shadows and Exceptions. - */ -public final class LazyMethodGen implements Traceable { - - private static final AnnotationAJ[] NO_ANNOTATIONAJ = new AnnotationAJ[] {}; - - private int modifiers; - private Type returnType; - private final String name; - private Type[] argumentTypes; - // private final String[] argumentNames; - private String[] declaredExceptions; - private InstructionList body; - private List<Attribute> attributes; - private List<AnnotationAJ> newAnnotations; - private List<ResolvedType> annotationsForRemoval; - private AnnotationAJ[][] newParameterAnnotations; - private final LazyClassGen enclosingClass; - private BcelMethod memberView; - private AjAttribute.EffectiveSignatureAttribute effectiveSignature; - int highestLineNumber = 0; - boolean wasPackedOptimally = false; - private Method savedMethod = null; - - // Some tools that may post process the output bytecode do not long local variable tables - // to be generated as one reason the tables may be missing in the first place is because - // the bytecode is odd. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=470658 - private final boolean originalMethodHasLocalVariableTable; - - /* - * We use LineNumberTags and not Gens. - * - * This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens or if we make it create - * LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created Gens - then on return from the MethodGen ctor we took - * them apart, reprocessed them all and created Tags. (see unpackLocals/unpackLineNumbers). As we have our own copy of Bcel, why - * not create the right thing straightaway? So setting this to true will call the MethodGen ctor() in such a way that it creates - * Tags - removing the need for unpackLocals/unpackLineNumbers - HOWEVER see the ensureAllLineNumberSetup() method for some - * other relevant info. - * - * Whats the difference between a Tag and a Gen? A Tag is more lightweight, it doesn't know which instructions it targets, it - * relies on the instructions targettingit - this reduces the amount of targeter manipulation we have to do. - */ - - /** - * This is nonnull if this method is the result of an "inlining". We currently copy methods into other classes for around - * advice. We add this field so we can get JSR45 information correct. If/when we do _actual_ inlining, we'll need to subtype - * LineNumberTag to have external line numbers. - */ - String fromFilename = null; - private int maxLocals; - private boolean canInline = true; - private boolean isSynthetic = false; - List<BcelShadow> matchedShadows; - // Used for interface introduction - this is the type of the interface the method is technically on - public ResolvedType definingType = null; - - static class LightweightBcelMethod extends BcelMethod { - - LightweightBcelMethod(BcelObjectType declaringType, Method method) { - super(declaringType, method); - // TODO Auto-generated constructor stub - } - - } - - public LazyMethodGen(int modifiers, Type returnType, String name, Type[] paramTypes, String[] declaredExceptions, - LazyClassGen enclosingClass) { - // enclosingClass.getName() + ", " + returnType); - this.memberView = null; // should be okay, since constructed ones aren't woven into - this.modifiers = modifiers; - this.returnType = returnType; - this.name = name; - this.argumentTypes = paramTypes; - // this.argumentNames = Utility.makeArgNames(paramTypes.length); - this.declaredExceptions = declaredExceptions; - if (!Modifier.isAbstract(modifiers)) { - body = new InstructionList(); - setMaxLocals(calculateMaxLocals()); - } else { - body = null; - } - this.attributes = new ArrayList<Attribute>(); - this.enclosingClass = enclosingClass; - assertGoodBody(); - this.originalMethodHasLocalVariableTable = true; // it is a new method, we want an lvar table - - // @AJ advice are not inlined by default since requires further analysis and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects are reweavable - // since the inlined version with wrappers and an to be done annotation to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - // TODO we could check for @Around advice as well - this.canInline = false; - } - } - } - - private int calculateMaxLocals() { - int ret = Modifier.isStatic(modifiers) ? 0 : 1; // will there be a 'this'? - for (Type type : argumentTypes) { - ret += type.getSize(); - } - return ret; - } - - // build from an existing method, lazy build saves most work for - // initialization - public LazyMethodGen(Method m, LazyClassGen enclosingClass) { - savedMethod = m; - - this.enclosingClass = enclosingClass; - if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) { - throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); - } - if ((m.isAbstract() || m.isNative()) && m.getCode() != null) { - throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); - } - this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); - this.originalMethodHasLocalVariableTable = savedMethod.getLocalVariableTable()!=null; - this.modifiers = m.getModifiers(); - this.name = m.getName(); - - // @AJ advice are not inlined by default since requires further analysis - // and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects - // are reweavable - // since the inlined version with wrappers and an to be done annotation - // to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - // TODO we could check for @Around advice as well - this.canInline = false; - } - } - } - - private boolean isAbstractOrNative(int modifiers) { - return Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers); - } - - public LazyMethodGen(BcelMethod m, LazyClassGen enclosingClass) { - savedMethod = m.getMethod(); - this.enclosingClass = enclosingClass; - if (!isAbstractOrNative(m.getModifiers()) && savedMethod.getCode() == null) { - throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); - } - if (isAbstractOrNative(m.getModifiers()) && savedMethod.getCode() != null) { - throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); - } - // this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), - // m); - this.memberView = m; - this.modifiers = savedMethod.getModifiers(); - this.name = m.getName(); - this.originalMethodHasLocalVariableTable = savedMethod.getLocalVariableTable() != null; - // @AJ advice are not inlined by default since requires further analysis - // and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects - // are reweavable - // since the inlined version with wrappers and an to be done annotation - // to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - // TODO we could check for @Around advice as well - this.canInline = false; - } - } - - } - - public boolean hasDeclaredLineNumberInfo() { - return (memberView != null && memberView.hasDeclarationLineNumberInfo()); - } - - public int getDeclarationLineNumber() { - if (hasDeclaredLineNumberInfo()) { - return memberView.getDeclarationLineNumber(); - } else { - return -1; - } - } - - public int getDeclarationOffset() { - if (hasDeclaredLineNumberInfo()) { - return memberView.getDeclarationOffset(); - } else { - return 0; - } - } - - public void addAnnotation(AnnotationAJ ax) { - initialize(); - if (memberView == null) { - // If member view is null, we manage them in newAnnotations - if (newAnnotations == null) { - newAnnotations = new ArrayList<AnnotationAJ>(); - } - newAnnotations.add(ax); - } else { - memberView.addAnnotation(ax); - } - } - - public void removeAnnotation(ResolvedType annotationType) { - initialize(); - if (memberView == null) { - // If member view is null, we manage them in newAnnotations - if (annotationsForRemoval == null) { - annotationsForRemoval = new ArrayList<ResolvedType>(); - } - annotationsForRemoval.add(annotationType); - } else { - memberView.removeAnnotation(annotationType); - } - } - - public void addParameterAnnotation(int parameterNumber, AnnotationAJ anno) { - initialize(); - if (memberView == null) { - if (newParameterAnnotations == null) { - // time to create it - int pcount = getArgumentTypes().length; - newParameterAnnotations = new AnnotationAJ[pcount][]; - for (int i = 0; i < pcount; i++) { - if (i == parameterNumber) { - newParameterAnnotations[i] = new AnnotationAJ[1]; - newParameterAnnotations[i][0] = anno; - } else { - newParameterAnnotations[i] = NO_ANNOTATIONAJ; - } - } - } else { - AnnotationAJ[] currentAnnoArray = newParameterAnnotations[parameterNumber]; - AnnotationAJ[] newAnnoArray = new AnnotationAJ[currentAnnoArray.length + 1]; - System.arraycopy(currentAnnoArray, 0, newAnnoArray, 0, currentAnnoArray.length); - newAnnoArray[currentAnnoArray.length] = anno; - newParameterAnnotations[parameterNumber] = newAnnoArray; - } - } else { - memberView.addParameterAnnotation(parameterNumber, anno); - } - } - - public ResolvedType[] getAnnotationTypes() { - initialize(); - if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { - // TODO Ignoring removed annotations for now - ResolvedType[] annotationTypes = new ResolvedType[newAnnotations.size()]; - for (int a=0,len=newAnnotations.size();a<len;a++) { - annotationTypes[a] = newAnnotations.get(a).getType(); - } - return annotationTypes; - } - return null; - } - - public AnnotationAJ[] getAnnotations() { - initialize(); - if (memberView == null && newAnnotations!=null && newAnnotations.size()!=0) { - return newAnnotations.toArray(new AnnotationAJ[newAnnotations.size()]); - } - return null; - } - - public boolean hasAnnotation(UnresolvedType annotationType) { - initialize(); - if (memberView == null) { - if (annotationsForRemoval != null) { - for (ResolvedType at : annotationsForRemoval) { - if (at.equals(annotationType)) { - return false; - } - } - } - // Check local annotations first - if (newAnnotations != null) { - for (AnnotationAJ annotation : newAnnotations) { - if (annotation.getTypeSignature().equals(annotationType.getSignature())) { - return true; - } - } - } - memberView = new BcelMethod(getEnclosingClass().getBcelObjectType(), getMethod()); - return memberView.hasAnnotation(annotationType); - } - return memberView.hasAnnotation(annotationType); - } - - private void initialize() { - if (returnType != null) { - return; - } - MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(), true); - - this.returnType = gen.getReturnType(); - this.argumentTypes = gen.getArgumentTypes(); - this.declaredExceptions = gen.getExceptions(); - this.attributes = gen.getAttributes(); - // this.annotations = gen.getAnnotations(); - this.maxLocals = gen.getMaxLocals(); - - // this.returnType = BcelWorld.makeBcelType(memberView.getReturnType()); - // this.argumentTypes = - // BcelWorld.makeBcelTypes(memberView.getParameterTypes()); - // - // this.declaredExceptions = - // UnresolvedType.getNames(memberView.getExceptions()); - // //gen.getExceptions(); - // this.attributes = new Attribute[0]; //gen.getAttributes(); - // this.maxLocals = savedMethod.getCode().getMaxLocals(); - - if (gen.isAbstract() || gen.isNative()) { - body = null; - } else { - // body = new InstructionList(savedMethod.getCode().getCode()); - body = gen.getInstructionList(); - unpackHandlers(gen); - ensureAllLineNumberSetup(); - highestLineNumber = gen.getHighestlinenumber(); - } - assertGoodBody(); - } - - // XXX we're relying on the javac promise I've just made up that we won't - // have an early exception - // in the list mask a later exception: That is, for two exceptions E and F, - // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So - // when we add F, - // we add it on the _OUTSIDE_ of any handlers that share starts or ends with - // it. - - // with that in mind, we merrily go adding ranges for exceptions. - - private void unpackHandlers(MethodGen gen) { - CodeExceptionGen[] exns = gen.getExceptionHandlers(); - if (exns != null) { - int len = exns.length; - // if (len > 0) hasExceptionHandlers = true; - int priority = len - 1; - for (int i = 0; i < len; i++, priority--) { - CodeExceptionGen exn = exns[i]; - - InstructionHandle start = Range.genStart(body, getOutermostExceptionStart(exn.getStartPC())); - InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC())); - // this doesn't necessarily handle overlapping correctly!!! - ExceptionRange er = new ExceptionRange(body, exn.getCatchType() == null ? null : BcelWorld.fromBcel(exn - .getCatchType()), priority); - er.associateWithTargets(start, end, exn.getHandlerPC()); - exn.setStartPC(null); // also removes from target - exn.setEndPC(null); // also removes from target - exn.setHandlerPC(null); // also removes from target - } - gen.removeExceptionHandlers(); - } - } - - private InstructionHandle getOutermostExceptionStart(InstructionHandle ih) { - while (true) { - if (ExceptionRange.isExceptionStart(ih.getPrev())) { - ih = ih.getPrev(); - } else { - return ih; - } - } - } - - private InstructionHandle getOutermostExceptionEnd(InstructionHandle ih) { - while (true) { - if (ExceptionRange.isExceptionEnd(ih.getNext())) { - ih = ih.getNext(); - } else { - return ih; - } - } - } - - /** - * On entry to this method we have a method whose instruction stream contains a few instructions that have line numbers assigned - * to them (LineNumberTags). The aim is to ensure every instruction has the right line number. This is necessary because some of - * them may be extracted out into other methods - and it'd be useful for them to maintain the source line number for debugging. - */ - public void ensureAllLineNumberSetup() { - LineNumberTag lastKnownLineNumberTag = null; - boolean skip = false; - for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - skip = false; - for (InstructionTargeter targeter : ih.getTargeters()) { - if (targeter instanceof LineNumberTag) { - lastKnownLineNumberTag = (LineNumberTag) targeter; - skip = true; - } - } - if (lastKnownLineNumberTag != null && !skip) { - ih.addTargeter(lastKnownLineNumberTag); - } - } - } - - // =============== - - public int allocateLocal(Type type) { - return allocateLocal(type.getSize()); - } - - public int allocateLocal(int slots) { - int max = getMaxLocals(); - setMaxLocals(max + slots); - return max; - } - - public Method getMethod() { - if (savedMethod != null) { - return savedMethod; // ??? this relies on gentle treatment of - // constant pool - } - - try { - MethodGen gen = pack(); - savedMethod = gen.getMethod(); - return savedMethod; - } catch (ClassGenException e) { - enclosingClass - .getBcelObjectType() - .getResolvedTypeX() - .getWorld() - .showMessage( - IMessage.ERROR, - WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD, this.getClassName(), this.getName(), - e.getMessage()), - this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null); - // throw e; PR 70201.... let the normal problem reporting - // infrastructure deal with this rather than crashing. - body = null; - MethodGen gen = pack(); - return gen.getMethod(); - } catch (RuntimeException re) { - if (re.getCause() instanceof ClassGenException) { - enclosingClass - .getBcelObjectType() - .getResolvedTypeX() - .getWorld() - .showMessage( - IMessage.ERROR, - WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD, this.getClassName(), - this.getName(), re.getCause().getMessage()), - this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null); - // throw e; PR 70201.... let the normal problem reporting - // infrastructure deal with this rather than crashing. - body = null; - MethodGen gen = pack(); - return gen.getMethod(); - } - throw re; - } - } - - public void markAsChanged() { - if (wasPackedOptimally) { - throw new RuntimeException("Already packed method is being re-modified: " + getClassName() + " " + toShortString()); - } - initialize(); - savedMethod = null; - } - - // ============================= - - @Override - public String toString() { - BcelObjectType bot = enclosingClass.getBcelObjectType(); - WeaverVersionInfo weaverVersion = (bot == null ? WeaverVersionInfo.CURRENT : bot.getWeaverVersionAttribute()); - return toLongString(weaverVersion); - } - - public String toShortString() { - String access = org.aspectj.apache.bcel.classfile.Utility.accessToString(getAccessFlags()); - - StringBuffer buf = new StringBuffer(); - - if (!access.equals("")) { - buf.append(access); - buf.append(" "); - } - buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(getReturnType().getSignature(), true)); - buf.append(" "); - buf.append(getName()); - buf.append("("); - { - int len = argumentTypes.length; - if (len > 0) { - buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(argumentTypes[0].getSignature(), true)); - for (int i = 1; i < argumentTypes.length; i++) { - buf.append(", "); - buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(argumentTypes[i].getSignature(), true)); - } - } - } - buf.append(")"); - - { - int len = declaredExceptions != null ? declaredExceptions.length : 0; - if (len > 0) { - buf.append(" throws "); - buf.append(declaredExceptions[0]); - for (int i = 1; i < declaredExceptions.length; i++) { - buf.append(", "); - buf.append(declaredExceptions[i]); - } - } - } - return buf.toString(); - } - - public String toLongString(WeaverVersionInfo weaverVersion) { - ByteArrayOutputStream s = new ByteArrayOutputStream(); - print(new PrintStream(s), weaverVersion); - return new String(s.toByteArray()); - } - - public void print(WeaverVersionInfo weaverVersion) { - print(System.out, weaverVersion); - } - - public void print(PrintStream out, WeaverVersionInfo weaverVersion) { - out.print(" " + toShortString()); - printAspectAttributes(out, weaverVersion); - - InstructionList body = getBody(); - if (body == null) { - out.println(";"); - return; - } - out.println(":"); - new BodyPrinter(out).run(); - out.println(" end " + toShortString()); - } - - private void printAspectAttributes(PrintStream out, WeaverVersionInfo weaverVersion) { - ISourceContext context = null; - if (enclosingClass != null && enclosingClass.getType() != null) { - context = enclosingClass.getType().getSourceContext(); - } - List<AjAttribute> as = Utility.readAjAttributes(getClassName(), attributes.toArray(new Attribute[] {}), context, null, weaverVersion, - new BcelConstantPoolReader(this.enclosingClass.getConstantPool())); - if (!as.isEmpty()) { - out.println(" " + as.get(0)); // XXX assuming exactly one - // attribute, munger... - } - } - - private class BodyPrinter { - Map<InstructionHandle, String> labelMap = new HashMap<InstructionHandle, String>(); - - InstructionList body; - PrintStream out; - ConstantPool pool; - - BodyPrinter(PrintStream out) { - this.pool = enclosingClass.getConstantPool(); - this.body = getBodyForPrint(); - this.out = out; - } - - BodyPrinter(PrintStream out, InstructionList il) { - this.pool = enclosingClass.getConstantPool(); - this.body = il; - this.out = out; - } - - void run() { - // killNops(); - assignLabels(); - print(); - } - - // label assignment - void assignLabels() { - LinkedList<ExceptionRange> exnTable = new LinkedList<ExceptionRange>(); - String pendingLabel = null; - // boolean hasPendingTargeters = false; - int lcounter = 0; - for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter t = tIter.next();// targeters - // [ - // i - // ] - // ; - if (t instanceof ExceptionRange) { - // assert isRangeHandle(h); - ExceptionRange r = (ExceptionRange) t; - if (r.getStart() == ih) { - insertHandler(r, exnTable); - } - } else if (t instanceof InstructionBranch) { - if (pendingLabel == null) { - pendingLabel = "L" + lcounter++; - } - } else { - // assert isRangeHandle(h) - } - } - if (pendingLabel != null) { - labelMap.put(ih, pendingLabel); - if (!Range.isRangeHandle(ih)) { - pendingLabel = null; - } - } - } - int ecounter = 0; - for (ExceptionRange er: exnTable) { - String exceptionLabel = "E" + ecounter++; - labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel); - labelMap.put(er.getHandler(), exceptionLabel); - } - } - - // printing - - void print() { - int depth = 0; - int currLine = -1; - bodyPrint: for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - if (Range.isRangeHandle(ih)) { - Range r = Range.getRange(ih); - // don't print empty ranges, that is, ranges who contain no - // actual instructions - for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) { - if (xx == r.getEnd()) { - continue bodyPrint; - } - } - - // doesn't handle nested: if (r.getStart().getNext() == - // r.getEnd()) continue; - if (r.getStart() == ih) { - printRangeString(r, depth++); - } else { - if (r.getEnd() != ih) { - throw new RuntimeException("bad"); - } - printRangeString(r, --depth); - } - } else { - printInstruction(ih, depth); - int line = getLineNumber(ih, currLine); - if (line != currLine) { - currLine = line; - out.println(" (line " + line + ")"); - } else { - out.println(); - } - } - } - } - - void printRangeString(Range r, int depth) { - printDepth(depth); - out.println(getRangeString(r, labelMap)); - } - - String getRangeString(Range r, Map<InstructionHandle, String> labelMap) { - if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - return er.toString() + " -> " + labelMap.get(er.getHandler()); - // - // + " PRI " + er.getPriority(); - } else { - return r.toString(); - } - } - - void printDepth(int depth) { - pad(BODY_INDENT); - while (depth > 0) { - out.print("| "); - depth--; - } - } - - void printLabel(String s, int depth) { - int space = Math.max(CODE_INDENT - depth * 2, 0); - if (s == null) { - pad(space); - } else { - space = Math.max(space - (s.length() + 2), 0); - pad(space); - out.print(s); - out.print(": "); - } - } - - void printInstruction(InstructionHandle h, int depth) { - printDepth(depth); - printLabel(labelMap.get(h), depth); - - Instruction inst = h.getInstruction(); - if (inst.isConstantPoolInstruction()) { - out.print(Constants.OPCODE_NAMES[inst.opcode].toUpperCase()); - out.print(" "); - out.print(pool.constantToString(pool.getConstant(inst.getIndex()))); - } else if (inst instanceof InstructionSelect) { - InstructionSelect sinst = (InstructionSelect) inst; - out.println(Constants.OPCODE_NAMES[sinst.opcode].toUpperCase()); - int[] matches = sinst.getMatchs(); - InstructionHandle[] targets = sinst.getTargets(); - InstructionHandle defaultTarget = sinst.getTarget(); - for (int i = 0, len = matches.length; i < len; i++) { - printDepth(depth); - printLabel(null, depth); - out.print(" "); - out.print(matches[i]); - out.print(": \t"); - out.println(labelMap.get(targets[i])); - } - printDepth(depth); - printLabel(null, depth); - out.print(" "); - out.print("default: \t"); - out.print(labelMap.get(defaultTarget)); - } else if (inst instanceof InstructionBranch) { - InstructionBranch brinst = (InstructionBranch) inst; - out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase()); - out.print(" "); - out.print(labelMap.get(brinst.getTarget())); - } else if (inst.isLocalVariableInstruction()) { - // LocalVariableInstruction lvinst = (LocalVariableInstruction) - // inst; - out.print(inst.toString(false).toUpperCase()); - int index = inst.getIndex(); - LocalVariableTag tag = getLocalVariableTag(h, index); - if (tag != null) { - out.print(" // "); - out.print(tag.getType()); - out.print(" "); - out.print(tag.getName()); - } - } else { - out.print(inst.toString(false).toUpperCase()); - } - } - - static final int BODY_INDENT = 4; - static final int CODE_INDENT = 16; - - void pad(int size) { - for (int i = 0; i < size; i++) { - out.print(" "); - } - } - } - - static LocalVariableTag getLocalVariableTag(InstructionHandle ih, int index) { - for (InstructionTargeter t : ih.getTargeters()) { - if (t instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) t; - if (lvt.getSlot() == index) { - return lvt; - } - } - } - return null; - } - - static int getLineNumber(InstructionHandle ih, int prevLine) { - for (InstructionTargeter t : ih.getTargeters()) { - if (t instanceof LineNumberTag) { - return ((LineNumberTag) t).getLineNumber(); - } - } - return prevLine; - } - - public boolean isStatic() { - return Modifier.isStatic(getAccessFlags()); - } - - public boolean isAbstract() { - return Modifier.isAbstract(getAccessFlags()); - } - - public boolean isBridgeMethod() { - return (getAccessFlags() & Constants.ACC_BRIDGE) != 0; - } - - public void addExceptionHandler(InstructionHandle start, InstructionHandle end, InstructionHandle handlerStart, - ObjectType catchType, boolean highPriority) { - - InstructionHandle start1 = Range.genStart(body, start); - InstructionHandle end1 = Range.genEnd(body, end); - - ExceptionRange er = new ExceptionRange(body, (catchType == null ? null : BcelWorld.fromBcel(catchType)), highPriority); - er.associateWithTargets(start1, end1, handlerStart); - } - - public int getAccessFlags() { - return modifiers; - } - - public int getAccessFlagsWithoutSynchronized() { - if (isSynchronized()) { - return modifiers - Modifier.SYNCHRONIZED; - } - return modifiers; - } - - public boolean isSynchronized() { - return (modifiers & Modifier.SYNCHRONIZED) != 0; - } - - public void setAccessFlags(int newFlags) { - this.modifiers = newFlags; - } - - public Type[] getArgumentTypes() { - initialize(); - return argumentTypes; - } - - public LazyClassGen getEnclosingClass() { - return enclosingClass; - } - - public int getMaxLocals() { - return maxLocals; - } - - public String getName() { - return name; - } - - public String getGenericReturnTypeSignature() { - if (memberView == null) { - return getReturnType().getSignature(); - } else { - return memberView.getGenericReturnType().getSignature(); - } - } - - public Type getReturnType() { - initialize(); - return returnType; - } - - public void setMaxLocals(int maxLocals) { - this.maxLocals = maxLocals; - } - - public InstructionList getBody() { - markAsChanged(); - return body; - } - - public InstructionList getBodyForPrint() { - return body; - } - - public boolean hasBody() { - if (savedMethod != null) { - return savedMethod.getCode() != null; - } - return body != null; - } - - public List<Attribute> getAttributes() { - return attributes; - } - - public String[] getDeclaredExceptions() { - return declaredExceptions; - } - - public String getClassName() { - return enclosingClass.getName(); - } - - // ---- packing! - - public MethodGen pack() { - forceSyntheticForAjcMagicMembers(); - - // killNops(); - int flags = getAccessFlags(); - if (enclosingClass.getWorld().isJoinpointSynchronizationEnabled() - && enclosingClass.getWorld().areSynchronizationPointcutsInUse()) { - flags = getAccessFlagsWithoutSynchronized(); - } - MethodGen gen = new MethodGen(flags, getReturnType(), getArgumentTypes(), null, // getArgumentNames(), - getName(), getEnclosingClass().getName(), new InstructionList(), getEnclosingClass().getConstantPool()); - for (int i = 0, len = declaredExceptions.length; i < len; i++) { - gen.addException(declaredExceptions[i]); - } - - for (Attribute attr : attributes) { - gen.addAttribute(attr); - } - - if (newAnnotations != null) { - for (AnnotationAJ element : newAnnotations) { - gen.addAnnotation(new AnnotationGen(((BcelAnnotation) element).getBcelAnnotation(), gen.getConstantPool(), true)); - } - } - - if (newParameterAnnotations != null) { - for (int i = 0; i < newParameterAnnotations.length; i++) { - AnnotationAJ[] annos = newParameterAnnotations[i]; - for (int j = 0; j < annos.length; j++) { - gen.addParameterAnnotation(i, - new AnnotationGen(((BcelAnnotation) annos[j]).getBcelAnnotation(), gen.getConstantPool(), true)); - } - } - } - - if (memberView != null && memberView.getAnnotations() != null && memberView.getAnnotations().length != 0) { - AnnotationAJ[] ans = memberView.getAnnotations(); - for (int i = 0, len = ans.length; i < len; i++) { - AnnotationGen a = ((BcelAnnotation) ans[i]).getBcelAnnotation(); - gen.addAnnotation(new AnnotationGen(a, gen.getConstantPool(), true)); - } - } - - if (isSynthetic) { - if (enclosingClass.getWorld().isInJava5Mode()) { - gen.setModifiers(gen.getModifiers() | Constants.ACC_SYNTHETIC); - } - if (!hasAttribute("Synthetic")) { - // belt and braces, do the attribute even on Java 5 in addition to the modifier flag - ConstantPool cpg = gen.getConstantPool(); - int index = cpg.addUtf8("Synthetic"); - gen.addAttribute(new Synthetic(index, 0, new byte[0], cpg)); - } - } - - if (hasBody()) { - if (this.enclosingClass.getWorld().shouldFastPackMethods()) { - if (isAdviceMethod() || getName().equals("<clinit>")) { - packBody(gen); - } else { - optimizedPackBody(gen); - } - } else { - packBody(gen); - } - - gen.setMaxLocals(true); - gen.setMaxStack(); - } else { - gen.setInstructionList(null); - } - return gen; - } - - private boolean hasAttribute(String attributeName) { - for (Attribute attr: attributes) { - if (attr.getName().equals(attributeName)) { - return true; - } - } - return false; - } - - private void forceSyntheticForAjcMagicMembers() { - if (NameMangler.isSyntheticMethod(getName(), inAspect())) { - makeSynthetic(); - } - } - - private boolean inAspect() { - BcelObjectType objectType = enclosingClass.getBcelObjectType(); - return (objectType == null ? false : objectType.isAspect()); - } - - public void makeSynthetic() { - isSynthetic = true; - } - - private static class LVPosition { - InstructionHandle start = null; - InstructionHandle end = null; - } - - /** - * fill the newly created method gen with our body, inspired by InstructionList.copy() - */ - public void packBody(MethodGen gen) { - InstructionList fresh = gen.getInstructionList(); - Map<InstructionHandle, InstructionHandle> map = copyAllInstructionsExceptRangeInstructionsInto(fresh); - - // at this point, no rangeHandles are in fresh. Let's use that... - - /* - * Update branch targets and insert various attributes. Insert our exceptionHandlers into a sorted list, so they can be - * added in order later. - */ - InstructionHandle oldInstructionHandle = getBody().getStart(); - InstructionHandle newInstructionHandle = fresh.getStart(); - LinkedList<ExceptionRange> exceptionList = new LinkedList<ExceptionRange>(); - - Map<LocalVariableTag, LVPosition> localVariables = new HashMap<LocalVariableTag, LVPosition>(); - - int currLine = -1; - int lineNumberOffset = (fromFilename == null) ? 0 : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); - - while (oldInstructionHandle != null) { - if (map.get(oldInstructionHandle) == null) { - // must be a range instruction since they're the only things we - // didn't copy across - handleRangeInstruction(oldInstructionHandle, exceptionList); - // just increment ih. - oldInstructionHandle = oldInstructionHandle.getNext(); - } else { - // assert map.get(ih) == jh - Instruction oldInstruction = oldInstructionHandle.getInstruction(); - Instruction newInstruction = newInstructionHandle.getInstruction(); - - if (oldInstruction instanceof InstructionBranch) { - handleBranchInstruction(map, oldInstruction, newInstruction); - } - - // now deal with line numbers - // and store up info for local variables - for (InstructionTargeter targeter : oldInstructionHandle.getTargeters()) { - if (targeter instanceof LineNumberTag) { - int line = ((LineNumberTag) targeter).getLineNumber(); - if (line != currLine) { - gen.addLineNumber(newInstructionHandle, line + lineNumberOffset); - currLine = line; - } - } else if (targeter instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) targeter; - LVPosition p = localVariables.get(lvt); - // If we don't know about it, create a new position and - // store - // If we do know about it - update its end position - if (p == null) { - LVPosition newp = new LVPosition(); - newp.start = newp.end = newInstructionHandle; - localVariables.put(lvt, newp); - } else { - p.end = newInstructionHandle; - } - } - } - - // now continue - oldInstructionHandle = oldInstructionHandle.getNext(); - newInstructionHandle = newInstructionHandle.getNext(); - } - } - - addExceptionHandlers(gen, map, exceptionList); - if (originalMethodHasLocalVariableTable || enclosingClass - .getBcelObjectType() - .getResolvedTypeX() - .getWorld().generateNewLvts) { - if (localVariables.size() == 0) { - // Might be a case of 173978 where around advice on an execution join point - // has caused everything to be extracted from the method and thus we - // are left with no local variables, not even the ones for 'this' and - // parameters passed to the method - createNewLocalVariables(gen); - } else { - addLocalVariables(gen, localVariables); - } - } - - // JAVAC adds line number tables (with just one entry) to generated - // accessor methods - this - // keeps some tools that rely on finding at least some form of - // linenumbertable happy. - // Let's check if we have one - if we don't then let's add one. - // TODO Could be made conditional on whether line debug info is being - // produced - if (gen.getLineNumbers().length == 0) { - gen.addLineNumber(gen.getInstructionList().getStart(), 1); - } - } - - private void createNewLocalVariables(MethodGen gen) { - gen.removeLocalVariables(); - // ignore <clinit> or <init> for now - if (!getName().startsWith("<")) { - int slot = 0; - InstructionHandle start = gen.getInstructionList().getStart(); - InstructionHandle end = gen.getInstructionList().getEnd(); - // Add a 'this' if non-static - if (!isStatic()) { - String cname = this.enclosingClass.getClassName(); - if (cname == null) { - return; // give up for now - } - Type enclosingType = BcelWorld.makeBcelType(UnresolvedType.forName(cname)); - gen.addLocalVariable("this", enclosingType, slot++, start, end); - } - // Add entries for the method arguments - String[] paramNames = (memberView == null ? null : memberView.getParameterNames()); - if (paramNames != null) { - for (int i = 0; i < argumentTypes.length; i++) { - String pname = paramNames[i]; - if (pname == null) { - pname = "arg" + i; - } - gen.addLocalVariable(pname, argumentTypes[i], slot, start, end); - slot += argumentTypes[i].getSize(); - } - } - } - } - - private World getWorld() { - return enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld(); - } - /* - * Optimized packing that does a 'local packing' of the code rather than building a brand new method and packing into it. Only - * usable when the packing is going to be done just once. - */ - public void optimizedPackBody(MethodGen gen) { - InstructionList theBody = getBody(); - InstructionHandle iHandle = theBody.getStart(); - - int currLine = -1; - int lineNumberOffset = (fromFilename == null) ? 0 : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); - Map<LocalVariableTag, LVPosition> localVariables = new HashMap<LocalVariableTag, LVPosition>(); - LinkedList<ExceptionRange> exceptionList = new LinkedList<ExceptionRange>(); - Set<InstructionHandle> forDeletion = new HashSet<InstructionHandle>(); - Set<BranchHandle> branchInstructions = new HashSet<BranchHandle>(); - // OPTIMIZE sort out in here: getRange()/insertHandler() and type of - // exceptionList - while (iHandle != null) { - Instruction inst = iHandle.getInstruction(); - // InstructionHandle nextInst = iHandle.getNext(); - // OPTIMIZE remove this instructionhandle as it now points to - // nowhere? - if (inst == Range.RANGEINSTRUCTION) { - Range r = Range.getRange(iHandle); - if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - if (er.getStart() == iHandle) { - if (!er.isEmpty()) { - // order is important, insert handlers in order of start - insertHandler(er, exceptionList); - } - } - } - forDeletion.add(iHandle); - } else { - if (inst instanceof InstructionBranch) { - branchInstructions.add((BranchHandle) iHandle); - } - - for (InstructionTargeter targeter : iHandle.getTargetersCopy()) { - if (targeter instanceof LineNumberTag) { - int line = ((LineNumberTag) targeter).getLineNumber(); - if (line != currLine) { - gen.addLineNumber(iHandle, line + lineNumberOffset); - currLine = line; - } - } else if (targeter instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) targeter; - LVPosition p = localVariables.get(lvt); - // If we don't know about it, create a new position - // and store - // If we do know about it - update its end position - if (p == null) { - LVPosition newp = new LVPosition(); - newp.start = newp.end = iHandle; - localVariables.put(lvt, newp); - } else { - p.end = iHandle; - } - } - } - } - iHandle = iHandle.getNext(); - } - for (BranchHandle branchHandle : branchInstructions) { - handleBranchInstruction(branchHandle, forDeletion); - } - // now add exception handlers - for (ExceptionRange r : exceptionList) { - if (r.isEmpty()) { - continue; - } - gen.addExceptionHandler(jumpForward(r.getRealStart(), forDeletion), jumpForward(r.getRealEnd(), forDeletion), - jumpForward(r.getHandler(), forDeletion), - (r.getCatchType() == null) ? null : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); - } - - for (InstructionHandle handle : forDeletion) { - try { - theBody.delete(handle); - } catch (TargetLostException e) { - e.printStackTrace(); - } - } - gen.setInstructionList(theBody); - if (originalMethodHasLocalVariableTable || getWorld().generateNewLvts) { - if (localVariables.size() == 0) { - // Might be a case of 173978 where around advice on an execution join point - // has caused everything to be extracted from the method and thus we - // are left with no local variables, not even the ones for 'this' and - // parameters passed to the method - createNewLocalVariables(gen); - } else { - addLocalVariables(gen, localVariables); - } - } - // JAVAC adds line number tables (with just one entry) to generated - // accessor methods - this - // keeps some tools that rely on finding at least some form of - // linenumbertable happy. - // Let's check if we have one - if we don't then let's add one. - // TODO Could be made conditional on whether line debug info is being - // produced - if (gen.getLineNumbers().length == 0) { - gen.addLineNumber(gen.getInstructionList().getStart(), 1); - } - wasPackedOptimally = true; - } - - private void addLocalVariables(MethodGen gen, Map<LocalVariableTag, LVPosition> localVariables) { - // now add local variables - gen.removeLocalVariables(); - - // this next iteration _might_ be overkill, but we had problems with - // bcel before with duplicate local variables. Now that we're patching - // bcel we should be able to do without it if we're paranoid enough - // through the rest of the compiler. - InstructionHandle methodStart = gen.getInstructionList().getStart(); - InstructionHandle methodEnd = gen.getInstructionList().getEnd(); - - // Determine how many 'slots' are used by parameters to the method. - // Then below we can determine if a local variable is a parameter variable, if it is - // we force its range to from the method start (as it may have been shuffled down - // due to insertion of advice like cflow entry) - int paramSlots = gen.isStatic() ? 0 : 1; - Type[] argTypes = gen.getArgumentTypes(); - if (argTypes != null) { - for (int i = 0; i < argTypes.length; i++) { - if (argTypes[i].getSize() == 2) { - paramSlots += 2; - } else { - paramSlots += 1; - } - } - } - if (!this.enclosingClass.getWorld().generateNewLvts) { - // Here the generateNewLvts option is used to control "Do not damage unusually positioned local - // variables that represent method parameters". Strictly speaking local variables that represent - // method parameters effectively have a bytecode range from 0..end_of_method - however some - // tools generate bytecode that specifies a compressed range. The code below would normally - // extend the parameter local variables to cover the full method but by setting paramSlots to -1 - // here we cause the code below to avoid modifying any local vars that represent method - // parameters. - paramSlots = -1; - } - - Map<InstructionHandle, Set<Integer>> duplicatedLocalMap = new HashMap<InstructionHandle, Set<Integer>>(); - for (LocalVariableTag tag : localVariables.keySet()) { - // have we already added one with the same slot number and start - // location? - // if so, just continue. - LVPosition lvpos = localVariables.get(tag); - InstructionHandle start = (tag.getSlot() < paramSlots ? methodStart : lvpos.start); - InstructionHandle end = (tag.getSlot() < paramSlots ? methodEnd : lvpos.end); - Set<Integer> slots = duplicatedLocalMap.get(start); - if (slots == null) { - slots = new HashSet<Integer>(); - duplicatedLocalMap.put(start, slots); - } else if (slots.contains(new Integer(tag.getSlot()))) { - // we already have a var starting at this tag with this slot - continue; - } - slots.add(Integer.valueOf(tag.getSlot())); - Type t = tag.getRealType(); - if (t == null) { - t = BcelWorld.makeBcelType(UnresolvedType.forSignature(tag.getType())); - } - gen.addLocalVariable(tag.getName(), t, tag.getSlot(), start, end); - } - } - - private void addExceptionHandlers(MethodGen gen, Map<InstructionHandle, InstructionHandle> map, - LinkedList<ExceptionRange> exnList) { - // now add exception handlers - for (ExceptionRange r : exnList) { - if (r.isEmpty()) { - continue; - } - InstructionHandle rMappedStart = remap(r.getRealStart(), map); - InstructionHandle rMappedEnd = remap(r.getRealEnd(), map); - InstructionHandle rMappedHandler = remap(r.getHandler(), map); - gen.addExceptionHandler(rMappedStart, rMappedEnd, rMappedHandler, (r.getCatchType() == null) ? null - : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); - } - } - - private void handleBranchInstruction(Map<InstructionHandle, InstructionHandle> map, Instruction oldInstruction, - Instruction newInstruction) { - InstructionBranch oldBranchInstruction = (InstructionBranch) oldInstruction; - InstructionBranch newBranchInstruction = (InstructionBranch) newInstruction; - InstructionHandle oldTarget = oldBranchInstruction.getTarget(); // old - // target - - // New target is in hash map - newBranchInstruction.setTarget(remap(oldTarget, map)); - - if (oldBranchInstruction instanceof InstructionSelect) { - // Either LOOKUPSWITCH or TABLESWITCH - InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets(); - InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets(); - - for (int k = oldTargets.length - 1; k >= 0; k--) { - // Update all targets - newTargets[k] = remap(oldTargets[k], map); - newTargets[k].addTargeter(newBranchInstruction); - } - } - } - - private InstructionHandle jumpForward(InstructionHandle t, Set<InstructionHandle> handlesForDeletion) { - InstructionHandle target = t; - if (handlesForDeletion.contains(target)) { - do { - target = target.getNext(); - } while (handlesForDeletion.contains(target)); - } - return target; - } - - /** - * Process a branch instruction with respect to instructions that are about to be deleted. If the target for the branch is a - * candidate for deletion, move it to the next valid instruction after the deleted target. - */ - private void handleBranchInstruction(BranchHandle branchHandle, Set<InstructionHandle> handlesForDeletion) { - InstructionBranch branchInstruction = (InstructionBranch) branchHandle.getInstruction(); - InstructionHandle target = branchInstruction.getTarget(); // old target - - if (handlesForDeletion.contains(target)) { - do { - target = target.getNext(); - } while (handlesForDeletion.contains(target)); - branchInstruction.setTarget(target); - } - - if (branchInstruction instanceof InstructionSelect) { - // Either LOOKUPSWITCH or TABLESWITCH - InstructionSelect iSelect = (InstructionSelect) branchInstruction; - InstructionHandle[] targets = iSelect.getTargets(); - for (int k = targets.length - 1; k >= 0; k--) { - InstructionHandle oneTarget = targets[k]; - if (handlesForDeletion.contains(oneTarget)) { - do { - oneTarget = oneTarget.getNext(); - } while (handlesForDeletion.contains(oneTarget)); - iSelect.setTarget(k, oneTarget); - oneTarget.addTargeter(branchInstruction); - } - } - } - } - - private void handleRangeInstruction(InstructionHandle ih, LinkedList<ExceptionRange> exnList) { - // we're a range instruction - Range r = Range.getRange(ih); - if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - if (er.getStart() == ih) { - // System.err.println("er " + er); - if (!er.isEmpty()) { - // order is important, insert handlers in order of start - insertHandler(er, exnList); - } - } - } else { - // we must be a shadow range or something equally useless, - // so forget about doing anything - } - } - - /* - * Make copies of all instructions, append them to the new list and associate old instruction references with the new ones, - * i.e., a 1:1 mapping. - */ - private Map<InstructionHandle, InstructionHandle> copyAllInstructionsExceptRangeInstructionsInto(InstructionList intoList) { - Map<InstructionHandle, InstructionHandle> map = new HashMap<InstructionHandle, InstructionHandle>(); - for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) { - if (Range.isRangeHandle(ih)) { - continue; - } - Instruction inst = ih.getInstruction(); - Instruction copy = Utility.copyInstruction(inst); - - if (copy instanceof InstructionBranch) { - map.put(ih, intoList.append((InstructionBranch) copy)); - } else { - map.put(ih, intoList.append(copy)); - } - } - return map; - } - - /** - * This procedure should not currently be used. - */ - // public void killNops() { - // InstructionHandle curr = body.getStart(); - // while (true) { - // if (curr == null) break; - // InstructionHandle next = curr.getNext(); - // if (curr.getInstruction() instanceof NOP) { - // InstructionTargeter[] targeters = curr.getTargeters(); - // if (targeters != null) { - // for (int i = 0, len = targeters.length; i < len; i++) { - // InstructionTargeter targeter = targeters[i]; - // targeter.updateTarget(curr, next); - // } - // } - // try { - // body.delete(curr); - // } catch (TargetLostException e) { - // } - // } - // curr = next; - // } - // } - // private static InstructionHandle fNext(InstructionHandle ih) { - // while (true) { - // if (ih.getInstruction()==Range.RANGEINSTRUCTION) ih = ih.getNext(); - // else return ih; - // } - // } - private static InstructionHandle remap(InstructionHandle handle, Map<InstructionHandle, InstructionHandle> map) { - while (true) { - InstructionHandle ret = map.get(handle); - if (ret == null) { - handle = handle.getNext(); - } else { - return ret; - } - } - } - - // Update to all these comments, ASC 11-01-2005 - // The right thing to do may be to do more with priorities as - // we create new exception handlers, but that is a relatively - // complex task. In the meantime, just taking account of the - // priority here enables a couple of bugs to be fixed to do - // with using return or break in code that contains a finally - // block (pr78021,pr79554). - - // exception ordering. - // What we should be doing is dealing with priority inversions way earlier - // than we are - // and counting on the tree structure. In which case, the below code is in - // fact right. - - // XXX THIS COMMENT BELOW IS CURRENTLY WRONG. - // An exception A preceeds an exception B in the exception table iff: - - // * A and B were in the original method, and A preceeded B in the original - // exception table - // * If A has a higher priority than B, than it preceeds B. - // * If A and B have the same priority, then the one whose START happens - // EARLIEST has LEAST priority. - // in short, the outermost exception has least priority. - // we implement this with a LinkedList. We could possibly implement this - // with a java.util.SortedSet, - // but I don't trust the only implementation, TreeSet, to do the right - // thing. - - /* private */static void insertHandler(ExceptionRange fresh, LinkedList<ExceptionRange> l) { - // Old implementation, simply: l.add(0,fresh); - for (ListIterator<ExceptionRange> iter = l.listIterator(); iter.hasNext();) { - ExceptionRange r = iter.next(); - // int freal = fresh.getRealStart().getPosition(); - // int rreal = r.getRealStart().getPosition(); - if (fresh.getPriority() >= r.getPriority()) { - iter.previous(); - iter.add(fresh); - return; - } - } - - // we have reached the end - l.add(fresh); - } - - public boolean isPrivate() { - return Modifier.isPrivate(getAccessFlags()); - } - - public boolean isProtected() { - return Modifier.isProtected(getAccessFlags()); - } - - public boolean isDefault() { - return !(isProtected() || isPrivate() || isPublic()); - } - - public boolean isPublic() { - return Modifier.isPublic(getAccessFlags()); - } - - // ---- - - /** - * A good body is a body with the following properties: - * - * <ul> - * <li>For each branch instruction S in body, target T of S is in body. - * <li>For each branch instruction S in body, target T of S has S as a targeter. - * <li>For each instruction T in body, for each branch instruction S that is a targeter of T, S is in body. - * <li>For each non-range-handle instruction T in body, for each instruction S that is a targeter of T, S is either a branch - * instruction, an exception range or a tag - * <li>For each range-handle instruction T in body, there is exactly one targeter S that is a range. - * <li>For each range-handle instruction T in body, the range R targeting T is in body. - * <li>For each instruction T in body, for each exception range R targeting T, R is in body. - * <li>For each exception range R in body, let T := R.handler. T is in body, and R is one of T's targeters - * <li>All ranges are properly nested: For all ranges Q and R, if Q.start preceeds R.start, then R.end preceeds Q.end. - * </ul> - * - * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and any InstructionHandle stored in a field - * of R (such as an exception handle) is in body". - */ - - public void assertGoodBody() { - if (true) { - return; // only enable for debugging - } - assertGoodBody(getBody(), toString()); - } - - public static void assertGoodBody(InstructionList il, String from) { - if (true) { - return; // only to be enabled for debugging - } -// if (il == null) { -// return; -// } -// Set body = new HashSet(); -// Stack<Range> ranges = new Stack<Range>(); -// for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { -// body.add(ih); -// if (ih.getInstruction() instanceof InstructionBranch) { -// body.add(ih.getInstruction()); -// } -// } -// -// for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { -// assertGoodHandle(ih, body, ranges, from); -// Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator(); -// while (tIter.hasNext()) { -// assertGoodTargeter(tIter.next(), ih, body, from); -// } -// } - } - -// private static void assertGoodHandle(InstructionHandle ih, Set body, Stack<Range> ranges, String from) { -// Instruction inst = ih.getInstruction(); -// if ((inst instanceof InstructionBranch) ^ (ih instanceof BranchHandle)) { -// throw new BCException("bad instruction/handle pair in " + from); -// } -// if (Range.isRangeHandle(ih)) { -// assertGoodRangeHandle(ih, body, ranges, from); -// } else if (inst instanceof InstructionBranch) { -// assertGoodBranchInstruction((BranchHandle) ih, (InstructionBranch) inst, body, ranges, from); -// } -// } - -// private static void assertGoodBranchInstruction(BranchHandle ih, InstructionBranch inst, Set body, Stack<Range> ranges, -// String from) { -// if (ih.getTarget() != inst.getTarget()) { -// throw new BCException("bad branch instruction/handle pair in " + from); -// } -// InstructionHandle target = ih.getTarget(); -// assertInBody(target, body, from); -// assertTargetedBy(target, inst, from); -// if (inst instanceof InstructionSelect) { -// InstructionSelect sel = (InstructionSelect) inst; -// InstructionHandle[] itargets = sel.getTargets(); -// for (int k = itargets.length - 1; k >= 0; k--) { -// assertInBody(itargets[k], body, from); -// assertTargetedBy(itargets[k], inst, from); -// } -// } -// } - - /** ih is an InstructionHandle or a BranchInstruction */ -// private static void assertInBody(Object ih, Set body, String from) { -// if (!body.contains(ih)) { -// throw new BCException("thing not in body in " + from); -// } -// } - -// private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) { -// Range r = getRangeAndAssertExactlyOne(ih, from); -// assertGoodRange(r, body, from); -// if (r.getStart() == ih) { -// ranges.push(r); -// } else if (r.getEnd() == ih) { -// if (ranges.peek() != r) { -// throw new BCException("bad range inclusion in " + from); -// } -// ranges.pop(); -// } -// } - -// private static void assertGoodRange(Range r, Set body, String from) { -// assertInBody(r.getStart(), body, from); -// assertRangeHandle(r.getStart(), from); -// assertTargetedBy(r.getStart(), r, from); -// -// assertInBody(r.getEnd(), body, from); -// assertRangeHandle(r.getEnd(), from); -// assertTargetedBy(r.getEnd(), r, from); -// -// if (r instanceof ExceptionRange) { -// ExceptionRange er = (ExceptionRange) r; -// assertInBody(er.getHandler(), body, from); -// assertTargetedBy(er.getHandler(), r, from); -// } -// } - -// private static void assertRangeHandle(InstructionHandle ih, String from) { -// if (!Range.isRangeHandle(ih)) { -// throw new BCException("bad range handle " + ih + " in " + from); -// } -// } - - private static void assertTargetedBy(InstructionHandle target, InstructionTargeter targeter, String from) { - Iterator tIter = target.getTargeters().iterator(); - while (tIter.hasNext()) { - if (((InstructionTargeter) tIter.next()) == targeter) { - return; - } - } - throw new RuntimeException("bad targeting relationship in " + from); - } - - private static void assertTargets(InstructionTargeter targeter, InstructionHandle target, String from) { - if (targeter instanceof Range) { - Range r = (Range) targeter; - if (r.getStart() == target || r.getEnd() == target) { - return; - } - if (r instanceof ExceptionRange) { - if (((ExceptionRange) r).getHandler() == target) { - return; - } - } - } else if (targeter instanceof InstructionBranch) { - InstructionBranch bi = (InstructionBranch) targeter; - if (bi.getTarget() == target) { - return; - } - if (targeter instanceof InstructionSelect) { - InstructionSelect sel = (InstructionSelect) targeter; - InstructionHandle[] itargets = sel.getTargets(); - for (int k = itargets.length - 1; k >= 0; k--) { - if (itargets[k] == target) { - return; - } - } - } - } else if (targeter instanceof Tag) { - return; - } - throw new BCException(targeter + " doesn't target " + target + " in " + from); - } - - private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) { - Range ret = null; - Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator(); - if (!tIter.hasNext()) { - throw new BCException("range handle with no range in " + from); - } - while (tIter.hasNext()) { - InstructionTargeter ts = tIter.next(); - if (ts instanceof Range) { - if (ret != null) { - throw new BCException("range handle with multiple ranges in " + from); - } - ret = (Range) ts; - } - } - if (ret == null) { - throw new BCException("range handle with no range in " + from); - } - return ret; - } - -// private static void assertGoodTargeter(InstructionTargeter t, InstructionHandle ih, Set body, String from) { -// assertTargets(t, ih, from); -// if (t instanceof Range) { -// assertGoodRange((Range) t, body, from); -// } else if (t instanceof InstructionBranch) { -// assertInBody(t, body, from); -// } -// } - - // ---- - - boolean isAdviceMethod() { - if (memberView == null) { - return false; - } - return memberView.getAssociatedShadowMunger() != null; - } - - boolean isAjSynthetic() { - if (memberView == null) { - return true; - } - return memberView.isAjSynthetic(); - } - - boolean isSynthetic() { - if (memberView == null) { - return false; - } - return memberView.isSynthetic(); - } - - public ISourceLocation getSourceLocation() { - if (memberView != null) { - return memberView.getSourceLocation(); - } - return null; - } - - public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { - // if (memberView == null) return null; - if (effectiveSignature != null) { - return effectiveSignature; - } - return memberView.getEffectiveSignature(); - } - - public void setEffectiveSignature(ResolvedMember member, Shadow.Kind kind, boolean shouldWeave) { - this.effectiveSignature = new AjAttribute.EffectiveSignatureAttribute(member, kind, shouldWeave); - } - - public String getSignature() { - if (memberView != null) { - return memberView.getSignature(); - } - return MemberImpl.typesToSignature(BcelWorld.fromBcel(getReturnType()), BcelWorld.fromBcel(getArgumentTypes()), false); - } - - public String getParameterSignature() { - if (memberView != null) { - return memberView.getParameterSignature(); - } - return MemberImpl.typesToSignature(BcelWorld.fromBcel(getArgumentTypes())); - } - - public BcelMethod getMemberView() { - return memberView; - } - - public void forcePublic() { - markAsChanged(); - modifiers = Utility.makePublic(modifiers); - } - - public boolean getCanInline() { - return canInline; - } - - public void setCanInline(boolean canInline) { - this.canInline = canInline; - } - - public void addAttribute(Attribute attribute) { - attributes.add(attribute); - } - - public String toTraceString() { - return toShortString(); - } - - public ConstantPool getConstantPool() { - return enclosingClass.getConstantPool(); - } - - public static boolean isConstructor(LazyMethodGen aMethod) { - return aMethod.getName().equals("<init>"); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/Range.java b/weaver/src/org/aspectj/weaver/bcel/Range.java deleted file mode 100644 index fa162c526..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/Range.java +++ /dev/null @@ -1,243 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.util.Iterator; - -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.weaver.BCException; - -abstract class Range implements InstructionTargeter { - - protected InstructionList body; - protected InstructionHandle start; - protected InstructionHandle end; - - // ---- initialization - - protected Range(InstructionList il) { - this.body = il; - } - - // ---- - - final InstructionList getBody() { - return body; - } - - final InstructionHandle getStart() { - return start; - } - - final InstructionHandle getEnd() { - return end; - } - - // ---- - - boolean isEmpty() { - InstructionHandle ih = start; - // System.err.println(" looking for " + end); - while (ih != end) { - // System.err.println(" ih " + ih); - if (!Range.isRangeHandle(ih)) { - return false; - } - ih = ih.getNext(); - } - return true; - } - - static InstructionHandle getRealStart(InstructionHandle ih) { - while (Range.isRangeHandle(ih)) { - ih = ih.getNext(); - } - return ih; - } - - InstructionHandle getRealStart() { - return getRealStart(start); - } - - static InstructionHandle getRealEnd(InstructionHandle ih) { - while (Range.isRangeHandle(ih)) { - ih = ih.getPrev(); - } - return ih; - } - - InstructionHandle getRealEnd() { - return getRealEnd(end); - } - - InstructionHandle getRealNext() { - return getRealStart(end); - } - - // ---- - - InstructionHandle insert(Instruction i, Where where) { - InstructionList il = new InstructionList(); - InstructionHandle ret = il.insert(i); - insert(il, where); - return ret; - } - - void insert(InstructionList freshIl, Where where) { - InstructionHandle h; - if (where == InsideBefore || where == OutsideBefore) { - h = getStart(); - } else { - h = getEnd(); - } - if (where == InsideBefore || where == OutsideAfter) { - body.append(h, freshIl); - } else { - InstructionHandle newStart = body.insert(h, freshIl); - if (where == OutsideBefore) { - // XXX this is slow. There's a better design than this. We should - // never have to retarget branches apart from the creation of ranges. - // basically, we should never weave OutsideBefore. - BcelShadow.retargetAllBranches(h, newStart); - } - } - - } - - InstructionHandle append(Instruction i) { - return insert(i, InsideAfter); - } - - void append(InstructionList i) { - insert(i, InsideAfter); - } - - private static void setLineNumberFromNext(InstructionHandle ih) { - int lineNumber = Utility.getSourceLine(ih.getNext()); - if (lineNumber != -1) { - Utility.setSourceLine(ih, lineNumber); - } - } - - static InstructionHandle genStart(InstructionList body) { - InstructionHandle ih = body.insert(Range.RANGEINSTRUCTION); - setLineNumberFromNext(ih); - return ih; - } - - static InstructionHandle genEnd(InstructionList body) { - return body.append(Range.RANGEINSTRUCTION); - } - - static InstructionHandle genStart(InstructionList body, InstructionHandle ih) { - if (ih == null) { - return genStart(body); - } - InstructionHandle freshIh = body.insert(ih, Range.RANGEINSTRUCTION); - setLineNumberFromNext(freshIh); - return freshIh; - } - - static InstructionHandle genEnd(InstructionList body, InstructionHandle ih) { - if (ih == null) { - return genEnd(body); - } - return body.append(ih, Range.RANGEINSTRUCTION); - } - - // ----- - - public boolean containsTarget(InstructionHandle ih) { - return false; - } - - public final void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { - throw new RuntimeException("Ranges must be updated with an enclosing instructionList"); - } - - protected void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih, InstructionList new_il) { - old_ih.removeTargeter(this); - if (new_ih != null) { - new_ih.addTargeter(this); - } - body = new_il; - - if (old_ih == start) { - start = new_ih; - } - if (old_ih == end) { - end = new_ih; - } - } - - public static final boolean isRangeHandle(InstructionHandle ih) { - if (ih == null) { - return false; - } - return ih.getInstruction() == Range.RANGEINSTRUCTION; - } - - protected static final Range getRange(InstructionHandle ih) { - // assert isRangeHandle(ih) - Range ret = null; - Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter targeter = tIter.next(); - if (targeter instanceof Range) { - Range r = (Range) targeter; - if (r.getStart() != ih && r.getEnd() != ih) { - continue; - } - if (ret != null) { - throw new BCException("multiple ranges on same range handle: " + ret + ", " + targeter); - } - ret = r; - } - } - if (ret == null) { - throw new BCException("shouldn't happen"); - } - return ret; - } - - // ---- - - static final Where InsideBefore = new Where("insideBefore"); - static final Where InsideAfter = new Where("insideAfter"); - static final Where OutsideBefore = new Where("outsideBefore"); - static final Where OutsideAfter = new Where("outsideAfter"); - - // ---- constants - - // note that this is STUPIDLY copied by Instruction.copy(), so don't do that. - - public static final Instruction RANGEINSTRUCTION = InstructionConstants.IMPDEP1; - - // ---- - - static class Where { - private String name; - - public Where(String name) { - this.name = name; - } - - public String toString() { - return name; - } - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java b/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java deleted file mode 100644 index 47c8400c5..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java +++ /dev/null @@ -1,244 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.util.Iterator; - -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionBranch; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionLV; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionSelect; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.apache.bcel.generic.LocalVariableTag; -import org.aspectj.apache.bcel.generic.RET; -import org.aspectj.apache.bcel.generic.TargetLostException; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.IntMap; -import org.aspectj.weaver.Shadow; - -final class ShadowRange extends Range { - - private BcelShadow shadow; - - // ---- initialization - - /** - * After this constructor is called, this range is not well situated unless both {@link #associateWithTargets} and - * {@link #associateWithShadow} are called. - */ - public ShadowRange(InstructionList body) { - super(body); - } - - protected void associateWithTargets(InstructionHandle start, InstructionHandle end) { - // assert body.contains(start) && body.contains(end); - this.start = start; - this.end = end; - start.addTargeter(this); - end.addTargeter(this); - } - - public void associateWithShadow(BcelShadow shadow) { - this.shadow = shadow; - shadow.setRange(this); - } - - // ---- - - public Shadow.Kind getKind() { - return shadow.getKind(); - } - - @Override - public String toString() { - return shadow.toString(); - } - - void extractInstructionsInto(LazyMethodGen freshMethod, IntMap remap, boolean addReturn) { - LazyMethodGen.assertGoodBody(getBody(), toString()); - freshMethod.assertGoodBody(); - InstructionList freshBody = freshMethod.getBody(); - - for (InstructionHandle oldIh = start.getNext(); oldIh != end; oldIh = oldIh.getNext()) { - // first we copy the instruction itself. - Instruction oldI = oldIh.getInstruction(); - Instruction freshI = (oldI == RANGEINSTRUCTION) ? oldI : Utility.copyInstruction(oldI); - - // Now we add it to the new instruction list. - InstructionHandle freshIh; - if (freshI instanceof InstructionBranch) { - // If it's a targeting instruction, - // update the target(s) to point to the new copy instead of the old copy. - InstructionBranch oldBranch = (InstructionBranch) oldI; - InstructionBranch freshBranch = (InstructionBranch) freshI; - InstructionHandle oldTarget = oldBranch.getTarget(); - oldTarget.removeTargeter(oldBranch); - oldTarget.addTargeter(freshBranch); - if (freshBranch instanceof InstructionSelect) { - InstructionSelect oldSelect = (InstructionSelect) oldI; - InstructionSelect freshSelect = (InstructionSelect) freshI; - InstructionHandle[] oldTargets = freshSelect.getTargets(); - for (int k = oldTargets.length - 1; k >= 0; k--) { - oldTargets[k].removeTargeter(oldSelect); - oldTargets[k].addTargeter(freshSelect); - } - } - freshIh = freshBody.append(freshBranch); - } else { - freshIh = freshBody.append(freshI); - } - - // if source comes before target: - // source <--> target - // --> [process: target.removeTargeter(source); target.addTargeter(sourcecopy)] - // source ---------\ - // v - // sourcecopy <--> target - // --> [ process: sourcecopy.updateTarget(target, targetcopy) ] - // source ----> target - // sourcecopy <--> targetcopy - - // if target comes before source - - // target <--> source - // --> [process: source.updateTarget(target, targetcopy) ] - // target - // targetcopy <--> source - // --> [process: targetcopy.removeTargeter(source); targetcopy.addTargeter(sourcecopy)] - // target source - // v - // targetcopy <--> sourcecopy - - // now deal with the old instruction's targeters. Update them all to point to us - // instead of the old instruction. We use updateTarget to do this. One goal is - // to make sure we remove all targeters from the old guy, so we can successfully - // delete it. - for (InstructionTargeter source : oldIh.getTargetersCopy()) { - if (source instanceof LocalVariableTag) { - Shadow.Kind kind = getKind(); - if (kind == Shadow.AdviceExecution || kind == Shadow.ConstructorExecution || kind == Shadow.MethodExecution - || kind == Shadow.PreInitialization || kind == Shadow.Initialization - || kind == Shadow.StaticInitialization) { - LocalVariableTag sourceLocalVariableTag = (LocalVariableTag) source; - if (sourceLocalVariableTag.getSlot() == 0) { - // might be 'this' so should be renamed if being dumped in a static method 277616 - if (sourceLocalVariableTag.getName().equals("this")) { - sourceLocalVariableTag.setName("ajc$this"); - } - } - // if we're extracting a whole block we can do this... - source.updateTarget(oldIh, freshIh); - } else { - // XXX destroying local variable info - // but only for a call or get join point, so no big deal - source.updateTarget(oldIh, null); - } - } else if (source instanceof Range) { - // exceptions and shadows are just moved - ((Range) source).updateTarget(oldIh, freshIh, freshBody); - } else { - // line numbers can be shared, - // branches will be copied along with us. - source.updateTarget(oldIh, freshIh); - } - } - // we're now done with the old instruction entirely, and will ignore them through - // the rest of this loop. The only time we'll see them again is a second pass to - // delete them. - - // now deal with local variable instructions. If this points to a remapped - // frame location, update the instruction's index. If this doesn't, - // do compaction/expansion: allocate a new local variable, and modify the remap - // to handle it. XXX We're doing the safe thing and allocating ALL these local variables - // as double-wides, in case the location is found to hold a double-wide later. - if (freshI.isLocalVariableInstruction() || freshI instanceof RET) { - // IndexedInstruction indexedI = (IndexedInstruction) freshI; - int oldIndex = freshI.getIndex(); - int freshIndex; - if (!remap.hasKey(oldIndex)) { - freshIndex = freshMethod.allocateLocal(2); - remap.put(oldIndex, freshIndex); - } else { - freshIndex = remap.get(oldIndex); - } - if (freshI instanceof RET) { - freshI.setIndex(freshIndex); - } else { - freshI = ((InstructionLV) freshI).setIndexAndCopyIfNecessary(freshIndex); - freshIh.setInstruction(freshI); - } - } - // System.err.println("JUST COPIED: " + - // oldIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool()) - // + " INTO " + - // freshIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool())); - } - - // now go through again and update variable slots that have been altered as a result - // of remapping... - for (InstructionHandle newIh = freshBody.getStart(); newIh != freshBody.getEnd(); newIh = newIh.getNext()) { - Iterator<InstructionTargeter> tIter = newIh.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter source = tIter.next(); - if (source instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) source; - if (!lvt.isRemapped() && remap.hasKey(lvt.getSlot())) { - lvt.updateSlot(remap.get(lvt.getSlot())); - } - } - } - } - - // we've now copied out all the instructions. - // now delete the instructions... we've already taken care of the damn - // targets, but since TargetLostException is checked, we have to do this stuff. - try { - for (InstructionHandle oldIh = start.getNext(); oldIh != end;) { - InstructionHandle next = oldIh.getNext(); - body.delete(oldIh); - oldIh = next; - } - } catch (TargetLostException e) { - throw new BCException("shouldn't have gotten a target lost"); - } - - // now add the return, if one is warranted. - InstructionHandle ret = null; - if (addReturn) { - // we really should pull this out somewhere... - ret = freshBody.append(InstructionFactory.createReturn(freshMethod.getReturnType())); - } - // and remap all the old targeters of the end handle of the range to the return. - for (InstructionTargeter t : end.getTargetersCopy()) { - if (t == this) { - continue; - } - if (!addReturn) { - throw new BCException("range has target, but we aren't adding a return"); - } else { - t.updateTarget(end, ret); - } - } - - LazyMethodGen.assertGoodBody(getBody(), toString()); - freshMethod.assertGoodBody(); - } - - public BcelShadow getShadow() { - return shadow; - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/TypeAnnotationAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/TypeAnnotationAccessVar.java deleted file mode 100644 index e23174389..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/TypeAnnotationAccessVar.java +++ /dev/null @@ -1,80 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005 IBM - * 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: - * Andy Clement initial implementation - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; - -/** - * Used for @this() @target() @args() - represents accessing an annotated 'thing'. Main use is to create the instructions that - * retrieve the annotation from the 'thing' - see createLoadInstructions() - */ -public class TypeAnnotationAccessVar extends BcelVar { - - private BcelVar target; - - public TypeAnnotationAccessVar(ResolvedType type, BcelVar theAnnotatedTargetIsStoredHere) { - super(type, 0); - target = theAnnotatedTargetIsStoredHere; - } - - public String toString() { - return "TypeAnnotationAccessVar(" + getType() + ")"; - } - - public Instruction createLoad(InstructionFactory fact) { - throw new RuntimeException("unimplemented"); - } - - public Instruction createStore(InstructionFactory fact) { - throw new RuntimeException("unimplemented"); - } - - public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { - throw new RuntimeException("unimplemented"); - } - - public void appendLoad(InstructionList il, InstructionFactory fact) { - il.append(createLoadInstructions(getType(), fact)); - } - - public InstructionList createLoadInstructions(ResolvedType toType, InstructionFactory fact) { - InstructionList il = new InstructionList(); - Type jlClass = BcelWorld.makeBcelType(UnresolvedType.JL_CLASS); - Type jlaAnnotation = BcelWorld.makeBcelType(UnresolvedType.ANNOTATION); - il.append(target.createLoad(fact)); - il.append(fact.createInvoke("java/lang/Object", "getClass", jlClass, new Type[] {}, Constants.INVOKEVIRTUAL)); - il.append(fact.createConstant(new ObjectType(toType.getName()))); - il.append(fact.createInvoke("java/lang/Class", "getAnnotation", jlaAnnotation, new Type[] { jlClass }, - Constants.INVOKEVIRTUAL)); - il.append(Utility.createConversion(fact, jlaAnnotation, BcelWorld.makeBcelType(toType))); - return il; - - } - - public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedType toType) { - il.append(createLoadInstructions(toType, fact)); - - } - - public void insertLoad(InstructionList il, InstructionFactory fact) { - il.insert(createLoadInstructions(getType(), fact)); - } - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/TypeDelegateResolver.java b/weaver/src/org/aspectj/weaver/bcel/TypeDelegateResolver.java deleted file mode 100644 index 2a29c927a..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/TypeDelegateResolver.java +++ /dev/null @@ -1,28 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 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: - * Andy Clement, SpringSource - * ******************************************************************/ -package org.aspectj.weaver.bcel; - -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; - -/** - * A type delegate resolver is able to create type delegates for a named reference type. A type delegate will implement - * ReferenceTypeDelegate. There are three kind of delegate already in existence: those created for eclipse structures, those - * created for bytecode structures, and those created based on reflection. - * - * @author Andy Clement - */ -public interface TypeDelegateResolver { - - ReferenceTypeDelegate getDelegate(ReferenceType referenceType); - -} diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java deleted file mode 100644 index 7076316f7..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java +++ /dev/null @@ -1,200 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.util.FileUtil; -import org.aspectj.weaver.IUnwovenClassFile; - -public class UnwovenClassFile implements IUnwovenClassFile { - protected String filename; - protected char[] charfilename; - protected byte[] bytes; - // protected JavaClass javaClass = null; - // protected byte[] writtenBytes = null; - protected List<ChildClass> writtenChildClasses = Collections.emptyList(); - protected String className = null; - protected boolean isModule = false; - - public UnwovenClassFile(String filename, byte[] bytes) { - this.filename = filename; - this.isModule = filename.toLowerCase().endsWith("module-info.java"); - this.bytes = bytes; - } - - /** Use if the classname is known, saves a bytecode parse */ - public UnwovenClassFile(String filename, String classname, byte[] bytes) { - this.filename = filename; - this.isModule = filename.toLowerCase().endsWith("module-info.class"); - this.className = classname; - this.bytes = bytes; - } - - public boolean shouldBeWoven() { - // Skip module-info files for now, they aren't really types - return !isModule; - } - - public String getFilename() { - return filename; - } - - public String makeInnerFileName(String innerName) { - String prefix = filename.substring(0, filename.length() - 6); // strip the .class - return prefix + "$" + innerName + ".class"; - } - - public byte[] getBytes() { - // if (bytes == null) bytes = javaClass.getBytes(); - return bytes; - } - - public JavaClass getJavaClass() { - // XXX need to know when to make a new class and when not to - // XXX this is an important optimization - if (getBytes() == null) { - System.out.println("no bytes for: " + getFilename()); - // Thread.currentThread().dumpStack(); - Thread.dumpStack(); - } - return Utility.makeJavaClass(filename, getBytes()); - // if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes()); - // return javaClass; - } - - public void writeUnchangedBytes() throws IOException { - writeWovenBytes(getBytes(), Collections.<ChildClass>emptyList()); - } - - public void writeWovenBytes(byte[] bytes, List<ChildClass> childClasses) throws IOException { - writeChildClasses(childClasses); - - // System.err.println("should write: " + getClassName()); - - // System.err.println("about to write: " + this + ", " + writtenBytes + ", "); - // + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) ); - - // if (writtenBytes != null && unchanged(bytes, writtenBytes)) return; - - // System.err.println(" actually wrote it"); - - BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename)); - os.write(bytes); - os.close(); - - // writtenBytes = bytes; - } - - private void writeChildClasses(List<ChildClass> childClasses) throws IOException { - // ??? we only really need to delete writtenChildClasses whose - // ??? names aren't in childClasses; however, it's unclear - // ??? how much that will affect performance - deleteAllChildClasses(); - - childClasses.removeAll(writtenChildClasses); // XXX is this right - - for (ChildClass childClass : childClasses) { - writeChildClassFile(childClass.name, childClass.bytes); - } - - writtenChildClasses = childClasses; - - } - - private void writeChildClassFile(String innerName, byte[] bytes) throws IOException { - BufferedOutputStream os = FileUtil.makeOutputStream(new File(makeInnerFileName(innerName))); - os.write(bytes); - os.close(); - } - - protected void deleteAllChildClasses() { - for (ChildClass childClass : writtenChildClasses) { - deleteChildClassFile(childClass.name); - } - } - - protected void deleteChildClassFile(String innerName) { - File childClassFile = new File(makeInnerFileName(innerName)); - childClassFile.delete(); - } - - /* private */static boolean unchanged(byte[] b1, byte[] b2) { - int len = b1.length; - if (b2.length != len) - return false; - for (int i = 0; i < len; i++) { - if (b1[i] != b2[i]) - return false; - } - return true; - } - - public char[] getClassNameAsChars() { - if (charfilename == null) { - charfilename = getClassName().replace('.', '/').toCharArray(); - } - return charfilename; - } - - public String getClassName() { - if (className == null) - className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely? - return className; - } - - @Override - public String toString() { - return "UnwovenClassFile(" + filename + ", " + getClassName() + ")"; - } - - // record - // OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put - // it back on! - public static class ChildClass { - public final String name; - public final byte[] bytes; - - ChildClass(String name, byte[] bytes) { - this.name = name; - this.bytes = bytes; - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof ChildClass)) - return false; - ChildClass o = (ChildClass) other; - return o.name.equals(name) && unchanged(o.bytes, bytes); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public String toString() { - return "(ChildClass " + name + ")"; - } - } - - public void setClassNameAsChars(char[] classNameAsChars) { - this.charfilename = classNameAsChars; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java deleted file mode 100644 index 18edc8413..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFileWithThirdPartyManagedBytecode.java +++ /dev/null @@ -1,36 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2004 IBM Corporation and others. - * 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: - * IBM Corporation - initial API and implementation - *******************************************************************************/ -package org.aspectj.weaver.bcel; - -/** - * @author colyer This subclass of UnwovenClassFile allows a third-party to manage the actual bytes that comprise the class. This - * means the third party can return a reference to an existing array, or create the bytes on demand, or apply any other - * strategy that makes sense. By refering to bytes held elsewhere, the goal is to reduce the overall memory consumption by - * not holding a copy. - */ -public class UnwovenClassFileWithThirdPartyManagedBytecode extends UnwovenClassFile { - - IByteCodeProvider provider; - - public interface IByteCodeProvider { - byte[] getBytes(); - } - - // OPTIMIZE make classname an input char[] - public UnwovenClassFileWithThirdPartyManagedBytecode(String filename, String classname, IByteCodeProvider provider) { - super(filename, classname, null); - this.provider = provider; - } - - public byte[] getBytes() { - return provider.getBytes(); - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/Utility.java b/weaver/src/org/aspectj/weaver/bcel/Utility.java deleted file mode 100644 index 4acf032fc..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/Utility.java +++ /dev/null @@ -1,719 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.bcel; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; - -import org.aspectj.apache.bcel.Constants; -import org.aspectj.apache.bcel.classfile.Attribute; -import org.aspectj.apache.bcel.classfile.ClassParser; -import org.aspectj.apache.bcel.classfile.ConstantPool; -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.Unknown; -import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue; -import org.aspectj.apache.bcel.classfile.annotation.ElementValue; -import org.aspectj.apache.bcel.classfile.annotation.NameValuePair; -import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue; -import org.aspectj.apache.bcel.generic.ArrayType; -import org.aspectj.apache.bcel.generic.BasicType; -import org.aspectj.apache.bcel.generic.Instruction; -import org.aspectj.apache.bcel.generic.InstructionByte; -import org.aspectj.apache.bcel.generic.InstructionCP; -import org.aspectj.apache.bcel.generic.InstructionConstants; -import org.aspectj.apache.bcel.generic.InstructionFactory; -import org.aspectj.apache.bcel.generic.InstructionHandle; -import org.aspectj.apache.bcel.generic.InstructionList; -import org.aspectj.apache.bcel.generic.InstructionSelect; -import org.aspectj.apache.bcel.generic.InstructionShort; -import org.aspectj.apache.bcel.generic.InstructionTargeter; -import org.aspectj.apache.bcel.generic.LineNumberTag; -import org.aspectj.apache.bcel.generic.ObjectType; -import org.aspectj.apache.bcel.generic.ReferenceType; -import org.aspectj.apache.bcel.generic.SwitchBuilder; -import org.aspectj.apache.bcel.generic.TargetLostException; -import org.aspectj.apache.bcel.generic.Type; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.weaver.AjAttribute; -import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; -import org.aspectj.weaver.AnnotationAJ; -import org.aspectj.weaver.BCException; -import org.aspectj.weaver.ConstantPoolReader; -import org.aspectj.weaver.ISourceContext; -import org.aspectj.weaver.Lint; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.Utils; -import org.aspectj.weaver.World; - -public class Utility { - - private final static char PACKAGE_INITIAL_CHAR = AjAttribute.AttributePrefix.charAt(0); - - public static List<AjAttribute> readAjAttributes(String classname, Attribute[] as, ISourceContext context, World w, - AjAttribute.WeaverVersionInfo version, ConstantPoolReader dataDecompressor) { - List<AjAttribute> attributes = new ArrayList<AjAttribute>(); - - // first pass, look for version - List<Unknown> forSecondPass = new ArrayList<Unknown>(); - for (int i = as.length - 1; i >= 0; i--) { - Attribute a = as[i]; - if (a instanceof Unknown) { - Unknown u = (Unknown) a; - String name = u.getName(); - if (name.charAt(0) == PACKAGE_INITIAL_CHAR) { // 'o'rg.aspectj - if (name.startsWith(AjAttribute.AttributePrefix)) { - if (name.endsWith(WeaverVersionInfo.AttributeName)) { - version = (AjAttribute.WeaverVersionInfo) AjAttribute.read(version, name, u.getBytes(), context, w, - dataDecompressor); - if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) { - throw new BCException( - "Unable to continue, this version of AspectJ supports classes built with weaver version " - + WeaverVersionInfo.toCurrentVersionString() + " but the class " + classname - + " is version " + version.toString() + ". Please update your AspectJ."); - } - } - forSecondPass.add(u); - } - } - } - } - - // FIXASC why going backwards? is it important - for (int i = forSecondPass.size() - 1; i >= 0; i--) { - Unknown a = forSecondPass.get(i); - String name = a.getName(); - AjAttribute attr = AjAttribute.read(version, name, a.getBytes(), context, w, dataDecompressor); - if (attr != null) { - attributes.add(attr); - } - } - return attributes; - } - - /* - * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave). - */ - public static String beautifyLocation(ISourceLocation isl) { - StringBuffer nice = new StringBuffer(); - if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().indexOf("no debug info available") != -1) { - nice.append("no debug info available"); - } else { - // can't use File.getName() as this fails when a Linux box - // encounters a path created on Windows and vice-versa - int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/'); - if (takeFrom == -1) { - takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\'); - } - nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1)); - if (isl.getLine() != 0) { - nice.append(":").append(isl.getLine()); - } - } - return nice.toString(); - } - - public static Instruction createSuperInvoke(InstructionFactory fact, BcelWorld world, Member signature) { - short kind; - if (Modifier.isInterface(signature.getModifiers())) { - throw new RuntimeException("bad"); - } else if (Modifier.isPrivate(signature.getModifiers()) || signature.getName().equals("<init>")) { - throw new RuntimeException("unimplemented, possibly bad"); - } else if (Modifier.isStatic(signature.getModifiers())) { - throw new RuntimeException("bad"); - } else { - kind = Constants.INVOKESPECIAL; - } - - return fact.createInvoke(signature.getDeclaringType().getName(), signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind); - } - - public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) { - short kind; - int signatureModifiers = signature.getModifiers(); - if (Modifier.isInterface(signatureModifiers)) { - kind = Constants.INVOKEINTERFACE; - } else if (Modifier.isStatic(signatureModifiers)) { - kind = Constants.INVOKESTATIC; - } else if (Modifier.isPrivate(signatureModifiers) || signature.getName().equals("<init>")) { - kind = Constants.INVOKESPECIAL; - } else { - kind = Constants.INVOKEVIRTUAL; - } - - UnresolvedType targetType = signature.getDeclaringType(); - if (targetType.isParameterizedType()) { - targetType = targetType.resolve(world).getGenericType(); - } - return fact.createInvoke(targetType.getName(), signature.getName(), BcelWorld.makeBcelType(signature.getReturnType()), - BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind); - } - - public static Instruction createGet(InstructionFactory fact, Member signature) { - short kind; - if (Modifier.isStatic(signature.getModifiers())) { - kind = Constants.GETSTATIC; - } else { - kind = Constants.GETFIELD; - } - - return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), kind); - } - - public static Instruction createSet(InstructionFactory fact, Member signature) { - short kind; - if (Modifier.isStatic(signature.getModifiers())) { - kind = Constants.PUTSTATIC; - } else { - kind = Constants.PUTFIELD; - } - - return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), kind); - } - - public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) { - int cpoolEntry = (t instanceof ArrayType) ? fact.getConstantPool().addArrayClass((ArrayType) t) : fact.getConstantPool() - .addClass((ObjectType) t); - return new InstructionCP(Constants.INSTANCEOF, cpoolEntry); - } - - public static Instruction createInvoke(InstructionFactory fact, LazyMethodGen m) { - short kind; - if (m.getEnclosingClass().isInterface()) { - if (m.isStatic()) { - // For static methods on interfaces - kind = Constants.INVOKESTATIC; - } else { - kind = Constants.INVOKEINTERFACE; - } - } else if (m.isStatic()) { - kind = Constants.INVOKESTATIC; - } else if (m.isPrivate() || m.getName().equals("<init>")) { - kind = Constants.INVOKESPECIAL; - } else { - kind = Constants.INVOKEVIRTUAL; - } - - return fact.createInvoke(m.getClassName(), m.getName(), m.getReturnType(), m.getArgumentTypes(), kind, m.getEnclosingClass().isInterface()); - } - - /** - * Create an invoke instruction - * - * @param fact - * @param kind INVOKEINTERFACE, INVOKEVIRTUAL.. - * @param member - * @return - */ - public static Instruction createInvoke(InstructionFactory fact, short kind, Member member) { - return fact.createInvoke(member.getDeclaringType().getName(), member.getName(), - BcelWorld.makeBcelType(member.getReturnType()), BcelWorld.makeBcelTypes(member.getParameterTypes()), kind); - } - - private static String[] argNames = new String[] { "arg0", "arg1", "arg2", "arg3", "arg4" }; - - // ??? these should perhaps be cached. Remember to profile this to see if - // it's a problem. - public static String[] makeArgNames(int n) { - String[] ret = new String[n]; - for (int i = 0; i < n; i++) { - if (i < 5) { - ret[i] = argNames[i]; - } else { - ret[i] = "arg" + i; - } - } - return ret; - } - - // Lookup table, for converting between pairs of types, it gives - // us the method name in the Conversions class - private static Hashtable<String, String> validBoxing = new Hashtable<String, String>(); - - static { - validBoxing.put("Ljava/lang/Byte;B", "byteObject"); - validBoxing.put("Ljava/lang/Character;C", "charObject"); - validBoxing.put("Ljava/lang/Double;D", "doubleObject"); - validBoxing.put("Ljava/lang/Float;F", "floatObject"); - validBoxing.put("Ljava/lang/Integer;I", "intObject"); - validBoxing.put("Ljava/lang/Long;J", "longObject"); - validBoxing.put("Ljava/lang/Short;S", "shortObject"); - validBoxing.put("Ljava/lang/Boolean;Z", "booleanObject"); - validBoxing.put("BLjava/lang/Byte;", "byteValue"); - validBoxing.put("CLjava/lang/Character;", "charValue"); - validBoxing.put("DLjava/lang/Double;", "doubleValue"); - validBoxing.put("FLjava/lang/Float;", "floatValue"); - validBoxing.put("ILjava/lang/Integer;", "intValue"); - validBoxing.put("JLjava/lang/Long;", "longValue"); - validBoxing.put("SLjava/lang/Short;", "shortValue"); - validBoxing.put("ZLjava/lang/Boolean;", "booleanValue"); - } - - public static void appendConversion(InstructionList il, InstructionFactory fact, ResolvedType fromType, ResolvedType toType) { - if (!toType.isConvertableFrom(fromType) && !fromType.isConvertableFrom(toType)) { - throw new BCException("can't convert from " + fromType + " to " + toType); - } - // XXX I'm sure this test can be simpler but my brain hurts and this works - World w = toType.getWorld(); - if (w == null) { // dbg349636 - throw new IllegalStateException("Debug349636: Unexpectedly found world null for type " + toType.getName()); - } - - if (!w.isInJava5Mode()) { - if (toType.needsNoConversionFrom(fromType)) { - return; - } - } else { - if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitiveType() ^ fromType.isPrimitiveType())) { - return; - } - } - if (toType.equals(UnresolvedType.VOID)) { - // assert fromType.equals(UnresolvedType.OBJECT) - il.append(InstructionFactory.createPop(fromType.getSize())); - } else if (fromType.equals(UnresolvedType.VOID)) { - // assert toType.equals(UnresolvedType.OBJECT) - il.append(InstructionFactory.createNull(Type.OBJECT)); - return; - } else if (fromType.equals(UnresolvedType.OBJECT)) { - Type to = BcelWorld.makeBcelType(toType); - if (toType.isPrimitiveType()) { - String name = toType.toString() + "Value"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT }, - Constants.INVOKESTATIC)); - } else { - il.append(fact.createCheckCast((ReferenceType) to)); - } - } else if (toType.equals(UnresolvedType.OBJECT)) { - // assert fromType.isPrimitive() - Type from = BcelWorld.makeBcelType(fromType); - String name = fromType.toString() + "Object"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from }, - Constants.INVOKESTATIC)); - } else if (toType.getWorld().isInJava5Mode() && validBoxing.get(toType.getSignature() + fromType.getSignature()) != null) { - // XXX could optimize by using any java boxing code that may be just - // before the call... - Type from = BcelWorld.makeBcelType(fromType); - Type to = BcelWorld.makeBcelType(toType); - String name = validBoxing.get(toType.getSignature() + fromType.getSignature()); - if (toType.isPrimitiveType()) { - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT }, - Constants.INVOKESTATIC)); - } else { - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from }, - Constants.INVOKESTATIC)); - il.append(fact.createCheckCast((ReferenceType) to)); - } - } else if (fromType.isPrimitiveType()) { - // assert toType.isPrimitive() - Type from = BcelWorld.makeBcelType(fromType); - Type to = BcelWorld.makeBcelType(toType); - try { - Instruction i = fact.createCast(from, to); - if (i != null) { - il.append(i); - } else { - il.append(fact.createCast(from, Type.INT)); - il.append(fact.createCast(Type.INT, to)); - } - } catch (RuntimeException e) { - il.append(fact.createCast(from, Type.INT)); - il.append(fact.createCast(Type.INT, to)); - } - } else { - Type to = BcelWorld.makeBcelType(toType); - // assert ! fromType.isPrimitive() && ! toType.isPrimitive() - il.append(fact.createCheckCast((ReferenceType) to)); - } - } - - public static InstructionList createConversion(InstructionFactory factory, Type fromType, Type toType) { - return createConversion(factory, fromType, toType, false); - } - - public static InstructionList createConversion(InstructionFactory fact, Type fromType, Type toType, boolean allowAutoboxing) { - // System.out.println("cast to: " + toType); - - InstructionList il = new InstructionList(); - - // PR71273 - if ((fromType.equals(Type.BYTE) || fromType.equals(Type.CHAR) || fromType.equals(Type.SHORT)) && (toType.equals(Type.INT))) { - return il; - } - - if (fromType.equals(toType)) { - return il; - } - if (toType.equals(Type.VOID)) { - il.append(InstructionFactory.createPop(fromType.getSize())); - return il; - } - - if (fromType.equals(Type.VOID)) { - if (toType instanceof BasicType) { - throw new BCException("attempting to cast from void to basic type"); - } - il.append(InstructionFactory.createNull(Type.OBJECT)); - return il; - } - - if (fromType.equals(Type.OBJECT)) { - if (toType instanceof BasicType) { - String name = toType.toString() + "Value"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT }, - Constants.INVOKESTATIC)); - return il; - } - } - - if (toType.equals(Type.OBJECT)) { - if (fromType instanceof BasicType) { - String name = fromType.toString() + "Object"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType }, - Constants.INVOKESTATIC)); - return il; - } else if (fromType instanceof ReferenceType) { - return il; - } else { - throw new RuntimeException(); - } - } - - if (fromType instanceof ReferenceType && ((ReferenceType) fromType).isAssignmentCompatibleWith(toType)) { - return il; - } - - if (allowAutoboxing) { - if (toType instanceof BasicType && fromType instanceof ReferenceType) { - // unboxing - String name = toType.toString() + "Value"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT }, - Constants.INVOKESTATIC)); - return il; - } - - if (fromType instanceof BasicType && toType instanceof ReferenceType) { - // boxing - String name = fromType.toString() + "Object"; - il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType }, - Constants.INVOKESTATIC)); - il.append(fact.createCast(Type.OBJECT, toType)); - return il; - } - } - - il.append(fact.createCast(fromType, toType)); - return il; - } - - public static Instruction createConstant(InstructionFactory fact, int value) { - Instruction inst; - switch (value) { - case -1: - inst = InstructionConstants.ICONST_M1; - break; - case 0: - inst = InstructionConstants.ICONST_0; - break; - case 1: - inst = InstructionConstants.ICONST_1; - break; - case 2: - inst = InstructionConstants.ICONST_2; - break; - case 3: - inst = InstructionConstants.ICONST_3; - break; - case 4: - inst = InstructionConstants.ICONST_4; - break; - case 5: - inst = InstructionConstants.ICONST_5; - break; - default: - if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { - inst = new InstructionByte(Constants.BIPUSH, (byte) value); - } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { - inst = new InstructionShort(Constants.SIPUSH, (short) value); - } else { - int ii = fact.getClassGen().getConstantPool().addInteger(value); - inst = new InstructionCP(value <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, ii); - } - break; - } - return inst; - } - - /** For testing purposes: bit clunky but does work */ - public static int testingParseCounter = 0; - - public static JavaClass makeJavaClass(String filename, byte[] bytes) { - try { - testingParseCounter++; - ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename); - return parser.parse(); - } catch (IOException e) { - throw new BCException("malformed class file"); - } - } - - /** - * replace an instruction handle with another instruction, in this case, a branch instruction. - * - * @param ih the instruction handle to replace. - * @param branchInstruction the branch instruction to replace ih with - * @param enclosingMethod where to find ih's instruction list. - */ - public static void replaceInstruction(InstructionHandle ih, InstructionList replacementInstructions, - LazyMethodGen enclosingMethod) { - InstructionList il = enclosingMethod.getBody(); - InstructionHandle fresh = il.append(ih, replacementInstructions); - deleteInstruction(ih, fresh, enclosingMethod); - } - - /** - * delete an instruction handle and retarget all targeters of the deleted instruction to the next instruction. Obviously, this - * should not be used to delete a control transfer instruction unless you know what you're doing. - * - * @param ih the instruction handle to delete. - * @param enclosingMethod where to find ih's instruction list. - */ - public static void deleteInstruction(InstructionHandle ih, LazyMethodGen enclosingMethod) { - deleteInstruction(ih, ih.getNext(), enclosingMethod); - } - - /** - * delete an instruction handle and retarget all targeters of the deleted instruction to the provided target. - * - * @param ih the instruction handle to delete - * @param retargetTo the instruction handle to retarget targeters of ih to. - * @param enclosingMethod where to find ih's instruction list. - */ - public static void deleteInstruction(InstructionHandle ih, InstructionHandle retargetTo, LazyMethodGen enclosingMethod) { - InstructionList il = enclosingMethod.getBody(); - for (InstructionTargeter targeter : ih.getTargetersCopy()) { - targeter.updateTarget(ih, retargetTo); - } - ih.removeAllTargeters(); - try { - il.delete(ih); - } catch (TargetLostException e) { - throw new BCException("this really can't happen"); - } - } - - /** - * Fix for Bugzilla #39479, #40109 patch contributed by Andy Clement - * - * Need to manually copy Select instructions - if we rely on the the 'fresh' object created by copy(), the InstructionHandle - * array 'targets' inside the Select object will not have been deep copied, so modifying targets in fresh will modify the - * original Select - not what we want ! (It is a bug in BCEL to do with cloning Select objects). - * - * <pre> - * declare error: - * call(* Instruction.copy()) && within(org.aspectj.weaver) - * && !withincode(* Utility.copyInstruction(Instruction)): - * "use Utility.copyInstruction to work-around bug in Select.copy()"; - * </pre> - */ - public static Instruction copyInstruction(Instruction i) { - if (i instanceof InstructionSelect) { - InstructionSelect freshSelect = (InstructionSelect) i; - - // Create a new targets array that looks just like the existing one - InstructionHandle[] targets = new InstructionHandle[freshSelect.getTargets().length]; - for (int ii = 0; ii < targets.length; ii++) { - targets[ii] = freshSelect.getTargets()[ii]; - } - - // Create a new select statement with the new targets array - - return new SwitchBuilder(freshSelect.getMatchs(), targets, freshSelect.getTarget()).getInstruction(); - } else { - return i.copy(); // Use clone for shallow copy... - } - } - - /** returns -1 if no source line attribute */ - // this naive version overruns the JVM stack size, if only Java understood - // tail recursion... - // public static int getSourceLine(InstructionHandle ih) { - // if (ih == null) return -1; - // - // InstructionTargeter[] ts = ih.getTargeters(); - // if (ts != null) { - // for (int j = ts.length - 1; j >= 0; j--) { - // InstructionTargeter t = ts[j]; - // if (t instanceof LineNumberTag) { - // return ((LineNumberTag)t).getLineNumber(); - // } - // } - // } - // return getSourceLine(ih.getNext()); - // } - public static int getSourceLine(InstructionHandle ih) {// ,boolean - // goforwards) { - int lookahead = 0; - // arbitrary rule that we will never lookahead more than 100 - // instructions for a line # - while (lookahead++ < 100) { - if (ih == null) { - return -1; - } - Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter t = tIter.next(); - if (t instanceof LineNumberTag) { - return ((LineNumberTag) t).getLineNumber(); - } - } - // if (goforwards) ih=ih.getNext(); else - ih = ih.getPrev(); - } - // System.err.println("no line information available for: " + ih); - return -1; - } - - // public static int getSourceLine(InstructionHandle ih) { - // return getSourceLine(ih,false); - // } - - // assumes that there is no already extant source line tag. Otherwise we'll - // have to be better. - public static void setSourceLine(InstructionHandle ih, int lineNumber) { - // OPTIMIZE LineNumberTag instances for the same line could be shared - // throughout a method... - ih.addTargeter(new LineNumberTag(lineNumber)); - } - - public static int makePublic(int i) { - return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC; - } - - public static BcelVar[] pushAndReturnArrayOfVars(ResolvedType[] proceedParamTypes, InstructionList il, InstructionFactory fact, - LazyMethodGen enclosingMethod) { - int len = proceedParamTypes.length; - BcelVar[] ret = new BcelVar[len]; - - for (int i = len - 1; i >= 0; i--) { - ResolvedType typeX = proceedParamTypes[i]; - Type type = BcelWorld.makeBcelType(typeX); - int local = enclosingMethod.allocateLocal(type); - - il.append(InstructionFactory.createStore(type, local)); - ret[i] = new BcelVar(typeX, local); - } - return ret; - } - - public static boolean isConstantPushInstruction(Instruction i) { - long ii = Constants.instFlags[i.opcode]; - return ((ii & Constants.PUSH_INST) != 0 && (ii & Constants.CONSTANT_INST) != 0); - } - - /** - * Checks for suppression specified on the member or on the declaring type of that member - */ - public static boolean isSuppressing(Member member, String lintkey) { - boolean isSuppressing = Utils.isSuppressing(member.getAnnotations(), lintkey); - if (isSuppressing) { - return true; - } - UnresolvedType type = member.getDeclaringType(); - if (type instanceof ResolvedType) { - return Utils.isSuppressing(((ResolvedType) type).getAnnotations(), lintkey); - } - return false; - } - - public static List<Lint.Kind> getSuppressedWarnings(AnnotationAJ[] anns, Lint lint) { - if (anns == null) { - return Collections.emptyList(); - } - // Go through the annotation types - List<Lint.Kind> suppressedWarnings = new ArrayList<Lint.Kind>(); - boolean found = false; - for (int i = 0; !found && i < anns.length; i++) { - // Check for the SuppressAjWarnings annotation - if (UnresolvedType.SUPPRESS_AJ_WARNINGS.getSignature().equals( - ((BcelAnnotation) anns[i]).getBcelAnnotation().getTypeSignature())) { - found = true; - // Two possibilities: - // 1. there are no values specified (i.e. @SuppressAjWarnings) - // 2. there are values specified (i.e. @SuppressAjWarnings("A") - // or @SuppressAjWarnings({"A","B"}) - List<NameValuePair> vals = ((BcelAnnotation) anns[i]).getBcelAnnotation().getValues(); - if (vals == null || vals.isEmpty()) { // (1) - suppressedWarnings.addAll(lint.allKinds()); - } else { // (2) - // We know the value is an array value - ArrayElementValue array = (ArrayElementValue) (vals.get(0)).getValue(); - ElementValue[] values = array.getElementValuesArray(); - for (int j = 0; j < values.length; j++) { - // We know values in the array are strings - SimpleElementValue value = (SimpleElementValue) values[j]; - Lint.Kind lintKind = lint.getLintKind(value.getValueString()); - if (lintKind != null) { - suppressedWarnings.add(lintKind); - } - } - } - } - } - return suppressedWarnings; - } - - // not yet used... - // public static boolean isSimple(Method method) { - // if (method.getCode()==null) return true; - // if (method.getCode().getCode().length>10) return false; - // InstructionList instrucs = new - // InstructionList(method.getCode().getCode()); // expensive! - // InstructionHandle InstrHandle = instrucs.getStart(); - // while (InstrHandle != null) { - // Instruction Instr = InstrHandle.getInstruction(); - // int opCode = Instr.opcode; - // // if current instruction is a branch instruction, see if it's a backward - // branch. - // // if it is return immediately (can't be trivial) - // if (Instr instanceof InstructionBranch) { - // // InstructionBranch BI = (InstructionBranch) Instr; - // if (Instr.getIndex() < 0) return false; - // } else if (Instr instanceof InvokeInstruction) { - // // if current instruction is an invocation, indicate that it can't be - // trivial - // return false; - // } - // InstrHandle = InstrHandle.getNext(); - // } - // return true; - // } - - public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) { - int nameIndex = pool.addUtf8(a.getNameString()); - byte[] bytes = a.getBytes(new BcelConstantPoolWriter(pool)); - int length = bytes.length; - - return new Unknown(nameIndex, length, bytes, pool); - } -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java b/weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java deleted file mode 100644 index 5d5bb6990..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/asm/AsmDetector.java +++ /dev/null @@ -1,36 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008 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: - * Andy Clement - * ******************************************************************/ -package org.aspectj.weaver.bcel.asm; - -import java.lang.reflect.Method; - -/** - * Determines if a version of asm is around that will enable us to add stack map attributes to classes that we produce. - * - * @author Andy Clement - */ -public class AsmDetector { - - public static boolean isAsmAround; - - static { - try { - Class<?> reader = Class.forName("aj.org.objectweb.asm.ClassReader"); - Class<?> visitor = Class.forName("aj.org.objectweb.asm.ClassVisitor"); - Method m = reader.getMethod("accept", new Class[] { visitor, Integer.TYPE }); - isAsmAround = m != null; - } catch (Exception e) { - isAsmAround = false; - } - // System.out.println(isAsmAround?"ASM detected":"No ASM found"); - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java b/weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java deleted file mode 100644 index dd3965b61..000000000 --- a/weaver/src/org/aspectj/weaver/bcel/asm/StackMapAdder.java +++ /dev/null @@ -1,121 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2008, 2018 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: - * Andy Clement - * ******************************************************************/ -package org.aspectj.weaver.bcel.asm; - -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; - -import aj.org.objectweb.asm.ClassReader; -import aj.org.objectweb.asm.ClassVisitor; -import aj.org.objectweb.asm.ClassWriter; -import aj.org.objectweb.asm.MethodVisitor; -import aj.org.objectweb.asm.Opcodes; - -/** - * Uses asm to add the stack map attribute to methods in a class. The class is passed in as pure byte data and then a reader/writer - * process it. The writer is wired into the world so that types can be resolved and getCommonSuperClass() can be implemented without - * class loading using the context class loader. - * - * It is important that the constant pool is preserved here and asm does not try to remove unused entries. That is because some - * entries are refered to from classfile attributes. Asm cannot see into these attributes so does not realise the constant pool - * entries are in use. In order to ensure the copying of cp occurs, we use the variant super constructor call in AspectJConnectClassWriter - * that passes in the classreader. However, ordinarily that change causes a further optimization: that if a classreader sees - * a methodvisitor that has been created by a ClassWriter then it just copies the data across without changing it (and so it - * fails to attach the stackmapattribute). In order to avoid this further optimization we use our own minimal MethodVisitor. - * - * @author Andy Clement - */ -public class StackMapAdder { - - public static byte[] addStackMaps(World world, byte[] data) { - try { - ClassReader cr = new ClassReader(data); - ClassWriter cw = new AspectJConnectClassWriter(cr, world); - ClassVisitor cv = new AspectJClassVisitor(cw); - cr.accept(cv, 0); - return cw.toByteArray(); - } catch (Throwable t) { - System.err.println("AspectJ Internal Error: unable to add stackmap attributes. " + t.getMessage()); - AsmDetector.isAsmAround = false; - return data; - } - } - - private static class AspectJClassVisitor extends ClassVisitor { - - public AspectJClassVisitor(ClassVisitor classwriter) { - super(Opcodes.ASM7, classwriter); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - return new AJMethodVisitor(mv); - } - - // Minimal pass through MethodVisitor just so that the ClassReader doesn't see one that has been directly - // created by a ClassWriter (see top level class comment) - static class AJMethodVisitor extends MethodVisitor { - public AJMethodVisitor(MethodVisitor mv) { - super(Opcodes.ASM7,mv); - } - } - - } - - private static class AspectJConnectClassWriter extends ClassWriter { - private final World world; - - public AspectJConnectClassWriter(ClassReader cr, World w) { - super(cr, ClassWriter.COMPUTE_FRAMES); // passing in cr is necessary so cpool isnt modified (see 2.2.4 of asm doc) - this.world = w; - } - - - // Implementation of getCommonSuperClass() that avoids Class.forName() - @Override - protected String getCommonSuperClass(final String type1, final String type2) { - - ResolvedType resolvedType1 = world.resolve(UnresolvedType.forName(type1.replace('/', '.'))); - ResolvedType resolvedType2 = world.resolve(UnresolvedType.forName(type2.replace('/', '.'))); - - if (resolvedType1.isAssignableFrom(resolvedType2)) { - return type1; - } - - if (resolvedType2.isAssignableFrom(resolvedType1)) { - return type2; - } - - if (resolvedType1.isInterface() || resolvedType2.isInterface()) { - return "java/lang/Object"; - } else { - do { - resolvedType1 = resolvedType1.getSuperclass(); - if (resolvedType1 == null) { - // This happens if some types are missing, the getSuperclass() call on - // MissingResolvedTypeWithKnownSignature will return the Missing type which - // in turn returns a superclass of null. By returning Object here it - // should surface the cantFindType message raised in the first problematic - // getSuperclass call - return "java/lang/Object"; - } - if (resolvedType1.isParameterizedOrGenericType()) { - resolvedType1 = resolvedType1.getRawType(); - } - } while (!resolvedType1.isAssignableFrom(resolvedType2)); - return resolvedType1.getRawName().replace('.', '/'); - } - } - } -} diff --git a/weaver/src/org/aspectj/weaver/loadtime/IWeavingContext.java b/weaver/src/org/aspectj/weaver/loadtime/IWeavingContext.java deleted file mode 100644 index 51b781e86..000000000 --- a/weaver/src/org/aspectj/weaver/loadtime/IWeavingContext.java +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * David Knibb initial implementation - *******************************************************************************/ -package org.aspectj.weaver.loadtime; - -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import java.util.List; - -import org.aspectj.weaver.loadtime.definition.Definition; -import org.aspectj.weaver.tools.WeavingAdaptor; - -/** - * This class adds support to AspectJ for an OSGi environment - * - * @author David Knibb - */ -public interface IWeavingContext { - - /** - * Allows the standard ClassLoader.getResources() mechanisms to be - * replaced with a different implementation. - * In an OSGi environment, this will allow for filtering to take - * place on the results of ClassLoader.getResources(). In a non-OSGi - * environment, ClassLoader.getResources should be returned. - * @param name the name of the resource to search for - * @return an enumeration containing all of the matching resources found - * @throws IOException - */ - public Enumeration<URL> getResources(String name) throws IOException; - - /** - * In an OSGi environment, determin which bundle a URL originated from. - * In a non-OSGi environment, implementors should return <code>null<code>. - * @param url - * @return - * @deprecated use getFile() or getClassLoaderName() - */ - public String getBundleIdFromURL(URL url); - - /** - * In an environment with multiple class loaders allows each to be - * identified using something safer and possibly shorter than toString - * @return name of the associated class loader - */ - public String getClassLoaderName (); - - public ClassLoader getClassLoader(); - - /** - * Format a URL - * @return filename - */ - public String getFile(URL url); - - /** - * In an environment with multiple class loaders allows messages - * to identified according to the weaving context - * @return short name - */ - public String getId (); - - /** - * Return true if the classloader associated with this weaving context - * is the one that will define the class with the specified name. - * In a delegating classloader hierarchy this might check the parent won't - * define it and the child will - in OSGi it will do something else. - * @param classname name of the class, eg. "java.lang.String" - * @return true if the associated classloader will define the class - */ - public boolean isLocallyDefined(String classname); - - /** - * Allow custom parsing of aop.xml or alternative mechanism for providing - * Definitions - * - * @param loader - * @param adaptor - * @return List containing 0 or more Definition instances - */ - public List<Definition> getDefinitions(final ClassLoader loader, WeavingAdaptor adaptor); - -} diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java b/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java deleted file mode 100644 index de780156e..000000000 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/Definition.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Alexandre Vasseur initial implementation - *******************************************************************************/ -package org.aspectj.weaver.loadtime.definition; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A POJO that contains raw strings from the XML (sort of XMLBean for our simple LTW DTD) - * - * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a> - */ -public class Definition { - - private final StringBuffer weaverOptions; - private final List<String> dumpPatterns; - private boolean dumpBefore; - private boolean perClassloaderDumpDir; - private final List<String> includePatterns; - private final List<String> excludePatterns; - private final List<String> aspectClassNames; - private final List<String> aspectExcludePatterns; - private final List<String> aspectIncludePatterns; - private final List<Definition.ConcreteAspect> concreteAspects; - - /** - * When aspects are defined, they can specify a scope type pattern and then will only apply to types matching that pattern. - */ - private final Map<String, String> scopedAspects; - - /** - * Some aspects (from aspect libraries) will describe a type that must be around for them to function properly - */ - private final Map<String, String> requiredTypesForAspects; - - public Definition() { - weaverOptions = new StringBuffer(); - dumpBefore = false; - perClassloaderDumpDir = false; - dumpPatterns = new ArrayList<String>(); - includePatterns = new ArrayList<String>(); - excludePatterns = new ArrayList<String>(); - aspectClassNames = new ArrayList<String>(); - aspectExcludePatterns = new ArrayList<String>(); - aspectIncludePatterns = new ArrayList<String>(); - concreteAspects = new ArrayList<Definition.ConcreteAspect>(); - scopedAspects = new HashMap<String, String>(); - requiredTypesForAspects = new HashMap<String, String>(); - } - - public String getWeaverOptions() { - return weaverOptions.toString(); - } - - public List<String> getDumpPatterns() { - return dumpPatterns; - } - - public void setDumpBefore(boolean b) { - dumpBefore = b; - } - - public boolean shouldDumpBefore() { - return dumpBefore; - } - - public void setCreateDumpDirPerClassloader(boolean b) { - perClassloaderDumpDir = b; - } - - public boolean createDumpDirPerClassloader() { - return perClassloaderDumpDir; - } - - public List<String> getIncludePatterns() { - return includePatterns; - } - - public List<String> getExcludePatterns() { - return excludePatterns; - } - - public List<String> getAspectClassNames() { - return aspectClassNames; - } - - public List<String> getAspectExcludePatterns() { - return aspectExcludePatterns; - } - - public List<String> getAspectIncludePatterns() { - return aspectIncludePatterns; - } - - public List<Definition.ConcreteAspect> getConcreteAspects() { - return concreteAspects; - } - - public static class ConcreteAspect { - public final String name; - public final String extend; - public final String precedence; - public final List<Definition.Pointcut> pointcuts; - public final List<Definition.DeclareAnnotation> declareAnnotations; - public final List<Definition.PointcutAndAdvice> pointcutsAndAdvice; - public final String perclause; - public List<Definition.DeclareErrorOrWarning> deows; - - public ConcreteAspect(String name, String extend) { - this(name, extend, null, null); - } - - public ConcreteAspect(String name, String extend, String precedence, String perclause) { - this.name = name; - // make sure extend set to null if "" - if (extend == null || extend.length() == 0) { - this.extend = null; - if (precedence == null || precedence.length() == 0) { - // if (pointcutsAndAdvice.size() == 0) { - // throw new RuntimeException("Not allowed"); - // } - } - } else { - this.extend = extend; - } - this.precedence = precedence; - this.pointcuts = new ArrayList<Definition.Pointcut>(); - this.declareAnnotations = new ArrayList<Definition.DeclareAnnotation>(); - this.pointcutsAndAdvice = new ArrayList<Definition.PointcutAndAdvice>(); - this.deows = new ArrayList<Definition.DeclareErrorOrWarning>(); - this.perclause = perclause; - } - } - - public static class Pointcut { - public final String name; - public final String expression; - - public Pointcut(String name, String expression) { - this.name = name; - this.expression = expression; - } - } - - public enum AdviceKind { - Before, After, AfterReturning, AfterThrowing, Around; - } - - public enum DeclareAnnotationKind { - Method, Field, Type; - } - - public static class DeclareAnnotation { - public final DeclareAnnotationKind declareAnnotationKind; - public final String pattern; - public final String annotation; - - public DeclareAnnotation(DeclareAnnotationKind kind, String pattern, String annotation) { - this.declareAnnotationKind = kind; - this.pattern = pattern; - this.annotation = annotation; - } - } - - public static class PointcutAndAdvice { - public final AdviceKind adviceKind; - public final String pointcut; - public final String adviceClass; // com.foo.Bar - public final String adviceMethod; // foo(java.lang.String,org.aspectj.lang.JoinPoint) - - public PointcutAndAdvice(AdviceKind adviceKind, String pointcut, String adviceClass, String adviceMethod) { - this.adviceKind = adviceKind; - this.pointcut = pointcut; - this.adviceClass = adviceClass; - this.adviceMethod = adviceMethod; - } - } - - public static class DeclareErrorOrWarning { - public final boolean isError; - public final String pointcut; - public final String message; - - public DeclareErrorOrWarning(boolean isError, String pointcut, String message) { - this.isError = isError; - this.pointcut = pointcut; - this.message = message; - } - } - - public void appendWeaverOptions(String option) { - weaverOptions.append(option.trim()).append(' '); - } - - public void addScopedAspect(String name, String scopePattern) { - scopedAspects.put(name, scopePattern); - } - - public String getScopeForAspect(String name) { - return scopedAspects.get(name); - } - - public void setAspectRequires(String name, String requiredType) { - requiredTypesForAspects.put(name, requiredType); - } - - public String getAspectRequires(String name) { - return requiredTypesForAspects.get(name); - } - -} diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java b/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java deleted file mode 100644 index 7ff275fd7..000000000 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/DocumentParser.java +++ /dev/null @@ -1,382 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Alexandre Vasseur initial implementation - * Abraham Nevado - Lucierna simple caching strategy - *******************************************************************************/ -package org.aspectj.weaver.loadtime.definition; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Hashtable; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParserFactory; - -import org.aspectj.util.LangUtil; -import org.aspectj.weaver.loadtime.definition.Definition.AdviceKind; -import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotation; -import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotationKind; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.helpers.XMLReaderFactory; - -/** - * - * @author Alexandre Vasseur - * @author A. Nevado - * @author Andy Clement - */ -public class DocumentParser extends DefaultHandler { - /** - * The current DTD public id. The matching dtd will be searched as a resource. - */ - private final static String DTD_PUBLIC_ID = "-//AspectJ//DTD 1.5.0//EN"; - - /** - * The DTD alias, for better user experience. - */ - private final static String DTD_PUBLIC_ID_ALIAS = "-//AspectJ//DTD//EN"; - - private final static String ASPECTJ_ELEMENT = "aspectj"; - private final static String WEAVER_ELEMENT = "weaver"; - private final static String DUMP_ELEMENT = "dump"; - private final static String DUMP_BEFOREANDAFTER_ATTRIBUTE = "beforeandafter"; - private final static String DUMP_PERCLASSLOADERDIR_ATTRIBUTE = "perclassloaderdumpdir"; - private final static String INCLUDE_ELEMENT = "include"; - private final static String EXCLUDE_ELEMENT = "exclude"; - private final static String OPTIONS_ATTRIBUTE = "options"; - private final static String ASPECTS_ELEMENT = "aspects"; - private final static String ASPECT_ELEMENT = "aspect"; - private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect"; - private final static String NAME_ATTRIBUTE = "name"; - private final static String SCOPE_ATTRIBUTE = "scope"; - private final static String REQUIRES_ATTRIBUTE = "requires"; - private final static String EXTEND_ATTRIBUTE = "extends"; - private final static String PRECEDENCE_ATTRIBUTE = "precedence"; - private final static String PERCLAUSE_ATTRIBUTE = "perclause"; - private final static String POINTCUT_ELEMENT = "pointcut"; - private final static String BEFORE_ELEMENT = "before"; - private final static String AFTER_ELEMENT = "after"; - private final static String AFTER_RETURNING_ELEMENT = "after-returning"; - private final static String AFTER_THROWING_ELEMENT = "after-throwing"; - private final static String AROUND_ELEMENT = "around"; - private final static String WITHIN_ATTRIBUTE = "within"; - private final static String EXPRESSION_ATTRIBUTE = "expression"; - private final static String DECLARE_ANNOTATION_ELEMENT = "declare-annotation"; - - private final Definition definition; - - private boolean inAspectJ; - private boolean inWeaver; - private boolean inAspects; - - private Definition.ConcreteAspect activeConcreteAspectDefinition; - - private static Hashtable<String, Definition> parsedFiles = new Hashtable<String, Definition>(); - private static boolean CACHE; - private static final boolean LIGHTPARSER; - - static { - boolean value = false; - try { - value = System.getProperty("org.aspectj.weaver.loadtime.configuration.cache", "true").equalsIgnoreCase("true"); - } catch (Throwable t) { - t.printStackTrace(); - } - CACHE = value; - - value = false; - try { - value = System.getProperty("org.aspectj.weaver.loadtime.configuration.lightxmlparser", "false") - .equalsIgnoreCase("true"); - } catch (Throwable t) { - t.printStackTrace(); - } - LIGHTPARSER = value; - } - - private DocumentParser() { - definition = new Definition(); - } - - public static Definition parse(final URL url) throws Exception { - if (CACHE && parsedFiles.containsKey(url.toString())) { - return parsedFiles.get(url.toString()); - } - Definition def = null; - - if (LIGHTPARSER) { - def = SimpleAOPParser.parse(url); - } else { - def = saxParsing(url); - } - - if (CACHE && def.getAspectClassNames().size() > 0) { - parsedFiles.put(url.toString(), def); - } - - return def; - } - - private static Definition saxParsing(URL url) throws SAXException, ParserConfigurationException, IOException { - DocumentParser parser = new DocumentParser(); - - XMLReader xmlReader = getXMLReader(); - xmlReader.setContentHandler(parser); - xmlReader.setErrorHandler(parser); - - try { - xmlReader.setFeature("http://xml.org/sax/features/validation", false); - } catch (SAXException e) { - // fine, the parser don't do validation - } - try { - xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); - } catch (SAXException e) { - // fine, the parser don't do validation - } - try { - xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - } catch (SAXException e) { - // fine, the parser don't do validation - } - - xmlReader.setEntityResolver(parser); - InputStream in = url.openStream(); - xmlReader.parse(new InputSource(in)); - return parser.definition; - } - - private static XMLReader getXMLReader() throws SAXException, ParserConfigurationException { - XMLReader xmlReader = null; - /* Try this first for Java 5 */ - try { - xmlReader = XMLReaderFactory.createXMLReader(); - } - - /* .. and ignore "System property ... not set" and then try this instead */ - catch (SAXException ex) { - xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); - } - return xmlReader; - } - - public InputSource resolveEntity(String publicId, String systemId) throws SAXException { - if (publicId.equals(DTD_PUBLIC_ID) || publicId.equals(DTD_PUBLIC_ID_ALIAS)) { - InputStream in = DocumentParser.class.getResourceAsStream("/aspectj_1_5_0.dtd"); - if (in == null) { - System.err.println("AspectJ - WARN - could not read DTD " + publicId); - return null; - } else { - return new InputSource(in); - } - } else { - System.err.println("AspectJ - WARN - unknown DTD " + publicId + " - consider using " + DTD_PUBLIC_ID); - return null; - } - } - - public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - if (ASPECT_ELEMENT.equals(qName)) { - String name = attributes.getValue(NAME_ATTRIBUTE); - String scopePattern = replaceXmlAnd(attributes.getValue(SCOPE_ATTRIBUTE)); - String requiredType = attributes.getValue(REQUIRES_ATTRIBUTE); - if (!isNull(name)) { - definition.getAspectClassNames().add(name); - if (scopePattern != null) { - definition.addScopedAspect(name, scopePattern); - } - if (requiredType != null) { - definition.setAspectRequires(name, requiredType); - } - } - } else if (WEAVER_ELEMENT.equals(qName)) { - String options = attributes.getValue(OPTIONS_ATTRIBUTE); - if (!isNull(options)) { - definition.appendWeaverOptions(options); - } - inWeaver = true; - } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - String name = attributes.getValue(NAME_ATTRIBUTE); - String extend = attributes.getValue(EXTEND_ATTRIBUTE); - String precedence = attributes.getValue(PRECEDENCE_ATTRIBUTE); - String perclause = attributes.getValue(PERCLAUSE_ATTRIBUTE); - if (!isNull(name)) { - activeConcreteAspectDefinition = new Definition.ConcreteAspect(name, extend, precedence, perclause); - // if (isNull(precedence) && !isNull(extend)) {// if no precedence, then extends must be there - // m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend); - // } else if (!isNull(precedence)) { - // // wether a pure precedence def, or an extendsANDprecedence def. - // m_lastConcreteAspect = new Definition.ConcreteAspect(name, extend, precedence, perclause); - // } - definition.getConcreteAspects().add(activeConcreteAspectDefinition); - } - } else if (POINTCUT_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) { - String name = attributes.getValue(NAME_ATTRIBUTE); - String expression = attributes.getValue(EXPRESSION_ATTRIBUTE); - if (!isNull(name) && !isNull(expression)) { - activeConcreteAspectDefinition.pointcuts.add(new Definition.Pointcut(name, replaceXmlAnd(expression))); - } - } else if (DECLARE_ANNOTATION_ELEMENT.equals(qName) && activeConcreteAspectDefinition!=null) { - String methodSig = attributes.getValue("method"); - String fieldSig = attributes.getValue("field"); - String typePat = attributes.getValue("type"); - String anno = attributes.getValue("annotation"); - if (isNull(anno)) { - throw new SAXException("Badly formed <declare-annotation> element, 'annotation' value is missing"); - } - if (isNull(methodSig) && isNull(fieldSig) && isNull(typePat)) { - throw new SAXException("Badly formed <declare-annotation> element, need one of 'method'/'field'/'type' specified"); - } - if (!isNull(methodSig)) { - // declare @method - activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Method, - methodSig, anno)); - } else if (!isNull(fieldSig)) { - // declare @field - activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Field, - fieldSig, anno)); - } else if (!isNull(typePat)) { - // declare @type - activeConcreteAspectDefinition.declareAnnotations.add(new Definition.DeclareAnnotation(DeclareAnnotationKind.Type, - typePat, anno)); - } - } else if (BEFORE_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) { - String pointcut = attributes.getValue(POINTCUT_ELEMENT); - String adviceClass = attributes.getValue("invokeClass"); - String adviceMethod = attributes.getValue("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Before, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } else { - throw new SAXException("Badly formed <before> element"); - } - } else if (AFTER_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) { - String pointcut = attributes.getValue(POINTCUT_ELEMENT); - String adviceClass = attributes.getValue("invokeClass"); - String adviceMethod = attributes.getValue("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.After, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } else { - throw new SAXException("Badly formed <after> element"); - } - } else if (AROUND_ELEMENT.equals(qName) && activeConcreteAspectDefinition != null) { - String pointcut = attributes.getValue(POINTCUT_ELEMENT); - String adviceClass = attributes.getValue("invokeClass"); - String adviceMethod = attributes.getValue("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - activeConcreteAspectDefinition.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Around, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } else { - throw new SAXException("Badly formed <before> element"); - } - } else if (ASPECTJ_ELEMENT.equals(qName)) { - if (inAspectJ) { - throw new SAXException("Found nested <aspectj> element"); - } - inAspectJ = true; - } else if (ASPECTS_ELEMENT.equals(qName)) { - inAspects = true; - } else if (INCLUDE_ELEMENT.equals(qName) && inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - definition.getIncludePatterns().add(typePattern); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - definition.getExcludePatterns().add(typePattern); - } - } else if (DUMP_ELEMENT.equals(qName) && inWeaver) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - definition.getDumpPatterns().add(typePattern); - } - String beforeAndAfter = attributes.getValue(DUMP_BEFOREANDAFTER_ATTRIBUTE); - if (isTrue(beforeAndAfter)) { - definition.setDumpBefore(true); - } - String perWeaverDumpDir = attributes.getValue(DUMP_PERCLASSLOADERDIR_ATTRIBUTE); - if (isTrue(perWeaverDumpDir)) { - definition.setCreateDumpDirPerClassloader(true); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && inAspects) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - definition.getAspectExcludePatterns().add(typePattern); - } - } else if (INCLUDE_ELEMENT.equals(qName) && inAspects) { - String typePattern = getWithinAttribute(attributes); - if (!isNull(typePattern)) { - definition.getAspectIncludePatterns().add(typePattern); - } - } else { - throw new SAXException("Unknown element while parsing <aspectj> element: " + qName); - } - super.startElement(uri, localName, qName, attributes); - } - - private String getWithinAttribute(Attributes attributes) { - return replaceXmlAnd(attributes.getValue(WITHIN_ATTRIBUTE)); - } - - public void endElement(String uri, String localName, String qName) throws SAXException { - if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - activeConcreteAspectDefinition = null; - } else if (ASPECTJ_ELEMENT.equals(qName)) { - inAspectJ = false; - } else if (WEAVER_ELEMENT.equals(qName)) { - inWeaver = false; - } else if (ASPECTS_ELEMENT.equals(qName)) { - inAspects = false; - } - super.endElement(uri, localName, qName); - } - - // TODO AV - define what we want for XML parser error - for now stderr - public void warning(SAXParseException e) throws SAXException { - super.warning(e); - } - - public void error(SAXParseException e) throws SAXException { - super.error(e); - } - - public void fatalError(SAXParseException e) throws SAXException { - super.fatalError(e); - } - - private static String replaceXmlAnd(String expression) { - // TODO AV do we need to handle "..)AND" or "AND(.." ? - return LangUtil.replace(expression, " AND ", " && "); - } - - private boolean isNull(String s) { - return (s == null || s.length() <= 0); - } - - private boolean isTrue(String s) { - return (s != null && s.equals("true")); - } - - /** - * Turn off caching - */ - public static void deactivateCaching() { - CACHE = false; - } - -} diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/LightXMLParser.java b/weaver/src/org/aspectj/weaver/loadtime/definition/LightXMLParser.java deleted file mode 100644 index 09a9df96f..000000000 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/LightXMLParser.java +++ /dev/null @@ -1,471 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Abraham Nevado - Lucierna initial implementation - *******************************************************************************/ -package org.aspectj.weaver.loadtime.definition; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class LightXMLParser { - - private final static char NULL_CHAR = '\0'; - private Map<String, Object> attributes; - private ArrayList children; - private String name; - private char pushedBackChar; - private Reader reader; - - private static Map<String, char[]> entities = new HashMap<String, char[]>(); - - static { - entities.put("amp", new char[] { '&' }); - entities.put("quot", new char[] { '"' }); - entities.put("apos", new char[] { '\'' }); - entities.put("lt", new char[] { '<' }); - entities.put("gt", new char[] { '>' }); - } - - public LightXMLParser() { - this.name = null; - this.attributes = new HashMap<String, Object>(); - this.children = new ArrayList(); - } - - public ArrayList getChildrens() { - return this.children; - } - - public String getName() { - return this.name; - } - - public void parseFromReader(Reader reader) throws Exception { - this.pushedBackChar = NULL_CHAR; - this.attributes = new HashMap<String, Object>(); - this.name = null; - this.children = new ArrayList(); - this.reader = reader; - - while (true) { - // Skips whiteSpaces, blanks, \r\n.. - char c = this.skipBlanks(); - - // All xml should start by <xml, a <!-- or <nodeName, if not throw - // exception - if (c != '<') { - throw new Exception("LightParser Exception: Expected < but got: " + c); - } - - // read next character - c = this.getNextChar(); - - // if starts with ! or ? it is <?xml or a comment: skip - if ((c == '!') || (c == '?')) { - this.skipCommentOrXmlTag(0); - } else { - // it is a node, pusch character back - this.pushBackChar(c); - // parse node - this.parseNode(this); - // Only one root node, so finsh. - return; - } - } - } - - private char skipBlanks() throws Exception { - while (true) { - char c = this.getNextChar(); - switch (c) { - case '\n': - case '\r': - case ' ': - case '\t': - break; - default: - return c; - } - } - } - - private char getWhitespaces(StringBuffer result) throws Exception { - while (true) { - char c = this.getNextChar(); - switch (c) { - case ' ': - case '\t': - case '\n': - result.append(c); - case '\r': - break; - default: - return c; - } - } - } - - private void getNodeName(StringBuffer result) throws Exception { - char c; - while (true) { - // Iterate while next character is not [a-z] [A-Z] [0-9] [ .:_-] not - // null - c = this.getNextChar(); - if (((c < 'a') || (c > 'z')) && ((c > 'Z') || (c < 'A')) && ((c > '9') || (c < '0')) && (c != '_') && (c != '-') - && (c != '.') && (c != ':')) { - this.pushBackChar(c); - return; - } - result.append(c); - } - } - - private void getString(StringBuffer string) throws Exception { - char delimiter = this.getNextChar(); - if ((delimiter != '\'') && (delimiter != '"')) { - throw new Exception("Parsing error. Expected ' or \" but got: " + delimiter); - - } - - while (true) { - char c = this.getNextChar(); - if (c == delimiter) { - return; - } else if (c == '&') { - this.mapEntity(string); - } else { - string.append(c); - } - } - } - - private void getPCData(StringBuffer data) throws Exception { - while (true) { - char c = this.getNextChar(); - if (c == '<') { - c = this.getNextChar(); - if (c == '!') { - this.checkCDATA(data); - } else { - this.pushBackChar(c); - return; - } - } else { - data.append(c); - } - } - } - - private boolean checkCDATA(StringBuffer buf) throws Exception { - char c = this.getNextChar(); - if (c != '[') { - this.pushBackChar(c); - this.skipCommentOrXmlTag(0); - return false; - } else if (!this.checkLiteral("CDATA[")) { - this.skipCommentOrXmlTag(1); // one [ has already been read - return false; - } else { - int delimiterCharsSkipped = 0; - while (delimiterCharsSkipped < 3) { - c = this.getNextChar(); - switch (c) { - case ']': - if (delimiterCharsSkipped < 2) { - delimiterCharsSkipped++; - } else { - buf.append(']'); - buf.append(']'); - delimiterCharsSkipped = 0; - } - break; - case '>': - if (delimiterCharsSkipped < 2) { - for (int i = 0; i < delimiterCharsSkipped; i++) { - buf.append(']'); - } - delimiterCharsSkipped = 0; - buf.append('>'); - } else { - delimiterCharsSkipped = 3; - } - break; - default: - for (int i = 0; i < delimiterCharsSkipped; i++) { - buf.append(']'); - } - buf.append(c); - delimiterCharsSkipped = 0; - } - } - return true; - } - } - - private void skipCommentOrXmlTag(int bracketLevel) throws Exception { - char delim = NULL_CHAR; - int level = 1; - char c; - if (bracketLevel == 0) { - c = this.getNextChar(); - if (c == '-') { - c = this.getNextChar(); - if (c == ']') { - bracketLevel--; - } else if (c == '[') { - bracketLevel++; - } else if (c == '-') { - this.skipComment(); - return; - } - } else if (c == '[') { - bracketLevel++; - } - } - while (level > 0) { - c = this.getNextChar(); - if (delim == NULL_CHAR) { - if ((c == '"') || (c == '\'')) { - delim = c; - } else if (bracketLevel <= 0) { - if (c == '<') { - level++; - } else if (c == '>') { - level--; - } - } - if (c == '[') { - bracketLevel++; - } else if (c == ']') { - bracketLevel--; - } - } else { - if (c == delim) { - delim = NULL_CHAR; - } - } - } - } - - private void parseNode(LightXMLParser elt) throws Exception { - // Now we are in a new node element. Get its name - StringBuffer buf = new StringBuffer(); - this.getNodeName(buf); - String name = buf.toString(); - elt.setName(name); - - char c = this.skipBlanks(); - while ((c != '>') && (c != '/')) { - // Get attributes - emptyBuf(buf); - this.pushBackChar(c); - this.getNodeName(buf); - String key = buf.toString(); - c = this.skipBlanks(); - if (c != '=') { - throw new Exception("Parsing error. Expected = but got: " + c); - } - // Go up to " character and push it back - this.pushBackChar(this.skipBlanks()); - - emptyBuf(buf); - this.getString(buf); - - elt.setAttribute(key, buf); - - // Skip blanks - c = this.skipBlanks(); - } - if (c == '/') { - c = this.getNextChar(); - if (c != '>') { - throw new Exception("Parsing error. Expected > but got: " + c); - } - return; - } - - // Now see if we got content, or CDATA, if content get it: it is free... - emptyBuf(buf); - c = this.getWhitespaces(buf); - if (c != '<') { - // It is PCDATA - this.pushBackChar(c); - this.getPCData(buf); - } else { - // It is content: get it, or CDATA. - while (true) { - c = this.getNextChar(); - if (c == '!') { - if (this.checkCDATA(buf)) { - this.getPCData(buf); - break; - } else { - c = this.getWhitespaces(buf); - if (c != '<') { - this.pushBackChar(c); - this.getPCData(buf); - break; - } - } - } else { - if (c != '/') { - emptyBuf(buf); - } - if (c == '/') { - this.pushBackChar(c); - } - break; - } - } - } - if (buf.length() == 0) { - // It is a comment - while (c != '/') { - if (c == '!') { - for (int i = 0; i < 2; i++) { - c = this.getNextChar(); - if (c != '-') { - throw new Exception("Parsing error. Expected element or comment"); - } - } - this.skipComment(); - } else { - // it is a new node - this.pushBackChar(c); - LightXMLParser child = this.createAnotherElement(); - this.parseNode(child); - elt.addChild(child); - } - c = this.skipBlanks(); - if (c != '<') { - throw new Exception("Parsing error. Expected <, but got: " + c); - } - c = this.getNextChar(); - } - this.pushBackChar(c); - } // Here content could be grabbed - - c = this.getNextChar(); - if (c != '/') { - throw new Exception("Parsing error. Expected /, but got: " + c); - } - this.pushBackChar(this.skipBlanks()); - if (!this.checkLiteral(name)) { - throw new Exception("Parsing error. Expected " + name); - } - if (this.skipBlanks() != '>') { - throw new Exception("Parsing error. Expected >, but got: " + c); - } - } - - private void skipComment() throws Exception { - int dashes = 2; - while (dashes > 0) { - char ch = this.getNextChar(); - if (ch == '-') { - dashes -= 1; - } else { - dashes = 2; - } - } - - char nextChar = this.getNextChar(); - if (nextChar != '>') { - throw new Exception("Parsing error. Expected > but got: " + nextChar); - } - } - - private boolean checkLiteral(String literal) throws Exception { - int length = literal.length(); - for (int i = 0; i < length; i++) { - if (this.getNextChar() != literal.charAt(i)) { - return false; - } - } - return true; - } - - private char getNextChar() throws Exception { - if (this.pushedBackChar != NULL_CHAR) { - char c = this.pushedBackChar; - this.pushedBackChar = NULL_CHAR; - return c; - } else { - int i = this.reader.read(); - if (i < 0) { - throw new Exception("Parsing error. Unexpected end of data"); - } else { - return (char) i; - } - } - } - - private void mapEntity(StringBuffer buf) throws Exception { - char c = this.NULL_CHAR; - StringBuffer keyBuf = new StringBuffer(); - while (true) { - c = this.getNextChar(); - if (c == ';') { - break; - } - keyBuf.append(c); - } - String key = keyBuf.toString(); - if (key.charAt(0) == '#') { - try { - if (key.charAt(1) == 'x') { - c = (char) Integer.parseInt(key.substring(2), 16); - } else { - c = (char) Integer.parseInt(key.substring(1), 10); - } - } catch (NumberFormatException e) { - throw new Exception("Unknown entity: " + key); - } - buf.append(c); - } else { - char[] value = (char[]) entities.get(key); - if (value == null) { - throw new Exception("Unknown entity: " + key); - } - buf.append(value); - } - } - - private void pushBackChar(char c) { - this.pushedBackChar = c; - } - - private void addChild(LightXMLParser child) { - this.children.add(child); - } - - private void setAttribute(String name, Object value) { - this.attributes.put(name, value.toString()); - } - - public Map<String, Object> getAttributes() { - return this.attributes; - } - - private LightXMLParser createAnotherElement() { - return new LightXMLParser(); - } - - private void setName(String name) { - this.name = name; - } - - private void emptyBuf(StringBuffer buf) { - buf.setLength(0); - } - -} diff --git a/weaver/src/org/aspectj/weaver/loadtime/definition/SimpleAOPParser.java b/weaver/src/org/aspectj/weaver/loadtime/definition/SimpleAOPParser.java deleted file mode 100644 index bcd6ddcd0..000000000 --- a/weaver/src/org/aspectj/weaver/loadtime/definition/SimpleAOPParser.java +++ /dev/null @@ -1,265 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Abraham Nevado - Lucierna initial implementation - * Just a slight variation of current DocumentParser.java from Alexandre Vasseur. - *******************************************************************************/ -package org.aspectj.weaver.loadtime.definition; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; - -import org.aspectj.util.LangUtil; -import org.aspectj.weaver.loadtime.definition.Definition.AdviceKind; -import org.aspectj.weaver.loadtime.definition.Definition.DeclareAnnotationKind; -import org.xml.sax.SAXException; - -/** - * This class has been created to avoid deadlocks when instrumenting SAXParser. - * So it is used as a wrapper for the ligthweigh XML parser LightXMLParser. - * - * @author A. Nevado - */ -public class SimpleAOPParser { - - private final static String ASPECTJ_ELEMENT = "aspectj"; - private final static String WEAVER_ELEMENT = "weaver"; - private final static String DUMP_ELEMENT = "dump"; - private final static String DUMP_BEFOREANDAFTER_ATTRIBUTE = "beforeandafter"; - private final static String DUMP_PERCLASSLOADERDIR_ATTRIBUTE = "perclassloaderdumpdir"; - private final static String INCLUDE_ELEMENT = "include"; - private final static String EXCLUDE_ELEMENT = "exclude"; - private final static String OPTIONS_ATTRIBUTE = "options"; - private final static String ASPECTS_ELEMENT = "aspects"; - private final static String ASPECT_ELEMENT = "aspect"; - private final static String CONCRETE_ASPECT_ELEMENT = "concrete-aspect"; - private final static String NAME_ATTRIBUTE = "name"; - private final static String SCOPE_ATTRIBUTE = "scope"; - private final static String REQUIRES_ATTRIBUTE = "requires"; - private final static String EXTEND_ATTRIBUTE = "extends"; - private final static String PRECEDENCE_ATTRIBUTE = "precedence"; - private final static String PERCLAUSE_ATTRIBUTE = "perclause"; - private final static String POINTCUT_ELEMENT = "pointcut"; - private final static String WITHIN_ATTRIBUTE = "within"; - private final static String EXPRESSION_ATTRIBUTE = "expression"; - private static final String DECLARE_ANNOTATION = "declare-annotation"; - private static final String ANNONATION_TAG = "annotation"; - private static final String ANNO_KIND_TYPE = "type"; - private static final String ANNO_KIND_METHOD = "method"; - private static final String ANNO_KIND_FIELD = "field"; - private final static String BEFORE_ELEMENT = "before"; - private final static String AFTER_ELEMENT = "after"; - private final static String AROUND_ELEMENT = "around"; - private final Definition m_definition; - private boolean m_inAspectJ; - private boolean m_inWeaver; - private boolean m_inAspects; - - private Definition.ConcreteAspect m_lastConcreteAspect; - - private SimpleAOPParser() { - m_definition = new Definition(); - } - - public static Definition parse(final URL url) throws Exception { - // FileReader freader = new FileReader("/tmp/aop.xml"); - InputStream in = url.openStream(); - LightXMLParser xml = new LightXMLParser(); - xml.parseFromReader(new InputStreamReader(in)); - SimpleAOPParser sap = new SimpleAOPParser(); - traverse(sap, xml); - return sap.m_definition; - } - - private void startElement(String qName, Map attrMap) throws Exception { - if (ASPECT_ELEMENT.equals(qName)) { - String name = (String) attrMap.get(NAME_ATTRIBUTE); - String scopePattern = replaceXmlAnd((String) attrMap - .get(SCOPE_ATTRIBUTE)); - String requiredType = (String) attrMap.get(REQUIRES_ATTRIBUTE); - if (!isNull(name)) { - m_definition.getAspectClassNames().add(name); - if (scopePattern != null) { - m_definition.addScopedAspect(name, scopePattern); - } - if (requiredType != null) { - m_definition.setAspectRequires(name, requiredType); - } - } - } else if (WEAVER_ELEMENT.equals(qName)) { - String options = (String) attrMap.get(OPTIONS_ATTRIBUTE); - if (!isNull(options)) { - m_definition.appendWeaverOptions(options); - } - m_inWeaver = true; - } else if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - String name = (String) attrMap.get(NAME_ATTRIBUTE); - String extend = (String) attrMap.get(EXTEND_ATTRIBUTE); - String precedence = (String) attrMap.get(PRECEDENCE_ATTRIBUTE); - String perclause = (String) attrMap.get(PERCLAUSE_ATTRIBUTE); - if (!isNull(name)) { - m_lastConcreteAspect = new Definition.ConcreteAspect(name, - extend, precedence, perclause); - m_definition.getConcreteAspects().add(m_lastConcreteAspect); - } - } else if (POINTCUT_ELEMENT.equals(qName) - && m_lastConcreteAspect != null) { - String name = (String) attrMap.get(NAME_ATTRIBUTE); - String expression = (String) attrMap.get(EXPRESSION_ATTRIBUTE); - if (!isNull(name) && !isNull(expression)) { - m_lastConcreteAspect.pointcuts.add(new Definition.Pointcut( - name, replaceXmlAnd(expression))); - } - } else if (ASPECTJ_ELEMENT.equals(qName)) { - if (m_inAspectJ) { - throw new Exception("Found nested <aspectj> element"); - } - m_inAspectJ = true; - } else if (ASPECTS_ELEMENT.equals(qName)) { - m_inAspects = true; - } else if (INCLUDE_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attrMap); - if (!isNull(typePattern)) { - m_definition.getIncludePatterns().add(typePattern); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attrMap); - if (!isNull(typePattern)) { - m_definition.getExcludePatterns().add(typePattern); - } - } else if (DUMP_ELEMENT.equals(qName) && m_inWeaver) { - String typePattern = getWithinAttribute(attrMap); - if (!isNull(typePattern)) { - m_definition.getDumpPatterns().add(typePattern); - } - String beforeAndAfter = (String) attrMap - .get(DUMP_BEFOREANDAFTER_ATTRIBUTE); - if (isTrue(beforeAndAfter)) { - m_definition.setDumpBefore(true); - } - String perWeaverDumpDir = (String) attrMap - .get(DUMP_PERCLASSLOADERDIR_ATTRIBUTE); - if (isTrue(perWeaverDumpDir)) { - m_definition.setCreateDumpDirPerClassloader(true); - } - } else if (EXCLUDE_ELEMENT.equals(qName) && m_inAspects) { - String typePattern = getWithinAttribute(attrMap); - if (!isNull(typePattern)) { - m_definition.getAspectExcludePatterns().add(typePattern); - } - } else if (INCLUDE_ELEMENT.equals(qName) && m_inAspects) { - String typePattern = getWithinAttribute(attrMap); - if (!isNull(typePattern)) { - m_definition.getAspectIncludePatterns().add(typePattern); - } - }else if (DECLARE_ANNOTATION.equals(qName) && m_inAspects) { - String anno = (String) attrMap.get(ANNONATION_TAG); - if (!isNull(anno)){ - String pattern = (String) attrMap.get(ANNO_KIND_FIELD); - if (pattern != null){ - m_lastConcreteAspect.declareAnnotations.add(new Definition.DeclareAnnotation( - DeclareAnnotationKind.Field, pattern, anno)); - } - else{ - pattern = (String) attrMap.get(ANNO_KIND_METHOD); - if (pattern != null){ - m_lastConcreteAspect.declareAnnotations.add(new Definition.DeclareAnnotation( - DeclareAnnotationKind.Method, pattern, anno)); - } - else{ - pattern = (String) attrMap.get(ANNO_KIND_TYPE); - if (pattern != null){ - m_lastConcreteAspect.declareAnnotations.add(new Definition.DeclareAnnotation( - DeclareAnnotationKind.Type, pattern, anno)); - } - } - } - - } - } - else if (BEFORE_ELEMENT.equals(qName) && m_inAspects ) { - String pointcut = (String) attrMap.get(POINTCUT_ELEMENT); - String adviceClass = (String) attrMap.get("invokeClass"); - String adviceMethod = (String) attrMap.get("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - m_lastConcreteAspect.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Before, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } else { - throw new SAXException("Badly formed <before> element"); - } - } else if (AFTER_ELEMENT.equals(qName) && m_inAspects) { - String pointcut = (String) attrMap.get(POINTCUT_ELEMENT); - String adviceClass = (String) attrMap.get("invokeClass"); - String adviceMethod = (String) attrMap.get("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - m_lastConcreteAspect.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.After, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } else { - throw new SAXException("Badly formed <after> element"); - } - } else if (AROUND_ELEMENT.equals(qName) && m_inAspects) { - String pointcut = (String) attrMap.get(POINTCUT_ELEMENT); - String adviceClass = (String) attrMap.get("invokeClass"); - String adviceMethod = (String) attrMap.get("invokeMethod"); - if (!isNull(pointcut) && !isNull(adviceClass) && !isNull(adviceMethod)) { - m_lastConcreteAspect.pointcutsAndAdvice.add(new Definition.PointcutAndAdvice(AdviceKind.Around, - replaceXmlAnd(pointcut), adviceClass, adviceMethod)); - } - } - else { - throw new Exception( - "Unknown element while parsing <aspectj> element: " + qName); - } - } - - private void endElement(String qName) throws Exception { - if (CONCRETE_ASPECT_ELEMENT.equals(qName)) { - m_lastConcreteAspect = null; - } else if (ASPECTJ_ELEMENT.equals(qName)) { - m_inAspectJ = false; - } else if (WEAVER_ELEMENT.equals(qName)) { - m_inWeaver = false; - } else if (ASPECTS_ELEMENT.equals(qName)) { - m_inAspects = false; - } - } - - private String getWithinAttribute(Map attributes) { - return replaceXmlAnd((String) attributes.get(WITHIN_ATTRIBUTE)); - } - - private static String replaceXmlAnd(String expression) { - // TODO AV do we need to handle "..)AND" or "AND(.." ? - return LangUtil.replace(expression, " AND ", " && "); - } - - private boolean isNull(String s) { - return (s == null || s.length() <= 0); - } - - private boolean isTrue(String s) { - return (s != null && s.equals("true")); - } - - private static void traverse(SimpleAOPParser sap, LightXMLParser xml) - throws Exception { - sap.startElement(xml.getName(), xml.getAttributes()); - ArrayList childrens = xml.getChildrens(); - for (int i = 0; i < childrens.size(); i++) { - LightXMLParser child = (LightXMLParser) childrens.get(i); - traverse(sap, child); - } - sap.endElement(xml.getName()); - - } -} diff --git a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java b/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java deleted file mode 100644 index de5a4d854..000000000 --- a/weaver/src/org/aspectj/weaver/ltw/LTWWorld.java +++ /dev/null @@ -1,294 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2005 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Ron Bodkin Initial implementation - * ******************************************************************/ -package org.aspectj.weaver.ltw; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.util.LangUtil; -import org.aspectj.weaver.Dump.IVisitor; -import org.aspectj.weaver.ICrossReferenceHandler; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ReferenceTypeDelegate; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.bcel.BcelWorld; -import org.aspectj.weaver.loadtime.IWeavingContext; -import org.aspectj.weaver.reflect.AnnotationFinder; -import org.aspectj.weaver.reflect.IReflectionWorld; -import org.aspectj.weaver.reflect.ReflectionBasedReferenceTypeDelegateFactory; -import org.aspectj.weaver.reflect.ReflectionWorld; - -/** - * @author adrian - * @author Ron Bodkin - * - * For use in LT weaving - * - * Backed by both a BcelWorld and a ReflectionWorld - * - * Needs a callback when a woven class is defined This is the trigger for us to ditch the class from Bcel and cache it in - * the reflective world instead. - * - * Create by passing in a classloader, message handler - */ -public class LTWWorld extends BcelWorld implements IReflectionWorld { - - private AnnotationFinder annotationFinder; - private IWeavingContext weavingContext; - private String classLoaderString; - - private String classLoaderParentString; - - protected final static Class concurrentMapClass; - - private static final boolean ShareBootstrapTypes = false; - protected static Map/* <String, WeakReference<ReflectionBasedReferenceTypeDelegate>> */bootstrapTypes; - - static { - if (ShareBootstrapTypes) { - concurrentMapClass = makeConcurrentMapClass(); - bootstrapTypes = makeConcurrentMap(); - } else { - concurrentMapClass = null; - } - } - - /** - * Build a World from a ClassLoader, for LTW support - */ - public LTWWorld(ClassLoader loader, IWeavingContext weavingContext, IMessageHandler handler, ICrossReferenceHandler xrefHandler) { - super(loader, handler, xrefHandler); - this.weavingContext = weavingContext; - try { - classLoaderString = loader.toString(); - } catch (Throwable t) { - // Possibly some state in the loader isn't initialized but is used in the toString() - classLoaderString = loader.getClass().getName()+":"+Integer.toString(System.identityHashCode(loader)); - } - classLoaderParentString = (loader.getParent() == null ? "<NullParent>" : loader.getParent().toString()); - setBehaveInJava5Way(LangUtil.is15VMOrGreater()); - annotationFinder = ReflectionWorld.makeAnnotationFinderIfAny(loader, this); - } - - public ClassLoader getClassLoader() { - return weavingContext.getClassLoader(); - } - - // TEST - // this is probably easier: just mark anything loaded while loading aspects as not - // expendible... it also fixes a possible bug whereby non-rewoven aspects are deemed expendible - // <exclude within="org.foo.aspects..*"/> - // protected boolean isExpendable(ResolvedType type) { - // return ((type != null) && !loadingAspects && !type.isAspect() && (!type - // .isPrimitiveType())); - // } - - /** - * @Override - */ - @Override - protected ReferenceTypeDelegate resolveDelegate(ReferenceType ty) { - - // use reflection delegates for all bootstrap types - ReferenceTypeDelegate bootstrapLoaderDelegate = resolveIfBootstrapDelegate(ty); - if (bootstrapLoaderDelegate != null) { - return bootstrapLoaderDelegate; - } - - return super.resolveDelegate(ty); - } - - protected ReferenceTypeDelegate resolveIfBootstrapDelegate(ReferenceType ty) { - // first check for anything available in the bootstrap loader: these types are just defined from that without allowing - // nondelegation - // if (!ShareBootstrapTypes) return null; - // String name = ty.getName(); - // Reference bootRef = (Reference) bootstrapTypes.get(name); - // if (bootRef != null) { - // ReferenceTypeDelegate rtd = (ReferenceTypeDelegate) bootRef.get(); - // if (rtd != null) { - // return rtd; - // } - // } - // - // char fc = name.charAt(0); - // if (fc == 'j' || fc == 'c' || fc == 'o' || fc == 's') { // cheaper than imminent string startsWith tests - // if (name.startsWith("java") || name.startsWith("com.sun.") || name.startsWith("org.w3c") || - // name.startsWith("sun.") || name.startsWith("org.omg")) { - // ReferenceTypeDelegate bootstrapLoaderDelegate = resolveReflectionTypeDelegate(ty, null); - // if (bootstrapLoaderDelegate != null) { - // // it's always fine to load these bytes: there's no weaving into them - // // and since the class isn't initialized, all we are doing at this point is loading the bytes - // // processedRefTypes.put(ty, this); // has no effect - and probably too aggressive if we did store - // // these in the type map - // - // // should we share these, like we do the BCEL delegates? - // bootstrapTypes.put(ty.getName(), new WeakReference(bootstrapLoaderDelegate)); - // } - // return bootstrapLoaderDelegate; - // } - // } - return null; - } - - /** - * Helper method to resolve the delegate from the reflection delegate factory. - */ - private ReferenceTypeDelegate resolveReflectionTypeDelegate(ReferenceType ty, ClassLoader resolutionLoader) { - ReferenceTypeDelegate res = ReflectionBasedReferenceTypeDelegateFactory.createDelegate(ty, this, resolutionLoader); - return res; - } - - /** - * Remove this class from the typeMap. Call back to be made from a publishing class loader The class loader should, ideally, - * make this call on each not yet working - * - * @param clazz - */ - public void loadedClass(Class clazz) { - } - - private static final long serialVersionUID = 1; - - public AnnotationFinder getAnnotationFinder() { - return this.annotationFinder; - } - - /* - * (non-Javadoc) - * - * @see org.aspectj.weaver.reflect.IReflectionWorld#resolve(java.lang.Class) - */ - public ResolvedType resolve(Class aClass) { - return ReflectionWorld.resolve(this, aClass); - } - - private static Map makeConcurrentMap() { - if (concurrentMapClass != null) { - try { - return (Map) concurrentMapClass.newInstance(); - } catch (InstantiationException ie) { - } catch (IllegalAccessException iae) { - } - // fall through if exceptions - } - return Collections.synchronizedMap(new HashMap()); - } - - private static Class makeConcurrentMapClass() { - String betterChoices[] = { "java.util.concurrent.ConcurrentHashMap", - "edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap", - "EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap" }; - for (int i = 0; i < betterChoices.length; i++) { - try { - return Class.forName(betterChoices[i]); - } catch (ClassNotFoundException cnfe) { - // try the next one - } catch (SecurityException se) { - // you get one of these if you dare to try to load an undefined class in a - // package starting with java like java.util.concurrent - } - } - return null; - } - - @Override - public boolean isRunMinimalMemory() { - if (isRunMinimalMemorySet()) { - return super.isRunMinimalMemory(); - } - return false; - } - - // One type is completed at a time, if multiple need doing then they - // are queued up - private boolean typeCompletionInProgress = false; - private List/* ResolvedType */typesForCompletion = new ArrayList(); - - @Override - protected void completeBinaryType(ResolvedType ret) { - if (isLocallyDefined(ret.getName())) { - if (typeCompletionInProgress) { - typesForCompletion.add(ret); - } else { - try { - typeCompletionInProgress = true; - completeHierarchyForType(ret); - } finally { - typeCompletionInProgress = false; - } - while (typesForCompletion.size() != 0) { - ResolvedType rt = (ResolvedType) typesForCompletion.get(0); - completeHierarchyForType(rt); - typesForCompletion.remove(0); - } - } - } else { - if (!ret.needsModifiableDelegate()) { - ret = completeNonLocalType(ret); - } - } - } - - private void completeHierarchyForType(ResolvedType ret) { - getLint().typeNotExposedToWeaver.setSuppressed(true); - weaveInterTypeDeclarations(ret); - getLint().typeNotExposedToWeaver.setSuppressed(false); - } - - protected boolean needsCompletion() { - return true; - } - - @Override - public boolean isLocallyDefined(String classname) { - return weavingContext.isLocallyDefined(classname); - } - - protected ResolvedType completeNonLocalType(ResolvedType ret) { - if (ret.isMissing()) { - return ret; // who knows ?!? - } - ResolvedType toResolve = ret; - if (ret.isParameterizedType() || ret.isGenericType()) { - toResolve = toResolve.getGenericType(); - } - ReferenceTypeDelegate rtd = resolveReflectionTypeDelegate((ReferenceType) toResolve, getClassLoader()); - ((ReferenceType) ret).setDelegate(rtd); - return ret; - } - - @Override - public void storeClass(JavaClass clazz) { - ensureRepositorySetup(); - delegate.storeClass(clazz); - } - - @Override - public void accept(IVisitor visitor) { - visitor.visitObject("Class loader:"); - visitor.visitObject(classLoaderString); - visitor.visitObject("Class loader parent:"); - visitor.visitObject(classLoaderParentString); - super.accept(visitor); - } - - public boolean isLoadtimeWeaving() { - return true; - } - -} diff --git a/weaver/src/org/aspectj/weaver/model/AsmRelationshipProvider.java b/weaver/src/org/aspectj/weaver/model/AsmRelationshipProvider.java deleted file mode 100644 index 5801397a8..000000000 --- a/weaver/src/org/aspectj/weaver/model/AsmRelationshipProvider.java +++ /dev/null @@ -1,1133 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). - * 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 - * ******************************************************************/ - -package org.aspectj.weaver.model; - -import java.io.File; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -import org.aspectj.asm.AsmManager; -import org.aspectj.asm.IHierarchy; -import org.aspectj.asm.IProgramElement; -import org.aspectj.asm.IRelationship; -import org.aspectj.asm.IRelationshipMap; -import org.aspectj.asm.internal.HandleProviderDelimiter; -import org.aspectj.asm.internal.ProgramElement; -import org.aspectj.bridge.ISourceLocation; -import org.aspectj.bridge.SourceLocation; -import org.aspectj.weaver.Advice; -import org.aspectj.weaver.AdviceKind; -import org.aspectj.weaver.Checker; -import org.aspectj.weaver.Lint; -import org.aspectj.weaver.Member; -import org.aspectj.weaver.NewParentTypeMunger; -import org.aspectj.weaver.ReferenceType; -import org.aspectj.weaver.ResolvedMember; -import org.aspectj.weaver.ResolvedPointcutDefinition; -import org.aspectj.weaver.ResolvedType; -import org.aspectj.weaver.ResolvedTypeMunger; -import org.aspectj.weaver.ResolvedTypeMunger.Kind; -import org.aspectj.weaver.Shadow; -import org.aspectj.weaver.ShadowMunger; -import org.aspectj.weaver.UnresolvedType; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.BcelShadow; -import org.aspectj.weaver.bcel.BcelTypeMunger; -import org.aspectj.weaver.patterns.DeclareErrorOrWarning; -import org.aspectj.weaver.patterns.DeclareParents; -import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.TypePatternList; - -public class AsmRelationshipProvider { - - public static final String ADVISES = "advises"; - public static final String ADVISED_BY = "advised by"; - public static final String DECLARES_ON = "declares on"; - public static final String DECLAREDY_BY = "declared by"; - public static final String SOFTENS = "softens"; - public static final String SOFTENED_BY = "softened by"; - public static final String MATCHED_BY = "matched by"; - public static final String MATCHES_DECLARE = "matches declare"; - public static final String INTER_TYPE_DECLARES = "declared on"; - public static final String INTER_TYPE_DECLARED_BY = "aspect declarations"; - - public static final String ANNOTATES = "annotates"; - public static final String ANNOTATED_BY = "annotated by"; - - // public static final String REMOVES_ANNOTATION = "removes annotation"; - // public static final String ANNOTATION_REMOVED_BY = "annotated removed by"; - - /** - * Add a relationship for a declare error or declare warning - */ - public static void addDeclareErrorOrWarningRelationship(AsmManager model, Shadow affectedShadow, Checker deow) { - if (model == null) { - return; - } - if (affectedShadow.getSourceLocation() == null || deow.getSourceLocation() == null) { - return; - } - - if (World.createInjarHierarchy) { - createHierarchyForBinaryAspect(model, deow); - } - - IProgramElement targetNode = getNode(model, affectedShadow); - if (targetNode == null) { - return; - } - String targetHandle = targetNode.getHandleIdentifier(); - if (targetHandle == null) { - return; - } - - IProgramElement sourceNode = model.getHierarchy().findElementForSourceLine(deow.getSourceLocation()); - String sourceHandle = sourceNode.getHandleIdentifier(); - if (sourceHandle == null) { - return; - } - - IRelationshipMap relmap = model.getRelationshipMap(); - IRelationship foreward = relmap.get(sourceHandle, IRelationship.Kind.DECLARE, MATCHED_BY, false, true); - foreward.addTarget(targetHandle); - - IRelationship back = relmap.get(targetHandle, IRelationship.Kind.DECLARE, MATCHES_DECLARE, false, true); - if (back != null && back.getTargets() != null) { - back.addTarget(sourceHandle); - } - if (sourceNode.getSourceLocation() != null) { - model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile()); - } - } - - private static boolean isMixinRelated(ResolvedTypeMunger typeTransformer) { - Kind kind = typeTransformer.getKind(); - return kind == ResolvedTypeMunger.MethodDelegate2 || kind == ResolvedTypeMunger.FieldHost - || (kind == ResolvedTypeMunger.Parent && ((NewParentTypeMunger) typeTransformer).isMixin()); - } - - /** - * Add a relationship for a type transformation (declare parents, intertype method declaration, declare annotation on type). - */ - public static void addRelationship(AsmManager model, ResolvedType onType, ResolvedTypeMunger typeTransformer, - ResolvedType originatingAspect) { - if (model == null) { - return; - } - - if (World.createInjarHierarchy && isBinaryAspect(originatingAspect)) { - createHierarchy(model, typeTransformer, originatingAspect); - } - - if (originatingAspect.getSourceLocation() != null) { - String sourceHandle = ""; - IProgramElement sourceNode = null; - if (typeTransformer.getSourceLocation() != null && typeTransformer.getSourceLocation().getOffset() != -1 - && !isMixinRelated(typeTransformer)) { - sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(), - originatingAspect.getClassName()); - IProgramElement closer = model.getHierarchy().findCloserMatchForLineNumber(sourceNode, - typeTransformer.getSourceLocation().getLine()); - if (closer != null) { - sourceNode = closer; - } - if (sourceNode == null) { - // This can be caused by the aspect defining the type munger actually being on the classpath and not the - // inpath or aspectpath. Rather than NPE at the next line, let's have another go at faulting it in. - // This inner loop is a small duplicate of the outer loop that attempts to find something closer than - // the type declaration - if (World.createInjarHierarchy) { - createHierarchy(model, typeTransformer, originatingAspect); - if (typeTransformer.getSourceLocation() != null && typeTransformer.getSourceLocation().getOffset() != -1 - && !isMixinRelated(typeTransformer)) { - sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(), - originatingAspect.getClassName()); - IProgramElement closer2 = model.getHierarchy().findCloserMatchForLineNumber(sourceNode, - typeTransformer.getSourceLocation().getLine()); - if (closer2 != null) { - sourceNode = closer2; - } - } else { - sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(), - originatingAspect.getClassName()); - } - } - } - sourceHandle = sourceNode.getHandleIdentifier(); - } else { - sourceNode = model.getHierarchy().findElementForType(originatingAspect.getPackageName(), - originatingAspect.getClassName()); - // sourceNode = - // asm.getHierarchy().findElementForSourceLine(originatingAspect - // .getSourceLocation()); - sourceHandle = sourceNode.getHandleIdentifier(); - } - // sourceNode = - // asm.getHierarchy().findElementForType(originatingAspect - // .getPackageName(), - // originatingAspect.getClassName()); - // // sourceNode = - // asm.getHierarchy().findElementForSourceLine(munger - // .getSourceLocation()); - // sourceHandle = - // asm.getHandleProvider().createHandleIdentifier(sourceNode); - if (sourceHandle == null) { - return; - } - String targetHandle = findOrFakeUpNode(model, onType); - if (targetHandle == null) { - return; - } - IRelationshipMap mapper = model.getRelationshipMap(); - IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARES, false, - true); - foreward.addTarget(targetHandle); - - IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, INTER_TYPE_DECLARED_BY, false, - true); - back.addTarget(sourceHandle); - if (sourceNode != null && sourceNode.getSourceLocation() != null) { - // May have been a bug in the compiled aspect - so it didn't get put in the model - model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile()); - } - } - } - - private static String findOrFakeUpNode(AsmManager model, ResolvedType onType) { - IHierarchy hierarchy = model.getHierarchy(); - ISourceLocation sourceLocation = onType.getSourceLocation(); - String canonicalFilePath = model.getCanonicalFilePath(sourceLocation.getSourceFile()); - int lineNumber = sourceLocation.getLine(); - // Find the relevant source file node first - IProgramElement node = hierarchy.findNodeForSourceFile(hierarchy.getRoot(), canonicalFilePath); - if (node == null) { - // Does not exist in the model - probably an inpath - String bpath = onType.getBinaryPath(); - if (bpath == null) { - return model.getHandleProvider().createHandleIdentifier(createFileStructureNode(model, canonicalFilePath)); - } else { - IProgramElement programElement = model.getHierarchy().getRoot(); - // =Foo/,<g(G.class[G - StringBuffer phantomHandle = new StringBuffer(); - - // =Foo - phantomHandle.append(programElement.getHandleIdentifier()); - - // /, - the comma is a 'well defined char' that means inpath - phantomHandle.append(HandleProviderDelimiter.PACKAGEFRAGMENTROOT.getDelimiter()).append( - HandleProviderDelimiter.PHANTOM.getDelimiter()); - - int pos = bpath.indexOf('!'); - if (pos != -1) { - // jar or dir - String jarPath = bpath.substring(0, pos); - String element = model.getHandleElementForInpath(jarPath); - if (element != null) { - phantomHandle.append(element); - } - } - - // <g - String packageName = onType.getPackageName(); - phantomHandle.append(HandleProviderDelimiter.PACKAGEFRAGMENT.getDelimiter()).append(packageName); - - // (G.class - // could fix the binary path to only be blah.class bit - int dotClassPosition = bpath.lastIndexOf(".class");// what to do if -1 - if (dotClassPosition == -1) { - phantomHandle.append(HandleProviderDelimiter.CLASSFILE.getDelimiter()).append("UNKNOWN.class"); - } else { - int startPosition = dotClassPosition; - char ch; - while (startPosition > 0 && ((ch = bpath.charAt(startPosition)) != '/' && ch != '\\' && ch != '!')) { - startPosition--; - } - String classFile = bpath.substring(startPosition + 1, dotClassPosition + 6); - phantomHandle.append(HandleProviderDelimiter.CLASSFILE.getDelimiter()).append(classFile); - } - - // [G - phantomHandle.append(HandleProviderDelimiter.TYPE.getDelimiter()).append(onType.getClassName()); - - return phantomHandle.toString(); - } - } else { - // Check if there is a more accurate child node of that source file node: - IProgramElement closernode = hierarchy.findCloserMatchForLineNumber(node, lineNumber); - if (closernode == null) { - return node.getHandleIdentifier(); - } else { - return closernode.getHandleIdentifier(); - } - } - - } - - public static IProgramElement createFileStructureNode(AsmManager asm, String sourceFilePath) { - // SourceFilePath might have originated on windows on linux... - int lastSlash = sourceFilePath.lastIndexOf('\\'); - if (lastSlash == -1) { - lastSlash = sourceFilePath.lastIndexOf('/'); - } - // '!' is used like in URLs "c:/blahblah/X.jar!a/b.class" - int i = sourceFilePath.lastIndexOf('!'); - int j = sourceFilePath.indexOf(".class"); - if (i > lastSlash && i != -1 && j != -1) { - // we are a binary aspect in the default package - lastSlash = i; - } - String fileName = sourceFilePath.substring(lastSlash + 1); - IProgramElement fileNode = new ProgramElement(asm, fileName, IProgramElement.Kind.FILE_JAVA, new SourceLocation(new File( - sourceFilePath), 1, 1), 0, null, null); - // fileNode.setSourceLocation(); - fileNode.addChild(IHierarchy.NO_STRUCTURE); - return fileNode; - } - - private static boolean isBinaryAspect(ResolvedType aspect) { - return aspect.getBinaryPath() != null; - } - - /** - * Returns the binarySourceLocation for the given sourcelocation. This isn't cached because it's used when faulting in the - * binary nodes and is called with ISourceLocations for all advice, pointcuts and deows contained within the - * resolvedDeclaringAspect. - */ - private static ISourceLocation getBinarySourceLocation(ResolvedType aspect, ISourceLocation sl) { - if (sl == null) { - return null; - } - String sourceFileName = null; - if (aspect instanceof ReferenceType) { - String s = ((ReferenceType) aspect).getDelegate().getSourcefilename(); - int i = s.lastIndexOf('/'); - if (i != -1) { - sourceFileName = s.substring(i + 1); - } else { - sourceFileName = s; - } - } - ISourceLocation sLoc = new SourceLocation(getBinaryFile(aspect), sl.getLine(), sl.getEndLine(), - ((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourceFileName); - return sLoc; - } - - private static ISourceLocation createSourceLocation(String sourcefilename, ResolvedType aspect, ISourceLocation sl) { - ISourceLocation sLoc = new SourceLocation(getBinaryFile(aspect), sl.getLine(), sl.getEndLine(), - ((sl.getColumn() == 0) ? ISourceLocation.NO_COLUMN : sl.getColumn()), sl.getContext(), sourcefilename); - return sLoc; - } - - private static String getSourceFileName(ResolvedType aspect) { - String sourceFileName = null; - if (aspect instanceof ReferenceType) { - String s = ((ReferenceType) aspect).getDelegate().getSourcefilename(); - int i = s.lastIndexOf('/'); - if (i != -1) { - sourceFileName = s.substring(i + 1); - } else { - sourceFileName = s; - } - } - return sourceFileName; - } - - /** - * Returns the File with pathname to the class file, for example either C:\temp - * \ajcSandbox\workspace\ajcTest16957.tmp\simple.jar!pkg\BinaryAspect.class if the class file is in a jar file, or - * C:\temp\ajcSandbox\workspace\ajcTest16957.tmp!pkg\BinaryAspect.class if the class file is in a directory - */ - private static File getBinaryFile(ResolvedType aspect) { - String s = aspect.getBinaryPath(); - File f = aspect.getSourceLocation().getSourceFile(); - // Replace the source file suffix with .class - int i = f.getPath().lastIndexOf('.'); - String path = null; - if (i != -1) { - path = f.getPath().substring(0, i) + ".class"; - } else { - path = f.getPath() + ".class"; - } - return new File(s + "!" + path); - } - - /** - * Create a basic hierarchy to represent an aspect only available in binary (from the aspectpath). - */ - private static void createHierarchy(AsmManager model, ResolvedTypeMunger typeTransformer, ResolvedType aspect) { - // assert aspect != null; - - // Check if already defined in the model - // IProgramElement filenode = - // model.getHierarchy().findElementForType(aspect.getPackageName(), - // aspect.getClassName()); - // SourceLine(typeTransformer.getSourceLocation()); - IProgramElement filenode = model.getHierarchy().findElementForSourceLine(typeTransformer.getSourceLocation()); - if (filenode == null) { - if (typeTransformer.getKind() == ResolvedTypeMunger.MethodDelegate2 - || typeTransformer.getKind() == ResolvedTypeMunger.FieldHost) { - // not yet faulting these in - return; - } - } - // the call to findElementForSourceLine(ISourceLocation) returns a file - // node - // if it can't find a node in the hierarchy for the given - // sourcelocation. - // Therefore, if this is returned, we know we can't find one and have to - // // continue to fault in the model. - // if (filenode != null) { // - if (!filenode.getKind().equals(IProgramElement.Kind.FILE_JAVA)) { - return; - } - - // create the class file node - ISourceLocation binLocation = getBinarySourceLocation(aspect, aspect.getSourceLocation()); - String f = getBinaryFile(aspect).getName(); - IProgramElement classFileNode = new ProgramElement(model, f, IProgramElement.Kind.FILE, binLocation, 0, null, null); - - // create package ipe if one exists.... - IProgramElement root = model.getHierarchy().getRoot(); - IProgramElement binaries = model.getHierarchy().findElementForLabel(root, IProgramElement.Kind.SOURCE_FOLDER, "binaries"); - if (binaries == null) { - binaries = new ProgramElement(model, "binaries", IProgramElement.Kind.SOURCE_FOLDER, new ArrayList<IProgramElement>()); - root.addChild(binaries); - } - // if (aspect.getPackageName() != null) { - String packagename = aspect.getPackageName() == null ? "" : aspect.getPackageName(); - // check that there doesn't already exist a node with this name - IProgramElement pkgNode = model.getHierarchy().findElementForLabel(binaries, IProgramElement.Kind.PACKAGE, packagename); - // note packages themselves have no source location - if (pkgNode == null) { - pkgNode = new ProgramElement(model, packagename, IProgramElement.Kind.PACKAGE, new ArrayList<IProgramElement>()); - binaries.addChild(pkgNode); - pkgNode.addChild(classFileNode); - } else { - // need to add it first otherwise the handle for classFileNode - // may not be generated correctly if it uses information from - // it's parent node - pkgNode.addChild(classFileNode); - for (IProgramElement element: pkgNode.getChildren()) { - if (!element.equals(classFileNode) && element.getHandleIdentifier().equals(classFileNode.getHandleIdentifier())) { - // already added the classfile so have already - // added the structure for this aspect - pkgNode.removeChild(classFileNode); - return; - } - } - } - // } else { - // // need to add it first otherwise the handle for classFileNode - // // may not be generated correctly if it uses information from - // // it's parent node - // root.addChild(classFileNode); - // for (Iterator iter = root.getChildren().iterator(); iter.hasNext();) - // { - // IProgramElement element = (IProgramElement) iter.next(); - // if (!element.equals(classFileNode) && - // element.getHandleIdentifier().equals - // (classFileNode.getHandleIdentifier())) { - // // already added the sourcefile so have already - // // added the structure for this aspect - // root.removeChild(classFileNode); - // return; - // } - // } - // } - - // add and create empty import declaration ipe - // no import container for binary type - 265693 - // classFileNode.addChild(new ProgramElement(model, "import declarations", IProgramElement.Kind.IMPORT_REFERENCE, null, 0, - // null, null)); - - // add and create aspect ipe - IProgramElement aspectNode = new ProgramElement(model, aspect.getSimpleName(), IProgramElement.Kind.ASPECT, - getBinarySourceLocation(aspect, aspect.getSourceLocation()), aspect.getModifiers(), null, null); - classFileNode.addChild(aspectNode); - - addChildNodes(model, aspect, aspectNode, aspect.getDeclaredPointcuts()); - - addChildNodes(model, aspect, aspectNode, aspect.getDeclaredAdvice()); - addChildNodes(model, aspect, aspectNode, aspect.getDeclares()); - addChildNodes(model, aspect, aspectNode, aspect.getTypeMungers()); - } - - /** - * Adds a declare annotation relationship, sometimes entities don't have source locs (methods/fields) so use other variants of - * this method if that is the case as they will look the entities up in the structure model. - */ - public static void addDeclareAnnotationRelationship(AsmManager model, ISourceLocation declareAnnotationLocation, - ISourceLocation annotatedLocation, boolean isRemove) { - if (model == null) { - return; - } - - IProgramElement sourceNode = model.getHierarchy().findElementForSourceLine(declareAnnotationLocation); - String sourceHandle = sourceNode.getHandleIdentifier(); - if (sourceHandle == null) { - return; - } - - IProgramElement targetNode = model.getHierarchy().findElementForSourceLine(annotatedLocation); - String targetHandle = targetNode.getHandleIdentifier(); - if (targetHandle == null) { - return; - } - - IRelationshipMap mapper = model.getRelationshipMap(); - // if (isRemove) { - // IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, REMOVES_ANNOTATION, false, - // true); - // foreward.addTarget(targetHandle); - // - // IRelationship back = mapper - // .get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATION_REMOVED_BY, false, true); - // back.addTarget(sourceHandle); - // if (sourceNode.getSourceLocation() != null) { - // model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile()); - // } - // } else { - IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true); - foreward.addTarget(targetHandle); - - IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true); - back.addTarget(sourceHandle); - if (sourceNode.getSourceLocation() != null) { - model.addAspectInEffectThisBuild(sourceNode.getSourceLocation().getSourceFile()); - } - // } - } - - /** - * Creates the hierarchy for binary aspects - */ - public static void createHierarchyForBinaryAspect(AsmManager asm, ShadowMunger munger) { - if (!munger.isBinary()) { - return; - } - - IProgramElement sourceFileNode = asm.getHierarchy().findElementForSourceLine(munger.getSourceLocation()); - // the call to findElementForSourceLine(ISourceLocation) returns a file - // node if it can't find a node in the hierarchy for the given sourcelocation. - // Therefore, if this is returned, we know we can't find one and have to - // continue to fault in the model. - if (!sourceFileNode.getKind().equals(IProgramElement.Kind.FILE_JAVA)) { - return; - } - - ResolvedType aspect = munger.getDeclaringType(); - - // create the class file node - IProgramElement classFileNode = new ProgramElement(asm, sourceFileNode.getName(), IProgramElement.Kind.FILE, - munger.getBinarySourceLocation(aspect.getSourceLocation()), 0, null, null); - - // create package ipe if one exists.... - IProgramElement root = asm.getHierarchy().getRoot(); - IProgramElement binaries = asm.getHierarchy().findElementForLabel(root, IProgramElement.Kind.SOURCE_FOLDER, "binaries"); - if (binaries == null) { - binaries = new ProgramElement(asm, "binaries", IProgramElement.Kind.SOURCE_FOLDER, new ArrayList<IProgramElement>()); - root.addChild(binaries); - } - // if (aspect.getPackageName() != null) { - String packagename = aspect.getPackageName() == null ? "" : aspect.getPackageName(); - // check that there doesn't already exist a node with this name - IProgramElement pkgNode = asm.getHierarchy().findElementForLabel(binaries, IProgramElement.Kind.PACKAGE, packagename); - // note packages themselves have no source location - if (pkgNode == null) { - pkgNode = new ProgramElement(asm, packagename, IProgramElement.Kind.PACKAGE, new ArrayList<IProgramElement>()); - binaries.addChild(pkgNode); - pkgNode.addChild(classFileNode); - } else { - // need to add it first otherwise the handle for classFileNode - // may not be generated correctly if it uses information from - // it's parent node - pkgNode.addChild(classFileNode); - for (IProgramElement element: pkgNode.getChildren()) { - if (!element.equals(classFileNode) && element.getHandleIdentifier().equals(classFileNode.getHandleIdentifier())) { - // already added the classfile so have already - // added the structure for this aspect - pkgNode.removeChild(classFileNode); - return; - } - } - } - // } else { - // // need to add it first otherwise the handle for classFileNode - // // may not be generated correctly if it uses information from - // // it's parent node - // root.addChild(classFileNode); - // for (Iterator iter = root.getChildren().iterator(); iter.hasNext();) - // { - // IProgramElement element = (IProgramElement) iter.next(); - // if (!element.equals(classFileNode) && - // element.getHandleIdentifier().equals - // (classFileNode.getHandleIdentifier())) { - // // already added the sourcefile so have already - // // added the structure for this aspect - // root.removeChild(classFileNode); - // return; - // } - // } - // } - - // add and create empty import declaration ipe - // classFileNode.addChild(new ProgramElement(asm, "import declarations", IProgramElement.Kind.IMPORT_REFERENCE, null, 0, - // null, - // null)); - - // add and create aspect ipe - IProgramElement aspectNode = new ProgramElement(asm, aspect.getSimpleName(), IProgramElement.Kind.ASPECT, - munger.getBinarySourceLocation(aspect.getSourceLocation()), aspect.getModifiers(), null, null); - classFileNode.addChild(aspectNode); - - String sourcefilename = getSourceFileName(aspect); - addPointcuts(asm, sourcefilename, aspect, aspectNode, aspect.getDeclaredPointcuts()); - addChildNodes(asm, aspect, aspectNode, aspect.getDeclaredAdvice()); - addChildNodes(asm, aspect, aspectNode, aspect.getDeclares()); - addChildNodes(asm, aspect, aspectNode, aspect.getTypeMungers()); - - } - - private static void addPointcuts(AsmManager model, String sourcefilename, ResolvedType aspect, - IProgramElement containingAspect, ResolvedMember[] pointcuts) { - for (int i = 0; i < pointcuts.length; i++) { - ResolvedMember pointcut = pointcuts[i]; - if (pointcut instanceof ResolvedPointcutDefinition) { - ResolvedPointcutDefinition rpcd = (ResolvedPointcutDefinition) pointcut; - Pointcut p = rpcd.getPointcut(); - ISourceLocation sLoc = (p == null ? null : p.getSourceLocation()); - if (sLoc == null) { - sLoc = rpcd.getSourceLocation(); - } - ISourceLocation pointcutLocation = (sLoc == null ? null : createSourceLocation(sourcefilename, aspect, sLoc)); - ProgramElement pointcutElement = new ProgramElement(model, pointcut.getName(), IProgramElement.Kind.POINTCUT, - pointcutLocation, pointcut.getModifiers(), NO_COMMENT, Collections.<IProgramElement>emptyList()); - containingAspect.addChild(pointcutElement); - } - } - } - - private static final String NO_COMMENT = null; - - private static void addChildNodes(AsmManager asm, ResolvedType aspect, IProgramElement parent, ResolvedMember[] children) { - for (int i = 0; i < children.length; i++) { - ResolvedMember pcd = children[i]; - if (pcd instanceof ResolvedPointcutDefinition) { - ResolvedPointcutDefinition rpcd = (ResolvedPointcutDefinition) pcd; - Pointcut p = rpcd.getPointcut(); - ISourceLocation sLoc = (p == null ? null : p.getSourceLocation()); - if (sLoc == null) { - sLoc = rpcd.getSourceLocation(); - } - parent.addChild(new ProgramElement(asm, pcd.getName(), IProgramElement.Kind.POINTCUT, getBinarySourceLocation( - aspect, sLoc), pcd.getModifiers(), null, Collections.<IProgramElement>emptyList())); - } - } - } - - private static void addChildNodes(AsmManager asm, ResolvedType aspect, IProgramElement parent, Collection<?> children) { - int deCtr = 1; - int dwCtr = 1; - for (Object element: children) { - if (element instanceof DeclareErrorOrWarning) { - DeclareErrorOrWarning decl = (DeclareErrorOrWarning) element; - int counter = 0; - if (decl.isError()) { - counter = deCtr++; - } else { - counter = dwCtr++; - } - parent.addChild(createDeclareErrorOrWarningChild(asm, aspect, decl, counter)); - } else if (element instanceof Advice) { - Advice advice = (Advice) element; - parent.addChild(createAdviceChild(asm, advice)); - } else if (element instanceof DeclareParents) { - parent.addChild(createDeclareParentsChild(asm, (DeclareParents) element)); - } else if (element instanceof BcelTypeMunger) { - IProgramElement newChild = createIntertypeDeclaredChild(asm, aspect, (BcelTypeMunger) element); - // newChild==null means it is something that could not be handled by createIntertypeDeclaredChild() - if (newChild != null) { - parent.addChild(newChild); - } - } - } - } - - // private static IProgramElement - // createDeclareErrorOrWarningChild(AsmManager asm, ShadowMunger munger, - // DeclareErrorOrWarning decl, int count) { - // IProgramElement deowNode = new ProgramElement(asm, decl.getName(), - // decl.isError() ? IProgramElement.Kind.DECLARE_ERROR - // : IProgramElement.Kind.DECLARE_WARNING, - // munger.getBinarySourceLocation(decl.getSourceLocation()), decl - // .getDeclaringType().getModifiers(), null, null); - // deowNode.setDetails("\"" + - // AsmRelationshipUtils.genDeclareMessage(decl.getMessage()) + "\""); - // if (count != -1) { - // deowNode.setBytecodeName(decl.getName() + "_" + count); - // } - // return deowNode; - // } - - private static IProgramElement createDeclareErrorOrWarningChild(AsmManager model, ResolvedType aspect, - DeclareErrorOrWarning decl, int count) { - IProgramElement deowNode = new ProgramElement(model, decl.getName(), decl.isError() ? IProgramElement.Kind.DECLARE_ERROR - : IProgramElement.Kind.DECLARE_WARNING, getBinarySourceLocation(aspect, decl.getSourceLocation()), decl - .getDeclaringType().getModifiers(), null, null); - deowNode.setDetails("\"" + AsmRelationshipUtils.genDeclareMessage(decl.getMessage()) + "\""); - if (count != -1) { - deowNode.setBytecodeName(decl.getName() + "_" + count); - } - return deowNode; - } - - private static IProgramElement createAdviceChild(AsmManager model, Advice advice) { - IProgramElement adviceNode = new ProgramElement(model, advice.getKind().getName(), IProgramElement.Kind.ADVICE, - advice.getBinarySourceLocation(advice.getSourceLocation()), advice.getSignature().getModifiers(), null, - Collections.<IProgramElement>emptyList()); - adviceNode.setDetails(AsmRelationshipUtils.genPointcutDetails(advice.getPointcut())); - adviceNode.setBytecodeName(advice.getSignature().getName()); - return adviceNode; - } - - /** - * Half baked implementation - will need completing if we go down this route rather than replacing it all for binary aspects. - * Doesn't attempt to get parameter names correct - they may have been lost during (de)serialization of the munger, but the - * member could still be located so they might be retrievable. - */ - private static IProgramElement createIntertypeDeclaredChild(AsmManager model, ResolvedType aspect, BcelTypeMunger itd) { - ResolvedTypeMunger rtMunger = itd.getMunger(); - - ResolvedMember sig = rtMunger.getSignature(); - Kind kind = rtMunger.getKind(); - if (kind == ResolvedTypeMunger.Field) { // ITD FIELD - // String name = rtMunger.getSignature().toString(); - String name = sig.getDeclaringType().getClassName() + "." + sig.getName(); - if (name.indexOf("$") != -1) { - name = name.substring(name.indexOf("$") + 1); - } - IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_FIELD, getBinarySourceLocation( - aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.<IProgramElement>emptyList()); - pe.setCorrespondingType(sig.getReturnType().getName()); - return pe; - } else if (kind == ResolvedTypeMunger.Method) { // ITD - // METHOD - String name = sig.getDeclaringType().getClassName() + "." + sig.getName(); - if (name.indexOf("$") != -1) { - name = name.substring(name.indexOf("$") + 1); - } - IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_METHOD, getBinarySourceLocation( - aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.<IProgramElement>emptyList()); - setParams(pe, sig); - return pe; - } else if (kind == ResolvedTypeMunger.Constructor) { - String name = sig.getDeclaringType().getClassName() + "." + sig.getDeclaringType().getClassName(); - if (name.indexOf("$") != -1) { - name = name.substring(name.indexOf("$") + 1); - } - IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_CONSTRUCTOR, - getBinarySourceLocation(aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, - Collections.<IProgramElement>emptyList()); - setParams(pe, sig); - return pe; - // } else if (kind == ResolvedTypeMunger.MethodDelegate2) { - // String name = sig.getDeclaringType().getClassName() + "." + sig.getName(); - // if (name.indexOf("$") != -1) { - // name = name.substring(name.indexOf("$") + 1); - // } - // IProgramElement pe = new ProgramElement(model, name, IProgramElement.Kind.INTER_TYPE_METHOD, getBinarySourceLocation( - // aspect, itd.getSourceLocation()), rtMunger.getSignature().getModifiers(), null, Collections.EMPTY_LIST); - // setParams(pe, sig); - // return pe; - } - // other cases ignored for now - return null; - } - - private static void setParams(IProgramElement pe, ResolvedMember sig) { - // do it for itds too - UnresolvedType[] ts = sig.getParameterTypes(); - pe.setParameterNames(Collections.<String>emptyList()); - // TODO should be doing param names? - if (ts == null) { - pe.setParameterSignatures(Collections.<char[]>emptyList(), Collections.<String>emptyList()); - } else { - List<char[]> paramSigs = new ArrayList<char[]>(); - for (int i = 0; i < ts.length; i++) { - paramSigs.add(ts[i].getSignature().toCharArray()); - } - pe.setParameterSignatures(paramSigs, Collections.<String>emptyList()); - } - pe.setCorrespondingType(sig.getReturnType().getName()); - } - - private static IProgramElement createDeclareParentsChild(AsmManager model, DeclareParents decp) { - IProgramElement decpElement = new ProgramElement(model, "declare parents", IProgramElement.Kind.DECLARE_PARENTS, - getBinarySourceLocation(decp.getDeclaringType(), decp.getSourceLocation()), Modifier.PUBLIC, null, - Collections.<IProgramElement>emptyList()); - setParentTypesOnDeclareParentsNode(decp, decpElement); - return decpElement; - } - - private static void setParentTypesOnDeclareParentsNode(DeclareParents decp, IProgramElement decpElement) { - TypePatternList tpl = decp.getParents(); - List<String> parents = new ArrayList<String>(); - for (int i = 0; i < tpl.size(); i++) { - parents.add(tpl.get(i).getExactType().getName().replaceAll("\\$", ".")); - } - decpElement.setParentTypes(parents); - } - - public static String getHandle(AsmManager asm, Advice advice) { - if (null == advice.handle) { - ISourceLocation sl = advice.getSourceLocation(); - if (sl != null) { - IProgramElement ipe = asm.getHierarchy().findElementForSourceLine(sl); - advice.handle = ipe.getHandleIdentifier(); - } - } - return advice.handle; - } - - public static void addAdvisedRelationship(AsmManager model, Shadow matchedShadow, ShadowMunger munger) { - if (model == null) { - return; - } - - if (munger instanceof Advice) { - Advice advice = (Advice) munger; - - if (advice.getKind().isPerEntry() || advice.getKind().isCflow()) { - // TODO: might want to show these in the future - return; - } - - if (World.createInjarHierarchy) { - createHierarchyForBinaryAspect(model, advice); - } - - IRelationshipMap mapper = model.getRelationshipMap(); - IProgramElement targetNode = getNode(model, matchedShadow); - if (targetNode == null) { - return; - } - boolean runtimeTest = advice.hasDynamicTests(); - - IProgramElement.ExtraInformation extra = new IProgramElement.ExtraInformation(); - - String adviceHandle = getHandle(model, advice); - if (adviceHandle == null) { - return; - } - - extra.setExtraAdviceInformation(advice.getKind().getName()); - IProgramElement adviceElement = model.getHierarchy().findElementForHandle(adviceHandle); - if (adviceElement != null) { - adviceElement.setExtraInfo(extra); - } - String targetHandle = targetNode.getHandleIdentifier(); - if (advice.getKind().equals(AdviceKind.Softener)) { - IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.DECLARE_SOFT, SOFTENS, runtimeTest, true); - if (foreward != null) { - foreward.addTarget(targetHandle); - } - - IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE, SOFTENED_BY, runtimeTest, true); - if (back != null) { - back.addTarget(adviceHandle); - } - } else { - IRelationship foreward = mapper.get(adviceHandle, IRelationship.Kind.ADVICE, ADVISES, runtimeTest, true); - if (foreward != null) { - foreward.addTarget(targetHandle); - } - - IRelationship back = mapper.get(targetHandle, IRelationship.Kind.ADVICE, ADVISED_BY, runtimeTest, true); - if (back != null) { - back.addTarget(adviceHandle); - } - } - if (adviceElement.getSourceLocation() != null) { - model.addAspectInEffectThisBuild(adviceElement.getSourceLocation().getSourceFile()); - } - } - } - - protected static IProgramElement getNode(AsmManager model, Shadow shadow) { - Member enclosingMember = shadow.getEnclosingCodeSignature(); - // This variant will not be tricked by ITDs that would report they are - // in the target type already. - // This enables us to discover the ITD declaration (in the aspect) and - // advise it appropriately. - - // Have to be smart here, for a code node within an ITD we want to - // lookup the declaration of the - // ITD in the aspect in order to add the code node at the right place - - // and not lookup the - // ITD as it applies in some target type. Due to the use of - // effectiveSignature we will find - // that shadow.getEnclosingCodeSignature() will return a member - // representing the ITD as it will - // appear in the target type. So here, we do an extra bit of analysis to - // make sure we - // do the right thing in the ITD case. - IProgramElement enclosingNode = null; - if (shadow instanceof BcelShadow) { - Member actualEnclosingMember = ((BcelShadow) shadow).getRealEnclosingCodeSignature(); - - if (actualEnclosingMember == null) { - enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember); - } else { - UnresolvedType type = enclosingMember.getDeclaringType(); - UnresolvedType actualType = actualEnclosingMember.getDeclaringType(); - - // if these are not the same, it is an ITD and we need to use - // the latter to lookup - if (type.equals(actualType)) { - enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember); - } else { - enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), actualEnclosingMember); - } - } - } else { - enclosingNode = lookupMember(model.getHierarchy(), shadow.getEnclosingType(), enclosingMember); - } - - if (enclosingNode == null) { - Lint.Kind err = shadow.getIWorld().getLint().shadowNotInStructure; - if (err.isEnabled()) { - err.signal(shadow.toString(), shadow.getSourceLocation()); - } - return null; - } - - Member shadowSig = shadow.getSignature(); - // pr235204 - if (shadow.getKind() == Shadow.MethodCall || shadow.getKind() == Shadow.ConstructorCall - || !shadowSig.equals(enclosingMember)) { - IProgramElement bodyNode = findOrCreateCodeNode(model, enclosingNode, shadowSig, shadow); - return bodyNode; - } else { - return enclosingNode; - } - } - - private static boolean sourceLinesMatch(ISourceLocation location1, ISourceLocation location2) { - return (location1.getLine() == location2.getLine()); - } - - /** - * Finds or creates a code IProgramElement for the given shadow. - * - * The byteCodeName of the created node is set to 'shadowSig.getName() + "!" + counter', eg "println!3". The counter is the - * occurence count of children within the enclosingNode which have the same name. So, for example, if a method contains two - * System.out.println statements, the first one will have byteCodeName 'println!1' and the second will have byteCodeName - * 'println!2'. This is to ensure the two nodes have unique handles when the handles do not depend on sourcelocations. - * - * Currently the shadows are examined in the sequence they appear in the source file. This means that the counters are - * consistent over incremental builds. All aspects are compiled up front and any new aspect created will force a full build. - * Moreover, if the body of the enclosingShadow is changed, then the model for this is rebuilt from scratch. - */ - private static IProgramElement findOrCreateCodeNode(AsmManager asm, IProgramElement enclosingNode, Member shadowSig, - Shadow shadow) { - for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext();) { - IProgramElement node = (IProgramElement) it.next(); - int excl = node.getBytecodeName().lastIndexOf('!'); - if (((excl != -1 && shadowSig.getName().equals(node.getBytecodeName().substring(0, excl))) || shadowSig.getName() - .equals(node.getBytecodeName())) - && shadowSig.getSignature().equals(node.getBytecodeSignature()) - && sourceLinesMatch(node.getSourceLocation(), shadow.getSourceLocation())) { - return node; - } - } - - ISourceLocation sl = shadow.getSourceLocation(); - - // XXX why not use shadow file? new SourceLocation(sl.getSourceFile(), - // sl.getLine()), - SourceLocation peLoc = new SourceLocation(enclosingNode.getSourceLocation().getSourceFile(), sl.getLine()); - peLoc.setOffset(sl.getOffset()); - IProgramElement peNode = new ProgramElement(asm, shadow.toString(), IProgramElement.Kind.CODE, peLoc, 0, null, null); - - // check to see if the enclosing shadow already has children with the - // same name. If so we want to add a counter to the byteCodeName - // otherwise - // we wont get unique handles - int numberOfChildrenWithThisName = 0; - for (IProgramElement child: enclosingNode.getChildren()) { - if (child.getName().equals(shadow.toString())) { - numberOfChildrenWithThisName++; - } - } - peNode.setBytecodeName(shadowSig.getName() + "!" + String.valueOf(numberOfChildrenWithThisName + 1)); - peNode.setBytecodeSignature(shadowSig.getSignature()); - enclosingNode.addChild(peNode); - return peNode; - } - - private static IProgramElement lookupMember(IHierarchy model, UnresolvedType declaringType, Member member) { - IProgramElement typeElement = model.findElementForType(declaringType.getPackageName(), declaringType.getClassName()); - if (typeElement == null) { - return null; - } - for (Iterator it = typeElement.getChildren().iterator(); it.hasNext();) { - IProgramElement element = (IProgramElement) it.next(); - if (member.getName().equals(element.getBytecodeName()) && member.getSignature().equals(element.getBytecodeSignature())) { - return element; - } - } - // if we can't find the member, we'll just put it in the class - return typeElement; - } - - /** - * Add a relationship for a matching declare annotation method or declare annotation constructor. Locating the method is a messy - * (for messy read 'fragile') bit of code that could break at any moment but it's working for my simple testcase. - */ - public static void addDeclareAnnotationMethodRelationship(ISourceLocation sourceLocation, String affectedTypeName, - ResolvedMember affectedMethod, AsmManager model) { - if (model == null) { - return; - } - - String pkg = null; - String type = affectedTypeName; - int packageSeparator = affectedTypeName.lastIndexOf("."); - if (packageSeparator != -1) { - pkg = affectedTypeName.substring(0, packageSeparator); - type = affectedTypeName.substring(packageSeparator + 1); - } - - IHierarchy hierarchy = model.getHierarchy(); - - IProgramElement typeElem = hierarchy.findElementForType(pkg, type); - if (typeElem == null) { - return; - } - if (!typeElem.getKind().isType()) { - throw new IllegalStateException("Did not find a type element, found a "+typeElem.getKind()+" element"); - } - - StringBuilder parmString = new StringBuilder("("); - UnresolvedType[] args = affectedMethod.getParameterTypes(); - for (int i = 0; i < args.length; i++) { - parmString.append(args[i].getName()); - if ((i + 1) < args.length) { - parmString.append(","); - } - } - parmString.append(")"); - IProgramElement methodElem = null; - - if (affectedMethod.getName().startsWith("<init>")) { - // its a ctor - methodElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.CONSTRUCTOR, type + parmString); - if (methodElem == null && args.length == 0) { - methodElem = typeElem; // assume default ctor - } - } else { - // its a method - methodElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.METHOD, affectedMethod.getName() - + parmString); - } - - if (methodElem == null) { - return; - } - - try { - String targetHandle = methodElem.getHandleIdentifier(); - if (targetHandle == null) { - return; - } - - IProgramElement sourceNode = hierarchy.findElementForSourceLine(sourceLocation); - String sourceHandle = sourceNode.getHandleIdentifier(); - if (sourceHandle == null) { - return; - } - - IRelationshipMap mapper = model.getRelationshipMap(); - IRelationship foreward = mapper.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true); - foreward.addTarget(targetHandle); - - IRelationship back = mapper.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true); - back.addTarget(sourceHandle); - } catch (Throwable t) { // I'm worried about that code above, this will - // make sure we don't explode if it plays up - t.printStackTrace(); // I know I know .. but I don't want to lose - // it! - } - } - - /** - * Add a relationship for a matching declare ATfield. Locating the field is trickier than it might seem since we have no line - * number info for it, we have to dig through the structure model under the fields' type in order to locate it. - */ - public static void addDeclareAnnotationFieldRelationship(AsmManager model, ISourceLocation declareLocation, - String affectedTypeName, ResolvedMember affectedFieldName, boolean isRemove) { - if (model == null) { - return; - } - - String pkg = null; - String type = affectedTypeName; - int packageSeparator = affectedTypeName.lastIndexOf("."); - if (packageSeparator != -1) { - pkg = affectedTypeName.substring(0, packageSeparator); - type = affectedTypeName.substring(packageSeparator + 1); - } - IHierarchy hierarchy = model.getHierarchy(); - IProgramElement typeElem = hierarchy.findElementForType(pkg, type); - if (typeElem == null) { - return; - } - - IProgramElement fieldElem = hierarchy.findElementForSignature(typeElem, IProgramElement.Kind.FIELD, - affectedFieldName.getName()); - if (fieldElem == null) { - return; - } - - String targetHandle = fieldElem.getHandleIdentifier(); - if (targetHandle == null) { - return; - } - - IProgramElement sourceNode = hierarchy.findElementForSourceLine(declareLocation); - String sourceHandle = sourceNode.getHandleIdentifier(); - if (sourceHandle == null) { - return; - } - - IRelationshipMap relmap = model.getRelationshipMap(); - // if (isRemove) { - // IRelationship foreward = relmap.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, REMOVES_ANNOTATION, false, - // true); - // foreward.addTarget(targetHandle); - // IRelationship back = relmap - // .get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATION_REMOVED_BY, false, true); - // back.addTarget(sourceHandle); - // } else { - IRelationship foreward = relmap.get(sourceHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATES, false, true); - foreward.addTarget(targetHandle); - IRelationship back = relmap.get(targetHandle, IRelationship.Kind.DECLARE_INTER_TYPE, ANNOTATED_BY, false, true); - back.addTarget(sourceHandle); - // } - } - -} diff --git a/weaver/src/org/aspectj/weaver/model/AsmRelationshipUtils.java b/weaver/src/org/aspectj/weaver/model/AsmRelationshipUtils.java deleted file mode 100644 index f9c9f6ae2..000000000 --- a/weaver/src/org/aspectj/weaver/model/AsmRelationshipUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************** - * Copyright (c) 2006 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://eclipse.org/legal/epl-v10.html - * - * Contributors: IBM Corporation - initial API and implementation - * Helen Hawkins - initial version - *******************************************************************/ -package org.aspectj.weaver.model; - -import org.aspectj.weaver.patterns.AndPointcut; -import org.aspectj.weaver.patterns.OrPointcut; -import org.aspectj.weaver.patterns.Pointcut; -import org.aspectj.weaver.patterns.ReferencePointcut; - -/** - * Provides utility methods for generating details for IProgramElements used when creating the model both from source (via - * AsmElementFormatter.visit(..)) and when filling in the model for binary aspects (via AsmRelationshipProvider bug 145963) - */ -public class AsmRelationshipUtils { - - // public static final String UNDEFINED="<undefined>"; - public static final String DECLARE_PRECEDENCE = "precedence"; - public static final String DECLARE_SOFT = "soft"; - public static final String DECLARE_PARENTS = "parents"; - public static final String DECLARE_WARNING = "warning"; - public static final String DECLARE_ERROR = "error"; - public static final String DECLARE_UNKNONWN = "<unknown declare>"; - public static final String POINTCUT_ABSTRACT = "<abstract pointcut>"; - public static final String POINTCUT_ANONYMOUS = "<anonymous pointcut>"; - public static final String DOUBLE_DOTS = ".."; - public static final int MAX_MESSAGE_LENGTH = 18; - public static final String DEC_LABEL = "declare"; - - /** - * Generates the declare message used in the details, for example if the declare warning statement has message - * "There should be no printlns" will return 'declare warning: "There should be n.."' - */ - public static String genDeclareMessage(String message) { - int length = message.length(); - if (length < MAX_MESSAGE_LENGTH) { - return message; - } else { - return message.substring(0, MAX_MESSAGE_LENGTH - 1) + DOUBLE_DOTS; - } - } - - /** - * Generates the pointcut details for the given pointcut, for example an anonymous pointcut will return '<anonymous pointcut>' - * and a named pointcut called p() will return 'p()..' - */ - public static String genPointcutDetails(Pointcut pcd) { - StringBuffer details = new StringBuffer(); - if (pcd instanceof ReferencePointcut) { - ReferencePointcut rp = (ReferencePointcut) pcd; - details.append(rp.name).append(DOUBLE_DOTS); - } else if (pcd instanceof AndPointcut) { - AndPointcut ap = (AndPointcut) pcd; - if (ap.getLeft() instanceof ReferencePointcut) { - details.append(ap.getLeft().toString()).append(DOUBLE_DOTS); - } else { - details.append(POINTCUT_ANONYMOUS).append(DOUBLE_DOTS); - } - } else if (pcd instanceof OrPointcut) { - OrPointcut op = (OrPointcut) pcd; - if (op.getLeft() instanceof ReferencePointcut) { - details.append(op.getLeft().toString()).append(DOUBLE_DOTS); - } else { - details.append(POINTCUT_ANONYMOUS).append(DOUBLE_DOTS); - } - } else { - details.append(POINTCUT_ANONYMOUS); - } - return details.toString(); - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java b/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java deleted file mode 100644 index a02400fb0..000000000 --- a/weaver/src/org/aspectj/weaver/tools/WeavingAdaptor.java +++ /dev/null @@ -1,951 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2004 IBM Corporation - * 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: - * Matthew Webster, Adrian Colyer, John Kew + Lyor Goldstein (caching) - * Martin Lippert initial implementation - * ******************************************************************/ - -package org.aspectj.weaver.tools; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; - -import org.aspectj.bridge.AbortException; -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.IMessage.Kind; -import org.aspectj.bridge.IMessageContext; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.IMessageHolder; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageHandler; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.bridge.MessageWriter; -import org.aspectj.bridge.Version; -import org.aspectj.bridge.WeaveMessage; -import org.aspectj.util.FileUtil; -import org.aspectj.util.LangUtil; -import org.aspectj.weaver.IClassFileProvider; -import org.aspectj.weaver.IUnwovenClassFile; -import org.aspectj.weaver.IWeaveRequestor; -import org.aspectj.weaver.World; -import org.aspectj.weaver.bcel.BcelObjectType; -import org.aspectj.weaver.bcel.BcelWeaver; -import org.aspectj.weaver.bcel.BcelWorld; -import org.aspectj.weaver.bcel.UnwovenClassFile; -import org.aspectj.weaver.tools.cache.CachedClassEntry; -import org.aspectj.weaver.tools.cache.CachedClassReference; -import org.aspectj.weaver.tools.cache.SimpleCache; -import org.aspectj.weaver.tools.cache.SimpleCacheFactory; -import org.aspectj.weaver.tools.cache.WeavedClassCache; - -// OPTIMIZE add guards for all the debug/info/etc -/** - * This adaptor allows the AspectJ compiler to be embedded in an existing system to facilitate load-time weaving. It provides an - * interface for a weaving class loader to provide a classpath to be woven by a set of aspects. A callback is supplied to allow a - * class loader to define classes generated by the compiler during the weaving process. - * <p> - * A weaving class loader should create a <code>WeavingAdaptor</code> before any classes are defined, typically during construction. - * The set of aspects passed to the adaptor is fixed for the lifetime of the adaptor although the classpath can be augmented. A - * system property can be set to allow verbose weaving messages to be written to the console. - * - */ -public class WeavingAdaptor implements IMessageContext { - - /** - * System property used to turn on verbose weaving messages - */ - public static final String WEAVING_ADAPTOR_VERBOSE = "aj.weaving.verbose"; - public static final String SHOW_WEAVE_INFO_PROPERTY = "org.aspectj.weaver.showWeaveInfo"; - public static final String TRACE_MESSAGES_PROPERTY = "org.aspectj.tracing.messages"; - - private final static String ASPECTJ_BASE_PACKAGE = "org.aspectj."; - private final static String PACKAGE_INITIAL_CHARS = ASPECTJ_BASE_PACKAGE.charAt(0) + "sj"; - - private boolean enabled = false; - protected boolean verbose = getVerbose(); - protected BcelWorld bcelWorld; - protected BcelWeaver weaver; - private IMessageHandler messageHandler; - private WeavingAdaptorMessageHolder messageHolder; - private boolean abortOnError = false; - protected GeneratedClassHandler generatedClassHandler; - protected Map<String, IUnwovenClassFile> generatedClasses = new HashMap<String, IUnwovenClassFile>(); - public BcelObjectType delegateForCurrentClass; // lazily initialized, should be used to prevent parsing bytecode multiple - // times - protected ProtectionDomain activeProtectionDomain; - - private boolean haveWarnedOnJavax = false; - protected WeavedClassCache cache; - - private int weavingSpecialTypes = 0; - private static final int INITIALIZED = 0x1; - private static final int WEAVE_JAVA_PACKAGE = 0x2; - private static final int WEAVE_JAVAX_PACKAGE = 0x4; - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(WeavingAdaptor.class); - - protected WeavingAdaptor() { - } - - /** - * Construct a WeavingAdaptor with a reference to a weaving class loader. The adaptor will automatically search the class loader - * hierarchy to resolve classes. The adaptor will also search the hierarchy for WeavingClassLoader instances to determine the - * set of aspects to be used for weaving. - * - * @param loader instance of <code>ClassLoader</code> - */ - public WeavingAdaptor(WeavingClassLoader loader) { - // System.err.println("? WeavingAdaptor.<init>(" + loader +"," + aspectURLs.length + ")"); - generatedClassHandler = loader; - init((ClassLoader)loader, getFullClassPath((ClassLoader) loader), getFullAspectPath((ClassLoader) loader/* ,aspectURLs */)); - } - - /** - * Construct a WeavingAdaptor with a reference to a <code>GeneratedClassHandler</code>, a full search path for resolving classes - * and a complete set of aspects. The search path must include classes loaded by the class loader constructing the - * WeavingAdaptor and all its parents in the hierarchy. - * - * @param handler <code>GeneratedClassHandler</code> - * @param classURLs the URLs from which to resolve classes - * @param aspectURLs the aspects used to weave classes defined by this class loader - */ - public WeavingAdaptor(GeneratedClassHandler handler, URL[] classURLs, URL[] aspectURLs) { - // System.err.println("? WeavingAdaptor.<init>()"); - generatedClassHandler = handler; - init(null, FileUtil.makeClasspath(classURLs), FileUtil.makeClasspath(aspectURLs)); - } - - protected List<String> getFullClassPath(ClassLoader loader) { - List<String> list = new LinkedList<String>(); - for (; loader != null; loader = loader.getParent()) { - if (loader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) loader).getURLs(); - list.addAll(0, FileUtil.makeClasspath(urls)); - } else { - warn("cannot determine classpath"); - } - } - // On Java9 it is possible to fail to find a URLClassLoader from which to derive a suitable classpath - // For now we can determine it from the java.class.path: - if (LangUtil.is19VMOrGreater()) { - list.add(0, LangUtil.getJrtFsFilePath()); - List<String> javaClassPathEntries = makeClasspath(System.getProperty("java.class.path")); - for (int i=javaClassPathEntries.size()-1;i>=0;i--) { - String javaClassPathEntry = javaClassPathEntries.get(i); - if (!list.contains(javaClassPathEntry)) { - list.add(0,javaClassPathEntry); - } - } - } - // On Java9 the sun.boot.class.path won't be set. System classes accessible through JRT filesystem - list.addAll(0, makeClasspath(System.getProperty("sun.boot.class.path"))); - return list; - } - - private List<String> getFullAspectPath(ClassLoader loader) { - List<String> list = new LinkedList<String>(); - for (; loader != null; loader = loader.getParent()) { - if (loader instanceof WeavingClassLoader) { - URL[] urls = ((WeavingClassLoader) loader).getAspectURLs(); - list.addAll(0, FileUtil.makeClasspath(urls)); - } - } - return list; - } - - private static boolean getVerbose() { - try { - return Boolean.getBoolean(WEAVING_ADAPTOR_VERBOSE); - } catch (Throwable t) { - // security exception - return false; - } - } - - /** - * Initialize the WeavingAdapter - * @param loader ClassLoader used by this adapter; which can be null - * @param classPath classpath of this adapter - * @param aspectPath list of aspect paths - */ - private void init(ClassLoader loader, List<String> classPath, List<String> aspectPath) { - abortOnError = true; - createMessageHandler(); - - info("using classpath: " + classPath); - info("using aspectpath: " + aspectPath); - - bcelWorld = new BcelWorld(classPath, messageHandler, null); - bcelWorld.setXnoInline(false); - bcelWorld.getLint().loadDefaultProperties(); - if (LangUtil.is15VMOrGreater()) { - bcelWorld.setBehaveInJava5Way(true); - } - - weaver = new BcelWeaver(bcelWorld); - registerAspectLibraries(aspectPath); - initializeCache(loader, aspectPath, null, getMessageHandler()); - enabled = true; - } - - /** - * If the cache is enabled, initialize it and swap out the existing classhandler - * for the caching one - - * - * @param loader classloader for this adapter, may be null - * @param aspects List of strings representing aspects managed by the adapter; these could be urls or classnames - * @param existingClassHandler current class handler - * @param myMessageHandler current message handler - */ - protected void initializeCache(ClassLoader loader, List<String> aspects, GeneratedClassHandler existingClassHandler, IMessageHandler myMessageHandler) { - if (WeavedClassCache.isEnabled()) { - cache = WeavedClassCache.createCache(loader, aspects, existingClassHandler, myMessageHandler); - // Wrap the existing class handler so that any generated classes are also cached - if (cache != null) { - this.generatedClassHandler = cache.getCachingClassHandler(); - } - } - } - - - protected void createMessageHandler() { - messageHolder = new WeavingAdaptorMessageHolder(new PrintWriter(System.err)); - messageHandler = messageHolder; - if (verbose) { - messageHandler.dontIgnore(IMessage.INFO); - } - if (Boolean.getBoolean(SHOW_WEAVE_INFO_PROPERTY)) { - messageHandler.dontIgnore(IMessage.WEAVEINFO); - } - info("AspectJ Weaver Version " + Version.text + " built on " + Version.time_text); //$NON-NLS-1$ - } - - protected IMessageHandler getMessageHandler() { - return messageHandler; - } - - public IMessageHolder getMessageHolder() { - return messageHolder; - } - - protected void setMessageHandler(IMessageHandler mh) { - if (mh instanceof ISupportsMessageContext) { - ISupportsMessageContext smc = (ISupportsMessageContext) mh; - smc.setMessageContext(this); - } - if (mh != messageHolder) { - messageHolder.setDelegate(mh); - } - messageHolder.flushMessages(); - } - - protected void disable() { - if (trace.isTraceEnabled()) { - trace.enter("disable", this); - } - - enabled = false; - messageHolder.flushMessages(); - - if (trace.isTraceEnabled()) { - trace.exit("disable"); - } - } - - protected void enable() { - enabled = true; - messageHolder.flushMessages(); - } - - protected boolean isEnabled() { - return enabled; - } - - /** - * Appends URL to path used by the WeavingAdptor to resolve classes - * - * @param url to be appended to search path - */ - public void addURL(URL url) { - File libFile = new File(url.getPath()); - try { - weaver.addLibraryJarFile(libFile); - } catch (IOException ex) { - warn("bad library: '" + libFile + "'"); - } - } - - /** - * Weave a class using aspects previously supplied to the adaptor. - * - * @param name the name of the class - * @param bytes the class bytes - * @return the woven bytes - * @exception IOException weave failed - */ - public byte[] weaveClass(String name, byte[] bytes) throws IOException { - return weaveClass(name, bytes, false); - } - - // Track if the weaver is already running on this thread - don't allow re-entrant calls - private ThreadLocal<Boolean> weaverRunning = new ThreadLocal<Boolean>() { - @Override - protected Boolean initialValue() { - return Boolean.FALSE; - } - }; - - /** - * Weave a class using aspects previously supplied to the adaptor. - * - * @param name the name of the class - * @param bytes the class bytes - * @param mustWeave if true then this class *must* get woven (used for concrete aspects generated from XML) - * @return the woven bytes - * @exception IOException weave failed - */ - public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException { - if (trace == null) { - // Pr231945: we are likely to be under tomcat and ENABLE_CLEAR_REFERENCES hasn't been set - System.err - .println("AspectJ Weaver cannot continue to weave, static state has been cleared. Are you under Tomcat? In order to weave '" - + name - + "' during shutdown, 'org.apache.catalina.loader.WebappClassLoader.ENABLE_CLEAR_REFERENCES=false' must be set (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=231945)."); - return bytes; - } - if (weaverRunning.get()) { - // System.out.println("AJC: avoiding re-entrant call to transform " + name); - return bytes; - } - try { - weaverRunning.set(true); - if (trace.isTraceEnabled()) { - trace.enter("weaveClass", this, new Object[] { name, bytes }); - } - - if (!enabled) { - if (trace.isTraceEnabled()) { - trace.exit("weaveClass", false); - } - return bytes; - } - - boolean debugOn = !messageHandler.isIgnoring(Message.DEBUG); - - try { - delegateForCurrentClass = null; - name = name.replace('/', '.'); - if (couldWeave(name, bytes)) { - if (accept(name, bytes)) { - - // Determine if we have the weaved class cached - CachedClassReference cacheKey = null; - final byte[] original_bytes = bytes; - if (cache != null && !mustWeave) { - cacheKey = cache.createCacheKey(name, original_bytes); - CachedClassEntry entry = cache.get(cacheKey, original_bytes); - if (entry != null) { - // If the entry has been explicitly ignored - // return the original bytes - if (entry.isIgnored()) { - return bytes; - } - return entry.getBytes(); - } - } - - // TODO @AspectJ problem - // Annotation style aspects need to be included regardless in order to get - // a valid aspectOf()/hasAspect() generated in them. However - if they are excluded - // (via include/exclude in aop.xml) they really should only get aspectOf()/hasAspect() - // and not be included in the full set of aspects being applied by 'this' weaver - if (debugOn) { - debug("weaving '" + name + "'"); - } - bytes = getWovenBytes(name, bytes); - // temporarily out - searching for @Aspect annotated types is a slow thing to do - we should - // expect the user to name them if they want them woven - just like code style - // } else if (shouldWeaveAnnotationStyleAspect(name, bytes)) { - // if (mustWeave) { - // if (bcelWorld.getLint().mustWeaveXmlDefinedAspects.isEnabled()) { - // bcelWorld.getLint().mustWeaveXmlDefinedAspects.signal(name, null); - // } - // } - // // an @AspectJ aspect needs to be at least munged by the aspectOf munger - // if (debugOn) { - // debug("weaving '" + name + "'"); - // } - // bytes = getAtAspectJAspectBytes(name, bytes); - - // Add the weaved class to the cache only if there - // has been an actual change - // JVK: Is there a better way to check if the class has - // been transformed without carrying up some value - // from the depths? - if (cacheKey != null) { - // If no transform has been applied, mark the class - // as ignored. - if (Arrays.equals(original_bytes, bytes)) { - cache.ignore(cacheKey, original_bytes); - } else { - cache.put(cacheKey, original_bytes, bytes); - } - } - } else if (debugOn) { - debug("not weaving '" + name + "'"); - } - } else if (debugOn) { - debug("cannot weave '" + name + "'"); - } - } finally { - delegateForCurrentClass = null; - } - - if (trace.isTraceEnabled()) { - trace.exit("weaveClass", bytes); - } - return bytes; - } finally { - weaverRunning.set(false); - } - } - - /** - * @param name - * @return true if even valid to weave: either with an accept check or to munge it for @AspectJ aspectof support - */ - private boolean couldWeave(String name, byte[] bytes) { - return !generatedClasses.containsKey(name) && shouldWeaveName(name); - } - - // ATAJ - protected boolean accept(String name, byte[] bytes) { - return true; - } - - protected boolean shouldDump(String name, boolean before) { - return false; - } - - private boolean shouldWeaveName(String name) { - if (PACKAGE_INITIAL_CHARS.indexOf(name.charAt(0)) != -1) { - if ((weavingSpecialTypes & INITIALIZED) == 0) { - weavingSpecialTypes |= INITIALIZED; - // initialize it - Properties p = weaver.getWorld().getExtraConfiguration(); - if (p != null) { - boolean b = p.getProperty(World.xsetWEAVE_JAVA_PACKAGES, "false").equalsIgnoreCase("true"); - if (b) { - weavingSpecialTypes |= WEAVE_JAVA_PACKAGE; - } - b = p.getProperty(World.xsetWEAVE_JAVAX_PACKAGES, "false").equalsIgnoreCase("true"); - if (b) { - weavingSpecialTypes |= WEAVE_JAVAX_PACKAGE; - } - } - } - if (name.startsWith(ASPECTJ_BASE_PACKAGE)) { - return false; - } - if (name.startsWith("sun.reflect.")) {// JDK reflect - return false; - } - if (name.startsWith("javax.")) { - if ((weavingSpecialTypes & WEAVE_JAVAX_PACKAGE) != 0) { - return true; - } else { - if (!haveWarnedOnJavax) { - haveWarnedOnJavax = true; - warn("javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified"); - } - return false; - } - } - if (name.startsWith("java.")) { - if ((weavingSpecialTypes & WEAVE_JAVA_PACKAGE) != 0) { - return true; - } else { - return false; - } - } - } - // boolean should = !(name.startsWith("org.aspectj.") - // || (name.startsWith("java.") && (weavingSpecialTypes & WEAVE_JAVA_PACKAGE) == 0) - // || (name.startsWith("javax.") && (weavingSpecialTypes & WEAVE_JAVAX_PACKAGE) == 0) - // // || name.startsWith("$Proxy")//JDK proxies//FIXME AV is that 1.3 proxy ? fe. ataspect.$Proxy0 is a java5 proxy... - // || name.startsWith("sun.reflect.")); - return true; - } - - /** - * We allow @AJ aspect weaving so that we can add aspectOf() as part of the weaving (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 shouldWeaveAnnotationStyleAspect(String name, byte[] bytes) { - if (delegateForCurrentClass == null) { - // if (weaver.getWorld().isASMAround()) return asmCheckAnnotationStyleAspect(bytes); - // else - ensureDelegateInitialized(name, bytes); - } - return (delegateForCurrentClass.isAnnotationStyleAspect()); - } - - // private boolean asmCheckAnnotationStyleAspect(byte[] bytes) { - // IsAtAspectAnnotationVisitor detector = new IsAtAspectAnnotationVisitor(); - // - // ClassReader cr = new ClassReader(bytes); - // try { - // cr.accept(detector, true);//, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); - // } catch (Exception spe) { - // // if anything goes wrong, e.g., an NPE, then assume it's NOT an @AspectJ aspect... - // System.err.println("Unexpected problem parsing bytes to discover @Aspect annotation"); - // spe.printStackTrace(); - // return false; - // } - // - // return detector.isAspect(); - // } - - protected void ensureDelegateInitialized(String name, byte[] bytes) { - if (delegateForCurrentClass == null) { - BcelWorld world = (BcelWorld) weaver.getWorld(); - delegateForCurrentClass = world.addSourceObjectType(name, bytes, false); - } - } - - /** - * Weave a set of bytes defining a class. - * - * @param name the name of the class being woven - * @param bytes the bytes that define the class - * @return byte[] the woven bytes for the class - * @throws IOException - */ - private byte[] getWovenBytes(String name, byte[] bytes) throws IOException { - WeavingClassFileProvider wcp = new WeavingClassFileProvider(name, bytes); - weaver.weave(wcp); - return wcp.getBytes(); - } - - /** - * Weave a set of bytes defining a class for only what is needed to turn @AspectJ aspect in a usefull form ie with aspectOf - * method - see #113587 - * - * @param name the name of the class being woven - * @param bytes the bytes that define the class - * @return byte[] the woven bytes for the class - * @throws IOException - */ - private byte[] getAtAspectJAspectBytes(String name, byte[] bytes) throws IOException { - WeavingClassFileProvider wcp = new WeavingClassFileProvider(name, bytes); - wcp.setApplyAtAspectJMungersOnly(); - weaver.weave(wcp); - return wcp.getBytes(); - } - - private void registerAspectLibraries(List aspectPath) { - // System.err.println("? WeavingAdaptor.registerAspectLibraries(" + aspectPath + ")"); - for (Iterator i = aspectPath.iterator(); i.hasNext();) { - String libName = (String) i.next(); - addAspectLibrary(libName); - } - - weaver.prepareForWeave(); - } - - /* - * Register an aspect library with this classloader for use during weaving. This class loader will also return (unmodified) any - * of the classes in the library in response to a <code>findClass()</code> request. The library is not required to be on the - * weavingClasspath given when this classloader was constructed. - * - * @param aspectLibraryJarFile a jar file representing an aspect library - * - * @throws IOException - */ - private void addAspectLibrary(String aspectLibraryName) { - File aspectLibrary = new File(aspectLibraryName); - if (aspectLibrary.isDirectory() || (FileUtil.isZipFile(aspectLibrary))) { - try { - info("adding aspect library: '" + aspectLibrary + "'"); - weaver.addLibraryJarFile(aspectLibrary); - } catch (IOException ex) { - error("exception adding aspect library: '" + ex + "'"); - } - } else { - error("bad aspect library: '" + aspectLibrary + "'"); - } - } - - private static List<String> makeClasspath(String cp) { - List<String> ret = new ArrayList<String>(); - if (cp != null) { - StringTokenizer tok = new StringTokenizer(cp, File.pathSeparator); - while (tok.hasMoreTokens()) { - ret.add(tok.nextToken()); - } - } - return ret; - } - - protected boolean debug(String message) { - return MessageUtil.debug(messageHandler, message); - } - - protected boolean info(String message) { - return MessageUtil.info(messageHandler, message); - } - - protected boolean warn(String message) { - return MessageUtil.warn(messageHandler, message); - } - - protected boolean warn(String message, Throwable th) { - return messageHandler.handleMessage(new Message(message, IMessage.WARNING, th, null)); - } - - protected boolean error(String message) { - return MessageUtil.error(messageHandler, message); - } - - protected boolean error(String message, Throwable th) { - return messageHandler.handleMessage(new Message(message, IMessage.ERROR, th, null)); - } - - public String getContextId() { - return "WeavingAdaptor"; - } - - /** - * Dump the given bytcode in _dump/... (dev mode) - * - * @param name - * @param b - * @param before whether we are dumping before weaving - * @throws Throwable - */ - protected void dump(String name, byte[] b, boolean before) { - String dirName = getDumpDir(); - - if (before) { - dirName = dirName + File.separator + "_before"; - } - - String className = name.replace('.', '/'); - final File dir; - if (className.indexOf('/') > 0) { - dir = new File(dirName + File.separator + className.substring(0, className.lastIndexOf('/'))); - } else { - dir = new File(dirName); - } - dir.mkdirs(); - String fileName = dirName + File.separator + className + ".class"; - try { - // System.out.println("WeavingAdaptor.dump() fileName=" + new File(fileName).getAbsolutePath()); - FileOutputStream os = new FileOutputStream(fileName); - os.write(b); - os.close(); - } catch (IOException ex) { - warn("unable to dump class " + name + " in directory " + dirName, ex); - } - } - - /** - * @return the directory in which to dump - default is _ajdump but it - */ - protected String getDumpDir() { - return "_ajdump"; - } - - /** - * Processes messages arising from weaver operations. Tell weaver to abort on any message more severe than warning. - */ - protected class WeavingAdaptorMessageHolder extends MessageHandler { - - private IMessageHandler delegate; - private List<IMessage> savedMessages; - - protected boolean traceMessages = Boolean.getBoolean(TRACE_MESSAGES_PROPERTY); - - public WeavingAdaptorMessageHolder(PrintWriter writer) { - - this.delegate = new WeavingAdaptorMessageWriter(writer); - super.dontIgnore(IMessage.WEAVEINFO); - } - - private void traceMessage(IMessage message) { - if (message instanceof WeaveMessage) { - trace.debug(render(message)); - } else if (message.isDebug()) { - trace.debug(render(message)); - } else if (message.isInfo()) { - trace.info(render(message)); - } else if (message.isWarning()) { - trace.warn(render(message), message.getThrown()); - } else if (message.isError()) { - trace.error(render(message), message.getThrown()); - } else if (message.isFailed()) { - trace.fatal(render(message), message.getThrown()); - } else if (message.isAbort()) { - trace.fatal(render(message), message.getThrown()); - } else { - trace.error(render(message), message.getThrown()); - } - } - - protected String render(IMessage message) { - return "[" + getContextId() + "] " + message.toString(); - } - - public void flushMessages() { - if (savedMessages == null) { - savedMessages = new ArrayList<IMessage>(); - savedMessages.addAll(super.getUnmodifiableListView()); - clearMessages(); - for (IMessage message : savedMessages) { - delegate.handleMessage(message); - } - } - // accumulating = false; - // messages.clear(); - } - - public void setDelegate(IMessageHandler messageHandler) { - delegate = messageHandler; - } - - /* - * IMessageHandler - */ - - @Override - public boolean handleMessage(IMessage message) throws AbortException { - if (traceMessages) { - traceMessage(message); - } - - super.handleMessage(message); - - if (abortOnError && 0 <= message.getKind().compareTo(IMessage.ERROR)) { - throw new AbortException(message); - } - // if (accumulating) { - // boolean result = addMessage(message); - // if (abortOnError && 0 <= message.getKind().compareTo(IMessage.ERROR)) { - // throw new AbortException(message); - // } - // return result; - // } - // else return delegate.handleMessage(message); - - if (savedMessages != null) { - delegate.handleMessage(message); - } - return true; - } - - @Override - public boolean isIgnoring(Kind kind) { - return delegate.isIgnoring(kind); - } - - @Override - public void dontIgnore(IMessage.Kind kind) { - if (null != kind && delegate != null) { - delegate.dontIgnore(kind); - } - } - - @Override - public void ignore(Kind kind) { - if (null != kind && delegate != null) { - delegate.ignore(kind); - } - } - - /* - * IMessageHolder - */ - - @Override - public List<IMessage> getUnmodifiableListView() { - // System.err.println("? WeavingAdaptorMessageHolder.getUnmodifiableListView() savedMessages=" + savedMessages); - List<IMessage> allMessages = new ArrayList<IMessage>(); - allMessages.addAll(savedMessages); - allMessages.addAll(super.getUnmodifiableListView()); - return allMessages; - } - } - - protected class WeavingAdaptorMessageWriter extends MessageWriter { - - private final Set<IMessage.Kind> ignoring = new HashSet<IMessage.Kind>(); - private final IMessage.Kind failKind; - - public WeavingAdaptorMessageWriter(PrintWriter writer) { - super(writer, true); - - ignore(IMessage.WEAVEINFO); - ignore(IMessage.DEBUG); - ignore(IMessage.INFO); - this.failKind = IMessage.ERROR; - } - - @Override - public boolean handleMessage(IMessage message) throws AbortException { - // boolean result = - super.handleMessage(message); - if (abortOnError && 0 <= message.getKind().compareTo(failKind)) { - throw new AbortException(message); - } - return true; - } - - @Override - public boolean isIgnoring(Kind kind) { - return ((null != kind) && (ignoring.contains(kind))); - } - - /** - * Set a message kind to be ignored from now on - */ - @Override - public void ignore(IMessage.Kind kind) { - if ((null != kind) && (!ignoring.contains(kind))) { - ignoring.add(kind); - } - } - - /** - * Remove a message kind from the list of those ignored from now on. - */ - @Override - public void dontIgnore(IMessage.Kind kind) { - if (null != kind) { - ignoring.remove(kind); - } - } - - @Override - protected String render(IMessage message) { - return "[" + getContextId() + "] " + super.render(message); - } - } - - private class WeavingClassFileProvider implements IClassFileProvider { - - private final UnwovenClassFile unwovenClass; - private final List<UnwovenClassFile> unwovenClasses = new ArrayList<UnwovenClassFile>(); - private IUnwovenClassFile wovenClass; - private boolean isApplyAtAspectJMungersOnly = false; - - public WeavingClassFileProvider(String name, byte[] bytes) { - ensureDelegateInitialized(name, bytes); - this.unwovenClass = new UnwovenClassFile(name, delegateForCurrentClass.getResolvedTypeX().getName(), bytes); - this.unwovenClasses.add(unwovenClass); - - if (shouldDump(name.replace('/', '.'), true)) { - dump(name, bytes, true); - } - - } - - public void setApplyAtAspectJMungersOnly() { - isApplyAtAspectJMungersOnly = true; - } - - public boolean isApplyAtAspectJMungersOnly() { - return isApplyAtAspectJMungersOnly; - } - - public byte[] getBytes() { - if (wovenClass != null) { - return wovenClass.getBytes(); - } else { - return unwovenClass.getBytes(); - } - } - - public Iterator<UnwovenClassFile> getClassFileIterator() { - return unwovenClasses.iterator(); - } - - public IWeaveRequestor getRequestor() { - return new IWeaveRequestor() { - - public void acceptResult(IUnwovenClassFile result) { - if (wovenClass == null) { - wovenClass = result; - String name = result.getClassName(); - if (shouldDump(name.replace('/', '.'), false)) { - dump(name, result.getBytes(), false); - } - } else { - // Classes generated by weaver e.g. around closure advice - String className = result.getClassName(); - byte[] resultBytes = result.getBytes(); - - if (SimpleCacheFactory.isEnabled()) { - SimpleCache lacache=SimpleCacheFactory.createSimpleCache(); - lacache.put(result.getClassName(), wovenClass.getBytes(), result.getBytes()); - lacache.addGeneratedClassesNames(wovenClass.getClassName(), wovenClass.getBytes(), result.getClassName()); - } - - generatedClasses.put(className, result); - generatedClasses.put(wovenClass.getClassName(), result); - generatedClassHandler.acceptClass(className, null, resultBytes); - } - } - - public void processingReweavableState() { - } - - public void addingTypeMungers() { - } - - public void weavingAspects() { - } - - public void weavingClasses() { - } - - public void weaveCompleted() { - // ResolvedType.resetPrimitives(); - if (delegateForCurrentClass != null) { - delegateForCurrentClass.weavingCompleted(); - } - // ResolvedType.resetPrimitives(); - // bcelWorld.discardType(typeBeingProcessed.getResolvedTypeX()); // work in progress - } - }; - } - } - - public void setActiveProtectionDomain(ProtectionDomain protectionDomain) { - activeProtectionDomain = protectionDomain; - } -}
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/tools/cache/AbstractCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/AbstractCacheBacking.java deleted file mode 100644 index 649e21d05..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/AbstractCacheBacking.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -import java.util.zip.CRC32; - -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -/** - * Basic "common" {@link CacheBacking} implementation - */ -public abstract class AbstractCacheBacking implements CacheBacking { - protected final Trace logger=TraceFactory.getTraceFactory().getTrace(getClass()); - - protected AbstractCacheBacking () { - super(); - } - - /** - * Calculates CRC32 on the provided bytes - * @param bytes The bytes array - ignored if <code>null</code>/empty - * @return Calculated CRC - * @see {@link CRC32} - */ - public static final long crc (byte[] bytes) { - if ((bytes == null) || (bytes.length <= 0)) { - return 0L; - } - - CRC32 crc32=new CRC32(); - crc32.update(bytes); - return crc32.getValue(); - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/AbstractFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/AbstractFileCacheBacking.java deleted file mode 100644 index 5447c158b..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/AbstractFileCacheBacking.java +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Useful "common" functionality for caching to files - */ -public abstract class AbstractFileCacheBacking extends AbstractCacheBacking { - /** - * Default property used to specify a default weaving cache dir location - */ - public static final String WEAVED_CLASS_CACHE_DIR = "aj.weaving.cache.dir"; - private final File cacheDirectory; - - protected AbstractFileCacheBacking (File cacheDirectory) { - if ((this.cacheDirectory=cacheDirectory) == null) { - throw new IllegalStateException("No cache directory specified"); - } - } - - public File getCacheDirectory () { - return cacheDirectory; - } - - protected void writeClassBytes (String key, byte[] bytes) throws Exception { - File dir=getCacheDirectory(), file=new File(dir, key); - FileOutputStream out=new FileOutputStream(file); - try { - out.write(bytes); - } finally { - close(out, file); - } - } - - protected void delete(File file) { - if (file.exists() && (!file.delete())) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Error deleting file " + file.getAbsolutePath()); - } - } - } - - protected void close(OutputStream out, File file) { - if (out != null) { - try { - out.close(); - } catch (IOException e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Failed (" + e.getClass().getSimpleName() + ")" - + " to close write file " + file.getAbsolutePath() - + ": " + e.getMessage(), e); - } - } - } - } - - protected void close(InputStream in, File file) { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Failed (" + e.getClass().getSimpleName() + ")" - + " to close read file " + file.getAbsolutePath() - + ": " + e.getMessage(), e); - } - } - } - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/AbstractIndexedFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/AbstractIndexedFileCacheBacking.java deleted file mode 100644 index 1580277b1..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/AbstractIndexedFileCacheBacking.java +++ /dev/null @@ -1,262 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.io.StreamCorruptedException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.Map; -import java.util.TreeMap; - -import org.aspectj.util.LangUtil; - -/** - * Uses an <code>index</code> file to keep track of the cached entries - */ -public abstract class AbstractIndexedFileCacheBacking extends AbstractFileCacheBacking { - /** - * Default name of cache index file - assumed to contain {@link IndexEntry}-s - */ - public static final String INDEX_FILE = "cache.idx"; - protected static final IndexEntry[] EMPTY_INDEX=new IndexEntry[0]; - protected static final String[] EMPTY_KEYS=new String[0]; - - private final File indexFile; - - protected AbstractIndexedFileCacheBacking(File cacheDir) { - super(cacheDir); - - indexFile = new File(cacheDir, INDEX_FILE); - } - - public File getIndexFile () { - return indexFile; - } - - public String[] getKeys(String regex) { - Map<String, IndexEntry> index=getIndex(); - if ((index == null) || index.isEmpty()) { - return EMPTY_KEYS; - } - - Collection<String> matches=new LinkedList<String>(); - synchronized(index) { - for (String key : index.keySet()) { - if (key.matches(regex)) { - matches.add(key); - } - } - } - - if (matches.isEmpty()) { - return EMPTY_KEYS; - } else { - return matches.toArray(new String[matches.size()]); - } - } - - protected Map<String, IndexEntry> readIndex () { - return readIndex(getCacheDirectory(), getIndexFile()); - } - - protected void writeIndex () { - writeIndex(getIndexFile()); - } - - protected void writeIndex (File file) { - try { - writeIndex(file, getIndex()); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("writeIndex(" + file + ") " + e.getClass().getSimpleName() + ": " + e.getMessage(), e); - } - } - } - - protected abstract Map<String, IndexEntry> getIndex (); - - protected Map<String, IndexEntry> readIndex (File cacheDir, File cacheFile) { - Map<String, IndexEntry> indexMap=new TreeMap<String, IndexEntry>(); - IndexEntry[] idxValues=readIndex(cacheFile); - if (LangUtil.isEmpty(idxValues)) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("readIndex(" + cacheFile + ") no index entries"); - } - return indexMap; - } - - for (IndexEntry ie : idxValues) { - IndexEntry resEntry=resolveIndexMapEntry(cacheDir, ie); - if (resEntry != null) { - indexMap.put(resEntry.key, resEntry); - } else if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("readIndex(" + cacheFile + ") skip " + ie.key); - } - } - - return indexMap; - } - - protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) { - return ie; - } - - public IndexEntry[] readIndex(File indexFile) { - if (!indexFile.canRead()) { - return EMPTY_INDEX; - } - - ObjectInputStream ois = null; - try { - ois = new ObjectInputStream(new FileInputStream(indexFile)); - return (IndexEntry[]) ois.readObject(); - } catch (Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Failed (" + e.getClass().getSimpleName() + ")" - + " to read index from " + indexFile.getAbsolutePath() - + " : " + e.getMessage(), e); - } - delete(indexFile); - } finally { - close(ois, indexFile); - } - - return EMPTY_INDEX; - } - - protected void writeIndex (File indexFile, Map<String,? extends IndexEntry> index) throws IOException { - writeIndex(indexFile, LangUtil.isEmpty(index) ? Collections.<IndexEntry>emptyList() : index.values()); - } - - protected void writeIndex (File indexFile, IndexEntry ... entries) throws IOException { - writeIndex(indexFile, LangUtil.isEmpty(entries) ? Collections.<IndexEntry>emptyList() : Arrays.asList(entries)); - } - - protected void writeIndex (File indexFile, Collection<? extends IndexEntry> entries) throws IOException { - File indexDir=indexFile.getParentFile(); - if ((!indexDir.exists()) && (!indexDir.mkdirs())) { - throw new IOException("Failed to create path to " + indexFile.getAbsolutePath()); - } - - int numEntries=LangUtil.isEmpty(entries) ? 0 : entries.size(); - IndexEntry[] entryValues=(numEntries <= 0) ? null : entries.toArray(new IndexEntry[numEntries]); - // if no entries, simply delete the index file - if (LangUtil.isEmpty(entryValues)) { - if (indexFile.exists() && (!indexFile.delete())) { - throw new StreamCorruptedException("Failed to clean up index file at " + indexFile.getAbsolutePath()); - } - - return; - } - - ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(indexFile), 4096)); - try { - oos.writeObject(entryValues); - } finally { - close(oos, indexFile); - } - } - - public static final IndexEntry createIndexEntry (CachedClassEntry classEntry, byte[] originalBytes) { - if (classEntry == null) { - return null; - } - - IndexEntry indexEntry = new IndexEntry(); - indexEntry.key = classEntry.getKey(); - indexEntry.generated = classEntry.isGenerated(); - indexEntry.ignored = classEntry.isIgnored(); - indexEntry.crcClass = crc(originalBytes); - if (!classEntry.isIgnored()) { - indexEntry.crcWeaved = crc(classEntry.getBytes()); - } - - return indexEntry; - } - - /** - * The default index entry in the index file - */ - public static class IndexEntry implements Serializable, Cloneable { - private static final long serialVersionUID = 756391290557029363L; - - public String key; - public boolean generated; - public boolean ignored; - public long crcClass; - public long crcWeaved; - - public IndexEntry () { - super(); - } - - @Override - public IndexEntry clone () { - try { - return getClass().cast(super.clone()); - } catch(CloneNotSupportedException e) { - throw new RuntimeException("Failed to clone: " + toString() + ": " + e.getMessage(), e); - } - } - - @Override - public int hashCode() { - return (int) (key.hashCode() - + (generated ? 1 : 0) - + (ignored ? 1 : 0) - + crcClass - + crcWeaved); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) - return false; - if (this == obj) - return true; - if (getClass() != obj.getClass()) - return false; - - IndexEntry other=(IndexEntry) obj; - if (this.key.equals(other.key) - && (this.ignored == other.ignored) - && (this.generated == other.generated) - && (this.crcClass == other.crcClass) - && (this.crcWeaved == other.crcWeaved)) { - return true; - } else { - return false; - } - } - - @Override - public String toString() { - return key - + "[" + (generated ? "generated" : "ignored") + "]" - + ";crcClass=0x" + Long.toHexString(crcClass) - + ";crcWeaved=0x" + Long.toHexString(crcWeaved) - ; - } - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/AsynchronousFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/AsynchronousFileCacheBacking.java deleted file mode 100644 index 636a82a7a..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/AsynchronousFileCacheBacking.java +++ /dev/null @@ -1,424 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; - -import org.aspectj.util.FileUtil; -import org.aspectj.util.LangUtil; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - -/** - * Uses a background thread to do the actual I/O and for caching "persistence" - * so that the caching works faster on repeated activations of the application. - * The class maintains an in-memory cache, and uses a queue of {@link AsyncCommand}s - * to signal to a background thread various actions required to "synchronize" - * the in-memory cache with the persisted copy. Whenever there is a cache miss - * from the {@link #get(CachedClassReference)} call, the weaver issues a - * {@link #put(CachedClassEntry)} call. This call has 2 side-effects:</BR> - * <UL> - * <LI> - * The in-memory cache is updated so that subsequent calls to {@link #get(CachedClassReference)} - * will not return the mapped value. - * </LI> - * - * <LI> - * An "update index" {@link AsyncCommand} is posted to the background - * thread so that the newly mapped value will be persisted (eventually) - * </LI> - * </UL> - * The actual persistence is implemented by the <U>concrete</U> classes - */ -public abstract class AsynchronousFileCacheBacking extends AbstractIndexedFileCacheBacking { - private static final BlockingQueue<AsyncCommand> commandsQ=new LinkedBlockingQueue<AsyncCommand>(); - private static final ExecutorService execService=Executors.newSingleThreadExecutor(); - private static Future<?> commandsRunner; - - protected final Map<String, IndexEntry> index, exposedIndex; - protected final Map<String, byte[]> bytesMap, exposedBytes; - - protected AsynchronousFileCacheBacking (File cacheDir) { - super(cacheDir); - - index = readIndex(cacheDir, getIndexFile()); - exposedIndex = Collections.unmodifiableMap(index); - bytesMap = readClassBytes(index, cacheDir); - exposedBytes = Collections.unmodifiableMap(bytesMap); - } - - @Override - protected Map<String, IndexEntry> getIndex() { - return index; - } - - public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes) { - String key=ref.getKey(); - final IndexEntry indexEntry; - synchronized(index) { - if ((indexEntry=index.get(key)) == null) { - return null; - } - } - - if (crc(originalBytes) != indexEntry.crcClass) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("get(" + getCacheDirectory() + ") mismatched original class bytes CRC for " + key); - } - - remove(key); - return null; - } - - if (indexEntry.ignored) { - return new CachedClassEntry(ref, WeavedClassCache.ZERO_BYTES, CachedClassEntry.EntryType.IGNORED); - } - - final byte[] bytes; - synchronized(bytesMap) { - /* - * NOTE: we assume that keys represent classes so if we have their - * bytes they will not be re-created - */ - if ((bytes=bytesMap.remove(key)) == null) { - return null; - } - } - - if (indexEntry.generated) { - return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.GENERATED); - } else { - return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.WEAVED); - } - } - - public void put(CachedClassEntry entry, byte[] originalBytes) { - String key=entry.getKey(); - byte[] bytes=entry.isIgnored() ? null : entry.getBytes(); - synchronized(index) { - IndexEntry indexEntry=index.get(key); - if (indexEntry != null) { - return; - } - - /* - * Note: we do not cache the class bytes - only send them to - * be saved. The assumption is that the 'put' call was invoked - * because 'get' failed to return any bytes. And since we assume - * that each class bytes are required only once, there is no - * need to cache them - */ - indexEntry = createIndexEntry(entry, originalBytes); - index.put(key, indexEntry); - } - - if (!postCacheCommand(new InsertCommand(this, key, bytes))) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("put(" + getCacheDirectory() + ") Failed to post insert command for " + key); - } - } - - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("put(" + getCacheDirectory() + ")[" + key + "] inserted"); - } - } - - public void remove(CachedClassReference ref) { - remove(ref.getKey()); - } - - protected IndexEntry remove (String key) { - IndexEntry entry; - synchronized(index) { - entry = index.remove(key); - } - - synchronized(bytesMap) { - bytesMap.remove(key); - } - - if (!postCacheCommand(new RemoveCommand(this, key))) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("remove(" + getCacheDirectory() + ") Failed to post remove command for " + key); - } - } - - if (entry != null) { - if (!key.equals(entry.key)) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("remove(" + getCacheDirectory() + ") Mismatched keys: " + key + " / " + entry.key); - } - } else if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("remove(" + getCacheDirectory() + ")[" + key + "] removed"); - } - } - - return entry; - } - - public List<IndexEntry> getIndexEntries () { - synchronized(index) { - if (index.isEmpty()) { - return Collections.emptyList(); - } else { - return new ArrayList<IndexEntry>(index.values()); - } - } - } - - public Map<String, IndexEntry> getIndexMap () { - return exposedIndex; - } - - public Map<String, byte[]> getBytesMap () { - return exposedBytes; - } - - public void clear() { - synchronized(index) { - index.clear(); - } - - if (!postCacheCommand(new ClearCommand(this))) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Failed to post clear command for " + getIndexFile()); - } - } - } - - protected void executeCommand (AsyncCommand cmd) throws Exception { - if (cmd instanceof ClearCommand) { - executeClearCommand(); - } else if (cmd instanceof UpdateIndexCommand) { - executeUpdateIndexCommand(); - } else if (cmd instanceof InsertCommand) { - executeInsertCommand((InsertCommand) cmd); - } else if (cmd instanceof RemoveCommand) { - executeRemoveCommand((RemoveCommand) cmd); - } else { - throw new UnsupportedOperationException("Unknown command: " + cmd); - } - } - - protected void executeClearCommand () throws Exception { - FileUtil.deleteContents(getIndexFile()); - FileUtil.deleteContents(getCacheDirectory()); - } - - protected void executeUpdateIndexCommand () throws Exception { - writeIndex(getIndexFile(), getIndexEntries()); - } - - protected void executeInsertCommand (InsertCommand cmd) throws Exception { - writeIndex(getIndexFile(), getIndexEntries()); - - byte[] bytes=cmd.getClassBytes(); - if (bytes != null) { - writeClassBytes(cmd.getKey(), bytes); - } - } - - protected void executeRemoveCommand (RemoveCommand cmd) throws Exception { - Exception err=null; - try { - removeClassBytes(cmd.getKey()); - } catch(Exception e) { - err = e; - } - - writeIndex(getIndexFile(), getIndexEntries()); - - if (err != null) { - throw err; // check if the class bytes remove had any problems - } - } - - /** - * Helper for {@link #executeRemoveCommand(RemoveCommand)} - * @param key The key representing the class whose bytes are to be removed - * @throws Exception if failed to remove class bytes - */ - protected abstract void removeClassBytes (String key) throws Exception; - - protected abstract Map<String, byte[]> readClassBytes (Map<String,IndexEntry> indexMap, File cacheDir); - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + String.valueOf(getCacheDirectory()) + "]"; - } - - protected static final <T extends AsynchronousFileCacheBacking> T createBacking ( - File cacheDir, AsynchronousFileCacheBackingCreator<T> creator) { - final Trace trace=TraceFactory.getTraceFactory().getTrace(AsynchronousFileCacheBacking.class); - if (!cacheDir.exists()) { - if (!cacheDir.mkdirs()) { - if ((trace != null) && trace.isTraceEnabled()) { - trace.error("Unable to create cache directory at " + cacheDir.getAbsolutePath()); - } - return null; - } - } - - if (!cacheDir.canWrite()) { - if ((trace != null) && trace.isTraceEnabled()) { - trace.error("Cache directory is not writable at " + cacheDir.getAbsolutePath()); - } - return null; - } - - // start the service (if needed) only if successfully create the backing instance - T backing=creator.create(cacheDir); - synchronized(execService) { - if (commandsRunner == null) { - commandsRunner = execService.submit(new Runnable() { - @SuppressWarnings("synthetic-access") - public void run() { - for ( ; ; ) { - try { - AsyncCommand cmd=commandsQ.take(); - try { - AsynchronousFileCacheBacking cache=cmd.getCache(); - cache.executeCommand(cmd); - } catch(Exception e) { - if ((trace != null) && trace.isTraceEnabled()) { - trace.error("Failed (" + e.getClass().getSimpleName() + ")" - + " to execute " + cmd + ": " + e.getMessage(), e); - } - } - } catch(InterruptedException e) { - if ((trace != null) && trace.isTraceEnabled()) { - trace.warn("Interrupted"); - } - Thread.currentThread().interrupt(); - break; - } - } - } - }); - } - } - - // fire-up an update-index command in case index was changed by the constructor - if (!postCacheCommand(new UpdateIndexCommand(backing))) { - if ((trace != null) && trace.isTraceEnabled()) { - trace.warn("Failed to offer update index command to " + cacheDir.getAbsolutePath()); - } - } - - return backing; - } - - public static final boolean postCacheCommand (AsyncCommand cmd) { - return commandsQ.offer(cmd); - } - - public static interface AsynchronousFileCacheBackingCreator<T extends AsynchronousFileCacheBacking> { - T create (File cacheDir); - } - /** - * Represents an asynchronous command that can be sent to the - * {@link AsynchronousFileCacheBacking} instance to be executed - * on it <U>asynchronously</U> - */ - public static interface AsyncCommand { - /** - * @return The {@link AsynchronousFileCacheBacking} on which - * this command is supposed to be executed - * @see AsynchronousFileCacheBacking#executeCommand(AsyncCommand) - */ - AsynchronousFileCacheBacking getCache (); - } - - public static abstract class AbstractCommand implements AsyncCommand { - private final AsynchronousFileCacheBacking cache; - protected AbstractCommand (AsynchronousFileCacheBacking backing) { - if ((cache=backing) == null) { - throw new IllegalStateException("No backing cache specified"); - } - } - - public final AsynchronousFileCacheBacking getCache () { - return cache; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + getCache() + "]"; - } - } - - public static class ClearCommand extends AbstractCommand { - public ClearCommand (AsynchronousFileCacheBacking cache) { - super(cache); - } - } - - public static class UpdateIndexCommand extends AbstractCommand { - public UpdateIndexCommand (AsynchronousFileCacheBacking cache) { - super(cache); - } - } - - /** - * Base class for {@link AbstractCommand}s that refer to a cache key - */ - public static abstract class KeyedCommand extends AbstractCommand { - private final String key; - protected KeyedCommand (AsynchronousFileCacheBacking cache, String keyValue) { - super(cache); - - if (LangUtil.isEmpty(keyValue)) { - throw new IllegalStateException("No key value"); - } - - key = keyValue; - } - - public final String getKey () { - return key; - } - - @Override - public String toString() { - return super.toString() + "[" + getKey() + "]"; - } - } - - public static class RemoveCommand extends KeyedCommand { - public RemoveCommand (AsynchronousFileCacheBacking cache, String keyValue) { - super(cache, keyValue); - } - } - - public static class InsertCommand extends KeyedCommand { - private final byte[] bytes; - - public InsertCommand (AsynchronousFileCacheBacking cache, String keyValue, byte[] classBytes) { - super(cache, keyValue); - bytes = classBytes; - } - - public final byte[] getClassBytes () { - return bytes; - } - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java deleted file mode 100644 index bcf7c0b60..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheBacking.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -/** - * Interface for the backing to the cache; usually a file, - * but could be an in-memory backing for testing. - * <p/> - * aspectj and jvmti provide no suitable guarantees - * on locking for class redefinitions, so every implementation - * must have a some locking mechanism to prevent invalid reads. - */ -public interface CacheBacking { - /** - * Return a list of keys which match the given - * regex. - * - * @param regex - * @return - */ - public String[] getKeys(String regex); - - /** - * Remove an entry from the cache - * - * @param ref - */ - public void remove(CachedClassReference ref); - - /** - * Clear the entire cache - */ - public void clear(); - - /** - * Get a cache entry - * - * @param ref entry to retrieve - * @param originalBytes Pre-weaving class bytes - required in order to - * ensure that the cached entry refers to the same original class - * @return the cached bytes or null, if the entry does not exist - */ - public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes); - - /** - * Put an entry in the cache - * - * @param entry key of the entry - * @param originalBytes Pre-weaving class bytes - required in order to - * ensure that the cached entry refers to the same original class - */ - public void put(CachedClassEntry entry, byte[] originalBytes); -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheFactory.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheFactory.java deleted file mode 100644 index 042ef61bd..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -/** - * Facility for overriding the default CacheKeyResolver - * and CacheBacking; an implementing factory must be set - * on the {@link WeavedClassCache} before the - * {@link org.aspectj.weaver.tools.WeavingAdaptor} is - * configured. - */ -public interface CacheFactory { - CacheKeyResolver createResolver(); - - CacheBacking createBacking(String scope); -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheKeyResolver.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheKeyResolver.java deleted file mode 100644 index 8c76ad878..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheKeyResolver.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.util.List; - -/** - * Interface to allow alternate hashing schemes for weaved and - * generated classes. While the DefaultCacheKeyResolver may be - * a reasonable naive implementation, the management and invalidation - * of the cache may be more usefully accomplished at the Application - * or Container level. - * <p/> - * The key is not a one-way hash; it must be convertible back to a - * className and must match the regex for the type of key it is - * (generated or weaved). - */ -public interface CacheKeyResolver { - /** - * Create a key for the given className from a class generated by - * the weaver such that: - * <pre> - * className == keyToClass(generatedKey(className)) holds - * and - * generatedKey(className).matches(getGeneratedRegex()) == true - * </pre> - * - * @param className class to create a key for - * @return key for the class, or null if no caching should be performed - */ - CachedClassReference generatedKey(String className); - - /** - * Create a key for the given class name and byte array from the pre-weaved - * class such that - * <pre> - * className == keyToClass(weavedKey(className, various_bytes)) holds - * and - * weavedKey(className, various_bytes).matches(getWeavedRegex()) == true - * </pre> - * - * @param className class to create a key for - * @param original_bytes bytes of the pre-weaved class - * @return key for the class, or null if no caching should be performed - */ - CachedClassReference weavedKey(String className, byte[] original_bytes); - - /** - * Convert a key back to a className - * - * @param key cache key - * @return className - */ - String keyToClass(String key); - - /** - * Create a unique string for the given classpath and aspect list - * - * @param loader Classloader for this adapter - * @param aspects list of aspects; either urls or class names handled by this adapter - * @return scope, or null, if no caching should be performed for this classloader - */ - String createClassLoaderScope(ClassLoader loader, List<String> aspects); - - /** - * Return a regex which matches all generated keys - * - * @return string regex - */ - String getGeneratedRegex(); - - /** - * Return a regex which matches all weaved keys; - * - * @return string regex - */ - String getWeavedRegex(); -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java b/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java deleted file mode 100644 index 1ccacfc18..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CacheStatistics.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -/** - * Maintains some basic statistics on the class cache. - */ -public class CacheStatistics { - private volatile int hits; - private volatile int misses; - private volatile int weaved; - private volatile int generated; - private volatile int ignored; - private volatile int puts; - private volatile int puts_ignored; - - public void hit() { - hits++; - } - - public void miss() { - misses++; - } - - public void weaved() { - weaved++; - } - - public void generated() { - generated++; - } - - public void ignored() { - ignored++; - } - - public void put() { - puts++; - } - - public void putIgnored() { - puts_ignored++; - } - - - public int getHits() { - return hits; - } - - public int getMisses() { - return misses; - } - - public int getWeaved() { - return weaved; - } - - public int getGenerated() { - return generated; - } - - public int getIgnored() { - return ignored; - } - - public int getPuts() { - return puts; - } - - public int getPutsIgnored() { - return puts_ignored; - } - - - public void reset() { - hits = 0; - misses = 0; - weaved = 0; - generated = 0; - ignored = 0; - puts = 0; - puts_ignored = 0; - } - - @Override - public String toString() { - return "CacheStatistics{" + - "hits=" + hits + - ", misses=" + misses + - ", weaved=" + weaved + - ", generated=" + generated + - ", ignored=" + ignored + - ", puts=" + puts + - ", puts_ignored=" + puts_ignored + - '}'; - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java deleted file mode 100644 index db74e7f92..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassEntry.java +++ /dev/null @@ -1,90 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ -package org.aspectj.weaver.tools.cache; - -/** - * Represents a class which has been cached - */ -public class CachedClassEntry { - static enum EntryType { - GENERATED, - WEAVED, - IGNORED, - } - - private final CachedClassReference ref; - private final byte[] weavedBytes; - private final EntryType type; - - public CachedClassEntry(CachedClassReference ref, byte[] weavedBytes, EntryType type) { - this.weavedBytes = weavedBytes; - this.ref = ref; - this.type = type; - } - - public String getClassName() { - return ref.getClassName(); - } - - public byte[] getBytes() { - return weavedBytes; - } - - public String getKey() { - return ref.getKey(); - } - - public boolean isGenerated() { - return type == EntryType.GENERATED; - } - - public boolean isWeaved() { - return type == EntryType.WEAVED; - } - - public boolean isIgnored() { - return type == EntryType.IGNORED; - } - - @Override - public int hashCode() { - return getClassName().hashCode() - + getKey().hashCode() - + type.hashCode() - ; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) - return false; - if (this == obj) - return true; - if (getClass() != obj.getClass()) - return false; - - CachedClassEntry other=(CachedClassEntry) obj; - if (getClassName().equals(other.getClassName()) - && getKey().equals(other.getKey()) - && (type == other.type)) { - return true; - } else { - return false; - } - } - - @Override - public String toString() { - return getClassName() + "[" + type + "]"; - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java b/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java deleted file mode 100644 index 7d48ff171..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/CachedClassReference.java +++ /dev/null @@ -1,85 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -/** - * A typed reference to a cached class entry. The key to any - * cache entry is a simple string, but that string may contain - * some specialized encoding. This class handles all of that - * encoding. - * <p/> - * External users of the cache should not be able to create these - * objects manually. - */ -public class CachedClassReference { - static enum EntryType { - GENERATED, - WEAVED, - IGNORED, - } - - private final String key; - private final String className; - - protected CachedClassReference(String key, CacheKeyResolver resolver) { - this(key, resolver.keyToClass(key)); - } - - /** - * Protected to allow only the WeavedClassCache initialization rights - * - * @param key encoded key of the class - * @param className the classname - */ - protected CachedClassReference(String key, String className) { - this.key = key; - this.className = className; - } - - public String getKey() { - return key; - } - - public String getClassName() { - return className; - } - - @Override - public int hashCode() { - return getKey().hashCode() + getClassName().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) - return false; - if (this == obj) - return true; - if (getClass() != obj.getClass()) - return false; - - CachedClassReference other=(CachedClassReference) obj; - if (getKey().equals(other.getKey()) - && getClassName().equals(other.getClassName())) { - return true; - } else { - return false; - } - } - - @Override - public String toString() { - return getClassName() + "[" + getKey() + "]"; - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java deleted file mode 100644 index 7eb796e4b..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheFactory.java +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -/** - * Default factory for creating the backing and resolving classes. - */ -public class DefaultCacheFactory implements CacheFactory { - public CacheKeyResolver createResolver() { - return new DefaultCacheKeyResolver(); - } - - public CacheBacking createBacking(String scope) { - return DefaultFileCacheBacking.createBacking(scope); - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java deleted file mode 100644 index 4951923d3..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultCacheKeyResolver.java +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.CRC32; - -/** - * Naive default class and classloader hashing implementation useful - * for some multi-classloader environments. - * <p/> - * This implementation creates classloader scopes of the form:<br/> - * "ExampleClassLoaderName.[crc hash]" - * <p/> - * And weaved class keys of the form:<br/> - * "com.foo.BarClassName.[bytes len][crc].weaved" - * <p/> - * And generated class keys of the form:<br/> - * "com.foo.BarClassName$AjClosure.generated - */ -public class DefaultCacheKeyResolver implements CacheKeyResolver { - public static final String GENERATED_SUFFIX = ".generated"; - public static final String WEAVED_SUFFIX = ".weaved"; - - /** - * Create a scope from a set of urls and aspect urls. Creates scope - * of the form "ExampleClassLoaderName.[md5sum]" or - * "ExampleClassLoaderName.[crc]" - * - * @param cl the classloader which uses the cache, can be null - * @param aspects the aspects - * @return a unique string for URLClassloaders, otherwise a non-unique classname - */ - public String createClassLoaderScope(ClassLoader cl, List<String> aspects) { - String name = cl != null ? cl.getClass().getSimpleName() : "unknown"; - - List<String> hashableStrings = new LinkedList<String>(); - StringBuilder hashable = new StringBuilder(256); - - // Add the list of loader urls to the hash list - if (cl != null && cl instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) cl).getURLs(); - for (int i = 0; i < urls.length; i++) { - hashableStrings.add(urls[i].toString()); - } - } - - hashableStrings.addAll(aspects); - Collections.sort(hashableStrings); - for (Iterator<String> it = hashableStrings.iterator(); it.hasNext(); ) { - String url = it.next(); - hashable.append(url); - } - String hash = null; - byte[] bytes = hashable.toString().getBytes(); - hash = crc(bytes); - - return name + '.' + hash; - } - - private String crc(byte[] input) { - CRC32 crc32 = new CRC32(); - crc32.update(input); - return String.valueOf(crc32.getValue()); - } - - public String getGeneratedRegex() { - return ".*" + GENERATED_SUFFIX; - } - - public String getWeavedRegex() { - return ".*" + WEAVED_SUFFIX; - } - - - /** - * Converts a cache key back to a className - * - * @param key to convert - * @return className, e.g. "com.foo.Bar" - */ - public String keyToClass(String key) { - if (key.endsWith(GENERATED_SUFFIX)) { - return key.replaceAll(GENERATED_SUFFIX + "$", ""); - } - if (key.endsWith(WEAVED_SUFFIX)) { - return key.replaceAll("\\.[^.]+" + WEAVED_SUFFIX, ""); - } - return key; - } - - public CachedClassReference weavedKey(String className, byte[] original_bytes) { - String hash = crc(original_bytes); - return new CachedClassReference(className + "." + hash + WEAVED_SUFFIX, className); - - } - - public CachedClassReference generatedKey(String className) { - return new CachedClassReference(className + GENERATED_SUFFIX, className); - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java deleted file mode 100644 index 21543a80d..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/DefaultFileCacheBacking.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FilenameFilter; -import java.io.OutputStream; -import java.util.Map; - -import org.aspectj.bridge.MessageUtil; -import org.aspectj.util.FileUtil; -import org.aspectj.util.LangUtil; - - -/** - * Naive File-Backed Class Cache with no expiry or application - * centric invalidation. - * <p/> - * Enabled with the system property, "aj.weaving.cache.dir" - * If this system property is not set, no caching will be - * performed. - * <p/> - * A CRC checksum is stored alongside the class file to verify - * the bytes on read. If for some reason there is an error - * reading either the class or crc file, or if the crc does not - * match the class data the cache entry is deleted. - * <p/> - * An alternate implementation of this could store the class file - * as a jar/zip directly, which would have the required crc; as - * a first pass however it is somewhat useful to view these files - * in expanded form for debugging. - */ -public class DefaultFileCacheBacking extends AbstractIndexedFileCacheBacking { - private final Map<String, IndexEntry> index; - - private static final Object LOCK = new Object(); - - protected DefaultFileCacheBacking(File cacheDir) { - super(cacheDir); - index = readIndex(); - } - - public static final DefaultFileCacheBacking createBacking(File cacheDir) { - if (!cacheDir.exists()) { - if (!cacheDir.mkdirs()) { - MessageUtil.error("Unable to create cache directory at " + cacheDir.getName()); - return null; - } - } else if (!cacheDir.isDirectory()) { - MessageUtil.error("Not a cache directory at " + cacheDir.getName()); - return null; - } - - if (!cacheDir.canWrite()) { - MessageUtil.error("Cache directory is not writable at " + cacheDir.getName()); - return null; - } - return new DefaultFileCacheBacking(cacheDir); - } - - @Override - protected Map<String, IndexEntry> getIndex() { - return index; - } - - @Override - protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) { - File cacheEntry = new File(cacheDir, ie.key); - if (ie.ignored || cacheEntry.canRead()) { - return ie; - } else { - return null; - } - } - - private void removeIndexEntry(String key) { - synchronized (LOCK) { - index.remove(key); - writeIndex(); - } - } - - private void addIndexEntry(IndexEntry ie) { - synchronized (LOCK) { - index.put(ie.key, ie); - writeIndex(); - } - } - - @Override - protected Map<String, IndexEntry> readIndex() { - synchronized (LOCK) { - return super.readIndex(); - } - } - - @Override - protected void writeIndex() { - synchronized (LOCK) { - super.writeIndex(); - } - } - - public void clear() { - File cacheDir=getCacheDirectory(); - int numDeleted=0; - synchronized (LOCK) { - numDeleted = FileUtil.deleteContents(cacheDir); - } - - if ((numDeleted > 0) && (logger != null) && logger.isTraceEnabled()) { - logger.info("clear(" + cacheDir + ") deleted"); - } - } - - public static CacheBacking createBacking(String scope) { - String cache = System.getProperty(WEAVED_CLASS_CACHE_DIR); - if (cache == null) { - return null; - } - - File cacheDir = new File(cache, scope); - return createBacking(cacheDir); - } - - @Override - public String[] getKeys(final String regex) { - File cacheDirectory = getCacheDirectory(); - File[] files = cacheDirectory.listFiles(new FilenameFilter() { - public boolean accept(File file, String s) { - if (s.matches(regex)) { - return true; - } - return false; - } - }); - if (LangUtil.isEmpty(files)) { - return EMPTY_KEYS; - } - String[] keys = new String[files.length]; - for (int i = 0; i < files.length; i++) { - keys[i] = files[i].getName(); - } - return keys; - } - - public CachedClassEntry get(CachedClassReference ref, byte[] originalBytes) { - File cacheDirectory = getCacheDirectory(); - String refKey=ref.getKey(); - File cacheFile = new File(cacheDirectory, refKey); - IndexEntry ie = index.get(refKey); - if (ie == null) { - // no index, delete - delete(cacheFile); - return null; - } - - // check if original file changed - if (crc(originalBytes) != ie.crcClass) { - delete(cacheFile); - return null; - } - - if (ie.ignored) { - return new CachedClassEntry(ref, WeavedClassCache.ZERO_BYTES, CachedClassEntry.EntryType.IGNORED); - } - - if (cacheFile.canRead()) { - byte[] bytes = read(cacheFile, ie.crcWeaved); - if (bytes != null) { - if (!ie.generated) { - return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.WEAVED); - } else { - return new CachedClassEntry(ref, bytes, CachedClassEntry.EntryType.GENERATED); - } - } - } - - return null; - } - - public void put(CachedClassEntry entry, byte[] originalBytes) { - File cacheDirectory = getCacheDirectory(); - String refKey = entry.getKey(); - IndexEntry ie = index.get(refKey); - File cacheFile = new File(cacheDirectory, refKey); - final boolean writeEntryBytes; - // check if original bytes changed or the ignored/generated flags - if ((ie != null) - && ((ie.ignored != entry.isIgnored()) || (ie.generated != entry.isGenerated()) || (crc(originalBytes) != ie.crcClass))) { - delete(cacheFile); - writeEntryBytes = true; - } else { - writeEntryBytes = !cacheFile.exists(); - } - - if (writeEntryBytes) { - ie = createIndexEntry(entry, originalBytes); - if (!entry.isIgnored()) { - ie.crcWeaved = write(cacheFile, entry.getBytes()); - } - addIndexEntry(ie); - } - } - - public void remove(CachedClassReference ref) { - File cacheDirectory = getCacheDirectory(); - String refKey = ref.getKey(); - File cacheFile = new File(cacheDirectory, refKey); - synchronized (LOCK) { - removeIndexEntry(refKey); - delete(cacheFile); - } - } - - @Override - protected void delete(File file) { - synchronized (LOCK) { - super.delete(file); - } - } - - protected byte[] read(File file, long expectedCRC) { - byte[] bytes=null; - synchronized (LOCK) { - FileInputStream fis = null; - try { - fis = new FileInputStream(file); - bytes = FileUtil.readAsByteArray(fis); - } catch (Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("read(" + file.getAbsolutePath() + ")" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to read contents: " + e.getMessage(), e); - } - } finally { - close(fis, file); - } - - // delete the file if there was an exception reading it or mismatched crc - if ((bytes == null) || (crc(bytes) != expectedCRC)) { - delete(file); - return null; - } - } - - return bytes; - } - - protected long write(File file, byte[] bytes) { - synchronized (LOCK) { - if (file.exists()) { - return -1L; - } - OutputStream out = null; - try { - out = new FileOutputStream(file); - out.write(bytes); - } catch (Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("write(" + file.getAbsolutePath() + ")" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to write contents: " + e.getMessage(), e); - } - // delete the file if there was an exception writing it - delete(file); - return -1L; - } finally { - close(out, file); - } - - return crc(bytes); - } - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/FlatFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/FlatFileCacheBacking.java deleted file mode 100644 index 6de416a80..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/FlatFileCacheBacking.java +++ /dev/null @@ -1,139 +0,0 @@ -/* ******************************************************************* - * Copyright (c) 2012 VMware, Inc. custard - * - * 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: - * Lyor Goldstein - * ******************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.StreamCorruptedException; -import java.util.Map; -import java.util.TreeMap; - -import org.aspectj.util.FileUtil; -import org.aspectj.util.LangUtil; - -/** - * Uses a "flat" files model to store the cached instrumented classes - * and aspects - i.e., each class/aspect is stored as a <U>separate</U> (binary) - * file. This is a good mechanism when the number of instrumented class is - * relatively small (a few 10's). The reason for it is that scanning a folder - * that has many files in it quickly becomes an I/O bottleneck. Also, some - * O/S-es may impose internal limits on the maximum number of "children" - * a folder node may have. On the other hand, it is much faster (again, for - * small number of instrumented classes) than the ZIP cache since each class/aspect - * is represented by a single file - thus adding/removing/modifying it is easier. - * - * @author Lyor Goldstein - */ -public class FlatFileCacheBacking extends AsynchronousFileCacheBacking { - private static final AsynchronousFileCacheBackingCreator<FlatFileCacheBacking> defaultCreator= - new AsynchronousFileCacheBackingCreator<FlatFileCacheBacking>() { - public FlatFileCacheBacking create(File cacheDir) { - return new FlatFileCacheBacking(cacheDir); - } - }; - public FlatFileCacheBacking(File cacheDir) { - super(cacheDir); - } - - public static final FlatFileCacheBacking createBacking (File cacheDir) { - return createBacking(cacheDir, defaultCreator); - } - - @Override - protected Map<String, byte[]> readClassBytes(Map<String, IndexEntry> indexMap, File cacheDir) { - return readClassBytes(indexMap, cacheDir.listFiles()); - } - - protected Map<String, byte[]> readClassBytes (Map<String,IndexEntry> indexMap, File[] files) { - Map<String, byte[]> result=new TreeMap<String, byte[]>(); - if (LangUtil.isEmpty(files)) { - return result; - } - - for (File file : files) { - if (!file.isFile()) { - continue; // skip sub-directories - we expect flat files - } - - String key=file.getName(); - if (INDEX_FILE.equalsIgnoreCase(key)) { - continue; // skip the index itself if found - } - - IndexEntry entry=indexMap.get(key); - if ((entry == null) || entry.ignored) { // if not in index or ignored then remove it - if ((logger != null) && logger.isTraceEnabled()) { - logger.info("readClassBytes(" + key + ") remove orphan/ignored: " + file.getAbsolutePath()); - } - FileUtil.deleteContents(file); - continue; - } - - try { - byte[] bytes=FileUtil.readAsByteArray(file); - long crc=crc(bytes); - if (crc != entry.crcWeaved) { - throw new StreamCorruptedException("Mismatched CRC - expected=" + entry.crcWeaved + "/got=" + crc); - } - - result.put(key, bytes); - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("readClassBytes(" + key + ") cached from " + file.getAbsolutePath()); - } - } catch(IOException e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.error("Failed (" + e.getClass().getSimpleName() + ")" - + " to read bytes from " + file.getAbsolutePath() - + ": " + e.getMessage()); - } - indexMap.remove(key); // no need for the entry if no file - force a re-write of its bytes - FileUtil.deleteContents(file); // assume some kind of corruption - continue; - } - } - - return result; - } - - @Override - protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) { - File cacheEntry = new File(cacheDir, ie.key); - if (ie.ignored || cacheEntry.canRead()) { - return ie; - } else { - return null; - } - } - - @Override - protected void writeClassBytes (String key, byte[] bytes) throws Exception { - File dir=getCacheDirectory(), file=new File(dir, key); - FileOutputStream out=new FileOutputStream(file); - try { - out.write(bytes); - } finally { - out.close(); - } - } - - @Override - protected void removeClassBytes (String key) throws Exception { - File dir=getCacheDirectory(), file=new File(dir, key); - if (file.exists() && (!file.delete())) { - throw new StreamCorruptedException("Failed to delete " + file.getAbsolutePath()); - } - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java b/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java deleted file mode 100644 index 91c332b6b..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/GeneratedCachedClassHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import org.aspectj.weaver.tools.GeneratedClassHandler; - -/** - * Handler for generated classes; such as Shadowed closures, etc. This wraps the normal - * generated class handler with caching - */ -public class GeneratedCachedClassHandler implements GeneratedClassHandler { - private final WeavedClassCache cache; - private final GeneratedClassHandler nextGeneratedClassHandler; - - public GeneratedCachedClassHandler(WeavedClassCache cache, GeneratedClassHandler nextHandler) { - this.cache = cache; - this.nextGeneratedClassHandler = nextHandler; - } - - public void acceptClass (String name, byte[] originalBytes, byte[] wovenBytes) { - // The cache expects classNames in dot form - CachedClassReference ref = cache.createGeneratedCacheKey(name.replace('/', '.')); - cache.put(ref, originalBytes, wovenBytes); - if (nextGeneratedClassHandler != null) { - nextGeneratedClassHandler.acceptClass(name, originalBytes, wovenBytes); - } - } -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/SimpleCache.java b/weaver/src/org/aspectj/weaver/tools/cache/SimpleCache.java deleted file mode 100644 index 45d718a14..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/SimpleCache.java +++ /dev/null @@ -1,377 +0,0 @@ -package org.aspectj.weaver.tools.cache; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.ProtectionDomain; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.CRC32; - -import org.aspectj.weaver.Dump; -import org.aspectj.weaver.tools.Trace; -import org.aspectj.weaver.tools.TraceFactory; - - -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Abraham Nevado (lucierna) initial implementation - ********************************************************************************/ - -public class SimpleCache { - - private static final String SAME_BYTES_STRING = "IDEM"; - private static final byte[] SAME_BYTES = SAME_BYTES_STRING.getBytes(); - - private Map<String, byte[]> cacheMap; - private boolean enabled = false; - - // cache for generated classes - private Map<String, byte[]> generatedCache; - private static final String GENERATED_CACHE_SUBFOLDER = "panenka.cache"; - private static final String GENERATED_CACHE_SEPARATOR = ";"; - - public static final String IMPL_NAME = "shared"; - - protected SimpleCache(String folder, boolean enabled) { - this.enabled = enabled; - - cacheMap = Collections.synchronizedMap(StoreableCachingMap.init(folder)); - - if (enabled) { - String generatedCachePath = folder + File.separator + GENERATED_CACHE_SUBFOLDER; - File f = new File (generatedCachePath); - if (!f.exists()){ - f.mkdir(); - } - generatedCache = Collections.synchronizedMap(StoreableCachingMap.init(generatedCachePath,0)); - } - } - - public byte[] getAndInitialize(String classname, byte[] bytes, - ClassLoader loader, ProtectionDomain protectionDomain) { - if (!enabled) { - return null; - } - byte[] res = get(classname, bytes); - - if (Arrays.equals(SAME_BYTES, res)) { - return bytes; - } else { - if (res != null) { - initializeClass(classname, res, loader, protectionDomain); - } - return res; - } - - } - - private byte[] get(String classname, byte bytes[]) { - String key = generateKey(classname, bytes); - - byte[] res = cacheMap.get(key); - return res; - } - - public void put(String classname, byte[] origbytes, byte[] wovenbytes) { - if (!enabled) { - return; - } - - String key = generateKey(classname, origbytes); - - if (Arrays.equals(origbytes, wovenbytes)) { - cacheMap.put(key, SAME_BYTES); - return; - } - cacheMap.put(key, wovenbytes); - } - - private String generateKey(String classname, byte[] bytes) { - CRC32 checksum = new CRC32(); - checksum.update(bytes); - long crc = checksum.getValue(); - classname = classname.replace("/", "."); - return new String(classname + "-" + crc); - - } - - private static class StoreableCachingMap extends HashMap { - private String folder; - private static final String CACHENAMEIDX = "cache.idx"; - - private long lastStored = System.currentTimeMillis(); - private static int DEF_STORING_TIMER = 60000; //ms - private int storingTimer; - - private transient Trace trace; - private void initTrace(){ - trace = TraceFactory.getTraceFactory().getTrace(StoreableCachingMap.class); - } - -// private StoreableCachingMap(String folder) { -// this.folder = folder; -// initTrace(); -// } - - private StoreableCachingMap(String folder, int storingTimer){ - this.folder = folder; - initTrace(); - this.storingTimer = storingTimer; - } - - public static StoreableCachingMap init(String folder) { - return init(folder,DEF_STORING_TIMER); - - } - - public static StoreableCachingMap init(String folder, int storingTimer) { - File file = new File(folder + File.separator + CACHENAMEIDX); - if (file.exists()) { - try { - ObjectInputStream in = new ObjectInputStream( - new FileInputStream(file)); - // Deserialize the object - StoreableCachingMap sm = (StoreableCachingMap) in.readObject(); - sm.initTrace(); - in.close(); - return sm; - } catch (Exception e) { - Trace trace = TraceFactory.getTraceFactory().getTrace(StoreableCachingMap.class); - trace.error("Error reading Storable Cache", e); - } - } - - return new StoreableCachingMap(folder,storingTimer); - - } - - @Override - public Object get(Object obj) { - try { - if (super.containsKey(obj)) { - String path = (String) super.get(obj); - if (path.equals(SAME_BYTES_STRING)) { - return SAME_BYTES; - } - return readFromPath(path); - } else { - return null; - } - } catch (IOException e) { - trace.error("Error reading key:"+obj.toString(),e); - Dump.dumpWithException(e); - } - return null; - } - - @Override - public Object put(Object key, Object value) { - try { - String path = null; - byte[] valueBytes = (byte[]) value; - - if (Arrays.equals(valueBytes, SAME_BYTES)) { - path = SAME_BYTES_STRING; - } else { - path = writeToPath((String) key, valueBytes); - } - Object result = super.put(key, path); - storeMap(); - return result; - } catch (IOException e) { - trace.error("Error inserting in cache: key:"+key.toString() + "; value:"+value.toString(), e); - Dump.dumpWithException(e); - } - return null; - } - - - - public void storeMap() { - long now = System.currentTimeMillis(); - if ((now - lastStored ) < storingTimer){ - return; - } - File file = new File(folder + File.separator + CACHENAMEIDX);; - try { - ObjectOutputStream out = new ObjectOutputStream( - new FileOutputStream(file)); - // Deserialize the object - out.writeObject(this); - out.close(); - lastStored = now; - } catch (Exception e) { - trace.error("Error storing cache; cache file:"+file.getAbsolutePath(), e); - Dump.dumpWithException(e); - } - } - - private byte[] readFromPath(String fullPath) throws IOException { - FileInputStream is = null ; - try{ - is = new FileInputStream(fullPath); - } - catch (FileNotFoundException e){ - //may be caused by a generated class that has been stored in generated cache but not saved at cache folder - System.out.println("FileNotFoundExceptions: The aspectj cache is corrupt. Please clean it and reboot the server. Cache path:"+this.folder ); - e.printStackTrace(); - return null; - } - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - int nRead; - byte[] data = new byte[16384]; - - while ((nRead = is.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } - - buffer.flush(); - is.close(); - return buffer.toByteArray(); - - } - - private String writeToPath(String key, byte[] bytes) throws IOException { - String fullPath = folder + File.separator + key; - FileOutputStream fos = new FileOutputStream(fullPath); - fos.write(bytes); - fos.flush(); - fos.close(); - return fullPath; - } - - } - - private void initializeClass(String className, byte[] bytes, - ClassLoader loader, ProtectionDomain protectionDomain) { - String[] generatedClassesNames = getGeneratedClassesNames(className,bytes); - - if (generatedClassesNames == null) { - return; - } - for (String generatedClassName : generatedClassesNames) { - - byte[] generatedBytes = get(generatedClassName, bytes); - - if (protectionDomain == null) { - defineClass(loader, generatedClassName, generatedBytes); - } else { - defineClass(loader, generatedClassName, generatedBytes, - protectionDomain); - } - - } - - } - - private String[] getGeneratedClassesNames(String className, byte[] bytes) { - String key = generateKey(className, bytes); - - byte[] readBytes = generatedCache.get(key); - if (readBytes == null) { - return null; - } - String readString = new String(readBytes); - return readString.split(GENERATED_CACHE_SEPARATOR); - } - - public void addGeneratedClassesNames(String parentClassName, byte[] parentBytes, String generatedClassName) { - if (!enabled) { - return; - } - String key = generateKey(parentClassName, parentBytes); - - byte[] storedBytes = generatedCache.get(key); - if (storedBytes == null) { - generatedCache.put(key, generatedClassName.getBytes()); - } else { - String storedClasses = new String(storedBytes); - storedClasses += GENERATED_CACHE_SEPARATOR + generatedClassName; - generatedCache.put(key, storedClasses.getBytes()); - } - } - - private Method defineClassMethod = null; - private Method defineClassWithProtectionDomainMethod = null; - - private void defineClass(ClassLoader loader, String name, byte[] bytes) { - - Object clazz = null; - - try { - if (defineClassMethod == null) { - defineClassMethod = ClassLoader.class.getDeclaredMethod( - "defineClass", new Class[] { String.class, - bytes.getClass(), int.class, int.class }); - } - defineClassMethod.setAccessible(true); - clazz = defineClassMethod.invoke(loader, new Object[] { name, - bytes, new Integer(0), new Integer(bytes.length) }); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof LinkageError) { - e.printStackTrace(); - } else { - System.out.println("define generated class failed" - + e.getTargetException()); - } - } catch (Exception e) { - e.printStackTrace(); - Dump.dumpWithException(e); - } - } - - private void defineClass(ClassLoader loader, String name, byte[] bytes, - ProtectionDomain protectionDomain) { - - Object clazz = null; - - try { - // System.out.println(">> Defining with protection domain " + name + - // " pd=" + protectionDomain); - if (defineClassWithProtectionDomainMethod == null) { - defineClassWithProtectionDomainMethod = ClassLoader.class - .getDeclaredMethod("defineClass", new Class[] { - String.class, bytes.getClass(), int.class, - int.class, ProtectionDomain.class }); - } - defineClassWithProtectionDomainMethod.setAccessible(true); - clazz = defineClassWithProtectionDomainMethod.invoke(loader, - new Object[] { name, bytes, Integer.valueOf(0), - new Integer(bytes.length), protectionDomain }); - } catch (InvocationTargetException e) { - if (e.getTargetException() instanceof LinkageError) { - e.printStackTrace(); - // is already defined (happens for X$ajcMightHaveAspect - // interfaces since aspects are reweaved) - // TODO maw I don't think this is OK and - } else { - e.printStackTrace(); - } - }catch (NullPointerException e) { - System.out.println("NullPointerException loading class:"+name+". Probabily caused by a corruput cache. Please clean it and reboot the server"); - } catch (Exception e) { - e.printStackTrace(); - Dump.dumpWithException(e); - } - - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/SimpleCacheFactory.java b/weaver/src/org/aspectj/weaver/tools/cache/SimpleCacheFactory.java deleted file mode 100644 index 49569dd0e..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/SimpleCacheFactory.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Abraham Nevado (lucierna) initial implementation - ********************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.io.File; - -import org.aspectj.weaver.Dump; - -public class SimpleCacheFactory { - - public static final String CACHE_ENABLED_PROPERTY = "aj.weaving.cache.enabled"; - public static final String CACHE_DIR = "aj.weaving.cache.dir"; - public static final String CACHE_IMPL = "aj.weaving.cache.impl"; - - public static final String PATH_DEFAULT= "/tmp/"; // TODO windows default...? - public static final boolean BYDEFAULT= false; - - - public static String path = PATH_DEFAULT; - public static Boolean enabled = false; - private static boolean determinedIfEnabled = false; - private static SimpleCache lacache=null; - - public static synchronized SimpleCache createSimpleCache(){ - if (lacache==null){ - if (!determinedIfEnabled) { - determineIfEnabled(); - } - - if (!enabled) { - return null; - } - - try { - path = System.getProperty(CACHE_DIR); - if (path == null){ - path = PATH_DEFAULT; - } - - } catch (Throwable t) { - path=PATH_DEFAULT; - t.printStackTrace(); - Dump.dumpWithException(t); - } - File f = new File(path); - if (!f.exists()){ - f.mkdir(); - } - lacache= new SimpleCache(path, enabled); - } - return lacache; - - } - - private static void determineIfEnabled() { - try { - String property = System.getProperty(CACHE_ENABLED_PROPERTY); - if (property == null ){ - enabled = BYDEFAULT; - } - else if (property.equalsIgnoreCase("true")){ - - String impl = System.getProperty(CACHE_IMPL); - if (SimpleCache.IMPL_NAME.equals(impl)){ - enabled = true; - } - else{ - enabled = BYDEFAULT; - } - } - else{ - enabled = BYDEFAULT; - } - - } catch (Throwable t) { - enabled=BYDEFAULT; - System.err.println("Error creating cache"); - t.printStackTrace(); - Dump.dumpWithException(t); - } - determinedIfEnabled = true; - } - - // Should behave ok with two threads going through here, well whoever gets there first will set determinedIfEnabled but only after - // it has set 'enabled' to the right value. - public static boolean isEnabled() { - if (!determinedIfEnabled) { - determineIfEnabled(); - } - return enabled; - } - - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java b/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java deleted file mode 100644 index b281d412f..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/WeavedClassCache.java +++ /dev/null @@ -1,278 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * John Kew (vmware) initial implementation - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.IMessageHandler; -import org.aspectj.bridge.Message; -import org.aspectj.bridge.MessageUtil; -import org.aspectj.weaver.tools.GeneratedClassHandler; - -import java.util.LinkedList; -import java.util.List; - -/** - * Manages a cache of weaved and generated classes similar to Eclipse Equinox, - * except designed to operate across multiple restarts of the JVM and with one - * cache per classloader; allowing URLClassLoaders with the same set of URI - * paths to share the same cache (with the default configuration). - * <p/> - * To enable the default configuration two system properties must be set: - * <pre> - * "-Daj.weaving.cache.enabled=true" - * "-Daj.weaving.cache.dir=/some/directory" - * </pre> - * <p/> - * The class cache is often something that application developers or - * containers would like to manage, so there are a few interfaces for overriding the - * default behavior and performing other management functions. - * <p/> - * {@link CacheBacking} <br/> - * Provides an interface for implementing a custom backing store - * for the cache; The default implementation in {@link DefaultFileCacheBacking} - * provides a naive file-backed cache. An alternate implementation may ignore - * caching until signaled explicitly by the application, or only cache files - * for a specific duration. This class delegates the locking and synchronization - * requirements to the CacheBacking implementation. - * <p/> - * {@link CacheKeyResolver} <br/> - * Provides methods for creating keys from classes to be cached and for - * creating the "scope" of the cache itself for a given classloader and aspect - * list. The default implementation is provided by {@link DefaultCacheKeyResolver} - * but an alternate implementation may want to associate a cache with a particular - * application running underneath a container. - * <p/> - * This naive cache does not normally invalidate *any* classes; the interfaces above - * must be used to implement more intelligent behavior. Cache invalidation - * problems may occur in at least three scenarios: - * <pre> - * 1. New aspects are added dynamically somewhere in the classloader hierarchy; affecting - * other classes elsewhere. - * 2. Use of declare parent in aspects to change the type hierarchy; if the cache - * has not invalidated the right classes in the type hierarchy aspectj may not - * be reconstruct the class incorrectly. - * 3. Similarly to (2), the addition of fields or methods on classes which have - * already been weaved and cached could have inter-type conflicts. - * </pre> - */ -public class WeavedClassCache { - public static final String WEAVED_CLASS_CACHE_ENABLED = "aj.weaving.cache.enabled"; - public static final String CACHE_IMPL = SimpleCacheFactory.CACHE_IMPL; - private static CacheFactory DEFAULT_FACTORY = new DefaultCacheFactory(); - public static final byte[] ZERO_BYTES = new byte[0]; - private final IMessageHandler messageHandler; - private final GeneratedCachedClassHandler cachingClassHandler; - private final CacheBacking backing; - private final CacheStatistics stats; - private final CacheKeyResolver resolver; - private final String name; - - private static final List<WeavedClassCache> cacheRegistry = new LinkedList<WeavedClassCache>(); - - protected WeavedClassCache(GeneratedClassHandler existingClassHandler, - IMessageHandler messageHandler, - String name, - CacheBacking backing, - CacheKeyResolver resolver) { - this.resolver = resolver; - this.name = name; - this.backing = backing; - this.messageHandler = messageHandler; - // wrap the existing class handler with a caching version - cachingClassHandler = new GeneratedCachedClassHandler(this, existingClassHandler); - this.stats = new CacheStatistics(); - synchronized (cacheRegistry) { - cacheRegistry.add(this); - } - } - - /** - * Creates a new cache using the resolver and backing returned by the DefaultCacheFactory. - * - * @param loader classloader for this cache - * @param aspects list of aspects used by the WeavingAdapter - * @param existingClassHandler the existing GeneratedClassHandler used by the weaver - * @param messageHandler the existing messageHandler used by the weaver - * @return - */ - public static WeavedClassCache createCache(ClassLoader loader, List<String> aspects, GeneratedClassHandler existingClassHandler, IMessageHandler messageHandler) { - CacheKeyResolver resolver = DEFAULT_FACTORY.createResolver(); - String name = resolver.createClassLoaderScope(loader, aspects); - if (name == null) { - return null; - } - CacheBacking backing = DEFAULT_FACTORY.createBacking(name); - if (backing != null) { - return new WeavedClassCache(existingClassHandler, messageHandler, name, backing, resolver); - } - return null; - } - - public String getName() { - return name; - } - - /** - * The Cache and be extended in two ways, through a specialized CacheKeyResolver and - * a specialized CacheBacking. The default factory used to create these classes can - * be set with this method. Since each weaver will create a cache, this method must be - * called before the weaver is first initialized. - * - * @param factory - */ - public static void setDefaultCacheFactory(CacheFactory factory) { - DEFAULT_FACTORY = factory; - } - - /** - * Created a key for a generated class - * - * @param className ClassName, e.g. "com.foo.Bar" - * @return the cache key, or null if no caching should be performed - */ - public CachedClassReference createGeneratedCacheKey(String className) { - return resolver.generatedKey(className); - } - - /** - * Create a key for a normal weaved class - * - * @param className ClassName, e.g. "com.foo.Bar" - * @param originalBytes Original byte array of the class - * @return a cache key, or null if no caching should be performed - */ - public CachedClassReference createCacheKey(String className, byte[] originalBytes) { - return resolver.weavedKey(className, originalBytes); - } - - /** - * Returns a generated class handler which wraps the handler this cache was initialized - * with; this handler should be used to make sure that generated classes are added - * to the cache - */ - public GeneratedClassHandler getCachingClassHandler() { - return cachingClassHandler; - } - - /** - * Has caching been enabled through the System property, - * WEAVED_CLASS_CACHE_ENABLED - * - * @return true if caching is enabled - */ - public static boolean isEnabled() { - String enabled = System.getProperty(WEAVED_CLASS_CACHE_ENABLED); - String impl = System.getProperty(CACHE_IMPL); - return (enabled != null && (impl == null || !SimpleCache.IMPL_NAME.equalsIgnoreCase(impl) ) ); - } - - /** - * Put a class in the cache - * - * @param ref reference to the entry, as created through createCacheKey - * @param classBytes pre-weaving class bytes - * @param weavedBytes bytes to cache - */ - public void put(CachedClassReference ref, byte[] classBytes, byte[] weavedBytes) { - CachedClassEntry.EntryType type = CachedClassEntry.EntryType.WEAVED; - if (ref.getKey().matches(resolver.getGeneratedRegex())) { - type = CachedClassEntry.EntryType.GENERATED; - } - backing.put(new CachedClassEntry(ref, weavedBytes, type), classBytes); - stats.put(); - } - - /** - * Get a cache value - * - * @param ref reference to the cache entry, created through createCacheKey - * @param classBytes Pre-weaving class bytes - required to ensure that - * cached aspects refer to an unchanged original class - * @return the CacheEntry, or null if no entry exists in the cache - */ - public CachedClassEntry get(CachedClassReference ref, byte[] classBytes) { - CachedClassEntry entry = backing.get(ref, classBytes); - if (entry == null) { - stats.miss(); - } else { - stats.hit(); - if (entry.isGenerated()) stats.generated(); - if (entry.isWeaved()) stats.weaved(); - if (entry.isIgnored()) stats.ignored(); - } - return entry; - } - - /** - * Put a cache entry to indicate that the class should not be - * weaved; the original bytes of the class should be used. - * - * @param ref The cache reference - * @param classBytes The un-weaved class bytes - */ - public void ignore(CachedClassReference ref, byte[] classBytes) { - stats.putIgnored(); - backing.put(new CachedClassEntry(ref, ZERO_BYTES, CachedClassEntry.EntryType.IGNORED), classBytes); - } - - /** - * Invalidate a cache entry - * - * @param ref - */ - public void remove(CachedClassReference ref) { - backing.remove(ref); - } - - /** - * Clear the entire cache - */ - public void clear() { - backing.clear(); - } - - /** - * Get the statistics associated with this cache, or - * null if statistics have not been enabled. - * - * @return - */ - public CacheStatistics getStats() { - return stats; - } - - /** - * Return a list of all WeavedClassCaches which have been initialized - * - * @return - */ - public static List<WeavedClassCache> getCaches() { - synchronized (cacheRegistry) { - return new LinkedList<WeavedClassCache>(cacheRegistry); - } - } - - protected void error(String message, Throwable th) { - messageHandler.handleMessage(new Message(message, IMessage.ERROR, th, null)); - } - - protected void error(String message) { - MessageUtil.error(messageHandler, message); - } - - protected void info(String message) { - MessageUtil.info(message); - } - -} diff --git a/weaver/src/org/aspectj/weaver/tools/cache/ZippedFileCacheBacking.java b/weaver/src/org/aspectj/weaver/tools/cache/ZippedFileCacheBacking.java deleted file mode 100644 index 6ee8b728c..000000000 --- a/weaver/src/org/aspectj/weaver/tools/cache/ZippedFileCacheBacking.java +++ /dev/null @@ -1,321 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * Lyor Goldstein (vmware) add support for weaved class being re-defined - *******************************************************************************/ - -package org.aspectj.weaver.tools.cache; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Map; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import java.util.zip.ZipOutputStream; - -import org.aspectj.util.FileUtil; -import org.aspectj.util.LangUtil; - -/** - * Uses a ZIP file to store the instrumented classes/aspects - each one as a - * <U>separate</U> {@link ZipEntry}. This mechanism is suitable for relatively - * large numbers of instrumented classes/aspects (100's and more) since it - * holds all of them in a single (ZIP) file. The down side is that any - * modifications to the cache require re-writing the entire ZIP file. This - * can cause the ZIP file to become corrupted if interrupted in mid-update, - * thus requiring the re-population of the cache on next application activation - * (though the overhead in this case is not prohibitvely high...) - */ -public class ZippedFileCacheBacking extends AsynchronousFileCacheBacking { - public static final String ZIP_FILE = "cache.zip"; - private static final AsynchronousFileCacheBackingCreator<ZippedFileCacheBacking> defaultCreator= - new AsynchronousFileCacheBackingCreator<ZippedFileCacheBacking>() { - public ZippedFileCacheBacking create(File cacheDir) { - return new ZippedFileCacheBacking(cacheDir); - } - }; - - private final File zipFile; - public ZippedFileCacheBacking(File cacheDir) { - super(cacheDir); - zipFile = new File(cacheDir, ZIP_FILE); - } - - public File getZipFile () { - return zipFile; - } - - public static final ZippedFileCacheBacking createBacking (File cacheDir) { - return createBacking(cacheDir, defaultCreator); - } - - @Override - protected void writeClassBytes(String key, byte[] bytes) throws Exception { - File outFile=getZipFile(); - Map<String,byte[]> entriesMap; - try { - entriesMap = readZipClassBytes(outFile); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("writeClassBytes(" + outFile + ")[" + key + "]" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to read current data: " + e.getMessage(), - e); - } - - FileUtil.deleteContents(outFile); - return; - } - - if (entriesMap.isEmpty()) { - entriesMap = Collections.singletonMap(key, bytes); - } else { - entriesMap.put(key, bytes); - } - - try { - writeZipClassBytes(outFile, entriesMap); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("writeClassBytes(" + outFile + ")[" + key + "]" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to write updated data: " + e.getMessage(), - e); - } - - FileUtil.deleteContents(outFile); - } - } - - @Override - protected void removeClassBytes(String key) throws Exception { - File outFile=getZipFile(); - Map<String,byte[]> entriesMap; - try { - entriesMap = readZipClassBytes(outFile); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("removeClassBytes(" + outFile + ")[" + key + "]" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to read current data: " + e.getMessage(), - e); - } - - FileUtil.deleteContents(outFile); - return; - } - - if (!entriesMap.isEmpty()) { - if (entriesMap.remove(key) == null) { - return; // not in the data file to begin with so nothing to update - } - } - - try { - writeZipClassBytes(outFile, entriesMap); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("removeClassBytes(" + outFile + ")[" + key + "]" - + " failed (" + e.getClass().getSimpleName() + ")" - + " to write updated data: " + e.getMessage(), - e); - } - - FileUtil.deleteContents(outFile); - } - } - - @Override - protected Map<String, byte[]> readClassBytes(Map<String, IndexEntry> indexMap, File cacheDir) { - File dataFile=new File(cacheDir, ZIP_FILE); - Map<String,byte[]> entriesMap; - boolean okEntries=true; - try { - entriesMap = readZipClassBytes(dataFile); - } catch(Exception e) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.warn("Failed (" + e.getClass().getSimpleName() + ")" - + " to read zip entries from " + dataFile - + ": " + e.getMessage(), - e); - } - - entriesMap = new TreeMap<String,byte[]>(); - okEntries = false; - } - - if (!syncClassBytesEntries(dataFile, indexMap, entriesMap)) { - okEntries = false; - } - - if (!okEntries) { - FileUtil.deleteContents(dataFile); - - if (!entriesMap.isEmpty()) { - entriesMap.clear(); - } - } - - syncIndexEntries(dataFile, indexMap, entriesMap); - - return entriesMap; - } - - // remove all non-ignored entries that have no class bytes - protected Collection<String> syncIndexEntries (File dataFile, Map<String, IndexEntry> indexMap, Map<String,byte[]> entriesMap) { - Collection<String> toDelete=null; - for (Map.Entry<String, IndexEntry> ie : indexMap.entrySet()) { - String key=ie.getKey(); - IndexEntry indexEntry=ie.getValue(); - if (indexEntry.ignored) { - continue; // ignored entries have no class bytes - } - - if (entriesMap.containsKey(key)) { - continue; - } - - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("syncIndexEntries(" + dataFile + ")[" + key + "] no class bytes"); - } - - if (toDelete == null) { - toDelete = new TreeSet<String>(); - } - toDelete.add(key); - } - - if (toDelete == null) { - return Collections.emptySet(); - } - - for (String key : toDelete) { - indexMap.remove(key); - } - - return toDelete; - } - - // check if all class bytes entries are valid - protected boolean syncClassBytesEntries (File dataFile, Map<String, IndexEntry> indexMap, Map<String,byte[]> entriesMap) { - boolean okEntries=true; - - for (Map.Entry<String,byte[]> bytesEntry : entriesMap.entrySet()) { - String key=bytesEntry.getKey(); - IndexEntry indexEntry=indexMap.get(key); - // ignored entries should have no bytes - if ((indexEntry == null) || indexEntry.ignored) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("syncClassBytesEntries(" + dataFile + ")[" + key + "] bad index entry"); - } - - okEntries = false; - continue; - } - - long crc=crc(bytesEntry.getValue()); - if (crc != indexEntry.crcWeaved) { - if ((logger != null) && logger.isTraceEnabled()) { - logger.debug("syncClassBytesEntries(" + dataFile + ")[" + key + "]" - + " mismatched CRC - expected=" + indexEntry.crcWeaved + "/got=" + crc); - } - - indexMap.remove(key); - okEntries = false; - continue; - } - } - - return okEntries; - } - - @Override - protected IndexEntry resolveIndexMapEntry(File cacheDir, IndexEntry ie) { - if (cacheDir.exists()) { - return ie; // we will take care of non-existing index entries in the readClassBytes method - } else { - return null; - } - } - - public static final Map<String,byte[]> readZipClassBytes (File file) throws IOException { - if (!file.canRead()) { - return Collections.emptyMap(); - } - - Map<String,byte[]> result=new TreeMap<String,byte[]>(); - byte[] copyBuf=new byte[4096]; - ByteArrayOutputStream out=new ByteArrayOutputStream(copyBuf.length); - ZipFile zipFile=new ZipFile(file); - try { - for (Enumeration<? extends ZipEntry> entries=zipFile.entries(); (entries != null) && entries.hasMoreElements(); ) { - ZipEntry e=entries.nextElement(); - String name=e.getName(); - if (LangUtil.isEmpty(name)) { - continue; - } - - out.reset(); - - InputStream zipStream=zipFile.getInputStream(e); - try { - for (int nRead=zipStream.read(copyBuf); nRead != (-1); nRead=zipStream.read(copyBuf)) { - out.write(copyBuf, 0, nRead); - } - } finally { - zipStream.close(); - } - - byte[] data=out.toByteArray(), prev=result.put(name, data); - if (prev != null) { - throw new StreamCorruptedException("Multiple entries for " + name); - } - } - } finally { - zipFile.close(); - } - - return result; - } - - public static final void writeZipClassBytes (File file, Map<String,byte[]> entriesMap) throws IOException { - if (entriesMap.isEmpty()) { - FileUtil.deleteContents(file); - return; - } - - File zipDir=file.getParentFile(); - if ((!zipDir.exists()) && (!zipDir.mkdirs())) { - throw new IOException("Failed to create path to " + zipDir.getAbsolutePath()); - } - - ZipOutputStream zipOut=new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(file), 4096)); - try { - for (Map.Entry<String,byte[]> bytesEntry : entriesMap.entrySet()) { - String key=bytesEntry.getKey(); - byte[] bytes=bytesEntry.getValue(); - zipOut.putNextEntry(new ZipEntry(key)); - zipOut.write(bytes); - zipOut.closeEntry(); - } - } finally { - zipOut.close(); - } - } -} |