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.

ThisJoinPointVisitor.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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 org.aspectj.bridge.context.CompilationAndWeavingContext;
  14. import org.aspectj.bridge.context.ContextToken;
  15. import org.aspectj.org.eclipse.jdt.internal.compiler.ASTVisitor;
  16. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
  17. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Expression;
  18. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MessageSend;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.NameReference;
  20. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.SingleNameReference;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.BooleanConstant;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.impl.Constant;
  23. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.Binding;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.BlockScope;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ClassScope;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
  29. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
  30. import org.aspectj.weaver.Advice;
  31. /**
  32. * Takes a method that already has the three extra parameters thisJoinPointStaticPart, thisJoinPoint and
  33. * thisEnclosingJoinPointStaticPart
  34. */
  35. public class ThisJoinPointVisitor extends ASTVisitor {
  36. boolean needsDynamic = false;
  37. boolean needsStatic = false;
  38. boolean needsStaticEnclosing = false;
  39. boolean needsThisAspectInstance = false;
  40. boolean hasEffectivelyStaticRef = false;
  41. boolean hasConstantReference = false;
  42. boolean constantReferenceValue = false; // only has valid value when hasConstantReference is true
  43. LocalVariableBinding thisJoinPointDec;
  44. LocalVariableBinding thisJoinPointStaticPartDec;
  45. LocalVariableBinding thisEnclosingJoinPointStaticPartDec;
  46. LocalVariableBinding thisAspectInstanceDec;
  47. LocalVariableBinding thisJoinPointDecLocal;
  48. LocalVariableBinding thisJoinPointStaticPartDecLocal;
  49. LocalVariableBinding thisEnclosingJoinPointStaticPartDecLocal;
  50. LocalVariableBinding thisAspectInstanceDecLocal;
  51. boolean replaceEffectivelyStaticRefs = false;
  52. boolean isIf = true;
  53. AbstractMethodDeclaration method;
  54. ThisJoinPointVisitor(AbstractMethodDeclaration method) {
  55. this.method = method;
  56. if (method instanceof AdviceDeclaration) {
  57. isIf = false;
  58. }
  59. int index = method.arguments.length - 3 - (isIf ? 1 : 0);
  60. thisJoinPointStaticPartDecLocal = method.scope.locals[index];
  61. thisJoinPointStaticPartDec = method.arguments[index++].binding;
  62. thisJoinPointDecLocal = method.scope.locals[index];
  63. thisJoinPointDec = method.arguments[index++].binding;
  64. thisEnclosingJoinPointStaticPartDecLocal = method.scope.locals[index];
  65. thisEnclosingJoinPointStaticPartDec = method.arguments[index++].binding;
  66. if (isIf) {
  67. thisAspectInstanceDecLocal = method.scope.locals[index];
  68. thisAspectInstanceDec = method.arguments[index++].binding;
  69. }
  70. }
  71. public void computeJoinPointParams() {
  72. // walk my body to see what is needed
  73. method.traverse(this, (ClassScope) null);
  74. // ??? add support for option to disable this optimization
  75. // System.err.println("walked: " + method);
  76. // System.err.println("check: "+ hasEffectivelyStaticRef + ", " + needsDynamic);
  77. if (hasEffectivelyStaticRef && !needsDynamic) {
  78. // replace effectively static refs with thisJoinPointStaticPart
  79. replaceEffectivelyStaticRefs = true;
  80. needsStatic = true;
  81. method.traverse(this, (ClassScope) null);
  82. }
  83. // System.err.println("done: " + method);
  84. }
  85. boolean isRef(NameReference ref, Binding binding) {
  86. // System.err.println("check ref: " + ref + " is " + System.identityHashCode(ref));
  87. return ref.binding == binding;
  88. }
  89. boolean isRef(Expression expr, Binding binding) {
  90. return expr instanceof NameReference && isRef((NameReference)expr, binding);
  91. }
  92. public void endVisit(SingleNameReference ref, BlockScope scope) {
  93. if (isRef(ref, thisJoinPointDec)) {
  94. needsDynamic = true;
  95. } else if (isRef(ref, thisJoinPointStaticPartDec)) {
  96. needsStatic = true;
  97. } else if (isRef(ref, thisEnclosingJoinPointStaticPartDec)) {
  98. needsStaticEnclosing = true;
  99. } else if (isIf && isRef(ref, thisAspectInstanceDec)) {
  100. needsThisAspectInstance = true;
  101. } else if (ref.constant != null && ref.constant != Constant.NotAConstant) {
  102. if (ref.constant instanceof BooleanConstant) {
  103. hasConstantReference = true;
  104. constantReferenceValue = ((BooleanConstant) ref.constant).booleanValue();
  105. }
  106. }
  107. }
  108. boolean canTreatAsStatic(String id) {
  109. return id.equals("toString") || id.equals("toShortString") || id.equals("toLongString") || id.equals("getKind")
  110. || id.equals("getSignature") || id.equals("getSourceLocation");
  111. // TODO: This is a good optimization, but requires more work than the above
  112. // we have to replace a call with a direct reference, not just a different call
  113. // || id.equals("getStaticPart");
  114. }
  115. // boolean canTreatAsStatic(VarExpr varExpr) {
  116. // ASTObject parent = varExpr.getParent();
  117. // if (parent instanceof CallExpr) {
  118. // Method calledMethod = ((CallExpr)parent).getMethod();
  119. // return canTreatAsStatic(calledMethod);
  120. //
  121. // //??? should add a case here to catch
  122. // //??? tjp.getEnclosingExecutionJoinPoint().STATIC_METHOD()
  123. // } else if (parent instanceof BinopExpr) {
  124. // BinopExpr binop = (BinopExpr)parent;
  125. // if (binop.getType().isEquivalent(this.getTypeManager().getStringType())) {
  126. // return true;
  127. // } else {
  128. // return false;
  129. // }
  130. // } else {
  131. // return false;
  132. // }
  133. // }
  134. boolean inBlockThatCantRun = false;
  135. public boolean visit(MessageSend call, BlockScope scope) {
  136. ContextToken tok = CompilationAndWeavingContext.enteringPhase(
  137. CompilationAndWeavingContext.OPTIMIZING_THIS_JOIN_POINT_CALLS, call.selector);
  138. Expression receiver = call.receiver;
  139. if (isRef(receiver, thisJoinPointDec)) {
  140. if (canTreatAsStatic(new String(call.selector))) {
  141. if (replaceEffectivelyStaticRefs) {
  142. replaceEffectivelyStaticRef(call);
  143. } else {
  144. // System.err.println("has static reg");
  145. hasEffectivelyStaticRef = true;
  146. if (call.arguments != null) {
  147. int argumentsLength = call.arguments.length;
  148. for (int i = 0; i < argumentsLength; i++)
  149. call.arguments[i].traverse(this, scope);
  150. }
  151. CompilationAndWeavingContext.leavingPhase(tok);
  152. return false;
  153. }
  154. }
  155. }
  156. boolean ret = super.visit(call, scope);
  157. CompilationAndWeavingContext.leavingPhase(tok);
  158. return ret;
  159. }
  160. private void replaceEffectivelyStaticRef(MessageSend call) {
  161. NameReference receiver = (NameReference) call.receiver;
  162. // Don't continue if the call binding is null, as we are going to report an error about this line of code!
  163. if (call.binding == null)
  164. return;
  165. // System.err.println("replace static ref: " + receiver + " is " + System.identityHashCode(receiver));
  166. receiver.binding = thisJoinPointStaticPartDecLocal; // thisJoinPointStaticPartDec;
  167. // receiver.codegenBinding = thisJoinPointStaticPartDecLocal;
  168. ReferenceBinding thisJoinPointStaticPartType = (ReferenceBinding) thisJoinPointStaticPartDec.type;
  169. receiver.actualReceiverType = receiver.resolvedType = thisJoinPointStaticPartType;
  170. call.setActualReceiverType(thisJoinPointStaticPartType);
  171. AstUtil.replaceMethodBinding(call, getEquivalentStaticBinding(call.binding));
  172. }
  173. private MethodBinding getEquivalentStaticBinding(MethodBinding template) {
  174. ReferenceBinding b = (ReferenceBinding) thisJoinPointStaticPartDec.type;
  175. return b.getExactMethod(template.selector, template.parameters, null);
  176. }
  177. public int removeUnusedExtraArguments() {
  178. int extraArgumentFlags = 0;
  179. this.computeJoinPointParams();
  180. MethodBinding binding = method.binding;
  181. int index = binding.parameters.length - 3 - (isIf ? 1 : 0);
  182. if (isIf) {
  183. if (needsThisAspectInstance) {
  184. extraArgumentFlags |= Advice.ThisAspectInstance;
  185. } else {
  186. removeParameter(index + 3);
  187. }
  188. }
  189. if (needsStaticEnclosing) {
  190. extraArgumentFlags |= Advice.ThisEnclosingJoinPointStaticPart;
  191. } else {
  192. removeParameter(index + 2);
  193. }
  194. if (needsDynamic) {
  195. extraArgumentFlags |= Advice.ThisJoinPoint;
  196. } else {
  197. removeParameter(index + 1);
  198. }
  199. if (needsStatic) {
  200. extraArgumentFlags |= Advice.ThisJoinPointStaticPart;
  201. } else {
  202. removeParameter(index + 0);
  203. }
  204. return extraArgumentFlags;
  205. }
  206. public boolean usedThisAspectInstance() {
  207. return needsThisAspectInstance;
  208. }
  209. private void removeParameter(int indexToRemove) {
  210. // TypeBinding[] parameters = method.binding.parameters;
  211. method.scope.locals = removeLocalBinding(indexToRemove, method.scope.locals);
  212. method.scope.localIndex -= 1;
  213. method.binding.parameters = removeParameter(indexToRemove, method.binding.parameters);
  214. }
  215. private static TypeBinding[] removeParameter(int index, TypeBinding[] bindings) {
  216. int len = bindings.length;
  217. TypeBinding[] ret = new TypeBinding[len - 1];
  218. System.arraycopy(bindings, 0, ret, 0, index);
  219. System.arraycopy(bindings, index + 1, ret, index, len - index - 1);
  220. return ret;
  221. }
  222. private static LocalVariableBinding[] removeLocalBinding(int index, LocalVariableBinding[] bindings) {
  223. int len = bindings.length;
  224. // ??? for performance we should do this in-place
  225. LocalVariableBinding[] ret = new LocalVariableBinding[len - 1];
  226. System.arraycopy(bindings, 0, ret, 0, index);
  227. System.arraycopy(bindings, index + 1, ret, index, len - index - 1);
  228. return ret;
  229. }
  230. }