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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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 org.aspectj.bridge.IMessage;
  22. import org.aspectj.util.FileUtil;
  23. import org.aspectj.util.FuzzyBoolean;
  24. import org.aspectj.weaver.Advice;
  25. import org.aspectj.weaver.CrosscuttingMembers;
  26. import org.aspectj.weaver.ISourceContext;
  27. import org.aspectj.weaver.IntMap;
  28. import org.aspectj.weaver.Member;
  29. import org.aspectj.weaver.NameMangler;
  30. import org.aspectj.weaver.ResolvedMember;
  31. import org.aspectj.weaver.ResolvedPointcutDefinition;
  32. import org.aspectj.weaver.ResolvedTypeX;
  33. import org.aspectj.weaver.Shadow;
  34. import org.aspectj.weaver.TypeX;
  35. import org.aspectj.weaver.WeaverMessages;
  36. import org.aspectj.weaver.World;
  37. import org.aspectj.weaver.ast.Test;
  38. public class CflowPointcut extends Pointcut {
  39. private Pointcut entry; // The pointcut inside the cflow() that represents the 'entry' point
  40. private boolean isBelow;// Is this cflowbelow?
  41. private int[] freeVars;
  42. private static Hashtable cflowFields = new Hashtable();
  43. private static Hashtable cflowBelowFields = new Hashtable();
  44. /**
  45. * Used to indicate that we're in the context of a cflow when concretizing if's
  46. *
  47. * Will be removed or replaced with something better when we handle this
  48. * as a non-error
  49. */
  50. public static final ResolvedPointcutDefinition CFLOW_MARKER =
  51. new ResolvedPointcutDefinition(null, 0, null, TypeX.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED));
  52. public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) {
  53. // System.err.println("Building cflow pointcut "+entry.toString());
  54. this.entry = entry;
  55. this.isBelow = isBelow;
  56. this.freeVars = freeVars;
  57. }
  58. public FuzzyBoolean fastMatch(FastMatchInfo type) {
  59. return FuzzyBoolean.MAYBE;
  60. }
  61. public FuzzyBoolean match(Shadow shadow) {
  62. //??? this is not maximally efficient
  63. return FuzzyBoolean.MAYBE;
  64. }
  65. public void write(DataOutputStream s) throws IOException {
  66. s.writeByte(Pointcut.CFLOW);
  67. entry.write(s);
  68. s.writeBoolean(isBelow);
  69. FileUtil.writeIntArray(freeVars, s);
  70. writeLocation(s);
  71. }
  72. public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException {
  73. CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s));
  74. ret.readLocation(context, s);
  75. return ret;
  76. }
  77. public void resolveBindings(IScope scope, Bindings bindings) {
  78. if (bindings == null) {
  79. entry.resolveBindings(scope, null);
  80. entry.state = RESOLVED;
  81. freeVars = new int[0];
  82. } else {
  83. //??? for if's sake we might need to be more careful here
  84. Bindings entryBindings = new Bindings(bindings.size());
  85. entry.resolveBindings(scope, entryBindings);
  86. entry.state = RESOLVED;
  87. freeVars = entryBindings.getUsedFormals();
  88. bindings.mergeIn(entryBindings, scope);
  89. }
  90. }
  91. public void resolveBindingsFromRTTI() {
  92. if (entry.state != RESOLVED) {
  93. entry.resolveBindingsFromRTTI();
  94. }
  95. }
  96. public boolean equals(Object other) {
  97. if (!(other instanceof CflowPointcut)) return false;
  98. CflowPointcut o = (CflowPointcut)other;
  99. return o.entry.equals(this.entry) && o.isBelow == this.isBelow;
  100. }
  101. public int hashCode() {
  102. int result = 17;
  103. result = 37*result + entry.hashCode();
  104. result = 37*result + (isBelow ? 0 : 1);
  105. return result;
  106. }
  107. public String toString() {
  108. return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")";
  109. }
  110. public Test findResidue(Shadow shadow, ExposedState state) {
  111. throw new RuntimeException("unimplemented");
  112. }
  113. public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) {
  114. // Enforce rule about which designators are supported in declare
  115. if (isDeclare(bindings.getEnclosingAdvice())) {
  116. inAspect.getWorld().showMessage(IMessage.ERROR,
  117. WeaverMessages.format(WeaverMessages.CFLOW_IN_DECLARE,isBelow?"below":""),
  118. bindings.getEnclosingAdvice().getSourceLocation(), null);
  119. return Pointcut.makeMatchesNothing(Pointcut.CONCRETE);
  120. }
  121. //make this remap from formal positions to arrayIndices
  122. IntMap entryBindings = new IntMap();
  123. for (int i=0, len=freeVars.length; i < len; i++) {
  124. int freeVar = freeVars[i];
  125. //int formalIndex = bindings.get(freeVar);
  126. entryBindings.put(freeVar, i);
  127. }
  128. entryBindings.copyContext(bindings);
  129. //System.out.println(this + " bindings: " + entryBindings);
  130. World world = inAspect.getWorld();
  131. Pointcut concreteEntry;
  132. ResolvedTypeX concreteAspect = bindings.getConcreteAspect();
  133. CrosscuttingMembers xcut = concreteAspect.crosscuttingMembers;
  134. Collection previousCflowEntries = xcut.getCflowEntries();
  135. entryBindings.pushEnclosingDefinition(CFLOW_MARKER);
  136. // This block concretizes the pointcut within the cflow pointcut
  137. try {
  138. concreteEntry = entry.concretize(inAspect, entryBindings);
  139. } finally {
  140. entryBindings.popEnclosingDefinitition();
  141. }
  142. List innerCflowEntries = new ArrayList(xcut.getCflowEntries());
  143. innerCflowEntries.removeAll(previousCflowEntries);
  144. Object field = getCflowfield(concreteEntry);
  145. // Four routes of interest through this code (did I hear someone say refactor??)
  146. // 1) no state in the cflow - we can use a counter *and* we have seen this pointcut
  147. // before - so use the same counter as before.
  148. // 2) no state in the cflow - we can use a counter, but this is the first time
  149. // we have seen this pointcut, so build the infrastructure.
  150. // 3) state in the cflow - we need to use a stack *and* we have seen this pointcut
  151. // before - so share the stack.
  152. // 4) state in the cflow - we need to use a stack, but this is the first time
  153. // we have seen this pointcut, so build the infrastructure.
  154. if (freeVars.length == 0) { // No state, so don't use a stack, use a counter.
  155. ResolvedMember localCflowField = null;
  156. // Check if we have already got a counter for this cflow pointcut
  157. if (field != null) {
  158. localCflowField = (ResolvedMember)field; // Use the one we already have
  159. } else {
  160. // Create a counter field in the aspect
  161. localCflowField = new ResolvedMember(Member.FIELD,concreteAspect,Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  162. NameMangler.cflowCounter(xcut),TypeX.forName(NameMangler.CFLOW_COUNTER_TYPE).getSignature());
  163. // Create type munger to add field to the aspect
  164. concreteAspect.crosscuttingMembers.addTypeMunger(world.makeCflowCounterFieldAdder(localCflowField));
  165. // Create shadow munger to push stuff onto the stack
  166. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  167. Advice.makeCflowEntry(world,concreteEntry,isBelow,localCflowField,freeVars.length,innerCflowEntries,inAspect));
  168. putCflowfield(concreteEntry,localCflowField); // Remember it
  169. }
  170. return new ConcreteCflowPointcut(localCflowField, null,true);
  171. } else {
  172. List slots = new ArrayList();
  173. for (int i=0, len=freeVars.length; i < len; i++) {
  174. int freeVar = freeVars[i];
  175. // we don't need to keep state that isn't actually exposed to advice
  176. //??? this means that we will store some state that we won't actually use, optimize this later
  177. if (!bindings.hasKey(freeVar)) continue;
  178. int formalIndex = bindings.get(freeVar);
  179. ResolvedTypeX formalType =
  180. bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world);
  181. ConcreteCflowPointcut.Slot slot =
  182. new ConcreteCflowPointcut.Slot(formalIndex, formalType, i);
  183. slots.add(slot);
  184. }
  185. ResolvedMember localCflowField = null;
  186. if (field != null) {
  187. localCflowField = (ResolvedMember)field;
  188. } else {
  189. localCflowField = new ResolvedMember(
  190. Member.FIELD, concreteAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL,
  191. NameMangler.cflowStack(xcut),
  192. TypeX.forName(NameMangler.CFLOW_STACK_TYPE).getSignature());
  193. //System.out.println("adding field to: " + inAspect + " field " + cflowField);
  194. // add field and initializer to inAspect
  195. //XXX and then that info above needs to be mapped down here to help with
  196. //XXX getting the exposed state right
  197. concreteAspect.crosscuttingMembers.addConcreteShadowMunger(
  198. Advice.makeCflowEntry(world, concreteEntry, isBelow, localCflowField, freeVars.length, innerCflowEntries,inAspect));
  199. concreteAspect.crosscuttingMembers.addTypeMunger(
  200. world.makeCflowStackFieldAdder(localCflowField));
  201. putCflowfield(concreteEntry,localCflowField);
  202. }
  203. return new ConcreteCflowPointcut(localCflowField, slots,false);
  204. }
  205. }
  206. public static void clearCaches() {
  207. cflowFields.clear();
  208. cflowBelowFields.clear();
  209. }
  210. private Object getCflowfield(Pointcut pcutkey) {
  211. if (isBelow) {
  212. return cflowBelowFields.get(pcutkey);
  213. } else {
  214. return cflowFields.get(pcutkey);
  215. }
  216. }
  217. private void putCflowfield(Pointcut pcutkey,Object o) {
  218. if (isBelow) {
  219. cflowBelowFields.put(pcutkey,o);
  220. } else {
  221. cflowFields.put(pcutkey,o);
  222. }
  223. }
  224. }