選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

BcelAdvice.java 30KB

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