123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.weaver.bcel;
-
- import org.aspectj.apache.bcel.Constants;
- import org.aspectj.apache.bcel.generic.InstructionFactory;
- import org.aspectj.apache.bcel.generic.InstructionHandle;
- import org.aspectj.apache.bcel.generic.InstructionList;
- import org.aspectj.apache.bcel.generic.ObjectType;
- import org.aspectj.apache.bcel.generic.ReferenceType;
- import org.aspectj.apache.bcel.generic.Type;
- import org.aspectj.weaver.BCException;
- import org.aspectj.weaver.Member;
- import org.aspectj.weaver.MemberImpl;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.ast.And;
- import org.aspectj.weaver.ast.Call;
- import org.aspectj.weaver.ast.CallExpr;
- import org.aspectj.weaver.ast.Expr;
- import org.aspectj.weaver.ast.FieldGet;
- import org.aspectj.weaver.ast.FieldGetCall;
- import org.aspectj.weaver.ast.HasAnnotation;
- import org.aspectj.weaver.ast.IExprVisitor;
- import org.aspectj.weaver.ast.ITestVisitor;
- import org.aspectj.weaver.ast.Instanceof;
- import org.aspectj.weaver.ast.Literal;
- import org.aspectj.weaver.ast.Not;
- import org.aspectj.weaver.ast.Or;
- import org.aspectj.weaver.ast.Test;
- import org.aspectj.weaver.ast.Var;
- import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
-
- // we generate right to left, btw.
- public final class BcelRenderer implements ITestVisitor, IExprVisitor {
-
- private InstructionList instructions;
- private InstructionFactory fact;
- private BcelWorld world;
-
- InstructionHandle sk, fk, next = null;
-
- private BcelRenderer(InstructionFactory fact, BcelWorld world) {
- super();
- this.fact = fact;
- this.world = world;
- this.instructions = new InstructionList();
- }
-
- // ---- renderers
-
- public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e) {
- BcelRenderer renderer = new BcelRenderer(fact, world);
- e.accept(renderer);
- return renderer.instructions;
- }
-
- public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e, Type desiredType) {
- BcelRenderer renderer = new BcelRenderer(fact, world);
- e.accept(renderer);
- InstructionList il = renderer.instructions;
- il.append(Utility.createConversion(fact, BcelWorld.makeBcelType(e.getType()), desiredType));
- return il;
- }
-
- public static InstructionList renderExprs(InstructionFactory fact, BcelWorld world, Expr[] es) {
- BcelRenderer renderer = new BcelRenderer(fact, world);
- for (int i = es.length - 1; i >= 0; i--) {
- es[i].accept(renderer);
- }
- return renderer.instructions;
- }
-
- /*
- * Get the instructions representing this test.
- *
- * @param e test to render
- *
- * @param sk instructionHandle to jump to if our rendered check succeeds (typically start of advice)
- *
- * @param fk instructionHandle to jump to if our rendered check fails (typically after end of advice)
- *
- * @param next instructionHandle that will follow this generated code. Passing in null will generate one unnecessary GOTO
- * instruction.
- *
- * @returns the instruction list representing this expression
- */
- public static InstructionList renderTest(InstructionFactory fact, BcelWorld world, Test e, InstructionHandle sk,
- InstructionHandle fk, InstructionHandle next) {
- BcelRenderer renderer = new BcelRenderer(fact, world);
- renderer.recur(e, sk, fk, next);
- return renderer.instructions;
- }
-
- // ---- recurrers
-
- private void recur(Test e, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) {
- this.sk = sk;
- this.fk = fk;
- this.next = next;
- e.accept(this);
- }
-
- // ---- test visitors
-
- public void visit(And e) {
- InstructionHandle savedFk = fk;
- recur(e.getRight(), sk, fk, next);
- InstructionHandle ning = instructions.getStart();
- recur(e.getLeft(), ning, savedFk, ning);
- }
-
- public void visit(Or e) {
- InstructionHandle savedSk = sk;
- recur(e.getRight(), sk, fk, next);
- recur(e.getLeft(), savedSk, instructions.getStart(), instructions.getStart());
- }
-
- public void visit(Not e) {
- recur(e.getBody(), fk, sk, next);
- }
-
- public void visit(Instanceof i) {
- instructions.insert(createJumpBasedOnBooleanOnStack());
- instructions.insert(Utility.createInstanceof(fact, (ReferenceType) BcelWorld.makeBcelType(i.getType())));
- i.getVar().accept(this);
- }
-
- public void visit(HasAnnotation hasAnnotation) {
- // in Java:
- // foo.class.isAnnotationPresent(annotationClass);
- // in bytecode:
-
- // ifnull? skip to the end if it is as getClass() will fail (see pr 257833)
-
- // load var onto the stack (done for us later)
- // invokevirtual java/lang/Object.getClass:()Ljava/lang/Class
- // ldc_w annotationClass
- // invokevirtual java/lang/Class.isAnnotationPresent:(Ljava/lang/Class;)Z
- InstructionList il = new InstructionList();
-
- // If it is null jump past the advice call
- il.append(InstructionFactory.createBranchInstruction(Constants.IFNULL, fk));
-
- // Load up the var again
- il.append(((BcelVar) hasAnnotation.getVar()).createLoad(fact));
-
- Member getClass = MemberImpl.method(UnresolvedType.OBJECT, 0, UnresolvedType.JL_CLASS, "getClass", UnresolvedType.NONE);
- il.append(Utility.createInvoke(fact, world, getClass));
- // aload annotationClass
- il.append(fact.createConstant(new ObjectType(hasAnnotation.getAnnotationType().getName())));
- // int annClassIndex = fact.getConstantPool().addClass(hasAnnotation.getAnnotationType().getSignature());
- // il.append(new LDC_W(annClassIndex));
- Member isAnnotationPresent = MemberImpl.method(UnresolvedType.JL_CLASS, 0, UnresolvedType.BOOLEAN, "isAnnotationPresent",
- new UnresolvedType[] { UnresolvedType.JL_CLASS });
- il.append(Utility.createInvoke(fact, world, isAnnotationPresent));
- il.append(createJumpBasedOnBooleanOnStack());
- instructions.insert(il);
- hasAnnotation.getVar().accept(this);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.aspectj.weaver.ast.ITestVisitor#visit(org.aspectj.weaver.internal.tools.MatchingContextBasedTest)
- */
- public void visit(MatchingContextBasedTest matchingContextTest) {
- throw new UnsupportedOperationException("matching context extension not supported in bytecode weaving");
- }
-
- private InstructionList createJumpBasedOnBooleanOnStack() {
- InstructionList il = new InstructionList();
- if (sk == fk) {
- // don't bother generating if it doesn't matter
- if (sk != next) {
- il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk));
- }
- return il;
- }
-
- if (fk == next) {
- il.insert(InstructionFactory.createBranchInstruction(Constants.IFNE, sk));
- } else if (sk == next) {
- il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk));
- } else {
- il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk));
- il.insert(InstructionFactory.createBranchInstruction(Constants.IFEQ, fk));
- }
- return il;
- }
-
- public void visit(Literal literal) {
- if (literal == Literal.FALSE) {
- throw new BCException("visiting a false expression");
- }
- }
-
- public void visit(Call call) {
- Member method = call.getMethod();
- // assert method.isStatic()
- Expr[] args = call.getArgs();
- InstructionList callIl = new InstructionList();
- for (int i = 0, len = args.length; i < len; i++) {
- // XXX only correct for static method calls
- Type desiredType = BcelWorld.makeBcelType(method.getParameterTypes()[i]);
- Expr arg = args[i];
- // if arg is null it is because we couldn't bind it properly, for example see 162135
- if (arg == null) {
- InstructionList iList = new InstructionList();
- iList.append(InstructionFactory.createNull(desiredType));
- callIl.append(iList);
- } else {
- callIl.append(renderExpr(fact, world, arg, desiredType));
- }
- }
- // System.out.println("rendered args: " + callIl);
- callIl.append(Utility.createInvoke(fact, world, method));
- callIl.append(createJumpBasedOnBooleanOnStack());
- instructions.insert(callIl);
- }
-
- public void visit(FieldGetCall fieldGetCall) {
- Member field = fieldGetCall.getField();
- Member method = fieldGetCall.getMethod();
- InstructionList il = new InstructionList();
- il.append(Utility.createGet(fact, field));
- // assert !method.isStatic()
- Expr[] args = fieldGetCall.getArgs();
- // System.out.println("args: " + Arrays.asList(args));
- il.append(renderExprs(fact, world, args));
- // System.out.println("rendered args: " + callIl);
- il.append(Utility.createInvoke(fact, world, method));
- il.append(createJumpBasedOnBooleanOnStack());
- instructions.insert(il);
- }
-
- // ---- expr visitors
-
- public void visit(Var var) {
- BcelVar bvar = (BcelVar) var;
- bvar.insertLoad(instructions, fact);
- }
-
- public void visit(FieldGet fieldGet) {
- Member field = fieldGet.getField();
- // assert field.isStatic()
- instructions.insert(Utility.createGet(fact, field));
- }
-
- public void visit(CallExpr call) {
- Member method = call.getMethod();
- // assert method.isStatic()
- Expr[] args = call.getArgs();
- InstructionList callIl = renderExprs(fact, world, args);
- callIl.append(Utility.createInvoke(fact, world, method));
- instructions.insert(callIl);
- }
-
- }
|