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

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