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.

BcelRenderer.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  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. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.lang.reflect.Modifier;
  14. import org.aspectj.apache.bcel.Constants;
  15. import org.aspectj.apache.bcel.generic.InstructionFactory;
  16. import org.aspectj.apache.bcel.generic.InstructionHandle;
  17. import org.aspectj.apache.bcel.generic.InstructionList;
  18. import org.aspectj.apache.bcel.generic.ObjectType;
  19. import org.aspectj.apache.bcel.generic.ReferenceType;
  20. import org.aspectj.apache.bcel.generic.Type;
  21. import org.aspectj.weaver.BCException;
  22. import org.aspectj.weaver.Member;
  23. import org.aspectj.weaver.MemberImpl;
  24. import org.aspectj.weaver.UnresolvedType;
  25. import org.aspectj.weaver.ast.And;
  26. import org.aspectj.weaver.ast.Call;
  27. import org.aspectj.weaver.ast.CallExpr;
  28. import org.aspectj.weaver.ast.Expr;
  29. import org.aspectj.weaver.ast.FieldGet;
  30. import org.aspectj.weaver.ast.FieldGetCall;
  31. import org.aspectj.weaver.ast.HasAnnotation;
  32. import org.aspectj.weaver.ast.IExprVisitor;
  33. import org.aspectj.weaver.ast.ITestVisitor;
  34. import org.aspectj.weaver.ast.Instanceof;
  35. import org.aspectj.weaver.ast.Literal;
  36. import org.aspectj.weaver.ast.Not;
  37. import org.aspectj.weaver.ast.Or;
  38. import org.aspectj.weaver.ast.Test;
  39. import org.aspectj.weaver.ast.Var;
  40. import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
  41. // we generate right to left, btw.
  42. public final class BcelRenderer implements ITestVisitor, IExprVisitor {
  43. private InstructionList instructions;
  44. private InstructionFactory fact;
  45. private BcelWorld world;
  46. InstructionHandle sk, fk, next = null;
  47. private BcelRenderer(InstructionFactory fact, BcelWorld world) {
  48. super();
  49. this.fact = fact;
  50. this.world = world;
  51. this.instructions = new InstructionList();
  52. }
  53. // ---- renderers
  54. public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e) {
  55. BcelRenderer renderer = new BcelRenderer(fact, world);
  56. e.accept(renderer);
  57. return renderer.instructions;
  58. }
  59. public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e, Type desiredType) {
  60. BcelRenderer renderer = new BcelRenderer(fact, world);
  61. e.accept(renderer);
  62. InstructionList il = renderer.instructions;
  63. il.append(Utility.createConversion(fact, BcelWorld.makeBcelType(e.getType()), desiredType));
  64. return il;
  65. }
  66. public static InstructionList renderExprs(InstructionFactory fact, BcelWorld world, Expr[] es) {
  67. BcelRenderer renderer = new BcelRenderer(fact, world);
  68. for (int i = es.length - 1; i >= 0; i--) {
  69. es[i].accept(renderer);
  70. }
  71. return renderer.instructions;
  72. }
  73. /*
  74. * Get the instructions representing this test.
  75. *
  76. * @param e test to render
  77. *
  78. * @param sk instructionHandle to jump to if our rendered check succeeds (typically start of advice)
  79. *
  80. * @param fk instructionHandle to jump to if our rendered check fails (typically after end of advice)
  81. *
  82. * @param next instructionHandle that will follow this generated code. Passing in null will generate one unnecessary GOTO
  83. * instruction.
  84. *
  85. * @returns the instruction list representing this expression
  86. */
  87. public static InstructionList renderTest(InstructionFactory fact, BcelWorld world, Test e, InstructionHandle sk,
  88. InstructionHandle fk, InstructionHandle next) {
  89. BcelRenderer renderer = new BcelRenderer(fact, world);
  90. renderer.recur(e, sk, fk, next);
  91. return renderer.instructions;
  92. }
  93. // ---- recurrers
  94. private void recur(Test e, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) {
  95. this.sk = sk;
  96. this.fk = fk;
  97. this.next = next;
  98. e.accept(this);
  99. }
  100. // ---- test visitors
  101. public void visit(And e) {
  102. InstructionHandle savedFk = fk;
  103. recur(e.getRight(), sk, fk, next);
  104. InstructionHandle ning = instructions.getStart();
  105. recur(e.getLeft(), ning, savedFk, ning);
  106. }
  107. public void visit(Or e) {
  108. InstructionHandle savedSk = sk;
  109. recur(e.getRight(), sk, fk, next);
  110. recur(e.getLeft(), savedSk, instructions.getStart(), instructions.getStart());
  111. }
  112. public void visit(Not e) {
  113. recur(e.getBody(), fk, sk, next);
  114. }
  115. public void visit(Instanceof i) {
  116. instructions.insert(createJumpBasedOnBooleanOnStack());
  117. instructions.insert(Utility.createInstanceof(fact, (ReferenceType) BcelWorld.makeBcelType(i.getType())));
  118. i.getVar().accept(this);
  119. }
  120. public void visit(HasAnnotation hasAnnotation) {
  121. // in Java:
  122. // foo.class.isAnnotationPresent(annotationClass);
  123. // in bytecode:
  124. // ifnull? skip to the end if it is as getClass() will fail (see pr 257833)
  125. // load var onto the stack (done for us later)
  126. // invokevirtual java/lang/Object.getClass:()Ljava/lang/Class
  127. // ldc_w annotationClass
  128. // invokevirtual java/lang/Class.isAnnotationPresent:(Ljava/lang/Class;)Z
  129. InstructionList il = new InstructionList();
  130. // If it is null jump past the advice call
  131. il.append(InstructionFactory.createBranchInstruction(Constants.IFNULL, fk));
  132. // Load up the var again
  133. il.append(((BcelVar) hasAnnotation.getVar()).createLoad(fact));
  134. Member getClass = MemberImpl.method(UnresolvedType.OBJECT, 0, UnresolvedType.JL_CLASS, "getClass", UnresolvedType.NONE);
  135. il.append(Utility.createInvoke(fact, world, getClass));
  136. // aload annotationClass
  137. il.append(fact.createConstant(new ObjectType(hasAnnotation.getAnnotationType().getName())));
  138. // int annClassIndex = fact.getConstantPool().addClass(hasAnnotation.getAnnotationType().getSignature());
  139. // il.append(new LDC_W(annClassIndex));
  140. Member isAnnotationPresent = MemberImpl.method(UnresolvedType.JL_CLASS, 0, UnresolvedType.BOOLEAN, "isAnnotationPresent",
  141. new UnresolvedType[] { UnresolvedType.JL_CLASS });
  142. il.append(Utility.createInvoke(fact, world, isAnnotationPresent));
  143. il.append(createJumpBasedOnBooleanOnStack());
  144. instructions.insert(il);
  145. hasAnnotation.getVar().accept(this);
  146. }
  147. /*
  148. * (non-Javadoc)
  149. *
  150. * @see org.aspectj.weaver.ast.ITestVisitor#visit(org.aspectj.weaver.internal.tools.MatchingContextBasedTest)
  151. */
  152. public void visit(MatchingContextBasedTest matchingContextTest) {
  153. throw new UnsupportedOperationException("matching context extension not supported in bytecode weaving");
  154. }
  155. private InstructionList createJumpBasedOnBooleanOnStack() {
  156. InstructionList il = new InstructionList();
  157. if (sk == fk) {
  158. // don't bother generating if it doesn't matter
  159. if (sk != next) {
  160. il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk));
  161. }
  162. return il;
  163. }
  164. if (fk == next) {
  165. il.insert(InstructionFactory.createBranchInstruction(Constants.IFNE, sk));
  166. } else if (sk == next) {
  167. il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk));
  168. } else {
  169. il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk));
  170. il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk));
  171. }
  172. return il;
  173. }
  174. public void visit(Literal literal) {
  175. if (literal == Literal.FALSE) {
  176. throw new BCException("visiting a false expression");
  177. }
  178. }
  179. public void visit(Call call) {
  180. Member method = call.getMethod();
  181. // assert method.isStatic()
  182. Expr[] args = call.getArgs();
  183. InstructionList callIl = new InstructionList();
  184. for (int i = 0, len = args.length; i < len; i++) {
  185. // XXX only correct for static method calls
  186. Type desiredType = BcelWorld.makeBcelType(method.getParameterTypes()[i]);
  187. Expr arg = args[i];
  188. // if arg is null it is because we couldn't bind it properly, for example see 162135
  189. if (arg == null) {
  190. InstructionList iList = new InstructionList();
  191. iList.append(InstructionFactory.createNull(desiredType));
  192. callIl.append(iList);
  193. } else {
  194. callIl.append(renderExpr(fact, world, arg, desiredType));
  195. }
  196. }
  197. // System.out.println("rendered args: " + callIl);
  198. callIl.append(Utility.createInvoke(fact, world, method));
  199. callIl.append(createJumpBasedOnBooleanOnStack());
  200. instructions.insert(callIl);
  201. }
  202. public void visit(FieldGetCall fieldGetCall) {
  203. Member field = fieldGetCall.getField();
  204. Member method = fieldGetCall.getMethod();
  205. InstructionList il = new InstructionList();
  206. il.append(Utility.createGet(fact, field));
  207. // assert !method.isStatic()
  208. Expr[] args = fieldGetCall.getArgs();
  209. // System.out.println("args: " + Arrays.asList(args));
  210. il.append(renderExprs(fact, world, args));
  211. // System.out.println("rendered args: " + callIl);
  212. il.append(Utility.createInvoke(fact, world, method));
  213. il.append(createJumpBasedOnBooleanOnStack());
  214. instructions.insert(il);
  215. }
  216. // ---- expr visitors
  217. public void visit(Var var) {
  218. BcelVar bvar = (BcelVar) var;
  219. bvar.insertLoad(instructions, fact);
  220. }
  221. public void visit(FieldGet fieldGet) {
  222. Member field = fieldGet.getField();
  223. // assert field.isStatic()
  224. instructions.insert(Utility.createGet(fact, field));
  225. }
  226. public void visit(CallExpr call) {
  227. Member method = call.getMethod();
  228. // assert method.isStatic()
  229. Expr[] args = call.getArgs();
  230. InstructionList callIl = renderExprs(fact, world, args);
  231. callIl.append(Utility.createInvoke(fact, world, method));
  232. instructions.insert(callIl);
  233. }
  234. }