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.

LazyMethodGen.java 44KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  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 Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.ByteArrayOutputStream;
  14. import java.io.PrintStream;
  15. import java.lang.reflect.Modifier;
  16. import java.util.ArrayList;
  17. import java.util.HashMap;
  18. import java.util.HashSet;
  19. import java.util.Iterator;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import java.util.Stack;
  25. import org.aspectj.apache.bcel.Constants;
  26. import org.aspectj.apache.bcel.classfile.Attribute;
  27. import org.aspectj.apache.bcel.classfile.ConstantPool;
  28. import org.aspectj.apache.bcel.classfile.Method;
  29. import org.aspectj.apache.bcel.classfile.Synthetic;
  30. import org.aspectj.apache.bcel.generic.BranchHandle;
  31. import org.aspectj.apache.bcel.generic.BranchInstruction;
  32. import org.aspectj.apache.bcel.generic.CPInstruction;
  33. import org.aspectj.apache.bcel.generic.ClassGenException;
  34. import org.aspectj.apache.bcel.generic.CodeExceptionGen;
  35. import org.aspectj.apache.bcel.generic.ConstantPoolGen;
  36. import org.aspectj.apache.bcel.generic.Instruction;
  37. import org.aspectj.apache.bcel.generic.InstructionHandle;
  38. import org.aspectj.apache.bcel.generic.InstructionList;
  39. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  40. import org.aspectj.apache.bcel.generic.LineNumberGen;
  41. import org.aspectj.apache.bcel.generic.LocalVariableGen;
  42. import org.aspectj.apache.bcel.generic.LocalVariableInstruction;
  43. import org.aspectj.apache.bcel.generic.MethodGen;
  44. import org.aspectj.apache.bcel.generic.ObjectType;
  45. import org.aspectj.apache.bcel.generic.Select;
  46. import org.aspectj.apache.bcel.generic.Type;
  47. import org.aspectj.bridge.IMessage;
  48. import org.aspectj.weaver.AjAttribute;
  49. import org.aspectj.weaver.BCException;
  50. import org.aspectj.weaver.ISourceContext;
  51. import org.aspectj.weaver.Member;
  52. import org.aspectj.weaver.ResolvedTypeX;
  53. import org.aspectj.weaver.WeaverMessages;
  54. /**
  55. * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the
  56. * low-level Method objects. It converts through {@link MethodGen} to create
  57. * and to serialize, but that's it.
  58. *
  59. * <p> At any rate, there are two ways to create LazyMethodGens.
  60. * One is from a method, which
  61. * does work through MethodGen to do the correct thing.
  62. * The other is the creation of a completely empty
  63. * LazyMethodGen, and it is used when we're constructing code from scratch.
  64. *
  65. * <p> We stay away from targeters for rangey things like Shadows and Exceptions.
  66. */
  67. public final class LazyMethodGen {
  68. private int accessFlags;
  69. private Type returnType;
  70. private final String name;
  71. private Type[] argumentTypes;
  72. //private final String[] argumentNames;
  73. private String[] declaredExceptions;
  74. private InstructionList body; // leaving null for abstracts
  75. private Attribute[] attributes;
  76. /* private */ final LazyClassGen enclosingClass;
  77. private final BcelMethod memberView;
  78. int highestLineNumber = 0;
  79. /** This is nonnull if this method is the result of an "inlining". We currently
  80. * copy methods into other classes for around advice. We add this field so
  81. * we can get JSR45 information correct. If/when we do _actual_ inlining,
  82. * we'll need to subtype LineNumberTag to have external line numbers.
  83. */
  84. String fromFilename = null;
  85. private int maxLocals;
  86. private boolean canInline = true;
  87. private boolean hasExceptionHandlers;
  88. private boolean isSynthetic = false;
  89. /**
  90. * only used by {@link BcelClassWeaver}
  91. */
  92. List /*ShadowMungers*/ matchedShadows;
  93. // Used for interface introduction
  94. // this is the type of the interface the method is technically on
  95. public ResolvedTypeX definingType = null;
  96. public LazyMethodGen(
  97. int accessFlags,
  98. Type returnType,
  99. String name,
  100. Type[] paramTypes,
  101. String[] declaredExceptions,
  102. LazyClassGen enclosingClass)
  103. {
  104. //System.err.println("raw create of: " + name + ", " + enclosingClass.getName() + ", " + returnType);
  105. this.memberView = null; // ??? should be okay, since constructed ones aren't woven into
  106. this.accessFlags = accessFlags;
  107. this.returnType = returnType;
  108. this.name = name;
  109. this.argumentTypes = paramTypes;
  110. //this.argumentNames = Utility.makeArgNames(paramTypes.length);
  111. this.declaredExceptions = declaredExceptions;
  112. if (!Modifier.isAbstract(accessFlags)) {
  113. body = new InstructionList();
  114. setMaxLocals(calculateMaxLocals());
  115. } else {
  116. body = null;
  117. }
  118. this.attributes = new Attribute[0];
  119. this.enclosingClass = enclosingClass;
  120. assertGoodBody();
  121. }
  122. private int calculateMaxLocals() {
  123. int ret = 0;
  124. if (!Modifier.isStatic(accessFlags)) ret++;
  125. for (int i = 0, len = argumentTypes.length; i < len; i++) {
  126. ret += argumentTypes[i].getSize();
  127. }
  128. return ret;
  129. }
  130. private Method savedMethod = null;
  131. // build from an existing method, lazy build saves most work for initialization
  132. public LazyMethodGen(Method m, LazyClassGen enclosingClass) {
  133. savedMethod = m;
  134. this.enclosingClass = enclosingClass;
  135. if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) {
  136. throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass);
  137. }
  138. if ((m.isAbstract() || m.isNative()) && m.getCode() != null) {
  139. throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass);
  140. }
  141. this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m);
  142. this.accessFlags = m.getAccessFlags();
  143. this.name = m.getName();
  144. }
  145. public boolean hasDeclaredLineNumberInfo() {
  146. return (memberView != null && memberView.hasDeclarationLineNumberInfo());
  147. }
  148. public int getDeclarationLineNumber() {
  149. if (hasDeclaredLineNumberInfo()) {
  150. return memberView.getDeclarationLineNumber();
  151. } else {
  152. return -1;
  153. }
  154. }
  155. private void initialize() {
  156. if (returnType != null) return;
  157. //System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod);
  158. MethodGen gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPoolGen());
  159. this.returnType = gen.getReturnType();
  160. this.argumentTypes = gen.getArgumentTypes();
  161. this.declaredExceptions = gen.getExceptions();
  162. this.attributes = gen.getAttributes();
  163. this.maxLocals = gen.getMaxLocals();
  164. // this.returnType = BcelWorld.makeBcelType(memberView.getReturnType());
  165. // this.argumentTypes = BcelWorld.makeBcelTypes(memberView.getParameterTypes());
  166. //
  167. // this.declaredExceptions = TypeX.getNames(memberView.getExceptions()); //gen.getExceptions();
  168. // this.attributes = new Attribute[0]; //gen.getAttributes();
  169. // this.maxLocals = savedMethod.getCode().getMaxLocals();
  170. if (gen.isAbstract() || gen.isNative()) {
  171. body = null;
  172. } else {
  173. //body = new InstructionList(savedMethod.getCode().getCode());
  174. body = gen.getInstructionList();
  175. unpackHandlers(gen);
  176. unpackLineNumbers(gen);
  177. unpackLocals(gen);
  178. }
  179. assertGoodBody();
  180. //System.err.println("initialized: " + this.getClassName() + "." + this.getName());
  181. }
  182. // XXX we're relying on the javac promise I've just made up that we won't have an early exception
  183. // in the list mask a later exception: That is, for two exceptions E and F,
  184. // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So when we add F,
  185. // we add it on the _OUTSIDE_ of any handlers that share starts or ends with it.
  186. // with that in mind, we merrily go adding ranges for exceptions.
  187. private void unpackHandlers(MethodGen gen) {
  188. CodeExceptionGen[] exns = gen.getExceptionHandlers();
  189. if (exns != null) {
  190. int len = exns.length;
  191. if (len > 0) hasExceptionHandlers = true;
  192. int priority = len - 1;
  193. for (int i = 0; i < len; i++, priority--) {
  194. CodeExceptionGen exn = exns[i];
  195. InstructionHandle start =
  196. Range.genStart(
  197. body,
  198. getOutermostExceptionStart(exn.getStartPC()));
  199. InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC()));
  200. // this doesn't necessarily handle overlapping correctly!!!
  201. ExceptionRange er =
  202. new ExceptionRange(
  203. body,
  204. exn.getCatchType() == null
  205. ? null
  206. : BcelWorld.fromBcel(exn.getCatchType()),
  207. priority);
  208. er.associateWithTargets(start, end, exn.getHandlerPC());
  209. exn.setStartPC(null); // also removes from target
  210. exn.setEndPC(null); // also removes from target
  211. exn.setHandlerPC(null); // also removes from target
  212. }
  213. gen.removeExceptionHandlers();
  214. }
  215. }
  216. private InstructionHandle getOutermostExceptionStart(InstructionHandle ih) {
  217. while (true) {
  218. if (ExceptionRange.isExceptionStart(ih.getPrev())) {
  219. ih = ih.getPrev();
  220. } else {
  221. return ih;
  222. }
  223. }
  224. }
  225. private InstructionHandle getOutermostExceptionEnd(InstructionHandle ih) {
  226. while (true) {
  227. if (ExceptionRange.isExceptionEnd(ih.getNext())) {
  228. ih = ih.getNext();
  229. } else {
  230. return ih;
  231. }
  232. }
  233. }
  234. private void unpackLineNumbers(MethodGen gen) {
  235. LineNumberTag lr = null;
  236. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  237. InstructionTargeter[] targeters = ih.getTargeters();
  238. if (targeters != null) {
  239. for (int i = targeters.length - 1; i >= 0; i--) {
  240. InstructionTargeter targeter = targeters[i];
  241. if (targeter instanceof LineNumberGen) {
  242. LineNumberGen lng = (LineNumberGen) targeter;
  243. lng.updateTarget(ih, null);
  244. int lineNumber = lng.getSourceLine();
  245. if (highestLineNumber < lineNumber) highestLineNumber = lineNumber;
  246. lr = new LineNumberTag(lineNumber);
  247. }
  248. }
  249. }
  250. if (lr != null) {
  251. ih.addTargeter(lr);
  252. }
  253. }
  254. gen.removeLineNumbers();
  255. }
  256. private void unpackLocals(MethodGen gen) {
  257. Set locals = new HashSet();
  258. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  259. InstructionTargeter[] targeters = ih.getTargeters();
  260. List ends = new ArrayList(0);
  261. if (targeters != null) {
  262. for (int i = targeters.length - 1; i >= 0; i--) {
  263. InstructionTargeter targeter = targeters[i];
  264. if (targeter instanceof LocalVariableGen) {
  265. LocalVariableGen lng = (LocalVariableGen) targeter;
  266. LocalVariableTag lr = new LocalVariableTag(BcelWorld.fromBcel(lng.getType()), lng.getName(), lng.getIndex());
  267. if (lng.getStart() == ih) {
  268. locals.add(lr);
  269. } else {
  270. ends.add(lr);
  271. }
  272. }
  273. }
  274. }
  275. for (Iterator i = locals.iterator(); i.hasNext(); ) {
  276. ih.addTargeter((LocalVariableTag) i.next());
  277. }
  278. locals.removeAll(ends);
  279. }
  280. gen.removeLocalVariables();
  281. }
  282. // ===============
  283. public int allocateLocal(Type type) {
  284. return allocateLocal(type.getSize());
  285. }
  286. public int allocateLocal(int slots) {
  287. int max = getMaxLocals();
  288. setMaxLocals(max + slots);
  289. return max;
  290. }
  291. public Method getMethod() {
  292. if (savedMethod != null) return savedMethod; //??? this relies on gentle treatment of constant pool
  293. try {
  294. MethodGen gen = pack();
  295. return gen.getMethod();
  296. } catch (ClassGenException e) {
  297. enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld().showMessage(
  298. IMessage.ERROR,
  299. WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD,
  300. this.getClassName(),
  301. this.getName(),
  302. e.getMessage()),
  303. this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null);
  304. // throw e; PR 70201.... let the normal problem reporting infrastructure deal with this rather than crashing.
  305. body = null;
  306. MethodGen gen = pack();
  307. return gen.getMethod();
  308. }
  309. }
  310. public void markAsChanged() {
  311. initialize();
  312. savedMethod = null;
  313. }
  314. // =============================
  315. public String toString() {
  316. return toLongString();
  317. }
  318. public String toShortString() {
  319. String access = org.aspectj.apache.bcel.classfile.Utility.accessToString(getAccessFlags());
  320. StringBuffer buf = new StringBuffer();
  321. if (!access.equals("")) {
  322. buf.append(access);
  323. buf.append(" ");
  324. }
  325. buf.append(
  326. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  327. getReturnType().getSignature(),
  328. true));
  329. buf.append(" ");
  330. buf.append(getName());
  331. buf.append("(");
  332. {
  333. int len = argumentTypes.length;
  334. if (len > 0) {
  335. buf.append(
  336. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  337. argumentTypes[0].getSignature(),
  338. true));
  339. for (int i = 1; i < argumentTypes.length; i++) {
  340. buf.append(", ");
  341. buf.append(
  342. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  343. argumentTypes[i].getSignature(),
  344. true));
  345. }
  346. }
  347. }
  348. buf.append(")");
  349. {
  350. int len = declaredExceptions != null ? declaredExceptions.length : 0;
  351. if (len > 0) {
  352. buf.append(" throws ");
  353. buf.append(declaredExceptions[0]);
  354. for (int i = 1; i < declaredExceptions.length; i++) {
  355. buf.append(", ");
  356. buf.append(declaredExceptions[i]);
  357. }
  358. }
  359. }
  360. return buf.toString();
  361. }
  362. public String toLongString() {
  363. ByteArrayOutputStream s = new ByteArrayOutputStream();
  364. print(new PrintStream(s));
  365. return new String(s.toByteArray());
  366. }
  367. public void print() {
  368. print(System.out);
  369. }
  370. public void print(PrintStream out) {
  371. out.print(" " + toShortString());
  372. printAspectAttributes(out);
  373. InstructionList body = getBody();
  374. if (body == null) {
  375. out.println(";");
  376. return;
  377. }
  378. out.println(":");
  379. new BodyPrinter(out).run();
  380. out.println(" end " + toShortString());
  381. }
  382. private void printAspectAttributes(PrintStream out) {
  383. ISourceContext context = null;
  384. if (enclosingClass != null && enclosingClass.getType() != null) {
  385. context = enclosingClass.getType().getSourceContext();
  386. }
  387. List as = BcelAttributes.readAjAttributes(attributes, context,null);
  388. if (! as.isEmpty()) {
  389. out.println(" " + as.get(0)); // XXX assuming exactly one attribute, munger...
  390. }
  391. }
  392. private class BodyPrinter {
  393. Map prefixMap = new HashMap();
  394. Map suffixMap = new HashMap();
  395. Map labelMap = new HashMap();
  396. InstructionList body;
  397. PrintStream out;
  398. ConstantPool pool;
  399. List ranges;
  400. BodyPrinter(PrintStream out) {
  401. this.pool = enclosingClass.getConstantPoolGen().getConstantPool();
  402. this.body = getBody();
  403. this.out = out;
  404. }
  405. void run() {
  406. //killNops();
  407. assignLabels();
  408. print();
  409. }
  410. // label assignment
  411. void assignLabels() {
  412. LinkedList exnTable = new LinkedList();
  413. String pendingLabel = null;
  414. // boolean hasPendingTargeters = false;
  415. int lcounter = 0;
  416. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  417. InstructionTargeter[] targeters = ih.getTargeters();
  418. if (targeters != null) {
  419. for (int i = targeters.length - 1; i >= 0; i--) {
  420. InstructionTargeter t = targeters[i];
  421. if (t instanceof ExceptionRange) {
  422. // assert isRangeHandle(h);
  423. ExceptionRange r = (ExceptionRange) t;
  424. if (r.getStart() == ih) {
  425. insertHandler(r, exnTable);
  426. }
  427. } else if (t instanceof BranchInstruction) {
  428. if (pendingLabel == null) {
  429. pendingLabel = "L" + lcounter++;
  430. }
  431. } else {
  432. // assert isRangeHandle(h)
  433. }
  434. }
  435. }
  436. if (pendingLabel != null) {
  437. labelMap.put(ih, pendingLabel);
  438. if (! Range.isRangeHandle(ih)) {
  439. pendingLabel = null;
  440. }
  441. }
  442. }
  443. int ecounter = 0;
  444. for (Iterator i = exnTable.iterator(); i.hasNext();) {
  445. ExceptionRange er = (ExceptionRange) i.next();
  446. String exceptionLabel = "E" + ecounter++;
  447. labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel);
  448. labelMap.put(er.getHandler(), exceptionLabel);
  449. }
  450. }
  451. // printing
  452. void print() {
  453. int depth = 0;
  454. int currLine = -1;
  455. bodyPrint:
  456. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  457. if (Range.isRangeHandle(ih)) {
  458. Range r = Range.getRange(ih);
  459. // don't print empty ranges, that is, ranges who contain no actual instructions
  460. for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) {
  461. if (xx == r.getEnd()) continue bodyPrint;
  462. }
  463. // doesn't handle nested: if (r.getStart().getNext() == r.getEnd()) continue;
  464. if (r.getStart() == ih) {
  465. printRangeString(r, depth++);
  466. } else {
  467. if (r.getEnd() != ih) throw new RuntimeException("bad");
  468. printRangeString(r, --depth);
  469. }
  470. } else {
  471. printInstruction(ih, depth);
  472. int line = getLineNumber(ih, currLine);
  473. if (line != currLine) {
  474. currLine = line;
  475. out.println(" (line " + line + ")");
  476. } else {
  477. out.println();
  478. }
  479. }
  480. }
  481. }
  482. void printRangeString(Range r, int depth) {
  483. printDepth(depth);
  484. out.println(getRangeString(r, labelMap));
  485. }
  486. String getRangeString(Range r, Map labelMap) {
  487. if (r instanceof ExceptionRange) {
  488. ExceptionRange er = (ExceptionRange) r;
  489. return er.toString() + " -> " + labelMap.get(er.getHandler());
  490. //
  491. // + " PRI " + er.getPriority();
  492. } else {
  493. return r.toString();
  494. }
  495. }
  496. void printDepth(int depth) {
  497. pad(BODY_INDENT);
  498. while (depth > 0) {
  499. out.print("| ");
  500. depth--;
  501. }
  502. }
  503. void printLabel(String s, int depth) {
  504. int space = Math.max(CODE_INDENT - depth * 2, 0);
  505. if (s == null) {
  506. pad(space);
  507. } else {
  508. space = Math.max(space - (s.length() + 2), 0);
  509. pad(space);
  510. out.print(s);
  511. out.print(": ");
  512. }
  513. }
  514. void printInstruction(InstructionHandle h, int depth) {
  515. printDepth(depth);
  516. printLabel((String) labelMap.get(h), depth);
  517. Instruction inst = h.getInstruction();
  518. if (inst instanceof CPInstruction) {
  519. CPInstruction cpinst = (CPInstruction) inst;
  520. out.print(Constants.OPCODE_NAMES[cpinst.getOpcode()].toUpperCase());
  521. out.print(" ");
  522. out.print(pool.constantToString(pool.getConstant(cpinst.getIndex())));
  523. } else if (inst instanceof Select) {
  524. Select sinst = (Select) inst;
  525. out.println(Constants.OPCODE_NAMES[sinst.getOpcode()].toUpperCase());
  526. int[] matches = sinst.getMatchs();
  527. InstructionHandle[] targets = sinst.getTargets();
  528. InstructionHandle defaultTarget = sinst.getTarget();
  529. for (int i = 0, len = matches.length; i < len; i++) {
  530. printDepth(depth);
  531. printLabel(null, depth);
  532. out.print(" ");
  533. out.print(matches[i]);
  534. out.print(": \t");
  535. out.println(labelMap.get(targets[i]));
  536. }
  537. printDepth(depth);
  538. printLabel(null, depth);
  539. out.print(" ");
  540. out.print("default: \t");
  541. out.print(labelMap.get(defaultTarget));
  542. } else if (inst instanceof BranchInstruction) {
  543. BranchInstruction brinst = (BranchInstruction) inst;
  544. out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase());
  545. out.print(" ");
  546. out.print(labelMap.get(brinst.getTarget()));
  547. } else if (inst instanceof LocalVariableInstruction) {
  548. LocalVariableInstruction lvinst = (LocalVariableInstruction) inst;
  549. out.print(inst.toString(false).toUpperCase());
  550. int index = lvinst.getIndex();
  551. LocalVariableTag tag = getLocalVariableTag(h, index);
  552. if (tag != null) {
  553. out.print(" // ");
  554. out.print(tag.getType());
  555. out.print(" ");
  556. out.print(tag.getName());
  557. }
  558. } else {
  559. out.print(inst.toString(false).toUpperCase());
  560. }
  561. }
  562. static final int BODY_INDENT = 4;
  563. static final int CODE_INDENT = 16;
  564. void pad(int size) {
  565. for (int i = 0; i < size; i++) {
  566. out.print(" ");
  567. }
  568. }
  569. }
  570. static LocalVariableTag getLocalVariableTag(
  571. InstructionHandle ih,
  572. int index)
  573. {
  574. InstructionTargeter[] targeters = ih.getTargeters();
  575. if (targeters == null) return null;
  576. for (int i = targeters.length - 1; i >= 0; i--) {
  577. InstructionTargeter t = targeters[i];
  578. if (t instanceof LocalVariableTag) {
  579. LocalVariableTag lvt = (LocalVariableTag) t;
  580. if (lvt.getSlot() == index) return lvt;
  581. }
  582. }
  583. return null;
  584. }
  585. static int getLineNumber(
  586. InstructionHandle ih,
  587. int prevLine)
  588. {
  589. InstructionTargeter[] targeters = ih.getTargeters();
  590. if (targeters == null) return prevLine;
  591. for (int i = targeters.length - 1; i >= 0; i--) {
  592. InstructionTargeter t = targeters[i];
  593. if (t instanceof LineNumberTag) {
  594. return ((LineNumberTag)t).getLineNumber();
  595. }
  596. }
  597. return prevLine;
  598. }
  599. public boolean isStatic() {
  600. return Modifier.isStatic(getAccessFlags());
  601. }
  602. public boolean isAbstract() {
  603. return Modifier.isAbstract(getAccessFlags());
  604. }
  605. public boolean isBridgeMethod() {
  606. return (getAccessFlags() & Constants.ACC_BRIDGE) != 0;
  607. }
  608. public void addExceptionHandler(
  609. InstructionHandle start,
  610. InstructionHandle end,
  611. InstructionHandle handlerStart,
  612. ObjectType catchType,
  613. boolean highPriority) {
  614. InstructionHandle start1 = Range.genStart(body, start);
  615. InstructionHandle end1 = Range.genEnd(body, end);
  616. ExceptionRange er =
  617. new ExceptionRange(body, BcelWorld.fromBcel(catchType), highPriority);
  618. er.associateWithTargets(start1, end1, handlerStart);
  619. }
  620. public int getAccessFlags() {
  621. return accessFlags;
  622. }
  623. public Type[] getArgumentTypes() {
  624. initialize();
  625. return argumentTypes;
  626. }
  627. public LazyClassGen getEnclosingClass() {
  628. return enclosingClass;
  629. }
  630. public int getMaxLocals() {
  631. return maxLocals;
  632. }
  633. public String getName() {
  634. return name;
  635. }
  636. public Type getReturnType() {
  637. initialize();
  638. return returnType;
  639. }
  640. public void setMaxLocals(int maxLocals) {
  641. this.maxLocals = maxLocals;
  642. }
  643. public InstructionList getBody() {
  644. markAsChanged();
  645. return body;
  646. }
  647. public boolean hasBody() {
  648. if (savedMethod != null) return savedMethod.getCode() != null;
  649. return body != null;
  650. }
  651. public Attribute[] getAttributes() {
  652. return attributes;
  653. }
  654. public String[] getDeclaredExceptions() {
  655. return declaredExceptions;
  656. }
  657. public String getClassName() {
  658. return enclosingClass.getName();
  659. }
  660. // ---- packing!
  661. public MethodGen pack() {
  662. //killNops();
  663. MethodGen gen =
  664. new MethodGen(
  665. getAccessFlags(),
  666. getReturnType(),
  667. getArgumentTypes(),
  668. null, //getArgumentNames(),
  669. getName(),
  670. getEnclosingClass().getName(),
  671. new InstructionList(),
  672. getEnclosingClass().getConstantPoolGen());
  673. for (int i = 0, len = declaredExceptions.length; i < len; i++) {
  674. gen.addException(declaredExceptions[i]);
  675. }
  676. for (int i = 0, len = attributes.length; i < len; i++) {
  677. gen.addAttribute(attributes[i]);
  678. }
  679. if (isSynthetic) {
  680. ConstantPoolGen cpg = gen.getConstantPool();
  681. int index = cpg.addUtf8("Synthetic");
  682. gen.addAttribute(new Synthetic(index, 0, new byte[0], cpg.getConstantPool()));
  683. }
  684. if (hasBody()) {
  685. packBody(gen);
  686. gen.setMaxLocals();
  687. gen.setMaxStack();
  688. } else {
  689. gen.setInstructionList(null);
  690. }
  691. return gen;
  692. }
  693. public void makeSynthetic() {
  694. isSynthetic = true;
  695. }
  696. /** fill the newly created method gen with our body,
  697. * inspired by InstructionList.copy()
  698. */
  699. public void packBody(MethodGen gen) {
  700. HashMap map = new HashMap();
  701. InstructionList fresh = gen.getInstructionList();
  702. /* Make copies of all instructions, append them to the new list
  703. * and associate old instruction references with the new ones, i.e.,
  704. * a 1:1 mapping.
  705. */
  706. for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) {
  707. if (Range.isRangeHandle(ih)) {
  708. continue;
  709. }
  710. Instruction i = ih.getInstruction();
  711. Instruction c = Utility.copyInstruction(i);
  712. if (c instanceof BranchInstruction)
  713. map.put(ih, fresh.append((BranchInstruction) c));
  714. else
  715. map.put(ih, fresh.append(c));
  716. }
  717. // at this point, no rangeHandles are in fresh. Let's use that...
  718. /* Update branch targets and insert various attributes.
  719. * Insert our exceptionHandlers
  720. * into a sorted list, so they can be added in order later.
  721. */
  722. InstructionHandle ih = getBody().getStart();
  723. InstructionHandle jh = fresh.getStart();
  724. LinkedList exnList = new LinkedList();
  725. // map from localvariabletag to instruction handle
  726. Map localVariableStarts = new HashMap();
  727. Map localVariableEnds = new HashMap();
  728. int currLine = -1;
  729. while (ih != null) {
  730. if (map.get(ih) == null) {
  731. // we're a range instruction
  732. Range r = Range.getRange(ih);
  733. if (r instanceof ExceptionRange) {
  734. ExceptionRange er = (ExceptionRange) r;
  735. if (er.getStart() == ih) {
  736. //System.err.println("er " + er);
  737. if (!er.isEmpty()){
  738. // order is important, insert handlers in order of start
  739. insertHandler(er, exnList);
  740. }
  741. }
  742. } else {
  743. // we must be a shadow range or something equally useless,
  744. // so forget about doing anything
  745. }
  746. // just increment ih.
  747. ih = ih.getNext();
  748. } else {
  749. // assert map.get(ih) == jh
  750. Instruction i = ih.getInstruction();
  751. Instruction j = jh.getInstruction();
  752. if (i instanceof BranchInstruction) {
  753. BranchInstruction bi = (BranchInstruction) i;
  754. BranchInstruction bj = (BranchInstruction) j;
  755. InstructionHandle itarget = bi.getTarget(); // old target
  756. // try {
  757. // New target is in hash map
  758. bj.setTarget(remap(itarget, map));
  759. // } catch (NullPointerException e) {
  760. // print();
  761. // System.out.println("Was trying to remap " + bi);
  762. // System.out.println("who's target was supposedly " + itarget);
  763. // throw e;
  764. // }
  765. if (bi instanceof Select) {
  766. // Either LOOKUPSWITCH or TABLESWITCH
  767. InstructionHandle[] itargets = ((Select) bi).getTargets();
  768. InstructionHandle[] jtargets = ((Select) bj).getTargets();
  769. for (int k = itargets.length - 1; k >= 0; k--) {
  770. // Update all targets
  771. jtargets[k] = remap(itargets[k], map);
  772. jtargets[k].addTargeter(bj);
  773. }
  774. }
  775. }
  776. // now deal with line numbers
  777. // and store up info for local variables
  778. InstructionTargeter[] targeters = ih.getTargeters();
  779. int lineNumberOffset =
  780. (fromFilename == null)
  781. ? 0
  782. : getEnclosingClass().getSourceDebugExtensionOffset(fromFilename);
  783. if (targeters != null) {
  784. for (int k = targeters.length - 1; k >= 0; k--) {
  785. InstructionTargeter targeter = targeters[k];
  786. if (targeter instanceof LineNumberTag) {
  787. int line = ((LineNumberTag)targeter).getLineNumber();
  788. if (line != currLine) {
  789. gen.addLineNumber(jh, line + lineNumberOffset);
  790. currLine = line;
  791. }
  792. } else if (targeter instanceof LocalVariableTag) {
  793. LocalVariableTag lvt = (LocalVariableTag) targeter;
  794. if (localVariableStarts.get(lvt) == null) {
  795. localVariableStarts.put(lvt, jh);
  796. }
  797. localVariableEnds.put(lvt, jh);
  798. }
  799. }
  800. }
  801. // now continue
  802. ih = ih.getNext();
  803. jh = jh.getNext();
  804. }
  805. }
  806. // now add exception handlers
  807. for (Iterator iter = exnList.iterator(); iter.hasNext();) {
  808. ExceptionRange r = (ExceptionRange) iter.next();
  809. if (r.isEmpty()) continue;
  810. gen.addExceptionHandler(
  811. remap(r.getRealStart(), map),
  812. remap(r.getRealEnd(), map),
  813. remap(r.getHandler(), map),
  814. (r.getCatchType() == null)
  815. ? null
  816. : (ObjectType) BcelWorld.makeBcelType(r.getCatchType()));
  817. }
  818. // now add local variables
  819. gen.removeLocalVariables();
  820. // this next iteration _might_ be overkill, but we had problems with
  821. // bcel before with duplicate local variables. Now that we're patching
  822. // bcel we should be able to do without it if we're paranoid enough
  823. // through the rest of the compiler.
  824. Map duplicatedLocalMap = new HashMap();
  825. List keys = new ArrayList();
  826. keys.addAll(localVariableStarts.keySet());
  827. for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
  828. LocalVariableTag tag = (LocalVariableTag) iter.next();
  829. // have we already added one with the same slot number and start location?
  830. // if so, just continue.
  831. InstructionHandle start = (InstructionHandle) localVariableStarts.get(tag);
  832. Set slots = (Set) duplicatedLocalMap.get(start);
  833. if (slots == null) {
  834. slots = new HashSet();
  835. duplicatedLocalMap.put(start, slots);
  836. }
  837. if (slots.contains(new Integer(tag.getSlot()))) {
  838. // we already have a var starting at this tag with this slot
  839. continue;
  840. }
  841. slots.add(new Integer(tag.getSlot()));
  842. gen.addLocalVariable(
  843. tag.getName(),
  844. BcelWorld.makeBcelType(tag.getType()),
  845. tag.getSlot(),
  846. (InstructionHandle) localVariableStarts.get(tag),
  847. (InstructionHandle) localVariableEnds.get(tag));
  848. }
  849. }
  850. /** This proedure should not currently be used.
  851. */
  852. // public void killNops() {
  853. // InstructionHandle curr = body.getStart();
  854. // while (true) {
  855. // if (curr == null) break;
  856. // InstructionHandle next = curr.getNext();
  857. // if (curr.getInstruction() instanceof NOP) {
  858. // InstructionTargeter[] targeters = curr.getTargeters();
  859. // if (targeters != null) {
  860. // for (int i = 0, len = targeters.length; i < len; i++) {
  861. // InstructionTargeter targeter = targeters[i];
  862. // targeter.updateTarget(curr, next);
  863. // }
  864. // }
  865. // try {
  866. // body.delete(curr);
  867. // } catch (TargetLostException e) {
  868. // }
  869. // }
  870. // curr = next;
  871. // }
  872. // }
  873. private static InstructionHandle remap(InstructionHandle ih, Map map) {
  874. while (true) {
  875. Object ret = map.get(ih);
  876. if (ret == null) {
  877. ih = ih.getNext();
  878. } else {
  879. return (InstructionHandle) ret;
  880. }
  881. }
  882. }
  883. // exception ordering.
  884. // What we should be doing is dealing with priority inversions way earlier than we are
  885. // and counting on the tree structure. In which case, the below code is in fact right.
  886. // XXX THIS COMMENT BELOW IS CURRENTLY WRONG.
  887. // An exception A preceeds an exception B in the exception table iff:
  888. // * A and B were in the original method, and A preceeded B in the original exception table
  889. // * If A has a higher priority than B, than it preceeds B.
  890. // * If A and B have the same priority, then the one whose START happens EARLIEST has LEAST priority.
  891. // in short, the outermost exception has least priority.
  892. // we implement this with a LinkedList. We could possibly implement this with a java.util.SortedSet,
  893. // but I don't trust the only implementation, TreeSet, to do the right thing.
  894. /* private */ static void insertHandler(ExceptionRange fresh, LinkedList l) {
  895. // for (ListIterator iter = l.listIterator(); iter.hasNext();) {
  896. // ExceptionRange r = (ExceptionRange) iter.next();
  897. // if (fresh.getPriority() >= r.getPriority()) {
  898. // iter.previous();
  899. // iter.add(fresh);
  900. // return;
  901. // }
  902. // }
  903. l.add(0, fresh);
  904. }
  905. public boolean isPrivate() {
  906. return Modifier.isPrivate(getAccessFlags());
  907. }
  908. // ----
  909. /** A good body is a body with the following properties:
  910. *
  911. * <ul>
  912. * <li> For each branch instruction S in body, target T of S is in body.
  913. * <li> For each branch instruction S in body, target T of S has S as a targeter.
  914. * <li> For each instruction T in body, for each branch instruction S that is a
  915. * targeter of T, S is in body.
  916. * <li> For each non-range-handle instruction T in body, for each instruction S
  917. * that is a targeter of T, S is
  918. * either a branch instruction, an exception range or a tag
  919. * <li> For each range-handle instruction T in body, there is exactly one targeter S
  920. * that is a range.
  921. * <li> For each range-handle instruction T in body, the range R targeting T is in body.
  922. * <li> For each instruction T in body, for each exception range R targeting T, R is
  923. * in body.
  924. * <li> For each exception range R in body, let T := R.handler. T is in body, and R is one
  925. * of T's targeters
  926. * <li> All ranges are properly nested: For all ranges Q and R, if Q.start preceeds
  927. * R.start, then R.end preceeds Q.end.
  928. * </ul>
  929. *
  930. * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and
  931. * any InstructionHandle stored in a field of R (such as an exception handle) is in body".
  932. */
  933. public void assertGoodBody() {
  934. if (true) return; // only enable for debugging, consider using cheaper toString()
  935. assertGoodBody(getBody(), toString()); //definingType.getNameAsIdentifier() + "." + getName()); //toString());
  936. }
  937. public static void assertGoodBody(InstructionList il, String from) {
  938. if (true) return; // only to be enabled for debugging
  939. if (il == null) return;
  940. Set body = new HashSet();
  941. Stack ranges = new Stack();
  942. for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
  943. body.add(ih);
  944. if (ih.getInstruction() instanceof BranchInstruction) {
  945. body.add(ih.getInstruction());
  946. }
  947. }
  948. for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
  949. assertGoodHandle(ih, body, ranges, from);
  950. InstructionTargeter[] ts = ih.getTargeters();
  951. if (ts != null) {
  952. for (int i = ts.length - 1; i >= 0; i--) {
  953. assertGoodTargeter(ts[i], ih, body, from);
  954. }
  955. }
  956. }
  957. }
  958. private static void assertGoodHandle(InstructionHandle ih, Set body, Stack ranges, String from) {
  959. Instruction inst = ih.getInstruction();
  960. if ((inst instanceof BranchInstruction) ^ (ih instanceof BranchHandle)) {
  961. throw new BCException("bad instruction/handle pair in " + from);
  962. }
  963. if (Range.isRangeHandle(ih)) {
  964. assertGoodRangeHandle(ih, body, ranges, from);
  965. } else if (inst instanceof BranchInstruction) {
  966. assertGoodBranchInstruction((BranchHandle) ih, (BranchInstruction) inst, body, ranges, from);
  967. }
  968. }
  969. private static void assertGoodBranchInstruction(
  970. BranchHandle ih,
  971. BranchInstruction inst,
  972. Set body,
  973. Stack ranges,
  974. String from)
  975. {
  976. if (ih.getTarget() != inst.getTarget()) {
  977. throw new BCException("bad branch instruction/handle pair in " + from);
  978. }
  979. InstructionHandle target = ih.getTarget();
  980. assertInBody(target, body, from);
  981. assertTargetedBy(target, inst, from);
  982. if (inst instanceof Select) {
  983. Select sel = (Select) inst;
  984. InstructionHandle[] itargets = sel.getTargets();
  985. for (int k = itargets.length - 1; k >= 0; k--) {
  986. assertInBody(itargets[k], body, from);
  987. assertTargetedBy(itargets[k], inst, from);
  988. }
  989. }
  990. }
  991. /** ih is an InstructionHandle or a BranchInstruction */
  992. private static void assertInBody(Object ih, Set body, String from) {
  993. if (! body.contains(ih)) throw new BCException("thing not in body in " + from);
  994. }
  995. private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) {
  996. Range r = getRangeAndAssertExactlyOne(ih, from);
  997. assertGoodRange(r, body, from);
  998. if (r.getStart() == ih) {
  999. ranges.push(r);
  1000. } else if (r.getEnd() == ih) {
  1001. if (ranges.peek() != r) throw new BCException("bad range inclusion in " + from);
  1002. ranges.pop();
  1003. }
  1004. }
  1005. private static void assertGoodRange(Range r, Set body, String from) {
  1006. assertInBody(r.getStart(), body, from);
  1007. assertRangeHandle(r.getStart(), from);
  1008. assertTargetedBy(r.getStart(), r, from);
  1009. assertInBody(r.getEnd(), body, from);
  1010. assertRangeHandle(r.getEnd(), from);
  1011. assertTargetedBy(r.getEnd(), r, from);
  1012. if (r instanceof ExceptionRange) {
  1013. ExceptionRange er = (ExceptionRange) r;
  1014. assertInBody(er.getHandler(), body, from);
  1015. assertTargetedBy(er.getHandler(), r, from);
  1016. }
  1017. }
  1018. private static void assertRangeHandle(InstructionHandle ih, String from) {
  1019. if (! Range.isRangeHandle(ih)) throw new BCException("bad range handle " + ih + " in " + from);
  1020. }
  1021. private static void assertTargetedBy(
  1022. InstructionHandle target,
  1023. InstructionTargeter targeter,
  1024. String from)
  1025. {
  1026. InstructionTargeter[] ts = target.getTargeters();
  1027. if (ts == null) throw new BCException("bad targeting relationship in " + from);
  1028. for (int i = ts.length - 1; i >= 0; i--) {
  1029. if (ts[i] == targeter) return;
  1030. }
  1031. throw new RuntimeException("bad targeting relationship in " + from);
  1032. }
  1033. private static void assertTargets(InstructionTargeter targeter, InstructionHandle target, String from) {
  1034. if (targeter instanceof Range) {
  1035. Range r = (Range) targeter;
  1036. if (r.getStart() == target || r.getEnd() == target) return;
  1037. if (r instanceof ExceptionRange) {
  1038. if (((ExceptionRange)r).getHandler() == target) return;
  1039. }
  1040. } else if (targeter instanceof BranchInstruction) {
  1041. BranchInstruction bi = (BranchInstruction) targeter;
  1042. if (bi.getTarget() == target) return;
  1043. if (targeter instanceof Select) {
  1044. Select sel = (Select) targeter;
  1045. InstructionHandle[] itargets = sel.getTargets();
  1046. for (int k = itargets.length - 1; k >= 0; k--) {
  1047. if (itargets[k] == target) return;
  1048. }
  1049. }
  1050. } else if (targeter instanceof Tag) {
  1051. return;
  1052. }
  1053. throw new BCException(targeter + " doesn't target " + target + " in " + from );
  1054. }
  1055. private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) {
  1056. Range ret = null;
  1057. InstructionTargeter[] ts = ih.getTargeters();
  1058. if (ts == null) throw new BCException("range handle with no range in " + from);
  1059. for (int i = ts.length - 1; i >= 0; i--) {
  1060. if (ts[i] instanceof Range) {
  1061. if (ret != null) throw new BCException("range handle with multiple ranges in " + from);
  1062. ret = (Range) ts[i];
  1063. }
  1064. }
  1065. if (ret == null) throw new BCException("range handle with no range in " + from);
  1066. return ret;
  1067. }
  1068. private static void assertGoodTargeter(
  1069. InstructionTargeter t,
  1070. InstructionHandle ih,
  1071. Set body,
  1072. String from)
  1073. {
  1074. assertTargets(t, ih, from);
  1075. if (t instanceof Range) {
  1076. assertGoodRange((Range) t, body, from);
  1077. } else if (t instanceof BranchInstruction) {
  1078. assertInBody(t, body, from);
  1079. }
  1080. }
  1081. // ----
  1082. boolean isAdviceMethod() {
  1083. return memberView.getAssociatedShadowMunger() != null;
  1084. }
  1085. boolean isAjSynthetic() {
  1086. if (memberView == null) return true;
  1087. return memberView.isAjSynthetic();
  1088. }
  1089. public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
  1090. //if (memberView == null) return null;
  1091. return memberView.getEffectiveSignature();
  1092. }
  1093. public String getSignature() {
  1094. if (memberView!=null) return memberView.getSignature();
  1095. return Member.typesToSignature(BcelWorld.fromBcel(getReturnType()),
  1096. BcelWorld.fromBcel(getArgumentTypes()));
  1097. }
  1098. public BcelMethod getMemberView() {
  1099. return memberView;
  1100. }
  1101. public void forcePublic() {
  1102. markAsChanged();
  1103. accessFlags = Utility.makePublic(accessFlags);
  1104. }
  1105. public boolean getCanInline() {
  1106. return canInline;
  1107. }
  1108. public void setCanInline(boolean canInline) {
  1109. this.canInline = canInline;
  1110. }
  1111. }