From cb46b4aa17ef055539ec9b6a7335564d2bc388d7 Mon Sep 17 00:00:00 2001 From: aclement Date: Sun, 31 Aug 2008 22:08:32 +0000 Subject: [PATCH] remove unused code --- .../src/org/aspectj/weaver/ast/CastExpr.java | 48 - weaver/src/org/aspectj/weaver/ast/Expr.java | 15 +- .../org/aspectj/weaver/ast/FieldGetOn.java | 41 - .../org/aspectj/weaver/ast/IExprVisitor.java | 23 +- .../aspectj/weaver/ast/StringConstExpr.java | 45 - .../org/aspectj/weaver/bcel/BcelRenderer.java | 369 +-- .../org/aspectj/weaver/bcel/BcelWeaver.java | 2224 +++++++------- .../org/aspectj/weaver/bcel/BcelWorld.java | 12 - .../org/aspectj/weaver/bcel/LazyClassGen.java | 18 +- .../aspectj/weaver/bcel/LazyMethodGen.java | 2646 ++++++++--------- weaver/src/org/aspectj/weaver/bcel/Range.java | 362 +-- .../aspectj/weaver/bcel/UnwovenClassFile.java | 153 +- .../src/org/aspectj/weaver/bcel/Utility.java | 1223 ++++---- .../weaver/patterns/FormalBinding.java | 91 +- .../testsrc/org/aspectj/weaver/TestUtils.java | 624 ++-- 15 files changed, 3706 insertions(+), 4188 deletions(-) delete mode 100644 weaver/src/org/aspectj/weaver/ast/CastExpr.java delete mode 100644 weaver/src/org/aspectj/weaver/ast/FieldGetOn.java delete mode 100644 weaver/src/org/aspectj/weaver/ast/StringConstExpr.java diff --git a/weaver/src/org/aspectj/weaver/ast/CastExpr.java b/weaver/src/org/aspectj/weaver/ast/CastExpr.java deleted file mode 100644 index 3bb07f4aa..000000000 --- a/weaver/src/org/aspectj/weaver/ast/CastExpr.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 Contributors. - * 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.ast; - -import org.aspectj.weaver.ResolvedType; - -/** - * Represents a cast expression. - *

- * Used when aspectOf is not existing in the aspect class (no pre-processing of aspects) ie when - * Object Aspects.aspectOf(..) API is used. - * - * @author Alexandre Vasseur - */ -public class CastExpr extends Expr { - - private String m_castToTypeName; - - private CallExpr m_expr; - - public CastExpr(CallExpr expr, String castToSignature) { - super(); - m_expr = expr; - m_castToTypeName = castToSignature; - } - - public void accept(IExprVisitor v) { - v.visit(m_expr); - v.visit(this); - } - - public String getTypeName() { - return m_castToTypeName; - } - - public ResolvedType getType() { - throw new RuntimeException("not supported"); - } -} diff --git a/weaver/src/org/aspectj/weaver/ast/Expr.java b/weaver/src/org/aspectj/weaver/ast/Expr.java index 238510a1e..1b22c8f42 100644 --- a/weaver/src/org/aspectj/weaver/ast/Expr.java +++ b/weaver/src/org/aspectj/weaver/ast/Expr.java @@ -10,7 +10,6 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.ast; import org.aspectj.weaver.Member; @@ -21,23 +20,15 @@ public abstract class Expr extends ASTNode { public Expr() { super(); } - - public static final Expr[] NONE = new Expr[0]; - public abstract void accept(IExprVisitor v); + public static final Expr[] NONE = new Expr[0]; - public abstract ResolvedType getType(); + public abstract void accept(IExprVisitor v); - public static FieldGet makeFieldGet(Member myField, ResolvedType inAspect) { - return new FieldGet(myField, inAspect); - } + public abstract ResolvedType getType(); public static CallExpr makeCallExpr(Member member, Expr[] exprs, ResolvedType returnType) { return new CallExpr(member, exprs, returnType); } - public static Expr makeStringConstantExpr(final String stringConst) { - return new StringConstExpr(stringConst); - } - } diff --git a/weaver/src/org/aspectj/weaver/ast/FieldGetOn.java b/weaver/src/org/aspectj/weaver/ast/FieldGetOn.java deleted file mode 100644 index 6bf0d38d8..000000000 --- a/weaver/src/org/aspectj/weaver/ast/FieldGetOn.java +++ /dev/null @@ -1,41 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 Contributors. - * 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.ast; - -import org.aspectj.weaver.Member; -import org.aspectj.weaver.UnresolvedType; - -/** - * Represents a field access on a given type. - *

- * Used when aspectOf is not existing in the aspect class (no pre-processing of aspects) - * - * @author Alexandre Vasseur - */ -public class FieldGetOn extends FieldGet { - - private UnresolvedType m_declaringType; - - public FieldGetOn(Member field, UnresolvedType declaringType) { - super(field, null); - m_declaringType = declaringType; - } - - public UnresolvedType getDeclaringType() { - return m_declaringType; - } - - public void accept(IExprVisitor v) { - v.visit(this); - } - -} diff --git a/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java b/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java index 47392e802..89e0b3d74 100644 --- a/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java +++ b/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java @@ -10,33 +10,14 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.ast; - public interface IExprVisitor { void visit(Var i); - void visit(FieldGet fieldGet); - void visit(CallExpr callExpr); - - /** - * Visit a string constant - * @param stringConstExpr - */ - void visit(StringConstExpr stringConstExpr); - /** - * Visit a CHECKCAST instruction - * @param castExpr - */ - void visit(CastExpr castExpr); - - /** - * Visit a field GET - * @param fieldGetOn - */ - void visit(FieldGetOn fieldGetOn); + void visit(FieldGet fieldGet); + void visit(CallExpr callExpr); } diff --git a/weaver/src/org/aspectj/weaver/ast/StringConstExpr.java b/weaver/src/org/aspectj/weaver/ast/StringConstExpr.java deleted file mode 100644 index c48e72e37..000000000 --- a/weaver/src/org/aspectj/weaver/ast/StringConstExpr.java +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005 Contributors. - * 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://eclipse.org/legal/epl-v10.html - * - * Contributors: - * initial implementation Alexandre Vasseur - *******************************************************************************/ -package org.aspectj.weaver.ast; - -import org.aspectj.weaver.ast.Expr; -import org.aspectj.weaver.ast.IExprVisitor; -import org.aspectj.weaver.ResolvedType; - -/** - * Represents a String constant instruction. - *

