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

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