Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

LazyMethodGen.java 45KB

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