- * Used when aspectOf is not existing in the aspect class (no pre-processing of aspects) - * - * @author Alexandre Vasseur - */ -public class StringConstExpr extends Expr { - - private String m_stringConst; - - public StringConstExpr(String stringConst) { - super(); - m_stringConst = stringConst; - } - - public void accept(IExprVisitor v) { - v.visit(this); - } - - public ResolvedType getType() { - throw new RuntimeException("not supported"); - } - - public String getStringConst() { - return m_stringConst; - } -} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java index a26d46f0a..5b8efc31b 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java @@ -10,7 +10,6 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.bcel; import org.aspectj.apache.bcel.Constants; @@ -28,11 +27,9 @@ 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.CastExpr; import org.aspectj.weaver.ast.Expr; import org.aspectj.weaver.ast.FieldGet; import org.aspectj.weaver.ast.FieldGetCall; -import org.aspectj.weaver.ast.FieldGetOn; import org.aspectj.weaver.ast.HasAnnotation; import org.aspectj.weaver.ast.IExprVisitor; import org.aspectj.weaver.ast.ITestVisitor; @@ -40,7 +37,6 @@ 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.StringConstExpr; import org.aspectj.weaver.ast.Test; import org.aspectj.weaver.ast.Var; import org.aspectj.weaver.internal.tools.MatchingContextBasedTest; @@ -48,209 +44,172 @@ 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; + private InstructionList instructions; + private InstructionFactory fact; + private BcelWorld world; - InstructionHandle sk, fk, next = null; + InstructionHandle sk, fk, next = null; - private BcelRenderer(InstructionFactory fact, BcelWorld world) { - super(); - this.fact = fact; - this.world = world; - this.instructions = new InstructionList(); - } + 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; - } + // ---- renderers - 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; - } + public static InstructionList renderExpr(InstructionFactory fact, BcelWorld world, Expr e) { + BcelRenderer renderer = new BcelRenderer(fact, world); + e.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; - } + 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; + } - /* - * 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) - * - * @returns the instruction list representing this expression - */ - public static InstructionList renderTest( - InstructionFactory fact, - BcelWorld world, - Test e, - InstructionHandle sk, - InstructionHandle fk) - { - return renderTest(fact, world, e, sk, fk, null); - } + 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; + } - // ---- recurrers + /* + * 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; + } - private void recur( - Test e, - InstructionHandle sk, - InstructionHandle fk, - InstructionHandle next) - { - this.sk = sk; - this.fk = fk; - this.next = next; - e.accept(this); - } + // ---- recurrers - // ---- test visitors + private void recur(Test e, InstructionHandle sk, InstructionHandle fk, InstructionHandle next) { + this.sk = sk; + this.fk = fk; + this.next = next; + e.accept(this); + } - public void visit(And e) { - InstructionHandle savedFk = fk; - recur(e.getRight(), sk, fk, next); - InstructionHandle ning = instructions.getStart(); - recur(e.getLeft(), ning, savedFk, ning); - } + // ---- test visitors - 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(And e) { + InstructionHandle savedFk = fk; + recur(e.getRight(), sk, fk, next); + InstructionHandle ning = instructions.getStart(); + recur(e.getLeft(), ning, savedFk, ning); + } - public void visit(Not e) { - recur(e.getBody(), fk, sk, next); - } + 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(Instanceof i) { - instructions.insert(createJumpBasedOnBooleanOnStack()); - instructions.insert( - Utility.createInstanceof(fact, (ReferenceType) BcelWorld.makeBcelType(i.getType()))); - i.getVar().accept(this); - } + public void visit(Not e) { + recur(e.getBody(), fk, sk, next); + } - public void visit(HasAnnotation hasAnnotation) { - // in Java: - // foo.class.isAnnotationPresent(annotationClass); - // in bytecode: - // 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(); - Member getClass = MemberImpl.method(UnresolvedType.OBJECT, 0, UnresolvedType.JAVA_LANG_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.JAVA_LANG_CLASS,0,ResolvedType.BOOLEAN,"isAnnotationPresent",new UnresolvedType[]{UnresolvedType.JAVA_LANG_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() { + 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: + // 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 (sk == fk) { - // don't bother generating if it doesn't matter - if (sk != next) { - il.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, sk)); - } - return il; - } + Member getClass = MemberImpl.method(UnresolvedType.OBJECT, 0, UnresolvedType.JAVA_LANG_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.JAVA_LANG_CLASS, 0, ResolvedType.BOOLEAN, + "isAnnotationPresent", new UnresolvedType[] { UnresolvedType.JAVA_LANG_CLASS }); + il.append(Utility.createInvoke(fact, world, isAnnotationPresent)); + il.append(createJumpBasedOnBooleanOnStack()); + instructions.insert(il); + hasAnnotation.getVar().accept(this); + } - 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; + /* + * (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("bad"); - } + public void visit(Literal literal) { + if (literal == Literal.FALSE) + throw new BCException("bad"); + } public void visit(Call call) { Member method = call.getMethod(); // assert method.isStatic() Expr[] args = call.getArgs(); - //System.out.println("args: " + Arrays.asList(args)); + // System.out.println("args: " + Arrays.asList(args)); InstructionList callIl = new InstructionList(); - for (int i=0, len=args.length; i < len; i++) { - //XXX only correct for static method calls + for (int i = 0, len = args.length; i < len; i++) { + // XXX only correct for static method calls Type desiredType = BcelWorld.makeBcelType(method.getParameterTypes()[i]); callIl.append(renderExpr(fact, world, args[i], desiredType)); } - //System.out.println("rendered args: " + callIl); + // System.out.println("rendered args: " + callIl); callIl.append(Utility.createInvoke(fact, world, method)); callIl.append(createJumpBasedOnBooleanOnStack()); - instructions.insert(callIl); + instructions.insert(callIl); } public void visit(FieldGetCall fieldGetCall) { @@ -260,58 +219,34 @@ public final class BcelRenderer implements ITestVisitor, IExprVisitor { 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); + // 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); + instructions.insert(il); } - // ---- expr visitors + // ---- expr visitors - public void visit(Var var) { - BcelVar bvar = (BcelVar) var; - bvar.insertLoad(instructions, fact); - } - - public void visit(FieldGet fieldGet) { + 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)); - } - + 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); + InstructionList callIl = renderExprs(fact, world, args); callIl.append(Utility.createInvoke(fact, world, method)); - instructions.insert(callIl); + instructions.insert(callIl); } - /** - * Visit a string constant - * @param stringConst - */ - public void visit(StringConstExpr stringConst) { - instructions.insert(fact.createConstant(stringConst.getStringConst())); - } - - /** - * Visit a CHECKCAST - * @param castExpr - */ - public void visit(CastExpr castExpr) { - instructions.append(fact.createCheckCast(new ObjectType(castExpr.getTypeName()))); - } - - /** - * Visit a field GET (static or not, depends on the field) - * @param fieldGet - */ - public void visit(FieldGetOn fieldGet) { - Member field = fieldGet.getField(); - instructions.insert(Utility.createGetOn(fact, field, fieldGet.getDeclaringType())); - } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java index f253a3900..1430f0929 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -11,10 +11,8 @@ * Alexandre Vasseur support for @AJ aspects * ******************************************************************/ - package org.aspectj.weaver.bcel; - import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileFilter; @@ -47,7 +45,6 @@ import org.aspectj.apache.bcel.classfile.ClassParser; import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.asm.AsmManager; import org.aspectj.bridge.IMessage; -import org.aspectj.bridge.IProgressListener; import org.aspectj.bridge.ISourceLocation; import org.aspectj.bridge.Message; import org.aspectj.bridge.MessageUtil; @@ -96,144 +93,138 @@ import org.aspectj.weaver.patterns.WithinPointcut; import org.aspectj.weaver.tools.Trace; import org.aspectj.weaver.tools.TraceFactory; - public class BcelWeaver { public static final String CLOSURE_CLASS_PREFIX = "$Ajc"; - + public static final String SYNTHETIC_CLASS_POSTFIX = "$ajc"; - - private BcelWorld world; - private CrosscuttingMembersSet xcutSet; - private IProgressListener progressListener = null; - private double progressMade; - private double progressPerClassFile; - - private boolean inReweavableMode = false; - - private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWeaver.class); - - public BcelWeaver(BcelWorld world) { - super(); - if (trace.isTraceEnabled()) trace.enter("",this,world); - this.world = world; - this.xcutSet = world.getCrosscuttingMembersSet(); - if (trace.isTraceEnabled()) trace.exit(""); - } - - public BcelWeaver() { - this(new BcelWorld()); - } - - // ---- fields -// private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ - private List addedClasses = new ArrayList(); /* List */ - private List deletedTypenames = new ArrayList(); /* List */ -// private Map resources = new HashMap(); /* String -> UnwovenClassFile */ + + private BcelWorld world; + private CrosscuttingMembersSet xcutSet; + + private boolean inReweavableMode = false; + + private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelWeaver.class); + + public BcelWeaver(BcelWorld world) { + super(); + if (trace.isTraceEnabled()) + trace.enter("", this, world); + this.world = world; + this.xcutSet = world.getCrosscuttingMembersSet(); + if (trace.isTraceEnabled()) + trace.exit(""); + } + + // ---- fields + // private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ + private List addedClasses = new ArrayList(); /* List */ + private List deletedTypenames = new ArrayList(); /* List */ + // private Map resources = new HashMap(); /* String -> UnwovenClassFile */ private Manifest manifest = null; - private boolean needToReweaveWorld = false; + private boolean needToReweaveWorld = false; - private boolean isBatchWeave = true; - private List shadowMungerList = null; // setup by prepareForWeave + private boolean isBatchWeave = true; + private List shadowMungerList = null; // setup by prepareForWeave private List typeMungerList = null; // setup by prepareForWeave - private List lateTypeMungerList = null; // setup by prepareForWeave + private List lateTypeMungerList = null; // setup by prepareForWeave private List declareParentsList = null; // setup by prepareForWeave - private ZipOutputStream zipOutputStream; + private ZipOutputStream zipOutputStream; private CustomMungerFactory customMungerFactory; // ---- - + // only called for testing - public void setShadowMungers(List l) { - shadowMungerList = l; - } - - - /** - * Add the given aspect to the weaver. - * The type is resolved to support DOT for static inner classes as well as DOLLAR - * - * @param aspectName - * @return aspect - */ - public ResolvedType addLibraryAspect(String aspectName) { - if (trace.isTraceEnabled()) trace.enter("addLibraryAspect",this,aspectName); - - // 1 - resolve as is - UnresolvedType unresolvedT = UnresolvedType.forName(aspectName); - unresolvedT.setNeedsModifiableDelegate(true); - ResolvedType type = world.resolve(unresolvedT, true); - if (type.isMissing()) { - // fallback on inner class lookup mechanism - String fixedName = aspectName; - int hasDot = fixedName.lastIndexOf('.'); - while (hasDot > 0) { - //System.out.println("BcelWeaver.addLibraryAspect " + fixedName); - char[] fixedNameChars = fixedName.toCharArray(); - fixedNameChars[hasDot] = '$'; - fixedName = new String(fixedNameChars); - hasDot = fixedName.lastIndexOf('.'); - UnresolvedType ut = UnresolvedType.forName(fixedName); - ut.setNeedsModifiableDelegate(true); - type = world.resolve(ut, true); - if (!type.isMissing()) { - break; - } - } - } - - //System.out.println("type: " + type + " for " + aspectName); + public void setShadowMungers(List l) { + shadowMungerList = l; + } + + /** + * Add the given aspect to the weaver. The type is resolved to support DOT for static inner classes as well as DOLLAR + * + * @param aspectName + * @return aspect + */ + public ResolvedType addLibraryAspect(String aspectName) { + if (trace.isTraceEnabled()) + trace.enter("addLibraryAspect", this, aspectName); + + // 1 - resolve as is + UnresolvedType unresolvedT = UnresolvedType.forName(aspectName); + unresolvedT.setNeedsModifiableDelegate(true); + ResolvedType type = world.resolve(unresolvedT, true); + if (type.isMissing()) { + // fallback on inner class lookup mechanism + String fixedName = aspectName; + int hasDot = fixedName.lastIndexOf('.'); + while (hasDot > 0) { + // System.out.println("BcelWeaver.addLibraryAspect " + fixedName); + char[] fixedNameChars = fixedName.toCharArray(); + fixedNameChars[hasDot] = '$'; + fixedName = new String(fixedNameChars); + hasDot = fixedName.lastIndexOf('.'); + UnresolvedType ut = UnresolvedType.forName(fixedName); + ut.setNeedsModifiableDelegate(true); + type = world.resolve(ut, true); + if (!type.isMissing()) { + break; + } + } + } + + // System.out.println("type: " + type + " for " + aspectName); if (type.isAspect()) { - + // Bug 119657 ensure we use the unwoven aspect - WeaverStateInfo wsi = type.getWeaverState(); + WeaverStateInfo wsi = type.getWeaverState(); if (wsi != null && wsi.isReweavable()) { - BcelObjectType classType = getClassType(type.getName()); + BcelObjectType classType = getClassType(type.getName()); JavaClass wovenJavaClass = classType.getJavaClass(); - JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(), - wsi.getUnwovenClassFileData(wovenJavaClass.getBytes())); + JavaClass unwovenJavaClass = Utility.makeJavaClass(wovenJavaClass.getFileName(), wsi + .getUnwovenClassFileData(wovenJavaClass.getBytes())); world.storeClass(unwovenJavaClass); classType.setJavaClass(unwovenJavaClass); -// classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); + // classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), + // wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); } - - //TODO AV - happens to reach that a lot of time: for each type flagged reweavable X for each aspect in the weaverstate - //=> mainly for nothing for LTW - pbly for something in incremental build... + + // TODO AV - happens to reach that a lot of time: for each type flagged reweavable X for each aspect in the weaverstate + // => mainly for nothing for LTW - pbly for something in incremental build... xcutSet.addOrReplaceAspect(type); - if (trace.isTraceEnabled()) trace.exit("addLibraryAspect",type); - if (type.getSuperclass().isAspect()) { - // If the supertype includes ITDs and the user has not included that aspect in the aop.xml, they will - // not get picked up, which can give unusual behaviour! See bug 223094 - // This change causes us to pick up the super aspect regardless of what was said in the aop.xml - giving - // predictable behaviour. If the user also supplied it, there will be no problem other than the second - // addition overriding the first - addLibraryAspect(type.getSuperclass().getName()); - } - return type; - } else { - // FIXME AV - better warning upon no such aspect from aop.xml + if (trace.isTraceEnabled()) + trace.exit("addLibraryAspect", type); + if (type.getSuperclass().isAspect()) { + // If the supertype includes ITDs and the user has not included that aspect in the aop.xml, they will + // not get picked up, which can give unusual behaviour! See bug 223094 + // This change causes us to pick up the super aspect regardless of what was said in the aop.xml - giving + // predictable behaviour. If the user also supplied it, there will be no problem other than the second + // addition overriding the first + addLibraryAspect(type.getSuperclass().getName()); + } + return type; + } else { + // FIXME AV - better warning upon no such aspect from aop.xml RuntimeException ex = new RuntimeException("Cannot register non aspect: " + type.getName() + " , " + aspectName); - if (trace.isTraceEnabled()) trace.exit("addLibraryAspect",ex); + if (trace.isTraceEnabled()) + trace.exit("addLibraryAspect", ex); throw ex; } - } - - + } - /** - * - * @param inFile File path to class directory or zip/jar class archive - * @throws IOException - */ - public void addLibraryJarFile(File inFile) throws IOException { + /** + * + * @param inFile File path to class directory or zip/jar class archive + * @throws IOException + */ + public void addLibraryJarFile(File inFile) throws IOException { List addedAspects = null; if (inFile.isDirectory()) { addedAspects = addAspectsFromDirectory(inFile); } else { addedAspects = addAspectsFromJarFile(inFile); } - + for (Iterator i = addedAspects.iterator(); i.hasNext();) { ResolvedType aspectX = (ResolvedType) i.next(); xcutSet.addOrReplaceAspect(aspectX); @@ -241,456 +232,449 @@ public class BcelWeaver { } private List addAspectsFromJarFile(File inFile) throws FileNotFoundException, IOException { - ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered + ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); // ??? buffered List addedAspects = new ArrayList(); while (true) { ZipEntry entry = inStream.getNextEntry(); - if (entry == null) break; - + if (entry == null) + break; + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { continue; } - + // FIXME ASC performance? of this alternative soln. ClassParser parser = new ClassParser(new ByteArrayInputStream(FileUtil.readAsByteArray(inStream)), entry.getName()); - JavaClass jc = parser.parse(); + JavaClass jc = parser.parse(); inStream.closeEntry(); - + ResolvedType type = world.addSourceObjectType(jc).getResolvedTypeX(); type.setBinaryPath(inFile.getAbsolutePath()); - if (type.isAspect()) { - addedAspects.add(type); - } - + if (type.isAspect()) { + addedAspects.add(type); + } + } - + inStream.close(); return addedAspects; } - private List addAspectsFromDirectory(File dir) throws FileNotFoundException, IOException{ + private List addAspectsFromDirectory(File dir) throws FileNotFoundException, IOException { List addedAspects = new ArrayList(); - File[] classFiles = FileUtil.listFiles(dir,new FileFilter(){ - + File[] classFiles = FileUtil.listFiles(dir, new FileFilter() { + public boolean accept(File pathname) { return pathname.getName().endsWith(".class"); } - + }); for (int i = 0; i < classFiles.length; i++) { FileInputStream fis = new FileInputStream(classFiles[i]); byte[] bytes = FileUtil.readAsByteArray(fis); - addIfAspect(bytes,classFiles[i].getAbsolutePath(),addedAspects,dir); + addIfAspect(bytes, classFiles[i].getAbsolutePath(), addedAspects, dir); fis.close(); } return addedAspects; } - + private void addIfAspect(byte[] bytes, String name, List toList, File dir) throws IOException { - ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes),name); + ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), name); JavaClass jc = parser.parse(); ResolvedType type = world.addSourceObjectType(jc).getResolvedTypeX(); String typeName = type.getName().replace('.', File.separatorChar); - int end = name.lastIndexOf(typeName+".class"); + int end = name.lastIndexOf(typeName + ".class"); String binaryPath = null; // if end is -1 then something wierd happened, the class file is not in the correct place, something like // bin/A.class when the declaration for A specifies it is in a package. - if (end==-1) { + if (end == -1) { binaryPath = dir.getAbsolutePath(); } else { - binaryPath = name.substring(0,end-1); + binaryPath = name.substring(0, end - 1); } - type.setBinaryPath(binaryPath); + type.setBinaryPath(binaryPath); if (type.isAspect()) { toList.add(type); } } - -// // The ANT copy task should be used to copy resources across. -// private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false; + // // The ANT copy task should be used to copy resources across. + // private final static boolean CopyResourcesFromInpathDirectoriesToOutput=false; /** - * Add any .class files in the directory to the outdir. Anything other than .class files in - * the directory (or its subdirectories) are considered resources and are also copied. - * + * Add any .class files in the directory to the outdir. Anything other than .class files in the directory (or its + * subdirectories) are considered resources and are also copied. + * */ - public List addDirectoryContents(File inFile,File outDir) throws IOException { + public List addDirectoryContents(File inFile, File outDir) throws IOException { List addedClassFiles = new ArrayList(); - + // Get a list of all files (i.e. everything that isnt a directory) - File[] files = FileUtil.listFiles(inFile,new FileFilter() { + File[] files = FileUtil.listFiles(inFile, new FileFilter() { public boolean accept(File f) { boolean accept = !f.isDirectory(); return accept; } }); - + // For each file, add it either as a real .class file or as a resource for (int i = 0; i < files.length; i++) { - addedClassFiles.add(addClassFile(files[i],inFile,outDir)); + addedClassFiles.add(addClassFile(files[i], inFile, outDir)); } - + return addedClassFiles; } - - /** Adds all class files in the jar + /** + * Adds all class files in the jar */ - public List addJarFile(File inFile, File outDir, boolean canBeDirectory){ -// System.err.println("? addJarFile(" + inFile + ", " + outDir + ")"); + public List addJarFile(File inFile, File outDir, boolean canBeDirectory) { + // System.err.println("? addJarFile(" + inFile + ", " + outDir + ")"); List addedClassFiles = new ArrayList(); needToReweaveWorld = true; JarFile inJar = null; - + try { // Is this a directory we are looking at? if (inFile.isDirectory() && canBeDirectory) { - addedClassFiles.addAll(addDirectoryContents(inFile,outDir)); + addedClassFiles.addAll(addDirectoryContents(inFile, outDir)); } else { - + inJar = new JarFile(inFile); addManifest(inJar.getManifest()); Enumeration entries = inJar.entries(); - + while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry)entries.nextElement(); + JarEntry entry = (JarEntry) entries.nextElement(); InputStream inStream = inJar.getInputStream(entry); - + byte[] bytes = FileUtil.readAsByteArray(inStream); String filename = entry.getName(); -// System.out.println("? addJarFile() filename='" + filename + "'"); + // System.out.println("? addJarFile() filename='" + filename + "'"); UnwovenClassFile classFile = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes); if (filename.endsWith(".class")) { this.addClassFile(classFile); addedClassFiles.add(classFile); } -// else if (!entry.isDirectory()) { -// -// /* bug-44190 Copy meta-data */ -// addResource(filename,classFile); -// } + // else if (!entry.isDirectory()) { + // + // /* bug-44190 Copy meta-data */ + // addResource(filename,classFile); + // } inStream.close(); } inJar.close(); } } catch (FileNotFoundException ex) { - IMessage message = new Message( - "Could not find input jar file " + inFile.getPath() + ", ignoring", - new SourceLocation(inFile,0), - false); + IMessage message = new Message("Could not find input jar file " + inFile.getPath() + ", ignoring", new SourceLocation( + inFile, 0), false); world.getMessageHandler().handleMessage(message); } catch (IOException ex) { - IMessage message = new Message( - "Could not read input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")", - new SourceLocation(inFile,0), - true); + IMessage message = new Message("Could not read input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")", + new SourceLocation(inFile, 0), true); world.getMessageHandler().handleMessage(message); } finally { if (inJar != null) { - try {inJar.close();} - catch (IOException ex) { - IMessage message = new Message( - "Could not close input jar file " + inFile.getPath() + "(" + ex.getMessage() + ")", - new SourceLocation(inFile,0), - true); - world.getMessageHandler().handleMessage(message); + try { + inJar.close(); + } catch (IOException ex) { + IMessage message = new Message("Could not close input jar file " + inFile.getPath() + "(" + ex.getMessage() + + ")", new SourceLocation(inFile, 0), true); + world.getMessageHandler().handleMessage(message); } } } - + return addedClassFiles; } -// public void addResource(String name, File inPath, File outDir) throws IOException { -// -// /* Eliminate CVS files. Relative paths use "/" */ -// if (!name.startsWith("CVS/") && (-1 == name.indexOf("/CVS/")) && !name.endsWith("/CVS")) { -//// System.err.println("? addResource('" + name + "')"); -//// BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(inPath)); -//// byte[] bytes = new byte[(int)inPath.length()]; -//// inStream.read(bytes); -//// inStream.close(); -// byte[] bytes = FileUtil.readAsByteArray(inPath); -// UnwovenClassFile resourceFile = new UnwovenClassFile(new File(outDir, name).getAbsolutePath(), bytes); -// addResource(name,resourceFile); -// } -// } + // public void addResource(String name, File inPath, File outDir) throws IOException { + // + // /* Eliminate CVS files. Relative paths use "/" */ + // if (!name.startsWith("CVS/") && (-1 == name.indexOf("/CVS/")) && !name.endsWith("/CVS")) { + // // System.err.println("? addResource('" + name + "')"); + // // BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(inPath)); + // // byte[] bytes = new byte[(int)inPath.length()]; + // // inStream.read(bytes); + // // inStream.close(); + // byte[] bytes = FileUtil.readAsByteArray(inPath); + // UnwovenClassFile resourceFile = new UnwovenClassFile(new File(outDir, name).getAbsolutePath(), bytes); + // addResource(name,resourceFile); + // } + // } public boolean needToReweaveWorld() { return needToReweaveWorld; } - - /** Should be addOrReplace - */ - public void addClassFile(UnwovenClassFile classFile) { - addedClasses.add(classFile); -// if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) { -//// throw new RuntimeException(classFile.getClassName()); -// } - world.addSourceObjectType(classFile.getJavaClass()); - } - - public UnwovenClassFile addClassFile(File classFile, File inPathDir, File outDir) throws IOException { + + /** + * Should be addOrReplace + */ + public void addClassFile(UnwovenClassFile classFile) { + addedClasses.add(classFile); + // if (null != sourceJavaClasses.put(classFile.getClassName(), classFile)) { + // // throw new RuntimeException(classFile.getClassName()); + // } + world.addSourceObjectType(classFile.getJavaClass()); + } + + public UnwovenClassFile addClassFile(File classFile, File inPathDir, File outDir) throws IOException { FileInputStream fis = new FileInputStream(classFile); byte[] bytes = FileUtil.readAsByteArray(fis); // String relativePath = files[i].getPath(); - + // ASSERT: files[i].getAbsolutePath().startsWith(inFile.getAbsolutePath() // or we are in trouble... - String filename = classFile.getAbsolutePath().substring( - inPathDir.getAbsolutePath().length()+1); - UnwovenClassFile ucf = new UnwovenClassFile(new File(outDir,filename).getAbsolutePath(),bytes); + String filename = classFile.getAbsolutePath().substring(inPathDir.getAbsolutePath().length() + 1); + UnwovenClassFile ucf = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes); if (filename.endsWith(".class")) { // System.err.println("BCELWeaver: processing class from input directory "+classFile); this.addClassFile(ucf); } fis.close(); return ucf; - } - - - public void deleteClassFile(String typename) { - deletedTypenames.add(typename); -// sourceJavaClasses.remove(typename); - world.deleteSourceObjectType(UnresolvedType.forName(typename)); - } - -// public void addResource (String name, UnwovenClassFile resourceFile) { -// /* bug-44190 Change error to warning and copy first resource */ -// if (!resources.containsKey(name)) { -// resources.put(name, resourceFile); -// } -// else { -// world.showMessage(IMessage.WARNING, "duplicate resource: '" + name + "'", -// null, null); -// } -// } + } + + public void deleteClassFile(String typename) { + deletedTypenames.add(typename); + // sourceJavaClasses.remove(typename); + world.deleteSourceObjectType(UnresolvedType.forName(typename)); + } + + // public void addResource (String name, UnwovenClassFile resourceFile) { + // /* bug-44190 Change error to warning and copy first resource */ + // if (!resources.containsKey(name)) { + // resources.put(name, resourceFile); + // } + // else { + // world.showMessage(IMessage.WARNING, "duplicate resource: '" + name + "'", + // null, null); + // } + // } // ---- weave preparation - public void setIsBatchWeave(boolean b) { - isBatchWeave=b; - } - - public void prepareForWeave() { - if (trace.isTraceEnabled()) trace.enter("prepareForWeave",this); - needToReweaveWorld = xcutSet.hasChangedSinceLastReset(); - - - // update mungers - for (Iterator i = addedClasses.iterator(); i.hasNext(); ) { - UnwovenClassFile jc = (UnwovenClassFile)i.next(); - String name = jc.getClassName(); - ResolvedType type = world.resolve(name); - //System.err.println("added: " + type + " aspect? " + type.isAspect()); - if (type.isAspect()) { - needToReweaveWorld |= xcutSet.addOrReplaceAspect(type); - } - } - - for (Iterator i = deletedTypenames.iterator(); i.hasNext(); ) { - String name = (String)i.next(); - if (xcutSet.deleteAspect(UnresolvedType.forName(name))) needToReweaveWorld = true; - } + public void setIsBatchWeave(boolean b) { + isBatchWeave = b; + } + + public void prepareForWeave() { + if (trace.isTraceEnabled()) + trace.enter("prepareForWeave", this); + needToReweaveWorld = xcutSet.hasChangedSinceLastReset(); + + // update mungers + for (Iterator i = addedClasses.iterator(); i.hasNext();) { + UnwovenClassFile jc = (UnwovenClassFile) i.next(); + String name = jc.getClassName(); + ResolvedType type = world.resolve(name); + // System.err.println("added: " + type + " aspect? " + type.isAspect()); + if (type.isAspect()) { + needToReweaveWorld |= xcutSet.addOrReplaceAspect(type); + } + } + + for (Iterator i = deletedTypenames.iterator(); i.hasNext();) { + String name = (String) i.next(); + if (xcutSet.deleteAspect(UnresolvedType.forName(name))) + needToReweaveWorld = true; + } shadowMungerList = xcutSet.getShadowMungers(); -// world.debug("shadow mungers=" + shadowMungerList); + // world.debug("shadow mungers=" + shadowMungerList); rewritePointcuts(shadowMungerList); // Sometimes an error occurs during rewriting pointcuts (for example, if ambiguous bindings // are detected) - we ought to fail the prepare when this happens because continuing with // inconsistent pointcuts could lead to problems typeMungerList = xcutSet.getTypeMungers(); - lateTypeMungerList = xcutSet.getLateTypeMungers(); + lateTypeMungerList = xcutSet.getLateTypeMungers(); declareParentsList = xcutSet.getDeclareParents(); - + addCustomMungers(); - - // The ordering here used to be based on a string compare on toString() for the two mungers - - // that breaks for the @AJ style where advice names aren't programmatically generated. So we + + // The ordering here used to be based on a string compare on toString() for the two mungers - + // that breaks for the @AJ style where advice names aren't programmatically generated. So we // have changed the sorting to be based on source location in the file - this is reliable, in // the case of source locations missing, we assume they are 'sorted' - i.e. the order in // which they were added to the collection is correct, this enables the @AJ stuff to work properly. - + // When @AJ processing starts filling in source locations for mungers, this code may need // a bit of alteration... - - Collections.sort( - shadowMungerList, - new Comparator() { - public int compare(Object o1, Object o2) { - ShadowMunger sm1 = (ShadowMunger)o1; - ShadowMunger sm2 = (ShadowMunger)o2; - if (sm1.getSourceLocation()==null) return (sm2.getSourceLocation()==null?0:1); - if (sm2.getSourceLocation()==null) return -1; - - return (sm2.getSourceLocation().getOffset()-sm1.getSourceLocation().getOffset()); - } - }); - + + Collections.sort(shadowMungerList, new Comparator() { + public int compare(Object o1, Object o2) { + ShadowMunger sm1 = (ShadowMunger) o1; + ShadowMunger sm2 = (ShadowMunger) o2; + if (sm1.getSourceLocation() == null) + return (sm2.getSourceLocation() == null ? 0 : 1); + if (sm2.getSourceLocation() == null) + return -1; + + return (sm2.getSourceLocation().getOffset() - sm1.getSourceLocation().getOffset()); + } + }); + if (inReweavableMode) - world.showMessage(IMessage.INFO, - WeaverMessages.format(WeaverMessages.REWEAVABLE_MODE), - null, null); - - if (trace.isTraceEnabled()) trace.exit("prepareForWeave"); - } - - private void addCustomMungers() { + world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.REWEAVABLE_MODE), null, null); + + if (trace.isTraceEnabled()) + trace.exit("prepareForWeave"); + } + + private void addCustomMungers() { if (customMungerFactory != null) { for (Iterator i = addedClasses.iterator(); i.hasNext();) { UnwovenClassFile jc = (UnwovenClassFile) i.next(); String name = jc.getClassName(); ResolvedType type = world.resolve(name); if (type.isAspect()) { - Collection/*ShadowMunger*/ shadowMungers = customMungerFactory.createCustomShadowMungers(type); + Collection/* ShadowMunger */shadowMungers = customMungerFactory.createCustomShadowMungers(type); if (shadowMungers != null) { shadowMungerList.addAll(shadowMungers); } - Collection/*ConcreteTypeMunger*/ typeMungers = customMungerFactory - .createCustomTypeMungers(type); + Collection/* ConcreteTypeMunger */typeMungers = customMungerFactory.createCustomTypeMungers(type); if (typeMungers != null) typeMungerList.addAll(typeMungers); } } } } - - public void setCustomMungerFactory(CustomMungerFactory factory) { - customMungerFactory = factory; - } - - /* - * Rewrite all of the pointcuts in the world into their most efficient - * form for subsequent matching. Also ensure that if pc1.equals(pc2) - * then pc1 == pc2 (for non-binding pcds) by making references all - * point to the same instance. - * Since pointcuts remember their match decision on the last shadow, - * this makes matching faster when many pointcuts share common elements, - * or even when one single pointcut has one common element (which can - * be a side-effect of DNF rewriting). - */ - private void rewritePointcuts(List/*ShadowMunger*/ shadowMungers) { - PointcutRewriter rewriter = new PointcutRewriter(); - for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) { + + public void setCustomMungerFactory(CustomMungerFactory factory) { + customMungerFactory = factory; + } + + /* + * Rewrite all of the pointcuts in the world into their most efficient form for subsequent matching. Also ensure that if + * pc1.equals(pc2) then pc1 == pc2 (for non-binding pcds) by making references all point to the same instance. Since pointcuts + * remember their match decision on the last shadow, this makes matching faster when many pointcuts share common elements, or + * even when one single pointcut has one common element (which can be a side-effect of DNF rewriting). + */ + private void rewritePointcuts(List/* ShadowMunger */shadowMungers) { + PointcutRewriter rewriter = new PointcutRewriter(); + for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) { ShadowMunger munger = (ShadowMunger) iter.next(); Pointcut p = munger.getPointcut(); Pointcut newP = rewriter.rewrite(p); // validateBindings now whilst we still have around the pointcut // that resembles what the user actually wrote in their program - // text. + // text. if (munger instanceof Advice) { Advice advice = (Advice) munger; if (advice.getSignature() != null) { final int numFormals; - final String names[]; - // If the advice is being concretized in a @AJ aspect *and* the advice was declared in - // an @AJ aspect (it could have been inherited from a code style aspect) then - // evaluate the alternative set of formals. pr125699 - if (advice.getConcreteAspect().isAnnotationStyleAspect() - && advice.getDeclaringAspect()!=null - && advice.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { - numFormals = advice.getBaseParameterCount(); - int numArgs = advice.getSignature().getParameterTypes().length; - if (numFormals > 0) { - names = advice.getSignature().getParameterNames(world); - validateBindings(newP,p,numArgs,names); - } - } else { - numFormals = advice.getBaseParameterCount(); - if (numFormals > 0) { - names = advice.getBaseParameterNames(world); - validateBindings(newP,p,numFormals,names); - } - } + final String names[]; + // If the advice is being concretized in a @AJ aspect *and* the advice was declared in + // an @AJ aspect (it could have been inherited from a code style aspect) then + // evaluate the alternative set of formals. pr125699 + if (advice.getConcreteAspect().isAnnotationStyleAspect() && advice.getDeclaringAspect() != null + && advice.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) { + numFormals = advice.getBaseParameterCount(); + int numArgs = advice.getSignature().getParameterTypes().length; + if (numFormals > 0) { + names = advice.getSignature().getParameterNames(world); + validateBindings(newP, p, numArgs, names); + } + } else { + numFormals = advice.getBaseParameterCount(); + if (numFormals > 0) { + names = advice.getBaseParameterNames(world); + validateBindings(newP, p, numFormals, names); + } + } } } munger.setPointcut(newP); } - // now that we have optimized individual pointcuts, optimize - // across the set of pointcuts.... - // Use a map from key based on pc equality, to value based on - // pc identity. - Map/**/ pcMap = new HashMap(); - for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) { + // now that we have optimized individual pointcuts, optimize + // across the set of pointcuts.... + // Use a map from key based on pc equality, to value based on + // pc identity. + Map/* */pcMap = new HashMap(); + for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) { ShadowMunger munger = (ShadowMunger) iter.next(); Pointcut p = munger.getPointcut(); - munger.setPointcut(shareEntriesFromMap(p,pcMap)); - } - } - - private Pointcut shareEntriesFromMap(Pointcut p,Map pcMap) { - // some things cant be shared... - if (p instanceof NameBindingPointcut) return p; - if (p instanceof IfPointcut) return p; - if (p instanceof ConcreteCflowPointcut) return p; - if (p instanceof AndPointcut) { - AndPointcut apc = (AndPointcut) p; - Pointcut left = shareEntriesFromMap(apc.getLeft(),pcMap); - Pointcut right = shareEntriesFromMap(apc.getRight(),pcMap); - return new AndPointcut(left,right); - } else if (p instanceof OrPointcut) { - OrPointcut opc = (OrPointcut) p; - Pointcut left = shareEntriesFromMap(opc.getLeft(),pcMap); - Pointcut right = shareEntriesFromMap(opc.getRight(),pcMap); - return new OrPointcut(left,right); - } else if (p instanceof NotPointcut) { - NotPointcut npc = (NotPointcut) p; - Pointcut not = shareEntriesFromMap(npc.getNegatedPointcut(),pcMap); - return new NotPointcut(not); - } else { - // primitive pcd - if (pcMap.containsKey(p)) { // based on equality - return (Pointcut) pcMap.get(p); // same instance (identity) - } else { - pcMap.put(p,p); - return p; - } - } - } - - // userPointcut is the pointcut that the user wrote in the program text. - // dnfPointcut is the same pointcut rewritten in DNF - // numFormals is the number of formal parameters in the pointcut - // if numFormals > 0 then every branch of a disjunction must bind each formal once and only once. - // in addition, the left and right branches of a disjunction must hold on join point kinds in - // common. - private void validateBindings(Pointcut dnfPointcut, Pointcut userPointcut, int numFormals, String[] names) { - if (numFormals == 0) return; // nothing to check - if (dnfPointcut.couldMatchKinds()==Shadow.NO_SHADOW_KINDS_BITS) return; // cant have problems if you dont match! - if (dnfPointcut instanceof OrPointcut) { - OrPointcut orBasedDNFPointcut = (OrPointcut) dnfPointcut; - Pointcut[] leftBindings = new Pointcut[numFormals]; - Pointcut[] rightBindings = new Pointcut[numFormals]; - validateOrBranch(orBasedDNFPointcut,userPointcut,numFormals,names,leftBindings,rightBindings); - } else { - Pointcut[] bindings = new Pointcut[numFormals]; - validateSingleBranch(dnfPointcut, userPointcut, numFormals, names,bindings); - } - } - - private void validateOrBranch(OrPointcut pc, Pointcut userPointcut, int numFormals, - String[] names, Pointcut[] leftBindings, Pointcut[] rightBindings) { - Pointcut left = pc.getLeft(); - Pointcut right = pc.getRight(); - if (left instanceof OrPointcut) { - Pointcut[] newRightBindings = new Pointcut[numFormals]; - validateOrBranch((OrPointcut)left,userPointcut,numFormals,names,leftBindings,newRightBindings); - } else { - if (left.couldMatchKinds()!=Shadow.NO_SHADOW_KINDS_BITS) - validateSingleBranch(left, userPointcut, numFormals, names, leftBindings); - } - if (right instanceof OrPointcut) { - Pointcut[] newLeftBindings = new Pointcut[numFormals]; - validateOrBranch((OrPointcut)right,userPointcut,numFormals,names,newLeftBindings,rightBindings); - } else { - if (right.couldMatchKinds()!=Shadow.NO_SHADOW_KINDS_BITS) - validateSingleBranch(right, userPointcut, numFormals, names, rightBindings); - } + munger.setPointcut(shareEntriesFromMap(p, pcMap)); + } + } + + private Pointcut shareEntriesFromMap(Pointcut p, Map pcMap) { + // some things cant be shared... + if (p instanceof NameBindingPointcut) + return p; + if (p instanceof IfPointcut) + return p; + if (p instanceof ConcreteCflowPointcut) + return p; + if (p instanceof AndPointcut) { + AndPointcut apc = (AndPointcut) p; + Pointcut left = shareEntriesFromMap(apc.getLeft(), pcMap); + Pointcut right = shareEntriesFromMap(apc.getRight(), pcMap); + return new AndPointcut(left, right); + } else if (p instanceof OrPointcut) { + OrPointcut opc = (OrPointcut) p; + Pointcut left = shareEntriesFromMap(opc.getLeft(), pcMap); + Pointcut right = shareEntriesFromMap(opc.getRight(), pcMap); + return new OrPointcut(left, right); + } else if (p instanceof NotPointcut) { + NotPointcut npc = (NotPointcut) p; + Pointcut not = shareEntriesFromMap(npc.getNegatedPointcut(), pcMap); + return new NotPointcut(not); + } else { + // primitive pcd + if (pcMap.containsKey(p)) { // based on equality + return (Pointcut) pcMap.get(p); // same instance (identity) + } else { + pcMap.put(p, p); + return p; + } + } + } + + // userPointcut is the pointcut that the user wrote in the program text. + // dnfPointcut is the same pointcut rewritten in DNF + // numFormals is the number of formal parameters in the pointcut + // if numFormals > 0 then every branch of a disjunction must bind each formal once and only once. + // in addition, the left and right branches of a disjunction must hold on join point kinds in + // common. + private void validateBindings(Pointcut dnfPointcut, Pointcut userPointcut, int numFormals, String[] names) { + if (numFormals == 0) + return; // nothing to check + if (dnfPointcut.couldMatchKinds() == Shadow.NO_SHADOW_KINDS_BITS) + return; // cant have problems if you dont match! + if (dnfPointcut instanceof OrPointcut) { + OrPointcut orBasedDNFPointcut = (OrPointcut) dnfPointcut; + Pointcut[] leftBindings = new Pointcut[numFormals]; + Pointcut[] rightBindings = new Pointcut[numFormals]; + validateOrBranch(orBasedDNFPointcut, userPointcut, numFormals, names, leftBindings, rightBindings); + } else { + Pointcut[] bindings = new Pointcut[numFormals]; + validateSingleBranch(dnfPointcut, userPointcut, numFormals, names, bindings); + } + } + + private void validateOrBranch(OrPointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] leftBindings, + Pointcut[] rightBindings) { + Pointcut left = pc.getLeft(); + Pointcut right = pc.getRight(); + if (left instanceof OrPointcut) { + Pointcut[] newRightBindings = new Pointcut[numFormals]; + validateOrBranch((OrPointcut) left, userPointcut, numFormals, names, leftBindings, newRightBindings); + } else { + if (left.couldMatchKinds() != Shadow.NO_SHADOW_KINDS_BITS) + validateSingleBranch(left, userPointcut, numFormals, names, leftBindings); + } + if (right instanceof OrPointcut) { + Pointcut[] newLeftBindings = new Pointcut[numFormals]; + validateOrBranch((OrPointcut) right, userPointcut, numFormals, names, newLeftBindings, rightBindings); + } else { + if (right.couldMatchKinds() != Shadow.NO_SHADOW_KINDS_BITS) + validateSingleBranch(right, userPointcut, numFormals, names, rightBindings); + } int kindsInCommon = left.couldMatchKinds() & right.couldMatchKinds(); - if (kindsInCommon!=Shadow.NO_SHADOW_KINDS_BITS && couldEverMatchSameJoinPoints(left,right)) { + if (kindsInCommon != Shadow.NO_SHADOW_KINDS_BITS && couldEverMatchSameJoinPoints(left, right)) { // we know that every branch binds every formal, so there is no ambiguity // if each branch binds it in exactly the same way... List ambiguousNames = new ArrayList(); @@ -704,143 +688,151 @@ public class BcelWeaver { } } if (!ambiguousNames.isEmpty()) - raiseAmbiguityInDisjunctionError(userPointcut,ambiguousNames); - } - } - + raiseAmbiguityInDisjunctionError(userPointcut, ambiguousNames); + } + } + // pc is a pointcut that does not contain any disjunctions - // check that every formal is bound (negation doesn't count). - // we know that numFormals > 0 or else we would not be called - private void validateSingleBranch(Pointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] bindings) { - boolean[] foundFormals = new boolean[numFormals]; - for (int i = 0; i < foundFormals.length; i++) { + // check that every formal is bound (negation doesn't count). + // we know that numFormals > 0 or else we would not be called + private void validateSingleBranch(Pointcut pc, Pointcut userPointcut, int numFormals, String[] names, Pointcut[] bindings) { + boolean[] foundFormals = new boolean[numFormals]; + for (int i = 0; i < foundFormals.length; i++) { foundFormals[i] = false; } - validateSingleBranchRecursion(pc, userPointcut, foundFormals, names, bindings); - for (int i = 0; i < foundFormals.length; i++) { + validateSingleBranchRecursion(pc, userPointcut, foundFormals, names, bindings); + for (int i = 0; i < foundFormals.length; i++) { if (!foundFormals[i]) { - boolean ignore = false; - // ATAJ soften the unbound error for implicit bindings like JoinPoint in @AJ style - for (int j = 0; j < userPointcut.m_ignoreUnboundBindingForNames.length; j++) { - if (names[i] != null && names[i].equals(userPointcut.m_ignoreUnboundBindingForNames[j])) { - ignore = true; - break; - } - } - if (!ignore) { - raiseUnboundFormalError(names[i],userPointcut); - } + boolean ignore = false; + // ATAJ soften the unbound error for implicit bindings like JoinPoint in @AJ style + for (int j = 0; j < userPointcut.m_ignoreUnboundBindingForNames.length; j++) { + if (names[i] != null && names[i].equals(userPointcut.m_ignoreUnboundBindingForNames[j])) { + ignore = true; + break; + } + } + if (!ignore) { + raiseUnboundFormalError(names[i], userPointcut); + } } } - } - + } + // each formal must appear exactly once - private void validateSingleBranchRecursion(Pointcut pc, Pointcut userPointcut, boolean[] foundFormals, String[] names, Pointcut[] bindings) { - if (pc instanceof NotPointcut) { - // nots can only appear at leaves in DNF - NotPointcut not = (NotPointcut) pc; - if (not.getNegatedPointcut() instanceof NameBindingPointcut) { - NameBindingPointcut nnbp = (NameBindingPointcut) not.getNegatedPointcut(); - if (!nnbp.getBindingAnnotationTypePatterns().isEmpty() && !nnbp.getBindingTypePatterns().isEmpty()) - raiseNegationBindingError(userPointcut); - } - } else if (pc instanceof AndPointcut) { - AndPointcut and = (AndPointcut) pc; - validateSingleBranchRecursion(and.getLeft(), userPointcut,foundFormals,names,bindings); - validateSingleBranchRecursion(and.getRight(),userPointcut,foundFormals,names,bindings); - } else if (pc instanceof NameBindingPointcut) { - List/*BindingTypePattern*/ btps = ((NameBindingPointcut)pc).getBindingTypePatterns(); - for (Iterator iter = btps.iterator(); iter.hasNext();) { + private void validateSingleBranchRecursion(Pointcut pc, Pointcut userPointcut, boolean[] foundFormals, String[] names, + Pointcut[] bindings) { + if (pc instanceof NotPointcut) { + // nots can only appear at leaves in DNF + NotPointcut not = (NotPointcut) pc; + if (not.getNegatedPointcut() instanceof NameBindingPointcut) { + NameBindingPointcut nnbp = (NameBindingPointcut) not.getNegatedPointcut(); + if (!nnbp.getBindingAnnotationTypePatterns().isEmpty() && !nnbp.getBindingTypePatterns().isEmpty()) + raiseNegationBindingError(userPointcut); + } + } else if (pc instanceof AndPointcut) { + AndPointcut and = (AndPointcut) pc; + validateSingleBranchRecursion(and.getLeft(), userPointcut, foundFormals, names, bindings); + validateSingleBranchRecursion(and.getRight(), userPointcut, foundFormals, names, bindings); + } else if (pc instanceof NameBindingPointcut) { + List/* BindingTypePattern */btps = ((NameBindingPointcut) pc).getBindingTypePatterns(); + for (Iterator iter = btps.iterator(); iter.hasNext();) { BindingTypePattern btp = (BindingTypePattern) iter.next(); int index = btp.getFormalIndex(); - bindings[index] = pc; + bindings[index] = pc; if (foundFormals[index]) { - raiseAmbiguousBindingError(names[index],userPointcut); + raiseAmbiguousBindingError(names[index], userPointcut); } else { foundFormals[index] = true; } } - List/* BindingPattern */baps = ((NameBindingPointcut) pc).getBindingAnnotationTypePatterns(); - for (Iterator iter = baps.iterator(); iter.hasNext();) { - BindingPattern bap = (BindingPattern) iter.next(); + List/* BindingPattern */baps = ((NameBindingPointcut) pc).getBindingAnnotationTypePatterns(); + for (Iterator iter = baps.iterator(); iter.hasNext();) { + BindingPattern bap = (BindingPattern) iter.next(); int index = bap.getFormalIndex(); bindings[index] = pc; if (foundFormals[index]) { - raiseAmbiguousBindingError(names[index],userPointcut); + raiseAmbiguousBindingError(names[index], userPointcut); } else { foundFormals[index] = true; } } - } else if (pc instanceof ConcreteCflowPointcut) { - ConcreteCflowPointcut cfp = (ConcreteCflowPointcut) pc; - int[] slots = cfp.getUsedFormalSlots(); - for (int i = 0; i < slots.length; i++) { - bindings[slots[i]] = cfp; + } else if (pc instanceof ConcreteCflowPointcut) { + ConcreteCflowPointcut cfp = (ConcreteCflowPointcut) pc; + int[] slots = cfp.getUsedFormalSlots(); + for (int i = 0; i < slots.length; i++) { + bindings[slots[i]] = cfp; if (foundFormals[slots[i]]) { - raiseAmbiguousBindingError(names[slots[i]],userPointcut); + raiseAmbiguousBindingError(names[slots[i]], userPointcut); } else { foundFormals[slots[i]] = true; - } + } } - } - } - - - // By returning false from this method, we are allowing binding of the same - // variable on either side of an or. - // Be conservative :- have to consider overriding, varargs, autoboxing, - // the effects of itds (on within for example), interfaces, the fact that - // join points can have multiple signatures and so on. - private boolean couldEverMatchSameJoinPoints(Pointcut left, Pointcut right) { - - if (left instanceof OrPointcut) { - OrPointcut leftOrPointcut = (OrPointcut)left; - if (couldEverMatchSameJoinPoints(leftOrPointcut.getLeft(),right)) return true; - if (couldEverMatchSameJoinPoints(leftOrPointcut.getRight(),right)) return true; - return false; - } - - if (right instanceof OrPointcut) { - OrPointcut rightOrPointcut = (OrPointcut)right; - if (couldEverMatchSameJoinPoints(left,rightOrPointcut.getLeft())) return true; - if (couldEverMatchSameJoinPoints(left,rightOrPointcut.getRight())) return true; - return false; - } - - // look for withins - WithinPointcut leftWithin = (WithinPointcut) findFirstPointcutIn(left,WithinPointcut.class); - WithinPointcut rightWithin = (WithinPointcut) findFirstPointcutIn(right,WithinPointcut.class); - if ((leftWithin != null) && (rightWithin != null)) { - if (!leftWithin.couldEverMatchSameJoinPointsAs(rightWithin)) return false; - } - // look for kinded - KindedPointcut leftKind = (KindedPointcut) findFirstPointcutIn(left,KindedPointcut.class); - KindedPointcut rightKind = (KindedPointcut) findFirstPointcutIn(right,KindedPointcut.class); - if ((leftKind != null) && (rightKind != null)) { - if (!leftKind.couldEverMatchSameJoinPointsAs(rightKind)) return false; - } - return true; - } - - private Pointcut findFirstPointcutIn(Pointcut toSearch, Class toLookFor) { - if (toSearch instanceof NotPointcut) return null; - if (toLookFor.isInstance(toSearch)) return toSearch; - if (toSearch instanceof AndPointcut) { - AndPointcut apc = (AndPointcut) toSearch; - Pointcut left = findFirstPointcutIn(apc.getLeft(),toLookFor); - if (left != null) return left; - return findFirstPointcutIn(apc.getRight(),toLookFor); - } - return null; - } - - /** + } + } + + // By returning false from this method, we are allowing binding of the same + // variable on either side of an or. + // Be conservative :- have to consider overriding, varargs, autoboxing, + // the effects of itds (on within for example), interfaces, the fact that + // join points can have multiple signatures and so on. + private boolean couldEverMatchSameJoinPoints(Pointcut left, Pointcut right) { + + if (left instanceof OrPointcut) { + OrPointcut leftOrPointcut = (OrPointcut) left; + if (couldEverMatchSameJoinPoints(leftOrPointcut.getLeft(), right)) + return true; + if (couldEverMatchSameJoinPoints(leftOrPointcut.getRight(), right)) + return true; + return false; + } + + if (right instanceof OrPointcut) { + OrPointcut rightOrPointcut = (OrPointcut) right; + if (couldEverMatchSameJoinPoints(left, rightOrPointcut.getLeft())) + return true; + if (couldEverMatchSameJoinPoints(left, rightOrPointcut.getRight())) + return true; + return false; + } + + // look for withins + WithinPointcut leftWithin = (WithinPointcut) findFirstPointcutIn(left, WithinPointcut.class); + WithinPointcut rightWithin = (WithinPointcut) findFirstPointcutIn(right, WithinPointcut.class); + if ((leftWithin != null) && (rightWithin != null)) { + if (!leftWithin.couldEverMatchSameJoinPointsAs(rightWithin)) + return false; + } + // look for kinded + KindedPointcut leftKind = (KindedPointcut) findFirstPointcutIn(left, KindedPointcut.class); + KindedPointcut rightKind = (KindedPointcut) findFirstPointcutIn(right, KindedPointcut.class); + if ((leftKind != null) && (rightKind != null)) { + if (!leftKind.couldEverMatchSameJoinPointsAs(rightKind)) + return false; + } + return true; + } + + private Pointcut findFirstPointcutIn(Pointcut toSearch, Class toLookFor) { + if (toSearch instanceof NotPointcut) + return null; + if (toLookFor.isInstance(toSearch)) + return toSearch; + if (toSearch instanceof AndPointcut) { + AndPointcut apc = (AndPointcut) toSearch; + Pointcut left = findFirstPointcutIn(apc.getLeft(), toLookFor); + if (left != null) + return left; + return findFirstPointcutIn(apc.getRight(), toLookFor); + } + return null; + } + + /** * @param userPointcut */ private void raiseNegationBindingError(Pointcut userPointcut) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.NEGATION_DOESNT_ALLOW_BINDING), - userPointcut.getSourceContext().makeSourceLocation(userPointcut),null); + world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.NEGATION_DOESNT_ALLOW_BINDING), userPointcut + .getSourceContext().makeSourceLocation(userPointcut), null); } /** @@ -848,10 +840,8 @@ public class BcelWeaver { * @param userPointcut */ private void raiseAmbiguousBindingError(String name, Pointcut userPointcut) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING, - name), - userPointcut.getSourceContext().makeSourceLocation(userPointcut),null); + world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING, name), userPointcut + .getSourceContext().makeSourceLocation(userPointcut), null); } /** @@ -863,108 +853,103 @@ public class BcelWeaver { formalNames.append(", "); formalNames.append(names.get(i)); } - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING_IN_OR,formalNames), - userPointcut.getSourceContext().makeSourceLocation(userPointcut),null); + world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.AMBIGUOUS_BINDING_IN_OR, formalNames), userPointcut + .getSourceContext().makeSourceLocation(userPointcut), null); } - /** + /** * @param name * @param userPointcut */ private void raiseUnboundFormalError(String name, Pointcut userPointcut) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL,name),userPointcut.getSourceLocation(),null); + world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.UNBOUND_FORMAL, name), userPointcut + .getSourceLocation(), null); } - -// public void dumpUnwoven(File file) throws IOException { -// BufferedOutputStream os = FileUtil.makeOutputStream(file); -// this.zipOutputStream = new ZipOutputStream(os); -// dumpUnwoven(); -// /* BUG 40943*/ -// dumpResourcesToOutJar(); -// zipOutputStream.close(); //this flushes and closes the acutal file -// } -// -// -// public void dumpUnwoven() throws IOException { -// Collection filesToDump = new HashSet(sourceJavaClasses.values()); -// for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// dumpUnchanged(classFile); -// } -// } - -// public void dumpResourcesToOutPath() throws IOException { -//// System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet()); -// Iterator i = resources.keySet().iterator(); -// while (i.hasNext()) { -// UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); -// dumpUnchanged(res); -// } -// //resources = new HashMap(); -// } -// + // public void dumpUnwoven(File file) throws IOException { + // BufferedOutputStream os = FileUtil.makeOutputStream(file); + // this.zipOutputStream = new ZipOutputStream(os); + // dumpUnwoven(); + // /* BUG 40943*/ + // dumpResourcesToOutJar(); + // zipOutputStream.close(); //this flushes and closes the acutal file + // } + // + // + // public void dumpUnwoven() throws IOException { + // Collection filesToDump = new HashSet(sourceJavaClasses.values()); + // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // dumpUnchanged(classFile); + // } + // } + + // public void dumpResourcesToOutPath() throws IOException { + // // System.err.println("? dumpResourcesToOutPath() resources=" + resources.keySet()); + // Iterator i = resources.keySet().iterator(); + // while (i.hasNext()) { + // UnwovenClassFile res = (UnwovenClassFile)resources.get(i.next()); + // dumpUnchanged(res); + // } + // //resources = new HashMap(); + // } + // /* BUG #40943 */ -// public void dumpResourcesToOutJar() throws IOException { -//// System.err.println("? dumpResourcesToOutJar() resources=" + resources.keySet()); -// Iterator i = resources.keySet().iterator(); -// while (i.hasNext()) { -// String name = (String)i.next(); -// UnwovenClassFile res = (UnwovenClassFile)resources.get(name); -// writeZipEntry(name,res.getBytes()); -// } -// resources = new HashMap(); -// } -// -// // halfway house for when the jar is managed outside of the weaver, but the resources -// // to be copied are known in the weaver. -// public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException { -// this.zipOutputStream = zos; -// dumpResourcesToOutJar(); -// } - - public void addManifest (Manifest newManifest) { -// System.out.println("? addManifest() newManifest=" + newManifest); + // public void dumpResourcesToOutJar() throws IOException { + // // System.err.println("? dumpResourcesToOutJar() resources=" + resources.keySet()); + // Iterator i = resources.keySet().iterator(); + // while (i.hasNext()) { + // String name = (String)i.next(); + // UnwovenClassFile res = (UnwovenClassFile)resources.get(name); + // writeZipEntry(name,res.getBytes()); + // } + // resources = new HashMap(); + // } + // + // // halfway house for when the jar is managed outside of the weaver, but the resources + // // to be copied are known in the weaver. + // public void dumpResourcesToOutJar(ZipOutputStream zos) throws IOException { + // this.zipOutputStream = zos; + // dumpResourcesToOutJar(); + // } + public void addManifest(Manifest newManifest) { + // System.out.println("? addManifest() newManifest=" + newManifest); if (manifest == null) { manifest = newManifest; } } - - public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; - + private static final String WEAVER_MANIFEST_VERSION = "1.0"; private static final Attributes.Name CREATED_BY = new Name("Created-By"); private static final String WEAVER_CREATED_BY = "AspectJ Compiler"; - - public Manifest getManifest (boolean shouldCreate) { - + + public Manifest getManifest(boolean shouldCreate) { + if (manifest == null && shouldCreate) { manifest = new Manifest(); Attributes attributes = manifest.getMainAttributes(); - attributes.put(Name.MANIFEST_VERSION,WEAVER_MANIFEST_VERSION); - attributes.put(CREATED_BY,WEAVER_CREATED_BY); + attributes.put(Name.MANIFEST_VERSION, WEAVER_MANIFEST_VERSION); + attributes.put(CREATED_BY, WEAVER_CREATED_BY); } - + return manifest; - } - - // ---- weaving - - // Used by some test cases only... - public Collection weave(File file) throws IOException { - OutputStream os = FileUtil.makeOutputStream(file); - this.zipOutputStream = new ZipOutputStream(os); - prepareForWeave(); - Collection c = weave( new IClassFileProvider() { - - public boolean isApplyAtAspectJMungersOnly() { - return false; - } - - public Iterator getClassFileIterator() { + } + + // ---- weaving + + // Used by some test cases only... + public Collection weave(File file) throws IOException { + OutputStream os = FileUtil.makeOutputStream(file); + this.zipOutputStream = new ZipOutputStream(os); + prepareForWeave(); + Collection c = weave(new IClassFileProvider() { + + public boolean isApplyAtAspectJMungersOnly() { + return false; + } + + public Iterator getClassFileIterator() { return addedClasses.iterator(); } @@ -973,427 +958,441 @@ public class BcelWeaver { public void acceptResult(UnwovenClassFile result) { try { writeZipEntry(result.filename, result.bytes); - } catch(IOException ex) {} + } catch (IOException ex) { + } + } + + public void processingReweavableState() { + } + + public void addingTypeMungers() { + } + + public void weavingAspects() { + } + + public void weavingClasses() { + } + + public void weaveCompleted() { } - public void processingReweavableState() {} - public void addingTypeMungers() {} - public void weavingAspects() {} - public void weavingClasses() {} - public void weaveCompleted() {} }; } }); -// /* BUG 40943*/ -// dumpResourcesToOutJar(); - zipOutputStream.close(); //this flushes and closes the acutal file - return c; - } - -// public Collection weave() throws IOException { -// prepareForWeave(); -// Collection filesToWeave; -// -// if (needToReweaveWorld) { -// filesToWeave = sourceJavaClasses.values(); -// } else { -// filesToWeave = addedClasses; -// } -// -// Collection wovenClassNames = new ArrayList(); -// world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + -// "(world=" + needToReweaveWorld + ")", null, null); -// -// -// //System.err.println("typeMungers: " + typeMungerList); -// -// prepareToProcessReweavableState(); -// // clear all state from files we'll be reweaving -// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// String className = classFile.getClassName(); -// BcelObjectType classType = getClassType(className); -// processReweavableStateIfPresent(className, classType); -// } -// -// -// -// //XXX this isn't quite the right place for this... -// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// String className = classFile.getClassName(); -// addTypeMungers(className); -// } -// -// // first weave into aspects -// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// String className = classFile.getClassName(); -// BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); -// if (classType.isAspect()) { -// weave(classFile, classType); -// wovenClassNames.add(className); -// } -// } -// -// // then weave into non-aspects -// for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// String className = classFile.getClassName(); -// BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); -// if (! classType.isAspect()) { -// weave(classFile, classType); -// wovenClassNames.add(className); -// } -// } -// -// if (zipOutputStream != null && !needToReweaveWorld) { -// Collection filesToDump = new HashSet(sourceJavaClasses.values()); -// filesToDump.removeAll(filesToWeave); -// for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { -// UnwovenClassFile classFile = (UnwovenClassFile)i.next(); -// dumpUnchanged(classFile); -// } -// } -// -// addedClasses = new ArrayList(); -// deletedTypenames = new ArrayList(); -// -// return wovenClassNames; -// } - - // variation of "weave" that sources class files from an external source. - public Collection weave(IClassFileProvider input) throws IOException { - if (trace.isTraceEnabled()) trace.enter("weave",this,input); - ContextToken weaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING, ""); - Collection wovenClassNames = new ArrayList(); - IWeaveRequestor requestor = input.getRequestor(); - - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - if (AsmManager.isCreatingModel() && !isBatchWeave) { - // remove all relationships where this file being woven is the target of the relationship - AsmManager.getDefault().removeRelationshipsTargettingThisType(classFile.getClassName()); - } - } - - // Go through the types and ensure any 'damaged' during compile time are repaired prior to weaving - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (theType!=null) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType!=null) classType.ensureDelegateConsistent(); - } - } - - // special case for AtAspectJMungerOnly - see #113587 - if (input.isApplyAtAspectJMungersOnly()) { - ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, ""); - requestor.weavingAspects(); -// ContextToken aspectToken = - CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - ResolvedType theType = world.resolve(className); - if (theType.isAnnotationStyleAspect()) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType==null) { - throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass()); - } - LazyClassGen clazz = classType.getLazyClassGen(); - BcelPerClauseAspectAdder selfMunger = new BcelPerClauseAspectAdder(theType, theType.getPerClause().getKind()); - selfMunger.forceMunge(clazz, true); - classType.finishedWith(); - UnwovenClassFile[] newClasses = getClassFilesFor(clazz); - for (int news = 0; news < newClasses.length; news++) { - requestor.acceptResult(newClasses[news]); - } - wovenClassNames.add(classFile.getClassName()); - } - } - requestor.weaveCompleted(); - CompilationAndWeavingContext.leavingPhase(atAspectJMungersOnly); - return wovenClassNames; - } - - requestor.processingReweavableState(); - ContextToken reweaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE,""); + // /* BUG 40943*/ + // dumpResourcesToOutJar(); + zipOutputStream.close(); // this flushes and closes the acutal file + return c; + } + + // public Collection weave() throws IOException { + // prepareForWeave(); + // Collection filesToWeave; + // + // if (needToReweaveWorld) { + // filesToWeave = sourceJavaClasses.values(); + // } else { + // filesToWeave = addedClasses; + // } + // + // Collection wovenClassNames = new ArrayList(); + // world.showMessage(IMessage.INFO, "might need to weave " + filesToWeave + + // "(world=" + needToReweaveWorld + ")", null, null); + // + // + // //System.err.println("typeMungers: " + typeMungerList); + // + // prepareToProcessReweavableState(); + // // clear all state from files we'll be reweaving + // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // String className = classFile.getClassName(); + // BcelObjectType classType = getClassType(className); + // processReweavableStateIfPresent(className, classType); + // } + // + // + // + // //XXX this isn't quite the right place for this... + // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // String className = classFile.getClassName(); + // addTypeMungers(className); + // } + // + // // first weave into aspects + // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // String className = classFile.getClassName(); + // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); + // if (classType.isAspect()) { + // weave(classFile, classType); + // wovenClassNames.add(className); + // } + // } + // + // // then weave into non-aspects + // for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // String className = classFile.getClassName(); + // BcelObjectType classType = BcelWorld.getBcelObjectType(world.resolve(className)); + // if (! classType.isAspect()) { + // weave(classFile, classType); + // wovenClassNames.add(className); + // } + // } + // + // if (zipOutputStream != null && !needToReweaveWorld) { + // Collection filesToDump = new HashSet(sourceJavaClasses.values()); + // filesToDump.removeAll(filesToWeave); + // for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { + // UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + // dumpUnchanged(classFile); + // } + // } + // + // addedClasses = new ArrayList(); + // deletedTypenames = new ArrayList(); + // + // return wovenClassNames; + // } + + // variation of "weave" that sources class files from an external source. + public Collection weave(IClassFileProvider input) throws IOException { + if (trace.isTraceEnabled()) + trace.enter("weave", this, input); + ContextToken weaveToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING, ""); + Collection wovenClassNames = new ArrayList(); + IWeaveRequestor requestor = input.getRequestor(); + + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); + if (AsmManager.isCreatingModel() && !isBatchWeave) { + // remove all relationships where this file being woven is the target of the relationship + AsmManager.getDefault().removeRelationshipsTargettingThisType(classFile.getClassName()); + } + } + + // Go through the types and ensure any 'damaged' during compile time are repaired prior to weaving + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); + String className = classFile.getClassName(); + ResolvedType theType = world.resolve(className); + if (theType != null) { + BcelObjectType classType = BcelWorld.getBcelObjectType(theType); + if (classType != null) + classType.ensureDelegateConsistent(); + } + } + + // special case for AtAspectJMungerOnly - see #113587 + if (input.isApplyAtAspectJMungersOnly()) { + ContextToken atAspectJMungersOnly = CompilationAndWeavingContext.enteringPhase( + CompilationAndWeavingContext.PROCESSING_ATASPECTJTYPE_MUNGERS_ONLY, ""); + requestor.weavingAspects(); + // ContextToken aspectToken = + CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); + String className = classFile.getClassName(); + ResolvedType theType = world.resolve(className); + if (theType.isAnnotationStyleAspect()) { + BcelObjectType classType = BcelWorld.getBcelObjectType(theType); + if (classType == null) { + throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); + } + LazyClassGen clazz = classType.getLazyClassGen(); + BcelPerClauseAspectAdder selfMunger = new BcelPerClauseAspectAdder(theType, theType.getPerClause().getKind()); + selfMunger.forceMunge(clazz, true); + classType.finishedWith(); + UnwovenClassFile[] newClasses = getClassFilesFor(clazz); + for (int news = 0; news < newClasses.length; news++) { + requestor.acceptResult(newClasses[news]); + } + wovenClassNames.add(classFile.getClassName()); + } + } + requestor.weaveCompleted(); + CompilationAndWeavingContext.leavingPhase(atAspectJMungersOnly); + return wovenClassNames; + } + + requestor.processingReweavableState(); + ContextToken reweaveToken = CompilationAndWeavingContext.enteringPhase( + CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, ""); prepareToProcessReweavableState(); // clear all state from files we'll be reweaving - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); String className = classFile.getClassName(); - BcelObjectType classType = getClassType(className); - - // null return from getClassType() means the delegate is an eclipse source type - so - // there *cant* be any reweavable state... (he bravely claimed...) - if (classType !=null) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, className); - processReweavableStateIfPresent(className, classType); - CompilationAndWeavingContext.leavingPhase(tok); - } + BcelObjectType classType = getClassType(className); + + // null return from getClassType() means the delegate is an eclipse source type - so + // there *cant* be any reweavable state... (he bravely claimed...) + if (classType != null) { + ContextToken tok = CompilationAndWeavingContext.enteringPhase( + CompilationAndWeavingContext.PROCESSING_REWEAVABLE_STATE, className); + processReweavableStateIfPresent(className, classType); + CompilationAndWeavingContext.leavingPhase(tok); + } } CompilationAndWeavingContext.leavingPhase(reweaveToken); - - ContextToken typeMungingToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS,""); + + ContextToken typeMungingToken = CompilationAndWeavingContext.enteringPhase( + CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, ""); requestor.addingTypeMungers(); - - // We process type mungers in two groups, first mungers that change the type - // hierarchy, then 'normal' ITD type mungers. - - - // Process the types in a predictable order (rather than the order encountered). - // For class A, the order is superclasses of A then superinterfaces of A - // (and this mechanism is applied recursively) - List typesToProcess = new ArrayList(); - for (Iterator iter = input.getClassFileIterator(); iter.hasNext();) { + + // We process type mungers in two groups, first mungers that change the type + // hierarchy, then 'normal' ITD type mungers. + + // Process the types in a predictable order (rather than the order encountered). + // For class A, the order is superclasses of A then superinterfaces of A + // (and this mechanism is applied recursively) + List typesToProcess = new ArrayList(); + for (Iterator iter = input.getClassFileIterator(); iter.hasNext();) { UnwovenClassFile clf = (UnwovenClassFile) iter.next(); - typesToProcess.add(clf.getClassName()); - } - while (typesToProcess.size()>0) { - weaveParentsFor(typesToProcess,(String)typesToProcess.get(0)); - } - - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); - String className = classFile.getClassName(); - addNormalTypeMungers(className); - } - - CompilationAndWeavingContext.leavingPhase(typeMungingToken); - + typesToProcess.add(clf.getClassName()); + } + while (typesToProcess.size() > 0) { + weaveParentsFor(typesToProcess, (String) typesToProcess.get(0)); + } + + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); + String className = classFile.getClassName(); + addNormalTypeMungers(className); + } + + CompilationAndWeavingContext.leavingPhase(typeMungingToken); + requestor.weavingAspects(); ContextToken aspectToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_ASPECTS, ""); // first weave into aspects - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (theType.isAspect()) { - BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType==null) { - + BcelObjectType classType = BcelWorld.getBcelObjectType(theType); + if (classType == null) { + // Sometimes.. if the Bcel Delegate couldn't be found then a problem occurred at compile time - on - // a previous compiler run. In this case I assert the delegate will still be an EclipseSourceType + // a previous compiler run. In this case I assert the delegate will still be an EclipseSourceType // and we can ignore the problem here (the original compile error will be reported again from // the eclipse source type) - pr113531 - ReferenceTypeDelegate theDelegate = ((ReferenceType)theType).getDelegate(); - if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) continue; + ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); + if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) + continue; - throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass()); + throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); } - weaveAndNotify(classFile, classType,requestor); - wovenClassNames.add(className); - } + weaveAndNotify(classFile, classType, requestor); + wovenClassNames.add(className); + } } - + CompilationAndWeavingContext.leavingPhase(aspectToken); requestor.weavingClasses(); ContextToken classToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_CLASSES, ""); // then weave into non-aspects - for (Iterator i = input.getClassFileIterator(); i.hasNext(); ) { - UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + for (Iterator i = input.getClassFileIterator(); i.hasNext();) { + UnwovenClassFile classFile = (UnwovenClassFile) i.next(); String className = classFile.getClassName(); ResolvedType theType = world.resolve(className); if (!theType.isAspect()) { BcelObjectType classType = BcelWorld.getBcelObjectType(theType); - if (classType==null) { - + if (classType == null) { + // bug 119882 - see above comment for bug 113531 - ReferenceTypeDelegate theDelegate = ((ReferenceType)theType).getDelegate(); - + ReferenceTypeDelegate theDelegate = ((ReferenceType) theType).getDelegate(); + // TODO urgh - put a method on the interface to check this, string compare is hideous - if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) continue; + if (theDelegate.getClass().getName().endsWith("EclipseSourceType")) + continue; - throw new BCException("Can't find bcel delegate for "+className+" type="+theType.getClass()); + throw new BCException("Can't find bcel delegate for " + className + " type=" + theType.getClass()); } - weaveAndNotify(classFile, classType, requestor); - wovenClassNames.add(className); - } + weaveAndNotify(classFile, classType, requestor); + wovenClassNames.add(className); + } } CompilationAndWeavingContext.leavingPhase(classToken); - + addedClasses = new ArrayList(); deletedTypenames = new ArrayList(); - - - requestor.weaveCompleted(); - CompilationAndWeavingContext.leavingPhase(weaveToken); - if (trace.isTraceEnabled()) trace.exit("weave",wovenClassNames); - return wovenClassNames; - } - - public void allWeavingComplete() { - warnOnUnmatchedAdvice(); - } - - /** - * In 1.5 mode and with XLint:adviceDidNotMatch enabled, put out messages for any - * mungers that did not match anything. - */ + + requestor.weaveCompleted(); + CompilationAndWeavingContext.leavingPhase(weaveToken); + if (trace.isTraceEnabled()) + trace.exit("weave", wovenClassNames); + return wovenClassNames; + } + + public void allWeavingComplete() { + warnOnUnmatchedAdvice(); + } + + /** + * In 1.5 mode and with XLint:adviceDidNotMatch enabled, put out messages for any mungers that did not match anything. + */ private void warnOnUnmatchedAdvice() { - + class AdviceLocation { - private int lineNo; + private int lineNo; private UnresolvedType inAspect; public AdviceLocation(BcelAdvice advice) { this.lineNo = advice.getSourceLocation().getLine(); this.inAspect = advice.getDeclaringAspect(); } - + public boolean equals(Object obj) { - if (!(obj instanceof AdviceLocation)) return false; + if (!(obj instanceof AdviceLocation)) + return false; AdviceLocation other = (AdviceLocation) obj; - if (this.lineNo != other.lineNo) return false; - if (!this.inAspect.equals(other.inAspect)) return false; + if (this.lineNo != other.lineNo) + return false; + if (!this.inAspect.equals(other.inAspect)) + return false; return true; } - + public int hashCode() { - return 37 + 17*lineNo + 17*inAspect.hashCode(); + return 37 + 17 * lineNo + 17 * inAspect.hashCode(); } } - + // FIXME asc Should be factored out into Xlint code and done automatically for all xlint messages, ideally. - // if a piece of advice hasn't matched anywhere and we are in -1.5 mode, put out a warning - if (world.isInJava5Mode() && - world.getLint().adviceDidNotMatch.isEnabled()) { - List l = world.getCrosscuttingMembersSet().getShadowMungers(); - Set alreadyWarnedLocations = new HashSet(); - - for (Iterator iter = l.iterator(); iter.hasNext();) { - ShadowMunger element = (ShadowMunger) iter.next(); - if (element instanceof BcelAdvice) { // This will stop us incorrectly reporting deow Checkers - BcelAdvice ba = (BcelAdvice)element; - if (!ba.hasMatchedSomething()) { - // Because we implement some features of AJ itself by creating our own kind of mungers, you sometimes - // find that ba.getSignature() is not a BcelMethod - for example it might be a cflow entry munger. - if (ba.getSignature()!=null) { - - // check we haven't already warned on this advice and line - // (cflow creates multiple mungers for the same advice) - AdviceLocation loc = new AdviceLocation(ba); - if (alreadyWarnedLocations.contains(loc)) { - continue; - } else { - alreadyWarnedLocations.add(loc); - } - - if (!(ba.getSignature() instanceof BcelMethod) - || !Utility.isSuppressing(ba.getSignature(),"adviceDidNotMatch")) { - world.getLint().adviceDidNotMatch.signal(ba.getDeclaringAspect().toString(), - new SourceLocation(element.getSourceLocation().getSourceFile(),element.getSourceLocation().getLine()));//element.getSourceLocation()); - } - } - } - } - } - } + // if a piece of advice hasn't matched anywhere and we are in -1.5 mode, put out a warning + if (world.isInJava5Mode() && world.getLint().adviceDidNotMatch.isEnabled()) { + List l = world.getCrosscuttingMembersSet().getShadowMungers(); + Set alreadyWarnedLocations = new HashSet(); + + for (Iterator iter = l.iterator(); iter.hasNext();) { + ShadowMunger element = (ShadowMunger) iter.next(); + if (element instanceof BcelAdvice) { // This will stop us incorrectly reporting deow Checkers + BcelAdvice ba = (BcelAdvice) element; + if (!ba.hasMatchedSomething()) { + // Because we implement some features of AJ itself by creating our own kind of mungers, you sometimes + // find that ba.getSignature() is not a BcelMethod - for example it might be a cflow entry munger. + if (ba.getSignature() != null) { + + // check we haven't already warned on this advice and line + // (cflow creates multiple mungers for the same advice) + AdviceLocation loc = new AdviceLocation(ba); + if (alreadyWarnedLocations.contains(loc)) { + continue; + } else { + alreadyWarnedLocations.add(loc); + } + + if (!(ba.getSignature() instanceof BcelMethod) + || !Utility.isSuppressing(ba.getSignature(), "adviceDidNotMatch")) { + world.getLint().adviceDidNotMatch.signal(ba.getDeclaringAspect().toString(), new SourceLocation( + element.getSourceLocation().getSourceFile(), element.getSourceLocation().getLine()));// element + // . + // getSourceLocation + // ( + // ) + // ) + // ; + } + } + } + } + } + } + } + + /** + * 'typeToWeave' is one from the 'typesForWeaving' list. This routine ensures we process supertypes (classes/interfaces) of + * 'typeToWeave' that are in the 'typesForWeaving' list before 'typeToWeave' itself. 'typesToWeave' is then removed from the + * 'typesForWeaving' list. + * + * Note: Future gotcha in here ... when supplying partial hierarchies, this algorithm may break down. If you have a hierarchy + * A>B>C and only give A and C to the weaver, it may choose to weave them in either order - but you'll probably have other + * problems if you are supplying partial hierarchies like that ! + */ + private void weaveParentsFor(List typesForWeaving, String typeToWeave) { + // Look at the supertype first + ResolvedType rtx = world.resolve(typeToWeave); + ResolvedType superType = rtx.getSuperclass(); + + if (superType != null && typesForWeaving.contains(superType.getName())) { + weaveParentsFor(typesForWeaving, superType.getName()); + } + + // Then look at the superinterface list + ResolvedType[] interfaceTypes = rtx.getDeclaredInterfaces(); + for (int i = 0; i < interfaceTypes.length; i++) { + ResolvedType rtxI = interfaceTypes[i]; + if (typesForWeaving.contains(rtxI.getName())) { + weaveParentsFor(typesForWeaving, rtxI.getName()); + } + } + ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_PARENTS, rtx + .getName()); + weaveParentTypeMungers(rtx); // Now do this type + CompilationAndWeavingContext.leavingPhase(tok); + typesForWeaving.remove(typeToWeave); // and remove it from the list of those to process } - - /** - * 'typeToWeave' is one from the 'typesForWeaving' list. This routine ensures we process - * supertypes (classes/interfaces) of 'typeToWeave' that are in the - * 'typesForWeaving' list before 'typeToWeave' itself. 'typesToWeave' is then removed from - * the 'typesForWeaving' list. - * - * Note: Future gotcha in here ... when supplying partial hierarchies, this algorithm may - * break down. If you have a hierarchy A>B>C and only give A and C to the weaver, it - * may choose to weave them in either order - but you'll probably have other problems if - * you are supplying partial hierarchies like that ! - */ - private void weaveParentsFor(List typesForWeaving,String typeToWeave) { - // Look at the supertype first - ResolvedType rtx = world.resolve(typeToWeave); - ResolvedType superType = rtx.getSuperclass(); - - if (superType!=null && typesForWeaving.contains(superType.getName())) { - weaveParentsFor(typesForWeaving,superType.getName()); - } - - // Then look at the superinterface list - ResolvedType[] interfaceTypes = rtx.getDeclaredInterfaces(); - for (int i = 0; i < interfaceTypes.length; i++) { - ResolvedType rtxI = interfaceTypes[i]; - if (typesForWeaving.contains(rtxI.getName())) { - weaveParentsFor(typesForWeaving,rtxI.getName()); - } - } - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_DECLARE_PARENTS,rtx.getName()); - weaveParentTypeMungers(rtx); // Now do this type - CompilationAndWeavingContext.leavingPhase(tok); - typesForWeaving.remove(typeToWeave); // and remove it from the list of those to process - } - - public void prepareToProcessReweavableState() { - } - - public void processReweavableStateIfPresent(String className, BcelObjectType classType) { + + public void prepareToProcessReweavableState() { + } + + public void processReweavableStateIfPresent(String className, BcelObjectType classType) { // If the class is marked reweavable, check any aspects around when it was built are in this world - WeaverStateInfo wsi = classType.getWeaverState(); - if (wsi!=null && wsi.isReweavable()) { // Check all necessary types are around! - world.showMessage(IMessage.INFO, - WeaverMessages.format(WeaverMessages.PROCESSING_REWEAVABLE,className,classType.getSourceLocation().getSourceFile()), - null,null); + WeaverStateInfo wsi = classType.getWeaverState(); + if (wsi != null && wsi.isReweavable()) { // Check all necessary types are around! + world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.PROCESSING_REWEAVABLE, className, classType + .getSourceLocation().getSourceFile()), null, null); Set aspectsPreviouslyInWorld = wsi.getAspectsAffectingType(); - if (aspectsPreviouslyInWorld!=null) { - // keep track of them just to ensure unique missing aspect error reporting - Set alreadyConfirmedReweavableState = new HashSet(); + if (aspectsPreviouslyInWorld != null) { + // keep track of them just to ensure unique missing aspect error reporting + Set alreadyConfirmedReweavableState = new HashSet(); for (Iterator iter = aspectsPreviouslyInWorld.iterator(); iter.hasNext();) { String requiredTypeName = (String) iter.next(); if (!alreadyConfirmedReweavableState.contains(requiredTypeName)) { - ResolvedType rtx = world.resolve(UnresolvedType.forName(requiredTypeName),true); + ResolvedType rtx = world.resolve(UnresolvedType.forName(requiredTypeName), true); boolean exists = !rtx.isMissing(); if (!exists) { - world.showMessage(IMessage.ERROR, - WeaverMessages.format(WeaverMessages.MISSING_REWEAVABLE_TYPE,requiredTypeName,className), - classType.getSourceLocation(), null); + world.showMessage(IMessage.ERROR, WeaverMessages.format(WeaverMessages.MISSING_REWEAVABLE_TYPE, + requiredTypeName, className), classType.getSourceLocation(), null); } else { - // weaved in aspect that are not declared in aop.xml trigger an error for now - // may cause headhache for LTW and packaged lib without aop.xml in - // see #104218 - if(!xcutSet.containsAspect(rtx)){ - world.showMessage( - IMessage.ERROR, - WeaverMessages.format( - WeaverMessages.REWEAVABLE_ASPECT_NOT_REGISTERED, - requiredTypeName, - className - ), - null, - null - ); - } else if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) - world.showMessage(IMessage.INFO, - WeaverMessages.format(WeaverMessages.VERIFIED_REWEAVABLE_TYPE,requiredTypeName,rtx.getSourceLocation().getSourceFile()), - null,null); - alreadyConfirmedReweavableState.add(requiredTypeName); + // weaved in aspect that are not declared in aop.xml trigger an error for now + // may cause headhache for LTW and packaged lib without aop.xml in + // see #104218 + if (!xcutSet.containsAspect(rtx)) { + world.showMessage(IMessage.ERROR, WeaverMessages.format( + WeaverMessages.REWEAVABLE_ASPECT_NOT_REGISTERED, requiredTypeName, className), null, null); + } else if (!world.getMessageHandler().isIgnoring(IMessage.INFO)) + world.showMessage(IMessage.INFO, WeaverMessages.format(WeaverMessages.VERIFIED_REWEAVABLE_TYPE, + requiredTypeName, rtx.getSourceLocation().getSourceFile()), null, null); + alreadyConfirmedReweavableState.add(requiredTypeName); } - } + } } } // old: - //classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData())); + // classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData())); // new: reweavable default with clever diff - classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi.getUnwovenClassFileData(classType.getJavaClass().getBytes()))); -// } else { -// classType.resetState(); + classType.setJavaClass(Utility.makeJavaClass(classType.getJavaClass().getFileName(), wsi + .getUnwovenClassFileData(classType.getJavaClass().getBytes()))); + // } else { + // classType.resetState(); } } - private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType, - IWeaveRequestor requestor) throws IOException { - trace.enter("weaveAndNotify",this,new Object[] {classFile,classType,requestor}); - - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_TYPE, classType.getResolvedTypeX().getName()); - LazyClassGen clazz = weaveWithoutDump(classFile,classType); - classType.finishedWith(); - //clazz is null if the classfile was unchanged by weaving... + private void weaveAndNotify(UnwovenClassFile classFile, BcelObjectType classType, IWeaveRequestor requestor) throws IOException { + trace.enter("weaveAndNotify", this, new Object[] { classFile, classType, requestor }); + + ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.WEAVING_TYPE, classType + .getResolvedTypeX().getName()); + LazyClassGen clazz = weaveWithoutDump(classFile, classType); + classType.finishedWith(); + // clazz is null if the classfile was unchanged by weaving... if (clazz != null) { UnwovenClassFile[] newClasses = getClassFilesFor(clazz); // OPTIMIZE can we avoid using the string name at all in UnwovenClassFile instances? @@ -1409,60 +1408,57 @@ public class BcelWeaver { } classType.weavingCompleted(); CompilationAndWeavingContext.leavingPhase(tok); - + trace.exit("weaveAndNotify"); - } - + } + /** helper method - will return NULL if the underlying delegate is an EclipseSourceType and not a BcelObjectType */ - public BcelObjectType getClassType(String forClass) { - return BcelWorld.getBcelObjectType(world.resolve(forClass)); - } - - - public void addParentTypeMungers(String typeName) { - weaveParentTypeMungers(world.resolve(typeName)); - } - - public void addNormalTypeMungers(String typeName) { - weaveNormalTypeMungers(world.resolve(typeName)); - } - - public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) { - List childClasses = clazz.getChildClasses(world); - UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()]; - ret[0] = new UnwovenClassFile(clazz.getFileName(),clazz.getClassName(),clazz.getJavaClassBytesIncludingReweavable(world)); - int index = 1; - for (Iterator iter = childClasses.iterator(); iter.hasNext();) { + public BcelObjectType getClassType(String forClass) { + return BcelWorld.getBcelObjectType(world.resolve(forClass)); + } + + public void addParentTypeMungers(String typeName) { + weaveParentTypeMungers(world.resolve(typeName)); + } + + public void addNormalTypeMungers(String typeName) { + weaveNormalTypeMungers(world.resolve(typeName)); + } + + public UnwovenClassFile[] getClassFilesFor(LazyClassGen clazz) { + List childClasses = clazz.getChildClasses(world); + UnwovenClassFile[] ret = new UnwovenClassFile[1 + childClasses.size()]; + ret[0] = new UnwovenClassFile(clazz.getFileName(), clazz.getClassName(), clazz.getJavaClassBytesIncludingReweavable(world)); + int index = 1; + for (Iterator iter = childClasses.iterator(); iter.hasNext();) { UnwovenClassFile.ChildClass element = (UnwovenClassFile.ChildClass) iter.next(); UnwovenClassFile childClass = new UnwovenClassFile(clazz.getFileName() + "$" + element.name, element.bytes); ret[index++] = childClass; } - return ret; - } - - /** - * Weaves new parents and annotations onto a type ("declare parents" and "declare @type") - * - * Algorithm: - * 1. First pass, do parents then do annotations. During this pass record: - * - any parent mungers that don't match but have a non-wild annotation type pattern - * - any annotation mungers that don't match - * 2. Multiple subsequent passes which go over the munger lists constructed in the first - * pass, repeatedly applying them until nothing changes. - * FIXME asc confirm that algorithm is optimal ?? - */ + return ret; + } + + /** + * Weaves new parents and annotations onto a type ("declare parents" and "declare @type") + * + * Algorithm: 1. First pass, do parents then do annotations. During this pass record: - any parent mungers that don't match but + * have a non-wild annotation type pattern - any annotation mungers that don't match 2. Multiple subsequent passes which go over + * the munger lists constructed in the first pass, repeatedly applying them until nothing changes. FIXME asc confirm that + * algorithm is optimal ?? + */ public void weaveParentTypeMungers(ResolvedType onType) { - if (onType.isRawType()) onType = onType.getGenericType(); - onType.clearInterTypeMungers(); - + if (onType.isRawType()) + onType = onType.getGenericType(); + onType.clearInterTypeMungers(); + List decpToRepeat = new ArrayList(); - boolean aParentChangeOccurred = false; + boolean aParentChangeOccurred = false; boolean anAnnotationChangeOccurred = false; // First pass - apply all decp mungers - for (Iterator i = declareParentsList.iterator(); i.hasNext(); ) { - DeclareParents decp = (DeclareParents)i.next(); - boolean typeChanged = applyDeclareParents(decp,onType); + for (Iterator i = declareParentsList.iterator(); i.hasNext();) { + DeclareParents decp = (DeclareParents) i.next(); + boolean typeChanged = applyDeclareParents(decp, onType); if (typeChanged) { aParentChangeOccurred = true; } else { @@ -1471,80 +1467,75 @@ public class BcelWeaver { } // Still first pass - apply all dec @type mungers - for (Iterator i = xcutSet.getDeclareAnnotationOnTypes().iterator();i.hasNext();) { - DeclareAnnotation decA = (DeclareAnnotation)i.next(); - boolean typeChanged = applyDeclareAtType(decA,onType,true); + for (Iterator i = xcutSet.getDeclareAnnotationOnTypes().iterator(); i.hasNext();) { + DeclareAnnotation decA = (DeclareAnnotation) i.next(); + boolean typeChanged = applyDeclareAtType(decA, onType, true); if (typeChanged) { anAnnotationChangeOccurred = true; } } - + while ((aParentChangeOccurred || anAnnotationChangeOccurred) && !decpToRepeat.isEmpty()) { anAnnotationChangeOccurred = aParentChangeOccurred = false; List decpToRepeatNextTime = new ArrayList(); for (Iterator iter = decpToRepeat.iterator(); iter.hasNext();) { DeclareParents decp = (DeclareParents) iter.next(); - boolean typeChanged = applyDeclareParents(decp,onType); + boolean typeChanged = applyDeclareParents(decp, onType); if (typeChanged) { aParentChangeOccurred = true; } else { decpToRepeatNextTime.add(decp); } } - + for (Iterator iter = xcutSet.getDeclareAnnotationOnTypes().iterator(); iter.hasNext();) { DeclareAnnotation decA = (DeclareAnnotation) iter.next(); - boolean typeChanged = applyDeclareAtType(decA,onType,false); + boolean typeChanged = applyDeclareAtType(decA, onType, false); if (typeChanged) { anAnnotationChangeOccurred = true; } } decpToRepeat = decpToRepeatNextTime; } - } + } - /** * Apply a declare @type - return true if we change the type */ - private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType,boolean reportProblems) { + private boolean applyDeclareAtType(DeclareAnnotation decA, ResolvedType onType, boolean reportProblems) { boolean didSomething = false; if (decA.matches(onType)) { - - if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) { - // Could put out a lint here for an already annotated type ... -// if (reportProblems) { -// world.getLint().elementAlreadyAnnotated.signal( -// new String[]{onType.toString(),decA.getAnnotationTypeX().toString()}, -// onType.getSourceLocation(),new ISourceLocation[]{decA.getSourceLocation()}); -// } - return false; - } - + + if (onType.hasAnnotation(decA.getAnnotationX().getSignature())) { + // Could put out a lint here for an already annotated type ... + // if (reportProblems) { + // world.getLint().elementAlreadyAnnotated.signal( + // new String[]{onType.toString(),decA.getAnnotationTypeX().toString()}, + // onType.getSourceLocation(),new ISourceLocation[]{decA.getSourceLocation()}); + // } + return false; + } + AnnotationX annoX = decA.getAnnotationX(); - + // check the annotation is suitable for the target - boolean problemReported = verifyTargetIsOK(decA, onType, annoX,reportProblems); + boolean problemReported = verifyTargetIsOK(decA, onType, annoX, reportProblems); if (!problemReported) { - AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decA.getSourceLocation(),onType.getSourceLocation()); - // TAG: WeavingMessage - if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){ - getWorld().getMessageHandler().handleMessage( - WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES, - new String[]{ - onType.toString(), - Utility.beautifyLocation(onType.getSourceLocation()), - decA.getAnnotationString(), - "type", - decA.getAspect().toString(), - Utility.beautifyLocation(decA.getSourceLocation()) - })); + AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decA.getSourceLocation(), + onType.getSourceLocation()); + // TAG: WeavingMessage + if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)) { + getWorld().getMessageHandler().handleMessage( + WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES, new String[] { + onType.toString(), Utility.beautifyLocation(onType.getSourceLocation()), + decA.getAnnotationString(), "type", decA.getAspect().toString(), + Utility.beautifyLocation(decA.getSourceLocation()) })); } didSomething = true; ResolvedTypeMunger newAnnotationTM = new AnnotationOnTypeMunger(annoX); newAnnotationTM.setSourceLocation(decA.getSourceLocation()); - onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM,decA.getAspect().resolve(world))); + onType.addInterTypeMunger(new BcelTypeMunger(newAnnotationTM, decA.getAspect().resolve(world))); decA.copyAnnotationTo(onType); } } @@ -1552,62 +1543,64 @@ public class BcelWeaver { } /** - * Checks for an @target() on the annotation and if found ensures it allows the annotation - * to be attached to the target type that matched. + * Checks for an @target() on the annotation and if found ensures it allows the annotation to be attached to the target type + * that matched. */ - private boolean verifyTargetIsOK(DeclareAnnotation decA, ResolvedType onType, AnnotationX annoX,boolean outputProblems) { + private boolean verifyTargetIsOK(DeclareAnnotation decA, ResolvedType onType, AnnotationX annoX, boolean outputProblems) { boolean problemReported = false; if (annoX.specifiesTarget()) { - if ( (onType.isAnnotation() && !annoX.allowedOnAnnotationType()) || - (!annoX.allowedOnRegularType())) { - if (outputProblems) { - if (decA.isExactPattern()) { - world.getMessageHandler().handleMessage(MessageUtil.error( - WeaverMessages.format(WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION, - onType.getName(),annoX.stringify(),annoX.getValidTargets()),decA.getSourceLocation())); - } else { - if (world.getLint().invalidTargetForAnnotation.isEnabled()) { - world.getLint().invalidTargetForAnnotation.signal( - new String[]{onType.getName(),annoX.stringify(),annoX.getValidTargets()},decA.getSourceLocation(),new ISourceLocation[]{onType.getSourceLocation()}); + if ((onType.isAnnotation() && !annoX.allowedOnAnnotationType()) || (!annoX.allowedOnRegularType())) { + if (outputProblems) { + if (decA.isExactPattern()) { + world.getMessageHandler().handleMessage( + MessageUtil.error(WeaverMessages.format(WeaverMessages.INCORRECT_TARGET_FOR_DECLARE_ANNOTATION, + onType.getName(), annoX.stringify(), annoX.getValidTargets()), decA.getSourceLocation())); + } else { + if (world.getLint().invalidTargetForAnnotation.isEnabled()) { + world.getLint().invalidTargetForAnnotation.signal(new String[] { onType.getName(), annoX.stringify(), + annoX.getValidTargets() }, decA.getSourceLocation(), new ISourceLocation[] { onType + .getSourceLocation() }); + } + } } + problemReported = true; } - } - problemReported = true; - } } return problemReported; } - + /** * Apply a single declare parents - return true if we change the type */ private boolean applyDeclareParents(DeclareParents p, ResolvedType onType) { boolean didSomething = false; - List newParents = p.findMatchingNewParents(onType,true); + List newParents = p.findMatchingNewParents(onType, true); if (!newParents.isEmpty()) { - didSomething=true; + didSomething = true; BcelObjectType classType = BcelWorld.getBcelObjectType(onType); - //System.err.println("need to do declare parents for: " + onType); - for (Iterator j = newParents.iterator(); j.hasNext(); ) { - ResolvedType newParent = (ResolvedType)j.next(); - - // We set it here so that the imminent matching for ITDs can succeed - we - // still haven't done the necessary changes to the class file itself - // (like transform super calls) - that is done in BcelTypeMunger.mungeNewParent() + // System.err.println("need to do declare parents for: " + onType); + for (Iterator j = newParents.iterator(); j.hasNext();) { + ResolvedType newParent = (ResolvedType) j.next(); + + // We set it here so that the imminent matching for ITDs can succeed - we + // still haven't done the necessary changes to the class file itself + // (like transform super calls) - that is done in BcelTypeMunger.mungeNewParent() classType.addParent(newParent); ResolvedTypeMunger newParentMunger = new NewParentTypeMunger(newParent); - newParentMunger.setSourceLocation(p.getSourceLocation()); + newParentMunger.setSourceLocation(p.getSourceLocation()); onType.addInterTypeMunger(new BcelTypeMunger(newParentMunger, xcutSet.findAspectDeclaringParents(p))); } } return didSomething; } - - public void weaveNormalTypeMungers(ResolvedType onType) { - ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, onType.getName()); - if (onType.isRawType() || onType.isParameterizedType()) onType = onType.getGenericType(); - for (Iterator i = typeMungerList.iterator(); i.hasNext(); ) { - ConcreteTypeMunger m = (ConcreteTypeMunger)i.next(); + + public void weaveNormalTypeMungers(ResolvedType onType) { + ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.PROCESSING_TYPE_MUNGERS, onType + .getName()); + if (onType.isRawType() || onType.isParameterizedType()) + onType = onType.getGenericType(); + for (Iterator i = typeMungerList.iterator(); i.hasNext();) { + ConcreteTypeMunger m = (ConcreteTypeMunger) i.next(); if (!m.isLateMunger() && m.matches(onType)) { onType.addInterTypeMunger(m); } @@ -1615,7 +1608,6 @@ public class BcelWeaver { CompilationAndWeavingContext.leavingPhase(tok); } - // exposed for ClassLoader dynamic weaving public LazyClassGen weaveWithoutDump(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { return weave(classFile, classType, false); @@ -1624,56 +1616,45 @@ public class BcelWeaver { // non-private for testing LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { LazyClassGen ret = weave(classFile, classType, true); - - if (progressListener != null) { - progressMade += progressPerClassFile; - progressListener.setProgress(progressMade); - progressListener.setText("woven: " + classFile.getFilename()); - } - return ret; } - private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException { + private LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType, boolean dump) throws IOException { if (classType.isSynthetic()) { // Don't touch synthetic classes - if (dump) dumpUnchanged(classFile); + if (dump) + dumpUnchanged(classFile); return null; } - + List shadowMungers = fastMatch(shadowMungerList, classType.getResolvedTypeX()); - List typeMungers = classType.getResolvedTypeX().getInterTypeMungers(); - - classType.getResolvedTypeX().checkInterTypeMungers(); + List typeMungers = classType.getResolvedTypeX().getInterTypeMungers(); + + classType.getResolvedTypeX().checkInterTypeMungers(); // Decide if we need to do actual weaving for this class - boolean mightNeedToWeave = - shadowMungers.size() > 0 || - typeMungers.size() > 0 || - classType.isAspect() || - world.getDeclareAnnotationOnMethods().size()>0 || - world.getDeclareAnnotationOnFields().size()>0; + boolean mightNeedToWeave = shadowMungers.size() > 0 || typeMungers.size() > 0 || classType.isAspect() + || world.getDeclareAnnotationOnMethods().size() > 0 || world.getDeclareAnnotationOnFields().size() > 0; // May need bridge methods if on 1.5 and something in our hierarchy is affected by ITDs - boolean mightNeedBridgeMethods = - world.isInJava5Mode() && - !classType.isInterface() && - classType.getResolvedTypeX().getInterTypeMungersIncludingSupers().size()>0; + boolean mightNeedBridgeMethods = world.isInJava5Mode() && !classType.isInterface() + && classType.getResolvedTypeX().getInterTypeMungersIncludingSupers().size() > 0; LazyClassGen clazz = null; if (mightNeedToWeave || mightNeedBridgeMethods) { clazz = classType.getLazyClassGen(); - //System.err.println("got lazy gen: " + clazz + ", " + clazz.getWeaverState()); + // System.err.println("got lazy gen: " + clazz + ", " + clazz.getWeaverState()); try { boolean isChanged = false; - - if (mightNeedToWeave) + + if (mightNeedToWeave) isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers, lateTypeMungerList); - if (mightNeedBridgeMethods) - isChanged = BcelClassWeaver.calculateAnyRequiredBridgeMethods(world,clazz) || isChanged; - + if (mightNeedBridgeMethods) + isChanged = BcelClassWeaver.calculateAnyRequiredBridgeMethods(world, clazz) || isChanged; + if (isChanged) { - if (dump) dump(classFile, clazz); + if (dump) + dump(classFile, clazz); return clazz; } } catch (RuntimeException re) { @@ -1685,9 +1666,7 @@ public class BcelWeaver { classDebugInfo = clazz.getClassName(); } String messageText = "trouble in: \n" + classDebugInfo; - getWorld().getMessageHandler().handleMessage( - new Message(messageText,IMessage.ABORT,re,null) - ); + getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); } catch (Error re) { String classDebugInfo = null; try { @@ -1697,29 +1676,25 @@ public class BcelWeaver { classDebugInfo = clazz.getClassName(); } String messageText = "trouble in: \n" + classDebugInfo; - getWorld().getMessageHandler().handleMessage( - new Message(messageText,IMessage.ABORT,re,null) - ); + getWorld().getMessageHandler().handleMessage(new Message(messageText, IMessage.ABORT, re, null)); } } - + // this is very odd return behavior trying to keep everyone happy if (dump) { dumpUnchanged(classFile); return clazz; } else { - // ATAJ: the class was not weaved, but since it gets there early it may have new generated inner classes - // attached to it to support LTW perX aspectOf support (see BcelPerClauseAspectAdder) - // that aggressively defines the inner $mayHaveAspect interface. - if (clazz != null && !clazz.getChildClasses(world).isEmpty()) { - return clazz; - } + // ATAJ: the class was not weaved, but since it gets there early it may have new generated inner classes + // attached to it to support LTW perX aspectOf support (see BcelPerClauseAspectAdder) + // that aggressively defines the inner $mayHaveAspect interface. + if (clazz != null && !clazz.getChildClasses(world).isEmpty()) { + return clazz; + } return null; } } - - // ---- writing private void dumpUnchanged(UnwovenClassFile classFile) throws IOException { @@ -1731,15 +1706,14 @@ public class BcelWeaver { } private String getEntryName(String className) { - //XXX what does bcel's getClassName do for inner names + // XXX what does bcel's getClassName do for inner names return className.replace('.', '/') + ".class"; } private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException { if (zipOutputStream != null) { String mainClassName = classFile.getJavaClass().getClassName(); - writeZipEntry(getEntryName(mainClassName), - clazz.getJavaClass(world).getBytes()); + writeZipEntry(getEntryName(mainClassName), clazz.getJavaClass(world).getBytes()); if (!clazz.getChildClasses(world).isEmpty()) { for (Iterator i = clazz.getChildClasses(world).iterator(); i.hasNext();) { UnwovenClassFile.ChildClass c = (UnwovenClassFile.ChildClass) i.next(); @@ -1747,23 +1721,21 @@ public class BcelWeaver { } } } else { - classFile.writeWovenBytes( - clazz.getJavaClass(world).getBytes(), - clazz.getChildClasses(world) - ); + classFile.writeWovenBytes(clazz.getJavaClass(world).getBytes(), clazz.getChildClasses(world)); } } - + private void writeZipEntry(String name, byte[] bytes) throws IOException { - ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right - + ZipEntry newEntry = new ZipEntry(name); // ??? get compression scheme right + zipOutputStream.putNextEntry(newEntry); zipOutputStream.write(bytes); zipOutputStream.closeEntry(); } private List fastMatch(List list, ResolvedType type) { - if (list == null) return Collections.EMPTY_LIST; + if (list == null) + return Collections.EMPTY_LIST; // here we do the coarsest grained fast match with no kind constraints // this will remove all obvious non-matches and see if we need to do any weaving @@ -1772,7 +1744,7 @@ public class BcelWeaver { List result = new ArrayList(); Iterator iter = list.iterator(); while (iter.hasNext()) { - ShadowMunger munger = (ShadowMunger)iter.next(); + ShadowMunger munger = (ShadowMunger) iter.next(); FuzzyBoolean fb = munger.getPointcut().fastMatch(info); if (fb.maybeTrue()) { result.add(munger); @@ -1781,34 +1753,32 @@ public class BcelWeaver { return result; } - public void setProgressListener(IProgressListener listener, double previousProgress, double progressPerClassFile) { - progressListener = listener; - this.progressMade = previousProgress; - this.progressPerClassFile = progressPerClassFile; - } - public void setReweavableMode(boolean xNotReweavable) { - if (trace.isTraceEnabled()) trace.enter("setReweavableMode",this,xNotReweavable); + if (trace.isTraceEnabled()) + trace.enter("setReweavableMode", this, xNotReweavable); inReweavableMode = !xNotReweavable; - WeaverStateInfo.setReweavableModeDefaults(!xNotReweavable,false,true); + WeaverStateInfo.setReweavableModeDefaults(!xNotReweavable, false, true); BcelClassWeaver.setReweavableMode(!xNotReweavable); - if (trace.isTraceEnabled()) trace.exit("setReweavableMode"); + if (trace.isTraceEnabled()) + trace.exit("setReweavableMode"); } public boolean isReweavable() { return inReweavableMode; } - public World getWorld() { - return world; - } + public World getWorld() { + return world; + } public void tidyUp() { - if (trace.isTraceEnabled()) trace.enter("tidyUp",this); - shadowMungerList = null; // setup by prepareForWeave + if (trace.isTraceEnabled()) + trace.enter("tidyUp", this); + shadowMungerList = null; // setup by prepareForWeave typeMungerList = null; // setup by prepareForWeave - lateTypeMungerList = null; // setup by prepareForWeave + lateTypeMungerList = null; // setup by prepareForWeave declareParentsList = null; // setup by prepareForWeave - if (trace.isTraceEnabled()) trace.exit("tidyUp"); + if (trace.isTraceEnabled()) + trace.exit("tidyUp"); } } diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java index 346f2c1f4..48970547c 100644 --- a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java @@ -25,7 +25,6 @@ import org.aspectj.apache.bcel.Constants; import org.aspectj.apache.bcel.classfile.ClassParser; import org.aspectj.apache.bcel.classfile.ConstantPool; import org.aspectj.apache.bcel.classfile.JavaClass; -import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.apache.bcel.generic.FieldInstruction; import org.aspectj.apache.bcel.generic.INVOKEINTERFACE; import org.aspectj.apache.bcel.generic.Instruction; @@ -397,17 +396,6 @@ public class BcelWorld extends World implements Repository { return MemberImpl.method(declaringType, modifier, name, signature); } - public static Member makeMungerMethodSignature(JavaClass javaClass, Method method) { - int mods = 0; - if (method.isStatic()) - mods = Modifier.STATIC; - else if (javaClass.isInterface()) - mods = Modifier.INTERFACE; - else if (method.isPrivate()) - mods = Modifier.PRIVATE; - return MemberImpl.method(UnresolvedType.forName(javaClass.getClassName()), mods, method.getName(), method.getSignature()); - } - public String toString() { StringBuffer buf = new StringBuffer(); buf.append("BcelWorld("); diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java index dcf553ce3..1f03069ae 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -345,14 +345,6 @@ public final class LazyClassGen { } } - public File getPackagePath(File root) { - String str = getInternalClassName(); - int index = str.lastIndexOf('/'); - if (index == -1) - return root; - return new File(root, str.substring(0, index)); - } - /** * Returns the packagename - if its the default package we return an empty string */ @@ -369,14 +361,6 @@ public final class LazyClassGen { return str.substring(0, index).replace('/', '.'); } - public String getClassId() { - String str = getInternalClassName(); - int index = str.lastIndexOf('/'); - if (index == -1) - return str; - return str.substring(index + 1); - } - public void addMethodGen(LazyMethodGen gen) { // assert gen.getClassName() == super.getClassName(); methodGens.add(gen); @@ -548,7 +532,7 @@ public final class LazyClassGen { boolean needAttribute = false; if (sigAttr != null) needAttribute = true; // If we had one before, we definetly still need one as types can't be 'removed' from the - // hierarchy + // hierarchy // check the interfaces if (!needAttribute) { diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java index 433a213f8..c3623b896 100644 --- a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -10,7 +10,6 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.io.ByteArrayOutputStream; @@ -65,311 +64,295 @@ import org.aspectj.weaver.WeaverMessages; import org.aspectj.weaver.AjAttribute.WeaverVersionInfo; import org.aspectj.weaver.tools.Traceable; - - -/** - * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the - * low-level Method objects. It converts through {@link MethodGen} to create - * and to serialize, but that's it. +/** + * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the low-level Method objects. It converts + * through {@link MethodGen} to create and to serialize, but that's it. * - *

