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.

CrosscuttingMembers.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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;
  13. import java.util.ArrayList;
  14. import java.util.Collection;
  15. import java.util.HashSet;
  16. import java.util.Hashtable;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Set;
  21. import org.aspectj.weaver.bcel.BcelAdvice;
  22. import org.aspectj.weaver.bcel.BcelMethod;
  23. import org.aspectj.weaver.bcel.BcelTypeMunger;
  24. import org.aspectj.weaver.patterns.Declare;
  25. import org.aspectj.weaver.patterns.DeclareAnnotation;
  26. import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
  27. import org.aspectj.weaver.patterns.DeclareParents;
  28. import org.aspectj.weaver.patterns.DeclarePrecedence;
  29. import org.aspectj.weaver.patterns.DeclareSoft;
  30. import org.aspectj.weaver.patterns.PerClause;
  31. import org.aspectj.weaver.patterns.Pointcut;
  32. import org.aspectj.weaver.patterns.PointcutRewriter;
  33. /**
  34. * This holds on to all members that have an invasive effect outside of
  35. * there own compilation unit. These members need to be all gathered up and in
  36. * a world before any weaving can take place.
  37. *
  38. * They are also important in the compilation process and need to be gathered
  39. * up before the inter-type declaration weaving stage (unsurprisingly).
  40. *
  41. * All members are concrete.
  42. *
  43. * @author Jim Hugunin
  44. */
  45. public class CrosscuttingMembers {
  46. private ResolvedType inAspect;
  47. private World world;
  48. private PerClause perClause;
  49. private List shadowMungers = new ArrayList(4);
  50. private List typeMungers = new ArrayList(4);
  51. private List lateTypeMungers = new ArrayList(0);
  52. private List declareParents = new ArrayList(4);
  53. private List declareSofts = new ArrayList(0);
  54. private List declareDominates = new ArrayList(4);
  55. // These are like declare parents type mungers
  56. private List declareAnnotationsOnType = new ArrayList();
  57. private List declareAnnotationsOnField = new ArrayList();
  58. private List declareAnnotationsOnMethods = new ArrayList(); // includes ctors
  59. private boolean shouldConcretizeIfNeeded = true;
  60. public CrosscuttingMembers(ResolvedType inAspect, boolean shouldConcretizeIfNeeded) {
  61. this.inAspect = inAspect;
  62. this.world = inAspect.getWorld();
  63. this.shouldConcretizeIfNeeded = shouldConcretizeIfNeeded;
  64. }
  65. private Hashtable cflowFields = new Hashtable();
  66. private Hashtable cflowBelowFields = new Hashtable();
  67. // public void addConcreteShadowMungers(Collection c) {
  68. // shadowMungers.addAll(c);
  69. // }
  70. public void addConcreteShadowMunger(ShadowMunger m) {
  71. // assert m is concrete
  72. shadowMungers.add(m);
  73. }
  74. public void addShadowMungers(Collection c) {
  75. for (Iterator i = c.iterator(); i.hasNext(); ) {
  76. addShadowMunger( (ShadowMunger)i.next() );
  77. }
  78. }
  79. private void addShadowMunger(ShadowMunger m) {
  80. if (inAspect.isAbstract()) return; // we don't do mungers for abstract aspects
  81. addConcreteShadowMunger(m.concretize(inAspect, world, perClause));
  82. }
  83. public void addTypeMungers(Collection c) {
  84. typeMungers.addAll(c);
  85. }
  86. public void addTypeMunger(ConcreteTypeMunger m) {
  87. if (m == null) throw new Error("FIXME AV - should not happen or what ?");//return; //???
  88. typeMungers.add(m);
  89. }
  90. public void addLateTypeMungers(Collection c) {
  91. lateTypeMungers.addAll(c);
  92. }
  93. public void addLateTypeMunger(ConcreteTypeMunger m) {
  94. lateTypeMungers.add(m);
  95. }
  96. public void addDeclares(Collection c) {
  97. for (Iterator i = c.iterator(); i.hasNext(); ) {
  98. addDeclare( (Declare)i.next() );
  99. }
  100. }
  101. public void addDeclare(Declare declare) {
  102. // this is not extensible, oh well
  103. if (declare instanceof DeclareErrorOrWarning) {
  104. ShadowMunger m = new Checker((DeclareErrorOrWarning)declare);
  105. m.setDeclaringType(declare.getDeclaringType());
  106. addShadowMunger(m);
  107. } else if (declare instanceof DeclarePrecedence) {
  108. declareDominates.add(declare);
  109. } else if (declare instanceof DeclareParents) {
  110. DeclareParents dp = (DeclareParents)declare;
  111. exposeTypes(dp.getParents().getExactTypes());
  112. declareParents.add(dp);
  113. } else if (declare instanceof DeclareSoft) {
  114. DeclareSoft d = (DeclareSoft)declare;
  115. // Ordered so that during concretization we can check the related munger
  116. ShadowMunger m = Advice.makeSoftener(world, d.getPointcut(), d.getException(),inAspect,d);
  117. m.setDeclaringType(d.getDeclaringType());
  118. Pointcut concretePointcut = d.getPointcut().concretize(inAspect, d.getDeclaringType(), 0,m);
  119. m.pointcut = concretePointcut;
  120. declareSofts.add(new DeclareSoft(d.getException(), concretePointcut));
  121. addConcreteShadowMunger(m);
  122. } else if (declare instanceof DeclareAnnotation) {
  123. // FIXME asc perf Possible Improvement. Investigate why this is called twice in a weave ?
  124. DeclareAnnotation da = (DeclareAnnotation)declare;
  125. if (da.getAspect() == null) da.setAspect(this.inAspect);
  126. if (da.isDeclareAtType()) {
  127. declareAnnotationsOnType.add(da);
  128. } else if (da.isDeclareAtField()) {
  129. declareAnnotationsOnField.add(da);
  130. } else if (da.isDeclareAtMethod() || da.isDeclareAtConstuctor()) {
  131. declareAnnotationsOnMethods.add(da);
  132. }
  133. } else {
  134. throw new RuntimeException("unimplemented");
  135. }
  136. }
  137. public void exposeTypes(Collection typesToExpose) {
  138. for (Iterator i = typesToExpose.iterator(); i.hasNext(); ) {
  139. exposeType((UnresolvedType)i.next());
  140. }
  141. }
  142. public void exposeType(UnresolvedType typeToExpose) {
  143. if (ResolvedType.isMissing(typeToExpose)) return;
  144. if (typeToExpose.isParameterizedType() || typeToExpose.isRawType()) {
  145. if (typeToExpose instanceof ResolvedType) {
  146. typeToExpose = ((ResolvedType)typeToExpose).getGenericType();
  147. } else {
  148. typeToExpose = UnresolvedType.forSignature(typeToExpose.getErasureSignature());
  149. }
  150. }
  151. // Check we haven't already got a munger for this:
  152. String signatureToLookFor = typeToExpose.getSignature();
  153. for (Iterator iterator = typeMungers.iterator(); iterator.hasNext();) {
  154. ConcreteTypeMunger cTM = (ConcreteTypeMunger) iterator.next();
  155. ResolvedTypeMunger rTM = cTM.getMunger();
  156. if (rTM!=null && rTM instanceof ExposeTypeMunger) {
  157. String exposedType = ((ExposeTypeMunger)rTM).getExposedTypeSignature();
  158. if (exposedType.equals(signatureToLookFor)) return; // dont need to bother
  159. }
  160. }
  161. addTypeMunger(world.concreteTypeMunger(new ExposeTypeMunger(typeToExpose), inAspect));
  162. // ResolvedMember member = new ResolvedMemberImpl(
  163. // Member.STATIC_INITIALIZATION, typeToExpose, 0, ResolvedType.VOID, "<clinit>", UnresolvedType.NONE);
  164. // addTypeMunger(world.concreteTypeMunger(
  165. // new PrivilegedAccessMunger(member), inAspect));
  166. }
  167. public void addPrivilegedAccesses(Collection accessedMembers) {
  168. for (Iterator i = accessedMembers.iterator(); i.hasNext(); ) {
  169. addPrivilegedAccess( (ResolvedMember)i.next() );
  170. }
  171. }
  172. private void addPrivilegedAccess(ResolvedMember member) {
  173. //System.err.println("add priv access: " + member);
  174. addTypeMunger(world.concreteTypeMunger(new PrivilegedAccessMunger(member), inAspect));
  175. }
  176. public Collection getCflowEntries() {
  177. ArrayList ret = new ArrayList();
  178. for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
  179. ShadowMunger m = (ShadowMunger)i.next();
  180. if (m instanceof Advice) {
  181. Advice a = (Advice)m;
  182. if (a.getKind().isCflow()) {
  183. ret.add(a);
  184. }
  185. }
  186. }
  187. return ret;
  188. }
  189. /**
  190. * Updates the records if something has changed. This is called at most twice, firstly
  191. * whilst collecting ITDs and declares. At this point the CrosscuttingMembers we're
  192. * comparing ourselves with doesn't know about shadowmungers. Therefore a straight comparison
  193. * with the existing list of shadowmungers would return that something has changed
  194. * even though it might not have, so in this first round we ignore the shadowMungers.
  195. * The second time this is called is whilst we're preparing to weave. At this point
  196. * we know everything in the system and so we're able to compare the shadowMunger list.
  197. * (see bug 129163)
  198. *
  199. * @param other
  200. * @param careAboutShadowMungers
  201. * @return true if something has changed since the last time this method was
  202. * called, false otherwise
  203. */
  204. public boolean replaceWith(CrosscuttingMembers other,boolean careAboutShadowMungers) {
  205. boolean changed = false;
  206. if (careAboutShadowMungers) {
  207. if (perClause == null || !perClause.equals(other.perClause)) {
  208. changed = true;
  209. perClause = other.perClause;
  210. }
  211. }
  212. //XXX all of the below should be set equality rather than list equality
  213. //System.err.println("old: " + shadowMungers + " new: " + other.shadowMungers);
  214. if (careAboutShadowMungers) {
  215. // bug 129163: use set equality rather than list equality
  216. Set theseShadowMungers = new HashSet();
  217. Set theseInlinedAroundMungers = new HashSet();
  218. for (Iterator iter = shadowMungers.iterator(); iter
  219. .hasNext();) {
  220. ShadowMunger munger = (ShadowMunger) iter.next();
  221. if (munger instanceof Advice) {
  222. Advice adviceMunger = (Advice)munger;
  223. // bug 154054: if we're around advice that has been inlined
  224. // then we need to do more checking than existing equals
  225. // methods allow
  226. if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
  227. theseInlinedAroundMungers.add(adviceMunger);
  228. } else {
  229. theseShadowMungers.add(adviceMunger);
  230. }
  231. } else {
  232. theseShadowMungers.add(munger);
  233. }
  234. }
  235. Set tempSet = new HashSet();
  236. tempSet.addAll(other.shadowMungers);
  237. Set otherShadowMungers = new HashSet();
  238. Set otherInlinedAroundMungers = new HashSet();
  239. for (Iterator iter = tempSet.iterator(); iter.hasNext();) {
  240. ShadowMunger munger = (ShadowMunger) iter.next();
  241. if (munger instanceof Advice) {
  242. Advice adviceMunger = (Advice)munger;
  243. // bug 154054: if we're around advice that has been inlined
  244. // then we need to do more checking than existing equals
  245. // methods allow
  246. if (!world.isXnoInline() && adviceMunger.getKind().equals(AdviceKind.Around)) {
  247. otherInlinedAroundMungers.add(rewritePointcutInMunger(adviceMunger));
  248. } else {
  249. otherShadowMungers.add(rewritePointcutInMunger(adviceMunger));
  250. }
  251. } else {
  252. otherShadowMungers.add(rewritePointcutInMunger(munger));
  253. }
  254. }
  255. if (!theseShadowMungers.equals(otherShadowMungers)) {
  256. changed = true;
  257. }
  258. if (!equivalent(theseInlinedAroundMungers,otherInlinedAroundMungers)) {
  259. changed = true;
  260. }
  261. // bug 158573 - if there are no changes then preserve whether
  262. // or not a particular shadowMunger has matched something.
  263. if (!changed) {
  264. for (Iterator iter = shadowMungers.iterator(); iter
  265. .hasNext();) {
  266. ShadowMunger munger = (ShadowMunger) iter.next();
  267. int i = other.shadowMungers.indexOf(munger);
  268. ShadowMunger otherMunger = (ShadowMunger) other.shadowMungers.get(i);
  269. if (munger instanceof BcelAdvice) {
  270. ((BcelAdvice)otherMunger).setHasMatchedSomething(((BcelAdvice)munger).hasMatchedSomething());
  271. }
  272. }
  273. }
  274. // replace the existing list of shadowmungers with the
  275. // new ones in case anything like the sourcelocation has
  276. // changed, however, don't want this flagged as a change
  277. // which will force a full build - bug 134541
  278. shadowMungers = other.shadowMungers;
  279. }
  280. // bug 129163: use set equality rather than list equality and
  281. // if we dont care about shadow mungers then ignore those
  282. // typeMungers which are created to help with the implementation
  283. // of shadowMungers
  284. Set theseTypeMungers = new HashSet();
  285. Set otherTypeMungers = new HashSet();
  286. if (!careAboutShadowMungers) {
  287. for (Iterator iter = typeMungers.iterator(); iter.hasNext();) {
  288. Object o = iter.next();
  289. if (o instanceof BcelTypeMunger) {
  290. BcelTypeMunger typeMunger = (BcelTypeMunger) o;
  291. if (!typeMunger.existsToSupportShadowMunging()) {
  292. theseTypeMungers.add(typeMunger);
  293. }
  294. } else {
  295. theseTypeMungers.add(o);
  296. }
  297. }
  298. for (Iterator iter = other.typeMungers.iterator(); iter.hasNext();) {
  299. Object o = iter.next();
  300. if (o instanceof BcelTypeMunger) {
  301. BcelTypeMunger typeMunger = (BcelTypeMunger) o;
  302. if (!typeMunger.existsToSupportShadowMunging()) {
  303. otherTypeMungers.add(typeMunger);
  304. }
  305. } else {
  306. otherTypeMungers.add(o);
  307. }
  308. }
  309. } else {
  310. theseTypeMungers.addAll(typeMungers);
  311. otherTypeMungers.addAll(other.typeMungers);
  312. }
  313. // initial go at equivalence logic rather than set compare (see pr133532)
  314. // if (theseTypeMungers.size()!=otherTypeMungers.size()) {
  315. // changed = true;
  316. // typeMungers = other.typeMungers;
  317. // } else {
  318. // boolean foundInequality=false;
  319. // for (Iterator iter = theseTypeMungers.iterator(); iter.hasNext() && !foundInequality;) {
  320. // Object thisOne = (Object) iter.next();
  321. // boolean foundInOtherSet = false;
  322. // for (Iterator iterator = otherTypeMungers.iterator(); iterator.hasNext();) {
  323. // Object otherOne = (Object) iterator.next();
  324. // if (thisOne instanceof ConcreteTypeMunger && otherOne instanceof ConcreteTypeMunger) {
  325. // if (((ConcreteTypeMunger)thisOne).equivalentTo(otherOne)) {
  326. // foundInOtherSet=true;
  327. // } else if (thisOne.equals(otherOne)) {
  328. // foundInOtherSet=true;
  329. // }
  330. // } else {
  331. // if (thisOne.equals(otherOne)) {
  332. // foundInOtherSet=true;
  333. // }
  334. // }
  335. // }
  336. // if (!foundInOtherSet) foundInequality=true;
  337. // }
  338. // if (foundInequality) {
  339. // changed = true;
  340. // typeMungers = other.typeMungers;
  341. //// } else {
  342. //// typeMungers = other.typeMungers;
  343. // }
  344. // }
  345. if (!theseTypeMungers.equals(otherTypeMungers)) {
  346. changed = true;
  347. typeMungers = other.typeMungers;
  348. }
  349. if (!lateTypeMungers.equals(other.lateTypeMungers)) {
  350. changed = true;
  351. lateTypeMungers = other.lateTypeMungers;
  352. }
  353. if (!declareDominates.equals(other.declareDominates)) {
  354. changed = true;
  355. declareDominates = other.declareDominates;
  356. }
  357. if (!declareParents.equals(other.declareParents)) {
  358. changed = true;
  359. declareParents = other.declareParents;
  360. }
  361. if (!declareSofts.equals(other.declareSofts)) {
  362. changed = true;
  363. declareSofts = other.declareSofts;
  364. }
  365. // DECAT for when attempting to replace an aspect
  366. if (!declareAnnotationsOnType.equals(other.declareAnnotationsOnType)) {
  367. changed = true;
  368. declareAnnotationsOnType = other.declareAnnotationsOnType;
  369. }
  370. if (!declareAnnotationsOnField.equals(other.declareAnnotationsOnField)) {
  371. changed = true;
  372. declareAnnotationsOnField = other.declareAnnotationsOnField;
  373. }
  374. if (!declareAnnotationsOnMethods.equals(other.declareAnnotationsOnMethods)) {
  375. changed = true;
  376. declareAnnotationsOnMethods = other.declareAnnotationsOnMethods;
  377. }
  378. return changed;
  379. }
  380. private boolean equivalent(Set theseInlinedAroundMungers, Set otherInlinedAroundMungers) {
  381. if (theseInlinedAroundMungers.size() != otherInlinedAroundMungers.size()) {
  382. return false;
  383. }
  384. for (Iterator iter = theseInlinedAroundMungers.iterator(); iter.hasNext();) {
  385. Advice thisAdvice = (Advice) iter.next();
  386. boolean foundIt = false;
  387. for (Iterator iterator = otherInlinedAroundMungers.iterator(); iterator.hasNext();) {
  388. Advice otherAdvice = (Advice) iterator.next();
  389. if (thisAdvice.equals(otherAdvice)) {
  390. if(thisAdvice.getSignature() instanceof BcelMethod) {
  391. if (((BcelMethod)thisAdvice.getSignature())
  392. .isEquivalentTo(otherAdvice.getSignature()) ) {
  393. foundIt = true;
  394. continue;
  395. }
  396. }
  397. return false;
  398. }
  399. }
  400. if (!foundIt) {
  401. return false;
  402. }
  403. }
  404. return true;
  405. }
  406. private ShadowMunger rewritePointcutInMunger(ShadowMunger munger) {
  407. PointcutRewriter pr = new PointcutRewriter();
  408. Pointcut p = munger.getPointcut();
  409. Pointcut newP = pr.rewrite(p);
  410. if (p.m_ignoreUnboundBindingForNames.length!=0) {// *sigh* dirty fix for dirty hacky implementation pr149305
  411. newP.m_ignoreUnboundBindingForNames = p.m_ignoreUnboundBindingForNames;
  412. }
  413. munger.setPointcut(newP);
  414. return munger;
  415. }
  416. public void setPerClause(PerClause perClause) {
  417. if (this.shouldConcretizeIfNeeded) {
  418. this.perClause = perClause.concretize(inAspect);
  419. } else {
  420. this.perClause = perClause;
  421. }
  422. }
  423. public List getDeclareDominates() {
  424. return declareDominates;
  425. }
  426. public List getDeclareParents() {
  427. return declareParents;
  428. }
  429. public List getDeclareSofts() {
  430. return declareSofts;
  431. }
  432. public List getShadowMungers() {
  433. return shadowMungers;
  434. }
  435. public List getTypeMungers() {
  436. return typeMungers;
  437. }
  438. public List getLateTypeMungers() {
  439. return lateTypeMungers;
  440. }
  441. public List getDeclareAnnotationOnTypes() {
  442. return declareAnnotationsOnType;
  443. }
  444. public List getDeclareAnnotationOnFields() {
  445. return declareAnnotationsOnField;
  446. }
  447. /**
  448. * includes declare @method and @constructor
  449. */
  450. public List getDeclareAnnotationOnMethods() {
  451. return declareAnnotationsOnMethods;
  452. }
  453. public Map getCflowBelowFields() {
  454. return cflowBelowFields;
  455. }
  456. public Map getCflowFields() {
  457. return cflowFields;
  458. }
  459. public void clearCaches() {
  460. cflowFields.clear();
  461. cflowBelowFields.clear();
  462. }
  463. }