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

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