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 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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 Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.patterns;
  13. import java.io.DataInputStream;
  14. import java.io.DataOutputStream;
  15. import java.io.IOException;
  16. import java.lang.reflect.Modifier;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.Hashtable;
  20. import java.util.List;
  21. import java.util.Set;
  22. import org.aspectj.bridge.IMessage;
  23. import org.aspectj.util.FileUtil;
  24. import org.aspectj.util.FuzzyBoolean;
  25. import org.aspectj.weaver.Advice;
  26. import org.aspectj.weaver.CrosscuttingMembers;
  27. import org.aspectj.weaver.ISourceContext;
  28. import org.aspectj.weaver.IntMap;
  29. import org.aspectj.weaver.Member;
  30. import org.aspectj.weaver.NameMangler;
  31. import org.aspectj.weaver.ResolvedMember;
  32. import org.aspectj.weaver.ResolvedPointcutDefinition;
  33. import org.aspectj.weaver.ResolvedTypeX;
  34. import org.aspectj.weaver.Shadow;
  35. import org.aspectj.weaver.TypeX;
  36. import org.aspectj.weaver.WeaverMessages;
  37. import org.aspectj.weaver.World;
  38. import org.aspectj.weaver.ast.Test;
  39. public class CflowPointcut extends Pointcut {
  40. private Pointcut entry; // The pointcut inside the cflow() that represents the 'entry' point
  41. private boolean isBelow;// Is this cflowbelow?
  42. private int[] freeVars;
  43. private static Hashtable cflowFields = new Hashtable();
  44. private static Hashtable cflowBelowFields = new Hashtable();
  45. /**
  46. * Used to indicate that we're in the context of a cflow when concretizing if's
  47. *
  48. * Will be removed or replaced with something better when we handle this
  49. * as a non-error
  50. */
  51. public static final ResolvedPointcutDefinition CFLOW_MARKER =
  52. new ResolvedPointcutDefinition(null, 0, null, TypeX.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. this.pointcutKind = CFLOW;
  59. }
  60. public Set couldMatchKinds() {
  61. return Shadow.ALL_SHADOW_KINDS;
  62. }
  63. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  64. return FuzzyBoolean.MAYBE;
  65. }
  66. protected FuzzyBoolean matchInternal(Shadow shadow) {
  67. //??? this is not maximally efficient
  68. return FuzzyBoolean.MAYBE;
  69. }
  70. /* (non-Javadoc)
  71. * @see org.aspectj.weaver.patterns.Pointcut#matchesDynamically(java.lang.Object, java.lang.Object, java.lang.Object[])
  72. */
  73. public boolean matchesDynamically(Object thisObject, Object targetObject,
  74. Object[] args) {
  75. throw new UnsupportedOperationException("cflow pointcut matching not supported by this operation");
  76. }
  77. /* (non-Javadoc)
  78. * @see org.aspectj.weaver.patterns.Pointcut#matchesStatically(java.lang.String, java.lang.reflect.Member, java.lang.Class, java.lang.Class, java.lang.reflect.Member)
  79. */
  80. public FuzzyBoolean matchesStatically(
  81. String joinpointKind, java.lang.reflect.Member member,
  82. Class thisClass, Class targetClass,
  83. java.lang.reflect.Member withinCode) {
  84. throw new UnsupportedOperationException("cflow pointcut matching not supported by this operation");
  85. }
  86. public void write(DataOutputStream s) throws IOException {
  87. s.writeByte(Pointcut.CFLOW);
  88. entry.write(s);
  89. s.writeBoolean(isBelow);
  90. FileUtil.writeIntArray(freeVars, s);
  91. writeLocation(s);
  92. }
  93. public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException {
  94. CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
  95. ret.readLocation(context, s);
  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 void resolveBindingsFromRTTI() {
  113. if (entry.state != RESOLVED) {
  114. entry.resolveBindingsFromRTTI();
  115. }
  116. }
  117. public boolean equals(Object other) {
  118. if (!(other instanceof CflowPointcut)) return false;
  119. CflowPointcut o = (CflowPointcut)other;
  120. return o.entry.equals(this.entry) && o.isBelow == this.isBelow;
  121. }
  122. public int hashCode() {
  123. int result = 17;
  124. result = 37*result + entry.hashCode();
  125. result = 37*result + (isBelow ? 0 : 1);
  126. return result;
  127. }
  128. public String toString() {
  129. return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
  130. }
  131. protected Test findResidueInternal(Shadow shadow, ExposedState state) {
  132. throw new RuntimeException("unimplemented");
  133. }
  134. public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
  135. // Enforce rule about which designators are supported in declare
  136. if (isDeclare(bindings.getEnclosingAdvice())) {
  137. inAspect.getWorld().showMessage(IMessage.ERROR,
  138. WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE,isBelow?"below":""),
  139. bindings.getEnclosingAdvice().getSourceLocation(), null);
  140. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  141. }
  142. //make this remap from formal positions to arrayIndices
  143. IntMap entryBindings = new IntMap();
  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. entryBindings.copyContext(bindings);
  150. //System.out.println(this + " bindings: " + entryBindings);
  151. World world = inAspect.getWorld();
  152. Pointcut concreteEntry;
  153. ResolvedTypeX concreteAspect = bindings.getConcreteAspect();
  154. CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
  155. Collection previousCflowEntries = xcut.getCflowEntries();
  156. entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
  157. // This block concretizes the pointcut within the cflow pointcut
  158. try {
  159. concreteEntry = entry.concretize(inAspect, entryBindings);
  160. } finally {
  161. entryBindings.popEnclosingDefinitition();
  162. }
  163. List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
  164. innerCflowEntries.removeAll(previousCflowEntries);
  165. Object field = getCflowfield(concreteEntry);
  166. // Four routes of interest through this code (did I hear someone say refactor??)
  167. // 1) no state in the cflow - we can use a counter *and* we have seen this pointcut
  168. // before - so use the same counter as before.
  169. // 2) no state in the cflow - we can use a counter, but this is the first time
  170. // we have seen this pointcut, so build the infrastructure.
  171. // 3) state in the cflow - we need to use a stack *and* we have seen this pointcut
  172. // before - so share the stack.
  173. // 4) state in the cflow - we need to use a stack, but this is the first time
  174. // we have seen this pointcut, so build the infrastructure.
  175. if (freeVars.length == 0) { // No state, so don't use a stack, use a counter.
  176. ResolvedMember localCflowField = null;
  177. // Check if we have already got a counter for this cflow pointcut
  178. if (field != null) {
  179. localCflowField = (ResolvedMember)field; // Use the one we already have
  180. } else {
  181. // Create a counter field in the aspect
  182. localCflowField = new ResolvedMember(Member.FIELD,concreteAspect,Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  183. NameMangler.cflowCounter(xcut),TypeX.forName(NameMangler.CFLOW_COUNTER_TYPE).getSignature());
  184. // Create type munger to add field to the aspect
  185. concreteAspect.crosscuttingMembers.addTypeMunger(world.makeCflowCounterFieldAdder(localCflowField));
  186. // Create shadow munger to push stuff onto the stack
  187. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  188. Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars.length,innerCflowEntries,inAspect));
  189. putCflowfield(concreteEntry,localCflowField); // Remember it
  190. }
  191. Pointcut ret = new ConcreteCflowPointcut(localCflowField, null,true);
  192. ret.copyLocationFrom(this);
  193. return ret;
  194. } else {
  195. List slots = new ArrayList();
  196. for (int i=0, len=freeVars.length; i < len; i++) {
  197. int freeVar = freeVars[i];
  198. // we don't need to keep state that isn't actually exposed to advice
  199. //??? this means that we will store some state that we won't actually use, optimize this later
  200. if (!bindings.hasKey(freeVar)) continue;
  201. int formalIndex = bindings.get(freeVar);
  202. ResolvedTypeX formalType =
  203. bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
  204. ConcreteCflowPointcut.Slot slot =
  205. new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
  206. slots.add(slot);
  207. }
  208. ResolvedMember localCflowField = null;
  209. if (field != null) {
  210. localCflowField = (ResolvedMember)field;
  211. } else {
  212. localCflowField = new ResolvedMember(
  213. Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  214. NameMangler.cflowStack(xcut),
  215. TypeX.forName(NameMangler.CFLOW_STACK_TYPE).getSignature());
  216. //System.out.println("adding field to: " + inAspect + " field " + cflowField);
  217. // add field and initializer to inAspect
  218. //XXX and then that info above needs to be mapped down here to help with
  219. //XXX getting the exposed state right
  220. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  221. Advice.makeCflowEntry(world, concreteEntry, isBelow, localCflowField, freeVars.length, innerCflowEntries,inAspect));
  222. concreteAspect.crosscuttingMembers.addTypeMunger(
  223. world.makeCflowStackFieldAdder(localCflowField));
  224. putCflowfield(concreteEntry,localCflowField);
  225. }
  226. Pointcut ret = new ConcreteCflowPointcut(localCflowField, slots,false);
  227. ret.copyLocationFrom(this);
  228. return ret;
  229. }
  230. }
  231. public static void clearCaches() {
  232. cflowFields.clear();
  233. cflowBelowFields.clear();
  234. }
  235. private Object getCflowfield(Pointcut pcutkey) {
  236. if (isBelow) {
  237. return cflowBelowFields.get(pcutkey);
  238. } else {
  239. return cflowFields.get(pcutkey);
  240. }
  241. }
  242. private void putCflowfield(Pointcut pcutkey,Object o) {
  243. if (isBelow) {
  244. cflowBelowFields.put(pcutkey,o);
  245. } else {
  246. cflowFields.put(pcutkey,o);
  247. }
  248. }
  249. }