Logo Search packages:      
Sourcecode: aspectj version File versions

CflowPointcut.java

/* *******************************************************************
 * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors: 
 *     PARC     initial implementation 
 * ******************************************************************/

package org.aspectj.weaver.patterns;

import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.aspectj.bridge.IMessage;
import org.aspectj.util.FileUtil;
import org.aspectj.util.FuzzyBoolean;
import org.aspectj.weaver.Advice;
import org.aspectj.weaver.CrosscuttingMembers;
import org.aspectj.weaver.ISourceContext;
import org.aspectj.weaver.IntMap;
import org.aspectj.weaver.Member;
import org.aspectj.weaver.NameMangler;
import org.aspectj.weaver.ResolvedMember;
import org.aspectj.weaver.ResolvedMemberImpl;
import org.aspectj.weaver.ResolvedPointcutDefinition;
import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.Shadow;
import org.aspectj.weaver.UnresolvedType;
import org.aspectj.weaver.VersionedDataInputStream;
import org.aspectj.weaver.WeaverMessages;
import org.aspectj.weaver.World;
import org.aspectj.weaver.ast.Test;

public class CflowPointcut extends Pointcut {
      private final Pointcut entry; // The pointcut inside the cflow() that
      // represents the 'entry' point
      boolean isBelow;// Is this cflowbelow?
      private int[] freeVars;

