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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  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.io.DataInputStream;
  14. import java.io.File;
  15. import java.io.IOException;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.HashSet;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import java.util.Set;
  22. import org.aspectj.asm.IRelationship;
  23. import org.aspectj.bridge.IMessage;
  24. import org.aspectj.bridge.ISourceLocation;
  25. import org.aspectj.bridge.Message;
  26. import org.aspectj.bridge.MessageUtil;
  27. import org.aspectj.bridge.WeaveMessage;
  28. import org.aspectj.lang.JoinPoint;
  29. import org.aspectj.util.PartialOrder;
  30. import org.aspectj.util.TypeSafeEnum;
  31. import org.aspectj.weaver.ast.Var;
  32. import org.aspectj.weaver.bcel.BcelAdvice;
  33. /*
  34. * The superclass of anything representing a the shadow of a join point. A shadow represents
  35. * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind
  36. * and a signature.
  37. */
  38. public abstract class Shadow {
  39. // every Shadow has a unique id, doesn't matter if it wraps...
  40. private static int nextShadowID = 100; // easier to spot than zero.
  41. private final Kind kind;
  42. private final Member signature;
  43. private Member matchingSignature;
  44. private ResolvedMember resolvedSignature;
  45. protected final Shadow enclosingShadow;
  46. protected List mungers = Collections.EMPTY_LIST;
  47. public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
  48. // ----
  49. protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
  50. this.kind = kind;
  51. this.signature = signature;
  52. this.enclosingShadow = enclosingShadow;
  53. }
  54. // ----
  55. public abstract World getIWorld();
  56. public List /*ShadowMunger*/ getMungers() {
  57. return mungers;
  58. }
  59. /**
  60. * could this(*) pcd ever match
  61. */
  62. public final boolean hasThis() {
  63. if (getKind().neverHasThis()) {
  64. return false;
  65. } else if (getKind().isEnclosingKind()) {
  66. return !getSignature().isStatic();
  67. } else if (enclosingShadow == null) {
  68. return false;
  69. } else {
  70. return enclosingShadow.hasThis();
  71. }
  72. }
  73. /**
  74. * the type of the this object here
  75. *
  76. * @throws IllegalStateException if there is no this here
  77. */
  78. public final UnresolvedType getThisType() {
  79. if (!hasThis()) throw new IllegalStateException("no this");
  80. if (getKind().isEnclosingKind()) {
  81. return getSignature().getDeclaringType();
  82. } else {
  83. return enclosingShadow.getThisType();
  84. }
  85. }
  86. /**
  87. * a var referencing this
  88. *
  89. * @throws IllegalStateException if there is no target here
  90. */
  91. public abstract Var getThisVar();
  92. /**
  93. * could target(*) pcd ever match
  94. */
  95. public final boolean hasTarget() {
  96. if (getKind().neverHasTarget()) {
  97. return false;
  98. } else if (getKind().isTargetSameAsThis()) {
  99. return hasThis();
  100. } else {
  101. return !getSignature().isStatic();
  102. }
  103. }
  104. /**
  105. * the type of the target object here
  106. *
  107. * @throws IllegalStateException if there is no target here
  108. */
  109. public final UnresolvedType getTargetType() {
  110. if (!hasTarget()) throw new IllegalStateException("no target");
  111. return getSignature().getDeclaringType();
  112. }
  113. /**
  114. * a var referencing the target
  115. *
  116. * @throws IllegalStateException if there is no target here
  117. */
  118. public abstract Var getTargetVar();
  119. public UnresolvedType[] getArgTypes() {
  120. if (getKind() == FieldSet) return new UnresolvedType[] { getSignature().getReturnType() };
  121. return getSignature().getParameterTypes();
  122. }
  123. public boolean isShadowForArrayConstructionJoinpoint() {
  124. return (getKind()==ConstructorCall && signature.getDeclaringType().isArray());
  125. }
  126. public boolean isShadowForMonitor() {
  127. return (getKind()==SynchronizationLock || getKind()==SynchronizationUnlock);
  128. }
  129. // will return the right length array of ints depending on how many dimensions the array has
  130. public ResolvedType[] getArgumentTypesForArrayConstructionShadow() {
  131. String s = signature.getDeclaringType().getSignature();
  132. int pos = s.indexOf("[");
  133. int dims = 1;
  134. while (pos<s.length()) {
  135. pos++;
  136. if (pos<s.length()) dims+=(s.charAt(pos)=='['?1:0);
  137. }
  138. if (dims==1) return new ResolvedType[]{ResolvedType.INT};
  139. ResolvedType[] someInts = new ResolvedType[dims];
  140. for (int i = 0; i < dims;i++) someInts[i] = ResolvedType.INT;
  141. return someInts;
  142. }
  143. public UnresolvedType[] getGenericArgTypes() {
  144. if (isShadowForArrayConstructionJoinpoint()) {
  145. return getArgumentTypesForArrayConstructionShadow();
  146. }
  147. if (isShadowForMonitor()) {
  148. return UnresolvedType.ARRAY_WITH_JUST_OBJECT;
  149. }
  150. if (getKind() == FieldSet) return new UnresolvedType[] { getResolvedSignature().getGenericReturnType() };
  151. return getResolvedSignature().getGenericParameterTypes();
  152. }
  153. public UnresolvedType getArgType(int arg) {
  154. if (getKind() == FieldSet) return getSignature().getReturnType();
  155. return getSignature().getParameterTypes()[arg];
  156. }
  157. public int getArgCount() {
  158. if (getKind() == FieldSet) return 1;
  159. return getSignature()
  160. .getParameterTypes().length;
  161. }
  162. public abstract UnresolvedType getEnclosingType();
  163. public abstract Var getArgVar(int i);
  164. public abstract Var getThisJoinPointVar();
  165. public abstract Var getThisJoinPointStaticPartVar();
  166. public abstract Var getThisEnclosingJoinPointStaticPartVar();
  167. // annotation variables
  168. public abstract Var getKindedAnnotationVar(UnresolvedType forAnnotationType);
  169. public abstract Var getWithinAnnotationVar(UnresolvedType forAnnotationType);
  170. public abstract Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType);
  171. public abstract Var getThisAnnotationVar(UnresolvedType forAnnotationType);
  172. public abstract Var getTargetAnnotationVar(UnresolvedType forAnnotationType);
  173. public abstract Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType);
  174. public abstract Member getEnclosingCodeSignature();
  175. /** returns the kind of shadow this is, representing what happens under this shadow
  176. */
  177. public Kind getKind() {
  178. return kind;
  179. }
  180. /** returns the signature of the thing under this shadow
  181. */
  182. public Member getSignature() {
  183. return signature;
  184. }
  185. /**
  186. * returns the signature of the thing under this shadow, with
  187. * any synthetic arguments removed
  188. */
  189. public Member getMatchingSignature() {
  190. return matchingSignature != null ? matchingSignature : signature;
  191. }
  192. public void setMatchingSignature(Member member) {
  193. this.matchingSignature = member;
  194. }
  195. /**
  196. * returns the resolved signature of the thing under this shadow
  197. *
  198. */
  199. public ResolvedMember getResolvedSignature() {
  200. if (resolvedSignature == null) {
  201. resolvedSignature = signature.resolve(getIWorld());
  202. }
  203. return resolvedSignature;
  204. }
  205. public UnresolvedType getReturnType() {
  206. if (kind == ConstructorCall) return getSignature().getDeclaringType();
  207. else if (kind == FieldSet) return ResolvedType.VOID;
  208. else if (kind == SynchronizationLock || kind==SynchronizationUnlock) return ResolvedType.VOID;
  209. return getResolvedSignature().getGenericReturnType();
  210. }
  211. /**
  212. * These names are the ones that will be returned by thisJoinPoint.getKind()
  213. * Those need to be documented somewhere
  214. */
  215. public static final Kind MethodCall = new Kind(JoinPoint.METHOD_CALL, 1, true);
  216. public static final Kind ConstructorCall = new Kind(JoinPoint.CONSTRUCTOR_CALL, 2, true);
  217. public static final Kind MethodExecution = new Kind(JoinPoint.METHOD_EXECUTION, 3, false);
  218. public static final Kind ConstructorExecution = new Kind(JoinPoint.CONSTRUCTOR_EXECUTION, 4, false);
  219. public static final Kind FieldGet = new Kind(JoinPoint.FIELD_GET, 5, true);
  220. public static final Kind FieldSet = new Kind(JoinPoint.FIELD_SET, 6, true);
  221. public static final Kind StaticInitialization = new Kind(JoinPoint.STATICINITIALIZATION, 7, false);
  222. public static final Kind PreInitialization = new Kind(JoinPoint.PREINITIALIZATION, 8, false);
  223. public static final Kind AdviceExecution = new Kind(JoinPoint.ADVICE_EXECUTION, 9, false);
  224. public static final Kind Initialization = new Kind(JoinPoint.INITIALIZATION, 10, false);
  225. public static final Kind ExceptionHandler = new Kind(JoinPoint.EXCEPTION_HANDLER, 11, true);
  226. public static final Kind SynchronizationLock = new Kind(JoinPoint.SYNCHRONIZATION_LOCK, 12, true);
  227. public static final Kind SynchronizationUnlock= new Kind(JoinPoint.SYNCHRONIZATION_UNLOCK, 13, true);
  228. // Bits here are 1<<(Kind.getKey()) - and unfortunately keys didn't start at zero so bits here start at 2
  229. public static final int MethodCallBit = 0x002;
  230. public static final int ConstructorCallBit = 0x004;
  231. public static final int MethodExecutionBit = 0x008;
  232. public static final int ConstructorExecutionBit = 0x010;
  233. public static final int FieldGetBit = 0x020;
  234. public static final int FieldSetBit = 0x040;
  235. public static final int StaticInitializationBit = 0x080;
  236. public static final int PreInitializationBit = 0x100;
  237. public static final int AdviceExecutionBit = 0x200;
  238. public static final int InitializationBit = 0x400;
  239. public static final int ExceptionHandlerBit = 0x800;
  240. public static final int SynchronizationLockBit =0x1000;
  241. public static final int SynchronizationUnlockBit=0x2000;
  242. public static final int MAX_SHADOW_KIND = 13;
  243. public static final Kind[] SHADOW_KINDS = new Kind[] {
  244. MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
  245. FieldGet, FieldSet, StaticInitialization, PreInitialization,
  246. AdviceExecution, Initialization, ExceptionHandler,SynchronizationLock,SynchronizationUnlock
  247. };
  248. public static final int ALL_SHADOW_KINDS_BITS;
  249. public static final int NO_SHADOW_KINDS_BITS;
  250. static {
  251. ALL_SHADOW_KINDS_BITS = 0x3ffe;
  252. NO_SHADOW_KINDS_BITS = 0x0000;
  253. }
  254. /**
  255. * Return count of how many bits set in the supplied parameter.
  256. */
  257. public static int howMany(int i) {
  258. int count = 0;
  259. for (int j = 0; j <SHADOW_KINDS.length; j++) {
  260. if ((i&SHADOW_KINDS[j].bit)!=0) count++;
  261. }
  262. return count;
  263. }
  264. /** A type-safe enum representing the kind of shadows
  265. */
  266. public static final class Kind extends TypeSafeEnum {
  267. // private boolean argsOnStack; //XXX unused
  268. public int bit;
  269. public Kind(String name, int key, boolean argsOnStack) {
  270. super(name, key);
  271. bit = 1<<key;
  272. // this.argsOnStack = argsOnStack;
  273. }
  274. public String toLegalJavaIdentifier() {
  275. return getName().replace('-', '_');
  276. }
  277. public boolean argsOnStack() {
  278. return !isTargetSameAsThis();
  279. }
  280. // !!! this is false for handlers!
  281. public boolean allowsExtraction() {
  282. return true;
  283. }
  284. public boolean isSet(int i) {
  285. return (i&bit)!=0;
  286. }
  287. // XXX revisit along with removal of priorities
  288. public boolean hasHighPriorityExceptions() {
  289. return !isTargetSameAsThis();
  290. }
  291. private final static int hasReturnValueFlag =
  292. MethodCallBit | ConstructorCallBit | MethodExecutionBit | FieldGetBit | AdviceExecutionBit;
  293. /**
  294. * These shadow kinds have return values that can be bound in
  295. * after returning(Dooberry doo) advice.
  296. * @return
  297. */
  298. public boolean hasReturnValue() {
  299. return (bit&hasReturnValueFlag)!=0;
  300. }
  301. private final static int isEnclosingKindFlag =
  302. MethodExecutionBit | ConstructorExecutionBit | AdviceExecutionBit | StaticInitializationBit | InitializationBit;
  303. /**
  304. * These are all the shadows that contains other shadows within them and
  305. * are often directly associated with methods.
  306. */
  307. public boolean isEnclosingKind() {
  308. return (bit&isEnclosingKindFlag)!=0;
  309. }
  310. private final static int isTargetSameAsThisFlag =
  311. MethodExecutionBit | ConstructorExecutionBit | StaticInitializationBit |
  312. PreInitializationBit | AdviceExecutionBit | InitializationBit;
  313. public boolean isTargetSameAsThis() {
  314. return (bit&isTargetSameAsThisFlag)!=0;
  315. }
  316. private final static int neverHasTargetFlag=
  317. ConstructorCallBit | ExceptionHandlerBit | PreInitializationBit | StaticInitializationBit | SynchronizationLockBit | SynchronizationUnlockBit;
  318. public boolean neverHasTarget() {
  319. return (bit&neverHasTargetFlag)!=0;
  320. }
  321. private final static int neverHasThisFlag=
  322. PreInitializationBit | StaticInitializationBit;
  323. public boolean neverHasThis() {
  324. return (bit&neverHasThisFlag)!=0;
  325. }
  326. public String getSimpleName() {
  327. int dash = getName().lastIndexOf('-');
  328. if (dash == -1) return getName();
  329. else return getName().substring(dash+1);
  330. }
  331. public static Kind read(DataInputStream s) throws IOException {
  332. int key = s.readByte();
  333. switch(key) {
  334. case 1: return MethodCall;
  335. case 2: return ConstructorCall;
  336. case 3: return MethodExecution;
  337. case 4: return ConstructorExecution;
  338. case 5: return FieldGet;
  339. case 6: return FieldSet;
  340. case 7: return StaticInitialization;
  341. case 8: return PreInitialization;
  342. case 9: return AdviceExecution;
  343. case 10: return Initialization;
  344. case 11: return ExceptionHandler;
  345. case 12: return SynchronizationLock;
  346. case 13: return SynchronizationUnlock;
  347. }
  348. throw new BCException("unknown kind: " + key);
  349. }
  350. }
  351. /**
  352. * Only does the check if the munger requires it (@AJ aspects don't)
  353. *
  354. * @param munger
  355. * @return
  356. */
  357. protected boolean checkMunger(ShadowMunger munger) {
  358. if (munger.mustCheckExceptions()) {
  359. for (Iterator i = munger.getThrownExceptions().iterator(); i.hasNext(); ) {
  360. if (!checkCanThrow(munger, (ResolvedType)i.next() )) return false;
  361. }
  362. }
  363. return true;
  364. }
  365. protected boolean checkCanThrow(ShadowMunger munger, ResolvedType resolvedTypeX) {
  366. if (getKind() == ExceptionHandler) {
  367. //XXX much too lenient rules here, need to walk up exception handlers
  368. return true;
  369. }
  370. if (!isDeclaredException(resolvedTypeX, getSignature())) {
  371. getIWorld().showMessage(IMessage.ERROR,
  372. WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED,resolvedTypeX,this), // from advice in \'" + munger. + "\'",
  373. getSourceLocation(), munger.getSourceLocation());
  374. }
  375. return true;
  376. }
  377. private boolean isDeclaredException(
  378. ResolvedType resolvedTypeX,
  379. Member member)
  380. {
  381. ResolvedType[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
  382. for (int i=0, len=excs.length; i < len; i++) {
  383. if (excs[i].isAssignableFrom(resolvedTypeX)) return true;
  384. }
  385. return false;
  386. }
  387. public void addMunger(ShadowMunger munger) {
  388. if (checkMunger(munger)) {
  389. if (mungers==Collections.EMPTY_LIST) mungers = new ArrayList();
  390. this.mungers.add(munger);
  391. }
  392. }
  393. public final void implement() {
  394. sortMungers();
  395. if (mungers == null) return;
  396. prepareForMungers();
  397. implementMungers();
  398. }
  399. private void sortMungers() {
  400. List sorted = PartialOrder.sort(mungers);
  401. // Bunch of code to work out whether to report xlints for advice that isn't ordered at this Joinpoint
  402. possiblyReportUnorderedAdvice(sorted);
  403. if (sorted == null) {
  404. // this means that we have circular dependencies
  405. for (Iterator i = mungers.iterator(); i.hasNext(); ) {
  406. ShadowMunger m = (ShadowMunger)i.next();
  407. getIWorld().getMessageHandler().handleMessage(
  408. MessageUtil.error(
  409. WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY,this), m.getSourceLocation()));
  410. }
  411. }
  412. mungers = sorted;
  413. }
  414. // not quite optimal... but the xlint is ignore by default
  415. private void possiblyReportUnorderedAdvice(List sorted) {
  416. if (sorted!=null && getIWorld().getLint().unorderedAdviceAtShadow.isEnabled() && mungers.size()>1) {
  417. // Stores a set of strings of the form 'aspect1:aspect2' which indicates there is no
  418. // precedence specified between the two aspects at this shadow.
  419. Set clashingAspects = new HashSet();
  420. int max = mungers.size();
  421. // Compare every pair of advice mungers
  422. for (int i = max-1; i >=0; i--) {
  423. for (int j=0; j<i; j++) {
  424. Object a = mungers.get(i);
  425. Object b = mungers.get(j);
  426. // Make sure they are the right type
  427. if (a instanceof BcelAdvice && b instanceof BcelAdvice) {
  428. BcelAdvice adviceA = (BcelAdvice)a;
  429. BcelAdvice adviceB = (BcelAdvice)b;
  430. if (!adviceA.concreteAspect.equals(adviceB.concreteAspect)) {
  431. AdviceKind adviceKindA = adviceA.getKind();
  432. AdviceKind adviceKindB = adviceB.getKind();
  433. // make sure they are the nice ones (<6) and not any synthetic advice ones we
  434. // create to support other features of the language.
  435. if (adviceKindA.getKey()<(byte)6 && adviceKindB.getKey()<(byte)6 &&
  436. adviceKindA.getPrecedence() == adviceKindB.getPrecedence()) {
  437. // Ask the world if it knows about precedence between these
  438. Integer order = getIWorld().getPrecedenceIfAny(
  439. adviceA.concreteAspect,
  440. adviceB.concreteAspect);
  441. if (order!=null &&
  442. order.equals(new Integer(0))) {
  443. String key = adviceA.getDeclaringAspect()+":"+adviceB.getDeclaringAspect();
  444. String possibleExistingKey = adviceB.getDeclaringAspect()+":"+adviceA.getDeclaringAspect();
  445. if (!clashingAspects.contains(possibleExistingKey)) clashingAspects.add(key);
  446. }
  447. }
  448. }
  449. }
  450. }
  451. }
  452. for (Iterator iter = clashingAspects.iterator(); iter.hasNext();) {
  453. String element = (String) iter.next();
  454. String aspect1 = element.substring(0,element.indexOf(":"));
  455. String aspect2 = element.substring(element.indexOf(":")+1);
  456. getIWorld().getLint().unorderedAdviceAtShadow.signal(
  457. new String[]{this.toString(),aspect1,aspect2},
  458. this.getSourceLocation(),null);
  459. }
  460. }
  461. }
  462. /** Prepare the shadow for implementation. After this is done, the shadow
  463. * should be in such a position that each munger simply needs to be implemented.
  464. */
  465. protected void prepareForMungers() {
  466. throw new RuntimeException("Generic shadows cannot be prepared");
  467. }
  468. /*
  469. * Ensure we report a nice source location - particular in the case
  470. * where the source info is missing (binary weave).
  471. */
  472. private String beautifyLocation(ISourceLocation isl) {
  473. StringBuffer nice = new StringBuffer();
  474. if (isl==null || isl.getSourceFile()==null || isl.getSourceFile().getName().indexOf("no debug info available")!=-1) {
  475. nice.append("no debug info available");
  476. } else {
  477. // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa
  478. int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
  479. if (takeFrom == -1) {
  480. takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
  481. }
  482. int binary = isl.getSourceFile().getPath().lastIndexOf('!');
  483. if (binary != -1 && binary < takeFrom) {
  484. // we have been woven by a binary aspect
  485. String pathToBinaryLoc = isl.getSourceFile().getPath().substring(0,binary + 1);
  486. if (pathToBinaryLoc.indexOf(".jar") != -1) {
  487. // only want to add the extra info if we're from a jar file
  488. int lastSlash = pathToBinaryLoc.lastIndexOf('/');
  489. if (lastSlash == -1) {
  490. lastSlash = pathToBinaryLoc.lastIndexOf('\\');
  491. }
  492. nice.append(pathToBinaryLoc.substring(lastSlash + 1));
  493. }
  494. }
  495. nice.append(isl.getSourceFile().getPath().substring(takeFrom +1));
  496. if (isl.getLine()!=0) nice.append(":").append(isl.getLine());
  497. // if it's a binary file then also want to give the file name
  498. if (isl.getSourceFileName() != null ) nice.append("(from " + isl.getSourceFileName() + ")");
  499. }
  500. return nice.toString();
  501. }
  502. /*
  503. * Report a message about the advice weave that has occurred. Some messing about
  504. * to make it pretty ! This code is just asking for an NPE to occur ...
  505. */
  506. private void reportWeavingMessage(ShadowMunger munger) {
  507. Advice advice = (Advice)munger;
  508. AdviceKind aKind = advice.getKind();
  509. // Only report on interesting advice kinds ...
  510. if (aKind == null || advice.getConcreteAspect()==null) {
  511. // We suspect someone is programmatically driving the weaver
  512. // (e.g. IdWeaveTestCase in the weaver testcases)
  513. return;
  514. }
  515. if (!( aKind.equals(AdviceKind.Before) ||
  516. aKind.equals(AdviceKind.After) ||
  517. aKind.equals(AdviceKind.AfterReturning) ||
  518. aKind.equals(AdviceKind.AfterThrowing) ||
  519. aKind.equals(AdviceKind.Around) ||
  520. aKind.equals(AdviceKind.Softener))) return;
  521. // synchronized blocks are implemented with multiple monitor_exit instructions in the bytecode
  522. // (one for normal exit from the method, one for abnormal exit), we only want to tell the user
  523. // once we have advised the end of the sync block, even though under the covers we will have
  524. // woven both exit points
  525. if (this.kind==Shadow.SynchronizationUnlock) {
  526. if (advice.lastReportedMonitorExitJoinpointLocation==null) {
  527. // this is the first time through, let's continue...
  528. advice.lastReportedMonitorExitJoinpointLocation = getSourceLocation();
  529. } else {
  530. if (areTheSame(getSourceLocation(),advice.lastReportedMonitorExitJoinpointLocation)) {
  531. // Don't report it again!
  532. advice.lastReportedMonitorExitJoinpointLocation=null;
  533. return;
  534. }
  535. // hmmm, this means some kind of nesting is going on, urgh
  536. advice.lastReportedMonitorExitJoinpointLocation=getSourceLocation();
  537. }
  538. }
  539. String description = advice.getKind().toString();
  540. String advisedType = this.getEnclosingType().getName();
  541. String advisingType= advice.getConcreteAspect().getName();
  542. Message msg = null;
  543. if (advice.getKind().equals(AdviceKind.Softener)) {
  544. msg = WeaveMessage.constructWeavingMessage(
  545. WeaveMessage.WEAVEMESSAGE_SOFTENS,
  546. new String[]{advisedType,beautifyLocation(getSourceLocation()),
  547. advisingType,beautifyLocation(munger.getSourceLocation())},
  548. advisedType,
  549. advisingType);
  550. } else {
  551. boolean runtimeTest = ((BcelAdvice)advice).hasDynamicTests();
  552. String joinPointDescription = this.toString();
  553. msg = WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ADVISES,
  554. new String[]{ joinPointDescription, advisedType, beautifyLocation(getSourceLocation()),
  555. description,
  556. advisingType,beautifyLocation(munger.getSourceLocation()),
  557. (runtimeTest?" [with runtime test]":"")},
  558. advisedType,
  559. advisingType);
  560. // Boolean.toString(runtimeTest)});
  561. }
  562. getIWorld().getMessageHandler().handleMessage(msg);
  563. }
  564. private boolean areTheSame(ISourceLocation locA, ISourceLocation locB) {
  565. if (locA==null) return locB==null;
  566. if (locB==null) return false;
  567. if (locA.getLine()!=locB.getLine()) return false;
  568. File fA = locA.getSourceFile();
  569. File fB = locA.getSourceFile();
  570. if (fA==null) return fB==null;
  571. if (fB==null) return false;
  572. return fA.getName().equals(fB.getName());
  573. }
  574. public IRelationship.Kind determineRelKind(ShadowMunger munger) {
  575. AdviceKind ak = ((Advice)munger).getKind();
  576. if (ak.getKey()==AdviceKind.Before.getKey())
  577. return IRelationship.Kind.ADVICE_BEFORE;
  578. else if (ak.getKey()==AdviceKind.After.getKey())
  579. return IRelationship.Kind.ADVICE_AFTER;
  580. else if (ak.getKey()==AdviceKind.AfterThrowing.getKey())
  581. return IRelationship.Kind.ADVICE_AFTERTHROWING;
  582. else if (ak.getKey()==AdviceKind.AfterReturning.getKey())
  583. return IRelationship.Kind.ADVICE_AFTERRETURNING;
  584. else if (ak.getKey()==AdviceKind.Around.getKey())
  585. return IRelationship.Kind.ADVICE_AROUND;
  586. else if (ak.getKey()==AdviceKind.CflowEntry.getKey() ||
  587. ak.getKey()==AdviceKind.CflowBelowEntry.getKey() ||
  588. ak.getKey()==AdviceKind.InterInitializer.getKey() ||
  589. ak.getKey()==AdviceKind.PerCflowEntry.getKey() ||
  590. ak.getKey()==AdviceKind.PerCflowBelowEntry.getKey() ||
  591. ak.getKey()==AdviceKind.PerThisEntry.getKey() ||
  592. ak.getKey()==AdviceKind.PerTargetEntry.getKey() ||
  593. ak.getKey()==AdviceKind.Softener.getKey() ||
  594. ak.getKey()==AdviceKind.PerTypeWithinEntry.getKey()) {
  595. //System.err.println("Dont want a message about this: "+ak);
  596. return null;
  597. }
  598. throw new RuntimeException("Shadow.determineRelKind: What the hell is it? "+ak);
  599. }
  600. /** Actually implement the (non-empty) mungers associated with this shadow */
  601. private void implementMungers() {
  602. World world = getIWorld();
  603. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  604. ShadowMunger munger = (ShadowMunger) iter.next();
  605. munger.implementOn(this);
  606. if (world.getCrossReferenceHandler() != null) {
  607. world.getCrossReferenceHandler().addCrossReference(
  608. munger.getSourceLocation(), // What is being applied
  609. this.getSourceLocation(), // Where is it being applied
  610. determineRelKind(munger), // What kind of advice?
  611. ((BcelAdvice)munger).hasDynamicTests() // Is a runtime test being stuffed in the code?
  612. );
  613. }
  614. // TAG: WeavingMessage
  615. if (!getIWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
  616. reportWeavingMessage(munger);
  617. }
  618. if (world.getModel() != null) {
  619. //System.err.println("munger: " + munger + " on " + this);
  620. AsmRelationshipProvider.getDefault().adviceMunger(world.getModel(), this, munger);
  621. }
  622. }
  623. }
  624. public String makeReflectiveFactoryString() {
  625. return null; //XXX
  626. }
  627. public abstract ISourceLocation getSourceLocation();
  628. // ---- utility
  629. public String toString() {
  630. return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
  631. }
  632. public String toResolvedString(World world) {
  633. return getKind() + "(" + world.resolve(getSignature()).toGenericString() + ")";
  634. }
  635. /**
  636. * Convert a bit array for the shadow kinds into a set of them... should only
  637. * be used for testing - mainline code should do bit manipulation!
  638. */
  639. public static Set toSet(int i) {
  640. Set results = new HashSet();
  641. for (int j = 0; j < Shadow.SHADOW_KINDS.length; j++) {
  642. Kind k = Shadow.SHADOW_KINDS[j];
  643. if (k.isSet(i)) results.add(k);
  644. }
  645. return results;
  646. }
  647. }