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.

BcelAdvice.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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.bcel;
  13. import java.util.*;
  14. import java.util.Collection;
  15. import java.util.Collections;
  16. import org.apache.bcel.generic.*;
  17. import org.aspectj.weaver.*;
  18. import org.aspectj.weaver.ast.Literal;
  19. import org.aspectj.weaver.ast.Test;
  20. import org.aspectj.weaver.patterns.*;
  21. /**
  22. * Advice implemented for bcel.
  23. *
  24. * @author Erik Hilsdale
  25. * @author Jim Hugunin
  26. */
  27. public class BcelAdvice extends Advice {
  28. private Test pointcutTest;
  29. private ExposedState exposedState;
  30. public BcelAdvice(
  31. AjAttribute.AdviceAttribute attribute,
  32. Pointcut pointcut,
  33. Member signature,
  34. ResolvedTypeX concreteAspect)
  35. {
  36. super(attribute, pointcut, signature);
  37. this.concreteAspect = concreteAspect;
  38. }
  39. // !!! must only be used for testing
  40. public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature,
  41. int extraArgumentFlags,
  42. int start, int end, ISourceContext sourceContext, ResolvedTypeX concreteAspect)
  43. {
  44. this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext),
  45. pointcut, signature, concreteAspect);
  46. thrownExceptions = Collections.EMPTY_LIST; //!!! interaction with unit tests
  47. }
  48. // ---- implementations of ShadowMunger's methods
  49. public void specializeOn(Shadow shadow) {
  50. if (getKind() == AdviceKind.Around) {
  51. ((BcelShadow)shadow).initializeForAroundClosure();
  52. }
  53. //XXX this case is just here for supporting lazy test code
  54. if (getKind() == null) {
  55. exposedState = new ExposedState(0);
  56. return;
  57. }
  58. if (getKind().isPerEntry()) {
  59. exposedState = new ExposedState(0);
  60. } else if (getKind().isCflow()) {
  61. exposedState = new ExposedState(nFreeVars);
  62. } else if (getSignature() != null) {
  63. exposedState = new ExposedState(getSignature());
  64. } else {
  65. exposedState = new ExposedState(0);
  66. return; //XXX this case is just here for supporting lazy test code
  67. }
  68. pointcutTest = getPointcut().findResidue(shadow, exposedState);
  69. // make sure thisJoinPoint parameters are initialized
  70. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  71. ((BcelShadow)shadow).getThisJoinPointStaticPartVar();
  72. }
  73. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  74. ((BcelShadow)shadow).getThisJoinPointVar();
  75. }
  76. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  77. ((BcelShadow)shadow).getThisEnclosingJoinPointStaticPartVar();
  78. }
  79. }
  80. private boolean canInline(Shadow s) {
  81. if (attribute.isProceedInInners()) return false;
  82. //XXX this guard seems to only be needed for bad test cases
  83. if (concreteAspect == null || concreteAspect == ResolvedTypeX.MISSING) return false;
  84. if (concreteAspect.getWorld().isXnoInline()) return false;
  85. //System.err.println("isWoven? " + ((BcelObjectType)concreteAspect).getLazyClassGen().getWeaverState());
  86. return BcelWorld.getBcelObjectType(concreteAspect).getLazyClassGen().getWeaverState()
  87. == WeaverStateKind.Woven;
  88. }
  89. public void implementOn(Shadow s) {
  90. BcelShadow shadow = (BcelShadow) s;
  91. if (getKind() == AdviceKind.Before) {
  92. shadow.weaveBefore(this);
  93. } else if (getKind() == AdviceKind.AfterReturning) {
  94. shadow.weaveAfterReturning(this);
  95. } else if (getKind() == AdviceKind.AfterThrowing) {
  96. TypeX catchType =
  97. hasExtraParameter()
  98. ? getExtraParameterType()
  99. : TypeX.THROWABLE;
  100. shadow.weaveAfterThrowing(this, catchType);
  101. } else if (getKind() == AdviceKind.After) {
  102. shadow.weaveAfter(this);
  103. } else if (getKind() == AdviceKind.Around) {
  104. if (!canInline(s)) {
  105. shadow.weaveAroundClosure(this, hasDynamicTests());
  106. } else {
  107. shadow.weaveAroundInline(this, hasDynamicTests());
  108. }
  109. } else if (getKind() == AdviceKind.InterInitializer) {
  110. shadow.weaveAfterReturning(this);
  111. } else if (getKind().isCflow()) {
  112. shadow.weaveCflowEntry(this, getSignature());
  113. } else if (getKind() == AdviceKind.PerThisEntry) {
  114. shadow.weavePerObjectEntry(this, (BcelVar)shadow.getThisVar());
  115. } else if (getKind() == AdviceKind.PerTargetEntry) {
  116. shadow.weavePerObjectEntry(this, (BcelVar)shadow.getTargetVar());
  117. } else if (getKind() == AdviceKind.Softener) {
  118. shadow.weaveSoftener(this, ((ExactTypePattern)exceptionType).getType());
  119. } else {
  120. throw new BCException("unimplemented kind: " + getKind());
  121. }
  122. }
  123. // ---- implementations
  124. private Collection collectCheckedExceptions(TypeX[] excs) {
  125. if (excs == null || excs.length == 0) return Collections.EMPTY_LIST;
  126. Collection ret = new ArrayList();
  127. World world = concreteAspect.getWorld();
  128. ResolvedTypeX runtimeException = world.resolve(TypeX.RUNTIME_EXCEPTION);
  129. ResolvedTypeX error = world.resolve(TypeX.ERROR);
  130. for (int i=0, len=excs.length; i < len; i++) {
  131. ResolvedTypeX t = world.resolve(excs[i]);
  132. if (!(runtimeException.isAssignableFrom(t) || error.isAssignableFrom(t))) {
  133. ret.add(t);
  134. }
  135. }
  136. return ret;
  137. }
  138. private Collection thrownExceptions = null;
  139. public Collection getThrownExceptions() {
  140. if (thrownExceptions == null) {
  141. //??? can we really lump in Around here, how does this interact with Throwable
  142. if (concreteAspect != null && concreteAspect.getWorld() != null && // null tests for test harness
  143. (getKind().isAfter() || getKind() == AdviceKind.Before || getKind() == AdviceKind.Around))
  144. {
  145. World world = concreteAspect.getWorld();
  146. ResolvedMember m = world.resolve(signature);
  147. if (m == null) {
  148. thrownExceptions = Collections.EMPTY_LIST;
  149. } else {
  150. thrownExceptions = collectCheckedExceptions(m.getExceptions());
  151. }
  152. } else {
  153. thrownExceptions = Collections.EMPTY_LIST;
  154. }
  155. }
  156. return thrownExceptions;
  157. }
  158. // only call me after prepare has been called
  159. public boolean hasDynamicTests() {
  160. // if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  161. // TypeX extraParameterType = getExtraParameterType();
  162. // if (! extraParameterType.equals(TypeX.OBJECT)
  163. // && ! extraParameterType.isPrimitive())
  164. // return true;
  165. // }
  166. return pointcutTest != null &&
  167. !(pointcutTest == Literal.TRUE);// || pointcutTest == Literal.NO_TEST);
  168. }
  169. /**
  170. * get the instruction list for the really simple version of this advice.
  171. * Is broken apart
  172. * for other advice, but if you want it in one block, this is the method to call.
  173. *
  174. * @param s The shadow around which these instructions will eventually live.
  175. * @param extraArgVar The var that will hold the return value or thrown exception
  176. * for afterX advice
  177. * @param ifNoAdvice The instructionHandle to jump to if the dynamic
  178. * tests for this munger fails.
  179. */
  180. InstructionList getAdviceInstructions(
  181. BcelShadow s,
  182. BcelVar extraArgVar,
  183. InstructionHandle ifNoAdvice)
  184. {
  185. BcelShadow shadow = (BcelShadow) s;
  186. InstructionFactory fact = shadow.getFactory();
  187. BcelWorld world = shadow.getWorld();
  188. InstructionList il = new InstructionList();
  189. // we test to see if we have the right kind of thing...
  190. // after throwing does this just by the exception mechanism.
  191. if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  192. TypeX extraParameterType = getExtraParameterType();
  193. if (! extraParameterType.equals(TypeX.OBJECT)
  194. && ! extraParameterType.isPrimitive()) {
  195. il.append(
  196. BcelRenderer.renderTest(
  197. fact,
  198. world,
  199. Test.makeInstanceof(
  200. extraArgVar, getExtraParameterType().resolve(world)),
  201. null,
  202. ifNoAdvice,
  203. null));
  204. }
  205. }
  206. il.append(getAdviceArgSetup(shadow, extraArgVar, null));
  207. il.append(getNonTestAdviceInstructions(shadow));
  208. InstructionHandle ifYesAdvice = il.getStart();
  209. il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice));
  210. return il;
  211. }
  212. public InstructionList getAdviceArgSetup(
  213. BcelShadow shadow,
  214. BcelVar extraVar,
  215. InstructionList closureInstantiation)
  216. {
  217. InstructionFactory fact = shadow.getFactory();
  218. BcelWorld world = shadow.getWorld();
  219. InstructionList il = new InstructionList();
  220. // if (targetAspectField != null) {
  221. // il.append(fact.createFieldAccess(
  222. // targetAspectField.getDeclaringType().getName(),
  223. // targetAspectField.getName(),
  224. // BcelWorld.makeBcelType(targetAspectField.getType()),
  225. // Constants.GETSTATIC));
  226. // }
  227. //
  228. //System.err.println("BcelAdvice: " + exposedState);
  229. if (exposedState.getAspectInstance() != null) {
  230. il.append(
  231. BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance()));
  232. }
  233. for (int i = 0, len = exposedState.size(); i < len; i++) {
  234. BcelVar v = (BcelVar) exposedState.get(i);
  235. if (v == null) continue;
  236. TypeX desiredTy = getSignature().getParameterTypes()[i];
  237. v.appendLoadAndConvert(il, fact, desiredTy.resolve(world));
  238. }
  239. if (getKind() == AdviceKind.Around) {
  240. il.append(closureInstantiation);
  241. } else if (hasExtraParameter()) {
  242. extraVar.appendLoadAndConvert(
  243. il,
  244. fact,
  245. getExtraParameterType().resolve(world));
  246. }
  247. // handle thisJoinPoint parameters
  248. // these need to be in that same order as parameters in
  249. // org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration
  250. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  251. shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact);
  252. }
  253. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  254. shadow.getThisJoinPointBcelVar().appendLoad(il, fact);
  255. }
  256. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  257. shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact);
  258. }
  259. return il;
  260. }
  261. public InstructionList getNonTestAdviceInstructions(BcelShadow shadow) {
  262. return new InstructionList(
  263. Utility.createInvoke(shadow.getFactory(), shadow.getWorld(), getSignature()));
  264. }
  265. public InstructionList getTestInstructions(
  266. BcelShadow shadow,
  267. InstructionHandle sk,
  268. InstructionHandle fk,
  269. InstructionHandle next)
  270. {
  271. //System.err.println("test: " + pointcutTest);
  272. return BcelRenderer.renderTest(
  273. shadow.getFactory(),
  274. shadow.getWorld(),
  275. pointcutTest,
  276. sk,
  277. fk,
  278. next);
  279. }
  280. public int compareTo(Object other) {
  281. if (!(other instanceof BcelAdvice)) return 0;
  282. BcelAdvice o = (BcelAdvice)other;
  283. //System.err.println("compareTo: " + this + ", " + o);
  284. if (kind.getPrecedence() != o.kind.getPrecedence()) {
  285. if (kind.getPrecedence() > o.kind.getPrecedence()) return +1;
  286. else return -1;
  287. }
  288. if (kind.isCflow()) {
  289. // System.err.println("sort: " + this + " innerCflowEntries " + innerCflowEntries);
  290. // System.err.println(" " + o + " innerCflowEntries " + o.innerCflowEntries);
  291. boolean isBelow = (kind == AdviceKind.CflowBelowEntry);
  292. if (this.innerCflowEntries.contains(o)) return isBelow ? +1 : -1;
  293. else if (o.innerCflowEntries.contains(this)) return isBelow ? -1 : +1;
  294. else return 0;
  295. }
  296. if (kind.isPerEntry() || kind == AdviceKind.Softener) {
  297. return 0;
  298. }
  299. //System.out.println("compare: " + this + " with " + other);
  300. World world = concreteAspect.getWorld();
  301. int ret =
  302. concreteAspect.getWorld().compareByDominates(
  303. concreteAspect,
  304. o.concreteAspect);
  305. if (ret != 0) return ret;
  306. ResolvedTypeX declaringAspect = getDeclaringAspect().resolve(world);
  307. ResolvedTypeX o_declaringAspect = o.getDeclaringAspect().resolve(world);
  308. if (declaringAspect == o_declaringAspect) {
  309. if (kind.isAfter() || o.kind.isAfter()) {
  310. return this.getStart() < o.getStart() ? -1: +1;
  311. } else {
  312. return this.getStart()< o.getStart() ? +1: -1;
  313. }
  314. } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) {
  315. return -1;
  316. } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) {
  317. return +1;
  318. } else {
  319. return 0;
  320. }
  321. }
  322. public BcelVar[] getExposedStateAsBcelVars() {
  323. //System.out.println("vars: " + Arrays.asList(exposedState.vars));
  324. if (exposedState == null) return BcelVar.NONE;
  325. int len = exposedState.vars.length;
  326. BcelVar[] ret = new BcelVar[len];
  327. for (int i=0; i < len; i++) {
  328. ret[i] = (BcelVar)exposedState.vars[i];
  329. }
  330. return ret; //(BcelVar[]) exposedState.vars;
  331. }
  332. }