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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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.weaver.Advice;
  20. import org.aspectj.weaver.AdviceKind;
  21. import org.aspectj.weaver.AjAttribute;
  22. import org.aspectj.weaver.NameMangler;
  23. import org.aspectj.weaver.ResolvedMember;
  24. import org.aspectj.weaver.TypeX;
  25. import org.eclipse.jdt.internal.compiler.ClassFile;
  26. import org.eclipse.jdt.internal.compiler.CompilationResult;
  27. import org.eclipse.jdt.internal.compiler.ast.Argument;
  28. import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
  29. import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  30. import org.eclipse.jdt.internal.compiler.ast.TypeReference;
  31. import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
  32. import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
  33. import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  34. import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  35. import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  36. import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  37. import org.eclipse.jdt.core.compiler.CharOperation;
  38. /**
  39. * Represents before, after and around advice in an aspect.
  40. * Will generate a method corresponding to the body of the advice with an
  41. * attribute including additional information.
  42. *
  43. * @author Jim Hugunin
  44. */
  45. public class AdviceDeclaration extends MethodDeclaration {
  46. public PointcutDesignator pointcutDesignator;
  47. int baseArgumentCount;
  48. public Argument extraArgument;
  49. public AdviceKind kind;
  50. private int extraArgumentFlags = 0;
  51. public MethodBinding proceedMethodBinding;
  52. public List proceedCalls = new ArrayList(2);
  53. public boolean proceedInInners;
  54. public ResolvedMember[] proceedCallSignatures;
  55. public boolean[] formalsUnchangedToProceed;
  56. public TypeX[] declaredExceptions;
  57. public AdviceDeclaration(CompilationResult result, AdviceKind kind) {
  58. super(result);
  59. this.returnType = TypeReference.baseTypeReference(T_void, 0);
  60. this.kind = kind;
  61. }
  62. protected int generateInfoAttributes(ClassFile classFile) {
  63. List l = new ArrayList(1);
  64. l.add(new EclipseAttributeAdapter(makeAttribute()));
  65. return classFile.generateMethodInfoAttribute(binding, l);
  66. }
  67. public AjAttribute makeAttribute() {
  68. if (kind == AdviceKind.Around) {
  69. return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(),
  70. extraArgumentFlags, sourceStart, sourceEnd, null,
  71. proceedInInners, proceedCallSignatures, formalsUnchangedToProceed,
  72. declaredExceptions);
  73. } else {
  74. return new AjAttribute.AdviceAttribute(kind, pointcutDesignator.getPointcut(),
  75. extraArgumentFlags, sourceStart, sourceEnd, null);
  76. }
  77. }
  78. public void resolveStatements() {
  79. if (binding == null || ignoreFurtherInvestigation) return;
  80. ClassScope upperScope = (ClassScope)scope.parent; //!!! safety
  81. modifiers = binding.modifiers = checkAndSetModifiers(modifiers, upperScope);
  82. if (kind == AdviceKind.AfterThrowing && extraArgument != null) {
  83. TypeBinding argTb = extraArgument.binding.type;
  84. TypeBinding expectedTb = upperScope.getJavaLangThrowable();
  85. if (!argTb.isCompatibleWith(expectedTb)) {
  86. scope.problemReporter().typeMismatchError(argTb, expectedTb, extraArgument);
  87. ignoreFurtherInvestigation = true;
  88. return;
  89. }
  90. }
  91. pointcutDesignator.finishResolveTypes(this, this.binding,
  92. baseArgumentCount, upperScope.referenceContext.binding);
  93. if (binding == null || ignoreFurtherInvestigation) return;
  94. if (kind == AdviceKind.Around) {
  95. ReferenceBinding[] exceptions =
  96. new ReferenceBinding[] { upperScope.getJavaLangThrowable() };
  97. proceedMethodBinding = new MethodBinding(Modifier.STATIC,
  98. "proceed".toCharArray(), binding.returnType,
  99. resize(baseArgumentCount+1, binding.parameters),
  100. exceptions, binding.declaringClass);
  101. proceedMethodBinding.selector =
  102. CharOperation.concat(selector, proceedMethodBinding.selector);
  103. }
  104. super.resolveStatements(); //upperScope);
  105. if (binding != null) determineExtraArgumentFlags();
  106. if (kind == AdviceKind.Around) {
  107. int n = proceedCalls.size();
  108. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(upperScope);
  109. //System.err.println("access to: " + Arrays.asList(handler.getMembers()));
  110. //XXX set these correctly
  111. formalsUnchangedToProceed = new boolean[baseArgumentCount];
  112. proceedCallSignatures = new ResolvedMember[0];
  113. proceedInInners = false;
  114. declaredExceptions = new TypeX[0];
  115. for (int i=0; i < n; i++) {
  116. Proceed call = (Proceed)proceedCalls.get(i);
  117. if (call.inInner) {
  118. //System.err.println("proceed in inner: " + call);
  119. proceedInInners = true;
  120. //XXX wrong
  121. //proceedCallSignatures[i] = world.makeResolvedMember(call.binding);
  122. }
  123. }
  124. // ??? should reorganize into AspectDeclaration
  125. // if we have proceed in inners we won't ever be inlined so the code below is unneeded
  126. if (!proceedInInners) {
  127. PrivilegedHandler handler = (PrivilegedHandler)upperScope.referenceContext.binding.privilegedHandler;
  128. if (handler == null) {
  129. handler = new PrivilegedHandler((AspectDeclaration)upperScope.referenceContext);
  130. //upperScope.referenceContext.binding.privilegedHandler = handler;
  131. }
  132. this.traverse(new MakeDeclsPublicVisitor(), (ClassScope)null);
  133. AccessForInlineVisitor v = new AccessForInlineVisitor((AspectDeclaration)upperScope.referenceContext, handler);
  134. this.traverse(v, (ClassScope) null);
  135. // ??? if we found a construct that we can't inline, set
  136. // proceedInInners so that we won't try to inline this body
  137. if (!v.isInlinable) proceedInInners = true;
  138. }
  139. }
  140. }
  141. public int getDeclaredParameterCount() {
  142. // this only works before code generation
  143. return this.arguments.length - 3 - ((extraArgument == null) ? 0 : 1);
  144. //Advice.countOnes(extraArgumentFlags);
  145. }
  146. public void generateProceedMethod(ClassScope classScope, ClassFile classFile) {
  147. MethodBinding binding = (MethodBinding)proceedMethodBinding;
  148. classFile.generateMethodInfoHeader(binding);
  149. int methodAttributeOffset = classFile.contentsOffset;
  150. int attributeNumber = classFile.generateMethodInfoAttribute(binding, AstUtil.getAjSyntheticAttribute());
  151. int codeAttributeOffset = classFile.contentsOffset;
  152. classFile.generateCodeAttributeHeader();
  153. CodeStream codeStream = classFile.codeStream;
  154. codeStream.reset(this, classFile);
  155. // push the closure
  156. int nargs = binding.parameters.length;
  157. int closureIndex = 0;
  158. for (int i=0; i < nargs-1; i++) {
  159. closureIndex += AstUtil.slotsNeeded(binding.parameters[i]);
  160. }
  161. codeStream.loadObject(closureIndex);
  162. // build the Object[]
  163. codeStream.generateInlinedValue(nargs-1);
  164. codeStream.newArray(classScope, new ArrayBinding(classScope.getType(TypeBinding.JAVA_LANG_OBJECT), 1));
  165. int index = 0;
  166. for (int i=0; i < nargs-1; i++) {
  167. TypeBinding type = binding.parameters[i];
  168. codeStream.dup();
  169. codeStream.generateInlinedValue(i);
  170. codeStream.load(type, index);
  171. index += AstUtil.slotsNeeded(type);
  172. if (type.isBaseType()) {
  173. codeStream.invokestatic(AjTypeConstants.getConversionMethodToObject(classScope, type));
  174. }
  175. codeStream.aastore();
  176. }
  177. // call run
  178. ReferenceBinding closureType = (ReferenceBinding)binding.parameters[nargs-1];
  179. MethodBinding runMethod = closureType.getMethods("run".toCharArray())[0];
  180. codeStream.invokevirtual(runMethod);
  181. TypeBinding returnType = binding.returnType;
  182. if (returnType.isBaseType()) {
  183. codeStream.invokestatic(AjTypeConstants.getConversionMethodFromObject(classScope, returnType));
  184. } else {
  185. codeStream.checkcast(returnType);
  186. }
  187. AstUtil.generateReturn(returnType, codeStream);
  188. classFile.completeCodeAttribute(codeAttributeOffset);
  189. attributeNumber++;
  190. classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
  191. }
  192. public void generateCode(ClassScope classScope, ClassFile classFile) {
  193. if (ignoreFurtherInvestigation) return;
  194. super.generateCode(classScope, classFile);
  195. if (proceedMethodBinding != null) {
  196. generateProceedMethod(classScope, classFile);
  197. }
  198. }
  199. private void determineExtraArgumentFlags() {
  200. if (extraArgument != null) extraArgumentFlags |= Advice.ExtraArgument;
  201. ThisJoinPointVisitor tjp = new ThisJoinPointVisitor(this);
  202. extraArgumentFlags |= tjp.removeUnusedExtraArguments();
  203. }
  204. private static TypeBinding[] resize(int newSize, TypeBinding[] bindings) {
  205. int len = bindings.length;
  206. TypeBinding[] ret = new TypeBinding[newSize];
  207. System.arraycopy(bindings, 0, ret, 0, Math.min(newSize, len));
  208. return ret;
  209. }
  210. public void postParse(TypeDeclaration typeDec) {
  211. this.selector =
  212. NameMangler.adviceName(EclipseFactory.fromBinding(typeDec.binding), kind, sourceStart).toCharArray();
  213. if (arguments != null) {
  214. baseArgumentCount = arguments.length;
  215. }
  216. if (kind == AdviceKind.Around) {
  217. extraArgument = makeFinalArgument("ajc_aroundClosure",
  218. AjTypeConstants.getAroundClosureType());
  219. }
  220. int addedArguments = 3;
  221. if (extraArgument != null) {
  222. addedArguments += 1;
  223. }
  224. arguments = extendArgumentsLength(arguments, addedArguments);
  225. int index = baseArgumentCount;
  226. if (extraArgument != null) {
  227. arguments[index++] = extraArgument;
  228. }
  229. arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  230. arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
  231. arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  232. if (pointcutDesignator.isError()) {
  233. this.ignoreFurtherInvestigation = true;
  234. }
  235. pointcutDesignator.postParse(typeDec, this);
  236. }
  237. private int checkAndSetModifiers(int modifiers, ClassScope scope) {
  238. if (modifiers == 0) return Modifier.PUBLIC;
  239. else if (modifiers == Modifier.STRICT) return Modifier.PUBLIC | Modifier.STRICT;
  240. else {
  241. tagAsHavingErrors();
  242. scope.problemReporter().signalError(declarationSourceStart, sourceStart-1, "illegal modifier on advice, only strictfp is allowed");
  243. return Modifier.PUBLIC;
  244. }
  245. }
  246. public static Argument[] addTjpArguments(Argument[] arguments) {
  247. int index = arguments.length;
  248. arguments = extendArgumentsLength(arguments, 3);
  249. arguments[index++] = makeFinalArgument("thisJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  250. arguments[index++] = makeFinalArgument("thisJoinPoint", AjTypeConstants.getJoinPointType());
  251. arguments[index++] = makeFinalArgument("thisEnclosingJoinPointStaticPart", AjTypeConstants.getJoinPointStaticPartType());
  252. return arguments;
  253. }
  254. private static Argument makeFinalArgument(String name, TypeReference typeRef) {
  255. long pos = 0; //XXX encode start and end location
  256. return new Argument(name.toCharArray(), pos, typeRef, Modifier.FINAL);
  257. }
  258. private static Argument[] extendArgumentsLength(Argument[] args, int addedArguments) {
  259. if (args == null) {
  260. return new Argument[addedArguments];
  261. }
  262. int len = args.length;
  263. Argument[] ret = new Argument[len + addedArguments];
  264. System.arraycopy(args, 0, ret, 0, len);
  265. return ret;
  266. }
  267. // public String toString(int tab) {
  268. // String s = tabString(tab);
  269. // if (modifiers != AccDefault) {
  270. // s += modifiersString(modifiers);
  271. // }
  272. //
  273. // if (kind == AdviceKind.Around) {
  274. // s += returnTypeToString(0);
  275. // }
  276. //
  277. // s += new String(selector) + "("; //$NON-NLS-1$
  278. // if (arguments != null) {
  279. // for (int i = 0; i < arguments.length; i++) {
  280. // s += arguments[i].toString(0);
  281. // if (i != (arguments.length - 1))
  282. // s = s + ", "; //$NON-NLS-1$
  283. // };
  284. // };
  285. // s += ")"; //$NON-NLS-1$
  286. //
  287. // if (extraArgument != null) {
  288. // s += "(" + extraArgument.toString(0) + ")";
  289. // }
  290. //
  291. //
  292. //
  293. // if (thrownExceptions != null) {
  294. // s += " throws "; //$NON-NLS-1$
  295. // for (int i = 0; i < thrownExceptions.length; i++) {
  296. // s += thrownExceptions[i].toString(0);
  297. // if (i != (thrownExceptions.length - 1))
  298. // s = s + ", "; //$NON-NLS-1$
  299. // };
  300. // };
  301. //
  302. // s += ": ";
  303. // if (pointcutDesignator != null) {
  304. // s += pointcutDesignator.toString(0);
  305. // }
  306. //
  307. // s += toStringStatements(tab + 1);
  308. // return s;
  309. // }
  310. public StringBuffer printBody(int indent, StringBuffer output) {
  311. output.append(": ");
  312. if (pointcutDesignator != null) {
  313. output.append(pointcutDesignator.toString());
  314. }
  315. return super.printBody(indent,output);
  316. }
  317. public StringBuffer printReturnType(int indent, StringBuffer output) {
  318. if (this.kind == AdviceKind.Around) {
  319. return super.printReturnType(indent,output);
  320. }
  321. return output;
  322. }
  323. }