Package org.aspectj.weaver.bcel

Source Code of org.aspectj.weaver.bcel.BcelClassWeaver

/* *******************************************************************
* 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 Common Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/cpl-v10.html
* Contributors:
*     PARC     initial implementation
* ******************************************************************/


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.Comparator;
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.Field;
import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.annotation.Annotation;
import org.aspectj.apache.bcel.generic.BranchInstruction;
import org.aspectj.apache.bcel.generic.CPInstruction;
import org.aspectj.apache.bcel.generic.ConstantPoolGen;
import org.aspectj.apache.bcel.generic.FieldGen;
import org.aspectj.apache.bcel.generic.FieldInstruction;
import org.aspectj.apache.bcel.generic.INVOKESPECIAL;
import org.aspectj.apache.bcel.generic.IndexedInstruction;
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.InstructionTargeter;
import org.aspectj.apache.bcel.generic.InvokeInstruction;
import org.aspectj.apache.bcel.generic.LocalVariableInstruction;
import org.aspectj.apache.bcel.generic.MethodGen;
import org.aspectj.apache.bcel.generic.NEW;
import org.aspectj.apache.bcel.generic.ObjectType;
import org.aspectj.apache.bcel.generic.PUTFIELD;
import org.aspectj.apache.bcel.generic.PUTSTATIC;
import org.aspectj.apache.bcel.generic.RET;
import org.aspectj.apache.bcel.generic.ReturnInstruction;
import org.aspectj.apache.bcel.generic.Select;
import org.aspectj.apache.bcel.generic.Type;
import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
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.AsmRelationshipProvider;
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.WeaverMessages;
import org.aspectj.weaver.WeaverMetrics;
import org.aspectj.weaver.WeaverStateInfo;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.ExactTypePattern;

class BcelClassWeaver implements IClassWeaver {
   
