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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  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. * Alexandre Vasseur support for @AJ aspects
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.lang.reflect.Modifier;
  15. import java.util.ArrayList;
  16. import java.util.Collection;
  17. import java.util.Collections;
  18. import java.util.Map;
  19. import org.aspectj.apache.bcel.Constants;
  20. import org.aspectj.apache.bcel.classfile.LocalVariable;
  21. import org.aspectj.apache.bcel.classfile.LocalVariableTable;
  22. import org.aspectj.apache.bcel.generic.InstructionConstants;
  23. import org.aspectj.apache.bcel.generic.InstructionFactory;
  24. import org.aspectj.apache.bcel.generic.InstructionHandle;
  25. import org.aspectj.apache.bcel.generic.InstructionList;
  26. import org.aspectj.apache.bcel.generic.LineNumberTag;
  27. import org.aspectj.apache.bcel.generic.LocalVariableTag;
  28. import org.aspectj.bridge.ISourceLocation;
  29. import org.aspectj.bridge.Message;
  30. import org.aspectj.weaver.Advice;
  31. import org.aspectj.weaver.AdviceKind;
  32. import org.aspectj.weaver.AjAttribute;
  33. import org.aspectj.weaver.BCException;
  34. import org.aspectj.weaver.IEclipseSourceContext;
  35. import org.aspectj.weaver.ISourceContext;
  36. import org.aspectj.weaver.Lint;
  37. import org.aspectj.weaver.Member;
  38. import org.aspectj.weaver.ReferenceType;
  39. import org.aspectj.weaver.ReferenceTypeDelegate;
  40. import org.aspectj.weaver.ResolvedMember;
  41. import org.aspectj.weaver.ResolvedMemberImpl;
  42. import org.aspectj.weaver.ResolvedType;
  43. import org.aspectj.weaver.Shadow;
  44. import org.aspectj.weaver.ShadowMunger;
  45. import org.aspectj.weaver.UnresolvedType;
  46. import org.aspectj.weaver.WeaverMessages;
  47. import org.aspectj.weaver.World;
  48. import org.aspectj.weaver.ast.Literal;
  49. import org.aspectj.weaver.ast.Test;
  50. import org.aspectj.weaver.patterns.ExactTypePattern;
  51. import org.aspectj.weaver.patterns.ExposedState;
  52. import org.aspectj.weaver.patterns.PerClause;
  53. import org.aspectj.weaver.patterns.Pointcut;
  54. /**
  55. * Advice implemented for BCEL
  56. *
  57. * @author Erik Hilsdale
  58. * @author Jim Hugunin
  59. * @author Andy Clement
  60. */
  61. class BcelAdvice extends Advice {
  62. /**
  63. * If a match is not entirely statically determinable, this captures the runtime test that must succeed in order for the advice
  64. * to run.
  65. */
  66. private Test runtimeTest;
  67. private ExposedState exposedState;
  68. private int containsInvokedynamic = 0;// 0 = dontknow, 1=no, 2=yes
  69. public BcelAdvice(AjAttribute.AdviceAttribute attribute, Pointcut pointcut, Member adviceSignature, ResolvedType concreteAspect) {
  70. super(attribute, pointcut, simplify(attribute.getKind(), adviceSignature));
  71. this.concreteAspect = concreteAspect;
  72. }
  73. public boolean bindsProceedingJoinPoint() {
  74. UnresolvedType[] parameterTypes = signature.getParameterTypes();
  75. for (int i=0;i<parameterTypes.length;i++) {
  76. if (parameterTypes[i].equals(UnresolvedType.PROCEEDING_JOINPOINT)) {
  77. return true;
  78. }
  79. }
  80. return false;
  81. }
  82. /**
  83. * A heavyweight BcelMethod object is only required for around advice that will be inlined. For other kinds of advice it is
  84. * possible to save some space.
  85. */
  86. private static Member simplify(AdviceKind kind, Member adviceSignature) {
  87. if (adviceSignature != null) {
  88. UnresolvedType adviceDeclaringType = adviceSignature.getDeclaringType();
  89. // if it isnt around advice or it is but inlining is turned off then shrink it to a ResolvedMemberImpl
  90. if (kind != AdviceKind.Around
  91. || ((adviceDeclaringType instanceof ResolvedType) && ((ResolvedType) adviceDeclaringType).getWorld()
  92. .isXnoInline())) {
  93. if (adviceSignature instanceof BcelMethod) {
  94. BcelMethod bm = (BcelMethod) adviceSignature;
  95. if (bm.getMethod() != null && bm.getMethod().getAnnotations() != null) {
  96. return adviceSignature;
  97. }
  98. ResolvedMemberImpl simplermember = new ResolvedMemberImpl(bm.getKind(), bm.getDeclaringType(),
  99. bm.getModifiers(), bm.getReturnType(), bm.getName(), bm.getParameterTypes());// ,bm.getExceptions(),bm.getBackingGenericMember()
  100. // );
  101. simplermember.setParameterNames(bm.getParameterNames());
  102. return simplermember;
  103. }
  104. }
  105. }
  106. return adviceSignature;
  107. }
  108. @Override
  109. public ShadowMunger concretize(ResolvedType fromType, World world, PerClause clause) {
  110. if (!world.areAllLintIgnored()) {
  111. suppressLintWarnings(world);
  112. }
  113. ShadowMunger ret = super.concretize(fromType, world, clause);
  114. if (!world.areAllLintIgnored()) {
  115. clearLintSuppressions(world, this.suppressedLintKinds);
  116. }
  117. IfFinder ifinder = new IfFinder();
  118. ret.getPointcut().accept(ifinder, null);
  119. boolean hasGuardTest = ifinder.hasIf && getKind() != AdviceKind.Around;
  120. boolean isAround = getKind() == AdviceKind.Around;
  121. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  122. if (!isAround && !hasGuardTest && world.getLint().noGuardForLazyTjp.isEnabled()) {
  123. // can't build tjp lazily, no suitable test...
  124. // ... only want to record it once against the advice(bug 133117)
  125. world.getLint().noGuardForLazyTjp.signal("", getSourceLocation());
  126. }
  127. }
  128. return ret;
  129. }
  130. @Override
  131. public ShadowMunger parameterizeWith(ResolvedType declaringType, Map<String, UnresolvedType> typeVariableMap) {
  132. Pointcut pc = getPointcut().parameterizeWith(typeVariableMap, declaringType.getWorld());
  133. BcelAdvice ret = null;
  134. Member adviceSignature = signature;
  135. // allows for around advice where the return value is a type variable (see pr115250)
  136. if (signature instanceof ResolvedMember && signature.getDeclaringType().isGenericType()) {
  137. adviceSignature = ((ResolvedMember) signature).parameterizedWith(declaringType.getTypeParameters(), declaringType,
  138. declaringType.isParameterizedType());
  139. }
  140. ret = new BcelAdvice(this.attribute, pc, adviceSignature, this.concreteAspect);
  141. return ret;
  142. }
  143. @Override
  144. public boolean match(Shadow shadow, World world) {
  145. if (world.areAllLintIgnored()) {
  146. return super.match(shadow, world);
  147. } else {
  148. suppressLintWarnings(world);
  149. boolean ret = super.match(shadow, world);
  150. clearLintSuppressions(world, this.suppressedLintKinds);
  151. return ret;
  152. }
  153. }
  154. @Override
  155. public void specializeOn(Shadow shadow) {
  156. if (getKind() == AdviceKind.Around) {
  157. ((BcelShadow) shadow).initializeForAroundClosure();
  158. }
  159. // XXX this case is just here for supporting lazy test code
  160. if (getKind() == null) {
  161. exposedState = new ExposedState(0);
  162. return;
  163. }
  164. if (getKind().isPerEntry()) {
  165. exposedState = new ExposedState(0);
  166. } else if (getKind().isCflow()) {
  167. exposedState = new ExposedState(nFreeVars);
  168. } else if (getSignature() != null) {
  169. exposedState = new ExposedState(getSignature());
  170. } else {
  171. exposedState = new ExposedState(0);
  172. return; // XXX this case is just here for supporting lazy test code
  173. }
  174. World world = shadow.getIWorld();
  175. if (!world.areAllLintIgnored()) {
  176. suppressLintWarnings(world);
  177. }
  178. exposedState.setConcreteAspect(concreteAspect);
  179. runtimeTest = getPointcut().findResidue(shadow, exposedState);
  180. if (!world.areAllLintIgnored()) {
  181. clearLintSuppressions(world, this.suppressedLintKinds);
  182. }
  183. // these initializations won't be performed by findResidue, but need to be
  184. // so that the joinpoint is primed for weaving
  185. if (getKind() == AdviceKind.PerThisEntry) {
  186. shadow.getThisVar();
  187. } else if (getKind() == AdviceKind.PerTargetEntry) {
  188. shadow.getTargetVar();
  189. }
  190. // make sure thisJoinPoint parameters are initialized
  191. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  192. ((BcelShadow) shadow).getThisJoinPointStaticPartVar();
  193. ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation());
  194. }
  195. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  196. boolean hasGuardTest = runtimeTest != Literal.TRUE && getKind() != AdviceKind.Around;
  197. boolean isAround = getKind() == AdviceKind.Around;
  198. ((BcelShadow) shadow).requireThisJoinPoint(hasGuardTest, isAround);
  199. ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation());
  200. if (!hasGuardTest && world.getLint().multipleAdviceStoppingLazyTjp.isEnabled()) {
  201. // collect up the problematic advice
  202. ((BcelShadow) shadow).addAdvicePreventingLazyTjp(this);
  203. }
  204. }
  205. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  206. ((BcelShadow) shadow).getThisEnclosingJoinPointStaticPartVar();
  207. ((BcelShadow) shadow).getEnclosingClass().warnOnAddedStaticInitializer(shadow, getSourceLocation());
  208. }
  209. }
  210. private boolean canInline(Shadow s) {
  211. if (attribute.isProceedInInners()) {
  212. return false;
  213. }
  214. // XXX this guard seems to only be needed for bad test cases
  215. if (concreteAspect == null || concreteAspect.isMissing()) {
  216. return false;
  217. }
  218. if (concreteAspect.getWorld().isXnoInline()) {
  219. return false;
  220. }
  221. // System.err.println("isWoven? " + ((BcelObjectType)concreteAspect).getLazyClassGen().getWeaverState());
  222. BcelObjectType boType = BcelWorld.getBcelObjectType(concreteAspect);
  223. if (boType == null) {
  224. // Could be a symptom that the aspect failed to build last build... return the default answer of false
  225. return false;
  226. }
  227. // Need isJava8 check
  228. // Does the advice contain invokedynamic...
  229. if (boType.javaClass.getMajor() >= Constants.MAJOR_1_8) {
  230. if (containsInvokedynamic == 0) {
  231. containsInvokedynamic = 1;
  232. LazyMethodGen lmg = boType.getLazyClassGen().getLazyMethodGen(this.signature.getName(), this.signature.getSignature(), true);
  233. // Check Java8 supertypes
  234. ResolvedType searchType = concreteAspect;
  235. while (lmg == null) {
  236. searchType = searchType.getSuperclass();
  237. if (searchType == null) break;
  238. ReferenceTypeDelegate rtd = ((ReferenceType)searchType).getDelegate();
  239. if (rtd instanceof BcelObjectType) {
  240. BcelObjectType bot = (BcelObjectType)rtd;
  241. if (bot.javaClass.getMajor() < Constants.MAJOR_1_8) {
  242. break;
  243. }
  244. lmg = bot.getLazyClassGen().getLazyMethodGen(this.signature.getName(), this.signature.getSignature(), true);
  245. }
  246. }
  247. if (lmg != null) {
  248. InstructionList ilist = lmg.getBody();
  249. for (InstructionHandle src = ilist.getStart(); src != null; src = src.getNext()) {
  250. if (src.getInstruction().opcode == Constants.INVOKEDYNAMIC) {
  251. containsInvokedynamic = 2;
  252. break;
  253. }
  254. }
  255. }
  256. }
  257. }
  258. if (containsInvokedynamic == 2) {
  259. return false;
  260. }
  261. return boType.getLazyClassGen().isWoven();
  262. }
  263. private boolean aspectIsBroken() {
  264. if (concreteAspect instanceof ReferenceType) {
  265. ReferenceTypeDelegate rtDelegate = ((ReferenceType) concreteAspect).getDelegate();
  266. if (!(rtDelegate instanceof BcelObjectType)) {
  267. return true;
  268. }
  269. }
  270. return false;
  271. }
  272. @Override
  273. public boolean implementOn(Shadow s) {
  274. hasMatchedAtLeastOnce = true;
  275. // pr263323 - if the aspect is broken then the delegate will not be usable for weaving
  276. if (aspectIsBroken()) {
  277. return false;
  278. }
  279. BcelShadow shadow = (BcelShadow) s;
  280. // remove any unnecessary exceptions if the compiler option is set to
  281. // error or warning and if this piece of advice throws exceptions
  282. // (bug 129282). This may be expanded to include other compiler warnings
  283. // at the moment it only deals with 'declared exception is not thrown'
  284. if (!shadow.getWorld().isIgnoringUnusedDeclaredThrownException() && !getThrownExceptions().isEmpty()) {
  285. Member member = shadow.getSignature();
  286. if (member instanceof BcelMethod) {
  287. removeUnnecessaryProblems((BcelMethod) member, ((BcelMethod) member).getDeclarationLineNumber());
  288. } else {
  289. // we're in a call shadow therefore need the line number of the
  290. // declared method (which may be in a different type). However,
  291. // we want to remove the problems from the CompilationResult
  292. // held within the current type's EclipseSourceContext so need
  293. // the enclosing shadow too
  294. ResolvedMember resolvedMember = shadow.getSignature().resolve(shadow.getWorld());
  295. if (resolvedMember instanceof BcelMethod && shadow.getEnclosingShadow() instanceof BcelShadow) {
  296. Member enclosingMember = shadow.getEnclosingShadow().getSignature();
  297. if (enclosingMember instanceof BcelMethod) {
  298. removeUnnecessaryProblems((BcelMethod) enclosingMember,
  299. ((BcelMethod) resolvedMember).getDeclarationLineNumber());
  300. }
  301. }
  302. }
  303. }
  304. if (shadow.getIWorld().isJoinpointSynchronizationEnabled() && shadow.getKind() == Shadow.MethodExecution
  305. && (s.getSignature().getModifiers() & Modifier.SYNCHRONIZED) != 0) {
  306. shadow.getIWorld().getLint().advisingSynchronizedMethods.signal(new String[] { shadow.toString() },
  307. shadow.getSourceLocation(), new ISourceLocation[] { getSourceLocation() });
  308. }
  309. // FIXME AV - see #75442, this logic is not enough so for now comment it out until we fix the bug
  310. // // callback for perObject AJC MightHaveAspect postMunge (#75442)
  311. // if (getConcreteAspect() != null
  312. // && getConcreteAspect().getPerClause() != null
  313. // && PerClause.PEROBJECT.equals(getConcreteAspect().getPerClause().getKind())) {
  314. // final PerObject clause;
  315. // if (getConcreteAspect().getPerClause() instanceof PerFromSuper) {
  316. // clause = (PerObject)((PerFromSuper) getConcreteAspect().getPerClause()).lookupConcretePerClause(getConcreteAspect());
  317. // } else {
  318. // clause = (PerObject) getConcreteAspect().getPerClause();
  319. // }
  320. // if (clause.isThis()) {
  321. // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getThisVar().getType(), getConcreteAspect());
  322. // } else {
  323. // PerObjectInterfaceTypeMunger.registerAsAdvisedBy(s.getTargetVar().getType(), getConcreteAspect());
  324. // }
  325. // }
  326. if (runtimeTest == Literal.FALSE) { // not usually allowed, except in one case (260384)
  327. Member sig = shadow.getSignature();
  328. if (sig.getArity() == 0 && shadow.getKind() == Shadow.MethodCall && sig.getName().charAt(0) == 'c'
  329. && sig.getReturnType().equals(ResolvedType.OBJECT) && sig.getName().equals("clone")) {
  330. return false;
  331. }
  332. }
  333. if (getKind() == AdviceKind.Before) {
  334. shadow.weaveBefore(this);
  335. } else if (getKind() == AdviceKind.AfterReturning) {
  336. shadow.weaveAfterReturning(this);
  337. } else if (getKind() == AdviceKind.AfterThrowing) {
  338. UnresolvedType catchType = hasExtraParameter() ? getExtraParameterType() : UnresolvedType.THROWABLE;
  339. shadow.weaveAfterThrowing(this, catchType);
  340. } else if (getKind() == AdviceKind.After) {
  341. shadow.weaveAfter(this);
  342. } else if (getKind() == AdviceKind.Around) {
  343. // Note: under regular LTW the aspect is usually loaded after the first use of any class affected by it.
  344. // This means that as long as the aspect has not been thru the LTW, it's woven state is unknown
  345. // and thus canInline(s) will return false.
  346. // To force inlining (test), ones can do Class aspect = FQNAspect.class in the clinit of the target class
  347. // FIXME AV : for AJC compiled @AJ aspect (or any code style aspect), the woven state can never be known
  348. // if the aspect belongs to a parent classloader. In that case the aspect will never be inlined.
  349. // It might be dangerous to change that especially for @AJ aspect non compiled with AJC since if those
  350. // are not weaved (f.e. use of some limited LTW etc) then they cannot be prepared for inlining.
  351. // One solution would be to flag @AJ aspect with an annotation as "prepared" and query that one.
  352. LazyClassGen enclosingClass = shadow.getEnclosingClass();
  353. if (enclosingClass != null && enclosingClass.isInterface() && shadow.getEnclosingMethod().getName().charAt(0) == '<') {
  354. // Do not add methods with bodies to an interface (252198, 163005)
  355. shadow.getWorld().getLint().cannotAdviseJoinpointInInterfaceWithAroundAdvice.signal(shadow.toString(),
  356. shadow.getSourceLocation());
  357. return false;
  358. }
  359. if (!canInline(s)) {
  360. shadow.weaveAroundClosure(this, hasDynamicTests());
  361. } else {
  362. shadow.weaveAroundInline(this, hasDynamicTests());
  363. }
  364. } else if (getKind() == AdviceKind.InterInitializer) {
  365. shadow.weaveAfterReturning(this);
  366. } else if (getKind().isCflow()) {
  367. shadow.weaveCflowEntry(this, getSignature());
  368. } else if (getKind() == AdviceKind.PerThisEntry) {
  369. shadow.weavePerObjectEntry(this, (BcelVar) shadow.getThisVar());
  370. } else if (getKind() == AdviceKind.PerTargetEntry) {
  371. shadow.weavePerObjectEntry(this, (BcelVar) shadow.getTargetVar());
  372. } else if (getKind() == AdviceKind.Softener) {
  373. shadow.weaveSoftener(this, ((ExactTypePattern) exceptionType).getType());
  374. } else if (getKind() == AdviceKind.PerTypeWithinEntry) {
  375. // PTWIMPL Entry to ptw is the static initialization of a type that matched the ptw type pattern
  376. shadow.weavePerTypeWithinAspectInitialization(this, shadow.getEnclosingType());
  377. } else {
  378. throw new BCException("unimplemented kind: " + getKind());
  379. }
  380. return true;
  381. }
  382. private void removeUnnecessaryProblems(BcelMethod method, int problemLineNumber) {
  383. ISourceContext sourceContext = method.getSourceContext();
  384. if (sourceContext instanceof IEclipseSourceContext) {
  385. ((IEclipseSourceContext) sourceContext).removeUnnecessaryProblems(method, problemLineNumber);
  386. }
  387. }
  388. // ---- implementations
  389. private Collection<ResolvedType> collectCheckedExceptions(UnresolvedType[] excs) {
  390. if (excs == null || excs.length == 0) {
  391. return Collections.emptyList();
  392. }
  393. Collection<ResolvedType> ret = new ArrayList<ResolvedType>();
  394. World world = concreteAspect.getWorld();
  395. ResolvedType runtimeException = world.getCoreType(UnresolvedType.RUNTIME_EXCEPTION);
  396. ResolvedType error = world.getCoreType(UnresolvedType.ERROR);
  397. for (int i = 0, len = excs.length; i < len; i++) {
  398. ResolvedType t = world.resolve(excs[i], true);
  399. if (t.isMissing()) {
  400. world.getLint().cantFindType
  401. .signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_EXCEPTION_TYPE, excs[i].getName()),
  402. getSourceLocation());
  403. // IMessage msg = new Message(
  404. // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_EXCEPTION_TYPE,excs[i].getName()),
  405. // "",IMessage.ERROR,getSourceLocation(),null,null);
  406. // world.getMessageHandler().handleMessage(msg);
  407. }
  408. if (!(runtimeException.isAssignableFrom(t) || error.isAssignableFrom(t))) {
  409. ret.add(t);
  410. }
  411. }
  412. return ret;
  413. }
  414. private Collection<ResolvedType> thrownExceptions = null;
  415. @Override
  416. public Collection<ResolvedType> getThrownExceptions() {
  417. if (thrownExceptions == null) {
  418. // ??? can we really lump in Around here, how does this interact with Throwable
  419. if (concreteAspect != null && concreteAspect.getWorld() != null && // null tests for test harness
  420. (getKind().isAfter() || getKind() == AdviceKind.Before || getKind() == AdviceKind.Around)) {
  421. World world = concreteAspect.getWorld();
  422. ResolvedMember m = world.resolve(signature);
  423. if (m == null) {
  424. thrownExceptions = Collections.emptyList();
  425. } else {
  426. thrownExceptions = collectCheckedExceptions(m.getExceptions());
  427. }
  428. } else {
  429. thrownExceptions = Collections.emptyList();
  430. }
  431. }
  432. return thrownExceptions;
  433. }
  434. /**
  435. * The munger must not check for the advice exceptions to be declared by the shadow in the case of @AJ aspects so that around
  436. * can throws Throwable
  437. *
  438. * @return
  439. */
  440. @Override
  441. public boolean mustCheckExceptions() {
  442. if (getConcreteAspect() == null) {
  443. return true;
  444. }
  445. return !getConcreteAspect().isAnnotationStyleAspect();
  446. }
  447. // only call me after prepare has been called
  448. @Override
  449. public boolean hasDynamicTests() {
  450. // if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  451. // UnresolvedType extraParameterType = getExtraParameterType();
  452. // if (! extraParameterType.equals(UnresolvedType.OBJECT)
  453. // && ! extraParameterType.isPrimitive())
  454. // return true;
  455. // }
  456. return runtimeTest != null && !(runtimeTest == Literal.TRUE);// || pointcutTest == Literal.NO_TEST);
  457. }
  458. /**
  459. * get the instruction list for the really simple version of this advice. Is broken apart for other advice, but if you want it
  460. * in one block, this is the method to call.
  461. *
  462. * @param s The shadow around which these instructions will eventually live.
  463. * @param extraArgVar The var that will hold the return value or thrown exception for afterX advice
  464. * @param ifNoAdvice The instructionHandle to jump to if the dynamic tests for this munger fails.
  465. */
  466. InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) {
  467. BcelShadow shadow = s;
  468. InstructionFactory fact = shadow.getFactory();
  469. BcelWorld world = shadow.getWorld();
  470. InstructionList il = new InstructionList();
  471. // we test to see if we have the right kind of thing...
  472. // after throwing does this just by the exception mechanism.
  473. if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) {
  474. UnresolvedType extraParameterType = getExtraParameterType();
  475. if (!extraParameterType.equals(UnresolvedType.OBJECT) && !extraParameterType.isPrimitiveType()) {
  476. il.append(BcelRenderer.renderTest(fact, world,
  477. Test.makeInstanceof(extraArgVar, getExtraParameterType().resolve(world)), null, ifNoAdvice, null));
  478. }
  479. }
  480. il.append(getAdviceArgSetup(shadow, extraArgVar, null));
  481. il.append(getNonTestAdviceInstructions(shadow));
  482. InstructionHandle ifYesAdvice = il.getStart();
  483. il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice));
  484. // If inserting instructions at the start of a method, we need a nice line number for this entry
  485. // in the stack trace
  486. if (shadow.getKind() == Shadow.MethodExecution && getKind() == AdviceKind.Before) {
  487. int lineNumber = 0;
  488. // Uncomment this code if you think we should use the method decl line number when it exists...
  489. // // If the advised join point is in a class built by AspectJ, we can use the declaration line number
  490. // boolean b = shadow.getEnclosingMethod().getMemberView().hasDeclarationLineNumberInfo();
  491. // if (b) {
  492. // lineNumber = shadow.getEnclosingMethod().getMemberView().getDeclarationLineNumber();
  493. // } else { // If it wasn't, the best we can do is the line number of the first instruction in the method
  494. lineNumber = shadow.getEnclosingMethod().getMemberView().getLineNumberOfFirstInstruction();
  495. // }
  496. InstructionHandle start = il.getStart();
  497. if (lineNumber > 0) {
  498. start.addTargeter(new LineNumberTag(lineNumber));
  499. }
  500. // Fix up the local variables: find any that have a startPC of 0 and ensure they target the new start of the method
  501. LocalVariableTable lvt = shadow.getEnclosingMethod().getMemberView().getMethod().getLocalVariableTable();
  502. if (lvt != null) {
  503. LocalVariable[] lvTable = lvt.getLocalVariableTable();
  504. for (int i = 0; i < lvTable.length; i++) {
  505. LocalVariable lv = lvTable[i];
  506. if (lv.getStartPC() == 0) {
  507. start.addTargeter(new LocalVariableTag(lv.getSignature(), lv.getName(), lv.getIndex(), 0));
  508. }
  509. }
  510. }
  511. }
  512. return il;
  513. }
  514. public InstructionList getAdviceArgSetup(BcelShadow shadow, BcelVar extraVar, InstructionList closureInstantiation) {
  515. InstructionFactory fact = shadow.getFactory();
  516. BcelWorld world = shadow.getWorld();
  517. InstructionList il = new InstructionList();
  518. // if (targetAspectField != null) {
  519. // il.append(fact.createFieldAccess(
  520. // targetAspectField.getDeclaringType().getName(),
  521. // targetAspectField.getName(),
  522. // BcelWorld.makeBcelType(targetAspectField.getType()),
  523. // Constants.GETSTATIC));
  524. // }
  525. //
  526. // System.err.println("BcelAdvice: " + exposedState);
  527. if (exposedState.getAspectInstance() != null) {
  528. il.append(BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance()));
  529. }
  530. // pr121385
  531. boolean x = this.getDeclaringAspect().resolve(world).isAnnotationStyleAspect();
  532. final boolean isAnnotationStyleAspect = getConcreteAspect() != null && getConcreteAspect().isAnnotationStyleAspect() && x;
  533. boolean previousIsClosure = false;
  534. for (int i = 0, len = exposedState.size(); i < len; i++) {
  535. if (exposedState.isErroneousVar(i)) {
  536. continue; // Erroneous vars have already had error msgs reported!
  537. }
  538. BcelVar v = (BcelVar) exposedState.get(i);
  539. if (v == null) {
  540. // if not @AJ aspect, go on with the regular binding handling
  541. if (!isAnnotationStyleAspect) {
  542. } else {
  543. // ATAJ: for @AJ aspects, handle implicit binding of xxJoinPoint
  544. // if (getKind() == AdviceKind.Around) {
  545. // previousIsClosure = true;
  546. // il.append(closureInstantiation);
  547. if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) {
  548. // make sure we are in an around, since we deal with the closure, not the arg here
  549. if (getKind() != AdviceKind.Around) {
  550. previousIsClosure = false;
  551. getConcreteAspect()
  552. .getWorld()
  553. .getMessageHandler()
  554. .handleMessage(
  555. new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg "
  556. + i + " in " + toString() + ")", this.getSourceLocation(), true));
  557. // try to avoid verify error and pass in null
  558. il.append(InstructionConstants.ACONST_NULL);
  559. } else {
  560. if (previousIsClosure) {
  561. il.append(InstructionConstants.DUP);
  562. } else {
  563. previousIsClosure = true;
  564. il.append(closureInstantiation.copy());
  565. shadow.closureVarInitialized = true;
  566. }
  567. }
  568. } else if ("Lorg/aspectj/lang/JoinPoint$StaticPart;".equals(getSignature().getParameterTypes()[i]
  569. .getSignature())) {
  570. previousIsClosure = false;
  571. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  572. shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact);
  573. }
  574. } else if ("Lorg/aspectj/lang/JoinPoint;".equals(getSignature().getParameterTypes()[i].getSignature())) {
  575. previousIsClosure = false;
  576. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  577. il.append(shadow.loadThisJoinPoint());
  578. }
  579. } else if ("Lorg/aspectj/lang/JoinPoint$EnclosingStaticPart;".equals(getSignature().getParameterTypes()[i]
  580. .getSignature())) {
  581. previousIsClosure = false;
  582. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  583. shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact);
  584. }
  585. } else if (hasExtraParameter()) {
  586. previousIsClosure = false;
  587. extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world));
  588. } else {
  589. previousIsClosure = false;
  590. getConcreteAspect()
  591. .getWorld()
  592. .getMessageHandler()
  593. .handleMessage(
  594. new Message("use of ProceedingJoinPoint is allowed only on around advice (" + "arg " + i
  595. + " in " + toString() + ")", this.getSourceLocation(), true));
  596. // try to avoid verify error and pass in null
  597. il.append(InstructionConstants.ACONST_NULL);
  598. }
  599. }
  600. } else {
  601. UnresolvedType desiredTy = getBindingParameterTypes()[i];
  602. v.appendLoadAndConvert(il, fact, desiredTy.resolve(world));
  603. }
  604. }
  605. // ATAJ: for code style aspect, handles the extraFlag as usual ie not
  606. // in the middle of the formal bindings but at the end, in a rock solid ordering
  607. if (!isAnnotationStyleAspect) {
  608. if (getKind() == AdviceKind.Around) {
  609. il.append(closureInstantiation);
  610. } else if (hasExtraParameter()) {
  611. extraVar.appendLoadAndConvert(il, fact, getExtraParameterType().resolve(world));
  612. }
  613. // handle thisJoinPoint parameters
  614. // these need to be in that same order as parameters in
  615. // org.aspectj.ajdt.internal.compiler.ast.AdviceDeclaration
  616. if ((getExtraParameterFlags() & ThisJoinPointStaticPart) != 0) {
  617. shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact);
  618. }
  619. if ((getExtraParameterFlags() & ThisJoinPoint) != 0) {
  620. il.append(shadow.loadThisJoinPoint());
  621. }
  622. if ((getExtraParameterFlags() & ThisEnclosingJoinPointStaticPart) != 0) {
  623. shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact);
  624. }
  625. }
  626. return il;
  627. }
  628. public InstructionList getNonTestAdviceInstructions(BcelShadow shadow) {
  629. return new InstructionList(Utility.createInvoke(shadow.getFactory(), shadow.getWorld(), getOriginalSignature()));
  630. }
  631. @Override
  632. public Member getOriginalSignature() {
  633. Member sig = getSignature();
  634. if (sig instanceof ResolvedMember) {
  635. ResolvedMember rsig = (ResolvedMember) sig;
  636. if (rsig.hasBackingGenericMember()) {
  637. return rsig.getBackingGenericMember();
  638. }
  639. }
  640. return sig;
  641. }
  642. public InstructionList getTestInstructions(BcelShadow shadow, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) {
  643. // System.err.println("test: " + pointcutTest);
  644. return BcelRenderer.renderTest(shadow.getFactory(), shadow.getWorld(), runtimeTest, sk, fk, next);
  645. }
  646. public int compareTo(Object other) {
  647. if (!(other instanceof BcelAdvice)) {
  648. return 0;
  649. }
  650. BcelAdvice o = (BcelAdvice) other;
  651. // System.err.println("compareTo: " + this + ", " + o);
  652. if (kind.getPrecedence() != o.kind.getPrecedence()) {
  653. if (kind.getPrecedence() > o.kind.getPrecedence()) {
  654. return +1;
  655. } else {
  656. return -1;
  657. }
  658. }
  659. if (kind.isCflow()) {
  660. // System.err.println("sort: " + this + " innerCflowEntries " + innerCflowEntries);
  661. // System.err.println(" " + o + " innerCflowEntries " + o.innerCflowEntries);
  662. boolean isBelow = (kind == AdviceKind.CflowBelowEntry);
  663. if (this.innerCflowEntries.contains(o)) {
  664. return isBelow ? +1 : -1;
  665. } else if (o.innerCflowEntries.contains(this)) {
  666. return isBelow ? -1 : +1;
  667. } else {
  668. return 0;
  669. }
  670. }
  671. if (kind.isPerEntry() || kind == AdviceKind.Softener) {
  672. return 0;
  673. }
  674. // System.out.println("compare: " + this + " with " + other);
  675. World world = concreteAspect.getWorld();
  676. int ret = concreteAspect.getWorld().compareByPrecedence(concreteAspect, o.concreteAspect);
  677. if (ret != 0) {
  678. return ret;
  679. }
  680. ResolvedType declaringAspect = getDeclaringAspect().resolve(world);
  681. ResolvedType o_declaringAspect = o.getDeclaringAspect().resolve(world);
  682. if (declaringAspect == o_declaringAspect) {
  683. if (kind.isAfter() || o.kind.isAfter()) {
  684. return this.getStart() < o.getStart() ? -1 : +1;
  685. } else {
  686. return this.getStart() < o.getStart() ? +1 : -1;
  687. }
  688. } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) {
  689. return -1;
  690. } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) {
  691. return +1;
  692. } else {
  693. return 0;
  694. }
  695. }
  696. public BcelVar[] getExposedStateAsBcelVars(boolean isAround) {
  697. // ATAJ aspect
  698. if (isAround) {
  699. // the closure instantiation has the same mapping as the extracted method from wich it is called
  700. if (getConcreteAspect() != null && getConcreteAspect().isAnnotationStyleAspect()) {
  701. return BcelVar.NONE;
  702. }
  703. }
  704. // System.out.println("vars: " + Arrays.asList(exposedState.vars));
  705. if (exposedState == null) {
  706. return BcelVar.NONE;
  707. }
  708. int len = exposedState.vars.length;
  709. BcelVar[] ret = new BcelVar[len];
  710. for (int i = 0; i < len; i++) {
  711. ret[i] = (BcelVar) exposedState.vars[i];
  712. }
  713. return ret; // (BcelVar[]) exposedState.vars;
  714. }
  715. protected void suppressLintWarnings(World inWorld) {
  716. if (suppressedLintKinds == null) {
  717. if (signature instanceof BcelMethod) {
  718. this.suppressedLintKinds = Utility.getSuppressedWarnings(signature.getAnnotations(), inWorld.getLint());
  719. } else {
  720. this.suppressedLintKinds = Collections.emptyList();
  721. return;
  722. }
  723. }
  724. inWorld.getLint().suppressKinds(suppressedLintKinds);
  725. }
  726. protected void clearLintSuppressions(World inWorld, Collection<Lint.Kind> toClear) {
  727. inWorld.getLint().clearSuppressions(toClear);
  728. }
  729. /**
  730. * For testing only
  731. */
  732. public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature, int extraArgumentFlags, int start, int end,
  733. ISourceContext sourceContext, ResolvedType concreteAspect) {
  734. this(new AjAttribute.AdviceAttribute(kind, pointcut, extraArgumentFlags, start, end, sourceContext), pointcut, signature,
  735. concreteAspect);
  736. thrownExceptions = Collections.emptyList(); // !!! interaction with unit tests
  737. }
  738. }