123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * ******************************************************************/
-
- package org.aspectj.weaver.bcel;
-
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Hashtable;
- import java.util.Iterator;
- import java.util.List;
-
- import org.aspectj.apache.bcel.Constants;
- import org.aspectj.apache.bcel.classfile.Attribute;
- 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.Unknown;
- import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
- import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
- import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
- import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
- import org.aspectj.apache.bcel.generic.ArrayType;
- import org.aspectj.apache.bcel.generic.BasicType;
- import org.aspectj.apache.bcel.generic.Instruction;
- import org.aspectj.apache.bcel.generic.InstructionByte;
- import org.aspectj.apache.bcel.generic.InstructionCP;
- import org.aspectj.apache.bcel.generic.InstructionConstants;
- import org.aspectj.apache.bcel.generic.InstructionFactory;
- import org.aspectj.apache.bcel.generic.InstructionHandle;
- import org.aspectj.apache.bcel.generic.InstructionList;
- import org.aspectj.apache.bcel.generic.InstructionSelect;
- import org.aspectj.apache.bcel.generic.InstructionShort;
- import org.aspectj.apache.bcel.generic.InstructionTargeter;
- import org.aspectj.apache.bcel.generic.LineNumberTag;
- import org.aspectj.apache.bcel.generic.ObjectType;
- import org.aspectj.apache.bcel.generic.ReferenceType;
- import org.aspectj.apache.bcel.generic.SwitchBuilder;
- import org.aspectj.apache.bcel.generic.TargetLostException;
- import org.aspectj.apache.bcel.generic.Type;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.weaver.AjAttribute;
- import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
- import org.aspectj.weaver.AnnotationAJ;
- import org.aspectj.weaver.BCException;
- import org.aspectj.weaver.ConstantPoolReader;
- import org.aspectj.weaver.ISourceContext;
- import org.aspectj.weaver.Lint;
- import org.aspectj.weaver.Member;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.Utils;
- import org.aspectj.weaver.World;
-
- public class Utility {
-
- private final static char PACKAGE_INITIAL_CHAR = AjAttribute.AttributePrefix.charAt(0);
-
- public static List<AjAttribute> readAjAttributes(String classname, Attribute[] as, ISourceContext context, World w,
- AjAttribute.WeaverVersionInfo version, ConstantPoolReader dataDecompressor) {
- List<AjAttribute> attributes = new ArrayList<AjAttribute>();
-
- // first pass, look for version
- List<Unknown> forSecondPass = new ArrayList<Unknown>();
- for (int i = as.length - 1; i >= 0; i--) {
- Attribute a = as[i];
- if (a instanceof Unknown) {
- Unknown u = (Unknown) a;
- String name = u.getName();
- if (name.charAt(0) == PACKAGE_INITIAL_CHAR) { // 'o'rg.aspectj
- if (name.startsWith(AjAttribute.AttributePrefix)) {
- if (name.endsWith(WeaverVersionInfo.AttributeName)) {
- version = (AjAttribute.WeaverVersionInfo) AjAttribute.read(version, name, u.getBytes(), context, w,
- dataDecompressor);
- if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) {
- throw new BCException(
- "Unable to continue, this version of AspectJ supports classes built with weaver version "
- + WeaverVersionInfo.toCurrentVersionString() + " but the class " + classname
- + " is version " + version.toString() + ". Please update your AspectJ.");
- }
- }
- forSecondPass.add(u);
- }
- }
- }
- }
-
- // FIXASC why going backwards? is it important
- for (int i = forSecondPass.size() - 1; i >= 0; i--) {
- Unknown a = forSecondPass.get(i);
- String name = a.getName();
- AjAttribute attr = AjAttribute.read(version, name, a.getBytes(), context, w, dataDecompressor);
- if (attr != null) {
- attributes.add(attr);
- }
- }
- return attributes;
- }
-
- /*
- * 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) {
- 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());
- }
- }
- return nice.toString();
- }
-
- public static Instruction createSuperInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
- short kind;
- if (Modifier.isInterface(signature.getModifiers())) {
- throw new RuntimeException("bad");
- } else if (Modifier.isPrivate(signature.getModifiers()) || signature.getName().equals("<init>")) {
- throw new RuntimeException("unimplemented, possibly bad");
- } else if (Modifier.isStatic(signature.getModifiers())) {
- 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);
- }
-
- public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
- short kind;
- int signatureModifiers = signature.getModifiers();
- if (Modifier.isInterface(signatureModifiers)) {
- kind = Constants.INVOKEINTERFACE;
- } else if (Modifier.isStatic(signatureModifiers)) {
- kind = Constants.INVOKESTATIC;
- } else if (Modifier.isPrivate(signatureModifiers) || signature.getName().equals("<init>")) {
- 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 (Modifier.isStatic(signature.getModifiers())) {
- kind = Constants.GETSTATIC;
- } else {
- kind = Constants.GETFIELD;
- }
-
- return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
- BcelWorld.makeBcelType(signature.getReturnType()), kind);
- }
-
- public static Instruction createSet(InstructionFactory fact, Member signature) {
- short kind;
- if (Modifier.isStatic(signature.getModifiers())) {
- kind = Constants.PUTSTATIC;
- } else {
- kind = Constants.PUTFIELD;
- }
-
- return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
- BcelWorld.makeBcelType(signature.getReturnType()), kind);
- }
-
- 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()) {
- if (m.isStatic()) {
- // For static methods on interfaces
- kind = Constants.INVOKESTATIC;
- } else {
- kind = Constants.INVOKEINTERFACE;
- }
- } else if (m.isStatic()) {
- kind = Constants.INVOKESTATIC;
- } else if (m.isPrivate() || m.getName().equals("<init>")) {
- kind = Constants.INVOKESPECIAL;
- } else {
- kind = Constants.INVOKEVIRTUAL;
- }
-
- return fact.createInvoke(m.getClassName(), m.getName(), m.getReturnType(), m.getArgumentTypes(), kind, m.getEnclosingClass().isInterface());
- }
-
- /**
- * 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<String, String> validBoxing = new Hashtable<String, String>();
-
- 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
- World w = toType.getWorld();
- if (w == null) { // dbg349636
- throw new IllegalStateException("Debug349636: Unexpectedly found world null for type " + toType.getName());
- }
-
- if (!w.isInJava5Mode()) {
- if (toType.needsNoConversionFrom(fromType)) {
- return;
- }
- } else {
- if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitiveType() ^ fromType.isPrimitiveType())) {
- return;
- }
- }
- if (toType.equals(UnresolvedType.VOID)) {
- // assert fromType.equals(UnresolvedType.OBJECT)
- il.append(InstructionFactory.createPop(fromType.getSize()));
- } else if (fromType.equals(UnresolvedType.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 = 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 {
- il.append(fact.createCast(from, Type.INT));
- il.append(fact.createCast(Type.INT, to));
- }
- } 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 JavaClass makeJavaClass(String filename, byte[] bytes) {
- try {
- testingParseCounter++;
- ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename);
- return parser.parse();
- } catch (IOException e) {
- throw new BCException("malformed class file");
- }
- }
-
- /**
- * replace an instruction handle with another instruction, in this case, a branch instruction.
- *
- * @param ih the instruction handle to replace.
- * @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.
- *
- * @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.
- *
- * @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();
- for (InstructionTargeter targeter : ih.getTargetersCopy()) {
- 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).
- *
- * <pre>
- * declare error:
- * call(* Instruction.copy()) && within(org.aspectj.weaver)
- * && !withincode(* Utility.copyInstruction(Instruction)):
- * "use Utility.copyInstruction to work-around bug in Select.copy()";
- * </pre>
- */
- public static Instruction copyInstruction(Instruction i) {
- if (i instanceof InstructionSelect) {
- 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];
- }
-
- // Create a new select statement with the new targets array
-
- 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;
- // arbitrary rule that we will never lookahead more than 100
- // instructions for a line #
- while (lookahead++ < 100) {
- if (ih == null) {
- return -1;
- }
- Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator();
- while (tIter.hasNext()) {
- InstructionTargeter t = 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));
- }
-
- public static int makePublic(int i) {
- return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC;
- }
-
- public static BcelVar[] pushAndReturnArrayOfVars(ResolvedType[] proceedParamTypes, InstructionList il, InstructionFactory fact,
- LazyMethodGen enclosingMethod) {
- int len = proceedParamTypes.length;
- BcelVar[] ret = new BcelVar[len];
-
- for (int i = len - 1; i >= 0; i--) {
- 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);
- }
-
- /**
- * Checks for suppression specified on the member or on the declaring type of that member
- */
- public static boolean isSuppressing(Member member, String lintkey) {
- boolean isSuppressing = Utils.isSuppressing(member.getAnnotations(), lintkey);
- if (isSuppressing) {
- return true;
- }
- UnresolvedType type = member.getDeclaringType();
- if (type instanceof ResolvedType) {
- return Utils.isSuppressing(((ResolvedType) type).getAnnotations(), lintkey);
- }
- return false;
- }
-
- public static List<Lint.Kind> getSuppressedWarnings(AnnotationAJ[] anns, Lint lint) {
- if (anns == null) {
- return Collections.emptyList();
- }
- // Go through the annotation types
- List<Lint.Kind> suppressedWarnings = new ArrayList<Lint.Kind>();
- boolean found = false;
- for (int i = 0; !found && i < anns.length; i++) {
- // Check for the SuppressAjWarnings annotation
- if (UnresolvedType.SUPPRESS_AJ_WARNINGS.getSignature().equals(
- ((BcelAnnotation) anns[i]).getBcelAnnotation().getTypeSignature())) {
- found = true;
- // Two possibilities:
- // 1. there are no values specified (i.e. @SuppressAjWarnings)
- // 2. there are values specified (i.e. @SuppressAjWarnings("A")
- // or @SuppressAjWarnings({"A","B"})
- List<NameValuePair> vals = ((BcelAnnotation) anns[i]).getBcelAnnotation().getValues();
- if (vals == null || vals.isEmpty()) { // (1)
- suppressedWarnings.addAll(lint.allKinds());
- } else { // (2)
- // We know the value is an array value
- ArrayElementValue array = (ArrayElementValue) (vals.get(0)).getValue();
- ElementValue[] values = array.getElementValuesArray();
- for (int j = 0; j < values.length; j++) {
- // We know values in the array are strings
- SimpleElementValue value = (SimpleElementValue) values[j];
- Lint.Kind lintKind = lint.getLintKind(value.getValueString());
- if (lintKind != null) {
- suppressedWarnings.add(lintKind);
- }
- }
- }
- }
- }
- 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(new BcelConstantPoolWriter(pool));
- int length = bytes.length;
-
- return new Unknown(nameIndex, length, bytes, pool);
- }
- }
|