You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Utility.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.ByteArrayInputStream;
  14. import java.io.IOException;
  15. import java.lang.reflect.Modifier;
  16. import java.util.ArrayList;
  17. import java.util.Collections;
  18. import java.util.Hashtable;
  19. import java.util.Iterator;
  20. import java.util.List;
  21. import org.aspectj.apache.bcel.Constants;
  22. import org.aspectj.apache.bcel.classfile.Attribute;
  23. import org.aspectj.apache.bcel.classfile.ClassParser;
  24. import org.aspectj.apache.bcel.classfile.ConstantPool;
  25. import org.aspectj.apache.bcel.classfile.JavaClass;
  26. import org.aspectj.apache.bcel.classfile.Unknown;
  27. import org.aspectj.apache.bcel.classfile.annotation.ArrayElementValue;
  28. import org.aspectj.apache.bcel.classfile.annotation.ElementValue;
  29. import org.aspectj.apache.bcel.classfile.annotation.NameValuePair;
  30. import org.aspectj.apache.bcel.classfile.annotation.SimpleElementValue;
  31. import org.aspectj.apache.bcel.generic.ArrayType;
  32. import org.aspectj.apache.bcel.generic.BasicType;
  33. import org.aspectj.apache.bcel.generic.Instruction;
  34. import org.aspectj.apache.bcel.generic.InstructionByte;
  35. import org.aspectj.apache.bcel.generic.InstructionCP;
  36. import org.aspectj.apache.bcel.generic.InstructionConstants;
  37. import org.aspectj.apache.bcel.generic.InstructionFactory;
  38. import org.aspectj.apache.bcel.generic.InstructionHandle;
  39. import org.aspectj.apache.bcel.generic.InstructionList;
  40. import org.aspectj.apache.bcel.generic.InstructionSelect;
  41. import org.aspectj.apache.bcel.generic.InstructionShort;
  42. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  43. import org.aspectj.apache.bcel.generic.LineNumberTag;
  44. import org.aspectj.apache.bcel.generic.ObjectType;
  45. import org.aspectj.apache.bcel.generic.ReferenceType;
  46. import org.aspectj.apache.bcel.generic.SwitchBuilder;
  47. import org.aspectj.apache.bcel.generic.TargetLostException;
  48. import org.aspectj.apache.bcel.generic.Type;
  49. import org.aspectj.bridge.ISourceLocation;
  50. import org.aspectj.weaver.AjAttribute;
  51. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  52. import org.aspectj.weaver.AnnotationAJ;
  53. import org.aspectj.weaver.BCException;
  54. import org.aspectj.weaver.ConstantPoolReader;
  55. import org.aspectj.weaver.ISourceContext;
  56. import org.aspectj.weaver.Lint;
  57. import org.aspectj.weaver.Member;
  58. import org.aspectj.weaver.ResolvedType;
  59. import org.aspectj.weaver.UnresolvedType;
  60. import org.aspectj.weaver.Utils;
  61. import org.aspectj.weaver.World;
  62. public class Utility {
  63. private final static char PACKAGE_INITIAL_CHAR = AjAttribute.AttributePrefix.charAt(0);
  64. public static List<AjAttribute> readAjAttributes(String classname, Attribute[] as, ISourceContext context, World w,
  65. AjAttribute.WeaverVersionInfo version, ConstantPoolReader dataDecompressor) {
  66. List<AjAttribute> attributes = new ArrayList<AjAttribute>();
  67. // first pass, look for version
  68. List<Unknown> forSecondPass = new ArrayList<Unknown>();
  69. for (int i = as.length - 1; i >= 0; i--) {
  70. Attribute a = as[i];
  71. if (a instanceof Unknown) {
  72. Unknown u = (Unknown) a;
  73. String name = u.getName();
  74. if (name.charAt(0) == PACKAGE_INITIAL_CHAR) { // 'o'rg.aspectj
  75. if (name.startsWith(AjAttribute.AttributePrefix)) {
  76. if (name.endsWith(WeaverVersionInfo.AttributeName)) {
  77. version = (AjAttribute.WeaverVersionInfo) AjAttribute.read(version, name, u.getBytes(), context, w,
  78. dataDecompressor);
  79. if (version.getMajorVersion() > WeaverVersionInfo.getCurrentWeaverMajorVersion()) {
  80. throw new BCException(
  81. "Unable to continue, this version of AspectJ supports classes built with weaver version "
  82. + WeaverVersionInfo.toCurrentVersionString() + " but the class " + classname
  83. + " is version " + version.toString() + ". Please update your AspectJ.");
  84. }
  85. }
  86. forSecondPass.add(u);
  87. }
  88. }
  89. }
  90. }
  91. // FIXASC why going backwards? is it important
  92. for (int i = forSecondPass.size() - 1; i >= 0; i--) {
  93. Unknown a = forSecondPass.get(i);
  94. String name = a.getName();
  95. AjAttribute attr = AjAttribute.read(version, name, a.getBytes(), context, w, dataDecompressor);
  96. if (attr != null) {
  97. attributes.add(attr);
  98. }
  99. }
  100. return attributes;
  101. }
  102. /*
  103. * Ensure we report a nice source location - particular in the case where the source info is missing (binary weave).
  104. */
  105. public static String beautifyLocation(ISourceLocation isl) {
  106. StringBuffer nice = new StringBuffer();
  107. if (isl == null || isl.getSourceFile() == null || isl.getSourceFile().getName().indexOf("no debug info available") != -1) {
  108. nice.append("no debug info available");
  109. } else {
  110. // can't use File.getName() as this fails when a Linux box
  111. // encounters a path created on Windows and vice-versa
  112. int takeFrom = isl.getSourceFile().getPath().lastIndexOf('/');
  113. if (takeFrom == -1) {
  114. takeFrom = isl.getSourceFile().getPath().lastIndexOf('\\');
  115. }
  116. nice.append(isl.getSourceFile().getPath().substring(takeFrom + 1));
  117. if (isl.getLine() != 0) {
  118. nice.append(":").append(isl.getLine());
  119. }
  120. }
  121. return nice.toString();
  122. }
  123. public static Instruction createSuperInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
  124. short kind;
  125. if (Modifier.isInterface(signature.getModifiers())) {
  126. throw new RuntimeException("bad");
  127. } else if (Modifier.isPrivate(signature.getModifiers()) || signature.getName().equals("<init>")) {
  128. throw new RuntimeException("unimplemented, possibly bad");
  129. } else if (Modifier.isStatic(signature.getModifiers())) {
  130. throw new RuntimeException("bad");
  131. } else {
  132. kind = Constants.INVOKESPECIAL;
  133. }
  134. return fact.createInvoke(signature.getDeclaringType().getName(), signature.getName(),
  135. BcelWorld.makeBcelType(signature.getReturnType()), BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind);
  136. }
  137. public static Instruction createInvoke(InstructionFactory fact, BcelWorld world, Member signature) {
  138. short kind;
  139. int signatureModifiers = signature.getModifiers();
  140. if (Modifier.isInterface(signatureModifiers)) {
  141. kind = Constants.INVOKEINTERFACE;
  142. } else if (Modifier.isStatic(signatureModifiers)) {
  143. kind = Constants.INVOKESTATIC;
  144. } else if (Modifier.isPrivate(signatureModifiers) || signature.getName().equals("<init>")) {
  145. kind = Constants.INVOKESPECIAL;
  146. } else {
  147. kind = Constants.INVOKEVIRTUAL;
  148. }
  149. UnresolvedType targetType = signature.getDeclaringType();
  150. if (targetType.isParameterizedType()) {
  151. targetType = targetType.resolve(world).getGenericType();
  152. }
  153. return fact.createInvoke(targetType.getName(), signature.getName(), BcelWorld.makeBcelType(signature.getReturnType()),
  154. BcelWorld.makeBcelTypes(signature.getParameterTypes()), kind);
  155. }
  156. public static Instruction createGet(InstructionFactory fact, Member signature) {
  157. short kind;
  158. if (Modifier.isStatic(signature.getModifiers())) {
  159. kind = Constants.GETSTATIC;
  160. } else {
  161. kind = Constants.GETFIELD;
  162. }
  163. return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
  164. BcelWorld.makeBcelType(signature.getReturnType()), kind);
  165. }
  166. public static Instruction createSet(InstructionFactory fact, Member signature) {
  167. short kind;
  168. if (Modifier.isStatic(signature.getModifiers())) {
  169. kind = Constants.PUTSTATIC;
  170. } else {
  171. kind = Constants.PUTFIELD;
  172. }
  173. return fact.createFieldAccess(signature.getDeclaringType().getName(), signature.getName(),
  174. BcelWorld.makeBcelType(signature.getReturnType()), kind);
  175. }
  176. public static Instruction createInstanceof(InstructionFactory fact, ReferenceType t) {
  177. int cpoolEntry = (t instanceof ArrayType) ? fact.getConstantPool().addArrayClass((ArrayType) t) : fact.getConstantPool()
  178. .addClass((ObjectType) t);
  179. return new InstructionCP(Constants.INSTANCEOF, cpoolEntry);
  180. }
  181. public static Instruction createInvoke(InstructionFactory fact, LazyMethodGen m) {
  182. short kind;
  183. if (m.getEnclosingClass().isInterface()) {
  184. if (m.isStatic()) {
  185. // For static methods on interfaces
  186. kind = Constants.INVOKESTATIC;
  187. } else {
  188. kind = Constants.INVOKEINTERFACE;
  189. }
  190. } else if (m.isStatic()) {
  191. kind = Constants.INVOKESTATIC;
  192. } else if (m.isPrivate() || m.getName().equals("<init>")) {
  193. kind = Constants.INVOKESPECIAL;
  194. } else {
  195. kind = Constants.INVOKEVIRTUAL;
  196. }
  197. return fact.createInvoke(m.getClassName(), m.getName(), m.getReturnType(), m.getArgumentTypes(), kind, m.getEnclosingClass().isInterface());
  198. }
  199. /**
  200. * Create an invoke instruction
  201. *
  202. * @param fact
  203. * @param kind INVOKEINTERFACE, INVOKEVIRTUAL..
  204. * @param member
  205. * @return
  206. */
  207. public static Instruction createInvoke(InstructionFactory fact, short kind, Member member) {
  208. return fact.createInvoke(member.getDeclaringType().getName(), member.getName(),
  209. BcelWorld.makeBcelType(member.getReturnType()), BcelWorld.makeBcelTypes(member.getParameterTypes()), kind);
  210. }
  211. private static String[] argNames = new String[] { "arg0", "arg1", "arg2", "arg3", "arg4" };
  212. // ??? these should perhaps be cached. Remember to profile this to see if
  213. // it's a problem.
  214. public static String[] makeArgNames(int n) {
  215. String[] ret = new String[n];
  216. for (int i = 0; i < n; i++) {
  217. if (i < 5) {
  218. ret[i] = argNames[i];
  219. } else {
  220. ret[i] = "arg" + i;
  221. }
  222. }
  223. return ret;
  224. }
  225. // Lookup table, for converting between pairs of types, it gives
  226. // us the method name in the Conversions class
  227. private static Hashtable<String, String> validBoxing = new Hashtable<String, String>();
  228. static {
  229. validBoxing.put("Ljava/lang/Byte;B", "byteObject");
  230. validBoxing.put("Ljava/lang/Character;C", "charObject");
  231. validBoxing.put("Ljava/lang/Double;D", "doubleObject");
  232. validBoxing.put("Ljava/lang/Float;F", "floatObject");
  233. validBoxing.put("Ljava/lang/Integer;I", "intObject");
  234. validBoxing.put("Ljava/lang/Long;J", "longObject");
  235. validBoxing.put("Ljava/lang/Short;S", "shortObject");
  236. validBoxing.put("Ljava/lang/Boolean;Z", "booleanObject");
  237. validBoxing.put("BLjava/lang/Byte;", "byteValue");
  238. validBoxing.put("CLjava/lang/Character;", "charValue");
  239. validBoxing.put("DLjava/lang/Double;", "doubleValue");
  240. validBoxing.put("FLjava/lang/Float;", "floatValue");
  241. validBoxing.put("ILjava/lang/Integer;", "intValue");
  242. validBoxing.put("JLjava/lang/Long;", "longValue");
  243. validBoxing.put("SLjava/lang/Short;", "shortValue");
  244. validBoxing.put("ZLjava/lang/Boolean;", "booleanValue");
  245. }
  246. public static void appendConversion(InstructionList il, InstructionFactory fact, ResolvedType fromType, ResolvedType toType) {
  247. if (!toType.isConvertableFrom(fromType) && !fromType.isConvertableFrom(toType)) {
  248. throw new BCException("can't convert from " + fromType + " to " + toType);
  249. }
  250. // XXX I'm sure this test can be simpler but my brain hurts and this works
  251. World w = toType.getWorld();
  252. if (w == null) { // dbg349636
  253. throw new IllegalStateException("Debug349636: Unexpectedly found world null for type " + toType.getName());
  254. }
  255. if (!w.isInJava5Mode()) {
  256. if (toType.needsNoConversionFrom(fromType)) {
  257. return;
  258. }
  259. } else {
  260. if (toType.needsNoConversionFrom(fromType) && !(toType.isPrimitiveType() ^ fromType.isPrimitiveType())) {
  261. return;
  262. }
  263. }
  264. if (toType.equals(UnresolvedType.VOID)) {
  265. // assert fromType.equals(UnresolvedType.OBJECT)
  266. il.append(InstructionFactory.createPop(fromType.getSize()));
  267. } else if (fromType.equals(UnresolvedType.VOID)) {
  268. // assert toType.equals(UnresolvedType.OBJECT)
  269. il.append(InstructionFactory.createNull(Type.OBJECT));
  270. return;
  271. } else if (fromType.equals(UnresolvedType.OBJECT)) {
  272. Type to = BcelWorld.makeBcelType(toType);
  273. if (toType.isPrimitiveType()) {
  274. String name = toType.toString() + "Value";
  275. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT },
  276. Constants.INVOKESTATIC));
  277. } else {
  278. il.append(fact.createCheckCast((ReferenceType) to));
  279. }
  280. } else if (toType.equals(UnresolvedType.OBJECT)) {
  281. // assert fromType.isPrimitive()
  282. Type from = BcelWorld.makeBcelType(fromType);
  283. String name = fromType.toString() + "Object";
  284. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from },
  285. Constants.INVOKESTATIC));
  286. } else if (toType.getWorld().isInJava5Mode() && validBoxing.get(toType.getSignature() + fromType.getSignature()) != null) {
  287. // XXX could optimize by using any java boxing code that may be just
  288. // before the call...
  289. Type from = BcelWorld.makeBcelType(fromType);
  290. Type to = BcelWorld.makeBcelType(toType);
  291. String name = validBoxing.get(toType.getSignature() + fromType.getSignature());
  292. if (toType.isPrimitiveType()) {
  293. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, to, new Type[] { Type.OBJECT },
  294. Constants.INVOKESTATIC));
  295. } else {
  296. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { from },
  297. Constants.INVOKESTATIC));
  298. il.append(fact.createCheckCast((ReferenceType) to));
  299. }
  300. } else if (fromType.isPrimitiveType()) {
  301. // assert toType.isPrimitive()
  302. Type from = BcelWorld.makeBcelType(fromType);
  303. Type to = BcelWorld.makeBcelType(toType);
  304. try {
  305. Instruction i = fact.createCast(from, to);
  306. if (i != null) {
  307. il.append(i);
  308. } else {
  309. il.append(fact.createCast(from, Type.INT));
  310. il.append(fact.createCast(Type.INT, to));
  311. }
  312. } catch (RuntimeException e) {
  313. il.append(fact.createCast(from, Type.INT));
  314. il.append(fact.createCast(Type.INT, to));
  315. }
  316. } else {
  317. Type to = BcelWorld.makeBcelType(toType);
  318. // assert ! fromType.isPrimitive() && ! toType.isPrimitive()
  319. il.append(fact.createCheckCast((ReferenceType) to));
  320. }
  321. }
  322. public static InstructionList createConversion(InstructionFactory factory, Type fromType, Type toType) {
  323. return createConversion(factory, fromType, toType, false);
  324. }
  325. public static InstructionList createConversion(InstructionFactory fact, Type fromType, Type toType, boolean allowAutoboxing) {
  326. // System.out.println("cast to: " + toType);
  327. InstructionList il = new InstructionList();
  328. // PR71273
  329. if ((fromType.equals(Type.BYTE) || fromType.equals(Type.CHAR) || fromType.equals(Type.SHORT)) && (toType.equals(Type.INT))) {
  330. return il;
  331. }
  332. if (fromType.equals(toType)) {
  333. return il;
  334. }
  335. if (toType.equals(Type.VOID)) {
  336. il.append(InstructionFactory.createPop(fromType.getSize()));
  337. return il;
  338. }
  339. if (fromType.equals(Type.VOID)) {
  340. if (toType instanceof BasicType) {
  341. throw new BCException("attempting to cast from void to basic type");
  342. }
  343. il.append(InstructionFactory.createNull(Type.OBJECT));
  344. return il;
  345. }
  346. if (fromType.equals(Type.OBJECT)) {
  347. if (toType instanceof BasicType) {
  348. String name = toType.toString() + "Value";
  349. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT },
  350. Constants.INVOKESTATIC));
  351. return il;
  352. }
  353. }
  354. if (toType.equals(Type.OBJECT)) {
  355. if (fromType instanceof BasicType) {
  356. String name = fromType.toString() + "Object";
  357. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType },
  358. Constants.INVOKESTATIC));
  359. return il;
  360. } else if (fromType instanceof ReferenceType) {
  361. return il;
  362. } else {
  363. throw new RuntimeException();
  364. }
  365. }
  366. if (fromType instanceof ReferenceType && ((ReferenceType) fromType).isAssignmentCompatibleWith(toType)) {
  367. return il;
  368. }
  369. if (allowAutoboxing) {
  370. if (toType instanceof BasicType && fromType instanceof ReferenceType) {
  371. // unboxing
  372. String name = toType.toString() + "Value";
  373. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, toType, new Type[] { Type.OBJECT },
  374. Constants.INVOKESTATIC));
  375. return il;
  376. }
  377. if (fromType instanceof BasicType && toType instanceof ReferenceType) {
  378. // boxing
  379. String name = fromType.toString() + "Object";
  380. il.append(fact.createInvoke("org.aspectj.runtime.internal.Conversions", name, Type.OBJECT, new Type[] { fromType },
  381. Constants.INVOKESTATIC));
  382. il.append(fact.createCast(Type.OBJECT, toType));
  383. return il;
  384. }
  385. }
  386. il.append(fact.createCast(fromType, toType));
  387. return il;
  388. }
  389. public static Instruction createConstant(InstructionFactory fact, int value) {
  390. Instruction inst;
  391. switch (value) {
  392. case -1:
  393. inst = InstructionConstants.ICONST_M1;
  394. break;
  395. case 0:
  396. inst = InstructionConstants.ICONST_0;
  397. break;
  398. case 1:
  399. inst = InstructionConstants.ICONST_1;
  400. break;
  401. case 2:
  402. inst = InstructionConstants.ICONST_2;
  403. break;
  404. case 3:
  405. inst = InstructionConstants.ICONST_3;
  406. break;
  407. case 4:
  408. inst = InstructionConstants.ICONST_4;
  409. break;
  410. case 5:
  411. inst = InstructionConstants.ICONST_5;
  412. break;
  413. default:
  414. if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
  415. inst = new InstructionByte(Constants.BIPUSH, (byte) value);
  416. } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
  417. inst = new InstructionShort(Constants.SIPUSH, (short) value);
  418. } else {
  419. int ii = fact.getClassGen().getConstantPool().addInteger(value);
  420. inst = new InstructionCP(value <= Constants.MAX_BYTE ? Constants.LDC : Constants.LDC_W, ii);
  421. }
  422. break;
  423. }
  424. return inst;
  425. }
  426. /** For testing purposes: bit clunky but does work */
  427. public static int testingParseCounter = 0;
  428. public static JavaClass makeJavaClass(String filename, byte[] bytes) {
  429. try {
  430. testingParseCounter++;
  431. ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename);
  432. return parser.parse();
  433. } catch (IOException e) {
  434. throw new BCException("malformed class file");
  435. }
  436. }
  437. /**
  438. * replace an instruction handle with another instruction, in this case, a branch instruction.
  439. *
  440. * @param ih the instruction handle to replace.
  441. * @param branchInstruction the branch instruction to replace ih with
  442. * @param enclosingMethod where to find ih's instruction list.
  443. */
  444. public static void replaceInstruction(InstructionHandle ih, InstructionList replacementInstructions,
  445. LazyMethodGen enclosingMethod) {
  446. InstructionList il = enclosingMethod.getBody();
  447. InstructionHandle fresh = il.append(ih, replacementInstructions);
  448. deleteInstruction(ih, fresh, enclosingMethod);
  449. }
  450. /**
  451. * delete an instruction handle and retarget all targeters of the deleted instruction to the next instruction. Obviously, this
  452. * should not be used to delete a control transfer instruction unless you know what you're doing.
  453. *
  454. * @param ih the instruction handle to delete.
  455. * @param enclosingMethod where to find ih's instruction list.
  456. */
  457. public static void deleteInstruction(InstructionHandle ih, LazyMethodGen enclosingMethod) {
  458. deleteInstruction(ih, ih.getNext(), enclosingMethod);
  459. }
  460. /**
  461. * delete an instruction handle and retarget all targeters of the deleted instruction to the provided target.
  462. *
  463. * @param ih the instruction handle to delete
  464. * @param retargetTo the instruction handle to retarget targeters of ih to.
  465. * @param enclosingMethod where to find ih's instruction list.
  466. */
  467. public static void deleteInstruction(InstructionHandle ih, InstructionHandle retargetTo, LazyMethodGen enclosingMethod) {
  468. InstructionList il = enclosingMethod.getBody();
  469. for (InstructionTargeter targeter : ih.getTargetersCopy()) {
  470. targeter.updateTarget(ih, retargetTo);
  471. }
  472. ih.removeAllTargeters();
  473. try {
  474. il.delete(ih);
  475. } catch (TargetLostException e) {
  476. throw new BCException("this really can't happen");
  477. }
  478. }
  479. /**
  480. * Fix for Bugzilla #39479, #40109 patch contributed by Andy Clement
  481. *
  482. * Need to manually copy Select instructions - if we rely on the the 'fresh' object created by copy(), the InstructionHandle
  483. * array 'targets' inside the Select object will not have been deep copied, so modifying targets in fresh will modify the
  484. * original Select - not what we want ! (It is a bug in BCEL to do with cloning Select objects).
  485. *
  486. * <pre>
  487. * declare error:
  488. * call(* Instruction.copy()) &amp;&amp; within(org.aspectj.weaver)
  489. * &amp;&amp; !withincode(* Utility.copyInstruction(Instruction)):
  490. * &quot;use Utility.copyInstruction to work-around bug in Select.copy()&quot;;
  491. * </pre>
  492. */
  493. public static Instruction copyInstruction(Instruction i) {
  494. if (i instanceof InstructionSelect) {
  495. InstructionSelect freshSelect = (InstructionSelect) i;
  496. // Create a new targets array that looks just like the existing one
  497. InstructionHandle[] targets = new InstructionHandle[freshSelect.getTargets().length];
  498. for (int ii = 0; ii < targets.length; ii++) {
  499. targets[ii] = freshSelect.getTargets()[ii];
  500. }
  501. // Create a new select statement with the new targets array
  502. return new SwitchBuilder(freshSelect.getMatchs(), targets, freshSelect.getTarget()).getInstruction();
  503. } else {
  504. return i.copy(); // Use clone for shallow copy...
  505. }
  506. }
  507. /** returns -1 if no source line attribute */
  508. // this naive version overruns the JVM stack size, if only Java understood
  509. // tail recursion...
  510. // public static int getSourceLine(InstructionHandle ih) {
  511. // if (ih == null) return -1;
  512. //
  513. // InstructionTargeter[] ts = ih.getTargeters();
  514. // if (ts != null) {
  515. // for (int j = ts.length - 1; j >= 0; j--) {
  516. // InstructionTargeter t = ts[j];
  517. // if (t instanceof LineNumberTag) {
  518. // return ((LineNumberTag)t).getLineNumber();
  519. // }
  520. // }
  521. // }
  522. // return getSourceLine(ih.getNext());
  523. // }
  524. public static int getSourceLine(InstructionHandle ih) {// ,boolean
  525. // goforwards) {
  526. int lookahead = 0;
  527. // arbitrary rule that we will never lookahead more than 100
  528. // instructions for a line #
  529. while (lookahead++ < 100) {
  530. if (ih == null) {
  531. return -1;
  532. }
  533. Iterator<InstructionTargeter> tIter = ih.getTargeters().iterator();
  534. while (tIter.hasNext()) {
  535. InstructionTargeter t = tIter.next();
  536. if (t instanceof LineNumberTag) {
  537. return ((LineNumberTag) t).getLineNumber();
  538. }
  539. }
  540. // if (goforwards) ih=ih.getNext(); else
  541. ih = ih.getPrev();
  542. }
  543. // System.err.println("no line information available for: " + ih);
  544. return -1;
  545. }
  546. // public static int getSourceLine(InstructionHandle ih) {
  547. // return getSourceLine(ih,false);
  548. // }
  549. // assumes that there is no already extant source line tag. Otherwise we'll
  550. // have to be better.
  551. public static void setSourceLine(InstructionHandle ih, int lineNumber) {
  552. // OPTIMIZE LineNumberTag instances for the same line could be shared
  553. // throughout a method...
  554. ih.addTargeter(new LineNumberTag(lineNumber));
  555. }
  556. public static int makePublic(int i) {
  557. return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC;
  558. }
  559. public static BcelVar[] pushAndReturnArrayOfVars(ResolvedType[] proceedParamTypes, InstructionList il, InstructionFactory fact,
  560. LazyMethodGen enclosingMethod) {
  561. int len = proceedParamTypes.length;
  562. BcelVar[] ret = new BcelVar[len];
  563. for (int i = len - 1; i >= 0; i--) {
  564. ResolvedType typeX = proceedParamTypes[i];
  565. Type type = BcelWorld.makeBcelType(typeX);
  566. int local = enclosingMethod.allocateLocal(type);
  567. il.append(InstructionFactory.createStore(type, local));
  568. ret[i] = new BcelVar(typeX, local);
  569. }
  570. return ret;
  571. }
  572. public static boolean isConstantPushInstruction(Instruction i) {
  573. long ii = Constants.instFlags[i.opcode];
  574. return ((ii & Constants.PUSH_INST) != 0 && (ii & Constants.CONSTANT_INST) != 0);
  575. }
  576. /**
  577. * Checks for suppression specified on the member or on the declaring type of that member
  578. */
  579. public static boolean isSuppressing(Member member, String lintkey) {
  580. boolean isSuppressing = Utils.isSuppressing(member.getAnnotations(), lintkey);
  581. if (isSuppressing) {
  582. return true;
  583. }
  584. UnresolvedType type = member.getDeclaringType();
  585. if (type instanceof ResolvedType) {
  586. return Utils.isSuppressing(((ResolvedType) type).getAnnotations(), lintkey);
  587. }
  588. return false;
  589. }
  590. public static List<Lint.Kind> getSuppressedWarnings(AnnotationAJ[] anns, Lint lint) {
  591. if (anns == null) {
  592. return Collections.emptyList();
  593. }
  594. // Go through the annotation types
  595. List<Lint.Kind> suppressedWarnings = new ArrayList<Lint.Kind>();
  596. boolean found = false;
  597. for (int i = 0; !found && i < anns.length; i++) {
  598. // Check for the SuppressAjWarnings annotation
  599. if (UnresolvedType.SUPPRESS_AJ_WARNINGS.getSignature().equals(
  600. ((BcelAnnotation) anns[i]).getBcelAnnotation().getTypeSignature())) {
  601. found = true;
  602. // Two possibilities:
  603. // 1. there are no values specified (i.e. @SuppressAjWarnings)
  604. // 2. there are values specified (i.e. @SuppressAjWarnings("A")
  605. // or @SuppressAjWarnings({"A","B"})
  606. List<NameValuePair> vals = ((BcelAnnotation) anns[i]).getBcelAnnotation().getValues();
  607. if (vals == null || vals.isEmpty()) { // (1)
  608. suppressedWarnings.addAll(lint.allKinds());
  609. } else { // (2)
  610. // We know the value is an array value
  611. ArrayElementValue array = (ArrayElementValue) (vals.get(0)).getValue();
  612. ElementValue[] values = array.getElementValuesArray();
  613. for (int j = 0; j < values.length; j++) {
  614. // We know values in the array are strings
  615. SimpleElementValue value = (SimpleElementValue) values[j];
  616. Lint.Kind lintKind = lint.getLintKind(value.getValueString());
  617. if (lintKind != null) {
  618. suppressedWarnings.add(lintKind);
  619. }
  620. }
  621. }
  622. }
  623. }
  624. return suppressedWarnings;
  625. }
  626. // not yet used...
  627. // public static boolean isSimple(Method method) {
  628. // if (method.getCode()==null) return true;
  629. // if (method.getCode().getCode().length>10) return false;
  630. // InstructionList instrucs = new
  631. // InstructionList(method.getCode().getCode()); // expensive!
  632. // InstructionHandle InstrHandle = instrucs.getStart();
  633. // while (InstrHandle != null) {
  634. // Instruction Instr = InstrHandle.getInstruction();
  635. // int opCode = Instr.opcode;
  636. // // if current instruction is a branch instruction, see if it's a backward
  637. // branch.
  638. // // if it is return immediately (can't be trivial)
  639. // if (Instr instanceof InstructionBranch) {
  640. // // InstructionBranch BI = (InstructionBranch) Instr;
  641. // if (Instr.getIndex() < 0) return false;
  642. // } else if (Instr instanceof InvokeInstruction) {
  643. // // if current instruction is an invocation, indicate that it can't be
  644. // trivial
  645. // return false;
  646. // }
  647. // InstrHandle = InstrHandle.getNext();
  648. // }
  649. // return true;
  650. // }
  651. public static Attribute bcelAttribute(AjAttribute a, ConstantPool pool) {
  652. int nameIndex = pool.addUtf8(a.getNameString());
  653. byte[] bytes = a.getBytes(new BcelConstantPoolWriter(pool));
  654. int length = bytes.length;
  655. return new Unknown(nameIndex, length, bytes, pool);
  656. }
  657. }