    /**
     * This is called from {@link BcelWeaver} to perform the per-class weaving process.
     */
  public static boolean weave(
    BcelWorld world,
    LazyClassGen clazz,
    List shadowMungers,
    List typeMungers,
        List lateTypeMungers)
  {
    boolean b =  new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers).weave();
    //System.out.println(clazz.getClassName() + ", " + clazz.getType().getWeaverState());
    //clazz.print();
    return b;
  }
 
  // --------------------------------------------
   
    private final LazyClassGen clazz;
    private final List         shadowMungers;
    private final List         typeMungers;
    private final List         lateTypeMungers;

    private final BcelObjectType  ty;    // alias of clazz.getType()
    private final BcelWorld       world; // alias of ty.getWorld()
    private final ConstantPoolGen cpg;   // alias of clazz.getConstantPoolGen()
    private final InstructionFactory fact; // alias of clazz.getFactory();

   
    private final List        addedLazyMethodGens           = new ArrayList();
    private final Set         addedDispatchTargets          = new HashSet();
   

  // Static setting across BcelClassWeavers
  private static boolean inReweavableMode = false;
   
   
    private        List addedSuperInitializersAsList = null; // List<IfaceInitList>
    private final Map  addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList
    private        List addedThisInitializers  = new ArrayList(); // List<NewFieldMunger>
    private        List addedClassInitializers  = new ArrayList(); // List<NewFieldMunger>
 
  private Map mapToAnnotations = new HashMap();
   
    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        initializationShadows         = new ArrayList(1);
   
  private BcelClassWeaver(
    BcelWorld world,
    LazyClassGen clazz,
    List shadowMungers,
    List typeMungers,
        List lateTypeMungers)
  {
    super();
    // assert world == clazz.getType().getWorld()
    this.world = world;
    this.clazz = clazz;
    this.shadowMungers = shadowMungers;
    this.typeMungers = typeMungers;
        this.lateTypeMungers = lateTypeMungers;
    this.ty = clazz.getBcelObjectType();
    this.cpg = clazz.getConstantPoolGen();
    this.fact = clazz.getFactory();
   
    fastMatchShadowMungers(shadowMungers);
   
    initializeSuperInitializerMap(ty.getResolvedTypeX());
  }
 

    private List[] perKindShadowMungers;
    private boolean canMatchBodyShadows = false;
    private boolean canMatchInitialization = false;
    private void fastMatchShadowMungers(List shadowMungers) {
      // beware the annoying property that SHADOW_KINDS[i].getKey == (i+1) !
     
      perKindShadowMungers = new List[Shadow.MAX_SHADOW_KIND + 1];
      for (int i = 0; i < perKindShadowMungers.length; i++) {
      perKindShadowMungers[i] = new ArrayList(0);
      }
      for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
      ShadowMunger munger = (ShadowMunger) iter.next();
      Set couldMatchKinds = munger.getPointcut().couldMatchKinds();
      for (Iterator kindIterator = couldMatchKinds.iterator();
           kindIterator.hasNext();) {
        Shadow.Kind aKind = (Shadow.Kind) kindIterator.next();
        perKindShadowMungers[aKind.getKey()].add(munger);
      }
    }
     
      if (!perKindShadowMungers[Shadow.Initialization.getKey()].isEmpty())
        canMatchInitialization = true;
     
      for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
      Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
      if (!kind.isEnclosingKind() && !perKindShadowMungers[i+1].isEmpty()) {
        canMatchBodyShadows = true;
      }
      if (perKindShadowMungers[i+1].isEmpty()) {
        perKindShadowMungers[i+1] = null;
      }
      }
    }
   
    private boolean canMatch(Shadow.Kind kind) {
      return perKindShadowMungers[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]);
        }
      }
    }
  }

  private boolean addSuperInitializer(ResolvedType onType) {
    if (onType.isRawType() || onType.isParameterizedType()) onType = onType.getGenericType();
    IfaceInitList l = (IfaceInitList) 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 (m.getSignature().isStatic()) {
      addedClassInitializers.add(cm);
    } else {
      if (onType == ty.getResolvedTypeX()) {
        addedThisInitializers.add(cm);
      } else {
        IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType);
        l.list.add(cm);
      }
    }
  }
   
    private static class IfaceInitList implements PartialOrder.PartialComparable {
      final ResolvedType onType;
      List list = new ArrayList();
      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 i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
      LazyMethodGen existing = (LazyMethodGen)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 i = clazz.getMethodGens().iterator(); i.hasNext(); ) {
      LazyMethodGen existing = (LazyMethodGen)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());
    }
    LazyMethodGen bridgeMethod = makeBridgeMethod(clazz,theBridgeMethod); // The bridge method in this type will have the same signature as the one in the supertype
    bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040 /*BRIDGE    = 0x00000040*/ );
    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 (debug) System.err.println("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);
  }
 
    // ----
   
    public boolean weave() {
        if (clazz.isWoven() && !clazz.isReweavable()) {
          world.showMessage(IMessage.ERROR,
              WeaverMessages.format(WeaverMessages.ALREADY_WOVEN,clazz.getType().getName()),
        ty.getSourceLocation(), null);
          return false;
        }
      

        Set aspectsAffectingType = null;
        if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType = new HashSet();
       
        boolean isChanged = false;
       
        // we want to "touch" all aspects
        if (clazz.getType().isAspect()) isChanged = true;

        // start by munging all typeMungers
        for (Iterator i = typeMungers.iterator(); i.hasNext(); ) {
          Object o = i.next();
          if ( !(o instanceof BcelTypeMunger) ) {
            //???System.err.println("surprising: " + o);
            continue;
          }
          BcelTypeMunger munger = (BcelTypeMunger)o;
          boolean typeMungerAffectedType = munger.munge(this);
          if (typeMungerAffectedType) {
            isChanged = true;
            if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.add(munger.getAspectType().getName());
          }
        }



        // 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(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 methodGens = new ArrayList(clazz.getMethodGens());
        for (Iterator i = methodGens.iterator(); i.hasNext();) {
            LazyMethodGen mg = (LazyMethodGen)i.next();
      if (! mg.hasBody()) continue;
      boolean shadowMungerMatched = match(mg);
      if (shadowMungerMatched) {
        // For matching mungers, add their declaring aspects to the list that affected this type
        if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.addAll(findAspectsForMungers(mg));
              isChanged = true;
      }
        }

        // now we weave all but the initialization shadows
    for (Iterator i = methodGens.iterator(); i.hasNext();) {
      LazyMethodGen mg = (LazyMethodGen)i.next();
      if (! mg.hasBody()) continue;
      implement(mg);
    }
     
       
        // 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"
      while (inlineSelfConstructors(methodGens));
      positionAndImplement(initializationShadows);
    }
   
        // now proceed with late type mungers
        if (lateTypeMungers != null) {
            for (Iterator 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().getName());
                    }
                }
            }
        }

        //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(); // FIXME asc are these potentially affected by declare annotation?
        }
       
        if (inReweavableMode) {
          WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo(true);
          wsi.addAspectsAffectingType(aspectsAffectingType);
          wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes());
          wsi.setReweavable(true);
        } else {
          clazz.getOrCreateWeaverStateInfo(false).setReweavable(false);
        }
       
        return isChanged;
    }
   
   
   
   
    // **************************** start of bridge method creation code *****************
   
    // debug flag for bridge method creation
  private static boolean debug=false;
   
 
  // FIXME asc tidy this lot up !!
 
    // FIXME asc 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.
     */
    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 (methodThatMightBeGettingOverridden.isStatic()) return null; // we can't be overriding a static method
    if (methodThatMightBeGettingOverridden.isPrivate())  return null; // we can't be overriding a private method
    if (!methodThatMightBeGettingOverridden.getName().equals(mname))  return null; // names dont match (this will also skip <init> and <clinit> too)
    if (methodThatMightBeGettingOverridden.getParameterTypes().length!=methodParamsArray.lengthreturn null; // check same number of parameters
    if (!isVisibilityOverride(mmods,methodThatMightBeGettingOverridden,inSamePackage))  return null;
 
    if (debug) System.err.println("  Seriously considering this might be getting overridden "+methodThatMightBeGettingOverridden);
   
    // Look at erasures of parameters (List<String> erased is List)
    boolean sameParams = true;
    for (int p = 0;p<methodThatMightBeGettingOverridden.getParameterTypes().length;p++) {
      if (!methodThatMightBeGettingOverridden.getParameterTypes()[p].getErasureSignature().equals(methodParamsArray[p].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
   
      if (sameParams) {         
        // check for covariance
        if (typeToCheck.isParameterizedType()) {
        return methodThatMightBeGettingOverridden.getBackingGenericMember();
        } else if (!methodThatMightBeGettingOverridden.getReturnType().getErasureSignature().equals(mrettype)) {
          return methodThatMightBeGettingOverridden; // covariance
        }
      }
      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) {
      if (inheritedMethod.isStatic()) return false;
      if (methodMods == inheritedMethod.getModifiers()) return true;

      if (inheritedMethod.isPrivate()) return false;
     
      boolean isPackageVisible = !inheritedMethod.isPrivate() && !inheritedMethod.isProtected()
                               && !inheritedMethod.isPublic();
      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 ResolvedMember checkForOverride(ResolvedType typeToCheck,String mname,String mparams,String mrettype,int mmods,String mpkg,UnresolvedType[] methodParamsArray) {

      if (typeToCheck==null) return null;
      if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) return null; // we just can't tell !
     
      if (debug) System.err.println("  Checking for override of "+mname+" in "+typeToCheck);
     
      String packageName = typeToCheck.getPackageName();
      if (packageName==null) packageName="";
      boolean inSamePackage = packageName.equals(mpkg); // used when looking at visibility rules
     
      ResolvedMember [] methods = typeToCheck.getDeclaredMethods();
      for (int ii=0;ii<methods.length;ii++) {
      ResolvedMember methodThatMightBeGettingOverridden = methods[ii]; // the method we are going to check     
      ResolvedMember isOverriding = isOverriding(typeToCheck,methodThatMightBeGettingOverridden,mname,mrettype,mmods,inSamePackage,methodParamsArray);
      if (isOverriding!=null) return isOverriding;
    }
    List l = typeToCheck.getInterTypeMungers();
    for (Iterator iterator = l.iterator(); iterator.hasNext();) {
      Object 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 (debug) System.err.println("Possible ITD candidate "+element);
          ResolvedMember aMethod = element.getSignature();
          ResolvedMember isOverriding = isOverriding(typeToCheck,aMethod,mname,mrettype,mmods,inSamePackage,methodParamsArray);
          if (isOverriding!=null) return isOverriding;
        }
      }
    }
   
   
    if (typeToCheck.equals(UnresolvedType.OBJECT)) return null;
   
      ResolvedType superclass = typeToCheck.getSuperclass();
    ResolvedMember overriddenMethod = checkForOverride(superclass,mname,mparams,mrettype,mmods,mpkg,methodParamsArray);
    if (overriddenMethod!=null) return overriddenMethod;
     
    ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces();
    for (int i = 0; i < interfaces.length; i++) {
      ResolvedType anInterface = interfaces[i];
      overriddenMethod = checkForOverride(anInterface,mname,mparams,mrettype,mmods,mpkg,methodParamsArray);
      if (overriddenMethod!=null) return overriddenMethod;
    }
    return null;
    }

    /**
     * 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) {
    if (!world.isInJava5Mode()) return false; // just double check... the caller should have already verified this
    if (clazz.isInterface()) return false; // dont bother if we're 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 methodsSet = new HashSet();
    for (int i = 0; i < methods.size(); i++) {
      LazyMethodGen aMethod = (LazyMethodGen)methods.get(i);
      methodsSet.add(aMethod.getName()+aMethod.getSignature()); // 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  = (LazyMethodGen)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 (debug) System.err.println("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 (debug) System.err.println("Checking supertype "+theSuperclass);
      String pkgName = clazz.getPackageName();
      UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes());
      ResolvedMember overriddenMethod = checkForOverride(theSuperclass,name,psig,rsig,bridgeToCandidate.getAccessFlags(),pkgName,bm);
      if (overriddenMethod!=null) {
        boolean alreadyHaveABridgeMethod = methodsSet.contains(overriddenMethod.getName()+overriddenMethod.getSignature());
        if (!alreadyHaveABridgeMethod) {
          if (debug) System.err.println("Bridging to "+overriddenMethod);
          createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
          didSomething = true;
          continue; // look at the next method
        }
      }

      // Check superinterfaces
      String[] interfaces = clazz.getInterfaceNames();
      for (int j = 0; j < interfaces.length; j++) {
        if (debug) System.err.println("Checking superinterface "+interfaces[j]);
        ResolvedType interfaceType = world.resolve(interfaces[j]);
        overriddenMethod = checkForOverride(interfaceType,name,psig,rsig,bridgeToCandidate.getAccessFlags(),clazz.getPackageName(),bm);
        if (overriddenMethod!=null) {
          boolean alreadyHaveABridgeMethod = methodsSet.contains(overriddenMethod.getName()+overriddenMethod.getSignature());
          if (!alreadyHaveABridgeMethod) {
            createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
            didSomething=true;
            if (debug) System.err.println("Bridging to "+overriddenMethod);
            continue; // look at the next method
         
        }
      }
    }

    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 reportedProblems = new ArrayList();
   
    List allDecams = world.getDeclareAnnotationOnMethods();
    if (allDecams.isEmpty()) return false; // nothing to do
   
    boolean isChanged = false;

    // deal with ITDs
    List 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);
    }
   
    // deal with all the other methods...
        List members = clazz.getMethodGens();
    List decaMs = getMatchingSubset(allDecams,clazz.getType());   
    if (decaMs.isEmpty()) return false; // nothing to do
    if (!members.isEmpty()) {
      Set unusedDecams = new HashSet();
      unusedDecams.addAll(decaMs);
          for (int memberCounter = 0;memberCounter<members.size();memberCounter++) {
            LazyMethodGen mg = (LazyMethodGen)members.get(memberCounter);
            if (!mg.getName().startsWith(NameMangler.PREFIX)) {
             
              // Single first pass
              List worthRetrying = new ArrayList();
              boolean modificationOccured = false;
             
              for (Iterator iter = decaMs.iterator(); iter.hasNext();) {
                DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
               
                if (decaM.matches(mg.getMemberView(),world)) {
                  if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) {
                    // remove the declare @method since don't want an error when
                    // the annotation is already there
                    unusedDecams.remove(decaM);
                    continue; // skip this one...
                  }
                 
                  Annotation a = decaM.getAnnotationX().getBcelAnnotation();
                  AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true);
                  Method oldMethod = mg.getMethod();
                  MethodGen myGen = new MethodGen(oldMethod,clazz.getClassName(),clazz.getConstantPoolGen());
                  myGen.addAnnotation(ag);
                  Method newMethod = myGen.getMethod();
                  mg.addAnnotation(decaM.getAnnotationX());
                  members.set(memberCounter,new LazyMethodGen(newMethod,clazz));
                 
                  AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.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 forRemoval = new ArrayList();
                for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
                  DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
                  if (decaM.matches(mg.getMemberView(),world)) {
                    if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) {
                      // remove the declare @method since don't want an error when
                        // the annotation is already there
                        unusedDecams.remove(decaM);
                      continue; // skip this one...
                    }
                    mg.addAnnotation(decaM.getAnnotationX());
                    AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
                    isChanged = true;
                    modificationOccured = true;
                    forRemoval.add(decaM);
                // remove the declare @method since have matched against it
                    unusedDecams.remove(decaM);
                  }
                }
                worthRetrying.removeAll(forRemoval);
              }
            }
          }
        checkUnusedDeclareAtTypes(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 getMatchingSubset(List declareAnnotations, ResolvedType type) {
      List subset = new ArrayList();
      for (Iterator iter = declareAnnotations.iterator(); iter.hasNext();) {
      DeclareAnnotation da = (DeclareAnnotation) iter.next();
      if (da.couldEverMatch(type)) {
        subset.add(da);
      }
    }
    return subset;
  }

 
    /**
     * Get a subset of all the type mungers defined on this aspect
     */
  private List getITDSubset(LazyClassGen clazz,ResolvedTypeMunger.Kind wantedKind) {
    List subset = new ArrayList();
    Collection c = clazz.getBcelObjectType().getTypeMungers();
    for (Iterator iter = c.iterator();iter.hasNext();) {
      BcelTypeMunger typeMunger = (BcelTypeMunger)iter.next();
      if (typeMunger.getMunger().getKind()==wantedKind)
        subset.add(typeMunger);
    }
    return subset;
  }
 
  public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz,BcelTypeMunger fieldMunger) {
    NewFieldTypeMunger nftm = (NewFieldTypeMunger)fieldMunger.getMunger();
    ResolvedMember lookingFor =AjcMemberMaker.interFieldInitializer(nftm.getSignature(),clazz.getType());
    List meths = clazz.getMethodGens();
    for (Iterator iter = meths.iterator(); iter.hasNext();) {
      LazyMethodGen element = (LazyMethodGen) iter.next();
      if (element.getName().equals(lookingFor.getName())) return element;
    }
    return null;
  }
 
  // FIXME asc refactor this to neaten it up
  public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz,BcelTypeMunger methodCtorMunger) {
    if (methodCtorMunger.getMunger() instanceof NewMethodTypeMunger) {
      NewMethodTypeMunger nftm = (NewMethodTypeMunger)methodCtorMunger.getMunger();
     
      ResolvedMember lookingFor = AjcMemberMaker.interMethodDispatcher(nftm.getSignature(),methodCtorMunger.getAspectType());
     
      List meths = clazz.getMethodGens();
      for (Iterator iter = meths.iterator(); iter.hasNext();) {
        LazyMethodGen element = (LazyMethodGen) iter.next();
        if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
      }
      return null;
    } else if (methodCtorMunger.getMunger() instanceof NewConstructorTypeMunger) {
      NewConstructorTypeMunger nftm = (NewConstructorTypeMunger)methodCtorMunger.getMunger();
      ResolvedMember lookingFor =AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(),nftm.getSignature().getDeclaringType(),nftm.getSignature().getParameterTypes());
      List meths = clazz.getMethodGens();
      for (Iterator iter = meths.iterator(); iter.hasNext();) {
        LazyMethodGen element = (LazyMethodGen) iter.next();
        if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
      }
      return null;
    } else {
      throw new RuntimeException("Not sure what this is: "+methodCtorMunger);
    }
  }
 
    /**
     * 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 decaFs, List itdFields,List reportedErrors) {
    boolean isChanged = false;
    for (Iterator iter = itdFields.iterator(); iter.hasNext();) {
      BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next();
      ResolvedMember itdIsActually = fieldMunger.getSignature();
      List worthRetrying = new ArrayList();
      boolean modificationOccured = false;
     
      for (Iterator iter2 = decaFs.iterator(); iter2.hasNext();) {
        DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
       
        if (decaF.matches(itdIsActually,world)) {
          LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
          if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
          annotationHolder.addAnnotation(decaF.getAnnotationX());
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
          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 forRemoval = new ArrayList();
                for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) {
          DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
          if (decaF.matches(itdIsActually,world)) {
          LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
          if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
          annotationHolder.addAnnotation(decaF.getAnnotationX());
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
          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 decaMCs, List itdMethodsCtors,List reportedErrors) {
    boolean isChanged = false;
    for (Iterator iter = itdMethodsCtors.iterator(); iter.hasNext();) {
      BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next();
      ResolvedMember unMangledInterMethod = methodctorMunger.getSignature();
      List worthRetrying = new ArrayList();
      boolean modificationOccured = false;
     
      for (Iterator iter2 = decaMCs.iterator(); iter2.hasNext();) {
        DeclareAnnotation decaMC = (DeclareAnnotation) 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.getAnnotationX());
          isChanged=true;
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
          reportMethodCtorWeavingMessage(clazz, unMangledInterMethod, decaMC,-1);
          modificationOccured = true;         
        } else {
          if (!decaMC.isStarredAnnotationPattern())
            worthRetrying.add(decaMC); // an annotation is specified that might be put on by a subsequent decaf
        }
      }
     
        while (!worthRetrying.isEmpty() && modificationOccured) {
        modificationOccured = false;
                List forRemoval = new ArrayList();
                for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) {
          DeclareAnnotation decaMC = (DeclareAnnotation) 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.getAnnotationX());
          unMangledInterMethod.addAnnotation(decaMC.getAnnotationX());
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
          isChanged = true;
          modificationOccured = true;
          forRemoval.add(decaMC);
          }
          worthRetrying.removeAll(forRemoval);
                }
        }
        }
        return isChanged;
  }
 
  private boolean dontAddTwice(DeclareAnnotation decaF, Annotation [] dontAddMeTwice){
    for (int i = 0; i < dontAddMeTwice.length; i++){
      Annotation ann = dontAddMeTwice[i];
      if (ann != null && decaF.getAnnotationX().getTypeName().equals(ann.getTypeName())){
        dontAddMeTwice[i] = null; // incase it really has been added twice!
        return true;
      }
    }
    return false;
  }
 
  /**
   * Weave any declare @field statements into the fields of the supplied class
   *
   * 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) {
   
        // 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

    List reportedProblems = new ArrayList();

    List allDecafs = world.getDeclareAnnotationOnFields();
    if (allDecafs.isEmpty()) return false; // nothing to do
   
   
    boolean isChanged = false;
    List itdFields = getITDSubset(clazz,ResolvedTypeMunger.Field);
    if (itdFields!=null) {
      isChanged = weaveAtFieldRepeatedly(allDecafs,itdFields,reportedProblems);
    }
   
        List decaFs = getMatchingSubset(allDecafs,clazz.getType());
    if (decaFs.isEmpty()) return false; // nothing more to do
    Field[] fields = clazz.getFieldGens();
    if (fields!=null) {
      Set unusedDecafs = new HashSet();
      unusedDecafs.addAll(decaFs);
          for (int fieldCounter = 0;fieldCounter<fields.length;fieldCounter++) {
            BcelField aBcelField = new BcelField(clazz.getBcelObjectType(),fields[fieldCounter]);
      if (!aBcelField.getName().startsWith(NameMangler.PREFIX)) {       
            // Single first pass
            List worthRetrying = new ArrayList();
            boolean modificationOccured = false;
           
            Annotation [] dontAddMeTwice = fields[fieldCounter].getAnnotations();
           
            // go through all the declare @field statements
            for (Iterator iter = decaFs.iterator(); iter.hasNext();) {
        DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
        if (decaF.matches(aBcelField,world)) {
         
          if (!dontAddTwice(decaF,dontAddMeTwice)){
            if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)){
                    // remove the declare @field since don't want an error when
                    // the annotation is already there
                    unusedDecafs.remove(decaF);
              continue;
            }
           
            if(decaF.getAnnotationX().isRuntimeVisible()){ // isAnnotationWithRuntimeRetention(clazz.getJavaClass(world))){
            //if(decaF.getAnnotationTypeX().isAnnotationWithRuntimeRetention(world)){           
              // it should be runtime visible, so put it on the Field
              Annotation a = decaF.getAnnotationX().getBcelAnnotation();
              AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true);
              FieldGen myGen = new FieldGen(fields[fieldCounter],clazz.getConstantPoolGen());
              myGen.addAnnotation(ag);
              Field newField = myGen.getField();
             
              aBcelField.addAnnotation(decaF.getAnnotationX());
              clazz.replaceField(fields[fieldCounter],newField);
              fields[fieldCounter]=newField;
             
            } else{
              aBcelField.addAnnotation(decaF.getAnnotationX());
            }
          }
         
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]);
          reportFieldAnnotationWeavingMessage(clazz, fields, fieldCounter, decaF);   
          isChanged = true;
          modificationOccured = true;
          // remove the declare @field since have matched against it
              unusedDecafs.remove(decaF);
        } else {
          if (!decaF.isStarredAnnotationPattern())
            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
              List forRemoval = new ArrayList();
              for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
        DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
        if (decaF.matches(aBcelField,world)) {
          // below code is for recursive things
          if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)) {
                // remove the declare @field since don't want an error when
                // the annotation is already there
                unusedDecafs.remove(decaF);
            continue; // skip this one...
          }
          aBcelField.addAnnotation(decaF.getAnnotationX());
          AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]);
          isChanged = true;
          modificationOccured = true;
          forRemoval.add(decaF);
          // remove the declare @field since have matched against it
              unusedDecafs.remove(decaF);
        }
        }
        worthRetrying.removeAll(forRemoval);
            }
      }
          }
        checkUnusedDeclareAtTypes(unusedDecafs,true);
        }
    return isChanged;
  }

  // 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 checkUnusedDeclareAtTypes(Set unusedDecaTs, boolean isDeclareAtField) {
    for (Iterator iter = unusedDecaTs.iterator(); iter.hasNext();) {
        DeclareAnnotation declA = (DeclareAnnotation) iter.next();
       
        // Error if an exact type pattern was specified
        if ((declA.isExactPattern() ||
          (declA.getSignaturePattern().getDeclaringType() instanceof ExactTypePattern))
          && (!declA.getSignaturePattern().getName().isAny()
              || (declA.getKind() == DeclareAnnotation.AT_CONSTRUCTOR))) {
         
          // Quickly check if an ITD meets supplies the 'missing' member
          boolean itdMatch = false;
          List lst = clazz.getType().getInterTypeMungers();
          for (Iterator iterator = lst.iterator(); iterator.hasNext() && !itdMatch;) {
          BcelTypeMunger element = (BcelTypeMunger) iterator.next();
          if (element.getMunger() instanceof NewFieldTypeMunger) {
            NewFieldTypeMunger nftm = (NewFieldTypeMunger)element.getMunger();
            itdMatch = declA.getSignaturePattern().matches(nftm.getSignature(),world,false);
            }else if (element.getMunger() instanceof NewMethodTypeMunger) {
            NewMethodTypeMunger nmtm = (NewMethodTypeMunger)element.getMunger();
            itdMatch = declA.getSignaturePattern().matches(nmtm.getSignature(),world,false);             
          } else if (element.getMunger() instanceof NewConstructorTypeMunger) {
            NewConstructorTypeMunger nctm = (NewConstructorTypeMunger)element.getMunger();
            itdMatch = declA.getSignaturePattern().matches(nctm.getSignature(),world,false);             
          }
        }
          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, Field[] fields, int fieldCounter, DeclareAnnotation decaF) {
    if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
      Field theField = fields[fieldCounter];
      world.getMessageHandler().handleMessage(
              WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
                  new String[]{
              theField.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 reportedProblems) {
    if (rm.hasAnnotation(deca.getAnnotationTypeX())) {
      if (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.getAnnotationTypeX().toString()},
              rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
        }
      }
    return true;
    }
    return false;
  }
 
  private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm,ResolvedMember itdfieldsig,DeclareAnnotation deca,List reportedProblems) {
      if (rm != null && rm.hasAnnotation(deca.getAnnotationTypeX())) {
        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[]{rm.toString(),deca.getAnnotationTypeX().toString()},
            rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
          }
        }
          return true;
      }
      return false;
    }
 
  private Set findAspectsForMungers(LazyMethodGen mg) {
    Set aspectsAffectingType = new HashSet();
    for (Iterator iter = mg.matchedShadows.iterator(); iter.hasNext();) {
      BcelShadow aShadow = (BcelShadow) iter.next()
      // Mungers in effect on that shadow
      for (Iterator iter2 = aShadow.getMungers().iterator();iter2.hasNext();) {
        ShadowMunger aMunger = (ShadowMunger) iter2.next();
        if (aMunger instanceof BcelAdvice) {
          BcelAdvice bAdvice = (BcelAdvice)aMunger;
          if(bAdvice.getConcreteAspect() != null){
            aspectsAffectingType.add(bAdvice.getConcreteAspect().getName());
          }
        } else {
        // It is a 'Checker' - we don't need to remember aspects that only contributed Checkers...
        }   
      }
    }
    return aspectsAffectingType;
  }


  private boolean inlineSelfConstructors(List methodGens) {
    boolean inlinedSomething = false;
    for (Iterator i = methodGens.iterator(); i.hasNext();) {
      LazyMethodGen mg = (LazyMethodGen) i.next();
      if (! mg.getName().equals("<init>")) continue;
      InstructionHandle ih = findSuperOrThisCall(mg);
      if (ih != null && isThisCall(ih)) {
        LazyMethodGen donor = getCalledMethod(ih);
        inlineMethod(donor, mg, ih);
        inlinedSomething = true;
      }
    }
    return inlinedSomething;
  }

  private void positionAndImplement(List initializationShadows) {
    for (Iterator i = initializationShadows.iterator(); i.hasNext(); ) {
      BcelShadow s = (BcelShadow) i.next();
      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((BcelShadow) 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) {
    INVOKESPECIAL inst = (INVOKESPECIAL) 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);
  }

  /** 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 srcToDest  = new HashMap();
    ConstantPoolGen donorCpg = donor.getEnclosingClass().getConstantPoolGen();
    ConstantPoolGen recipientCpg = recipient.getEnclosingClass().getConstantPoolGen();
   
    boolean isAcrossClass = donorCpg != recipientCpg;
   
    // 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 (fresh instanceof CPInstruction) {
        // 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) {
          CPInstruction cpi = (CPInstruction) fresh;
          cpi.setIndex(
            recipientCpg.addConstant(
              donorCpg.getConstant(cpi.getIndex()),
              donorCpg));
        }
      }
      if (src.getInstruction() == Range.RANGEINSTRUCTION) {
        dest = ret.append(Range.RANGEINSTRUCTION);
      } else if (fresh instanceof ReturnInstruction) {
        if (keepReturns) {
          dest = ret.append(fresh);
        } else {
          dest =
            ret.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end));
        }
      } else if (fresh instanceof BranchInstruction) {
        dest = ret.append((BranchInstruction) fresh);
      } else if (
        fresh instanceof LocalVariableInstruction || fresh instanceof RET) {
        IndexedInstruction indexed = (IndexedInstruction) fresh;
        int oldIndex = indexed.getIndex();
        int freshIndex;
        if (!frameEnv.hasKey(oldIndex)) {
          freshIndex = recipient.allocateLocal(2);
          frameEnv.put(oldIndex, freshIndex);
        } else {
          freshIndex = frameEnv.get(oldIndex);
        }
        indexed.setIndex(freshIndex);
        dest = ret.append(fresh);
      } else {
        dest = ret.append(fresh);
      }
      srcToDest.put(src, dest);
    }
   
    // second pass: retarget branch instructions, copy ranges and tags
    Map tagMap = new HashMap();
    Map shadowMap = new HashMap();   
    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 BranchInstruction) {
        BranchInstruction branch = (BranchInstruction) 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 Select) {
            Select select = (Select) 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
          InstructionTargeter[] srcTargeters = src.getTargeters();
          if (srcTargeters != null) {
              for (int j = srcTargeters.length - 1; j >= 0; j--) {
                  InstructionTargeter old = srcTargeters[j];
                  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(
                          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) ret.append(footer);
    return ret;
  }

  /** 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() {
        public int compare(Object a, Object b) {
          LazyMethodGen aa = (LazyMethodGen) a;
          LazyMethodGen bb = (LazyMethodGen) b;
          int i = aa.getName().compareTo(bb.getName());
          if (i != 0) return i;
          return aa.getSignature().compareTo(bb.getSignature());
        }
      }
    );
   
    for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
      clazz.addMethodGen((LazyMethodGen)i.next());
    }
  }

    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 instanceof INVOKESPECIAL
        && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) {
        depth--;
        if (depth == 0) return start;
      } else if (inst instanceof NEW) {
        depth++;
      }
      start = start.getNext();
    }
  }

  // ----
 
  private boolean match(LazyMethodGen mg) {
    BcelShadow enclosingShadow;

    List shadowAccumulator = new ArrayList();
    // we want to match ajsynthetic constructors...
    if (mg.getName().equals("<init>")) {
      return matchInit(mg, shadowAccumulator);
    } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) {
      return false;     
    } else {
      if (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) {
          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!!)
         
          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().startsWith("ajc$interFieldInit")) {
        if (match(enclosingShadow, shadowAccumulator)) {
          enclosingShadow.init();
        }
      }
      mg.matchedShadows = shadowAccumulator;
      return !shadowAccumulator.isEmpty();
    }
  }

  private boolean matchInit(LazyMethodGen mg, List 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 (superOrThisCall != null && ! isThisCall(superOrThisCall)) {
      InstructionHandle curr = enclosingShadow.getRange().getStart();
      for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) {
        IfaceInitList l = (IfaceInitList) 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 list, boolean isStatic) {
    list = PartialOrder.sort(list);
        if (list == null) {
          throw new BCException("circularity in inter-types");
        }
   
    InstructionList ret = new InstructionList();
   
    for (Iterator i = list.iterator(); i.hasNext();) {
      ConcreteTypeMunger cmunger = (ConcreteTypeMunger) i.next();
      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 shadowAccumulator)
  {
    Instruction i = ih.getInstruction();
    if ((i instanceof FieldInstruction) &&
      (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))
    ) {
      FieldInstruction fi = (FieldInstruction) i;
           
      if (fi instanceof PUTFIELD || fi instanceof 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.getConstantPoolGen()).equals("<init>")) {
        if (canMatch(Shadow.ConstructorCall))
          match(
              BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow),
              shadowAccumulator);
      } else if (ii instanceof 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 {
          matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
      }
    }
    // performance optimization... we only actually care about ASTORE instructions,
    // since that's what every javac type thing ever uses to start a handler, but for
    // now we'll do this for everybody.
    if (!canMatch(Shadow.ExceptionHandler)) return;
    if (Range.isRangeHandle(ih)) return;
    InstructionTargeter[] targeters = ih.getTargeters();
    if (targeters != null) {
      for (int j = 0; j < targeters.length; j++) {
        InstructionTargeter t = targeters[j];
        if (t instanceof ExceptionRange) {
          // assert t.getHandler() == ih
          ExceptionRange er = (ExceptionRange) t;
          if (er.getCatchType() == null) continue;
          if (isInitFailureHandler(ih)) return;
         
          match(
            BcelShadow.makeExceptionHandler(
              world,
              er,
              mg, ih, enclosingShadow),
            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() instanceof PUTSTATIC) {
      String name = ((PUTSTATIC)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 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 {
      match(
        BcelShadow.makeFieldSet(world, mg, ih, enclosingShadow),
        shadowAccumulator);
    }
  }

  private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List 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;
  }
 
  /**
   * 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();
    ResolvedType[] annotations = (ResolvedType[])mapToAnnotations.get(rm);
    String methodName = declaredSig.getName();
    // FIXME asc shouldnt really rely on string names !
    if (annotations == null) {
      if (rm.getKind()==Member.FIELD) {
        if (methodName.startsWith("ajc$inlineAccessField")) {
          ResolvedMember resolvedDooberry = world.resolve(rm);
          annotations = resolvedDooberry.getAnnotationTypes();
        } else {
          ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm,memberHostType);
          ResolvedMember resolvedDooberry = world.resolve(realthing);
          annotations = resolvedDooberry.getAnnotationTypes();
        }
      } else if (rm.getKind()==Member.METHOD && !rm.isAbstract()) {
        if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) {
          ResolvedMember resolvedDooberry = world.resolve(declaredSig);
          annotations = resolvedDooberry.getAnnotationTypes();
        } else {
          ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world),memberHostType).resolve(world);
          // ResolvedMember resolvedDooberry = world.resolve(realthing);
          ResolvedMember theRealMember = findResolvedMemberNamed(memberHostType.resolve(world),realthing.getName());
          // AMC temp guard for M4
          if (theRealMember == 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");
          }
          annotations = theRealMember.getAnnotationTypes();
        }
      } else if (rm.getKind()==Member.CONSTRUCTOR) {
        ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(),rm.getParameterTypes());
        ResolvedMember resolvedDooberry = world.resolve(realThing);
        // AMC temp guard for M4
        if (resolvedDooberry == 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");
        }
        annotations = resolvedDooberry.getAnnotationTypes();
      }
      if (annotations == null)
          annotations = new ResolvedType[0];
      mapToAnnotations.put(rm,annotations);
    }
    rm.setAnnotationTypes(annotations);
    }
      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 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(ResolvedType.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 {
        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();
       
        fixAnnotationsForResolvedMember(rm,declaredSig); // abracadabra
       
        if (canMatch(effectiveSig.getShadowKind()))
          match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow,
              effectiveSig.getShadowKind(), rm), shadowAccumulator);
      }
    } else {
      if (canMatch(Shadow.MethodCall))
        match(
            BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow),
            shadowAccumulator);
    }
  }
 
    private boolean match(BcelShadow shadow, List shadowAccumulator) {
      //System.err.println("match: " + shadow);
      ContextToken shadowMatchToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MATCHING_SHADOW, shadow);
        boolean isMatched = false;
        for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
            ShadowMunger munger = (ShadowMunger)i.next();
            ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut());
            if (munger.match(shadow, world)) {
             
        WeaverMetrics.recordMatchResult(true);// Could pass: munger
                shadow.addMunger(munger);
                isMatched = true;
          if (shadow.getKind() == Shadow.StaticInitialization) {
          clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation());
          }
       
            } else {
              WeaverMetrics.recordMatchResult(false); // Could pass: munger
          }
            CompilationAndWeavingContext.leavingPhase(mungerMatchToken);
        }      

        if (isMatched) shadowAccumulator.add(shadow);
        CompilationAndWeavingContext.leavingPhase(shadowMatchToken);
        return isMatched;
    }
   
    // ----
   
    private void implement(LazyMethodGen mg) {
      List 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 (Iterator i = shadows.iterator(); i.hasNext(); ) {
            BcelShadow shadow = (BcelShadow)i.next();
            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 List getShadowMungers() {
    return shadowMungers;
  }

  public BcelWorld getWorld() {
    return world;
  }
 
  // Called by the BcelWeaver to let us know all BcelClassWeavers need to collect reweavable info
  public static void setReweavableMode(boolean mode) {
    inReweavableMode = mode;
  }
 
  public static boolean getReweavableMode() {
    return inReweavableMode;
  }
 
  public String toString() {
    return "BcelClassWeaver instance for : "+clazz;
  }
   

}
TOP

Related Classes of org.aspectj.weaver.bcel.BcelClassWeaver

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.