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.

AdviceDeclaration.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import org.aspectj.ajdt.internal.compiler.lookup.AjTypeConstants;
  17. import org.aspectj.ajdt.internal.compiler.lookup.EclipseFactory;
  18. import org.aspectj.ajdt.internal.compiler.lookup.PrivilegedHandler;
  19. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  20. import org.aspectj.bridge.context.ContextToken;
  21. import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Annotation;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Argument;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeReference;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
  30. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  31. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  32. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  33. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  34. import org.aspectj.weaver.Advice;
  35. import org.aspectj.weaver.AdviceKind;
  36. import org.aspectj.weaver.AjAttribute;
  37. import org.aspectj.weaver.NameMangler;
  38. import org.aspectj.weaver.ResolvedMember;
  39. import org.aspectj.weaver.UnresolvedType;
  40. /**
  41. * Represents before, after and around advice in an aspect.
  42. * Will generate a method corresponding to the body of the advice with an
  43. * attribute including additional information.
  44. *
  45. * @author Jim Hugunin
  46. */
  47. public class AdviceDeclaration extends AjMethodDeclaration {
  48. public PointcutDesignator pointcutDesignator; // set during parsing
  49. int baseArgumentCount; // referenced by IfPseudoToken.makeArguments
  50. public Argument extraArgument; // set during parsing, referenced by Proceed
  51. public AdviceKind kind; // set during parsing, referenced by Proceed and AsmElementFormatter
  52. private int extraArgumentFlags = 0;
  53. public MethodBinding proceedMethodBinding; // set during this.resolveStaments, referenced by Proceed
  54. public List proceedCalls = new ArrayList(2); // populated during Proceed.findEnclosingAround
  55. private boolean proceedInInners;
  56. private ResolvedMember[] proceedCallSignatures;
  57. private boolean[] formalsUnchangedToProceed;
  58. private UnresolvedType[] declaredExceptions;
  59. public AdviceDeclaration(CompilationResult result, AdviceKind kind) {
  60. super(result);
  61. this.returnType = TypeReference.baseTypeReference(T_void, 0);
  62. this.kind = kind;
  63. }
  64. // override
  65. protected int generateInfoAttributes(ClassFile classFile) {
  66. List l = new ArrayList(1);
  67. l.add(new EclipseAttributeAdapter(makeAttribute()));
  68. addDeclarationStartLineAttribute(l,classFile);
  69. return classFile.generateMethodInfoAttribute(binding, false, l);
  70. }
  71. private AjAttribute makeAttribute() {
  72. if (kind == AdviceKind.Around) {
  73. return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(),
  74. extraArgumentFlags, sourceStart, sourceEnd, null,
  75. proceedInInners, proceedCallSignatures, formalsUnchangedToProceed,
  76. declaredExceptions);
  77. } else {
  78. return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(),
  79. extraArgumentFlags, sourceStart, sourceEnd, null);
  80. }
  81. }
  82. // override
  83. public void resolveStatements() {
  84. if (binding == null || ignoreFurtherInvestigation) return;
  85. ClassScope upperScope = (ClassScope)scope.parent; //!!! safety
  86. modifiers = checkAndSetModifiers(modifiers, upperScope);
  87. int bindingModifiers = (modifiers | (binding.modifiers & AccGenericSignature));
  88. binding.modifiers = bindingModifiers;
  89. if (kind == AdviceKind.AfterThrowing && extraArgument != null) {
  90. TypeBinding argTb = extraArgument.binding.type;
  91. TypeBinding expectedTb = upperScope.getJavaLangThrowable();
  92. if (!argTb.isCompatibleWith(expectedTb)) {
  93. scope.problemReporter().typeMismatchError(argTb, expectedTb, extraArgument);
  94. ignoreFurtherInvestigation = true;
  95. return;
  96. }
  97. }
  98. pointcutDesignator.finishResolveTypes(this, this.binding,
  99. baseArgumentCount, upperScope.referenceContext.binding);
  100. if (binding == null || ignoreFurtherInvestigation) return;
  101. if (kind == AdviceKind.Around) {
  102. ReferenceBinding[] exceptions =
  103. new ReferenceBinding[] { upperScope.getJavaLangThrowable() };
  104. proceedMethodBinding = new MethodBinding(Modifier.STATIC,
  105. "proceed".toCharArray(), binding.returnType,
  106. resize(baseArgumentCount+1, binding.parameters),
  107. exceptions, binding.declaringClass);
  108. proceedMethodBinding.selector =
  109. CharOperation.concat(selector, proceedMethodBinding.selector);
  110. }
  111. super.resolveStatements(); //upperScope);
  112. if (binding != null) determineExtraArgumentFlags();
  113. if (kind == AdviceKind.Around) {
  114. int n = proceedCalls.size();
  115. // EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
  116. //System.err.println("access to: " + Arrays.asList(handler.getMembers()));
  117. //XXX set these correctly
  118. formalsUnchangedToProceed = new boolean[baseArgumentCount];
  119. proceedCallSignatures = new ResolvedMember[0];
  120. proceedInInners = false;
  121. declaredExceptions = new UnresolvedType[0];
  122. for (int i=0; i < n; i++) {
  123. Proceed call = (Proceed)proceedCalls.get(i);
  124. if (call.inInner) {
  125. //System.err.println("proceed in inner: " + call);
  126. proceedInInners = true;
  127. //XXX wrong
  128. //proceedCallSignatures[i] = world.makeResolvedMember(call.binding);
  129. }
  130. }
  131. // ??? should reorganize into AspectDeclaration
  132. // if we have proceed in inners we won't ever be inlined so the code below is unneeded
  133. if (!proceedInInners) {
  134. PrivilegedHandler handler = (PrivilegedHandler)upperScope.referenceContext.binding.privilegedHandler;
  135. if (handler == null) {
  136. handler = new PrivilegedHandler((AspectDeclaration)upperScope.referenceContext);
  137. //upperScope.referenceContext.binding.privilegedHandler = handler;
  138. }
  139. this.traverse(new MakeDeclsPublicVisitor(), (ClassScope)null);
  140. AccessForInlineVisitor v = new AccessForInlineVisitor((AspectDeclaration)upperScope.referenceContext, handler);
  141. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.ACCESS_FOR_INLINE, selector);
  142. this.traverse(v, (ClassScope) null);
  143. CompilationAndWeavingContext.leavingPhase(tok);
  144. // ??? if we found a construct that we can't inline, set
  145. // proceedInInners so that we won't try to inline this body
  146. if (!v.isInlinable) proceedInInners = true;
  147. }
  148. }
  149. }
  150. // called by Proceed.resolveType
  151. public int getDeclaredParameterCount() {
  152. // this only works before code generation
  153. return this.arguments.length - 3 - ((extraArgument == null) ? 0 : 1);
  154. //Advice.countOnes(extraArgumentFlags);
  155. }
  156. private void generateProceedMethod(ClassScope classScope, ClassFile classFile) {
  157. MethodBinding binding = (MethodBinding)proceedMethodBinding;
  158. classFile.generateMethodInfoHeader(binding);
  159. int methodAttributeOffset = classFile.contentsOffset;
  160. int attributeNumber = classFile.generateMethodInfoAttribute(binding, false, AstUtil.getAjSyntheticAttribute());
  161. int codeAttributeOffset = classFile.contentsOffset;
  162. classFile.generateCodeAttributeHeader();
  163. CodeStream codeStream = classFile.codeStream;
  164. codeStream.reset(this, classFile);
  165. // push the closure
  166. int nargs = binding.parameters.length;
  167. int closureIndex = 0;
  168. for (int i=0; i < nargs-1; i++) {
  169. closureIndex += AstUtil.slotsNeeded(binding.parameters[i]);
  170. }
  171. codeStream.loadObject(closureIndex);
  172. // build the Object[]
  173. codeStream.generateInlinedValue(nargs-1);
  174. codeStream.newArray(
  175. new ArrayBinding(
  176. classScope.getType(TypeBinding.JAVA_LANG_OBJECT,
  177. TypeBinding.JAVA_LANG_OBJECT.length),
  178. 1,
  179. classScope.environment()));
  180. int index = 0;
  181. for (int i=0; i < nargs-1; i++) {
  182. TypeBinding type = binding.parameters[i];
  183. codeStream.dup();
  184. codeStream.generateInlinedValue(i);
  185. codeStream.load(type, index);
  186. index += AstUtil.slotsNeeded(type);
  187. if (type.isBaseType()) {
  188. codeStream.invokestatic(AjTypeConstants.getConversionMethodToObject(classScope, type));
  189. }
  190. codeStream.aastore();
  191. }
  192. // call run
  193. ReferenceBinding closureType = (ReferenceBinding)binding.parameters[nargs-1];
  194. MethodBinding runMethod = closureType.getMethods("run".toCharArray())[0];
  195. codeStream.invokevirtual(runMethod);
  196. TypeBinding returnType = binding.returnType;
  197. if (returnType.isBaseType()) {
  198. codeStream.invokestatic(AjTypeConstants.getConversionMethodFromObject(classScope, returnType));
  199. } else {
  200. codeStream.checkcast(returnType);
  201. }
  202. AstUtil.generateReturn(returnType, codeStream);
  203. classFile.completeCodeAttribute(codeAttributeOffset);
  204. attributeNumber++;
  205. classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
  206. }
  207. // override
  208. public void generateCode(ClassScope classScope, ClassFile classFile) {
  209. if (ignoreFurtherInvestigation) return;
  210. super.generateCode(classScope, classFile);
  211. if (proceedMethodBinding != null) {
  212. generateProceedMethod(classScope, classFile);
  213. }
  214. }
  215. private void determineExtraArgumentFlags() {
  216. if (extraArgument != null) extraArgumentFlags |= Advice.ExtraArgument;
  217. ThisJoinPointVisitor tjp = new ThisJoinPointVisitor(this);
  218. extraArgumentFlags |= tjp.removeUnusedExtraArguments();
  219. }
  220. private static TypeBinding[] resize(int newSize, TypeBinding[] bindings) {
  221. int len = bindings.length;
  222. TypeBinding[] ret = new TypeBinding[newSize];
  223. System.arraycopy(bindings, 0, ret, 0, Math.min(newSize, len));
  224. return ret;
  225. }
  226. /**
  227. * Add either the @Before, @After, @Around, @AfterReturning or @AfterThrowing annotation
  228. */
  229. public void addAtAspectJAnnotations() {
  230. Annotation adviceAnnotation = null;
  231. String pointcutExpression = pointcutDesignator.getPointcut().toString();
  232. String extraArgumentName = "";
  233. if (extraArgument != null) {
  234. extraArgumentName = new String(extraArgument.name);
  235. }
  236. if (kind == AdviceKind.Before) {
  237. adviceAnnotation = AtAspectJAnnotationFactory.createBeforeAnnotation(pointcutExpression,declarationSourceStart);
  238. } else if (kind == AdviceKind.After) {
  239. adviceAnnotation = AtAspectJAnnotationFactory.createAfterAnnotation(pointcutExpression,declarationSourceStart);
  240. } else if (kind == AdviceKind.AfterReturning) {
  241. adviceAnnotation = AtAspectJAnnotationFactory.createAfterReturningAnnotation(pointcutExpression,extraArgumentName,declarationSourceStart);
  242. } else if (kind == AdviceKind.AfterThrowing) {
  243. adviceAnnotation = AtAspectJAnnotationFactory.createAfterThrowingAnnotation(pointcutExpression,extraArgumentName,declarationSourceStart);
  244. } else if (kind == AdviceKind.Around) {
  245. adviceAnnotation = AtAspectJAnnotationFactory.createAroundAnnotation(pointcutExpression,declarationSourceStart);
  246. }
  247. AtAspectJAnnotationFactory.addAnnotation(this, adviceAnnotation);
  248. }
  249. // override, Called by ClassScope.postParse
  250. public void postParse(TypeDeclaration typeDec) {
  251. AspectDeclaration aspectDecl = (AspectDeclaration)typeDec;
  252. int adviceSequenceNumberInType = aspectDecl.adviceCounter++;
  253. StringBuffer stringifiedPointcut = new StringBuffer(30);
  254. pointcutDesignator.print(0,stringifiedPointcut);
  255. this.selector =
  256. NameMangler.adviceName(
  257. EclipseFactory.getName(typeDec.binding).replace('.', '_'),
  258. kind,
  259. adviceSequenceNumberInType,
  260. stringifiedPointcut.toString().hashCode()).toCharArray();
  261. if (arguments != null) {
  262. baseArgumentCount = arguments.length;
  263. }
  264. if (kind == AdviceKind.Around) {
  265. extraArgument = makeFinalArgument("ajc_aroundClosure",
  266. AjTypeConstants.getAroundClosureType());
  267. }
  268. int addedArguments = 3;
  269. if (extraArgument != null) {
  270. addedArguments += 1;
  271. }
  272. arguments = extendArgumentsLength(arguments, addedArguments);
  273. int index = baseArgumentCount;
  274. if (extraArgument != null) {
  275. arguments[index++] = extraArgument;
  276. }
  277. arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  278. arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
  279. arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  280. if (pointcutDesignator.isError()) {
  281. this.ignoreFurtherInvestigation = true;
  282. }
  283. pointcutDesignator.postParse(typeDec, this);
  284. }
  285. private int checkAndSetModifiers(int modifiers, ClassScope scope) {
  286. if (modifiers == 0) return Modifier.PUBLIC;
  287. else if (modifiers == Modifier.STRICT) return Modifier.PUBLIC | Modifier.STRICT;
  288. else {
  289. tagAsHavingErrors();
  290. scope.problemReporter().signalError(declarationSourceStart, sourceStart-1, "illegal modifier on advice, only strictfp is allowed");
  291. return Modifier.PUBLIC;
  292. }
  293. }
  294. // called by IfPseudoToken
  295. public static Argument[] addTjpArguments(Argument[] arguments) {
  296. int index = arguments.length;
  297. arguments = extendArgumentsLength(arguments, 3);
  298. arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  299. arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
  300. arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  301. return arguments;
  302. }
  303. private static Argument makeFinalArgument(String name, TypeReference typeRef) {
  304. long pos = 0; //XXX encode start and end location
  305. return new Argument(name.toCharArray(), pos, typeRef, Modifier.FINAL);
  306. }
  307. private static Argument[] extendArgumentsLength(Argument[] args, int addedArguments) {
  308. if (args == null) {
  309. return new Argument[addedArguments];
  310. }
  311. int len = args.length;
  312. Argument[] ret = new Argument[len + addedArguments];
  313. System.arraycopy(args, 0, ret, 0, len);
  314. return ret;
  315. }
  316. // public String toString(int tab) {
  317. // String s = tabString(tab);
  318. // if (modifiers != AccDefault) {
  319. // s += modifiersString(modifiers);
  320. // }
  321. //
  322. // if (kind == AdviceKind.Around) {
  323. // s += returnTypeToString(0);
  324. // }
  325. //
  326. // s += new String(selector) + "("; //$NON-NLS-1$
  327. // if (arguments != null) {
  328. // for (int i = 0; i < arguments.length; i++) {
  329. // s += arguments[i].toString(0);
  330. // if (i != (arguments.length - 1))
  331. // s = s + ", "; //$NON-NLS-1$
  332. // };
  333. // };
  334. // s += ")"; //$NON-NLS-1$
  335. //
  336. // if (extraArgument != null) {
  337. // s += "(" + extraArgument.toString(0) + ")";
  338. // }
  339. //
  340. //
  341. //
  342. // if (thrownExceptions != null) {
  343. // s += " throws "; //$NON-NLS-1$
  344. // for (int i = 0; i < thrownExceptions.length; i++) {
  345. // s += thrownExceptions[i].toString(0);
  346. // if (i != (thrownExceptions.length - 1))
  347. // s = s + ", "; //$NON-NLS-1$
  348. // };
  349. // };
  350. //
  351. // s += ": ";
  352. // if (pointcutDesignator != null) {
  353. // s += pointcutDesignator.toString(0);
  354. // }
  355. //
  356. // s += toStringStatements(tab + 1);
  357. // return s;
  358. // }
  359. public StringBuffer printBody(int indent, StringBuffer output) {
  360. output.append(": ");
  361. if (pointcutDesignator != null) {
  362. output.append(pointcutDesignator.toString());
  363. }
  364. return super.printBody(indent,output);
  365. }
  366. public StringBuffer printReturnType(int indent, StringBuffer output) {
  367. if (this.kind == AdviceKind.Around) {
  368. return super.printReturnType(indent,output);
  369. }
  370. return output;
  371. }
  372. }