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.

Shadow.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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;
  13. import java.io.DataInputStream;
  14. import java.io.IOException;
  15. import java.util.ArrayList;
  16. import java.util.HashSet;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Set;
  20. import org.aspectj.asm.IRelationship;
  21. import org.aspectj.bridge.*;
  22. import org.aspectj.bridge.MessageUtil;
  23. import org.aspectj.lang.JoinPoint;
  24. import org.aspectj.util.PartialOrder;
  25. import org.aspectj.util.TypeSafeEnum;
  26. import org.aspectj.weaver.ast.Var;
  27. import org.aspectj.weaver.bcel.BcelAdvice;
  28. /*
  29. * The superclass of anything representing a the shadow of a join point. A shadow represents
  30. * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind
  31. * and a signature.
  32. */
  33. public abstract class Shadow {
  34. // every Shadow has a unique id, doesn't matter if it wraps...
  35. private static int nextShadowID = 100; // easier to spot than zero.
  36. private final Kind kind;
  37. private final Member signature;
  38. protected final Shadow enclosingShadow;
  39. protected List mungers = new ArrayList(1);
  40. public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
  41. // ----
  42. protected Shadow(Kind kind, Member signature, Shadow enclosingShadow) {
  43. this.kind = kind;
  44. this.signature = signature;
  45. this.enclosingShadow = enclosingShadow;
  46. }
  47. // ----
  48. public abstract World getIWorld();
  49. public List /*ShadowMunger*/ getMungers() {
  50. return mungers;
  51. }
  52. /**
  53. * could this(*) pcd ever match
  54. */
  55. public final boolean hasThis() {
  56. if (getKind().neverHasThis()) {
  57. return false;
  58. } else if (getKind().isEnclosingKind()) {
  59. return !getSignature().isStatic();
  60. } else if (enclosingShadow == null) {
  61. return false;
  62. } else {
  63. return enclosingShadow.hasThis();
  64. }
  65. }
  66. /**
  67. * the type of the this object here
  68. *
  69. * @throws IllegalStateException if there is no this here
  70. */
  71. public final TypeX getThisType() {
  72. if (!hasThis()) throw new IllegalStateException("no this");
  73. if (getKind().isEnclosingKind()) {
  74. return getSignature().getDeclaringType();
  75. } else {
  76. return enclosingShadow.getThisType();
  77. }
  78. }
  79. /**
  80. * a var referencing this
  81. *
  82. * @throws IllegalStateException if there is no target here
  83. */
  84. public abstract Var getThisVar();
  85. /**
  86. * could target(*) pcd ever match
  87. */
  88. public final boolean hasTarget() {
  89. if (getKind().neverHasTarget()) {
  90. return false;
  91. } else if (getKind().isTargetSameAsThis()) {
  92. return hasThis();
  93. } else {
  94. return !getSignature().isStatic();
  95. }
  96. }
  97. /**
  98. * the type of the target object here
  99. *
  100. * @throws IllegalStateException if there is no target here
  101. */
  102. public final TypeX getTargetType() {
  103. if (!hasTarget()) throw new IllegalStateException("no target");
  104. return getSignature().getDeclaringType();
  105. }
  106. /**
  107. * a var referencing the target
  108. *
  109. * @throws IllegalStateException if there is no target here
  110. */
  111. public abstract Var getTargetVar();
  112. public TypeX[] getArgTypes() {
  113. if (getKind() == FieldSet) return new TypeX[] { getSignature().getReturnType() };
  114. return getSignature().getParameterTypes();
  115. }
  116. public TypeX getArgType(int arg) {
  117. if (getKind() == FieldSet) return getSignature().getReturnType();
  118. return getSignature().getParameterTypes()[arg];
  119. }
  120. public int getArgCount() {
  121. if (getKind() == FieldSet) return 1;
  122. return getSignature()
  123. .getParameterTypes().length;
  124. }
  125. public abstract TypeX getEnclosingType();
  126. public abstract Var getArgVar(int i);
  127. public abstract Var getThisJoinPointVar();
  128. public abstract Var getThisJoinPointStaticPartVar();
  129. public abstract Var getThisEnclosingJoinPointStaticPartVar();
  130. // annotation variables
  131. public abstract Var getKindedAnnotationVar(TypeX forAnnotationType);
  132. public abstract Var getWithinAnnotationVar(TypeX forAnnotationType);
  133. public abstract Var getWithinCodeAnnotationVar(TypeX forAnnotationType);
  134. public abstract Var getThisAnnotationVar(TypeX forAnnotationType);
  135. public abstract Var getTargetAnnotationVar(TypeX forAnnotationType);
  136. public abstract Var getArgAnnotationVar(int i, TypeX forAnnotationType);
  137. public abstract Member getEnclosingCodeSignature();
  138. /** returns the kind of shadow this is, representing what happens under this shadow
  139. */
  140. public Kind getKind() {
  141. return kind;
  142. }
  143. /** returns the signature of the thing under this shadow
  144. */
  145. public Member getSignature() {
  146. return signature;
  147. }
  148. public TypeX getReturnType() {
  149. if (kind == ConstructorCall) return getSignature().getDeclaringType();
  150. else if (kind == FieldSet) return ResolvedTypeX.VOID;
  151. return getSignature().getReturnType();
  152. }
  153. /**
  154. * These names are the ones that will be returned by thisJoinPoint.getKind()
  155. * Those need to be documented somewhere
  156. */
  157. public static final Kind MethodCall = new Kind(JoinPoint.METHOD_CALL, 1, true);
  158. public static final Kind ConstructorCall = new Kind(JoinPoint.CONSTRUCTOR_CALL, 2, true);
  159. public static final Kind MethodExecution = new Kind(JoinPoint.METHOD_EXECUTION, 3, false);
  160. public static final Kind ConstructorExecution = new Kind(JoinPoint.CONSTRUCTOR_EXECUTION, 4, false);
  161. public static final Kind FieldGet = new Kind(JoinPoint.FIELD_GET, 5, true);
  162. public static final Kind FieldSet = new Kind(JoinPoint.FIELD_SET, 6, true);
  163. public static final Kind StaticInitialization = new Kind(JoinPoint.STATICINITIALIZATION, 7, false);
  164. public static final Kind PreInitialization = new Kind(JoinPoint.PREINTIALIZATION, 8, false);
  165. public static final Kind AdviceExecution = new Kind(JoinPoint.ADVICE_EXECUTION, 9, false);
  166. public static final Kind Initialization = new Kind(JoinPoint.INITIALIZATION, 10, false);
  167. public static final Kind ExceptionHandler = new Kind(JoinPoint.EXCEPTION_HANDLER, 11, true);
  168. public static final int MAX_SHADOW_KIND = 11;
  169. public static final Kind[] SHADOW_KINDS = new Kind[] {
  170. MethodCall, ConstructorCall, MethodExecution, ConstructorExecution,
  171. FieldGet, FieldSet, StaticInitialization, PreInitialization,
  172. AdviceExecution, Initialization, ExceptionHandler,
  173. };
  174. public static final Set ALL_SHADOW_KINDS = new HashSet();
  175. static {
  176. for (int i = 0; i < SHADOW_KINDS.length; i++) {
  177. ALL_SHADOW_KINDS.add(SHADOW_KINDS[i]);
  178. }
  179. }
  180. /** A type-safe enum representing the kind of shadows
  181. */
  182. public static final class Kind extends TypeSafeEnum {
  183. private boolean argsOnStack; //XXX unused
  184. public Kind(String name, int key, boolean argsOnStack) {
  185. super(name, key);
  186. this.argsOnStack = argsOnStack;
  187. }
  188. public String toLegalJavaIdentifier() {
  189. return getName().replace('-', '_');
  190. }
  191. public boolean argsOnStack() {
  192. return !isTargetSameAsThis();
  193. }
  194. // !!! this is false for handlers!
  195. public boolean allowsExtraction() {
  196. return true;
  197. }
  198. // XXX revisit along with removal of priorities
  199. public boolean hasHighPriorityExceptions() {
  200. return !isTargetSameAsThis();
  201. }
  202. /**
  203. * These are all the shadows that contains other shadows within them and
  204. * are often directly associated with methods.
  205. */
  206. public boolean isEnclosingKind() {
  207. return this == MethodExecution || this == ConstructorExecution ||
  208. this == AdviceExecution || this == StaticInitialization
  209. || this == Initialization;
  210. }
  211. public boolean isTargetSameAsThis() {
  212. return this == MethodExecution
  213. || this == ConstructorExecution
  214. || this == StaticInitialization
  215. || this == PreInitialization
  216. || this == AdviceExecution
  217. || this == Initialization;
  218. }
  219. public boolean neverHasTarget() {
  220. return this == ConstructorCall
  221. || this == ExceptionHandler
  222. || this == PreInitialization
  223. || this == StaticInitialization;
  224. }
  225. public boolean neverHasThis() {
  226. return this == PreInitialization
  227. || this == StaticInitialization;
  228. }
  229. public String getSimpleName() {
  230. int dash = getName().lastIndexOf('-');
  231. if (dash == -1) return getName();
  232. else return getName().substring(dash+1);
  233. }
  234. public static Kind read(DataInputStream s) throws IOException {
  235. int key = s.readByte();
  236. switch(key) {
  237. case 1: return MethodCall;
  238. case 2: return ConstructorCall;
  239. case 3: return MethodExecution;
  240. case 4: return ConstructorExecution;
  241. case 5: return FieldGet;
  242. case 6: return FieldSet;
  243. case 7: return StaticInitialization;
  244. case 8: return PreInitialization;
  245. case 9: return AdviceExecution;
  246. case 10: return Initialization;
  247. case 11: return ExceptionHandler;
  248. }
  249. throw new BCException("unknown kind: " + key);
  250. }
  251. }
  252. protected boolean checkMunger(ShadowMunger munger) {
  253. for (Iterator i = munger.getThrownExceptions().iterator(); i.hasNext(); ) {
  254. if (!checkCanThrow(munger, (ResolvedTypeX)i.next() )) return false;
  255. }
  256. return true;
  257. }
  258. protected boolean checkCanThrow(ShadowMunger munger, ResolvedTypeX resolvedTypeX) {
  259. if (getKind() == ExceptionHandler) {
  260. //XXX much too lenient rules here, need to walk up exception handlers
  261. return true;
  262. }
  263. if (!isDeclaredException(resolvedTypeX, getSignature())) {
  264. getIWorld().showMessage(IMessage.ERROR,
  265. WeaverMessages.format(WeaverMessages.CANT_THROW_CHECKED,resolvedTypeX,this), // from advice in \'" + munger. + "\'",
  266. getSourceLocation(), munger.getSourceLocation());
  267. }
  268. return true;
  269. }
  270. private boolean isDeclaredException(
  271. ResolvedTypeX resolvedTypeX,
  272. Member member)
  273. {
  274. ResolvedTypeX[] excs = getIWorld().resolve(member.getExceptions(getIWorld()));
  275. for (int i=0, len=excs.length; i < len; i++) {
  276. if (excs[i].isAssignableFrom(resolvedTypeX)) return true;
  277. }
  278. return false;
  279. }
  280. public void addMunger(ShadowMunger munger) {
  281. if (checkMunger(munger)) this.mungers.add(munger);
  282. }
  283. public final void implement() {
  284. sortMungers();
  285. if (mungers == null) return;
  286. prepareForMungers();
  287. implementMungers();
  288. }
  289. private void sortMungers() {
  290. List sorted = PartialOrder.sort(mungers);
  291. if (sorted == null) {
  292. // this means that we have circular dependencies
  293. for (Iterator i = mungers.iterator(); i.hasNext(); ) {
  294. ShadowMunger m = (ShadowMunger)i.next();
  295. getIWorld().getMessageHandler().handleMessage(
  296. MessageUtil.error(
  297. WeaverMessages.format(WeaverMessages.CIRCULAR_DEPENDENCY,this), m.getSourceLocation()));
  298. }
  299. }
  300. mungers = sorted;
  301. }
  302. /** Prepare the shadow for implementation. After this is done, the shadow
  303. * should be in such a position that each munger simply needs to be implemented.
  304. */
  305. protected void prepareForMungers() {
  306. throw new RuntimeException("Generic shadows cannot be prepared");
  307. }
  308. /*
  309. * Ensure we report a nice source location - particular in the case
  310. * where the source info is missing (binary weave).
  311. */
  312. private String beautifyLocation(ISourceLocation isl) {
  313. StringBuffer nice = new StringBuffer();
  314. if (isl==null || isl.getSourceFile()==null || isl.getSourceFile().getName().indexOf("no debug info available")!=-1) {
  315. nice.append("no debug info available");
  316. } else {
  317. // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa
  318. int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
  319. if (takeFrom == -1) {
  320. takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
  321. }
  322. nice.append(isl.getSourceFile().getPath().substring(takeFrom +1));
  323. if (isl.getLine()!=0) nice.append(":").append(isl.getLine());
  324. }
  325. return nice.toString();
  326. }
  327. /*
  328. * Report a message about the advice weave that has occurred. Some messing about
  329. * to make it pretty ! This code is just asking for an NPE to occur ...
  330. */
  331. private void reportWeavingMessage(ShadowMunger munger) {
  332. Advice advice = (Advice)munger;
  333. AdviceKind aKind = advice.getKind();
  334. // Only report on interesting advice kinds ...
  335. if (aKind == null || advice.getConcreteAspect()==null) {
  336. // We suspect someone is programmatically driving the weaver
  337. // (e.g. IdWeaveTestCase in the weaver testcases)
  338. return;
  339. }
  340. if (!( aKind.equals(AdviceKind.Before) ||
  341. aKind.equals(AdviceKind.After) ||
  342. aKind.equals(AdviceKind.AfterReturning) ||
  343. aKind.equals(AdviceKind.AfterThrowing) ||
  344. aKind.equals(AdviceKind.Around) ||
  345. aKind.equals(AdviceKind.Softener))) return;
  346. String description = advice.getKind().toString();
  347. String advisedType = this.getEnclosingType().getName();
  348. String advisingType= advice.getConcreteAspect().getName();
  349. Message msg = null;
  350. if (advice.getKind().equals(AdviceKind.Softener)) {
  351. msg = WeaveMessage.constructWeavingMessage(
  352. WeaveMessage.WEAVEMESSAGE_SOFTENS,
  353. new String[]{advisedType,beautifyLocation(getSourceLocation()),
  354. advisingType,beautifyLocation(munger.getSourceLocation())});
  355. } else {
  356. boolean runtimeTest = ((BcelAdvice)advice).hasDynamicTests();
  357. msg = WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ADVISES,
  358. new String[]{ advisedType, beautifyLocation(getSourceLocation()),
  359. description,
  360. advisingType,beautifyLocation(munger.getSourceLocation()),
  361. (runtimeTest?" [with runtime test]":"")});
  362. // Boolean.toString(runtimeTest)});
  363. }
  364. getIWorld().getMessageHandler().handleMessage(msg);
  365. }
  366. public IRelationship.Kind determineRelKind(ShadowMunger munger) {
  367. AdviceKind ak = ((Advice)munger).getKind();
  368. if (ak.getKey()==AdviceKind.Before.getKey())
  369. return IRelationship.Kind.ADVICE_BEFORE;
  370. else if (ak.getKey()==AdviceKind.After.getKey())
  371. return IRelationship.Kind.ADVICE_AFTER;
  372. else if (ak.getKey()==AdviceKind.AfterThrowing.getKey())
  373. return IRelationship.Kind.ADVICE_AFTERTHROWING;
  374. else if (ak.getKey()==AdviceKind.AfterReturning.getKey())
  375. return IRelationship.Kind.ADVICE_AFTERRETURNING;
  376. else if (ak.getKey()==AdviceKind.Around.getKey())
  377. return IRelationship.Kind.ADVICE_AROUND;
  378. else if (ak.getKey()==AdviceKind.CflowEntry.getKey() ||
  379. ak.getKey()==AdviceKind.CflowBelowEntry.getKey() ||
  380. ak.getKey()==AdviceKind.InterInitializer.getKey() ||
  381. ak.getKey()==AdviceKind.PerCflowEntry.getKey() ||
  382. ak.getKey()==AdviceKind.PerCflowBelowEntry.getKey() ||
  383. ak.getKey()==AdviceKind.PerThisEntry.getKey() ||
  384. ak.getKey()==AdviceKind.PerTargetEntry.getKey() ||
  385. ak.getKey()==AdviceKind.Softener.getKey()) {
  386. System.err.println("Dont want a message about this: "+ak);
  387. return null;
  388. }
  389. throw new RuntimeException("Shadow.determineRelKind: What the hell is it? "+ak);
  390. }
  391. /** Actually implement the (non-empty) mungers associated with this shadow */
  392. private void implementMungers() {
  393. World world = getIWorld();
  394. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  395. ShadowMunger munger = (ShadowMunger) iter.next();
  396. munger.implementOn(this);
  397. if (world.xrefHandler != null) {
  398. world.xrefHandler.addCrossReference(
  399. munger.getSourceLocation(), // What is being applied
  400. this.getSourceLocation(), // Where is it being applied
  401. determineRelKind(munger), // What kind of advice?
  402. ((BcelAdvice)munger).hasDynamicTests() // Is a runtime test being stuffed in the code?
  403. );
  404. }
  405. // TAG: WeavingMessage
  406. if (!getIWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) {
  407. reportWeavingMessage(munger);
  408. }
  409. if (world.getModel() != null) {
  410. //System.err.println("munger: " + munger + " on " + this);
  411. AsmRelationshipProvider.getDefault().adviceMunger(world.getModel(), this, munger);
  412. }
  413. }
  414. }
  415. public String makeReflectiveFactoryString() {
  416. return null; //XXX
  417. }
  418. public abstract ISourceLocation getSourceLocation();
  419. // ---- utility
  420. public String toString() {
  421. return getKind() + "(" + getSignature() + ")"; // + getSourceLines();
  422. }
  423. }