      /**
       * Used to indicate that we're in the context of a cflow when concretizing if's
       * 
       * Will be removed or replaced with something better when we handle this as a non-error
       */
      public static final ResolvedPointcutDefinition CFLOW_MARKER = new ResolvedPointcutDefinition(null, 0, null,
                  UnresolvedType.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));

      public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) {
            // System.err.println("Building cflow pointcut "+entry.toString());
            this.entry = entry;
            this.isBelow = isBelow;
            this.freeVars = freeVars;
            pointcutKind = CFLOW;
      }

      /**
       * @return Returns true is this is a cflowbelow pointcut
       */
      public boolean isCflowBelow() {
            return isBelow;
      }

      public int couldMatchKinds() {
            return Shadow.ALL_SHADOW_KINDS_BITS;
      }

      // enh 76055
      public Pointcut getEntry() {
            return entry;
      }

      public FuzzyBoolean fastMatch(FastMatchInfo type) {
            return FuzzyBoolean.MAYBE;
      }

      protected FuzzyBoolean matchInternal(Shadow shadow) {
            // ??? this is not maximally efficient
            return FuzzyBoolean.MAYBE;
      }

      public void write(DataOutputStream s) throws IOException {
            s.writeByte(Pointcut.CFLOW);
            entry.write(s);
            s.writeBoolean(isBelow);
            FileUtil.writeIntArray(freeVars, s);
            writeLocation(s);
      }

      public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {

            CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
            ret.readLocation(context, s);
            return ret;
      }

      public Pointcut parameterizeWith(Map typeVariableMap, World w) {
            CflowPointcut ret = new CflowPointcut(entry.parameterizeWith(typeVariableMap, w), isBelow, freeVars);
            ret.copyLocationFrom(this);
            return ret;
      }

      public void resolveBindings(IScope scope, Bindings bindings) {
            if (bindings == null) {
                  entry.resolveBindings(scope, null);
                  entry.state = RESOLVED;
                  freeVars = new int[0];
            } else {
                  // ??? for if's sake we might need to be more careful here
                  Bindings entryBindings = new Bindings(bindings.size());

                  entry.resolveBindings(scope, entryBindings);
                  entry.state = RESOLVED;

                  freeVars = entryBindings.getUsedFormals();

                  bindings.mergeIn(entryBindings, scope);
            }
      }

      public boolean equals(Object other) {
            if (!(other instanceof CflowPointcut))
                  return false;
            CflowPointcut o = (CflowPointcut) other;
            return o.entry.equals(entry) && o.isBelow == isBelow;
      }

      public int hashCode() {
            int result = 17;
            result = 37 * result + entry.hashCode();
            result = 37 * result + (isBelow ? 0 : 1);
            return result;
      }

      public String toString() {
            return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
      }

      protected Test findResidueInternal(Shadow shadow, ExposedState state) {
            throw new RuntimeException("unimplemented - did concretization fail?");
      }

      public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {

            // the pointcut is marked as CONCRETE after returning from this
            // call - so we can't skip concretization
            // if (this.entry.state == Pointcut.SYMBOLIC) {
            // // too early to concretize, return unchanged
            // return this;
            // }

            // Enforce rule about which designators are supported in declare
            if (isDeclare(bindings.getEnclosingAdvice())) {
                  inAspect.getWorld().showMessage(IMessage.ERROR,
                              WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE, isBelow ? "below" : ""),
                              bindings.getEnclosingAdvice().getSourceLocation(), null);
                  return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
            }

            // make this remap from formal positions to arrayIndices
            IntMap entryBindings = new IntMap();
            if (freeVars != null) {
                  for (int i = 0, len = freeVars.length; i < len; i++) {
                        int freeVar = freeVars[i];
                        // int formalIndex = bindings.get(freeVar);
                        entryBindings.put(freeVar, i);
                  }
            }
            entryBindings.copyContext(bindings);
            // System.out.println(this + " bindings: " + entryBindings);

            World world = inAspect.getWorld();

            Pointcut concreteEntry;

            ResolvedType concreteAspect = bindings.getConcreteAspect();

            CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
            Collection previousCflowEntries = xcut.getCflowEntries();

            entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
            // This block concretizes the pointcut within the cflow pointcut
            try {
                  concreteEntry = entry.concretize(inAspect, declaringType, entryBindings);
            } finally {
                  entryBindings.popEnclosingDefinitition();
            }

            List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
            innerCflowEntries.removeAll(previousCflowEntries);

            // Four routes of interest through this code (did I hear someone say
            // refactor??)
            // 1) no state in the cflow - we can use a counter *and* we have seen
            // this pointcut
            // before - so use the same counter as before.
            // 2) no state in the cflow - we can use a counter, but this is the
            // first time
            // we have seen this pointcut, so build the infrastructure.
            // 3) state in the cflow - we need to use a stack *and* we have seen
            // this pointcut
            // before - so share the stack.
            // 4) state in the cflow - we need to use a stack, but this is the first
            // time
            // we have seen this pointcut, so build the infrastructure.

            if (freeVars == null || freeVars.length == 0) { // No state, so don't
                  // use a stack, use a
                  // counter.
                  ResolvedMember localCflowField = null;

                  Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "counter");

                  // Check if we have already got a counter for this cflow pointcut
                  if (field != null) {
                        localCflowField = (ResolvedMember) field; // Use the one we
                        // already have

                  } else {

                        // Create a counter field in the aspect
                        localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC
                                    | Modifier.FINAL, NameMangler.cflowCounter(xcut), UnresolvedType.forName(NameMangler.CFLOW_COUNTER_TYPE)
                                    .getSignature());

                        // Create type munger to add field to the aspect
                        concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport().makeCflowCounterFieldAdder(
                                    localCflowField));

                        // Create shadow munger to push stuff onto the stack
                        concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
                                    localCflowField, freeVars == null ? 0 : freeVars.length, innerCflowEntries, inAspect));

                        putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "counter"); // Remember
                        // it
                  }

                  Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, null, true);
                  ret.copyLocationFrom(this);
                  return ret;
            } else {

                  List slots = new ArrayList();

                  for (int i = 0, len = freeVars.length; i < len; i++) {
                        int freeVar = freeVars[i];

                        // we don't need to keep state that isn't actually exposed to
                        // advice
                        // ??? this means that we will store some state that we won't
                        // actually use, optimize this later
                        if (!bindings.hasKey(freeVar))
                              continue;

                        int formalIndex = bindings.get(freeVar);

                        // We need to look in the right place for the type of the
                        // formal. Suppose the advice looks like this:
                        // before(String s): somePointcut(*,s)
                        // where the first argument in somePointcut is of type Number
                        // for free variable 0 we want to ask the pointcut for the type
                        // of its first argument, if we only
                        // ask the advice for the type of its first argument then we'll
                        // get the wrong type (pr86903)

                        ResolvedPointcutDefinition enclosingDef = bindings.peekEnclosingDefinition();
                        ResolvedType formalType = null;

                        // Is there a useful enclosing pointcut?
                        if (enclosingDef != null && enclosingDef.getParameterTypes().length > 0) {
                              formalType = enclosingDef.getParameterTypes()[freeVar].resolve(world);
                        } else {
                              formalType = bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
                        }

                        ConcreteCflowPointcut.Slot slot = new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
                        slots.add(slot);
                  }
                  ResolvedMember localCflowField = null;
                  Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "stack");
                  if (field != null) {
                        localCflowField = (ResolvedMember) field;
                  } else {

                        localCflowField = new ResolvedMemberImpl(Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC
                                    | Modifier.FINAL, NameMangler.cflowStack(xcut), UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE)
                                    .getSignature());
                        // System.out.println("adding field to: " + inAspect + " field "
                        // + cflowField);

                        // add field and initializer to inAspect
                        // XXX and then that info above needs to be mapped down here to
                        // help with
                        // XXX getting the exposed state right
                        concreteAspect.crosscuttingMembers.addConcreteShadowMunger(Advice.makeCflowEntry(world, concreteEntry, isBelow,
                                    localCflowField, freeVars.length, innerCflowEntries, inAspect));

                        concreteAspect.crosscuttingMembers.addTypeMunger(world.getWeavingSupport()
                                    .makeCflowStackFieldAdder(localCflowField));
                        putCflowfield(xcut, concreteEntry, concreteAspect, localCflowField, "stack");
                  }
                  Pointcut ret = new ConcreteCflowPointcut(concreteAspect, localCflowField, slots, false);
                  ret.copyLocationFrom(this);
                  return ret;
            }

      }

      private String getKey(Pointcut p, ResolvedType a, String stackOrCounter) {
            StringBuffer sb = new StringBuffer();
            sb.append(a.getName());
            sb.append("::");
            sb.append(p.toString());
            sb.append("::");
            sb.append(stackOrCounter);
            return sb.toString();
      }

      private Object getCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, String stackOrCounter) {
            String key = getKey(pcutkey, concreteAspect, stackOrCounter);
            Object o = null;
            if (isBelow)
                  o = xcut.getCflowBelowFields().get(key);
            else
                  o = xcut.getCflowFields().get(key);
            // System.err.println("Retrieving for key "+key+" returning "+o);
            return o;
      }

      private void putCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect, Object o,
                  String stackOrCounter) {
            String key = getKey(pcutkey, concreteAspect, stackOrCounter);
            // System.err.println("Storing cflow field for key"+key);
            if (isBelow) {
                  xcut.getCflowBelowFields().put(key, o);
            } else {
                  xcut.getCflowFields().put(key, o);
            }
      }

      public Object accept(PatternNodeVisitor visitor, Object data) {
            return visitor.visit(this, data);
      }

}

Generated by  Doxygen 1.6.0   Back to index