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 26KB

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