Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  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. * Alexandre Vasseur support for @AJ aspects
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.util.ArrayList;
  15. import java.util.Collection;
  16. import java.util.Collections;
  17. import org.aspectj.apache.bcel.generic.InstructionFactory;
  18. import org.aspectj.apache.bcel.generic.InstructionHandle;
  19. import org.aspectj.apache.bcel.generic.InstructionList;
  20. import org.aspectj.apache.bcel.generic.InstructionConstants;
  21. import org.aspectj.bridge.IMessage;
  22. import org.aspectj.bridge.Message;
  23. import org.aspectj.weaver.Advice;
  24. import org.aspectj.weaver.AdviceKind;
  25. import org.aspectj.weaver.AjAttribute;
  26. import org.aspectj.weaver.BCException;
  27. import org.aspectj.weaver.ISourceContext;
  28. import org.aspectj.weaver.Member;
  29. import org.aspectj.weaver.ResolvedMember;
  30. import org.aspectj.weaver.ResolvedTypeX;
  31. import org.aspectj.weaver.Shadow;
  32. import org.aspectj.weaver.TypeX;
  33. import org.aspectj.weaver.WeaverMessages;
  34. import org.aspectj.weaver.World;
  35. import org.aspectj.weaver.ast.Literal;
  36. import org.aspectj.weaver.ast.Test;
  37. import org.aspectj.weaver.patterns.ExactTypePattern;
  38. import org.aspectj.weaver.patterns.ExposedState;
  39. import org.aspectj.weaver.patterns.Pointcut;
  40. /**
  41. * Advice implemented for bcel.
  42. *
  43. * @author Erik Hilsdale
  44. * @author Jim Hugunin
  45. */
  46. public class BcelAdvice extends Advice {
  47. private Test pointcutTest;
  48. private ExposedState exposedState;
  49. private boolean hasMatchedAtLeastOnce = false;
  50. public BcelAdvice(
  51. AjAttribute.AdviceAttribute attribute,
  52. Pointcut pointcut,
  53. Member signature,
  54. ResolvedTypeX concreteAspect)
  55. {
  56. super(attribute, pointcut, signature);
  57. this.concreteAspect = concreteAspect;
  58. }
  59. // !!! must only be used for testing
  60. public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature,
  61. int extraArgumentFlags,
  62. int start, int end, ISourceContext sourceContext, ResolvedTypeX concreteAspect)
  63. {
  64. this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext),
  65. pointcut, signature, concreteAspect);
  66. thrownExceptions = Collections.EMPTY_LIST; //!!! interaction with unit tests
  67. }
  68. // ---- implementations of ShadowMunger's methods
  69. public void specializeOn(Shadow shadow) {
  70. if (getKind() == AdviceKind.Around) {
  71. ((BcelShadow)shadow).initializeForAroundClosure();
  72. }
  73. //XXX this case is just here for supporting lazy test code
  74. if (getKind() == null) {
  75. exposedState = new ExposedState(0);
  76. return;
  77. }
  78. if (getKind().isPerEntry()) {
  79. exposedState = new ExposedState(0);
  80. } else if (getKind().isCflow()) {
  81. exposedState = new ExposedState(nFreeVars);
  82. } else if (getSignature() != null) {
  83. exposedState = new ExposedState(getSignature());
  84. } else {
  85. exposedState = new ExposedState(0);
  86. return; //XXX this case is just here for supporting lazy test code
  87. }
  88. pointcutTest = getPointcut().findResidue(shadow, exposedState);
  89. // these initializations won't be performed by findResidue, but need to be
  90. // so that the joinpoint is primed for weaving
  91. if (getKind() == AdviceKind.PerThisEntry) {
  92. shadow.getThisVar();
  93. } else if (getKind() == AdviceKind.PerTargetEntry) {
  94. shadow.getTargetVar();
  95. }
  96. // make sure thisJoinPoint parameters are initialized
  97. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  98. ((BcelShadow)shadow).getThisJoinPointStaticPartVar();
  99. ((BcelShadow)shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow,getSourceLocation());
  100. }
  101. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  102. ((BcelShadow)shadow).requireThisJoinPoint(pointcutTest != Literal.TRUE && getKind() != AdviceKind.Around);
  103. ((BcelShadow)shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow,getSourceLocation());
  104. }
  105. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  106. ((BcelShadow)shadow).getThisEnclosingJoinPointStaticPartVar();
  107. ((BcelShadow)shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow,getSourceLocation());
  108. }
  109. }
  110. private boolean canInline(Shadow s) {
  111. if (attribute.isProceedInInners()) return false;
  112. //XXX this guard seems to only be needed for bad test cases
  113. if (concreteAspect == null || concreteAspect == ResolvedTypeX.MISSING) return false;
  114. if (concreteAspect.getWorld().isXnoInline()) return false;
  115. //System.err.println("isWoven? " + ((BcelObjectType)concreteAspect).getLazyClassGen().getWeaverState());
  116. return BcelWorld.getBcelObjectType(concreteAspect).getLazyClassGen().isWoven();
  117. }
  118. public void implementOn(Shadow s) {
  119. hasMatchedAtLeastOnce=true;
  120. BcelShadow shadow = (BcelShadow) s;
  121. //FIXME AV - see #75442, this logic is not enough so for now comment it out until we fix the bug
  122. // // callback for perObject AJC MightHaveAspect postMunge (#75442)
  123. // if (getConcreteAspect() != null
  124. // && getConcreteAspect().getPerClause() != null
  125. // && PerClause.PEROBJECT.equals(getConcreteAspect().getPerClause().getKind())) {
  126. // final PerObject clause;
  127. // if (getConcreteAspect().getPerClause() instanceof PerFromSuper) {
  128. // clause = (PerObject)((PerFromSuper) getConcreteAspect().getPerClause()).lookupConcretePerClause(getConcreteAspect());
  129. // } else {
  130. // clause = (PerObject) getConcreteAspect().getPerClause();
  131. // }
  132. // if (clause.isThis()) {
  133. // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getThisVar().getType(), getConcreteAspect());
  134. // } else {
  135. // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getTargetVar().getType(), getConcreteAspect());
  136. // }
  137. // }
  138. if (getKind() == AdviceKind.Before) {
  139. shadow.weaveBefore(this);
  140. } else if (getKind() == AdviceKind.AfterReturning) {
  141. shadow.weaveAfterReturning(this);
  142. } else if (getKind() == AdviceKind.AfterThrowing) {
  143. TypeX catchType =
  144. hasExtraParameter()
  145. ? getExtraParameterType()
  146. : TypeX.THROWABLE;
  147. shadow.weaveAfterThrowing(this, catchType);
  148. } else if (getKind() == AdviceKind.After) {
  149. shadow.weaveAfter(this);
  150. } else if (getKind() == AdviceKind.Around) {
  151. // Note: under regular LTW the aspect is usually loaded after the first use of any class affecteted by it
  152. // This means that as long as the aspect has not been thru the LTW, it's woven state is unknown
  153. // and thus canInline(s) will return false.
  154. // To force inlining (test), ones can do Class aspect = FQNAspect.class in the clinit of the target class
  155. // FIXME AV : for AJC compiled @AJ aspect (or any code style aspect), the woven state can never be known
  156. // if the aspect belongs to a parent classloader. In that case the aspect will never be inlined.
  157. // It might be dangerous to change that especially for @AJ aspect non compiled with AJC since if those
  158. // are not weaved (f.e. use of some limiteed LTW etc) then they cannot be prepared for inlining.
  159. // One solution would be to flag @AJ aspect with an annotation as "prepared" and query that one.
  160. if (!canInline(s)) {
  161. shadow.weaveAroundClosure(this, hasDynamicTests());
  162. } else {
  163. shadow.weaveAroundInline(this, hasDynamicTests());
  164. }
  165. } else if (getKind() == AdviceKind.InterInitializer) {
  166. shadow.weaveAfterReturning(this);
  167. } else if (getKind().isCflow()) {
  168. shadow.weaveCflowEntry(this, getSignature());
  169. } else if (getKind() == AdviceKind.PerThisEntry) {
  170. shadow.weavePerObjectEntry(this, (BcelVar)shadow.getThisVar());
  171. } else if (getKind() == AdviceKind.PerTargetEntry) {
  172. shadow.weavePerObjectEntry(this, (BcelVar)shadow.getTargetVar());
  173. } else if (getKind() == AdviceKind.Softener) {
  174. shadow.weaveSoftener(this, ((ExactTypePattern)exceptionType).getType());
  175. } else if (getKind() == AdviceKind.PerTypeWithinEntry) {
  176. // PTWIMPL Entry to ptw is the static initialization of a type that matched the ptw type pattern
  177. shadow.weavePerTypeWithinAspectInitialization(this,shadow.getEnclosingType());
  178. } else {
  179. throw new BCException("unimplemented kind: " + getKind());
  180. }
  181. }
  182. // ---- implementations
  183. private Collection collectCheckedExceptions(TypeX[] excs) {
  184. if (excs == null || excs.length == 0) return Collections.EMPTY_LIST;
  185. Collection ret = new ArrayList();
  186. World world = concreteAspect.getWorld();
  187. ResolvedTypeX runtimeException = world.getCoreType(TypeX.RUNTIME_EXCEPTION);
  188. ResolvedTypeX error = world.getCoreType(TypeX.ERROR);
  189. for (int i=0, len=excs.length; i < len; i++) {
  190. ResolvedTypeX t = world.resolve(excs[i],true);
  191. if (t == ResolvedTypeX.MISSING) {
  192. IMessage msg = new Message(
  193. WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_EXCEPTION_TYPE,excs[i].getName()),
  194. "",IMessage.ERROR,getSourceLocation(),null,null);
  195. world.getMessageHandler().handleMessage(msg);
  196. }
  197. if (!(runtimeException.isAssignableFrom(t) || error.isAssignableFrom(t))) {
  198. ret.add(t);
  199. }
  200. }
  201. return ret;
  202. }
  203. private Collection thrownExceptions = null;
  204. public Collection getThrownExceptions() {
  205. if (thrownExceptions == null) {
  206. //??? can we really lump in Around here, how does this interact with Throwable
  207. if (concreteAspect != null && concreteAspect.getWorld() != null && // null tests for test harness
  208. (getKind().isAfter() || getKind() == AdviceKind.Before || getKind() == AdviceKind.Around))
  209. {
  210. World world = concreteAspect.getWorld();
  211. ResolvedMember m = world.resolve(signature);
  212. if (m == null) {
  213. thrownExceptions = Collections.EMPTY_LIST;
  214. } else {
  215. thrownExceptions = collectCheckedExceptions(m.getExceptions());
  216. }
  217. } else {
  218. thrownExceptions = Collections.EMPTY_LIST;
  219. }
  220. }
  221. return thrownExceptions;
  222. }
  223. /**
  224. * The munger must not check for the advice exceptions to be declared by the shadow in the case
  225. * of @AJ aspects so that around can throws Throwable
  226. *
  227. * @return
  228. */
  229. public boolean mustCheckExceptions() {
  230. if (getConcreteAspect() == null) {
  231. return true;
  232. }
  233. return !getConcreteAspect().isAnnotationStyleAspect();
  234. }
  235. // only call me after prepare has been called
  236. public boolean hasDynamicTests() {
  237. // if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  238. // TypeX extraParameterType = getExtraParameterType();
  239. // if (! extraParameterType.equals(TypeX.OBJECT)
  240. // && ! extraParameterType.isPrimitive())
  241. // return true;
  242. // }
  243. return pointcutTest != null &&
  244. !(pointcutTest == Literal.TRUE);// || pointcutTest == Literal.NO_TEST);
  245. }
  246. /**
  247. * get the instruction list for the really simple version of this advice.
  248. * Is broken apart
  249. * for other advice, but if you want it in one block, this is the method to call.
  250. *
  251. * @param s The shadow around which these instructions will eventually live.
  252. * @param extraArgVar The var that will hold the return value or thrown exception
  253. * for afterX advice
  254. * @param ifNoAdvice The instructionHandle to jump to if the dynamic
  255. * tests for this munger fails.
  256. */
  257. InstructionList getAdviceInstructions(
  258. BcelShadow s,
  259. BcelVar extraArgVar,
  260. InstructionHandle ifNoAdvice)
  261. {
  262. BcelShadow shadow = (BcelShadow) s;
  263. InstructionFactory fact = shadow.getFactory();
  264. BcelWorld world = shadow.getWorld();
  265. InstructionList il = new InstructionList();
  266. // we test to see if we have the right kind of thing...
  267. // after throwing does this just by the exception mechanism.
  268. if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  269. TypeX extraParameterType = getExtraParameterType();
  270. if (! extraParameterType.equals(TypeX.OBJECT)
  271. && ! extraParameterType.isPrimitive()) {
  272. il.append(
  273. BcelRenderer.renderTest(
  274. fact,
  275. world,
  276. Test.makeInstanceof(
  277. extraArgVar, getExtraParameterType().resolve(world)),
  278. null,
  279. ifNoAdvice,
  280. null));
  281. }
  282. }
  283. il.append(getAdviceArgSetup(shadow, extraArgVar, null));
  284. il.append(getNonTestAdviceInstructions(shadow));
  285. InstructionHandle ifYesAdvice = il.getStart();
  286. il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice));
  287. return il;
  288. }
  289. public InstructionList getAdviceArgSetup(
  290. BcelShadow shadow,
  291. BcelVar extraVar,
  292. InstructionList closureInstantiation)
  293. {
  294. InstructionFactory fact = shadow.getFactory();
  295. BcelWorld world = shadow.getWorld();
  296. InstructionList il = new InstructionList();
  297. // if (targetAspectField != null) {
  298. // il.append(fact.createFieldAccess(
  299. // targetAspectField.getDeclaringType().getName(),
  300. // targetAspectField.getName(),
  301. // BcelWorld.makeBcelType(targetAspectField.getType()),
  302. // Constants.GETSTATIC));
  303. // }
  304. //
  305. //System.err.println("BcelAdvice: " + exposedState);
  306. if (exposedState.getAspectInstance() != null) {
  307. il.append(
  308. BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance()));
  309. }
  310. for (int i = 0, len = exposedState.size(); i < len; i++) {
  311. if (exposedState.isErroneousVar(i)) continue; // Erroneous vars have already had error msgs reported!
  312. BcelVar v = (BcelVar) exposedState.get(i);
  313. if (v == null) {
  314. // if not @AJ aspect, go on with the regular binding handling
  315. if (getConcreteAspect()==null || !getConcreteAspect().isAnnotationStyleAspect()) {
  316. ;
  317. } else {
  318. // ATAJ: for @AJ aspects, handle implicit binding of xxJoinPoint
  319. if (getKind() == AdviceKind.Around) {
  320. il.append(closureInstantiation);
  321. } else if ("Lorg/aspectj/lang/JoinPoint$StaticPart;".equals(getSignature().getParameterTypes()[i].getSignature())) {
  322. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  323. shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact);
  324. }
  325. } else if ("Lorg/aspectj/lang/JoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) {
  326. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  327. il.append(shadow.loadThisJoinPoint());
  328. }
  329. } else if ("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".equals(getSignature().getParameterTypes()[i].getSignature())) {
  330. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  331. shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact);
  332. }
  333. } else if (hasExtraParameter()) {
  334. extraVar.appendLoadAndConvert(
  335. il,
  336. fact,
  337. getExtraParameterType().resolve(world));
  338. } else {
  339. getConcreteAspect().getWorld().getMessageHandler().handleMessage(
  340. new Message(
  341. "use of ProceedingJoinPoint is allowed only on around advice ("
  342. + "arg " + i + " in " + toString() + ")",
  343. this.getSourceLocation(),
  344. true
  345. )
  346. );
  347. // try to avoid verify error and pass in null
  348. il.append(InstructionConstants.ACONST_NULL);
  349. }
  350. }
  351. } else {
  352. TypeX desiredTy = getSignature().getParameterTypes()[i];
  353. v.appendLoadAndConvert(il, fact, desiredTy.resolve(world));
  354. }
  355. }
  356. // ATAJ: for code style aspect, handles the extraFlag as usual ie not
  357. // in the middle of the formal bindings but at the end, in a rock solid ordering
  358. if (getConcreteAspect()==null || !getConcreteAspect().isAnnotationStyleAspect()) {
  359. if (getKind() == AdviceKind.Around) {
  360. il.append(closureInstantiation);
  361. } else if (hasExtraParameter()) {
  362. extraVar.appendLoadAndConvert(
  363. il,
  364. fact,
  365. getExtraParameterType().resolve(world));
  366. }
  367. // handle thisJoinPoint parameters
  368. // these need to be in that same order as parameters in
  369. // org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration
  370. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  371. shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact);
  372. }
  373. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  374. il.append(shadow.loadThisJoinPoint());
  375. }
  376. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  377. shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact);
  378. }
  379. }
  380. return il;
  381. }
  382. public InstructionList getNonTestAdviceInstructions(BcelShadow shadow) {
  383. return new InstructionList(
  384. Utility.createInvoke(shadow.getFactory(), shadow.getWorld(), getSignature()));
  385. }
  386. public InstructionList getTestInstructions(
  387. BcelShadow shadow,
  388. InstructionHandle sk,
  389. InstructionHandle fk,
  390. InstructionHandle next)
  391. {
  392. //System.err.println("test: " + pointcutTest);
  393. return BcelRenderer.renderTest(
  394. shadow.getFactory(),
  395. shadow.getWorld(),
  396. pointcutTest,
  397. sk,
  398. fk,
  399. next);
  400. }
  401. public int compareTo(Object other) {
  402. if (!(other instanceof BcelAdvice)) return 0;
  403. BcelAdvice o = (BcelAdvice)other;
  404. //System.err.println("compareTo: " + this + ", " + o);
  405. if (kind.getPrecedence() != o.kind.getPrecedence()) {
  406. if (kind.getPrecedence() > o.kind.getPrecedence()) return +1;
  407. else return -1;
  408. }
  409. if (kind.isCflow()) {
  410. // System.err.println("sort: " + this + " innerCflowEntries " + innerCflowEntries);
  411. // System.err.println(" " + o + " innerCflowEntries " + o.innerCflowEntries);
  412. boolean isBelow = (kind == AdviceKind.CflowBelowEntry);
  413. if (this.innerCflowEntries.contains(o)) return isBelow ? +1 : -1;
  414. else if (o.innerCflowEntries.contains(this)) return isBelow ? -1 : +1;
  415. else return 0;
  416. }
  417. if (kind.isPerEntry() || kind == AdviceKind.Softener) {
  418. return 0;
  419. }
  420. //System.out.println("compare: " + this + " with " + other);
  421. World world = concreteAspect.getWorld();
  422. int ret =
  423. concreteAspect.getWorld().compareByDominates(
  424. concreteAspect,
  425. o.concreteAspect);
  426. if (ret != 0) return ret;
  427. ResolvedTypeX declaringAspect = getDeclaringAspect().resolve(world);
  428. ResolvedTypeX o_declaringAspect = o.getDeclaringAspect().resolve(world);
  429. if (declaringAspect == o_declaringAspect) {
  430. if (kind.isAfter() || o.kind.isAfter()) {
  431. return this.getStart() < o.getStart() ? -1: +1;
  432. } else {
  433. return this.getStart()< o.getStart() ? +1: -1;
  434. }
  435. } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) {
  436. return -1;
  437. } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) {
  438. return +1;
  439. } else {
  440. return 0;
  441. }
  442. }
  443. public BcelVar[] getExposedStateAsBcelVars() {
  444. // ATAJ aspect
  445. // the closure instantiation has the same mapping as the extracted method from wich it is called
  446. if (getConcreteAspect()!= null && getConcreteAspect().isAnnotationStyleAspect()) {
  447. return BcelVar.NONE;
  448. }
  449. //System.out.println("vars: " + Arrays.asList(exposedState.vars));
  450. if (exposedState == null) return BcelVar.NONE;
  451. int len = exposedState.vars.length;
  452. BcelVar[] ret = new BcelVar[len];
  453. for (int i=0; i < len; i++) {
  454. ret[i] = (BcelVar)exposedState.vars[i];
  455. }
  456. return ret; //(BcelVar[]) exposedState.vars;
  457. }
  458. public boolean hasMatchedSomething() {
  459. return hasMatchedAtLeastOnce;
  460. }
  461. }