You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CflowPointcut.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.io.DataOutputStream;
  14. import java.io.IOException;
  15. import java.lang.reflect.Modifier;
  16. import java.util.ArrayList;
  17. import java.util.Collection;
  18. import java.util.Enumeration;
  19. import java.util.Hashtable;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map;
  23. import org.aspectj.bridge.IMessage;
  24. import org.aspectj.util.FileUtil;
  25. import org.aspectj.util.FuzzyBoolean;
  26. import org.aspectj.weaver.Advice;
  27. import org.aspectj.weaver.CrosscuttingMembers;
  28. import org.aspectj.weaver.ISourceContext;
  29. import org.aspectj.weaver.IntMap;
  30. import org.aspectj.weaver.Member;
  31. import org.aspectj.weaver.NameMangler;
  32. import org.aspectj.weaver.ResolvedMember;
  33. import org.aspectj.weaver.ResolvedMemberImpl;
  34. import org.aspectj.weaver.ResolvedPointcutDefinition;
  35. import org.aspectj.weaver.ResolvedType;
  36. import org.aspectj.weaver.Shadow;
  37. import org.aspectj.weaver.UnresolvedType;
  38. import org.aspectj.weaver.VersionedDataInputStream;
  39. import org.aspectj.weaver.WeaverMessages;
  40. import org.aspectj.weaver.World;
  41. import org.aspectj.weaver.ast.Test;
  42. public class CflowPointcut extends Pointcut {
  43. private Pointcut entry; // The pointcut inside the cflow() that represents the 'entry' point
  44. boolean isBelow;// Is this cflowbelow?
  45. private int[] freeVars;
  46. /**
  47. * Used to indicate that we're in the context of a cflow when concretizing if's
  48. *
  49. * Will be removed or replaced with something better when we handle this
  50. * as a non-error
  51. */
  52. public static final ResolvedPointcutDefinition CFLOW_MARKER =
  53. new ResolvedPointcutDefinition(null, 0, null, UnresolvedType.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
  54. public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) {
  55. // System.err.println("Building cflow pointcut "+entry.toString());
  56. this.entry = entry;
  57. this.isBelow = isBelow;
  58. this.freeVars = freeVars;
  59. this.pointcutKind = CFLOW;
  60. }
  61. /**
  62. * @return Returns true is this is a cflowbelow pointcut
  63. */
  64. public boolean isCflowBelow() {
  65. return isBelow;
  66. }
  67. public int couldMatchKinds() {
  68. return Shadow.ALL_SHADOW_KINDS_BITS;
  69. }
  70. // enh 76055
  71. public Pointcut getEntry() {
  72. return entry;
  73. }
  74. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  75. return FuzzyBoolean.MAYBE;
  76. }
  77. protected FuzzyBoolean matchInternal(Shadow shadow) {
  78. //??? this is not maximally efficient
  79. return FuzzyBoolean.MAYBE;
  80. }
  81. public void write(DataOutputStream s) throws IOException {
  82. s.writeByte(Pointcut.CFLOW);
  83. entry.write(s);
  84. s.writeBoolean(isBelow);
  85. FileUtil.writeIntArray(freeVars, s);
  86. writeLocation(s);
  87. }
  88. public static Pointcut read(VersionedDataInputStream s, ISourceContext context) throws IOException {
  89. CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
  90. ret.readLocation(context, s);
  91. return ret;
  92. }
  93. public Pointcut parameterizeWith(Map typeVariableMap,World w) {
  94. CflowPointcut ret = new CflowPointcut(entry.parameterizeWith(typeVariableMap,w),isBelow,freeVars);
  95. ret.copyLocationFrom(this);
  96. return ret;
  97. }
  98. public void resolveBindings(IScope scope, Bindings bindings) {
  99. if (bindings == null) {
  100. entry.resolveBindings(scope, null);
  101. entry.state = RESOLVED;
  102. freeVars = new int[0];
  103. } else {
  104. //??? for if's sake we might need to be more careful here
  105. Bindings entryBindings = new Bindings(bindings.size());
  106. entry.resolveBindings(scope, entryBindings);
  107. entry.state = RESOLVED;
  108. freeVars = entryBindings.getUsedFormals();
  109. bindings.mergeIn(entryBindings, scope);
  110. }
  111. }
  112. public boolean equals(Object other) {
  113. if (!(other instanceof CflowPointcut)) return false;
  114. CflowPointcut o = (CflowPointcut)other;
  115. return o.entry.equals(this.entry) && o.isBelow == this.isBelow;
  116. }
  117. public int hashCode() {
  118. int result = 17;
  119. result = 37*result + entry.hashCode();
  120. result = 37*result + (isBelow ? 0 : 1);
  121. return result;
  122. }
  123. public String toString() {
  124. return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
  125. }
  126. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  127. throw new RuntimeException("unimplemented - did concretization fail?");
  128. }
  129. public Pointcut concretize1(ResolvedType inAspect, ResolvedType declaringType, IntMap bindings) {
  130. // the pointcut is marked as CONCRETE after returning from this
  131. // call - so we can't skip concretization
  132. // if (this.entry.state == Pointcut.SYMBOLIC) {
  133. // // too early to concretize, return unchanged
  134. // return this;
  135. // }
  136. // Enforce rule about which designators are supported in declare
  137. if (isDeclare(bindings.getEnclosingAdvice())) {
  138. inAspect.getWorld().showMessage(IMessage.ERROR,
  139. WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE,isBelow?"below":""),
  140. bindings.getEnclosingAdvice().getSourceLocation(), null);
  141. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  142. }
  143. //make this remap from formal positions to arrayIndices
  144. IntMap entryBindings = new IntMap();
  145. if (freeVars!=null) {
  146. for (int i=0, len=freeVars.length; i < len; i++) {
  147. int freeVar = freeVars[i];
  148. //int formalIndex = bindings.get(freeVar);
  149. entryBindings.put(freeVar, i);
  150. }
  151. }
  152. entryBindings.copyContext(bindings);
  153. //System.out.println(this + " bindings: " + entryBindings);
  154. World world = inAspect.getWorld();
  155. Pointcut concreteEntry;
  156. ResolvedType concreteAspect = bindings.getConcreteAspect();
  157. CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
  158. Collection previousCflowEntries = xcut.getCflowEntries();
  159. entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
  160. // This block concretizes the pointcut within the cflow pointcut
  161. try {
  162. concreteEntry = entry.concretize(inAspect, declaringType, entryBindings);
  163. } finally {
  164. entryBindings.popEnclosingDefinitition();
  165. }
  166. List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
  167. innerCflowEntries.removeAll(previousCflowEntries);
  168. // Four routes of interest through this code (did I hear someone say refactor??)
  169. // 1) no state in the cflow - we can use a counter *and* we have seen this pointcut
  170. // before - so use the same counter as before.
  171. // 2) no state in the cflow - we can use a counter, but this is the first time
  172. // we have seen this pointcut, so build the infrastructure.
  173. // 3) state in the cflow - we need to use a stack *and* we have seen this pointcut
  174. // before - so share the stack.
  175. // 4) state in the cflow - we need to use a stack, but this is the first time
  176. // we have seen this pointcut, so build the infrastructure.
  177. if (freeVars==null || freeVars.length == 0) { // No state, so don't use a stack, use a counter.
  178. ResolvedMember localCflowField = null;
  179. Object field = getCflowfield(xcut, concreteEntry, concreteAspect, "counter");
  180. // Check if we have already got a counter for this cflow pointcut
  181. if (field != null) {
  182. localCflowField = (ResolvedMember)field; // Use the one we already have
  183. } else {
  184. // Create a counter field in the aspect
  185. localCflowField = new ResolvedMemberImpl(Member.FIELD,concreteAspect,Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  186. NameMangler.cflowCounter(xcut),UnresolvedType.forName(NameMangler.CFLOW_COUNTER_TYPE).getSignature());
  187. // Create type munger to add field to the aspect
  188. concreteAspect.crosscuttingMembers.addTypeMunger(world.makeCflowCounterFieldAdder(localCflowField));
  189. // Create shadow munger to push stuff onto the stack
  190. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  191. Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars==null?0:freeVars.length,innerCflowEntries,inAspect));
  192. putCflowfield(xcut,concreteEntry,concreteAspect,localCflowField,"counter"); // Remember it
  193. }
  194. Pointcut ret = new ConcreteCflowPointcut(localCflowField, null,true);
  195. ret.copyLocationFrom(this);
  196. return ret;
  197. } else {
  198. List slots = new ArrayList();
  199. for (int i=0, len=freeVars.length; i < len; i++) {
  200. int freeVar = freeVars[i];
  201. // we don't need to keep state that isn't actually exposed to advice
  202. //??? this means that we will store some state that we won't actually use, optimize this later
  203. if (!bindings.hasKey(freeVar)) continue;
  204. int formalIndex = bindings.get(freeVar);
  205. // We need to look in the right place for the type of the formal. Suppose the advice looks like this:
  206. // before(String s): somePointcut(*,s)
  207. // where the first argument in somePointcut is of type Number
  208. // for free variable 0 we want to ask the pointcut for the type of its first argument, if we only
  209. // ask the advice for the type of its first argument then we'll get the wrong type (pr86903)
  210. ResolvedPointcutDefinition enclosingDef = bindings.peekEnclosingDefinition();
  211. ResolvedType formalType = null;
  212. // Is there a useful enclosing pointcut?
  213. if (enclosingDef!=null && enclosingDef.getParameterTypes().length>0) {
  214. formalType = enclosingDef.getParameterTypes()[freeVar].resolve(world);
  215. } else {
  216. formalType = bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
  217. }
  218. ConcreteCflowPointcut.Slot slot =
  219. new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
  220. slots.add(slot);
  221. }
  222. ResolvedMember localCflowField = null;
  223. Object field = getCflowfield(xcut,concreteEntry,concreteAspect,"stack");
  224. if (field != null) {
  225. localCflowField = (ResolvedMember)field;
  226. } else {
  227. localCflowField = new ResolvedMemberImpl(
  228. Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  229. NameMangler.cflowStack(xcut),
  230. UnresolvedType.forName(NameMangler.CFLOW_STACK_TYPE).getSignature());
  231. //System.out.println("adding field to: " + inAspect + " field " + cflowField);
  232. // add field and initializer to inAspect
  233. //XXX and then that info above needs to be mapped down here to help with
  234. //XXX getting the exposed state right
  235. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  236. Advice.makeCflowEntry(world, concreteEntry, isBelow, localCflowField, freeVars.length, innerCflowEntries,inAspect));
  237. concreteAspect.crosscuttingMembers.addTypeMunger(
  238. world.makeCflowStackFieldAdder(localCflowField));
  239. putCflowfield(xcut,concreteEntry,concreteAspect,localCflowField,"stack");
  240. }
  241. Pointcut ret = new ConcreteCflowPointcut(localCflowField, slots,false);
  242. ret.copyLocationFrom(this);
  243. return ret;
  244. }
  245. }
  246. private String getKey(Pointcut p,ResolvedType a,String stackOrCounter) {
  247. StringBuffer sb = new StringBuffer();
  248. sb.append(a.getName());
  249. sb.append("::");
  250. sb.append(p.toString());
  251. sb.append("::");
  252. sb.append(stackOrCounter);
  253. return sb.toString();
  254. }
  255. private Object getCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey, ResolvedType concreteAspect,String stackOrCounter) {
  256. String key = getKey(pcutkey,concreteAspect,stackOrCounter);
  257. Object o =null;
  258. if (isBelow) o = xcut.getCflowBelowFields().get(key);
  259. else o = xcut.getCflowFields().get(key);
  260. //System.err.println("Retrieving for key "+key+" returning "+o);
  261. return o;
  262. }
  263. private void putCflowfield(CrosscuttingMembers xcut, Pointcut pcutkey,ResolvedType concreteAspect,Object o,String stackOrCounter) {
  264. String key = getKey(pcutkey,concreteAspect,stackOrCounter);
  265. //System.err.println("Storing cflow field for key"+key);
  266. if (isBelow) {
  267. xcut.getCflowBelowFields().put(key,o);
  268. } else {
  269. xcut.getCflowFields().put(key,o);
  270. }
  271. }
  272. public Object accept(PatternNodeVisitor visitor, Object data) {
  273. return visitor.visit(this, data);
  274. }
  275. }