At any rate, there are two ways to create LazyMethodGens. - * One is from a method, which - * does work through MethodGen to do the correct thing. - * The other is the creation of a completely empty - * LazyMethodGen, and it is used when we're constructing code from scratch. + *

+ * At any rate, there are two ways to create LazyMethodGens. One is from a method, which does work through MethodGen to do the + * correct thing. The other is the creation of a completely empty LazyMethodGen, and it is used when we're constructing code from + * scratch. * - *

We stay away from targeters for rangey things like Shadows and Exceptions. + *

+ * We stay away from targeters for rangey things like Shadows and Exceptions. */ public final class LazyMethodGen implements Traceable { - private static final int ACC_SYNTHETIC = 0x1000; - - private int accessFlags; - private Type returnType; - private final String name; - private Type[] argumentTypes; - //private final String[] argumentNames; - private String[] declaredExceptions; - private InstructionList body; // leaving null for abstracts - private List attributes; - private List newAnnotations; - private final LazyClassGen enclosingClass; - private BcelMethod memberView; - private AjAttribute.EffectiveSignatureAttribute effectiveSignature; - int highestLineNumber = 0; - boolean wasPackedOptimally = false; - - /* - * We use LineNumberTags and not Gens. - * - * This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens - * or if we make it create LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created - * Gens - then on return from the MethodGen ctor we took them apart, reprocessed them all and - * created Tags. (see unpackLocals/unpackLineNumbers). As we have our own copy of Bcel, why not create - * the right thing straightaway? So setting this to true will call the MethodGen ctor() in such - * a way that it creates Tags - removing the need for unpackLocals/unpackLineNumbers - HOWEVER see - * the ensureAllLineNumberSetup() method for some other relevant info. - * - * Whats the difference between a Tag and a Gen? A Tag is more lightweight, it doesn't know which - * instructions it targets, it relies on the instructions targetting *it* - this reduces the amount - * of targeter manipulation we have to do. - * - */ - - /** This is nonnull if this method is the result of an "inlining". We currently - * copy methods into other classes for around advice. We add this field so - * we can get JSR45 information correct. If/when we do _actual_ inlining, - * we'll need to subtype LineNumberTag to have external line numbers. + private static final int ACC_SYNTHETIC = 0x1000; + + private int accessFlags; + private Type returnType; + private final String name; + private Type[] argumentTypes; + // private final String[] argumentNames; + private String[] declaredExceptions; + private InstructionList body; // leaving null for abstracts + private List attributes; + private List newAnnotations; + private final LazyClassGen enclosingClass; + private BcelMethod memberView; + private AjAttribute.EffectiveSignatureAttribute effectiveSignature; + int highestLineNumber = 0; + boolean wasPackedOptimally = false; + + /* + * We use LineNumberTags and not Gens. + * + * This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens or if we make it create + * LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created Gens - then on return from the MethodGen ctor we took + * them apart, reprocessed them all and created Tags. (see unpackLocals/unpackLineNumbers). As we have our own copy of Bcel, why + * not create the right thing straightaway? So setting this to true will call the MethodGen ctor() in such a way that it creates + * Tags - removing the need for unpackLocals/unpackLineNumbers - HOWEVER see the ensureAllLineNumberSetup() method for some + * other relevant info. + * + * Whats the difference between a Tag and a Gen? A Tag is more lightweight, it doesn't know which instructions it targets, it + * relies on the instructions targettingit - this reduces the amount of targeter manipulation we have to do. + */ + + /** + * This is nonnull if this method is the result of an "inlining". We currently copy methods into other classes for around + * advice. We add this field so we can get JSR45 information correct. If/when we do _actual_ inlining, we'll need to subtype + * LineNumberTag to have external line numbers. */ String fromFilename = null; - private int maxLocals; - - private boolean canInline = true; -// private boolean hasExceptionHandlers; - - private boolean isSynthetic = false; - - /** - * only used by {@link BcelClassWeaver} - */ - List /*ShadowMungers*/ matchedShadows; - List /*Test*/ matchedShadowTests; - - // Used for interface introduction - // this is the type of the interface the method is technically on - public ResolvedType definingType = null; - - public LazyMethodGen( - int accessFlags, - Type returnType, - String name, - Type[] paramTypes, - String[] declaredExceptions, - LazyClassGen enclosingClass) - { - //System.err.println("raw create of: " + name + ", " + enclosingClass.getName() + ", " + returnType); + private int maxLocals; + + private boolean canInline = true; + // private boolean hasExceptionHandlers; + + private boolean isSynthetic = false; + + /** + * only used by {@link BcelClassWeaver} + */ + List /* ShadowMungers */matchedShadows; + + // Used for interface introduction + // this is the type of the interface the method is technically on + public ResolvedType definingType = null; + + public LazyMethodGen(int accessFlags, Type returnType, String name, Type[] paramTypes, String[] declaredExceptions, + LazyClassGen enclosingClass) { + // System.err.println("raw create of: " + name + ", " + enclosingClass.getName() + ", " + returnType); this.memberView = null; // ??? should be okay, since constructed ones aren't woven into - this.accessFlags = accessFlags; - this.returnType = returnType; - this.name = name; - this.argumentTypes = paramTypes; - //this.argumentNames = Utility.makeArgNames(paramTypes.length); - this.declaredExceptions = declaredExceptions; - if (!Modifier.isAbstract(accessFlags)) { - body = new InstructionList(); - setMaxLocals(calculateMaxLocals()); - } else { - body = null; - } - this.attributes = new ArrayList(); - this.enclosingClass = enclosingClass; - assertGoodBody(); - - // @AJ advice are not inlined by default since requires further analysis - // and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects are reweavable - // since the inlined version with wrappers and an to be done annotation to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - //TODO we could check for @Around advice as well - this.canInline = false; - } - } - } - - private int calculateMaxLocals() { - int ret = 0; - if (!Modifier.isStatic(accessFlags)) ret++; - for (int i = 0, len = argumentTypes.length; i < len; i++) { - ret += argumentTypes[i].getSize(); - } - return ret; - } - - private Method savedMethod = null; - // build from an existing method, lazy build saves most work for initialization - public LazyMethodGen(Method m, LazyClassGen enclosingClass) { - savedMethod = m; - - this.enclosingClass = enclosingClass; - if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) { - throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); - } - if ((m.isAbstract() || m.isNative()) && m.getCode() != null) { - throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); - } + this.accessFlags = accessFlags; + this.returnType = returnType; + this.name = name; + this.argumentTypes = paramTypes; + // this.argumentNames = Utility.makeArgNames(paramTypes.length); + this.declaredExceptions = declaredExceptions; + if (!Modifier.isAbstract(accessFlags)) { + body = new InstructionList(); + setMaxLocals(calculateMaxLocals()); + } else { + body = null; + } + this.attributes = new ArrayList(); + this.enclosingClass = enclosingClass; + assertGoodBody(); + + // @AJ advice are not inlined by default since requires further analysis + // and weaving ordering control + // TODO AV - improve - note: no room for improvement as long as aspects are reweavable + // since the inlined version with wrappers and an to be done annotation to keep + // inline state will be garbaged due to reweavable impl + if (memberView != null && isAdviceMethod()) { + if (enclosingClass.getType().isAnnotationStyleAspect()) { + // TODO we could check for @Around advice as well + this.canInline = false; + } + } + } + + private int calculateMaxLocals() { + int ret = 0; + if (!Modifier.isStatic(accessFlags)) + ret++; + for (int i = 0, len = argumentTypes.length; i < len; i++) { + ret += argumentTypes[i].getSize(); + } + return ret; + } + + private Method savedMethod = null; + + // build from an existing method, lazy build saves most work for initialization + public LazyMethodGen(Method m, LazyClassGen enclosingClass) { + savedMethod = m; + + this.enclosingClass = enclosingClass; + if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) { + throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); + } + if ((m.isAbstract() || m.isNative()) && m.getCode() != null) { + throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); + } this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); - + this.accessFlags = m.getModifiers(); this.name = m.getName(); - // @AJ advice are not inlined by default since requires further analysis - // and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects are reweavable - // since the inlined version with wrappers and an to be done annotation to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - //TODO we could check for @Around advice as well - this.canInline = false; - } - } - } - public LazyMethodGen(BcelMethod m,LazyClassGen enclosingClass) { - savedMethod = m.getMethod(); - this.enclosingClass = enclosingClass; - if (!(m.isAbstract() || m.isNative()) && savedMethod.getCode() == null) { - throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); - } - if ((m.isAbstract() || m.isNative()) && savedMethod.getCode() != null) { - throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); - } - //this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); - this.memberView = m; + // @AJ advice are not inlined by default since requires further analysis + // and weaving ordering control + // TODO AV - improve - note: no room for improvement as long as aspects are reweavable + // since the inlined version with wrappers and an to be done annotation to keep + // inline state will be garbaged due to reweavable impl + if (memberView != null && isAdviceMethod()) { + if (enclosingClass.getType().isAnnotationStyleAspect()) { + // TODO we could check for @Around advice as well + this.canInline = false; + } + } + } + + public LazyMethodGen(BcelMethod m, LazyClassGen enclosingClass) { + savedMethod = m.getMethod(); + this.enclosingClass = enclosingClass; + if (!(m.isAbstract() || m.isNative()) && savedMethod.getCode() == null) { + throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); + } + if ((m.isAbstract() || m.isNative()) && savedMethod.getCode() != null) { + throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass); + } + // this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m); + this.memberView = m; this.accessFlags = savedMethod.getModifiers(); this.name = m.getName(); - // @AJ advice are not inlined by default since requires further analysis - // and weaving ordering control - // TODO AV - improve - note: no room for improvement as long as aspects are reweavable - // since the inlined version with wrappers and an to be done annotation to keep - // inline state will be garbaged due to reweavable impl - if (memberView != null && isAdviceMethod()) { - if (enclosingClass.getType().isAnnotationStyleAspect()) { - //TODO we could check for @Around advice as well - this.canInline = false; - } - } - - } - - public boolean hasDeclaredLineNumberInfo() { - return (memberView != null && memberView.hasDeclarationLineNumberInfo()); - } - - public int getDeclarationLineNumber() { - if (hasDeclaredLineNumberInfo()) { - return memberView.getDeclarationLineNumber(); - } else { - return -1; - } - } - + // @AJ advice are not inlined by default since requires further analysis + // and weaving ordering control + // TODO AV - improve - note: no room for improvement as long as aspects are reweavable + // since the inlined version with wrappers and an to be done annotation to keep + // inline state will be garbaged due to reweavable impl + if (memberView != null && isAdviceMethod()) { + if (enclosingClass.getType().isAnnotationStyleAspect()) { + // TODO we could check for @Around advice as well + this.canInline = false; + } + } + + } + + public boolean hasDeclaredLineNumberInfo() { + return (memberView != null && memberView.hasDeclarationLineNumberInfo()); + } + + public int getDeclarationLineNumber() { + if (hasDeclaredLineNumberInfo()) { + return memberView.getDeclarationLineNumber(); + } else { + return -1; + } + } + public int getDeclarationOffset() { - if (hasDeclaredLineNumberInfo()) { - return memberView.getDeclarationOffset(); - } else { - return 0; - } - } - - public void addAnnotation(AnnotationX ax) { - initialize(); - if (memberView==null) { + if (hasDeclaredLineNumberInfo()) { + return memberView.getDeclarationOffset(); + } else { + return 0; + } + } + + public void addAnnotation(AnnotationX ax) { + initialize(); + if (memberView == null) { // If member view is null, we manage them in newAnnotations - if (newAnnotations==null) newAnnotations = new ArrayList(); + if (newAnnotations == null) + newAnnotations = new ArrayList(); newAnnotations.add(ax); } else { memberView.addAnnotation(ax); } - } - + } public boolean hasAnnotation(UnresolvedType annotationTypeX) { initialize(); - if (memberView==null) { + if (memberView == null) { // Check local annotations first - if (newAnnotations!=null) { + if (newAnnotations != null) { for (Iterator iter = newAnnotations.iterator(); iter.hasNext();) { AnnotationX element = (AnnotationX) iter.next(); - if (element.getBcelAnnotation().getTypeName().equals(annotationTypeX.getName())) return true; + if (element.getBcelAnnotation().getTypeName().equals(annotationTypeX.getName())) + return true; } } - memberView = new BcelMethod(getEnclosingClass().getBcelObjectType(), getMethod()); - return memberView.hasAnnotation(annotationTypeX); + memberView = new BcelMethod(getEnclosingClass().getBcelObjectType(), getMethod()); + return memberView.hasAnnotation(annotationTypeX); } return memberView.hasAnnotation(annotationTypeX); } - - private void initialize() { - if (returnType != null) return; - - //System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod); - - MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(),true); - + + private void initialize() { + if (returnType != null) + return; + + // System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + + // savedMethod); + + MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(), true); + this.returnType = gen.getReturnType(); this.argumentTypes = gen.getArgumentTypes(); this.declaredExceptions = gen.getExceptions(); this.attributes = gen.getAttributes(); - //this.annotations = gen.getAnnotations(); + // this.annotations = gen.getAnnotations(); this.maxLocals = gen.getMaxLocals(); - -// this.returnType = BcelWorld.makeBcelType(memberView.getReturnType()); -// this.argumentTypes = BcelWorld.makeBcelTypes(memberView.getParameterTypes()); -// -// this.declaredExceptions = UnresolvedType.getNames(memberView.getExceptions()); //gen.getExceptions(); -// this.attributes = new Attribute[0]; //gen.getAttributes(); -// this.maxLocals = savedMethod.getCode().getMaxLocals(); - - - if (gen.isAbstract() || gen.isNative()) { - body = null; - } else { - //body = new InstructionList(savedMethod.getCode().getCode()); - body = gen.getInstructionList(); - - unpackHandlers(gen); - + + // this.returnType = BcelWorld.makeBcelType(memberView.getReturnType()); + // this.argumentTypes = BcelWorld.makeBcelTypes(memberView.getParameterTypes()); + // + // this.declaredExceptions = UnresolvedType.getNames(memberView.getExceptions()); //gen.getExceptions(); + // this.attributes = new Attribute[0]; //gen.getAttributes(); + // this.maxLocals = savedMethod.getCode().getMaxLocals(); + + if (gen.isAbstract() || gen.isNative()) { + body = null; + } else { + // body = new InstructionList(savedMethod.getCode().getCode()); + body = gen.getInstructionList(); + + unpackHandlers(gen); + ensureAllLineNumberSetup(); - highestLineNumber = gen.getHighestlinenumber(); - - } - assertGoodBody(); - - //System.err.println("initialized: " + this.getClassName() + "." + this.getName()); - } - - // XXX we're relying on the javac promise I've just made up that we won't have an early exception - // in the list mask a later exception: That is, for two exceptions E and F, - // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So when we add F, - // we add it on the _OUTSIDE_ of any handlers that share starts or ends with it. - - // with that in mind, we merrily go adding ranges for exceptions. - - private void unpackHandlers(MethodGen gen) { - CodeExceptionGen[] exns = gen.getExceptionHandlers(); - if (exns != null) { - int len = exns.length; - // if (len > 0) hasExceptionHandlers = true; - int priority = len - 1; - for (int i = 0; i < len; i++, priority--) { - CodeExceptionGen exn = exns[i]; - - InstructionHandle start = - Range.genStart( - body, - getOutermostExceptionStart(exn.getStartPC())); - InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC())); - // this doesn't necessarily handle overlapping correctly!!! - ExceptionRange er = - new ExceptionRange( - body, - exn.getCatchType() == null - ? null - : BcelWorld.fromBcel(exn.getCatchType()), - priority); - er.associateWithTargets(start, end, exn.getHandlerPC()); - exn.setStartPC(null); // also removes from target - exn.setEndPC(null); // also removes from target - exn.setHandlerPC(null); // also removes from target - } - gen.removeExceptionHandlers(); - } - } + highestLineNumber = gen.getHighestlinenumber(); + + } + assertGoodBody(); + + // System.err.println("initialized: " + this.getClassName() + "." + this.getName()); + } + + // XXX we're relying on the javac promise I've just made up that we won't have an early exception + // in the list mask a later exception: That is, for two exceptions E and F, + // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So when we add F, + // we add it on the _OUTSIDE_ of any handlers that share starts or ends with it. + + // with that in mind, we merrily go adding ranges for exceptions. + + private void unpackHandlers(MethodGen gen) { + CodeExceptionGen[] exns = gen.getExceptionHandlers(); + if (exns != null) { + int len = exns.length; + // if (len > 0) hasExceptionHandlers = true; + int priority = len - 1; + for (int i = 0; i < len; i++, priority--) { + CodeExceptionGen exn = exns[i]; + + InstructionHandle start = Range.genStart(body, getOutermostExceptionStart(exn.getStartPC())); + InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC())); + // this doesn't necessarily handle overlapping correctly!!! + ExceptionRange er = new ExceptionRange(body, exn.getCatchType() == null ? null : BcelWorld.fromBcel(exn + .getCatchType()), priority); + er.associateWithTargets(start, end, exn.getHandlerPC()); + exn.setStartPC(null); // also removes from target + exn.setEndPC(null); // also removes from target + exn.setHandlerPC(null); // also removes from target + } + gen.removeExceptionHandlers(); + } + } private InstructionHandle getOutermostExceptionStart(InstructionHandle ih) { while (true) { @@ -379,7 +362,8 @@ public final class LazyMethodGen implements Traceable { return ih; } } - } + } + private InstructionHandle getOutermostExceptionEnd(InstructionHandle ih) { while (true) { if (ExceptionRange.isExceptionEnd(ih.getNext())) { @@ -390,1058 +374,1010 @@ public final class LazyMethodGen implements Traceable { } } - /** - * On entry to this method we have a method whose instruction stream contains a few instructions - * that have line numbers assigned to them (LineNumberTags). The aim is to ensure every instruction - * has the right line number. This is necessary because some of them may be extracted out into other - * methods - and it'd be useful for them to maintain the source line number for debugging. - */ - public void ensureAllLineNumberSetup() { - LineNumberTag lr = null; - boolean skip = false; - for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - Iterator tIter = ih.getTargeters().iterator(); - skip = false; - while (tIter.hasNext()) { - InstructionTargeter targeter = (InstructionTargeter)tIter.next(); - if (targeter instanceof LineNumberTag) { - lr = (LineNumberTag) targeter; - skip=true; - } - } - if (lr != null && !skip) { - ih.addTargeter(lr); - } - } - } - - // =============== - - public int allocateLocal(Type type) { - return allocateLocal(type.getSize()); - } - - public int allocateLocal(int slots) { - int max = getMaxLocals(); - setMaxLocals(max + slots); - return max; - } - - public Method getMethod() { - if (savedMethod != null) return savedMethod; //??? this relies on gentle treatment of constant pool - - try { + /** + * On entry to this method we have a method whose instruction stream contains a few instructions that have line numbers assigned + * to them (LineNumberTags). The aim is to ensure every instruction has the right line number. This is necessary because some of + * them may be extracted out into other methods - and it'd be useful for them to maintain the source line number for debugging. + */ + public void ensureAllLineNumberSetup() { + LineNumberTag lr = null; + boolean skip = false; + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + Iterator tIter = ih.getTargeters().iterator(); + skip = false; + while (tIter.hasNext()) { + InstructionTargeter targeter = (InstructionTargeter) tIter.next(); + if (targeter instanceof LineNumberTag) { + lr = (LineNumberTag) targeter; + skip = true; + } + } + if (lr != null && !skip) { + ih.addTargeter(lr); + } + } + } + + // =============== + + public int allocateLocal(Type type) { + return allocateLocal(type.getSize()); + } + + public int allocateLocal(int slots) { + int max = getMaxLocals(); + setMaxLocals(max + slots); + return max; + } + + public Method getMethod() { + if (savedMethod != null) + return savedMethod; // ??? this relies on gentle treatment of constant pool + + try { MethodGen gen = pack(); savedMethod = gen.getMethod(); return savedMethod; - } catch (ClassGenException e) { - enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld().showMessage( - IMessage.ERROR, - WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD, - this.getClassName(), - this.getName(), - e.getMessage()), - this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null); -// throw e; PR 70201.... let the normal problem reporting infrastructure deal with this rather than crashing. - body = null; - MethodGen gen = pack(); - return gen.getMethod(); - } - } - - public void markAsChanged() { - if (wasPackedOptimally) { - throw new RuntimeException("Already packed method is being re-modified: "+getClassName()+" "+toShortString()); - } - initialize(); - savedMethod = null; - } - - // ============================= + } catch (ClassGenException e) { + enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld().showMessage( + IMessage.ERROR, + WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD, this.getClassName(), this.getName(), e + .getMessage()), this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null); + // throw e; PR 70201.... let the normal problem reporting infrastructure deal with this rather than crashing. + body = null; + MethodGen gen = pack(); + return gen.getMethod(); + } + } + + public void markAsChanged() { + if (wasPackedOptimally) { + throw new RuntimeException("Already packed method is being re-modified: " + getClassName() + " " + toShortString()); + } + initialize(); + savedMethod = null; + } + + // ============================= public String toString() { BcelObjectType bot = enclosingClass.getBcelObjectType(); - WeaverVersionInfo weaverVersion = (bot==null?WeaverVersionInfo.CURRENT:bot.getWeaverVersionAttribute()); + WeaverVersionInfo weaverVersion = (bot == null ? WeaverVersionInfo.CURRENT : bot.getWeaverVersionAttribute()); return toLongString(weaverVersion); } - public String toShortString() { - String access = org.aspectj.apache.bcel.classfile.Utility.accessToString(getAccessFlags()); - - StringBuffer buf = new StringBuffer(); - - if (!access.equals("")) { - buf.append(access); - buf.append(" "); - } - buf.append( - org.aspectj.apache.bcel.classfile.Utility.signatureToString( - getReturnType().getSignature(), - true)); - buf.append(" "); - buf.append(getName()); - buf.append("("); + public String toShortString() { + String access = org.aspectj.apache.bcel.classfile.Utility.accessToString(getAccessFlags()); + + StringBuffer buf = new StringBuffer(); + + if (!access.equals("")) { + buf.append(access); + buf.append(" "); + } + buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(getReturnType().getSignature(), true)); + buf.append(" "); + buf.append(getName()); + buf.append("("); { int len = argumentTypes.length; if (len > 0) { - buf.append( - org.aspectj.apache.bcel.classfile.Utility.signatureToString( - argumentTypes[0].getSignature(), - true)); + buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(argumentTypes[0].getSignature(), true)); for (int i = 1; i < argumentTypes.length; i++) { buf.append(", "); - buf.append( - org.aspectj.apache.bcel.classfile.Utility.signatureToString( - argumentTypes[i].getSignature(), - true)); + buf.append(org.aspectj.apache.bcel.classfile.Utility.signatureToString(argumentTypes[i].getSignature(), true)); + } + } + } + buf.append(")"); + + { + int len = declaredExceptions != null ? declaredExceptions.length : 0; + if (len > 0) { + buf.append(" throws "); + buf.append(declaredExceptions[0]); + for (int i = 1; i < declaredExceptions.length; i++) { + buf.append(", "); + buf.append(declaredExceptions[i]); } } } - buf.append(")"); - - { - int len = declaredExceptions != null ? declaredExceptions.length : 0; - if (len > 0) { - buf.append(" throws "); - buf.append(declaredExceptions[0]); - for (int i = 1; i < declaredExceptions.length; i++) { - buf.append(", "); - buf.append(declaredExceptions[i]); - } - } - } - return buf.toString(); - } - - public String toLongString(WeaverVersionInfo weaverVersion) { - ByteArrayOutputStream s = new ByteArrayOutputStream(); - print(new PrintStream(s),weaverVersion); - return new String(s.toByteArray()); - } - - public void print(WeaverVersionInfo weaverVersion) { - print(System.out,weaverVersion); - } - - public void print(PrintStream out, WeaverVersionInfo weaverVersion) { - out.print(" " + toShortString()); - printAspectAttributes(out,weaverVersion); - - InstructionList body = getBody(); - if (body == null) { - out.println(";"); - return; - } - out.println(":"); - new BodyPrinter(out).run(); - out.println(" end " + toShortString()); - } + return buf.toString(); + } + public String toLongString(WeaverVersionInfo weaverVersion) { + ByteArrayOutputStream s = new ByteArrayOutputStream(); + print(new PrintStream(s), weaverVersion); + return new String(s.toByteArray()); + } + + public void print(WeaverVersionInfo weaverVersion) { + print(System.out, weaverVersion); + } + + public void print(PrintStream out, WeaverVersionInfo weaverVersion) { + out.print(" " + toShortString()); + printAspectAttributes(out, weaverVersion); + + InstructionList body = getBody(); + if (body == null) { + out.println(";"); + return; + } + out.println(":"); + new BodyPrinter(out).run(); + out.println(" end " + toShortString()); + } private void printAspectAttributes(PrintStream out, WeaverVersionInfo weaverVersion) { ISourceContext context = null; if (enclosingClass != null && enclosingClass.getType() != null) { context = enclosingClass.getType().getSourceContext(); } - List as = BcelAttributes.readAjAttributes(getClassName(), (Attribute[])attributes.toArray(new Attribute[]{}), context,null,weaverVersion); - if (! as.isEmpty()) { + List as = BcelAttributes.readAjAttributes(getClassName(), (Attribute[]) attributes.toArray(new Attribute[] {}), context, + null, weaverVersion); + if (!as.isEmpty()) { out.println(" " + as.get(0)); // XXX assuming exactly one attribute, munger... } } + private class BodyPrinter { + Map labelMap = new HashMap(); + + InstructionList body; + PrintStream out; + ConstantPool pool; + + BodyPrinter(PrintStream out) { + this.pool = enclosingClass.getConstantPool(); + this.body = getBodyForPrint(); + this.out = out; + } + + BodyPrinter(PrintStream out, InstructionList il) { + this.pool = enclosingClass.getConstantPool(); + this.body = il; + this.out = out; + } + + void run() { + // killNops(); + assignLabels(); + print(); + } + + // label assignment + void assignLabels() { + LinkedList exnTable = new LinkedList(); + String pendingLabel = null; + // boolean hasPendingTargeters = false; + int lcounter = 0; + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + Iterator tIter = ih.getTargeters().iterator(); + while (tIter.hasNext()) { + InstructionTargeter t = (InstructionTargeter) tIter.next();// targeters[i]; + if (t instanceof ExceptionRange) { + // assert isRangeHandle(h); + ExceptionRange r = (ExceptionRange) t; + if (r.getStart() == ih) { + insertHandler(r, exnTable); + } + } else if (t instanceof InstructionBranch) { + if (pendingLabel == null) { + pendingLabel = "L" + lcounter++; + } + } else { + // assert isRangeHandle(h) + } + } + if (pendingLabel != null) { + labelMap.put(ih, pendingLabel); + if (!Range.isRangeHandle(ih)) { + pendingLabel = null; + } + } + } + int ecounter = 0; + for (Iterator i = exnTable.iterator(); i.hasNext();) { + ExceptionRange er = (ExceptionRange) i.next(); + String exceptionLabel = "E" + ecounter++; + labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel); + labelMap.put(er.getHandler(), exceptionLabel); + } + } - private class BodyPrinter { - Map labelMap = new HashMap(); - - InstructionList body; - PrintStream out; - ConstantPool pool; - - BodyPrinter(PrintStream out) { - this.pool = enclosingClass.getConstantPool(); - this.body = getBodyForPrint(); - this.out = out; - } - - BodyPrinter(PrintStream out,InstructionList il) { - this.pool = enclosingClass.getConstantPool(); - this.body = il; - this.out = out; - } - - void run() { - //killNops(); - assignLabels(); - print(); - } - - // label assignment - void assignLabels() { - LinkedList exnTable = new LinkedList(); - String pendingLabel = null; -// boolean hasPendingTargeters = false; - int lcounter = 0; - for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - Iterator tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter t = (InstructionTargeter)tIter.next();//targeters[i]; - if (t instanceof ExceptionRange) { - // assert isRangeHandle(h); - ExceptionRange r = (ExceptionRange) t; - if (r.getStart() == ih) { - insertHandler(r, exnTable); - } - } else if (t instanceof InstructionBranch) { - if (pendingLabel == null) { - pendingLabel = "L" + lcounter++; - } - } else { - // assert isRangeHandle(h) - } - } - if (pendingLabel != null) { - labelMap.put(ih, pendingLabel); - if (! Range.isRangeHandle(ih)) { - pendingLabel = null; - } - } - } - int ecounter = 0; - for (Iterator i = exnTable.iterator(); i.hasNext();) { - ExceptionRange er = (ExceptionRange) i.next(); - String exceptionLabel = "E" + ecounter++; - labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel); - labelMap.put(er.getHandler(), exceptionLabel); - } - } - - // printing - - void print() { - int depth = 0; - int currLine = -1; - bodyPrint: - for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { - if (Range.isRangeHandle(ih)) { - Range r = Range.getRange(ih); - // don't print empty ranges, that is, ranges who contain no actual instructions - for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) { - if (xx == r.getEnd()) continue bodyPrint; - } - - // doesn't handle nested: if (r.getStart().getNext() == r.getEnd()) continue; - if (r.getStart() == ih) { - printRangeString(r, depth++); - } else { - if (r.getEnd() != ih) throw new RuntimeException("bad"); - printRangeString(r, --depth); - } - } else { - printInstruction(ih, depth); - int line = getLineNumber(ih, currLine); - if (line != currLine) { - currLine = line; - out.println(" (line " + line + ")"); - } else { - out.println(); - } - } - } - } - - void printRangeString(Range r, int depth) { - printDepth(depth); - out.println(getRangeString(r, labelMap)); - } - - - String getRangeString(Range r, Map labelMap) { - if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - return er.toString() + " -> " + labelMap.get(er.getHandler()); -// -// + " PRI " + er.getPriority(); - } else { - return r.toString(); - } - } - - void printDepth(int depth) { - pad(BODY_INDENT); - while (depth > 0) { - out.print("| "); - depth--; - } - } - - - void printLabel(String s, int depth) { - int space = Math.max(CODE_INDENT - depth * 2, 0); - if (s == null) { - pad(space); - } else { - space = Math.max(space - (s.length() + 2), 0); - pad(space); - out.print(s); - out.print(": "); - } - } - - void printInstruction(InstructionHandle h, int depth) { - printDepth(depth); - printLabel((String) labelMap.get(h), depth); - - Instruction inst = h.getInstruction(); - if (inst.isConstantPoolInstruction()) { - out.print(Constants.OPCODE_NAMES[inst.opcode].toUpperCase()); - out.print(" "); - out.print(pool.constantToString(pool.getConstant(inst.getIndex()))); - } else if (inst instanceof InstructionSelect) { - InstructionSelect sinst = (InstructionSelect) inst; - out.println(Constants.OPCODE_NAMES[sinst.opcode].toUpperCase()); - int[] matches = sinst.getMatchs(); - InstructionHandle[] targets = sinst.getTargets(); - InstructionHandle defaultTarget = sinst.getTarget(); - for (int i = 0, len = matches.length; i < len; i++) { - printDepth(depth); - printLabel(null, depth); - out.print(" "); - out.print(matches[i]); - out.print(": \t"); - out.println(labelMap.get(targets[i])); - } - printDepth(depth); - printLabel(null, depth); - out.print(" "); - out.print("default: \t"); - out.print(labelMap.get(defaultTarget)); - } else if (inst instanceof InstructionBranch) { - InstructionBranch brinst = (InstructionBranch) inst; - out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase()); - out.print(" "); - out.print(labelMap.get(brinst.getTarget())); - } else if (inst.isLocalVariableInstruction()) { - //LocalVariableInstruction lvinst = (LocalVariableInstruction) inst; - out.print(inst.toString(false).toUpperCase()); - int index = inst.getIndex(); - LocalVariableTag tag = getLocalVariableTag(h, index); - if (tag != null) { - out.print(" // "); - out.print(tag.getType()); - out.print(" "); - out.print(tag.getName()); - } - } else { - out.print(inst.toString(false).toUpperCase()); - } - } - - - - - static final int BODY_INDENT = 4; - static final int CODE_INDENT = 16; - - void pad(int size) { - for (int i = 0; i < size; i++) { - out.print(" "); - } - } - } - - - static LocalVariableTag getLocalVariableTag( - InstructionHandle ih, - int index) - { - Iterator tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter t = (InstructionTargeter)tIter.next(); - if (t instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) t; - if (lvt.getSlot() == index) return lvt; - } - } - return null; - } - - static int getLineNumber( - InstructionHandle ih, - int prevLine) - { - Iterator tIter = ih.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter t = (InstructionTargeter)tIter.next(); - if (t instanceof LineNumberTag) { - return ((LineNumberTag)t).getLineNumber(); - } - } - return prevLine; - } + // printing + + void print() { + int depth = 0; + int currLine = -1; + bodyPrint: for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + if (Range.isRangeHandle(ih)) { + Range r = Range.getRange(ih); + // don't print empty ranges, that is, ranges who contain no actual instructions + for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) { + if (xx == r.getEnd()) + continue bodyPrint; + } + + // doesn't handle nested: if (r.getStart().getNext() == r.getEnd()) continue; + if (r.getStart() == ih) { + printRangeString(r, depth++); + } else { + if (r.getEnd() != ih) + throw new RuntimeException("bad"); + printRangeString(r, --depth); + } + } else { + printInstruction(ih, depth); + int line = getLineNumber(ih, currLine); + if (line != currLine) { + currLine = line; + out.println(" (line " + line + ")"); + } else { + out.println(); + } + } + } + } + + void printRangeString(Range r, int depth) { + printDepth(depth); + out.println(getRangeString(r, labelMap)); + } + + String getRangeString(Range r, Map labelMap) { + if (r instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) r; + return er.toString() + " -> " + labelMap.get(er.getHandler()); + // + // + " PRI " + er.getPriority(); + } else { + return r.toString(); + } + } + + void printDepth(int depth) { + pad(BODY_INDENT); + while (depth > 0) { + out.print("| "); + depth--; + } + } + + void printLabel(String s, int depth) { + int space = Math.max(CODE_INDENT - depth * 2, 0); + if (s == null) { + pad(space); + } else { + space = Math.max(space - (s.length() + 2), 0); + pad(space); + out.print(s); + out.print(": "); + } + } + + void printInstruction(InstructionHandle h, int depth) { + printDepth(depth); + printLabel((String) labelMap.get(h), depth); + + Instruction inst = h.getInstruction(); + if (inst.isConstantPoolInstruction()) { + out.print(Constants.OPCODE_NAMES[inst.opcode].toUpperCase()); + out.print(" "); + out.print(pool.constantToString(pool.getConstant(inst.getIndex()))); + } else if (inst instanceof InstructionSelect) { + InstructionSelect sinst = (InstructionSelect) inst; + out.println(Constants.OPCODE_NAMES[sinst.opcode].toUpperCase()); + int[] matches = sinst.getMatchs(); + InstructionHandle[] targets = sinst.getTargets(); + InstructionHandle defaultTarget = sinst.getTarget(); + for (int i = 0, len = matches.length; i < len; i++) { + printDepth(depth); + printLabel(null, depth); + out.print(" "); + out.print(matches[i]); + out.print(": \t"); + out.println(labelMap.get(targets[i])); + } + printDepth(depth); + printLabel(null, depth); + out.print(" "); + out.print("default: \t"); + out.print(labelMap.get(defaultTarget)); + } else if (inst instanceof InstructionBranch) { + InstructionBranch brinst = (InstructionBranch) inst; + out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase()); + out.print(" "); + out.print(labelMap.get(brinst.getTarget())); + } else if (inst.isLocalVariableInstruction()) { + // LocalVariableInstruction lvinst = (LocalVariableInstruction) inst; + out.print(inst.toString(false).toUpperCase()); + int index = inst.getIndex(); + LocalVariableTag tag = getLocalVariableTag(h, index); + if (tag != null) { + out.print(" // "); + out.print(tag.getType()); + out.print(" "); + out.print(tag.getName()); + } + } else { + out.print(inst.toString(false).toUpperCase()); + } + } + + static final int BODY_INDENT = 4; + static final int CODE_INDENT = 16; + + void pad(int size) { + for (int i = 0; i < size; i++) { + out.print(" "); + } + } + } + + static LocalVariableTag getLocalVariableTag(InstructionHandle ih, int index) { + Iterator tIter = ih.getTargeters().iterator(); + while (tIter.hasNext()) { + InstructionTargeter t = (InstructionTargeter) tIter.next(); + if (t instanceof LocalVariableTag) { + LocalVariableTag lvt = (LocalVariableTag) t; + if (lvt.getSlot() == index) + return lvt; + } + } + return null; + } + + static int getLineNumber(InstructionHandle ih, int prevLine) { + Iterator tIter = ih.getTargeters().iterator(); + while (tIter.hasNext()) { + InstructionTargeter t = (InstructionTargeter) tIter.next(); + if (t instanceof LineNumberTag) { + return ((LineNumberTag) t).getLineNumber(); + } + } + return prevLine; + } public boolean isStatic() { return Modifier.isStatic(getAccessFlags()); } - + public boolean isAbstract() { return Modifier.isAbstract(getAccessFlags()); } - + public boolean isBridgeMethod() { return (getAccessFlags() & Constants.ACC_BRIDGE) != 0; } - - public void addExceptionHandler( - InstructionHandle start, - InstructionHandle end, - InstructionHandle handlerStart, - ObjectType catchType, - boolean highPriority) { - - InstructionHandle start1 = Range.genStart(body, start); - InstructionHandle end1 = Range.genEnd(body, end); - - ExceptionRange er = - new ExceptionRange(body, (catchType==null?null:BcelWorld.fromBcel(catchType)), highPriority); - er.associateWithTargets(start1, end1, handlerStart); - } - - public int getAccessFlags() { - return accessFlags; - } - - public int getAccessFlagsWithoutSynchronized() { - if (isSynchronized()) return accessFlags - Modifier.SYNCHRONIZED; - return accessFlags; - } - - public boolean isSynchronized() { - return (accessFlags & Modifier.SYNCHRONIZED)!=0; - } - - public void setAccessFlags(int newFlags) { - this.accessFlags = newFlags; - } - - public Type[] getArgumentTypes() { - initialize(); - return argumentTypes; - } - - public LazyClassGen getEnclosingClass() { - return enclosingClass; - } - - public int getMaxLocals() { - return maxLocals; - } - - public String getName() { - return name; - } - - public String getGenericReturnTypeSignature() { - if (memberView == null) { - return getReturnType().getSignature(); - } else { - return memberView.getGenericReturnType().getSignature(); - } - } - - public Type getReturnType() { - initialize(); - return returnType; - } - - public void setMaxLocals(int maxLocals) { - this.maxLocals = maxLocals; - } - - public InstructionList getBody() { - markAsChanged(); - return body; - } - public InstructionList getBodyForPrint() { - return body; - } - - public boolean hasBody() { - if (savedMethod != null) return savedMethod.getCode() != null; - return body != null; - } - - public List/*Attribute*/ getAttributes() { - return attributes; - } - - public String[] getDeclaredExceptions() { - return declaredExceptions; - } - - public String getClassName() { - return enclosingClass.getName(); - } - - - // ---- packing! - - public MethodGen pack() { - forceSyntheticForAjcMagicMembers(); - - //killNops(); - int flags = getAccessFlags(); - if (enclosingClass.getWorld().isJoinpointSynchronizationEnabled() && - enclosingClass.getWorld().areSynchronizationPointcutsInUse()) { - flags = getAccessFlagsWithoutSynchronized(); - } - MethodGen gen = - new MethodGen( - flags, - getReturnType(), - getArgumentTypes(), - null, //getArgumentNames(), - getName(), - getEnclosingClass().getName(), - new InstructionList(), - getEnclosingClass().getConstantPool()); - for (int i = 0, len = declaredExceptions.length; i < len; i++) { - gen.addException(declaredExceptions[i]); - } - - for (int i = 0, len = attributes.size(); i < len; i++) { - gen.addAttribute((Attribute)attributes.get(i)); - } - - if (newAnnotations!=null) { + + public void addExceptionHandler(InstructionHandle start, InstructionHandle end, InstructionHandle handlerStart, + ObjectType catchType, boolean highPriority) { + + InstructionHandle start1 = Range.genStart(body, start); + InstructionHandle end1 = Range.genEnd(body, end); + + ExceptionRange er = new ExceptionRange(body, (catchType == null ? null : BcelWorld.fromBcel(catchType)), highPriority); + er.associateWithTargets(start1, end1, handlerStart); + } + + public int getAccessFlags() { + return accessFlags; + } + + public int getAccessFlagsWithoutSynchronized() { + if (isSynchronized()) + return accessFlags - Modifier.SYNCHRONIZED; + return accessFlags; + } + + public boolean isSynchronized() { + return (accessFlags & Modifier.SYNCHRONIZED) != 0; + } + + public void setAccessFlags(int newFlags) { + this.accessFlags = newFlags; + } + + public Type[] getArgumentTypes() { + initialize(); + return argumentTypes; + } + + public LazyClassGen getEnclosingClass() { + return enclosingClass; + } + + public int getMaxLocals() { + return maxLocals; + } + + public String getName() { + return name; + } + + public String getGenericReturnTypeSignature() { + if (memberView == null) { + return getReturnType().getSignature(); + } else { + return memberView.getGenericReturnType().getSignature(); + } + } + + public Type getReturnType() { + initialize(); + return returnType; + } + + public void setMaxLocals(int maxLocals) { + this.maxLocals = maxLocals; + } + + public InstructionList getBody() { + markAsChanged(); + return body; + } + + public InstructionList getBodyForPrint() { + return body; + } + + public boolean hasBody() { + if (savedMethod != null) + return savedMethod.getCode() != null; + return body != null; + } + + public List/* Attribute */getAttributes() { + return attributes; + } + + public String[] getDeclaredExceptions() { + return declaredExceptions; + } + + public String getClassName() { + return enclosingClass.getName(); + } + + // ---- packing! + + public MethodGen pack() { + forceSyntheticForAjcMagicMembers(); + + // killNops(); + int flags = getAccessFlags(); + if (enclosingClass.getWorld().isJoinpointSynchronizationEnabled() + && enclosingClass.getWorld().areSynchronizationPointcutsInUse()) { + flags = getAccessFlagsWithoutSynchronized(); + } + MethodGen gen = new MethodGen(flags, getReturnType(), getArgumentTypes(), null, // getArgumentNames(), + getName(), getEnclosingClass().getName(), new InstructionList(), getEnclosingClass().getConstantPool()); + for (int i = 0, len = declaredExceptions.length; i < len; i++) { + gen.addException(declaredExceptions[i]); + } + + for (int i = 0, len = attributes.size(); i < len; i++) { + gen.addAttribute((Attribute) attributes.get(i)); + } + + if (newAnnotations != null) { for (Iterator iter = newAnnotations.iterator(); iter.hasNext();) { AnnotationX element = (AnnotationX) iter.next(); - gen.addAnnotation(new AnnotationGen(element.getBcelAnnotation(),gen.getConstantPool(),true)); + gen.addAnnotation(new AnnotationGen(element.getBcelAnnotation(), gen.getConstantPool(), true)); + } + } + + if (memberView != null && memberView.getAnnotations() != null && memberView.getAnnotations().length != 0) { + AnnotationX[] ans = memberView.getAnnotations(); + for (int i = 0, len = ans.length; i < len; i++) { + AnnotationGen a = ans[i].getBcelAnnotation(); + gen.addAnnotation(new AnnotationGen(a, gen.getConstantPool(), true)); } - } - - if (memberView!=null && memberView.getAnnotations()!=null && memberView.getAnnotations().length!=0) { - AnnotationX[] ans = memberView.getAnnotations(); - for (int i = 0, len = ans.length; i < len; i++) { - AnnotationGen a= ans[i].getBcelAnnotation(); - gen.addAnnotation(new AnnotationGen(a,gen.getConstantPool(),true)); - } - } - - if (isSynthetic) { - if (enclosingClass.getWorld().isInJava5Mode()) { - gen.setModifiers(gen.getModifiers() | ACC_SYNTHETIC); - } - // belt and braces, do the attribute even on Java 5 in addition to the modifier flag - ConstantPool cpg = gen.getConstantPool(); - int index = cpg.addUtf8("Synthetic"); - gen.addAttribute(new Synthetic(index, 0, new byte[0], cpg)); - } - - if (hasBody()) { - if (this.enclosingClass.getWorld().shouldFastPackMethods()) { - if (isAdviceMethod() || getName().equals("")) { - packBody(gen); - } else { - optimizedPackBody(gen); - } - } else { - packBody(gen); - } - gen.setMaxLocals(); - gen.setMaxStack(); - } else { - gen.setInstructionList(null); - } - return gen; - } - - private void forceSyntheticForAjcMagicMembers() { + } + + if (isSynthetic) { + if (enclosingClass.getWorld().isInJava5Mode()) { + gen.setModifiers(gen.getModifiers() | ACC_SYNTHETIC); + } + // belt and braces, do the attribute even on Java 5 in addition to the modifier flag + ConstantPool cpg = gen.getConstantPool(); + int index = cpg.addUtf8("Synthetic"); + gen.addAttribute(new Synthetic(index, 0, new byte[0], cpg)); + } + + if (hasBody()) { + if (this.enclosingClass.getWorld().shouldFastPackMethods()) { + if (isAdviceMethod() || getName().equals("")) { + packBody(gen); + } else { + optimizedPackBody(gen); + } + } else { + packBody(gen); + } + gen.setMaxLocals(); + gen.setMaxStack(); + } else { + gen.setInstructionList(null); + } + return gen; + } + + private void forceSyntheticForAjcMagicMembers() { if (NameMangler.isSyntheticMethod(getName(), inAspect())) { makeSynthetic(); } } - - private boolean inAspect() { - BcelObjectType objectType = enclosingClass.getBcelObjectType(); - return (objectType == null ? false : objectType.isAspect()); - } + + private boolean inAspect() { + BcelObjectType objectType = enclosingClass.getBcelObjectType(); + return (objectType == null ? false : objectType.isAspect()); + } public void makeSynthetic() { - isSynthetic = true; - } - - private static class LVPosition { - InstructionHandle start = null; - InstructionHandle end = null; - } - - /** fill the newly created method gen with our body, - * inspired by InstructionList.copy() - */ - public void packBody(MethodGen gen) { - InstructionList fresh = gen.getInstructionList(); - Map map = copyAllInstructionsExceptRangeInstructionsInto(fresh); - - // at this point, no rangeHandles are in fresh. Let's use that... - - /* Update branch targets and insert various attributes. - * Insert our exceptionHandlers - * into a sorted list, so they can be added in order later. - */ - InstructionHandle oldInstructionHandle = getBody().getStart(); - InstructionHandle newInstructionHandle = fresh.getStart(); - LinkedList exceptionList = new LinkedList(); + isSynthetic = true; + } + + private static class LVPosition { + InstructionHandle start = null; + InstructionHandle end = null; + } + + /** + * fill the newly created method gen with our body, inspired by InstructionList.copy() + */ + public void packBody(MethodGen gen) { + InstructionList fresh = gen.getInstructionList(); + Map map = copyAllInstructionsExceptRangeInstructionsInto(fresh); + + // at this point, no rangeHandles are in fresh. Let's use that... + + /* + * Update branch targets and insert various attributes. Insert our exceptionHandlers into a sorted list, so they can be + * added in order later. + */ + InstructionHandle oldInstructionHandle = getBody().getStart(); + InstructionHandle newInstructionHandle = fresh.getStart(); + LinkedList exceptionList = new LinkedList(); // map from localvariabletag to instruction handle - Map localVariables = new HashMap(); - - int currLine = -1; - int lineNumberOffset = (fromFilename == null) ? 0: getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); - - while (oldInstructionHandle != null) { - if (map.get(oldInstructionHandle) == null) { - // must be a range instruction since they're the only things we didn't copy across - handleRangeInstruction(oldInstructionHandle, exceptionList); - // just increment ih. - oldInstructionHandle = oldInstructionHandle.getNext(); - } else { - // assert map.get(ih) == jh - Instruction oldInstruction = oldInstructionHandle.getInstruction(); - Instruction newInstruction = newInstructionHandle.getInstruction(); - - if (oldInstruction instanceof InstructionBranch) { - handleBranchInstruction(map, oldInstruction, newInstruction); - } - - // now deal with line numbers - // and store up info for local variables - Iterator tIter = oldInstructionHandle.getTargeters().iterator(); - while (tIter.hasNext()) { - InstructionTargeter targeter = (InstructionTargeter)tIter.next();//targeters[k]; - if (targeter instanceof LineNumberTag) { - int line = ((LineNumberTag)targeter).getLineNumber(); - if (line != currLine) { - gen.addLineNumber(newInstructionHandle, line + lineNumberOffset); - currLine = line; - } - } else if (targeter instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) targeter; - LVPosition p = (LVPosition)localVariables.get(lvt); - // If we don't know about it, create a new position and store - // If we do know about it - update its end position - if (p==null) { - LVPosition newp = new LVPosition(); - newp.start=newp.end=newInstructionHandle; - localVariables.put(lvt,newp); - } else { - p.end = newInstructionHandle; - } - } - } - - // now continue - oldInstructionHandle = oldInstructionHandle.getNext(); - newInstructionHandle = newInstructionHandle.getNext(); - } - } - - addExceptionHandlers(gen, map, exceptionList); - addLocalVariables(gen,localVariables); - - // JAVAC adds line number tables (with just one entry) to generated accessor methods - this - // keeps some tools that rely on finding at least some form of linenumbertable happy. - // Let's check if we have one - if we don't then let's add one. - // TODO Could be made conditional on whether line debug info is being produced - if (gen.getLineNumbers().length==0) { - gen.addLineNumber(gen.getInstructionList().getStart(),1); - } - } - - - /* - * Optimized packing that does a 'local packing' of the code rather than building a brand new method - * and packing into it. Only usable when the packing is going to be done just once. - */ - public void optimizedPackBody(MethodGen gen) { - InstructionList theBody = getBody(); - InstructionHandle iHandle = theBody.getStart(); - - int currLine = -1; - int lineNumberOffset = (fromFilename == null) ? 0: getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); - Map localVariables = new HashMap(); - LinkedList exceptionList = new LinkedList(); - Set forDeletion = new HashSet(); - Set branchInstructions = new HashSet(); - // OPTIMIZE sort out in here: getRange()/insertHandler() and type of exceptionList - while (iHandle != null) { - Instruction inst = iHandle.getInstruction(); -// InstructionHandle nextInst = iHandle.getNext(); - // OPTIMIZE remove this instructionhandle as it now points to nowhere? - if (inst == Range.RANGEINSTRUCTION) { - Range r = Range.getRange(iHandle); - if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - if (er.getStart() == iHandle) { - if (!er.isEmpty()){ - // order is important, insert handlers in order of start - insertHandler(er, exceptionList); - } - } - } - forDeletion.add(iHandle); - } else { - if (inst instanceof InstructionBranch) { - branchInstructions.add(iHandle); - } - - InstructionTargeter[] targeters = iHandle.getTargetersArray(); - if (targeters != null) { - for (int k = targeters.length - 1; k >= 0; k--) { - InstructionTargeter targeter = targeters[k]; - if (targeter instanceof LineNumberTag) { - int line = ((LineNumberTag)targeter).getLineNumber(); - if (line != currLine) { - gen.addLineNumber(iHandle, line + lineNumberOffset); - currLine = line; - } - } else if (targeter instanceof LocalVariableTag) { - LocalVariableTag lvt = (LocalVariableTag) targeter; - LVPosition p = (LVPosition)localVariables.get(lvt); - // If we don't know about it, create a new position and store - // If we do know about it - update its end position - if (p==null) { - LVPosition newp = new LVPosition(); - newp.start=newp.end=iHandle; - localVariables.put(lvt,newp); - } else { - p.end = iHandle; - } - } - } - } - } - iHandle = iHandle.getNext(); - } - for (Iterator iterator = branchInstructions.iterator(); iterator.hasNext();) { + Map localVariables = new HashMap(); + + int currLine = -1; + int lineNumberOffset = (fromFilename == null) ? 0 : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); + + while (oldInstructionHandle != null) { + if (map.get(oldInstructionHandle) == null) { + // must be a range instruction since they're the only things we didn't copy across + handleRangeInstruction(oldInstructionHandle, exceptionList); + // just increment ih. + oldInstructionHandle = oldInstructionHandle.getNext(); + } else { + // assert map.get(ih) == jh + Instruction oldInstruction = oldInstructionHandle.getInstruction(); + Instruction newInstruction = newInstructionHandle.getInstruction(); + + if (oldInstruction instanceof InstructionBranch) { + handleBranchInstruction(map, oldInstruction, newInstruction); + } + + // now deal with line numbers + // and store up info for local variables + Iterator tIter = oldInstructionHandle.getTargeters().iterator(); + while (tIter.hasNext()) { + InstructionTargeter targeter = (InstructionTargeter) tIter.next();// targeters[k]; + if (targeter instanceof LineNumberTag) { + int line = ((LineNumberTag) targeter).getLineNumber(); + if (line != currLine) { + gen.addLineNumber(newInstructionHandle, line + lineNumberOffset); + currLine = line; + } + } else if (targeter instanceof LocalVariableTag) { + LocalVariableTag lvt = (LocalVariableTag) targeter; + LVPosition p = (LVPosition) localVariables.get(lvt); + // If we don't know about it, create a new position and store + // If we do know about it - update its end position + if (p == null) { + LVPosition newp = new LVPosition(); + newp.start = newp.end = newInstructionHandle; + localVariables.put(lvt, newp); + } else { + p.end = newInstructionHandle; + } + } + } + + // now continue + oldInstructionHandle = oldInstructionHandle.getNext(); + newInstructionHandle = newInstructionHandle.getNext(); + } + } + + addExceptionHandlers(gen, map, exceptionList); + addLocalVariables(gen, localVariables); + + // JAVAC adds line number tables (with just one entry) to generated accessor methods - this + // keeps some tools that rely on finding at least some form of linenumbertable happy. + // Let's check if we have one - if we don't then let's add one. + // TODO Could be made conditional on whether line debug info is being produced + if (gen.getLineNumbers().length == 0) { + gen.addLineNumber(gen.getInstructionList().getStart(), 1); + } + } + + /* + * Optimized packing that does a 'local packing' of the code rather than building a brand new method and packing into it. Only + * usable when the packing is going to be done just once. + */ + public void optimizedPackBody(MethodGen gen) { + InstructionList theBody = getBody(); + InstructionHandle iHandle = theBody.getStart(); + + int currLine = -1; + int lineNumberOffset = (fromFilename == null) ? 0 : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename); + Map localVariables = new HashMap(); + LinkedList exceptionList = new LinkedList(); + Set forDeletion = new HashSet(); + Set branchInstructions = new HashSet(); + // OPTIMIZE sort out in here: getRange()/insertHandler() and type of exceptionList + while (iHandle != null) { + Instruction inst = iHandle.getInstruction(); + // InstructionHandle nextInst = iHandle.getNext(); + // OPTIMIZE remove this instructionhandle as it now points to nowhere? + if (inst == Range.RANGEINSTRUCTION) { + Range r = Range.getRange(iHandle); + if (r instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) r; + if (er.getStart() == iHandle) { + if (!er.isEmpty()) { + // order is important, insert handlers in order of start + insertHandler(er, exceptionList); + } + } + } + forDeletion.add(iHandle); + } else { + if (inst instanceof InstructionBranch) { + branchInstructions.add(iHandle); + } + + InstructionTargeter[] targeters = iHandle.getTargetersArray(); + if (targeters != null) { + for (int k = targeters.length - 1; k >= 0; k--) { + InstructionTargeter targeter = targeters[k]; + if (targeter instanceof LineNumberTag) { + int line = ((LineNumberTag) targeter).getLineNumber(); + if (line != currLine) { + gen.addLineNumber(iHandle, line + lineNumberOffset); + currLine = line; + } + } else if (targeter instanceof LocalVariableTag) { + LocalVariableTag lvt = (LocalVariableTag) targeter; + LVPosition p = (LVPosition) localVariables.get(lvt); + // If we don't know about it, create a new position and store + // If we do know about it - update its end position + if (p == null) { + LVPosition newp = new LVPosition(); + newp.start = newp.end = iHandle; + localVariables.put(lvt, newp); + } else { + p.end = iHandle; + } + } + } + } + } + iHandle = iHandle.getNext(); + } + for (Iterator iterator = branchInstructions.iterator(); iterator.hasNext();) { BranchHandle iBranch = (BranchHandle) iterator.next(); - handleBranchInstruction(iBranch,forDeletion); - } - // now add exception handlers - for (Iterator iter = exceptionList.iterator(); iter.hasNext();) { - ExceptionRange r = (ExceptionRange) iter.next(); - if (r.isEmpty()) continue; - gen.addExceptionHandler( - jumpForward(r.getRealStart(),forDeletion), - jumpForward(r.getRealEnd(),forDeletion), - jumpForward(r.getHandler(),forDeletion), - (r.getCatchType() == null) - ? null - : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); - } - - for (Iterator iterator = forDeletion.iterator(); iterator.hasNext();) { - try { - theBody.delete((InstructionHandle)iterator.next()); + handleBranchInstruction(iBranch, forDeletion); + } + // now add exception handlers + for (Iterator iter = exceptionList.iterator(); iter.hasNext();) { + ExceptionRange r = (ExceptionRange) iter.next(); + if (r.isEmpty()) + continue; + gen.addExceptionHandler(jumpForward(r.getRealStart(), forDeletion), jumpForward(r.getRealEnd(), forDeletion), + jumpForward(r.getHandler(), forDeletion), (r.getCatchType() == null) ? null : (ObjectType) BcelWorld + .makeBcelType(r.getCatchType())); + } + + for (Iterator iterator = forDeletion.iterator(); iterator.hasNext();) { + try { + theBody.delete((InstructionHandle) iterator.next()); } catch (TargetLostException e) { e.printStackTrace(); } - } - gen.setInstructionList(theBody); - addLocalVariables(gen,localVariables); - - // JAVAC adds line number tables (with just one entry) to generated accessor methods - this - // keeps some tools that rely on finding at least some form of linenumbertable happy. - // Let's check if we have one - if we don't then let's add one. - // TODO Could be made conditional on whether line debug info is being produced - if (gen.getLineNumbers().length==0) { - gen.addLineNumber(gen.getInstructionList().getStart(),1); - } - wasPackedOptimally = true; - } - - private void addLocalVariables(MethodGen gen, Map localVariables) { + } + gen.setInstructionList(theBody); + addLocalVariables(gen, localVariables); + + // JAVAC adds line number tables (with just one entry) to generated accessor methods - this + // keeps some tools that rely on finding at least some form of linenumbertable happy. + // Let's check if we have one - if we don't then let's add one. + // TODO Could be made conditional on whether line debug info is being produced + if (gen.getLineNumbers().length == 0) { + gen.addLineNumber(gen.getInstructionList().getStart(), 1); + } + wasPackedOptimally = true; + } + + private void addLocalVariables(MethodGen gen, Map localVariables) { // now add local variables - gen.removeLocalVariables(); + gen.removeLocalVariables(); // this next iteration _might_ be overkill, but we had problems with - // bcel before with duplicate local variables. Now that we're patching + // bcel before with duplicate local variables. Now that we're patching // bcel we should be able to do without it if we're paranoid enough // through the rest of the compiler. - - Map duplicatedLocalMap = new HashMap(); - for (Iterator iter = localVariables.keySet().iterator(); iter.hasNext(); ) { - LocalVariableTag tag = (LocalVariableTag) iter.next(); - // have we already added one with the same slot number and start location? - // if so, just continue. - LVPosition lvpos = (LVPosition)localVariables.get(tag); - InstructionHandle start = lvpos.start; - Set slots = (Set) duplicatedLocalMap.get(start); - if (slots == null) { - slots = new HashSet(); - duplicatedLocalMap.put(start, slots); - } else if (slots.contains(new Integer(tag.getSlot()))) { - // we already have a var starting at this tag with this slot - continue; - } - slots.add(new Integer(tag.getSlot())); - Type t = tag.getRealType(); - if (t==null) { - t = BcelWorld.makeBcelType(UnresolvedType.forSignature(tag.getType())); - } - gen.addLocalVariable( - tag.getName(), - t, - tag.getSlot(), start, lvpos.end); - } - } + Map duplicatedLocalMap = new HashMap(); + for (Iterator iter = localVariables.keySet().iterator(); iter.hasNext();) { + LocalVariableTag tag = (LocalVariableTag) iter.next(); + // have we already added one with the same slot number and start location? + // if so, just continue. + LVPosition lvpos = (LVPosition) localVariables.get(tag); + InstructionHandle start = lvpos.start; + Set slots = (Set) duplicatedLocalMap.get(start); + if (slots == null) { + slots = new HashSet(); + duplicatedLocalMap.put(start, slots); + } else if (slots.contains(new Integer(tag.getSlot()))) { + // we already have a var starting at this tag with this slot + continue; + } + slots.add(new Integer(tag.getSlot())); + Type t = tag.getRealType(); + if (t == null) { + t = BcelWorld.makeBcelType(UnresolvedType.forSignature(tag.getType())); + } + gen.addLocalVariable(tag.getName(), t, tag.getSlot(), start, lvpos.end); + } + } private void addExceptionHandlers(MethodGen gen, Map map, LinkedList exnList) { // now add exception handlers - for (Iterator iter = exnList.iterator(); iter.hasNext();) { - ExceptionRange r = (ExceptionRange) iter.next(); - if (r.isEmpty()) continue; - InstructionHandle rMappedStart = remap(r.getRealStart(), map); - InstructionHandle rMappedEnd = remap(r.getRealEnd(), map); - InstructionHandle rMappedHandler = remap(r.getHandler(), map); - gen.addExceptionHandler(rMappedStart,rMappedEnd,rMappedHandler, - (r.getCatchType() == null) - ? null - : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); - } + for (Iterator iter = exnList.iterator(); iter.hasNext();) { + ExceptionRange r = (ExceptionRange) iter.next(); + if (r.isEmpty()) + continue; + InstructionHandle rMappedStart = remap(r.getRealStart(), map); + InstructionHandle rMappedEnd = remap(r.getRealEnd(), map); + InstructionHandle rMappedHandler = remap(r.getHandler(), map); + gen.addExceptionHandler(rMappedStart, rMappedEnd, rMappedHandler, (r.getCatchType() == null) ? null + : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); + } } private void handleBranchInstruction(Map map, Instruction oldInstruction, Instruction newInstruction) { InstructionBranch oldBranchInstruction = (InstructionBranch) oldInstruction; InstructionBranch newBranchInstruction = (InstructionBranch) newInstruction; - InstructionHandle oldTarget = oldBranchInstruction.getTarget(); // old target - - // New target is in hash map - newBranchInstruction.setTarget(remap(oldTarget, map)); - - if (oldBranchInstruction instanceof InstructionSelect) { - // Either LOOKUPSWITCH or TABLESWITCH - InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets(); - InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets(); - - for (int k = oldTargets.length - 1; k >= 0; k--) { - // Update all targets - newTargets[k] = remap(oldTargets[k], map); - newTargets[k].addTargeter(newBranchInstruction); - } - } - } - - private InstructionHandle jumpForward(InstructionHandle t,Set handlesForDeletion) { - + InstructionHandle oldTarget = oldBranchInstruction.getTarget(); // old target + + // New target is in hash map + newBranchInstruction.setTarget(remap(oldTarget, map)); + + if (oldBranchInstruction instanceof InstructionSelect) { + // Either LOOKUPSWITCH or TABLESWITCH + InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets(); + InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets(); + + for (int k = oldTargets.length - 1; k >= 0; k--) { + // Update all targets + newTargets[k] = remap(oldTargets[k], map); + newTargets[k].addTargeter(newBranchInstruction); + } + } + } + + private InstructionHandle jumpForward(InstructionHandle t, Set handlesForDeletion) { + InstructionHandle target = t; - if (handlesForDeletion.contains(target)) { - do { - target = target.getNext(); - } while (handlesForDeletion.contains(target)); - } - return target; - } - + if (handlesForDeletion.contains(target)) { + do { + target = target.getNext(); + } while (handlesForDeletion.contains(target)); + } + return target; + } + private void handleBranchInstruction(BranchHandle branchHandle, Set handlesForDeletion) { InstructionBranch branchInstruction = (InstructionBranch) branchHandle.getInstruction(); - InstructionHandle target = branchInstruction.getTarget(); // old target - - if (handlesForDeletion.contains(target)) { - do { - target = target.getNext(); - } while (handlesForDeletion.contains(target)); - branchInstruction.setTarget(target); - } - - if (branchInstruction instanceof InstructionSelect) { - // Either LOOKUPSWITCH or TABLESWITCH - InstructionSelect iSelect = ((InstructionSelect)branchInstruction); - InstructionHandle[] targets = iSelect.getTargets(); - for (int k = targets.length - 1; k >= 0; k--) { - InstructionHandle oneTarget = targets[k]; - if (handlesForDeletion.contains(oneTarget)) { - do { - oneTarget = oneTarget.getNext(); - } while (handlesForDeletion.contains(oneTarget)); - iSelect.setTarget(k,oneTarget); - oneTarget.addTargeter(branchInstruction); - } - } - } + InstructionHandle target = branchInstruction.getTarget(); // old target + + if (handlesForDeletion.contains(target)) { + do { + target = target.getNext(); + } while (handlesForDeletion.contains(target)); + branchInstruction.setTarget(target); + } + + if (branchInstruction instanceof InstructionSelect) { + // Either LOOKUPSWITCH or TABLESWITCH + InstructionSelect iSelect = ((InstructionSelect) branchInstruction); + InstructionHandle[] targets = iSelect.getTargets(); + for (int k = targets.length - 1; k >= 0; k--) { + InstructionHandle oneTarget = targets[k]; + if (handlesForDeletion.contains(oneTarget)) { + do { + oneTarget = oneTarget.getNext(); + } while (handlesForDeletion.contains(oneTarget)); + iSelect.setTarget(k, oneTarget); + oneTarget.addTargeter(branchInstruction); + } + } + } } private void handleRangeInstruction(InstructionHandle ih, LinkedList exnList) { // we're a range instruction Range r = Range.getRange(ih); if (r instanceof ExceptionRange) { - ExceptionRange er = (ExceptionRange) r; - if (er.getStart() == ih) { - //System.err.println("er " + er); - if (!er.isEmpty()){ - // order is important, insert handlers in order of start - insertHandler(er, exnList); - } - } + ExceptionRange er = (ExceptionRange) r; + if (er.getStart() == ih) { + // System.err.println("er " + er); + if (!er.isEmpty()) { + // order is important, insert handlers in order of start + insertHandler(er, exnList); + } + } } else { - // we must be a shadow range or something equally useless, - // so forget about doing anything - } - } - - /* Make copies of all instructions, append them to the new list - * and associate old instruction references with the new ones, i.e., - * a 1:1 mapping. - */ - private Map copyAllInstructionsExceptRangeInstructionsInto(InstructionList intoList) { - HashMap map = new HashMap(); - for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) { - if (Range.isRangeHandle(ih)) { - continue; - } - Instruction i = ih.getInstruction(); - Instruction c = Utility.copyInstruction(i); - - if (c instanceof InstructionBranch) - map.put(ih, intoList.append((InstructionBranch) c)); - else - map.put(ih, intoList.append(c)); - } - return map; - } - - /** This procedure should not currently be used. + // we must be a shadow range or something equally useless, + // so forget about doing anything + } + } + + /* + * Make copies of all instructions, append them to the new list and associate old instruction references with the new ones, + * i.e., a 1:1 mapping. + */ + private Map copyAllInstructionsExceptRangeInstructionsInto(InstructionList intoList) { + HashMap map = new HashMap(); + for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) { + if (Range.isRangeHandle(ih)) { + continue; + } + Instruction i = ih.getInstruction(); + Instruction c = Utility.copyInstruction(i); + + if (c instanceof InstructionBranch) + map.put(ih, intoList.append((InstructionBranch) c)); + else + map.put(ih, intoList.append(c)); + } + return map; + } + + /** + * This procedure should not currently be used. */ -// public void killNops() { -// InstructionHandle curr = body.getStart(); -// while (true) { -// if (curr == null) break; -// InstructionHandle next = curr.getNext(); -// if (curr.getInstruction() instanceof NOP) { -// InstructionTargeter[] targeters = curr.getTargeters(); -// if (targeters != null) { -// for (int i = 0, len = targeters.length; i < len; i++) { -// InstructionTargeter targeter = targeters[i]; -// targeter.updateTarget(curr, next); -// } -// } -// try { -// body.delete(curr); -// } catch (TargetLostException e) { -// } -// } -// curr = next; -// } -// } - -// private static InstructionHandle fNext(InstructionHandle ih) { -// while (true) { -// if (ih.getInstruction()==Range.RANGEINSTRUCTION) ih = ih.getNext(); -// else return ih; -// } -// } - - private static InstructionHandle remap(InstructionHandle ih, Map map) { - while (true) { - Object ret = map.get(ih); - if (ret == null) { - ih = ih.getNext(); - } else { - return (InstructionHandle) ret; - } - } - } - - // Update to all these comments, ASC 11-01-2005 - // The right thing to do may be to do more with priorities as - // we create new exception handlers, but that is a relatively - // complex task. In the meantime, just taking account of the - // priority here enables a couple of bugs to be fixed to do - // with using return or break in code that contains a finally - // block (pr78021,pr79554). - - // exception ordering. - // What we should be doing is dealing with priority inversions way earlier than we are - // and counting on the tree structure. In which case, the below code is in fact right. - - - // XXX THIS COMMENT BELOW IS CURRENTLY WRONG. - // An exception A preceeds an exception B in the exception table iff: - - // * A and B were in the original method, and A preceeded B in the original exception table - // * If A has a higher priority than B, than it preceeds B. - // * If A and B have the same priority, then the one whose START happens EARLIEST has LEAST priority. - // in short, the outermost exception has least priority. - // we implement this with a LinkedList. We could possibly implement this with a java.util.SortedSet, - // but I don't trust the only implementation, TreeSet, to do the right thing. - - /* private */ static void insertHandler(ExceptionRange fresh, LinkedList l) { - // Old implementation, simply: l.add(0,fresh); - for (ListIterator iter = l.listIterator(); iter.hasNext();) { - ExceptionRange r = (ExceptionRange) iter.next(); -// int freal = fresh.getRealStart().getPosition(); -// int rreal = r.getRealStart().getPosition(); - if (fresh.getPriority() >= r.getPriority()) { - iter.previous(); - iter.add(fresh); - return; - } - } - - // we have reached the end - l.add(fresh); - } - - - public boolean isPrivate() { - return Modifier.isPrivate(getAccessFlags()); - } - public boolean isProtected() { - return Modifier.isProtected(getAccessFlags()); - } - public boolean isDefault() { - return !(isProtected() || isPrivate() || isPublic()); - } - public boolean isPublic() { - return Modifier.isPublic(getAccessFlags()); - } + // public void killNops() { + // InstructionHandle curr = body.getStart(); + // while (true) { + // if (curr == null) break; + // InstructionHandle next = curr.getNext(); + // if (curr.getInstruction() instanceof NOP) { + // InstructionTargeter[] targeters = curr.getTargeters(); + // if (targeters != null) { + // for (int i = 0, len = targeters.length; i < len; i++) { + // InstructionTargeter targeter = targeters[i]; + // targeter.updateTarget(curr, next); + // } + // } + // try { + // body.delete(curr); + // } catch (TargetLostException e) { + // } + // } + // curr = next; + // } + // } + // private static InstructionHandle fNext(InstructionHandle ih) { + // while (true) { + // if (ih.getInstruction()==Range.RANGEINSTRUCTION) ih = ih.getNext(); + // else return ih; + // } + // } + private static InstructionHandle remap(InstructionHandle ih, Map map) { + while (true) { + Object ret = map.get(ih); + if (ret == null) { + ih = ih.getNext(); + } else { + return (InstructionHandle) ret; + } + } + } + // Update to all these comments, ASC 11-01-2005 + // The right thing to do may be to do more with priorities as + // we create new exception handlers, but that is a relatively + // complex task. In the meantime, just taking account of the + // priority here enables a couple of bugs to be fixed to do + // with using return or break in code that contains a finally + // block (pr78021,pr79554). + + // exception ordering. + // What we should be doing is dealing with priority inversions way earlier than we are + // and counting on the tree structure. In which case, the below code is in fact right. + + // XXX THIS COMMENT BELOW IS CURRENTLY WRONG. + // An exception A preceeds an exception B in the exception table iff: + + // * A and B were in the original method, and A preceeded B in the original exception table + // * If A has a higher priority than B, than it preceeds B. + // * If A and B have the same priority, then the one whose START happens EARLIEST has LEAST priority. + // in short, the outermost exception has least priority. + // we implement this with a LinkedList. We could possibly implement this with a java.util.SortedSet, + // but I don't trust the only implementation, TreeSet, to do the right thing. + + /* private */static void insertHandler(ExceptionRange fresh, LinkedList l) { + // Old implementation, simply: l.add(0,fresh); + for (ListIterator iter = l.listIterator(); iter.hasNext();) { + ExceptionRange r = (ExceptionRange) iter.next(); + // int freal = fresh.getRealStart().getPosition(); + // int rreal = r.getRealStart().getPosition(); + if (fresh.getPriority() >= r.getPriority()) { + iter.previous(); + iter.add(fresh); + return; + } + } + + // we have reached the end + l.add(fresh); + } + + public boolean isPrivate() { + return Modifier.isPrivate(getAccessFlags()); + } + + public boolean isProtected() { + return Modifier.isProtected(getAccessFlags()); + } + + public boolean isDefault() { + return !(isProtected() || isPrivate() || isPublic()); + } + + public boolean isPublic() { + return Modifier.isPublic(getAccessFlags()); + } // ---- - - /** A good body is a body with the following properties: - * + + /** + * A good body is a body with the following properties: + * *

- * - * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and - * any InstructionHandle stored in a field of R (such as an exception handle) is in body". + * + * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and any InstructionHandle stored in a field + * of R (such as an exception handle) is in body". */ - + public void assertGoodBody() { - if (true) return; // only enable for debugging, consider using cheaper toString() - assertGoodBody(getBody(), toString()); //definingType.getNameAsIdentifier() + "." + getName()); //toString()); + if (true) + return; // only enable for debugging, consider using cheaper toString() + assertGoodBody(getBody(), toString()); // definingType.getNameAsIdentifier() + "." + getName()); //toString()); } - + public static void assertGoodBody(InstructionList il, String from) { - if (true) return; // only to be enabled for debugging - if (il == null) return; + if (true) + return; // only to be enabled for debugging + if (il == null) + return; Set body = new HashSet(); Stack ranges = new Stack(); for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { @@ -1450,12 +1386,12 @@ public final class LazyMethodGen implements Traceable { body.add(ih.getInstruction()); } } - + for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { assertGoodHandle(ih, body, ranges, from); Iterator tIter = ih.getTargeters().iterator(); while (tIter.hasNext()) { - assertGoodTargeter((InstructionTargeter)tIter.next(),ih,body,from); + assertGoodTargeter((InstructionTargeter) tIter.next(), ih, body, from); } } } @@ -1472,13 +1408,7 @@ public final class LazyMethodGen implements Traceable { } } - private static void assertGoodBranchInstruction( - BranchHandle ih, - InstructionBranch inst, - Set body, - Stack ranges, - String from) - { + private static void assertGoodBranchInstruction(BranchHandle ih, InstructionBranch inst, Set body, Stack ranges, String from) { if (ih.getTarget() != inst.getTarget()) { throw new BCException("bad branch instruction/handle pair in " + from); } @@ -1487,31 +1417,33 @@ public final class LazyMethodGen implements Traceable { assertTargetedBy(target, inst, from); if (inst instanceof InstructionSelect) { InstructionSelect sel = (InstructionSelect) inst; - InstructionHandle[] itargets = sel.getTargets(); - for (int k = itargets.length - 1; k >= 0; k--) { + InstructionHandle[] itargets = sel.getTargets(); + for (int k = itargets.length - 1; k >= 0; k--) { assertInBody(itargets[k], body, from); assertTargetedBy(itargets[k], inst, from); - } - } + } + } } /** ih is an InstructionHandle or a BranchInstruction */ private static void assertInBody(Object ih, Set body, String from) { - if (! body.contains(ih)) throw new BCException("thing not in body in " + from); + if (!body.contains(ih)) + throw new BCException("thing not in body in " + from); } - private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) { + private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) { Range r = getRangeAndAssertExactlyOne(ih, from); assertGoodRange(r, body, from); if (r.getStart() == ih) { ranges.push(r); } else if (r.getEnd() == ih) { - if (ranges.peek() != r) throw new BCException("bad range inclusion in " + from); + if (ranges.peek() != r) + throw new BCException("bad range inclusion in " + from); ranges.pop(); } - } - - private static void assertGoodRange(Range r, Set body, String from) { + } + + private static void assertGoodRange(Range r, Set body, String from) { assertInBody(r.getStart(), body, from); assertRangeHandle(r.getStart(), from); assertTargetedBy(r.getStart(), r, from); @@ -1519,130 +1451,131 @@ public final class LazyMethodGen implements Traceable { assertInBody(r.getEnd(), body, from); assertRangeHandle(r.getEnd(), from); assertTargetedBy(r.getEnd(), r, from); - + if (r instanceof ExceptionRange) { ExceptionRange er = (ExceptionRange) r; assertInBody(er.getHandler(), body, from); assertTargetedBy(er.getHandler(), r, from); - } - } + } + } private static void assertRangeHandle(InstructionHandle ih, String from) { - if (! Range.isRangeHandle(ih)) throw new BCException("bad range handle " + ih + " in " + from); + if (!Range.isRangeHandle(ih)) + throw new BCException("bad range handle " + ih + " in " + from); } - - private static void assertTargetedBy( - InstructionHandle target, - InstructionTargeter targeter, - String from) - { - Iterator tIter = target.getTargeters().iterator(); - while (tIter.hasNext()) { - if (((InstructionTargeter)tIter.next()) == targeter) return; - } + private static void assertTargetedBy(InstructionHandle target, InstructionTargeter targeter, String from) { + Iterator tIter = target.getTargeters().iterator(); + while (tIter.hasNext()) { + if (((InstructionTargeter) tIter.next()) == targeter) + return; + } throw new RuntimeException("bad targeting relationship in " + from); - } - + } + private static void assertTargets(InstructionTargeter targeter, InstructionHandle target, String from) { if (targeter instanceof Range) { Range r = (Range) targeter; - if (r.getStart() == target || r.getEnd() == target) return; + if (r.getStart() == target || r.getEnd() == target) + return; if (r instanceof ExceptionRange) { - if (((ExceptionRange)r).getHandler() == target) return; + if (((ExceptionRange) r).getHandler() == target) + return; } } else if (targeter instanceof InstructionBranch) { InstructionBranch bi = (InstructionBranch) targeter; - if (bi.getTarget() == target) return; + if (bi.getTarget() == target) + return; if (targeter instanceof InstructionSelect) { InstructionSelect sel = (InstructionSelect) targeter; - InstructionHandle[] itargets = sel.getTargets(); - for (int k = itargets.length - 1; k >= 0; k--) { - if (itargets[k] == target) return; - } - } + InstructionHandle[] itargets = sel.getTargets(); + for (int k = itargets.length - 1; k >= 0; k--) { + if (itargets[k] == target) + return; + } + } } else if (targeter instanceof Tag) { return; } - throw new BCException(targeter + " doesn't target " + target + " in " + from ); - } - - private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) { - Range ret = null; - Iterator tIter = ih.getTargeters().iterator(); - if (!tIter.hasNext()) { - throw new BCException("range handle with no range in " + from); - } - while (tIter.hasNext()) { - InstructionTargeter ts = (InstructionTargeter)tIter.next(); - if (ts instanceof Range) { - if (ret != null) throw new BCException("range handle with multiple ranges in " + from); - ret = (Range) ts; - } - } - if (ret == null) throw new BCException("range handle with no range in " + from); + throw new BCException(targeter + " doesn't target " + target + " in " + from); + } + + private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) { + Range ret = null; + Iterator tIter = ih.getTargeters().iterator(); + if (!tIter.hasNext()) { + throw new BCException("range handle with no range in " + from); + } + while (tIter.hasNext()) { + InstructionTargeter ts = (InstructionTargeter) tIter.next(); + if (ts instanceof Range) { + if (ret != null) + throw new BCException("range handle with multiple ranges in " + from); + ret = (Range) ts; + } + } + if (ret == null) + throw new BCException("range handle with no range in " + from); return ret; - } - - private static void assertGoodTargeter( - InstructionTargeter t, - InstructionHandle ih, - Set body, - String from) - { - assertTargets(t, ih, from); + } + + private static void assertGoodTargeter(InstructionTargeter t, InstructionHandle ih, Set body, String from) { + assertTargets(t, ih, from); if (t instanceof Range) { assertGoodRange((Range) t, body, from); } else if (t instanceof InstructionBranch) { assertInBody(t, body, from); } - } - - - // ---- - - boolean isAdviceMethod() { - if (memberView==null) return false; - return memberView.getAssociatedShadowMunger() != null; - } - - boolean isAjSynthetic() { - if (memberView == null) return true; - return memberView.isAjSynthetic(); - } - - - boolean isSynthetic() { - if (memberView == null) return false; - return memberView.isSynthetic(); - } - - public ISourceLocation getSourceLocation() { - if (memberView!=null) return memberView.getSourceLocation(); - return null; - } - - public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { - //if (memberView == null) return null; - if (effectiveSignature != null) return effectiveSignature; - return memberView.getEffectiveSignature(); - } - - public void setEffectiveSignature(ResolvedMember member, Shadow.Kind kind, boolean shouldWeave) { - this.effectiveSignature = - new AjAttribute.EffectiveSignatureAttribute(member,kind,shouldWeave); - } - + } + + // ---- + + boolean isAdviceMethod() { + if (memberView == null) + return false; + return memberView.getAssociatedShadowMunger() != null; + } + + boolean isAjSynthetic() { + if (memberView == null) + return true; + return memberView.isAjSynthetic(); + } + + boolean isSynthetic() { + if (memberView == null) + return false; + return memberView.isSynthetic(); + } + + public ISourceLocation getSourceLocation() { + if (memberView != null) + return memberView.getSourceLocation(); + return null; + } + + public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { + // if (memberView == null) return null; + if (effectiveSignature != null) + return effectiveSignature; + return memberView.getEffectiveSignature(); + } + + public void setEffectiveSignature(ResolvedMember member, Shadow.Kind kind, boolean shouldWeave) { + this.effectiveSignature = new AjAttribute.EffectiveSignatureAttribute(member, kind, shouldWeave); + } + public String getSignature() { - if (memberView!=null) return memberView.getSignature(); - return MemberImpl.typesToSignature(BcelWorld.fromBcel(getReturnType()), - BcelWorld.fromBcel(getArgumentTypes()),false); + if (memberView != null) + return memberView.getSignature(); + return MemberImpl.typesToSignature(BcelWorld.fromBcel(getReturnType()), BcelWorld.fromBcel(getArgumentTypes()), false); + } + + public String getParameterSignature() { + if (memberView != null) + return memberView.getParameterSignature(); + return MemberImpl.typesToSignature(BcelWorld.fromBcel(getArgumentTypes())); } - - public String getParameterSignature() { - if (memberView!=null) return memberView.getParameterSignature(); - return MemberImpl.typesToSignature(BcelWorld.fromBcel(getArgumentTypes())); - } public BcelMethod getMemberView() { return memberView; @@ -1661,17 +1594,18 @@ public final class LazyMethodGen implements Traceable { this.canInline = canInline; } - /** - * Adds an attribute to the method - * @param attr - */ - public void addAttribute(Attribute attr) { - attributes.add(attr); -// Attribute[] newAttributes = new Attribute[attributes.length + 1]; -// System.arraycopy(attributes, 0, newAttributes, 0, attributes.length); -// newAttributes[attributes.length] = attr; -// attributes = newAttributes; - } + /** + * Adds an attribute to the method + * + * @param attr + */ + public void addAttribute(Attribute attr) { + attributes.add(attr); + // Attribute[] newAttributes = new Attribute[attributes.length + 1]; + // System.arraycopy(attributes, 0, newAttributes, 0, attributes.length); + // newAttributes[attributes.length] = attr; + // attributes = newAttributes; + } public String toTraceString() { return toShortString(); diff --git a/weaver/src/org/aspectj/weaver/bcel/Range.java b/weaver/src/org/aspectj/weaver/bcel/Range.java index c0d46d8f0..b0516a3de 100644 --- a/weaver/src/org/aspectj/weaver/bcel/Range.java +++ b/weaver/src/org/aspectj/weaver/bcel/Range.java @@ -10,11 +10,9 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.util.Iterator; -import java.util.Map; import org.aspectj.apache.bcel.generic.Instruction; import org.aspectj.apache.bcel.generic.InstructionConstants; @@ -25,9 +23,9 @@ import org.aspectj.weaver.BCException; abstract class Range implements InstructionTargeter { - protected InstructionList body; - protected InstructionHandle start; - protected InstructionHandle end; + protected InstructionList body; + protected InstructionHandle start; + protected InstructionHandle end; // ---- initialization @@ -35,202 +33,204 @@ abstract class Range implements InstructionTargeter { this.body = il; } - - // ---- + // ---- final InstructionList getBody() { return body; } - final InstructionHandle getStart() { - return start; - } - final InstructionHandle getEnd() { - return end; - } - - // ---- - - boolean isEmpty() { - InstructionHandle ih = start; - //System.err.println(" looking for " + end); - while (ih != end) { - //System.err.println(" ih " + ih); - if (! Range.isRangeHandle(ih)) return false; - ih = ih.getNext(); - } - return true; - } - - static InstructionHandle getRealStart(InstructionHandle ih) { - while (Range.isRangeHandle(ih)) { - ih = ih.getNext(); - } - return ih; - } - - InstructionHandle getRealStart() { - return getRealStart(start); - } - - static InstructionHandle getRealEnd(InstructionHandle ih) { - while (Range.isRangeHandle(ih)) { - ih = ih.getPrev(); - } - return ih; - } - InstructionHandle getRealEnd() { - return getRealEnd(end); - } - - InstructionHandle getRealNext() { - return getRealStart(end); - } - - static InstructionHandle getRealPrev(InstructionHandle ih) { - InstructionHandle ret = ih.getPrev(); - while (isRangeHandle(ret)) { - ret = ret.getPrev(); + + final InstructionHandle getStart() { + return start; + } + + final InstructionHandle getEnd() { + return end; + } + + // ---- + + boolean isEmpty() { + InstructionHandle ih = start; + // System.err.println(" looking for " + end); + while (ih != end) { + // System.err.println(" ih " + ih); + if (!Range.isRangeHandle(ih)) + return false; + ih = ih.getNext(); + } + return true; + } + + static InstructionHandle getRealStart(InstructionHandle ih) { + while (Range.isRangeHandle(ih)) { + ih = ih.getNext(); + } + return ih; + } + + InstructionHandle getRealStart() { + return getRealStart(start); + } + + static InstructionHandle getRealEnd(InstructionHandle ih) { + while (Range.isRangeHandle(ih)) { + ih = ih.getPrev(); } + return ih; + } + + InstructionHandle getRealEnd() { + return getRealEnd(end); + } + + InstructionHandle getRealNext() { + return getRealStart(end); + } + + // ---- + + InstructionHandle insert(Instruction i, Where where) { + InstructionList il = new InstructionList(); + InstructionHandle ret = il.insert(i); + insert(il, where); return ret; } - // ---- - - InstructionHandle insert(Instruction i, Where where) { - InstructionList il = new InstructionList(); - InstructionHandle ret = il.insert(i); - insert(il, where); - return ret; - } - void insert(InstructionList freshIl, Where where) { - InstructionHandle h; - if (where == InsideBefore || where == OutsideBefore) { - h = getStart(); - } else { - h = getEnd(); - } - if (where == InsideBefore || where == OutsideAfter) { - body.append(h, freshIl); - } else { - InstructionHandle newStart = body.insert(h, freshIl); - if (where == OutsideBefore) { - // XXX this is slow. There's a better design than this. We should - // never have to retarget branches apart from the creation of ranges. - // basically, we should never weave OutsideBefore. + void insert(InstructionList freshIl, Where where) { + InstructionHandle h; + if (where == InsideBefore || where == OutsideBefore) { + h = getStart(); + } else { + h = getEnd(); + } + if (where == InsideBefore || where == OutsideAfter) { + body.append(h, freshIl); + } else { + InstructionHandle newStart = body.insert(h, freshIl); + if (where == OutsideBefore) { + // XXX this is slow. There's a better design than this. We should + // never have to retarget branches apart from the creation of ranges. + // basically, we should never weave OutsideBefore. BcelShadow.retargetAllBranches(h, newStart); - } - } - - } - InstructionHandle append(Instruction i) { - return insert(i, InsideAfter); - } - void append(InstructionList i) { - insert(i, InsideAfter); - } - - static InstructionHandle remap(InstructionHandle h, Map m) { - return (InstructionHandle) m.get(h); - } - - private static void setLineNumberFromNext(InstructionHandle ih) { - int lineNumber = Utility.getSourceLine(ih.getNext()); - if (lineNumber != -1) { - Utility.setSourceLine(ih, lineNumber); - } - } - - static InstructionHandle genStart(InstructionList body) { - InstructionHandle ih = body.insert(Range.RANGEINSTRUCTION); - setLineNumberFromNext(ih); - return ih; - } - - static InstructionHandle genEnd(InstructionList body) { - return body.append(Range.RANGEINSTRUCTION); - } - static InstructionHandle genStart(InstructionList body, InstructionHandle ih) { - if (ih == null) return genStart(body); - InstructionHandle freshIh = body.insert(ih, Range.RANGEINSTRUCTION); - setLineNumberFromNext(freshIh); - return freshIh; - } - - static InstructionHandle genEnd(InstructionList body, InstructionHandle ih) { - if (ih == null) return genEnd(body); - return body.append(ih, Range.RANGEINSTRUCTION); - } - - // ----- - - public boolean containsTarget(InstructionHandle ih) { - return false; - } - - public final void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { - throw new RuntimeException("Ranges must be updated with an enclosing instructionList"); - } - - protected void updateTarget( - InstructionHandle old_ih, - InstructionHandle new_ih, - InstructionList new_il) - { - old_ih.removeTargeter(this); - if (new_ih != null) - new_ih.addTargeter(this); - body = new_il; - - if (old_ih == start) { - start = new_ih; - } - if (old_ih == end) { - end = new_ih; - } - } - - public static final boolean isRangeHandle(InstructionHandle ih) { - if (ih == null) return false; - return ih.getInstruction() == Range.RANGEINSTRUCTION; - } - - protected static final Range getRange(InstructionHandle ih) { - // assert isRangeHandle(ih) + } + } + + } + + InstructionHandle append(Instruction i) { + return insert(i, InsideAfter); + } + + void append(InstructionList i) { + insert(i, InsideAfter); + } + + private static void setLineNumberFromNext(InstructionHandle ih) { + int lineNumber = Utility.getSourceLine(ih.getNext()); + if (lineNumber != -1) { + Utility.setSourceLine(ih, lineNumber); + } + } + + static InstructionHandle genStart(InstructionList body) { + InstructionHandle ih = body.insert(Range.RANGEINSTRUCTION); + setLineNumberFromNext(ih); + return ih; + } + + static InstructionHandle genEnd(InstructionList body) { + return body.append(Range.RANGEINSTRUCTION); + } + + static InstructionHandle genStart(InstructionList body, InstructionHandle ih) { + if (ih == null) + return genStart(body); + InstructionHandle freshIh = body.insert(ih, Range.RANGEINSTRUCTION); + setLineNumberFromNext(freshIh); + return freshIh; + } + + static InstructionHandle genEnd(InstructionList body, InstructionHandle ih) { + if (ih == null) + return genEnd(body); + return body.append(ih, Range.RANGEINSTRUCTION); + } + + // ----- + + public boolean containsTarget(InstructionHandle ih) { + return false; + } + + public final void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { + throw new RuntimeException("Ranges must be updated with an enclosing instructionList"); + } + + protected void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih, InstructionList new_il) { + old_ih.removeTargeter(this); + if (new_ih != null) + new_ih.addTargeter(this); + body = new_il; + + if (old_ih == start) { + start = new_ih; + } + if (old_ih == end) { + end = new_ih; + } + } + + public static final boolean isRangeHandle(InstructionHandle ih) { + if (ih == null) + return false; + return ih.getInstruction() == Range.RANGEINSTRUCTION; + } + + protected static final Range getRange(InstructionHandle ih) { + // assert isRangeHandle(ih) Range ret = null; Iterator tIter = ih.getTargeters().iterator(); while (tIter.hasNext()) { - InstructionTargeter targeter = (InstructionTargeter)tIter.next(); - if (targeter instanceof Range) { - Range r = (Range) targeter; - if (r.getStart() != ih && r.getEnd() != ih) continue; - if (ret != null) throw new BCException("multiple ranges on same range handle: " + ret + ", " + targeter); - ret = r; - } - } + InstructionTargeter targeter = (InstructionTargeter) tIter.next(); + if (targeter instanceof Range) { + Range r = (Range) targeter; + if (r.getStart() != ih && r.getEnd() != ih) + continue; + if (ret != null) + throw new BCException("multiple ranges on same range handle: " + ret + ", " + targeter); + ret = r; + } + } if (ret == null) { throw new BCException("shouldn't happen"); } return ret; - } + } + + // ---- - // ---- + static final Where InsideBefore = new Where("insideBefore"); + static final Where InsideAfter = new Where("insideAfter"); + static final Where OutsideBefore = new Where("outsideBefore"); + static final Where OutsideAfter = new Where("outsideAfter"); - static final Where InsideBefore = new Where("insideBefore"); - static final Where InsideAfter = new Where("insideAfter"); - static final Where OutsideBefore = new Where("outsideBefore"); - static final Where OutsideAfter = new Where("outsideAfter"); + // ---- constants - // ---- constants + // note that this is STUPIDLY copied by Instruction.copy(), so don't do that. - // note that this is STUPIDLY copied by Instruction.copy(), so don't do that. + public static final Instruction RANGEINSTRUCTION = InstructionConstants.IMPDEP1; - public static final Instruction RANGEINSTRUCTION = InstructionConstants.IMPDEP1; - - // ---- + // ---- - static class Where { - private String name; - public Where(String name) { this.name = name; } - public String toString() { return name; } - } + static class Where { + private String name; + + public Where(String name) { + this.name = name; + } + + public String toString() { + return name; + } + } } diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java index 7e43d465d..e45eac109 100644 --- a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java +++ b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java @@ -10,12 +10,10 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.io.BufferedOutputStream; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; import java.util.Collections; import java.util.Iterator; @@ -28,104 +26,97 @@ public class UnwovenClassFile { protected String filename; protected char[] charfilename; protected byte[] bytes; -// protected JavaClass javaClass = null; - //protected byte[] writtenBytes = null; - protected List /* ChildClass */ writtenChildClasses = Collections.EMPTY_LIST; + // protected JavaClass javaClass = null; + // protected byte[] writtenBytes = null; + protected List /* ChildClass */writtenChildClasses = Collections.EMPTY_LIST; protected String className = null; - + public UnwovenClassFile(String filename, byte[] bytes) { this.filename = filename; this.bytes = bytes; } - /** Use if the classname is known, saves a bytecode parse */ - public UnwovenClassFile(String filename, String classname,byte[] bytes) { + /** Use if the classname is known, saves a bytecode parse */ + public UnwovenClassFile(String filename, String classname, byte[] bytes) { this.filename = filename; this.className = classname; this.bytes = bytes; } - + public String getFilename() { return filename; } - + public String makeInnerFileName(String innerName) { - String prefix = filename.substring(0, filename.length()-6); // strip the .class + String prefix = filename.substring(0, filename.length() - 6); // strip the .class return prefix + "$" + innerName + ".class"; } - + public byte[] getBytes() { -// if (bytes == null) bytes = javaClass.getBytes(); + // if (bytes == null) bytes = javaClass.getBytes(); return bytes; } - + public JavaClass getJavaClass() { - //XXX need to know when to make a new class and when not to - //XXX this is an important optimization + // XXX need to know when to make a new class and when not to + // XXX this is an important optimization if (getBytes() == null) { System.out.println("no bytes for: " + getFilename()); - //Thread.currentThread().dumpStack(); - Thread.dumpStack(); + // Thread.currentThread().dumpStack(); + Thread.dumpStack(); } return Utility.makeJavaClass(filename, getBytes()); -// if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes()); -// return javaClass; - } - - public boolean exists() { - return getBytes() != null; + // if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes()); + // return javaClass; } - public void writeUnchangedBytes() throws IOException { writeWovenBytes(getBytes(), Collections.EMPTY_LIST); } - - public void writeWovenBytes(byte[] bytes, List childClasses) throws IOException { + + public void writeWovenBytes(byte[] bytes, List childClasses) throws IOException { writeChildClasses(childClasses); - - //System.err.println("should write: " + getClassName()); - - //System.err.println("about to write: " + this + ", " + writtenBytes + ", "); -// + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) ); - - //if (writtenBytes != null && unchanged(bytes, writtenBytes)) return; - - //System.err.println(" actually wrote it"); - + + // System.err.println("should write: " + getClassName()); + + // System.err.println("about to write: " + this + ", " + writtenBytes + ", "); + // + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) ); + + // if (writtenBytes != null && unchanged(bytes, writtenBytes)) return; + + // System.err.println(" actually wrote it"); + BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename)); os.write(bytes); os.close(); - - //writtenBytes = bytes; + + // writtenBytes = bytes; } private void writeChildClasses(List childClasses) throws IOException { - //??? we only really need to delete writtenChildClasses whose - //??? names aren't in childClasses; however, it's unclear - //??? how much that will affect performance + // ??? we only really need to delete writtenChildClasses whose + // ??? names aren't in childClasses; however, it's unclear + // ??? how much that will affect performance deleteAllChildClasses(); - childClasses.removeAll(writtenChildClasses); //XXX is this right - + childClasses.removeAll(writtenChildClasses); // XXX is this right + for (Iterator iter = childClasses.iterator(); iter.hasNext();) { ChildClass childClass = (ChildClass) iter.next(); writeChildClassFile(childClass.name, childClass.bytes); - + } - + writtenChildClasses = childClasses; - + } private void writeChildClassFile(String innerName, byte[] bytes) throws IOException { - BufferedOutputStream os = - FileUtil.makeOutputStream(new File(makeInnerFileName(innerName))); + BufferedOutputStream os = FileUtil.makeOutputStream(new File(makeInnerFileName(innerName))); os.write(bytes); os.close(); } - protected void deleteAllChildClasses() { for (Iterator iter = writtenChildClasses.iterator(); iter.hasNext();) { ChildClass childClass = (ChildClass) iter.next(); @@ -138,77 +129,57 @@ public class UnwovenClassFile { childClassFile.delete(); } - - - /* private */ static boolean unchanged(byte[] b1, byte[] b2) { + /* private */static boolean unchanged(byte[] b1, byte[] b2) { int len = b1.length; - if (b2.length != len) return false; - for (int i=0; i < len; i++) { - if (b1[i] != b2[i]) return false; + if (b2.length != len) + return false; + for (int i = 0; i < len; i++) { + if (b1[i] != b2[i]) + return false; } return true; } public char[] getClassNameAsChars() { - if (charfilename==null) { + if (charfilename == null) { charfilename = getClassName().replace('.', '/').toCharArray(); } return charfilename; } - + public String getClassName() { - if (className == null) className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely? + if (className == null) + className = getJavaClass().getClassName(); // OPTIMIZE quicker way to determine name??? surely? return className; } - + public String toString() { return "UnwovenClassFile(" + filename + ", " + getClassName() + ")"; } - - /** - * delete not just this file, but any files in the same directory that - * were generated as a result of weaving it (e.g. for an around closure). - */ - public void deleteRealFile() throws IOException { - File victim = new File(filename); - String namePrefix = victim.getName(); - namePrefix = namePrefix.substring(0,namePrefix.lastIndexOf('.')); - final String targetPrefix = namePrefix + "$Ajc"; - File dir = victim.getParentFile(); - if (dir != null) { - File[] weaverGenerated = dir.listFiles(new FilenameFilter() { - public boolean accept(File dir, String name) { - return name.startsWith(targetPrefix); - }}); - if (weaverGenerated!=null) { - for (int i = 0; i < weaverGenerated.length; i++) { - weaverGenerated[i].delete(); - } - } - } - victim.delete(); - } // record - // OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put it back on! + // OPTIMIZE why is the 'short name' used here (the bit after the dollar) - seems we mess about a lot trimming it off only to put + // it back on! public static class ChildClass { public final String name; public final byte[] bytes; - + ChildClass(String name, byte[] bytes) { this.name = name; this.bytes = bytes; } - + public boolean equals(Object other) { - if (! (other instanceof ChildClass)) return false; + if (!(other instanceof ChildClass)) + return false; ChildClass o = (ChildClass) other; return o.name.equals(name) && unchanged(o.bytes, bytes); } + public int hashCode() { return name.hashCode(); } - + public String toString() { return "(ChildClass " + name + ")"; } @@ -218,7 +189,3 @@ public class UnwovenClassFile { this.charfilename = classNameAsChars; } } - - - - diff --git a/weaver/src/org/aspectj/weaver/bcel/Utility.java b/weaver/src/org/aspectj/weaver/bcel/Utility.java index 1fe85e37d..9eb24e9b8 100644 --- a/weaver/src/org/aspectj/weaver/bcel/Utility.java +++ b/weaver/src/org/aspectj/weaver/bcel/Utility.java @@ -10,7 +10,6 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.bcel; import java.io.ByteArrayInputStream; @@ -63,151 +62,124 @@ import org.aspectj.weaver.ResolvedType; import org.aspectj.weaver.UnresolvedType; public class Utility { - + /* - * Ensure we report a nice source location - particular in the case - * where the source info is missing (binary weave). + * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave). */ public static String beautifyLocation(ISourceLocation isl) { StringBuffer nice = new StringBuffer(); - if (isl==null || isl.getSourceFile()==null || isl.getSourceFile().getName().indexOf("no debug info available")!=-1) { + if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().indexOf("no debug info available") != -1) { nice.append("no debug info available"); - } else { - // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa - int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/'); - if (takeFrom == -1) { - takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\'); - } - nice.append(isl.getSourceFile().getPath().substring(takeFrom +1)); - if (isl.getLine()!=0) nice.append(":").append(isl.getLine()); + } else { + // can't use File.getName() as this fails when a Linux box encounters a path created on Windows and vice-versa + int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/'); + if (takeFrom == -1) { + takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\'); + } + nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1)); + if (isl.getLine() != 0) + nice.append(":").append(isl.getLine()); } return nice.toString(); } - - - public static Instruction createSuperInvoke( - InstructionFactory fact, - BcelWorld world, - Member signature) { - short kind; - if (signature.isInterface()) { - throw new RuntimeException("bad"); - } else if (signature.isPrivate() || signature.getName().equals("")) { - throw new RuntimeException("unimplemented, possibly bad"); - } else if (signature.isStatic()) { - throw new RuntimeException("bad"); - } else { - kind = Constants.INVOKESPECIAL; - } - - return fact.createInvoke( - signature.getDeclaringType().getName(), - signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), - BcelWorld.makeBcelTypes(signature.getParameterTypes()), - kind); - } - - // XXX don't need the world now - public static Instruction createInvoke( - InstructionFactory fact, - BcelWorld world, - Member signature) { - short kind; - if (signature.isInterface()) { - kind = Constants.INVOKEINTERFACE; - } else if (signature.isStatic()) { - kind = Constants.INVOKESTATIC; - } else if (signature.isPrivate() || signature.getName().equals("")) { - kind = Constants.INVOKESPECIAL; - } else { - kind = Constants.INVOKEVIRTUAL; - } - - UnresolvedType targetType = signature.getDeclaringType(); - if (targetType.isParameterizedType()) { - targetType = targetType.resolve(world).getGenericType(); - } - return fact.createInvoke( - targetType.getName(), - signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), - BcelWorld.makeBcelTypes(signature.getParameterTypes()), - kind); + + public static Instruction createSuperInvoke(InstructionFactory fact, BcelWorld world, Member signature) { + short kind; + if (signature.isInterface()) { + throw new RuntimeException("bad"); + } else if (signature.isPrivate() || signature.getName().equals("")) { + throw new RuntimeException("unimplemented, possibly bad"); + } else if (signature.isStatic()) { + throw new RuntimeException("bad"); + } else { + kind = Constants.INVOKESPECIAL; + } + + return fact.createInvoke(signature.getDeclaringType().getName(), signature.getName(), BcelWorld.makeBcelType(signature + .getReturnType()), BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind); + } + + // XXX don't need the world now + public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) { + short kind; + if (signature.isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (signature.isStatic()) { + kind = Constants.INVOKESTATIC; + } else if (signature.isPrivate() || signature.getName().equals("")) { + kind = Constants.INVOKESPECIAL; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + UnresolvedType targetType = signature.getDeclaringType(); + if (targetType.isParameterizedType()) { + targetType = targetType.resolve(world).getGenericType(); + } + return fact.createInvoke(targetType.getName(), signature.getName(), BcelWorld.makeBcelType(signature.getReturnType()), + BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind); } public static Instruction createGet(InstructionFactory fact, Member signature) { - short kind; - if (signature.isStatic()) { - kind = Constants.GETSTATIC; - } else { - kind = Constants.GETFIELD; - } - - return fact.createFieldAccess( - signature.getDeclaringType().getName(), - signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), - kind); - } - - /** - * Creae a field GET instruction - * - * @param fact - * @param signature - * @param declaringType - * @return - */ - public static Instruction createGetOn(InstructionFactory fact, Member signature, UnresolvedType declaringType) { - short kind; - if (signature.isStatic()) { - kind = Constants.GETSTATIC; - } else { - kind = Constants.GETFIELD; - } - - return fact.createFieldAccess( - declaringType.getName(), - signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), - kind); - } + short kind; + if (signature.isStatic()) { + kind = Constants.GETSTATIC; + } else { + kind = Constants.GETFIELD; + } + + return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(), BcelWorld.makeBcelType(signature + .getReturnType()), kind); + } + + /** + * Creae a field GET instruction + * + * @param fact + * @param signature + * @param declaringType + * @return + */ + public static Instruction createGetOn(InstructionFactory fact, Member signature, UnresolvedType declaringType) { + short kind; + if (signature.isStatic()) { + kind = Constants.GETSTATIC; + } else { + kind = Constants.GETFIELD; + } + + return fact.createFieldAccess(declaringType.getName(), signature.getName(), BcelWorld.makeBcelType(signature + .getReturnType()), kind); + } public static Instruction createSet(InstructionFactory fact, Member signature) { - short kind; - if (signature.isStatic()) { - kind = Constants.PUTSTATIC; - } else { - kind = Constants.PUTFIELD; - } - - return fact.createFieldAccess( - signature.getDeclaringType().getName(), - signature.getName(), - BcelWorld.makeBcelType(signature.getReturnType()), - kind); - } - - public static Instruction createInvoke( - InstructionFactory fact, - JavaClass declaringClass, - Method newMethod) { - short kind; - if (newMethod.isInterface()) { - kind = Constants.INVOKEINTERFACE; - } else if (newMethod.isStatic()) { - kind = Constants.INVOKESTATIC; - } else if (newMethod.isPrivate() || newMethod.getName().equals("")) { - kind = Constants.INVOKESPECIAL; - } else { - kind = Constants.INVOKEVIRTUAL; - } - - String sig = newMethod.getSignature(); - return fact.createInvoke(declaringClass.getClassName(),newMethod.getName(),sig,kind); - } - + short kind; + if (signature.isStatic()) { + kind = Constants.PUTSTATIC; + } else { + kind = Constants.PUTFIELD; + } + + return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(), BcelWorld.makeBcelType(signature + .getReturnType()), kind); + } + + public static Instruction createInvoke(InstructionFactory fact, JavaClass declaringClass, Method newMethod) { + short kind; + if (newMethod.isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (newMethod.isStatic()) { + kind = Constants.INVOKESTATIC; + } else if (newMethod.isPrivate() || newMethod.getName().equals("")) { + kind = Constants.INVOKESPECIAL; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + String sig = newMethod.getSignature(); + return fact.createInvoke(declaringClass.getClassName(), newMethod.getName(), sig, kind); + } + public static byte[] stringToUTF(String s) { try { ByteArrayOutputStream out0 = new ByteArrayOutputStream(); @@ -219,340 +191,289 @@ public class Utility { } } - public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) { - int cpoolEntry = - (t instanceof ArrayType) - ? fact.getConstantPool().addArrayClass((ArrayType)t) - : fact.getConstantPool().addClass((ObjectType)t); - return new InstructionCP(Constants.INSTANCEOF,cpoolEntry); - } - - public static Instruction createInvoke( - InstructionFactory fact, - LazyMethodGen m) { - short kind; - if (m.getEnclosingClass().isInterface()) { - kind = Constants.INVOKEINTERFACE; - } else if (m.isStatic()) { - kind = Constants.INVOKESTATIC; - } else if (m.isPrivate() || m.getName().equals("")) { - kind = Constants.INVOKESPECIAL; - } else { - kind = Constants.INVOKEVIRTUAL; - } - - return fact.createInvoke( - m.getClassName(), - m.getName(), - m.getReturnType(), - m.getArgumentTypes(), - kind); - } - - /** - * Create an invoke instruction - * - * @param fact - * @param kind INVOKEINTERFACE, INVOKEVIRTUAL.. - * @param member - * @return - */ - public static Instruction createInvoke( - InstructionFactory fact, - short kind, - Member member) { - return fact.createInvoke( - member.getDeclaringType().getName(), - member.getName(), - BcelWorld.makeBcelType(member.getReturnType()), - BcelWorld.makeBcelTypes(member.getParameterTypes()), - kind); - } - - private static String[] argNames = new String[] { "arg0", "arg1", "arg2", "arg3", "arg4" }; - - // ??? these should perhaps be cached. Remember to profile this to see if it's a problem. - public static String[] makeArgNames(int n) { - String[] ret = new String[n]; - for (int i=0; i= Byte.MIN_VALUE) { - inst = new InstructionByte(Constants.BIPUSH,(byte)value); - } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { - inst = new InstructionShort(Constants.SIPUSH,(short)value); + public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) { + int cpoolEntry = (t instanceof ArrayType) ? fact.getConstantPool().addArrayClass((ArrayType) t) : fact.getConstantPool() + .addClass((ObjectType) t); + return new InstructionCP(Constants.INSTANCEOF, cpoolEntry); + } + + public static Instruction createInvoke(InstructionFactory fact, LazyMethodGen m) { + short kind; + if (m.getEnclosingClass().isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (m.isStatic()) { + kind = Constants.INVOKESTATIC; + } else if (m.isPrivate() || m.getName().equals("")) { + kind = Constants.INVOKESPECIAL; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + return fact.createInvoke(m.getClassName(), m.getName(), m.getReturnType(), m.getArgumentTypes(), kind); + } + + /** + * Create an invoke instruction + * + * @param fact + * @param kind INVOKEINTERFACE, INVOKEVIRTUAL.. + * @param member + * @return + */ + public static Instruction createInvoke(InstructionFactory fact, short kind, Member member) { + return fact.createInvoke(member.getDeclaringType().getName(), member.getName(), BcelWorld.makeBcelType(member + .getReturnType()), BcelWorld.makeBcelTypes(member.getParameterTypes()), kind); + } + + private static String[] argNames = new String[] { "arg0", "arg1", "arg2", "arg3", "arg4" }; + + // ??? these should perhaps be cached. Remember to profile this to see if it's a problem. + public static String[] makeArgNames(int n) { + String[] ret = new String[n]; + for (int i = 0; i < n; i++) { + if (i < 5) { + ret[i] = argNames[i]; + } else { + ret[i] = "arg" + i; + } + } + return ret; + } + + // Lookup table, for converting between pairs of types, it gives + // us the method name in the Conversions class + private static Hashtable validBoxing = new Hashtable(); + + static { + validBoxing.put("Ljava/lang/Byte;B", "byteObject"); + validBoxing.put("Ljava/lang/Character;C", "charObject"); + validBoxing.put("Ljava/lang/Double;D", "doubleObject"); + validBoxing.put("Ljava/lang/Float;F", "floatObject"); + validBoxing.put("Ljava/lang/Integer;I", "intObject"); + validBoxing.put("Ljava/lang/Long;J", "longObject"); + validBoxing.put("Ljava/lang/Short;S", "shortObject"); + validBoxing.put("Ljava/lang/Boolean;Z", "booleanObject"); + validBoxing.put("BLjava/lang/Byte;", "byteValue"); + validBoxing.put("CLjava/lang/Character;", "charValue"); + validBoxing.put("DLjava/lang/Double;", "doubleValue"); + validBoxing.put("FLjava/lang/Float;", "floatValue"); + validBoxing.put("ILjava/lang/Integer;", "intValue"); + validBoxing.put("JLjava/lang/Long;", "longValue"); + validBoxing.put("SLjava/lang/Short;", "shortValue"); + validBoxing.put("ZLjava/lang/Boolean;", "booleanValue"); + } + + public static void appendConversion(InstructionList il, InstructionFactory fact, ResolvedType fromType, ResolvedType toType) { + if (!toType.isConvertableFrom(fromType) && !fromType.isConvertableFrom(toType)) { + throw new BCException("can't convert from " + fromType + " to " + toType); + } + // XXX I'm sure this test can be simpler but my brain hurts and this works + if (!toType.getWorld().isInJava5Mode()) { + if (toType.needsNoConversionFrom(fromType)) + return; + } else { + if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitiveType() ^ fromType.isPrimitiveType())) + return; + } + if (toType.equals(ResolvedType.VOID)) { + // assert fromType.equals(UnresolvedType.OBJECT) + il.append(InstructionFactory.createPop(fromType.getSize())); + } else if (fromType.equals(ResolvedType.VOID)) { + // assert toType.equals(UnresolvedType.OBJECT) + il.append(InstructionFactory.createNull(Type.OBJECT)); + return; + } else if (fromType.equals(UnresolvedType.OBJECT)) { + Type to = BcelWorld.makeBcelType(toType); + if (toType.isPrimitiveType()) { + String name = toType.toString() + "Value"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + } else { + il.append(fact.createCheckCast((ReferenceType) to)); + } + } else if (toType.equals(UnresolvedType.OBJECT)) { + // assert fromType.isPrimitive() + Type from = BcelWorld.makeBcelType(fromType); + String name = fromType.toString() + "Object"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from }, + Constants.INVOKESTATIC)); + } else if (toType.getWorld().isInJava5Mode() && validBoxing.get(toType.getSignature() + fromType.getSignature()) != null) { + // XXX could optimize by using any java boxing code that may be just before the call... + Type from = BcelWorld.makeBcelType(fromType); + Type to = BcelWorld.makeBcelType(toType); + String name = (String) validBoxing.get(toType.getSignature() + fromType.getSignature()); + if (toType.isPrimitiveType()) { + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + } else { + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from }, + Constants.INVOKESTATIC)); + il.append(fact.createCheckCast((ReferenceType) to)); + } + } else if (fromType.isPrimitiveType()) { + // assert toType.isPrimitive() + Type from = BcelWorld.makeBcelType(fromType); + Type to = BcelWorld.makeBcelType(toType); + try { + Instruction i = fact.createCast(from, to); + if (i != null) { + il.append(i); } else { - int ii = fact.getClassGen().getConstantPool().addInteger(value); - inst = new InstructionCP(value<=Constants.MAX_BYTE?Constants.LDC:Constants.LDC_W,ii); + il.append(fact.createCast(from, Type.INT)); + il.append(fact.createCast(Type.INT, to)); } - break; + } catch (RuntimeException e) { + il.append(fact.createCast(from, Type.INT)); + il.append(fact.createCast(Type.INT, to)); + } + } else { + Type to = BcelWorld.makeBcelType(toType); + // assert ! fromType.isPrimitive() && ! toType.isPrimitive() + il.append(fact.createCheckCast((ReferenceType) to)); + } + } + + public static InstructionList createConversion(InstructionFactory factory, Type fromType, Type toType) { + return createConversion(factory, fromType, toType, false); + } + + public static InstructionList createConversion(InstructionFactory fact, Type fromType, Type toType, boolean allowAutoboxing) { + // System.out.println("cast to: " + toType); + + InstructionList il = new InstructionList(); + + // PR71273 + if ((fromType.equals(Type.BYTE) || fromType.equals(Type.CHAR) || fromType.equals(Type.SHORT)) && (toType.equals(Type.INT))) { + return il; + } + + if (fromType.equals(toType)) + return il; + if (toType.equals(Type.VOID)) { + il.append(InstructionFactory.createPop(fromType.getSize())); + return il; + } + + if (fromType.equals(Type.VOID)) { + if (toType instanceof BasicType) + throw new BCException("attempting to cast from void to basic type"); + il.append(InstructionFactory.createNull(Type.OBJECT)); + return il; + } + + if (fromType.equals(Type.OBJECT)) { + if (toType instanceof BasicType) { + String name = toType.toString() + "Value"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + return il; + } + } + + if (toType.equals(Type.OBJECT)) { + if (fromType instanceof BasicType) { + String name = fromType.toString() + "Object"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType }, + Constants.INVOKESTATIC)); + return il; + } else if (fromType instanceof ReferenceType) { + return il; + } else { + throw new RuntimeException(); + } + } + + if (fromType instanceof ReferenceType && ((ReferenceType) fromType).isAssignmentCompatibleWith(toType)) { + return il; + } + + if (allowAutoboxing) { + if (toType instanceof BasicType && fromType instanceof ReferenceType) { + // unboxing + String name = toType.toString() + "Value"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + return il; + } + + if (fromType instanceof BasicType && toType instanceof ReferenceType) { + // boxing + String name = fromType.toString() + "Object"; + il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType }, + Constants.INVOKESTATIC)); + il.append(fact.createCast(Type.OBJECT, toType)); + return il; + } + } + + il.append(fact.createCast(fromType, toType)); + return il; + } + + public static Instruction createConstant(InstructionFactory fact, int value) { + Instruction inst; + switch (value) { + case -1: + inst = InstructionConstants.ICONST_M1; + break; + case 0: + inst = InstructionConstants.ICONST_0; + break; + case 1: + inst = InstructionConstants.ICONST_1; + break; + case 2: + inst = InstructionConstants.ICONST_2; + break; + case 3: + inst = InstructionConstants.ICONST_3; + break; + case 4: + inst = InstructionConstants.ICONST_4; + break; + case 5: + inst = InstructionConstants.ICONST_5; + break; + default: + if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { + inst = new InstructionByte(Constants.BIPUSH, (byte) value); + } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { + inst = new InstructionShort(Constants.SIPUSH, (short) value); + } else { + int ii = fact.getClassGen().getConstantPool().addInteger(value); + inst = new InstructionCP(value <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, ii); + } + break; } return inst; } - + /** For testing purposes: bit clunky but does work */ - public static int testingParseCounter=0; + public static int testingParseCounter = 0; public static JavaClass makeJavaClass(String filename, byte[] bytes) { try { testingParseCounter++; - ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename); - return parser.parse(); + ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename); + return parser.parse(); } catch (IOException e) { throw new BCException("malformed class file"); - } - } - - public static String arrayToString(int[] a) { - int len = a.length; - if (len == 0) return "[]"; - StringBuffer buf = new StringBuffer("["); - buf.append(a[0]); - for (int i = 1; i < len; i++) { - buf.append(", "); - buf.append(a[i]); - } - buf.append("]"); - return buf.toString(); - } + } + } + + public static String arrayToString(int[] a) { + int len = a.length; + if (len == 0) + return "[]"; + StringBuffer buf = new StringBuffer("["); + buf.append(a[0]); + for (int i = 1; i < len; i++) { + buf.append(", "); + buf.append(a[i]); + } + buf.append("]"); + return buf.toString(); + } /** * replace an instruction handle with another instruction, in this case, a branch instruction. @@ -561,134 +482,121 @@ public class Utility { * @param branchInstruction the branch instruction to replace ih with * @param enclosingMethod where to find ih's instruction list. */ - public static void replaceInstruction( - InstructionHandle ih, - InstructionList replacementInstructions, - LazyMethodGen enclosingMethod) { - InstructionList il = enclosingMethod.getBody(); - InstructionHandle fresh = il.append(ih, replacementInstructions); - deleteInstruction(ih,fresh,enclosingMethod); - } - - /** delete an instruction handle and retarget all targeters of the deleted instruction - * to the next instruction. Obviously, this should not be used to delete - * a control transfer instruction unless you know what you're doing. + public static void replaceInstruction(InstructionHandle ih, InstructionList replacementInstructions, + LazyMethodGen enclosingMethod) { + InstructionList il = enclosingMethod.getBody(); + InstructionHandle fresh = il.append(ih, replacementInstructions); + deleteInstruction(ih, fresh, enclosingMethod); + } + + /** + * delete an instruction handle and retarget all targeters of the deleted instruction to the next instruction. Obviously, this + * should not be used to delete a control transfer instruction unless you know what you're doing. * * @param ih the instruction handle to delete. * @param enclosingMethod where to find ih's instruction list. */ - public static void deleteInstruction( - InstructionHandle ih, - LazyMethodGen enclosingMethod) - { - deleteInstruction(ih, ih.getNext(), enclosingMethod); - } - - - /** delete an instruction handle and retarget all targeters of the deleted instruction - * to the provided target. + public static void deleteInstruction(InstructionHandle ih, LazyMethodGen enclosingMethod) { + deleteInstruction(ih, ih.getNext(), enclosingMethod); + } + + /** + * delete an instruction handle and retarget all targeters of the deleted instruction to the provided target. * * @param ih the instruction handle to delete * @param retargetTo the instruction handle to retarget targeters of ih to. * @param enclosingMethod where to find ih's instruction list. */ - public static void deleteInstruction( - InstructionHandle ih, - InstructionHandle retargetTo, - LazyMethodGen enclosingMethod) - { - InstructionList il = enclosingMethod.getBody(); - InstructionTargeter[] targeters = ih.getTargetersArray(); - if (targeters != null) { - for (int i = targeters.length - 1; i >= 0; i--) { - InstructionTargeter targeter = targeters[i]; - targeter.updateTarget(ih, retargetTo); - } - ih.removeAllTargeters(); - } - try { - il.delete(ih); - } catch (TargetLostException e) { - throw new BCException("this really can't happen"); - } - } - - /** - * Fix for Bugzilla #39479, #40109 patch contributed by Andy Clement - * - * Need to manually copy Select instructions - if we rely on the the 'fresh' object - * created by copy(), the InstructionHandle array 'targets' inside the Select - * object will not have been deep copied, so modifying targets in fresh will modify - * the original Select - not what we want ! (It is a bug in BCEL to do with cloning - * Select objects). - * - *
-   	 * declare error:
-   	 *     call(* Instruction.copy()) && within(org.aspectj.weaver)
-   	 *       && !withincode(* Utility.copyInstruction(Instruction)):
-   	 *     "use Utility.copyInstruction to work-around bug in Select.copy()";
-   	 * 
- */ + public static void deleteInstruction(InstructionHandle ih, InstructionHandle retargetTo, LazyMethodGen enclosingMethod) { + InstructionList il = enclosingMethod.getBody(); + InstructionTargeter[] targeters = ih.getTargetersArray(); + if (targeters != null) { + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter targeter = targeters[i]; + targeter.updateTarget(ih, retargetTo); + } + ih.removeAllTargeters(); + } + try { + il.delete(ih); + } catch (TargetLostException e) { + throw new BCException("this really can't happen"); + } + } + + /** + * Fix for Bugzilla #39479, #40109 patch contributed by Andy Clement + * + * Need to manually copy Select instructions - if we rely on the the 'fresh' object created by copy(), the InstructionHandle + * array 'targets' inside the Select object will not have been deep copied, so modifying targets in fresh will modify the + * original Select - not what we want ! (It is a bug in BCEL to do with cloning Select objects). + * + *
+	 * declare error:
+	 *     call(* Instruction.copy()) && within(org.aspectj.weaver)
+	 *       && !withincode(* Utility.copyInstruction(Instruction)):
+	 *     "use Utility.copyInstruction to work-around bug in Select.copy()";
+	 * 
+ */ public static Instruction copyInstruction(Instruction i) { if (i instanceof InstructionSelect) { - InstructionSelect freshSelect = (InstructionSelect)i; - + InstructionSelect freshSelect = (InstructionSelect) i; + // Create a new targets array that looks just like the existing one InstructionHandle[] targets = new InstructionHandle[freshSelect.getTargets().length]; for (int ii = 0; ii < targets.length; ii++) { - targets[ii] = freshSelect.getTargets()[ii]; + targets[ii] = freshSelect.getTargets()[ii]; } - + // Create a new select statement with the new targets array - - return new SwitchBuilder(freshSelect.getMatchs(), targets, freshSelect.getTarget()).getInstruction(); + + return new SwitchBuilder(freshSelect.getMatchs(), targets, freshSelect.getTarget()).getInstruction(); } else { return i.copy(); // Use clone for shallow copy... } } - /** returns -1 if no source line attribute */ // this naive version overruns the JVM stack size, if only Java understood tail recursion... -// public static int getSourceLine(InstructionHandle ih) { -// if (ih == null) return -1; -// -// InstructionTargeter[] ts = ih.getTargeters(); -// if (ts != null) { -// for (int j = ts.length - 1; j >= 0; j--) { -// InstructionTargeter t = ts[j]; -// if (t instanceof LineNumberTag) { -// return ((LineNumberTag)t).getLineNumber(); -// } -// } -// } -// return getSourceLine(ih.getNext()); -// } - - public static int getSourceLine(InstructionHandle ih) {//,boolean goforwards) { - int lookahead=0; + // public static int getSourceLine(InstructionHandle ih) { + // if (ih == null) return -1; + // + // InstructionTargeter[] ts = ih.getTargeters(); + // if (ts != null) { + // for (int j = ts.length - 1; j >= 0; j--) { + // InstructionTargeter t = ts[j]; + // if (t instanceof LineNumberTag) { + // return ((LineNumberTag)t).getLineNumber(); + // } + // } + // } + // return getSourceLine(ih.getNext()); + // } + public static int getSourceLine(InstructionHandle ih) {// ,boolean goforwards) { + int lookahead = 0; // arbitrary rule that we will never lookahead more than 100 instructions for a line # while (lookahead++ < 100) { - if (ih == null) return -1; + if (ih == null) + return -1; Iterator tIter = ih.getTargeters().iterator(); while (tIter.hasNext()) { - InstructionTargeter t = (InstructionTargeter)tIter.next(); - if (t instanceof LineNumberTag) { - return ((LineNumberTag)t).getLineNumber(); - } - } -// if (goforwards) ih=ih.getNext(); else - ih=ih.getPrev(); - } - //System.err.println("no line information available for: " + ih); - return -1; - } - -// public static int getSourceLine(InstructionHandle ih) { -// return getSourceLine(ih,false); -// } - - // assumes that there is no already extant source line tag. Otherwise we'll have to be better. + InstructionTargeter t = (InstructionTargeter) tIter.next(); + if (t instanceof LineNumberTag) { + return ((LineNumberTag) t).getLineNumber(); + } + } + // if (goforwards) ih=ih.getNext(); else + ih = ih.getPrev(); + } + // System.err.println("no line information available for: " + ih); + return -1; + } + + // public static int getSourceLine(InstructionHandle ih) { + // return getSourceLine(ih,false); + // } + + // assumes that there is no already extant source line tag. Otherwise we'll have to be better. public static void setSourceLine(InstructionHandle ih, int lineNumber) { // OPTIMIZE LineNumberTag instances for the same line could be shared throughout a method... ih.addTargeter(new LineNumberTag(lineNumber)); @@ -697,15 +605,9 @@ public class Utility { public static int makePublic(int i) { return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC; } - public static int makePrivate(int i) { - return i & ~(Modifier.PROTECTED | Modifier.PUBLIC) | Modifier.PRIVATE; - } - public static BcelVar[] pushAndReturnArrayOfVars( - ResolvedType[] proceedParamTypes, - InstructionList il, - InstructionFactory fact, - LazyMethodGen enclosingMethod) - { + + public static BcelVar[] pushAndReturnArrayOfVars(ResolvedType[] proceedParamTypes, InstructionList il, InstructionFactory fact, + LazyMethodGen enclosingMethod) { int len = proceedParamTypes.length; BcelVar[] ret = new BcelVar[len]; @@ -713,126 +615,129 @@ public class Utility { ResolvedType typeX = proceedParamTypes[i]; Type type = BcelWorld.makeBcelType(typeX); int local = enclosingMethod.allocateLocal(type); - + il.append(InstructionFactory.createStore(type, local)); ret[i] = new BcelVar(typeX, local); - } + } return ret; } public static boolean isConstantPushInstruction(Instruction i) { - long ii= Constants.instFlags[i.opcode]; - return ((ii&Constants.PUSH_INST)!=0 && (ii&Constants.CONSTANT_INST)!=0); + long ii = Constants.instFlags[i.opcode]; + return ((ii & Constants.PUSH_INST) != 0 && (ii & Constants.CONSTANT_INST) != 0); } - + /** * Checks for suppression specified on the member or on the declaring type of that member */ - public static boolean isSuppressing(Member member,String lintkey) { + public static boolean isSuppressing(Member member, String lintkey) { boolean isSuppressing = Utility.isSuppressing(member.getAnnotations(), lintkey); - if (isSuppressing) return true; + if (isSuppressing) + return true; UnresolvedType type = member.getDeclaringType(); if (type instanceof ResolvedType) { - return Utility.isSuppressing(((ResolvedType)type).getAnnotations(),lintkey); + return Utility.isSuppressing(((ResolvedType) type).getAnnotations(), lintkey); } return false; } /** - * Check if the annotations contain a SuppressAjWarnings annotation and - * if that annotation specifies that the given lint message (identified - * by its key) should be ignored. - * - */ - public static boolean isSuppressing(AnnotationX[] anns,String lintkey) { - if (anns == null) return false; - boolean suppressed = false; - // Go through the annotation types on the advice - for (int i = 0;!suppressed && i10) return false; -// InstructionList instrucs = new InstructionList(method.getCode().getCode()); // expensive! -// InstructionHandle InstrHandle = instrucs.getStart(); -// while (InstrHandle != null) { -// Instruction Instr = InstrHandle.getInstruction(); -// int opCode = Instr.opcode; -// // if current instruction is a branch instruction, see if it's a backward branch. -// // if it is return immediately (can't be trivial) -// if (Instr instanceof InstructionBranch) { -// // InstructionBranch BI = (InstructionBranch) Instr; -// if (Instr.getIndex() < 0) return false; -// } else if (Instr instanceof InvokeInstruction) { -// // if current instruction is an invocation, indicate that it can't be trivial -// return false; -// } -// InstrHandle = InstrHandle.getNext(); -// } -// return true; -// } + } + } + return suppressedWarnings; + } + + // not yet used... + // public static boolean isSimple(Method method) { + // if (method.getCode()==null) return true; + // if (method.getCode().getCode().length>10) return false; + // InstructionList instrucs = new InstructionList(method.getCode().getCode()); // expensive! + // InstructionHandle InstrHandle = instrucs.getStart(); + // while (InstrHandle != null) { + // Instruction Instr = InstrHandle.getInstruction(); + // int opCode = Instr.opcode; + // // if current instruction is a branch instruction, see if it's a backward branch. + // // if it is return immediately (can't be trivial) + // if (Instr instanceof InstructionBranch) { + // // InstructionBranch BI = (InstructionBranch) Instr; + // if (Instr.getIndex() < 0) return false; + // } else if (Instr instanceof InvokeInstruction) { + // // if current instruction is an invocation, indicate that it can't be trivial + // return false; + // } + // InstrHandle = InstrHandle.getNext(); + // } + // return true; + // } public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) { int nameIndex = pool.addUtf8(a.getNameString()); byte[] bytes = a.getBytes(); int length = bytes.length; - + return new Unknown(nameIndex, length, bytes, pool); } } \ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java b/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java index 201b8a534..73693f07c 100644 --- a/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java +++ b/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java @@ -10,7 +10,6 @@ * PARC initial implementation * ******************************************************************/ - package org.aspectj.weaver.patterns; import org.aspectj.weaver.IHasPosition; @@ -18,37 +17,31 @@ import org.aspectj.weaver.UnresolvedType; public class FormalBinding implements IHasPosition { private final UnresolvedType type; - private final String name; + private final String name; private final int index; private final int start, end; - private final String fileName; - - public FormalBinding(UnresolvedType type, String name, int index, int start, int end, String fileName) { + + public FormalBinding(UnresolvedType type, String name, int index, int start, int end) { this.type = type; - this.name = name; + this.name = name; this.index = index; this.start = start; this.end = end; - this.fileName = fileName; } - - public FormalBinding(UnresolvedType type, int index) { - this(type, "unknown", index, 0, 0, "unknown"); - } - - public FormalBinding(UnresolvedType type, String name, int index) { - this(type, name, index, 0, 0, "unknown"); - } - - // ---- - + + public FormalBinding(UnresolvedType type, int index) { + this(type, "unknown", index, 0, 0); + } + + public FormalBinding(UnresolvedType type, String name, int index) { + this(type, name, index, 0, 0); + } + + // ---- + public String toString() { return type.toString() + ":" + index; } - - public String getFileName() { - return fileName; - } public int getEnd() { return end; @@ -58,32 +51,32 @@ public class FormalBinding implements IHasPosition { return start; } - public int getIndex() { - return index; - } - - public String getName() { - return name; - } - - public UnresolvedType getType() { - return type; - } - - // ---- - - public static final FormalBinding[] NONE = new FormalBinding[0]; - - /** - * A marker class for bindings for which we want to ignore unbound issue and consider - * them as implicit binding - f.e. to handle JoinPoint in @AJ advices - * - * @author Alexandre Vasseur - */ - public static class ImplicitFormalBinding extends FormalBinding { - public ImplicitFormalBinding(UnresolvedType type, String name, int index) { - super(type, name, index); - } - } + public int getIndex() { + return index; + } + + public String getName() { + return name; + } + + public UnresolvedType getType() { + return type; + } + + // ---- + + public static final FormalBinding[] NONE = new FormalBinding[0]; + + /** + * A marker class for bindings for which we want to ignore unbound issue and consider them as implicit binding - f.e. to handle + * JoinPoint in @AJ advices + * + * @author Alexandre Vasseur + */ + public static class ImplicitFormalBinding extends FormalBinding { + public ImplicitFormalBinding(UnresolvedType type, String name, int index) { + super(type, name, index); + } + } } diff --git a/weaver/testsrc/org/aspectj/weaver/TestUtils.java b/weaver/testsrc/org/aspectj/weaver/TestUtils.java index ca3bb4e6c..9be8f50bb 100644 --- a/weaver/testsrc/org/aspectj/weaver/TestUtils.java +++ b/weaver/testsrc/org/aspectj/weaver/TestUtils.java @@ -20,326 +20,330 @@ import org.aspectj.weaver.patterns.FormalBinding; import org.aspectj.weaver.patterns.Pointcut; import org.aspectj.weaver.patterns.SimpleScope; - public class TestUtils { - private static final String[] ZERO_STRINGS = new String[0]; + private static final String[] ZERO_STRINGS = new String[0]; + + // For stringifying a delegate - extracted from AbstractReferenceTypeDelegate, not fixed up + // /** + // * Create the string representation for a delegate, allowing us to + // * more easily compare delegate implementations. + // */ + // public String stringifyDelegate() { + // + // StringBuffer result = new StringBuffer(); + // result.append("=== Delegate for "+getResolvedTypeX().getName()+"\n"); + // + // result.append("isAspect?"+isAspect()+"\n"); + // result.append("isAnnotationStyleAspect?"+isAnnotationStyleAspect()+"\n"); + // result.append("isInterface?"+isInterface()+"\n"); + // result.append("isEnum?"+isEnum()+"\n"); + // result.append("isClass?"+isClass()+"\n"); + // result.append("-\n"); + // result.append("isAnnotation?"+isAnnotation()+"\n"); + // result.append("retentionPolicy="+getRetentionPolicy()+"\n"); + // result.append("canAnnotationTargetType?"+canAnnotationTargetType()+"\n"); + // AnnotationTargetKind[] kinds = getAnnotationTargetKinds(); + // if (kinds!=null && kinds.length>0) { + // result.append("annotationTargetKinds:["); + // for (int i = 0; i < kinds.length; i++) { + // AnnotationTargetKind kind = kinds[i]; + // result.append(kind); + // if ((i+1)0) { + // result.append("getAnnotations() returns: "+axs.length+" annotations\n"); + // for (int i = 0; i < axs.length; i++) { + // AnnotationX annotationX = axs[i]; + // result.append(" #"+i+") "+annotationX+"\n"); + // } + // } else { + // result.append("getAnnotations() returns nothing\n"); + // } + // ResolvedType[] axtypes = getAnnotationTypes(); + // if (axtypes!=null && axtypes.length>0) { + // result.append("getAnnotationTypes() returns: "+axtypes.length+" annotations\n"); + // for (int i = 0; i < axtypes.length; i++) { + // ResolvedType annotation = axtypes[i]; + // result.append(" #"+i+") "+annotation+":"+annotation.getClass()+"\n"); + // } + // } else { + // result.append("getAnnotationTypes() returns nothing\n"); + // } + // + // result.append("isExposedToWeaver?"+isExposedToWeaver()+"\n"); + // result.append("getSuperclass?"+getSuperclass()+"\n"); + // result.append("getResolvedTypeX?"+getResolvedTypeX()+"\n"); + // result.append("--\n"); + // + // ResolvedMember[] fields = getDeclaredFields(); + // if (fields!=null && fields.length>0) { + // result.append("The fields: "+fields.length+"\n"); + // for (int i = 0; i < fields.length; i++) { + // ResolvedMember member = fields[i]; + // result.append("f"+i+") "+member.toDebugString()+"\n"); + // } + // } + // ResolvedMember[] methods = getDeclaredMethods(); + // if (methods!=null && methods.length>0) { + // result.append("The methods: "+methods.length+"\n"); + // for (int i = 0; i < methods.length; i++) { + // ResolvedMember member = methods[i]; + // result.append("m"+i+") "+member.toDebugString()+"\n"); + // } + // } + // ResolvedType[] interfaces = getDeclaredInterfaces(); + // if (interfaces!=null && interfaces.length>0) { + // result.append("The interfaces: "+interfaces.length+"\n"); + // for (int i = 0; i < interfaces.length; i++) { + // ResolvedType member = interfaces[i]; + // result.append("i"+i+") "+member+"\n"); + // } + // } + // + // result.append("getModifiers?"+getModifiers()+"\n"); + // + // result.append("perclause="+getPerClause()+"\n"); + // + // result.append("aj:weaverstate="+getWeaverState()+"\n"); + // + // ResolvedMember[] pointcuts = getDeclaredPointcuts(); + // if (pointcuts!=null && pointcuts.length>0) { + // result.append("The pointcuts: "+pointcuts.length+"\n"); + // + // // Sort the damn things + // List sortedSetOfPointcuts = new ArrayList(); + // for (int i = 0; i < pointcuts.length; i++) {sortedSetOfPointcuts.add(pointcuts[i]);} + // Collections.sort(sortedSetOfPointcuts); + // + // int i =0; + // for (Iterator iter = sortedSetOfPointcuts.iterator(); iter.hasNext();) { + // ResolvedMember member = (ResolvedMember) iter.next(); + // result.append("p"+i+") "+member.toDebugString()+"\n"); + // i++; + // } + // } + // + // Collection declares = getDeclares(); + // if (declares.size()>0) { + // result.append("The declares: "+declares.size()+"\n"); + // + // // // Sort the damn things + // // List sortedSetOfPointcuts = new ArrayList(); + // // for (int i = 0; i < pointcuts.length; i++) {sortedSetOfPointcuts.add(pointcuts[i]);} + // // Collections.sort(sortedSetOfPointcuts); + // + // int i=0; + // for (Iterator iter = declares.iterator(); iter.hasNext();) { + // Declare dec = (Declare) iter.next(); + // result.append("d"+i+") "+dec.toString()+"\n"); + // i++; + // } + // } + // + // TypeVariable[] tv = getTypeVariables(); + // if (tv!=null && tv.length>0) { + // result.append("The type variables: "+tv.length+"\n"); + // for (int i = 0; i < tv.length; i++) { + // result.append("tv"+i+") "+tv[i]+"\n"); + // } + // } + // + // Collection tmungers = getTypeMungers(); + // if (tmungers.size()>0) { + // List sorted = new ArrayList(); + // sorted.addAll(tmungers); + // Collections.sort(sorted,new Comparator() { + // public int compare(Object arg0, Object arg1) { + // return arg0.toString().compareTo(arg1.toString()); + // } + // }); + // result.append("The type mungers: "+tmungers.size()+"\n"); + // int i=0; + // for (Iterator iter = sorted.iterator(); iter.hasNext();) { + // ConcreteTypeMunger mun = (ConcreteTypeMunger) iter.next(); + // result.append("tm"+i+") "+mun.toString()+"\n"); + // i++; + // } + // } + // + // result.append("doesNotExposeShadowMungers?"+doesNotExposeShadowMungers()+"\n"); + // + // Collection pas = getPrivilegedAccesses(); + // if (pas!=null && pas.size()>0) { + // // List sorted = new ArrayList(); + // // sorted.addAll(tmungers); + // // Collections.sort(sorted,new Comparator() { + // // public int compare(Object arg0, Object arg1) { + // // return arg0.toString().compareTo(arg1.toString()); + // // } + // // }); + // result.append("The privileged accesses: "+pas.size()+"\n"); + // int i=0; + // for (Iterator iter = pas.iterator(); iter.hasNext();) { + // ResolvedMember mun = (ResolvedMember) iter.next(); + // result.append("tm"+i+") "+mun.toDebugString()+"\n"); + // i++; + // } + // } + // + // // public Collection getPrivilegedAccesses(); + // // public boolean hasAnnotation(UnresolvedType ofType); + // result.append("==="); + // return result.toString(); + // } + + /** + * Build a member from a string representation:
+ * + *
+	 * static? TypeName TypeName.Id
+	 * 
+ * + *
+ */ + public static MemberImpl fieldFromString(String str) { + str = str.trim(); + final int len = str.length(); + int i = 0; + int mods = 0; + if (str.startsWith("static", i)) { + mods = Modifier.STATIC; + i += 6; + while (Character.isWhitespace(str.charAt(i))) + i++; + } + int start = i; + while (!Character.isWhitespace(str.charAt(i))) + i++; + UnresolvedType retTy = UnresolvedType.forName(str.substring(start, i)); + + start = i; + i = str.lastIndexOf('.'); + UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); + start = ++i; + String name = str.substring(start, len).trim(); + return new MemberImpl(Member.FIELD, declaringTy, mods, retTy, name, UnresolvedType.NONE); + } + + /** + * Build a member from a string representation:
+ * + *
+	 * (static|interface|private)? TypeName TypeName . Id ( TypeName , ...)
+	 * 
+ * + *
+ */ + + public static Member methodFromString(String str) { + str = str.trim(); + // final int len = str.length(); + int i = 0; + + int mods = 0; + if (str.startsWith("static", i)) { + mods = Modifier.STATIC; + i += 6; + } else if (str.startsWith("interface", i)) { + mods = Modifier.INTERFACE; + i += 9; + } else if (str.startsWith("private", i)) { + mods = Modifier.PRIVATE; + i += 7; + } + while (Character.isWhitespace(str.charAt(i))) + i++; - // For stringifying a delegate - extracted from AbstractReferenceTypeDelegate, not fixed up -// /** -// * Create the string representation for a delegate, allowing us to -// * more easily compare delegate implementations. -// */ -// public String stringifyDelegate() { -// -// StringBuffer result = new StringBuffer(); -// result.append("=== Delegate for "+getResolvedTypeX().getName()+"\n"); -// -// result.append("isAspect?"+isAspect()+"\n"); -// result.append("isAnnotationStyleAspect?"+isAnnotationStyleAspect()+"\n"); -// result.append("isInterface?"+isInterface()+"\n"); -// result.append("isEnum?"+isEnum()+"\n"); -// result.append("isClass?"+isClass()+"\n"); -// result.append("-\n"); -// result.append("isAnnotation?"+isAnnotation()+"\n"); -// result.append("retentionPolicy="+getRetentionPolicy()+"\n"); -// result.append("canAnnotationTargetType?"+canAnnotationTargetType()+"\n"); -// AnnotationTargetKind[] kinds = getAnnotationTargetKinds(); -// if (kinds!=null && kinds.length>0) { -// result.append("annotationTargetKinds:["); -// for (int i = 0; i < kinds.length; i++) { -// AnnotationTargetKind kind = kinds[i]; -// result.append(kind); -// if ((i+1)0) { -// result.append("getAnnotations() returns: "+axs.length+" annotations\n"); -// for (int i = 0; i < axs.length; i++) { -// AnnotationX annotationX = axs[i]; -// result.append(" #"+i+") "+annotationX+"\n"); -// } -// } else { -// result.append("getAnnotations() returns nothing\n"); -// } -// ResolvedType[] axtypes = getAnnotationTypes(); -// if (axtypes!=null && axtypes.length>0) { -// result.append("getAnnotationTypes() returns: "+axtypes.length+" annotations\n"); -// for (int i = 0; i < axtypes.length; i++) { -// ResolvedType annotation = axtypes[i]; -// result.append(" #"+i+") "+annotation+":"+annotation.getClass()+"\n"); -// } -// } else { -// result.append("getAnnotationTypes() returns nothing\n"); -// } -// -// result.append("isExposedToWeaver?"+isExposedToWeaver()+"\n"); -// result.append("getSuperclass?"+getSuperclass()+"\n"); -// result.append("getResolvedTypeX?"+getResolvedTypeX()+"\n"); -// result.append("--\n"); -// -// ResolvedMember[] fields = getDeclaredFields(); -// if (fields!=null && fields.length>0) { -// result.append("The fields: "+fields.length+"\n"); -// for (int i = 0; i < fields.length; i++) { -// ResolvedMember member = fields[i]; -// result.append("f"+i+") "+member.toDebugString()+"\n"); -// } -// } -// ResolvedMember[] methods = getDeclaredMethods(); -// if (methods!=null && methods.length>0) { -// result.append("The methods: "+methods.length+"\n"); -// for (int i = 0; i < methods.length; i++) { -// ResolvedMember member = methods[i]; -// result.append("m"+i+") "+member.toDebugString()+"\n"); -// } -// } -// ResolvedType[] interfaces = getDeclaredInterfaces(); -// if (interfaces!=null && interfaces.length>0) { -// result.append("The interfaces: "+interfaces.length+"\n"); -// for (int i = 0; i < interfaces.length; i++) { -// ResolvedType member = interfaces[i]; -// result.append("i"+i+") "+member+"\n"); -// } -// } -// -// result.append("getModifiers?"+getModifiers()+"\n"); -// -// result.append("perclause="+getPerClause()+"\n"); -// -// result.append("aj:weaverstate="+getWeaverState()+"\n"); -// -// ResolvedMember[] pointcuts = getDeclaredPointcuts(); -// if (pointcuts!=null && pointcuts.length>0) { -// result.append("The pointcuts: "+pointcuts.length+"\n"); -// -// // Sort the damn things -// List sortedSetOfPointcuts = new ArrayList(); -// for (int i = 0; i < pointcuts.length; i++) {sortedSetOfPointcuts.add(pointcuts[i]);} -// Collections.sort(sortedSetOfPointcuts); -// -// int i =0; -// for (Iterator iter = sortedSetOfPointcuts.iterator(); iter.hasNext();) { -// ResolvedMember member = (ResolvedMember) iter.next(); -// result.append("p"+i+") "+member.toDebugString()+"\n"); -// i++; -// } -// } -// -// Collection declares = getDeclares(); -// if (declares.size()>0) { -// result.append("The declares: "+declares.size()+"\n"); -// -//// // Sort the damn things -//// List sortedSetOfPointcuts = new ArrayList(); -//// for (int i = 0; i < pointcuts.length; i++) {sortedSetOfPointcuts.add(pointcuts[i]);} -//// Collections.sort(sortedSetOfPointcuts); -// -// int i=0; -// for (Iterator iter = declares.iterator(); iter.hasNext();) { -// Declare dec = (Declare) iter.next(); -// result.append("d"+i+") "+dec.toString()+"\n"); -// i++; -// } -// } -// -// TypeVariable[] tv = getTypeVariables(); -// if (tv!=null && tv.length>0) { -// result.append("The type variables: "+tv.length+"\n"); -// for (int i = 0; i < tv.length; i++) { -// result.append("tv"+i+") "+tv[i]+"\n"); -// } -// } -// -// Collection tmungers = getTypeMungers(); -// if (tmungers.size()>0) { -// List sorted = new ArrayList(); -// sorted.addAll(tmungers); -// Collections.sort(sorted,new Comparator() { -// public int compare(Object arg0, Object arg1) { -// return arg0.toString().compareTo(arg1.toString()); -// } -// }); -// result.append("The type mungers: "+tmungers.size()+"\n"); -// int i=0; -// for (Iterator iter = sorted.iterator(); iter.hasNext();) { -// ConcreteTypeMunger mun = (ConcreteTypeMunger) iter.next(); -// result.append("tm"+i+") "+mun.toString()+"\n"); -// i++; -// } -// } -// -// result.append("doesNotExposeShadowMungers?"+doesNotExposeShadowMungers()+"\n"); -// -// Collection pas = getPrivilegedAccesses(); -// if (pas!=null && pas.size()>0) { -//// List sorted = new ArrayList(); -//// sorted.addAll(tmungers); -//// Collections.sort(sorted,new Comparator() { -//// public int compare(Object arg0, Object arg1) { -//// return arg0.toString().compareTo(arg1.toString()); -//// } -//// }); -// result.append("The privileged accesses: "+pas.size()+"\n"); -// int i=0; -// for (Iterator iter = pas.iterator(); iter.hasNext();) { -// ResolvedMember mun = (ResolvedMember) iter.next(); -// result.append("tm"+i+") "+mun.toDebugString()+"\n"); -// i++; -// } -// } -// -//// public Collection getPrivilegedAccesses(); -//// public boolean hasAnnotation(UnresolvedType ofType); -// result.append("==="); -// return result.toString(); -// } - - /** - * Build a member from a string representation: - *
-     * static? TypeName TypeName.Id
-     * 
- */ - public static MemberImpl fieldFromString(String str) { - str = str.trim(); - final int len = str.length(); - int i = 0; - int mods = 0; - if (str.startsWith("static", i)) { - mods = Modifier.STATIC; - i += 6; - while (Character.isWhitespace(str.charAt(i))) i++; - } - int start = i; - while (! Character.isWhitespace(str.charAt(i))) i++; - UnresolvedType retTy = UnresolvedType.forName(str.substring(start, i)); + int start = i; + while (!Character.isWhitespace(str.charAt(i))) + i++; + UnresolvedType returnTy = UnresolvedType.forName(str.substring(start, i)); - start = i; - i = str.lastIndexOf('.'); - UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); - start = ++i; - String name = str.substring(start, len).trim(); - return new MemberImpl( - Member.FIELD, - declaringTy, - mods, - retTy, - name, - UnresolvedType.NONE); - } + start = i; + i = str.indexOf('(', i); + i = str.lastIndexOf('.', i); + UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); - /** - * Build a member from a string representation: - *
-     * (static|interface|private)? TypeName TypeName . Id ( TypeName , ...)
-     * 
- */ - - public static Member methodFromString(String str) { - str = str.trim(); - // final int len = str.length(); - int i = 0; + start = ++i; + i = str.indexOf('(', i); + String name = str.substring(start, i).trim(); + start = ++i; + i = str.indexOf(')', i); - int mods = 0; - if (str.startsWith("static", i)) { - mods = Modifier.STATIC; - i += 6; - } else if (str.startsWith("interface", i)) { - mods = Modifier.INTERFACE; - i += 9; - } else if (str.startsWith("private", i)) { - mods = Modifier.PRIVATE; - i += 7; - } - while (Character.isWhitespace(str.charAt(i))) i++; - - int start = i; - while (! Character.isWhitespace(str.charAt(i))) i++; - UnresolvedType returnTy = UnresolvedType.forName(str.substring(start, i)); + String[] paramTypeNames = parseIds(str.substring(start, i).trim()); - start = i; - i = str.indexOf('(', i); - i = str.lastIndexOf('.', i); - UnresolvedType declaringTy = UnresolvedType.forName(str.substring(start, i).trim()); - - start = ++i; - i = str.indexOf('(', i); - String name = str.substring(start, i).trim(); - start = ++i; - i = str.indexOf(')', i); - - String[] paramTypeNames = parseIds(str.substring(start, i).trim()); + return MemberImpl.method(declaringTy, mods, returnTy, name, UnresolvedType.forNames(paramTypeNames)); + } - return MemberImpl.method(declaringTy, mods, returnTy, name, UnresolvedType.forNames(paramTypeNames)); - } + private static String[] parseIds(String str) { + if (str.length() == 0) + return ZERO_STRINGS; + List l = new ArrayList(); + int start = 0; + while (true) { + int i = str.indexOf(',', start); + if (i == -1) { + l.add(str.substring(start).trim()); + break; + } + l.add(str.substring(start, i).trim()); + start = i + 1; + } + return (String[]) l.toArray(new String[l.size()]); + } - private static String[] parseIds(String str) { - if (str.length() == 0) return ZERO_STRINGS; - List l = new ArrayList(); - int start = 0; - while (true) { - int i = str.indexOf(',', start); - if (i == -1) { - l.add(str.substring(start).trim()); - break; - } - l.add(str.substring(start, i).trim()); - start = i+1; - } - return (String[]) l.toArray(new String[l.size()]); - } + /** + * Moved from BcelWorld to here + * + * Parse a string into advice. + * + *
+ * + *
+	 * Kind ( Id , ... ) : Pointcut -> MethodSignature
+	 * 
+ * + *
+ */ + public static Advice shadowMunger(World w, String str, int extraFlag) { + str = str.trim(); + int start = 0; + int i = str.indexOf('('); + AdviceKind kind = AdviceKind.stringToKind(str.substring(start, i)); + start = ++i; + i = str.indexOf(')', i); + String[] ids = parseIds(str.substring(start, i).trim()); + // start = ++i; - /** - * Moved from BcelWorld to here - * - * Parse a string into advice. - * - *
-     * Kind ( Id , ... ) : Pointcut -> MethodSignature
-     * 
- */ - public static Advice shadowMunger(World w,String str, int extraFlag) { - str = str.trim(); - int start = 0; - int i = str.indexOf('('); - AdviceKind kind = - AdviceKind.stringToKind(str.substring(start, i)); - start = ++i; - i = str.indexOf(')', i); - String[] ids = parseIds(str.substring(start, i).trim()); - //start = ++i; - - - - i = str.indexOf(':', i); - start = ++i; - i = str.indexOf("->", i); - Pointcut pointcut = Pointcut.fromString(str.substring(start, i).trim()); - Member m = TestUtils.methodFromString(str.substring(i+2, str.length()).trim()); + i = str.indexOf(':', i); + start = ++i; + i = str.indexOf("->", i); + Pointcut pointcut = Pointcut.fromString(str.substring(start, i).trim()); + Member m = TestUtils.methodFromString(str.substring(i + 2, str.length()).trim()); - // now, we resolve - UnresolvedType[] types = m.getParameterTypes(); - FormalBinding[] bindings = new FormalBinding[ids.length]; - for (int j = 0, len = ids.length; j < len; j++) { - bindings[j] = new FormalBinding(types[j], ids[j], j, 0, 0, "fromString"); - } + // now, we resolve + UnresolvedType[] types = m.getParameterTypes(); + FormalBinding[] bindings = new FormalBinding[ids.length]; + for (int j = 0, len = ids.length; j < len; j++) { + bindings[j] = new FormalBinding(types[j], ids[j], j, 0, 0); + } - Pointcut p = - pointcut.resolve(new SimpleScope(w, bindings)); + Pointcut p = pointcut.resolve(new SimpleScope(w, bindings)); - return new BcelAdvice(kind, p, m, extraFlag, 0, 0, null, null); - } + return new BcelAdvice(kind, p, m, extraFlag, 0, 0, null, null); + } } -- 2.39.5