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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.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.ListIterator;
  23. import java.util.Map;
  24. import java.util.Properties;
  25. import java.util.Set;
  26. import java.util.Stack;
  27. import org.aspectj.apache.bcel.Constants;
  28. import org.aspectj.apache.bcel.classfile.Attribute;
  29. import org.aspectj.apache.bcel.classfile.ConstantPool;
  30. import org.aspectj.apache.bcel.classfile.Method;
  31. import org.aspectj.apache.bcel.classfile.Synthetic;
  32. import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
  33. import org.aspectj.apache.bcel.generic.BranchHandle;
  34. import org.aspectj.apache.bcel.generic.ClassGenException;
  35. import org.aspectj.apache.bcel.generic.CodeExceptionGen;
  36. import org.aspectj.apache.bcel.generic.Instruction;
  37. import org.aspectj.apache.bcel.generic.InstructionBranch;
  38. import org.aspectj.apache.bcel.generic.InstructionComparator;
  39. import org.aspectj.apache.bcel.generic.InstructionHandle;
  40. import org.aspectj.apache.bcel.generic.InstructionList;
  41. import org.aspectj.apache.bcel.generic.InstructionSelect;
  42. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  43. import org.aspectj.apache.bcel.generic.LineNumberGen;
  44. import org.aspectj.apache.bcel.generic.LineNumberTag;
  45. import org.aspectj.apache.bcel.generic.LocalVariableGen;
  46. import org.aspectj.apache.bcel.generic.LocalVariableTag;
  47. import org.aspectj.apache.bcel.generic.MethodGen;
  48. import org.aspectj.apache.bcel.generic.ObjectType;
  49. import org.aspectj.apache.bcel.generic.Tag;
  50. import org.aspectj.apache.bcel.generic.TargetLostException;
  51. import org.aspectj.apache.bcel.generic.Type;
  52. import org.aspectj.bridge.IMessage;
  53. import org.aspectj.bridge.ISourceLocation;
  54. import org.aspectj.bridge.MessageUtil;
  55. import org.aspectj.weaver.AjAttribute;
  56. import org.aspectj.weaver.AnnotationX;
  57. import org.aspectj.weaver.BCException;
  58. import org.aspectj.weaver.ISourceContext;
  59. import org.aspectj.weaver.MemberImpl;
  60. import org.aspectj.weaver.NameMangler;
  61. import org.aspectj.weaver.ResolvedMember;
  62. import org.aspectj.weaver.ResolvedType;
  63. import org.aspectj.weaver.Shadow;
  64. import org.aspectj.weaver.UnresolvedType;
  65. import org.aspectj.weaver.WeaverMessages;
  66. import org.aspectj.weaver.AjAttribute.WeaverVersionInfo;
  67. import org.aspectj.weaver.tools.Traceable;
  68. /**
  69. * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the
  70. * low-level Method objects. It converts through {@link MethodGen} to create
  71. * and to serialize, but that's it.
  72. *
  73. * <p> At any rate, there are two ways to create LazyMethodGens.
  74. * One is from a method, which
  75. * does work through MethodGen to do the correct thing.
  76. * The other is the creation of a completely empty
  77. * LazyMethodGen, and it is used when we're constructing code from scratch.
  78. *
  79. * <p> We stay away from targeters for rangey things like Shadows and Exceptions.
  80. */
  81. public final class LazyMethodGen implements Traceable {
  82. private static final int ACC_SYNTHETIC = 0x1000;
  83. private int accessFlags;
  84. private Type returnType;
  85. private final String name;
  86. private Type[] argumentTypes;
  87. //private final String[] argumentNames;
  88. private String[] declaredExceptions;
  89. private InstructionList body; // leaving null for abstracts
  90. private List attributes;
  91. private List newAnnotations;
  92. private final LazyClassGen enclosingClass;
  93. private BcelMethod memberView;
  94. private AjAttribute.EffectiveSignatureAttribute effectiveSignature;
  95. int highestLineNumber = 0;
  96. boolean wasNewPacked = false;
  97. /*
  98. * We use LineNumberTags and not Gens.
  99. *
  100. * This option specifies whether we let the BCEL classes create LineNumberGens and LocalVariableGens
  101. * or if we make it create LineNumberTags and LocalVariableTags. Up until 1.5.1 we always created
  102. * Gens - then on return from the MethodGen ctor we took them apart, reprocessed them all and
  103. * created Tags. (see unpackLocals/unpackLineNumbers). As we have our own copy of Bcel, why not create
  104. * the right thing straightaway? So setting this to true will call the MethodGen ctor() in such
  105. * a way that it creates Tags - removing the need for unpackLocals/unpackLineNumbers - HOWEVER see
  106. * the ensureAllLineNumberSetup() method for some other relevant info.
  107. *
  108. * Whats the difference between a Tag and a Gen? A Tag is more lightweight, it doesn't know which
  109. * instructions it targets, it relies on the instructions targetting *it* - this reduces the amount
  110. * of targeter manipulation we have to do.
  111. *
  112. */
  113. /** This is nonnull if this method is the result of an "inlining". We currently
  114. * copy methods into other classes for around advice. We add this field so
  115. * we can get JSR45 information correct. If/when we do _actual_ inlining,
  116. * we'll need to subtype LineNumberTag to have external line numbers.
  117. */
  118. String fromFilename = null;
  119. private int maxLocals;
  120. private boolean canInline = true;
  121. // private boolean hasExceptionHandlers;
  122. private boolean isSynthetic = false;
  123. /**
  124. * only used by {@link BcelClassWeaver}
  125. */
  126. List /*ShadowMungers*/ matchedShadows;
  127. List /*Test*/ matchedShadowTests;
  128. // Used for interface introduction
  129. // this is the type of the interface the method is technically on
  130. public ResolvedType definingType = null;
  131. public LazyMethodGen(
  132. int accessFlags,
  133. Type returnType,
  134. String name,
  135. Type[] paramTypes,
  136. String[] declaredExceptions,
  137. LazyClassGen enclosingClass)
  138. {
  139. //System.err.println("raw create of: " + name + ", " + enclosingClass.getName() + ", " + returnType);
  140. this.memberView = null; // ??? should be okay, since constructed ones aren't woven into
  141. this.accessFlags = accessFlags;
  142. this.returnType = returnType;
  143. this.name = name;
  144. this.argumentTypes = paramTypes;
  145. //this.argumentNames = Utility.makeArgNames(paramTypes.length);
  146. this.declaredExceptions = declaredExceptions;
  147. if (!Modifier.isAbstract(accessFlags)) {
  148. body = new InstructionList();
  149. setMaxLocals(calculateMaxLocals());
  150. } else {
  151. body = null;
  152. }
  153. this.attributes = new ArrayList();
  154. this.enclosingClass = enclosingClass;
  155. assertGoodBody();
  156. // @AJ advice are not inlined by default since requires further analysis
  157. // and weaving ordering control
  158. // TODO AV - improve - note: no room for improvement as long as aspects are reweavable
  159. // since the inlined version with wrappers and an to be done annotation to keep
  160. // inline state will be garbaged due to reweavable impl
  161. if (memberView != null && isAdviceMethod()) {
  162. if (enclosingClass.getType().isAnnotationStyleAspect()) {
  163. //TODO we could check for @Around advice as well
  164. this.canInline = false;
  165. }
  166. }
  167. }
  168. private int calculateMaxLocals() {
  169. int ret = 0;
  170. if (!Modifier.isStatic(accessFlags)) ret++;
  171. for (int i = 0, len = argumentTypes.length; i < len; i++) {
  172. ret += argumentTypes[i].getSize();
  173. }
  174. return ret;
  175. }
  176. private Method savedMethod = null;
  177. // build from an existing method, lazy build saves most work for initialization
  178. public LazyMethodGen(Method m, LazyClassGen enclosingClass) {
  179. savedMethod = m;
  180. this.enclosingClass = enclosingClass;
  181. if (!(m.isAbstract() || m.isNative()) && m.getCode() == null) {
  182. throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass);
  183. }
  184. if ((m.isAbstract() || m.isNative()) && m.getCode() != null) {
  185. throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass);
  186. }
  187. this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m);
  188. this.accessFlags = m.getModifiers();
  189. this.name = m.getName();
  190. // @AJ advice are not inlined by default since requires further analysis
  191. // and weaving ordering control
  192. // TODO AV - improve - note: no room for improvement as long as aspects are reweavable
  193. // since the inlined version with wrappers and an to be done annotation to keep
  194. // inline state will be garbaged due to reweavable impl
  195. if (memberView != null && isAdviceMethod()) {
  196. if (enclosingClass.getType().isAnnotationStyleAspect()) {
  197. //TODO we could check for @Around advice as well
  198. this.canInline = false;
  199. }
  200. }
  201. }
  202. public LazyMethodGen(BcelMethod m,LazyClassGen enclosingClass) {
  203. savedMethod = m.getMethod();
  204. this.enclosingClass = enclosingClass;
  205. if (!(m.isAbstract() || m.isNative()) && savedMethod.getCode() == null) {
  206. throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass);
  207. }
  208. if ((m.isAbstract() || m.isNative()) && savedMethod.getCode() != null) {
  209. throw new RuntimeException("bad abstract method with code: " + m + " on " + enclosingClass);
  210. }
  211. //this.memberView = new BcelMethod(enclosingClass.getBcelObjectType(), m);
  212. this.memberView = m;
  213. this.accessFlags = savedMethod.getModifiers();
  214. this.name = m.getName();
  215. // @AJ advice are not inlined by default since requires further analysis
  216. // and weaving ordering control
  217. // TODO AV - improve - note: no room for improvement as long as aspects are reweavable
  218. // since the inlined version with wrappers and an to be done annotation to keep
  219. // inline state will be garbaged due to reweavable impl
  220. if (memberView != null && isAdviceMethod()) {
  221. if (enclosingClass.getType().isAnnotationStyleAspect()) {
  222. //TODO we could check for @Around advice as well
  223. this.canInline = false;
  224. }
  225. }
  226. }
  227. public boolean hasDeclaredLineNumberInfo() {
  228. return (memberView != null && memberView.hasDeclarationLineNumberInfo());
  229. }
  230. public int getDeclarationLineNumber() {
  231. if (hasDeclaredLineNumberInfo()) {
  232. return memberView.getDeclarationLineNumber();
  233. } else {
  234. return -1;
  235. }
  236. }
  237. public int getDeclarationOffset() {
  238. if (hasDeclaredLineNumberInfo()) {
  239. return memberView.getDeclarationOffset();
  240. } else {
  241. return 0;
  242. }
  243. }
  244. public void addAnnotation(AnnotationX ax) {
  245. initialize();
  246. if (memberView==null) {
  247. // If member view is null, we manage them in newAnnotations
  248. if (newAnnotations==null) newAnnotations = new ArrayList();
  249. newAnnotations.add(ax);
  250. } else {
  251. memberView.addAnnotation(ax);
  252. }
  253. }
  254. public boolean hasAnnotation(UnresolvedType annotationTypeX) {
  255. initialize();
  256. if (memberView==null) {
  257. // Check local annotations first
  258. if (newAnnotations!=null) {
  259. for (Iterator iter = newAnnotations.iterator(); iter.hasNext();) {
  260. AnnotationX element = (AnnotationX) iter.next();
  261. if (element.getBcelAnnotation().getTypeName().equals(annotationTypeX.getName())) return true;
  262. }
  263. }
  264. memberView = new BcelMethod(getEnclosingClass().getBcelObjectType(), getMethod());
  265. return memberView.hasAnnotation(annotationTypeX);
  266. }
  267. return memberView.hasAnnotation(annotationTypeX);
  268. }
  269. private void initialize() {
  270. if (returnType != null) return;
  271. //System.err.println("initializing: " + getName() + ", " + enclosingClass.getName() + ", " + returnType + ", " + savedMethod);
  272. MethodGen gen = null;
  273. try {
  274. gen = new MethodGen(savedMethod, enclosingClass.getName(), enclosingClass.getConstantPool(),true);
  275. } catch (RuntimeException t) {
  276. System.err.println(getName());
  277. throw t;
  278. }
  279. this.returnType = gen.getReturnType();
  280. this.argumentTypes = gen.getArgumentTypes();
  281. this.declaredExceptions = gen.getExceptions();
  282. this.attributes = gen.getAttributes();
  283. //this.annotations = gen.getAnnotations();
  284. this.maxLocals = gen.getMaxLocals();
  285. // this.returnType = BcelWorld.makeBcelType(memberView.getReturnType());
  286. // this.argumentTypes = BcelWorld.makeBcelTypes(memberView.getParameterTypes());
  287. //
  288. // this.declaredExceptions = UnresolvedType.getNames(memberView.getExceptions()); //gen.getExceptions();
  289. // this.attributes = new Attribute[0]; //gen.getAttributes();
  290. // this.maxLocals = savedMethod.getCode().getMaxLocals();
  291. if (gen.isAbstract() || gen.isNative()) {
  292. body = null;
  293. } else {
  294. //body = new InstructionList(savedMethod.getCode().getCode());
  295. body = gen.getInstructionList();
  296. unpackHandlers(gen);
  297. ensureAllLineNumberSetup(gen);
  298. highestLineNumber = gen.getHighestlinenumber();
  299. }
  300. assertGoodBody();
  301. //System.err.println("initialized: " + this.getClassName() + "." + this.getName());
  302. }
  303. // XXX we're relying on the javac promise I've just made up that we won't have an early exception
  304. // in the list mask a later exception: That is, for two exceptions E and F,
  305. // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So when we add F,
  306. // we add it on the _OUTSIDE_ of any handlers that share starts or ends with it.
  307. // with that in mind, we merrily go adding ranges for exceptions.
  308. private void unpackHandlers(MethodGen gen) {
  309. CodeExceptionGen[] exns = gen.getExceptionHandlers();
  310. if (exns != null) {
  311. int len = exns.length;
  312. // if (len > 0) hasExceptionHandlers = true;
  313. int priority = len - 1;
  314. for (int i = 0; i < len; i++, priority--) {
  315. CodeExceptionGen exn = exns[i];
  316. InstructionHandle start =
  317. Range.genStart(
  318. body,
  319. getOutermostExceptionStart(exn.getStartPC()));
  320. InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC()));
  321. // this doesn't necessarily handle overlapping correctly!!!
  322. ExceptionRange er =
  323. new ExceptionRange(
  324. body,
  325. exn.getCatchType() == null
  326. ? null
  327. : BcelWorld.fromBcel(exn.getCatchType()),
  328. priority);
  329. er.associateWithTargets(start, end, exn.getHandlerPC());
  330. exn.setStartPC(null); // also removes from target
  331. exn.setEndPC(null); // also removes from target
  332. exn.setHandlerPC(null); // also removes from target
  333. }
  334. gen.removeExceptionHandlers();
  335. }
  336. }
  337. private InstructionHandle getOutermostExceptionStart(InstructionHandle ih) {
  338. while (true) {
  339. if (ExceptionRange.isExceptionStart(ih.getPrev())) {
  340. ih = ih.getPrev();
  341. } else {
  342. return ih;
  343. }
  344. }
  345. }
  346. private InstructionHandle getOutermostExceptionEnd(InstructionHandle ih) {
  347. while (true) {
  348. if (ExceptionRange.isExceptionEnd(ih.getNext())) {
  349. ih = ih.getNext();
  350. } else {
  351. return ih;
  352. }
  353. }
  354. }
  355. /**
  356. * On entry to this method we have a method whose instruction stream contains a few instructions
  357. * that have line numbers assigned to them (LineNumberTags). The aim is to ensure every instruction
  358. * has the right line number. This is necessary because some of them may be extracted out into other
  359. * methods - and it'd be useful for them to maintain the source line number for debugging.
  360. */
  361. private void ensureAllLineNumberSetup(MethodGen gen) {
  362. LineNumberTag lr = null;
  363. boolean skip = false;
  364. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  365. InstructionTargeter[] targeters = ih.getTargeters();
  366. skip = false;
  367. if (targeters != null) {
  368. for (int i = targeters.length - 1; i >= 0; i--) {
  369. InstructionTargeter targeter = targeters[i];
  370. if (targeter instanceof LineNumberTag) {
  371. lr = (LineNumberTag) targeter;
  372. skip=true;
  373. }
  374. }
  375. }
  376. if (lr != null && !skip) {
  377. ih.addTargeter(lr);
  378. }
  379. }
  380. }
  381. // ===============
  382. public int allocateLocal(Type type) {
  383. return allocateLocal(type.getSize());
  384. }
  385. public int allocateLocal(int slots) {
  386. int max = getMaxLocals();
  387. setMaxLocals(max + slots);
  388. return max;
  389. }
  390. public Method getMethod() {
  391. if (savedMethod != null) return savedMethod; //??? this relies on gentle treatment of constant pool
  392. try {
  393. MethodGen gen = pack();
  394. savedMethod = gen.getMethod();
  395. return savedMethod;
  396. } catch (ClassGenException e) {
  397. enclosingClass.getBcelObjectType().getResolvedTypeX().getWorld().showMessage(
  398. IMessage.ERROR,
  399. WeaverMessages.format(WeaverMessages.PROBLEM_GENERATING_METHOD,
  400. this.getClassName(),
  401. this.getName(),
  402. e.getMessage()),
  403. this.getMemberView() == null ? null : this.getMemberView().getSourceLocation(), null);
  404. // throw e; PR 70201.... let the normal problem reporting infrastructure deal with this rather than crashing.
  405. body = null;
  406. MethodGen gen = pack();
  407. return gen.getMethod();
  408. }
  409. }
  410. public void markAsChanged() {
  411. if (wasNewPacked) {
  412. throw new RuntimeException("Already packed method is being re-modified: "+getClassName()+" "+toShortString());
  413. }
  414. initialize();
  415. savedMethod = null;
  416. }
  417. // =============================
  418. public String toString() {
  419. BcelObjectType bot = enclosingClass.getBcelObjectType();
  420. WeaverVersionInfo weaverVersion = (bot==null?WeaverVersionInfo.CURRENT:bot.getWeaverVersionAttribute());
  421. return toLongString(weaverVersion);
  422. }
  423. public String toShortString() {
  424. String access = org.aspectj.apache.bcel.classfile.Utility.accessToString(getAccessFlags());
  425. StringBuffer buf = new StringBuffer();
  426. if (!access.equals("")) {
  427. buf.append(access);
  428. buf.append(" ");
  429. }
  430. buf.append(
  431. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  432. getReturnType().getSignature(),
  433. true));
  434. buf.append(" ");
  435. buf.append(getName());
  436. buf.append("(");
  437. {
  438. int len = argumentTypes.length;
  439. if (len > 0) {
  440. buf.append(
  441. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  442. argumentTypes[0].getSignature(),
  443. true));
  444. for (int i = 1; i < argumentTypes.length; i++) {
  445. buf.append(", ");
  446. buf.append(
  447. org.aspectj.apache.bcel.classfile.Utility.signatureToString(
  448. argumentTypes[i].getSignature(),
  449. true));
  450. }
  451. }
  452. }
  453. buf.append(")");
  454. {
  455. int len = declaredExceptions != null ? declaredExceptions.length : 0;
  456. if (len > 0) {
  457. buf.append(" throws ");
  458. buf.append(declaredExceptions[0]);
  459. for (int i = 1; i < declaredExceptions.length; i++) {
  460. buf.append(", ");
  461. buf.append(declaredExceptions[i]);
  462. }
  463. }
  464. }
  465. return buf.toString();
  466. }
  467. public String toLongString(WeaverVersionInfo weaverVersion) {
  468. ByteArrayOutputStream s = new ByteArrayOutputStream();
  469. print(new PrintStream(s),weaverVersion);
  470. return new String(s.toByteArray());
  471. }
  472. public void print(WeaverVersionInfo weaverVersion) {
  473. print(System.out,weaverVersion);
  474. }
  475. public void print(PrintStream out, WeaverVersionInfo weaverVersion) {
  476. out.print(" " + toShortString());
  477. printAspectAttributes(out,weaverVersion);
  478. InstructionList body = getBody();
  479. if (body == null) {
  480. out.println(";");
  481. return;
  482. }
  483. out.println(":");
  484. new BodyPrinter(out).run();
  485. out.println(" end " + toShortString());
  486. }
  487. private void printAspectAttributes(PrintStream out, WeaverVersionInfo weaverVersion) {
  488. ISourceContext context = null;
  489. if (enclosingClass != null && enclosingClass.getType() != null) {
  490. context = enclosingClass.getType().getSourceContext();
  491. }
  492. List as = BcelAttributes.readAjAttributes(getClassName(), (Attribute[])attributes.toArray(new Attribute[]{}), context,null,weaverVersion);
  493. if (! as.isEmpty()) {
  494. out.println(" " + as.get(0)); // XXX assuming exactly one attribute, munger...
  495. }
  496. }
  497. private class BodyPrinter {
  498. Map prefixMap = new HashMap();
  499. Map suffixMap = new HashMap();
  500. Map labelMap = new HashMap();
  501. InstructionList body;
  502. PrintStream out;
  503. ConstantPool pool;
  504. List ranges;
  505. BodyPrinter(PrintStream out) {
  506. this.pool = enclosingClass.getConstantPool();
  507. this.body = getBody();
  508. this.out = out;
  509. }
  510. void run() {
  511. //killNops();
  512. assignLabels();
  513. print();
  514. }
  515. // label assignment
  516. void assignLabels() {
  517. LinkedList exnTable = new LinkedList();
  518. String pendingLabel = null;
  519. // boolean hasPendingTargeters = false;
  520. int lcounter = 0;
  521. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  522. InstructionTargeter[] targeters = ih.getTargeters();
  523. if (targeters != null) {
  524. for (int i = targeters.length - 1; i >= 0; i--) {
  525. InstructionTargeter t = targeters[i];
  526. if (t instanceof ExceptionRange) {
  527. // assert isRangeHandle(h);
  528. ExceptionRange r = (ExceptionRange) t;
  529. if (r.getStart() == ih) {
  530. insertHandler(r, exnTable);
  531. }
  532. } else if (t instanceof InstructionBranch) {
  533. if (pendingLabel == null) {
  534. pendingLabel = "L" + lcounter++;
  535. }
  536. } else {
  537. // assert isRangeHandle(h)
  538. }
  539. }
  540. }
  541. if (pendingLabel != null) {
  542. labelMap.put(ih, pendingLabel);
  543. if (! Range.isRangeHandle(ih)) {
  544. pendingLabel = null;
  545. }
  546. }
  547. }
  548. int ecounter = 0;
  549. for (Iterator i = exnTable.iterator(); i.hasNext();) {
  550. ExceptionRange er = (ExceptionRange) i.next();
  551. String exceptionLabel = "E" + ecounter++;
  552. labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel);
  553. labelMap.put(er.getHandler(), exceptionLabel);
  554. }
  555. }
  556. // printing
  557. void print() {
  558. int depth = 0;
  559. int currLine = -1;
  560. bodyPrint:
  561. for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) {
  562. if (Range.isRangeHandle(ih)) {
  563. Range r = Range.getRange(ih);
  564. // don't print empty ranges, that is, ranges who contain no actual instructions
  565. for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) {
  566. if (xx == r.getEnd()) continue bodyPrint;
  567. }
  568. // doesn't handle nested: if (r.getStart().getNext() == r.getEnd()) continue;
  569. if (r.getStart() == ih) {
  570. printRangeString(r, depth++);
  571. } else {
  572. if (r.getEnd() != ih) throw new RuntimeException("bad");
  573. printRangeString(r, --depth);
  574. }
  575. } else {
  576. printInstruction(ih, depth);
  577. int line = getLineNumber(ih, currLine);
  578. if (line != currLine) {
  579. currLine = line;
  580. out.println(" (line " + line + ")");
  581. } else {
  582. out.println();
  583. }
  584. }
  585. }
  586. }
  587. void printRangeString(Range r, int depth) {
  588. printDepth(depth);
  589. out.println(getRangeString(r, labelMap));
  590. }
  591. String getRangeString(Range r, Map labelMap) {
  592. if (r instanceof ExceptionRange) {
  593. ExceptionRange er = (ExceptionRange) r;
  594. return er.toString() + " -> " + labelMap.get(er.getHandler());
  595. //
  596. // + " PRI " + er.getPriority();
  597. } else {
  598. return r.toString();
  599. }
  600. }
  601. void printDepth(int depth) {
  602. pad(BODY_INDENT);
  603. while (depth > 0) {
  604. out.print("| ");
  605. depth--;
  606. }
  607. }
  608. void printLabel(String s, int depth) {
  609. int space = Math.max(CODE_INDENT - depth * 2, 0);
  610. if (s == null) {
  611. pad(space);
  612. } else {
  613. space = Math.max(space - (s.length() + 2), 0);
  614. pad(space);
  615. out.print(s);
  616. out.print(": ");
  617. }
  618. }
  619. void printInstruction(InstructionHandle h, int depth) {
  620. printDepth(depth);
  621. printLabel((String) labelMap.get(h), depth);
  622. Instruction inst = h.getInstruction();
  623. if (inst.isConstantPoolInstruction()) {
  624. out.print(Constants.OPCODE_NAMES[inst.opcode].toUpperCase());
  625. out.print(" ");
  626. out.print(pool.constantToString(pool.getConstant(inst.getIndex())));
  627. } else if (inst instanceof InstructionSelect) {
  628. InstructionSelect sinst = (InstructionSelect) inst;
  629. out.println(Constants.OPCODE_NAMES[sinst.opcode].toUpperCase());
  630. int[] matches = sinst.getMatchs();
  631. InstructionHandle[] targets = sinst.getTargets();
  632. InstructionHandle defaultTarget = sinst.getTarget();
  633. for (int i = 0, len = matches.length; i < len; i++) {
  634. printDepth(depth);
  635. printLabel(null, depth);
  636. out.print(" ");
  637. out.print(matches[i]);
  638. out.print(": \t");
  639. out.println(labelMap.get(targets[i]));
  640. }
  641. printDepth(depth);
  642. printLabel(null, depth);
  643. out.print(" ");
  644. out.print("default: \t");
  645. out.print(labelMap.get(defaultTarget));
  646. } else if (inst instanceof InstructionBranch) {
  647. InstructionBranch brinst = (InstructionBranch) inst;
  648. out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase());
  649. out.print(" ");
  650. out.print(labelMap.get(brinst.getTarget()));
  651. } else if (inst.isLocalVariableInstruction()) {
  652. //LocalVariableInstruction lvinst = (LocalVariableInstruction) inst;
  653. out.print(inst.toString(false).toUpperCase());
  654. int index = inst.getIndex();
  655. LocalVariableTag tag = getLocalVariableTag(h, index);
  656. if (tag != null) {
  657. out.print(" // ");
  658. out.print(tag.getType());
  659. out.print(" ");
  660. out.print(tag.getName());
  661. }
  662. } else {
  663. out.print(inst.toString(false).toUpperCase());
  664. }
  665. }
  666. static final int BODY_INDENT = 4;
  667. static final int CODE_INDENT = 16;
  668. void pad(int size) {
  669. for (int i = 0; i < size; i++) {
  670. out.print(" ");
  671. }
  672. }
  673. }
  674. static LocalVariableTag getLocalVariableTag(
  675. InstructionHandle ih,
  676. int index)
  677. {
  678. InstructionTargeter[] targeters = ih.getTargeters();
  679. if (targeters == null) return null;
  680. for (int i = targeters.length - 1; i >= 0; i--) {
  681. InstructionTargeter t = targeters[i];
  682. if (t instanceof LocalVariableTag) {
  683. LocalVariableTag lvt = (LocalVariableTag) t;
  684. if (lvt.getSlot() == index) return lvt;
  685. }
  686. }
  687. return null;
  688. }
  689. static int getLineNumber(
  690. InstructionHandle ih,
  691. int prevLine)
  692. {
  693. InstructionTargeter[] targeters = ih.getTargeters();
  694. if (targeters == null) return prevLine;
  695. for (int i = targeters.length - 1; i >= 0; i--) {
  696. InstructionTargeter t = targeters[i];
  697. if (t instanceof LineNumberTag) {
  698. return ((LineNumberTag)t).getLineNumber();
  699. }
  700. }
  701. return prevLine;
  702. }
  703. public boolean isStatic() {
  704. return Modifier.isStatic(getAccessFlags());
  705. }
  706. public boolean isAbstract() {
  707. return Modifier.isAbstract(getAccessFlags());
  708. }
  709. public boolean isBridgeMethod() {
  710. return (getAccessFlags() & Constants.ACC_BRIDGE) != 0;
  711. }
  712. public void addExceptionHandler(
  713. InstructionHandle start,
  714. InstructionHandle end,
  715. InstructionHandle handlerStart,
  716. ObjectType catchType,
  717. boolean highPriority) {
  718. InstructionHandle start1 = Range.genStart(body, start);
  719. InstructionHandle end1 = Range.genEnd(body, end);
  720. ExceptionRange er =
  721. new ExceptionRange(body, (catchType==null?null:BcelWorld.fromBcel(catchType)), highPriority);
  722. er.associateWithTargets(start1, end1, handlerStart);
  723. }
  724. public int getAccessFlags() {
  725. return accessFlags;
  726. }
  727. public int getAccessFlagsWithoutSynchronized() {
  728. if (isSynchronized()) return accessFlags - Modifier.SYNCHRONIZED;
  729. return accessFlags;
  730. }
  731. public boolean isSynchronized() {
  732. return (accessFlags & Modifier.SYNCHRONIZED)!=0;
  733. }
  734. public void setAccessFlags(int newFlags) {
  735. this.accessFlags = newFlags;
  736. }
  737. public Type[] getArgumentTypes() {
  738. initialize();
  739. return argumentTypes;
  740. }
  741. public LazyClassGen getEnclosingClass() {
  742. return enclosingClass;
  743. }
  744. public int getMaxLocals() {
  745. return maxLocals;
  746. }
  747. public String getName() {
  748. return name;
  749. }
  750. public String getGenericReturnTypeSignature() {
  751. if (memberView == null) {
  752. return getReturnType().getSignature();
  753. } else {
  754. return memberView.getGenericReturnType().getSignature();
  755. }
  756. }
  757. public Type getReturnType() {
  758. initialize();
  759. return returnType;
  760. }
  761. public void setMaxLocals(int maxLocals) {
  762. this.maxLocals = maxLocals;
  763. }
  764. public InstructionList getBody() {
  765. markAsChanged();
  766. return body;
  767. }
  768. public boolean hasBody() {
  769. if (savedMethod != null) return savedMethod.getCode() != null;
  770. return body != null;
  771. }
  772. public List/*Attribute*/ getAttributes() {
  773. return attributes;
  774. }
  775. public String[] getDeclaredExceptions() {
  776. return declaredExceptions;
  777. }
  778. public String getClassName() {
  779. return enclosingClass.getName();
  780. }
  781. // ---- packing!
  782. public MethodGen pack() {
  783. forceSyntheticForAjcMagicMembers();
  784. //killNops();
  785. int flags = getAccessFlags();
  786. if (enclosingClass.getWorld().isJoinpointSynchronizationEnabled() &&
  787. enclosingClass.getWorld().areSynchronizationPointcutsInUse()) {
  788. flags = getAccessFlagsWithoutSynchronized();
  789. }
  790. MethodGen gen =
  791. new MethodGen(
  792. flags,
  793. getReturnType(),
  794. getArgumentTypes(),
  795. null, //getArgumentNames(),
  796. getName(),
  797. getEnclosingClass().getName(),
  798. new InstructionList(),
  799. getEnclosingClass().getConstantPool());
  800. for (int i = 0, len = declaredExceptions.length; i < len; i++) {
  801. gen.addException(declaredExceptions[i]);
  802. }
  803. for (int i = 0, len = attributes.size(); i < len; i++) {
  804. gen.addAttribute((Attribute)attributes.get(i));
  805. }
  806. if (newAnnotations!=null) {
  807. for (Iterator iter = newAnnotations.iterator(); iter.hasNext();) {
  808. AnnotationX element = (AnnotationX) iter.next();
  809. gen.addAnnotation(new AnnotationGen(element.getBcelAnnotation(),gen.getConstantPool(),true));
  810. }
  811. }
  812. if (memberView!=null && memberView.getAnnotations()!=null && memberView.getAnnotations().length!=0) {
  813. AnnotationX[] ans = memberView.getAnnotations();
  814. for (int i = 0, len = ans.length; i < len; i++) {
  815. AnnotationGen a= ans[i].getBcelAnnotation();
  816. gen.addAnnotation(new AnnotationGen(a,gen.getConstantPool(),true));
  817. }
  818. }
  819. if (isSynthetic) {
  820. if (enclosingClass.getWorld().isInJava5Mode()) {
  821. gen.setModifiers(gen.getModifiers() | ACC_SYNTHETIC);
  822. }
  823. // belt and braces, do the attribute even on Java 5 in addition to the modifier flag
  824. ConstantPool cpg = gen.getConstantPool();
  825. int index = cpg.addUtf8("Synthetic");
  826. gen.addAttribute(new Synthetic(index, 0, new byte[0], cpg));
  827. }
  828. if (hasBody()) {
  829. if (this.enclosingClass.getWorld().shouldGoForIt()) {
  830. if (isAdviceMethod() || getName().equals("<clinit>")) {
  831. packBody(gen);
  832. } else {
  833. newPackBody(gen);
  834. }
  835. } else {
  836. packBody(gen);
  837. }
  838. // FINISH OFF CASE/SWITCH !
  839. gen.setMaxLocals();
  840. gen.setMaxStack();
  841. } else {
  842. gen.setInstructionList(null);
  843. }
  844. return gen;
  845. }
  846. private void forceSyntheticForAjcMagicMembers() {
  847. if (NameMangler.isSyntheticMethod(getName(), inAspect())) {
  848. makeSynthetic();
  849. }
  850. }
  851. private boolean inAspect() {
  852. BcelObjectType objectType = enclosingClass.getBcelObjectType();
  853. return (objectType == null ? false : objectType.isAspect());
  854. }
  855. public void makeSynthetic() {
  856. isSynthetic = true;
  857. }
  858. private static class LVPosition {
  859. InstructionHandle start = null;
  860. InstructionHandle end = null;
  861. }
  862. /** fill the newly created method gen with our body,
  863. * inspired by InstructionList.copy()
  864. */
  865. public void packBody(MethodGen gen) {
  866. InstructionList fresh = gen.getInstructionList();
  867. Map map = copyAllInstructionsExceptRangeInstructionsInto(fresh);
  868. // at this point, no rangeHandles are in fresh. Let's use that...
  869. /* Update branch targets and insert various attributes.
  870. * Insert our exceptionHandlers
  871. * into a sorted list, so they can be added in order later.
  872. */
  873. InstructionHandle oldInstructionHandle = getBody().getStart();
  874. InstructionHandle newInstructionHandle = fresh.getStart();
  875. LinkedList exceptionList = new LinkedList();
  876. // map from localvariabletag to instruction handle
  877. Map localVariables = new HashMap();
  878. int currLine = -1;
  879. int lineNumberOffset = (fromFilename == null) ? 0: getEnclosingClass().getSourceDebugExtensionOffset(fromFilename);
  880. while (oldInstructionHandle != null) {
  881. if (map.get(oldInstructionHandle) == null) {
  882. // must be a range instruction since they're the only things we didn't copy across
  883. handleRangeInstruction(oldInstructionHandle, exceptionList);
  884. // just increment ih.
  885. oldInstructionHandle = oldInstructionHandle.getNext();
  886. } else {
  887. // assert map.get(ih) == jh
  888. Instruction oldInstruction = oldInstructionHandle.getInstruction();
  889. Instruction newInstruction = newInstructionHandle.getInstruction();
  890. if (oldInstruction instanceof InstructionBranch) {
  891. handleBranchInstruction(map, oldInstruction, newInstruction);
  892. }
  893. // now deal with line numbers
  894. // and store up info for local variables
  895. InstructionTargeter[] targeters = oldInstructionHandle.getTargeters();
  896. if (targeters != null) {
  897. for (int k = targeters.length - 1; k >= 0; k--) {
  898. InstructionTargeter targeter = targeters[k];
  899. if (targeter instanceof LineNumberTag) {
  900. int line = ((LineNumberTag)targeter).getLineNumber();
  901. if (line != currLine) {
  902. gen.addLineNumber(newInstructionHandle, line + lineNumberOffset);
  903. currLine = line;
  904. }
  905. } else if (targeter instanceof LocalVariableTag) {
  906. LocalVariableTag lvt = (LocalVariableTag) targeter;
  907. LVPosition p = (LVPosition)localVariables.get(lvt);
  908. // If we don't know about it, create a new position and store
  909. // If we do know about it - update its end position
  910. if (p==null) {
  911. LVPosition newp = new LVPosition();
  912. newp.start=newp.end=newInstructionHandle;
  913. localVariables.put(lvt,newp);
  914. } else {
  915. p.end = newInstructionHandle;
  916. }
  917. }
  918. }
  919. }
  920. // now continue
  921. oldInstructionHandle = oldInstructionHandle.getNext();
  922. newInstructionHandle = newInstructionHandle.getNext();
  923. }
  924. }
  925. addExceptionHandlers(gen, map, exceptionList);
  926. addLocalVariables(gen,localVariables);
  927. // JAVAC adds line number tables (with just one entry) to generated accessor methods - this
  928. // keeps some tools that rely on finding at least some form of linenumbertable happy.
  929. // Let's check if we have one - if we don't then let's add one.
  930. // TODO Could be made conditional on whether line debug info is being produced
  931. if (gen.getLineNumbers().length==0) {
  932. gen.addLineNumber(gen.getInstructionList().getStart(),1);
  933. }
  934. }
  935. /*
  936. * Andys version
  937. */
  938. public void newPackBody(MethodGen gen) {
  939. InstructionList theBody = getBody();
  940. InstructionHandle iHandle = theBody.getStart();
  941. int currLine = -1;
  942. int lineNumberOffset = (fromFilename == null) ? 0: getEnclosingClass().getSourceDebugExtensionOffset(fromFilename);
  943. Map localVariables = new HashMap();
  944. LinkedList exceptionList = new LinkedList();
  945. Set forDeletion = new HashSet();
  946. Set branchInstructions = new HashSet();
  947. // OPTIMIZE sort out in here: getRange()/insertHandler() and type of exceptionList
  948. while (iHandle != null) {
  949. Instruction inst = iHandle.getInstruction();
  950. InstructionHandle nextInst = iHandle.getNext();
  951. // OPTIMIZE remove this instructionhandle as it now points to nowhere?
  952. if (inst == Range.RANGEINSTRUCTION) {
  953. Range r = Range.getRange(iHandle);
  954. if (r instanceof ExceptionRange) {
  955. ExceptionRange er = (ExceptionRange) r;
  956. if (er.getStart() == iHandle) {
  957. if (!er.isEmpty()){
  958. // order is important, insert handlers in order of start
  959. insertHandler(er, exceptionList);
  960. }
  961. }
  962. }
  963. forDeletion.add(iHandle);
  964. } else {
  965. if (inst instanceof InstructionBranch) {
  966. branchInstructions.add(iHandle);
  967. }
  968. InstructionTargeter[] targeters = iHandle.getTargeters();
  969. if (targeters != null) {
  970. for (int k = targeters.length - 1; k >= 0; k--) {
  971. InstructionTargeter targeter = targeters[k];
  972. if (targeter instanceof LineNumberTag) {
  973. int line = ((LineNumberTag)targeter).getLineNumber();
  974. if (line != currLine) {
  975. gen.addLineNumber(iHandle, line + lineNumberOffset);
  976. currLine = line;
  977. }
  978. } else if (targeter instanceof LocalVariableTag) {
  979. LocalVariableTag lvt = (LocalVariableTag) targeter;
  980. LVPosition p = (LVPosition)localVariables.get(lvt);
  981. // If we don't know about it, create a new position and store
  982. // If we do know about it - update its end position
  983. if (p==null) {
  984. LVPosition newp = new LVPosition();
  985. newp.start=newp.end=iHandle;
  986. localVariables.put(lvt,newp);
  987. } else {
  988. p.end = iHandle;
  989. }
  990. }
  991. }
  992. }
  993. }
  994. iHandle = iHandle.getNext();
  995. }
  996. for (Iterator iterator = branchInstructions.iterator(); iterator.hasNext();) {
  997. BranchHandle iBranch = (BranchHandle) iterator.next();
  998. handleBranchInstruction(iBranch,forDeletion);
  999. }
  1000. // now add exception handlers
  1001. for (Iterator iter = exceptionList.iterator(); iter.hasNext();) {
  1002. ExceptionRange r = (ExceptionRange) iter.next();
  1003. if (r.isEmpty()) continue;
  1004. gen.addExceptionHandler(
  1005. jumpForward(r.getRealStart(),forDeletion),
  1006. jumpForward(r.getRealEnd(),forDeletion),
  1007. jumpForward(r.getHandler(),forDeletion),
  1008. (r.getCatchType() == null)
  1009. ? null
  1010. : (ObjectType) BcelWorld.makeBcelType(r.getCatchType()));
  1011. }
  1012. for (Iterator iterator = forDeletion.iterator(); iterator.hasNext();) {
  1013. try {
  1014. theBody.delete((InstructionHandle)iterator.next());
  1015. } catch (TargetLostException e) {
  1016. // TODO Auto-generated catch block
  1017. e.printStackTrace();
  1018. }
  1019. }
  1020. gen.setInstructionList(theBody);
  1021. addLocalVariables(gen,localVariables);
  1022. // JAVAC adds line number tables (with just one entry) to generated accessor methods - this
  1023. // keeps some tools that rely on finding at least some form of linenumbertable happy.
  1024. // Let's check if we have one - if we don't then let's add one.
  1025. // TODO Could be made conditional on whether line debug info is being produced
  1026. if (gen.getLineNumbers().length==0) {
  1027. gen.addLineNumber(gen.getInstructionList().getStart(),1);
  1028. }
  1029. wasNewPacked = true;
  1030. }
  1031. private void addLocalVariables(MethodGen gen, Map localVariables) {
  1032. // now add local variables
  1033. gen.removeLocalVariables();
  1034. // this next iteration _might_ be overkill, but we had problems with
  1035. // bcel before with duplicate local variables. Now that we're patching
  1036. // bcel we should be able to do without it if we're paranoid enough
  1037. // through the rest of the compiler.
  1038. Map duplicatedLocalMap = new HashMap();
  1039. for (Iterator iter = localVariables.keySet().iterator(); iter.hasNext(); ) {
  1040. LocalVariableTag tag = (LocalVariableTag) iter.next();
  1041. // have we already added one with the same slot number and start location?
  1042. // if so, just continue.
  1043. LVPosition lvpos = (LVPosition)localVariables.get(tag);
  1044. InstructionHandle start = lvpos.start;
  1045. Set slots = (Set) duplicatedLocalMap.get(start);
  1046. if (slots == null) {
  1047. slots = new HashSet();
  1048. duplicatedLocalMap.put(start, slots);
  1049. } else if (slots.contains(new Integer(tag.getSlot()))) {
  1050. // we already have a var starting at this tag with this slot
  1051. continue;
  1052. }
  1053. slots.add(new Integer(tag.getSlot()));
  1054. Type t = tag.getRealType();
  1055. if (t==null) {
  1056. t = BcelWorld.makeBcelType(UnresolvedType.forSignature(tag.getType()));
  1057. }
  1058. gen.addLocalVariable(
  1059. tag.getName(),
  1060. t,
  1061. tag.getSlot(),(InstructionHandle) start,(InstructionHandle) lvpos.end);
  1062. }
  1063. }
  1064. private void addExceptionHandlers(MethodGen gen, Map map, LinkedList exnList) {
  1065. // now add exception handlers
  1066. for (Iterator iter = exnList.iterator(); iter.hasNext();) {
  1067. ExceptionRange r = (ExceptionRange) iter.next();
  1068. if (r.isEmpty()) continue;
  1069. gen.addExceptionHandler(
  1070. remap(r.getRealStart(), map),
  1071. remap(r.getRealEnd(), map),
  1072. remap(r.getHandler(), map),
  1073. (r.getCatchType() == null)
  1074. ? null
  1075. : (ObjectType) BcelWorld.makeBcelType(r.getCatchType()));
  1076. }
  1077. }
  1078. private void handleBranchInstruction(Map map, Instruction oldInstruction, Instruction newInstruction) {
  1079. InstructionBranch oldBranchInstruction = (InstructionBranch) oldInstruction;
  1080. InstructionBranch newBranchInstruction = (InstructionBranch) newInstruction;
  1081. InstructionHandle oldTarget = oldBranchInstruction.getTarget(); // old target
  1082. // New target is in hash map
  1083. newBranchInstruction.setTarget(remap(oldTarget, map));
  1084. if (oldBranchInstruction instanceof InstructionSelect) {
  1085. // Either LOOKUPSWITCH or TABLESWITCH
  1086. InstructionHandle[] oldTargets = ((InstructionSelect) oldBranchInstruction).getTargets();
  1087. InstructionHandle[] newTargets = ((InstructionSelect) newBranchInstruction).getTargets();
  1088. for (int k = oldTargets.length - 1; k >= 0; k--) {
  1089. // Update all targets
  1090. newTargets[k] = remap(oldTargets[k], map);
  1091. newTargets[k].addTargeter(newBranchInstruction);
  1092. }
  1093. }
  1094. }
  1095. private InstructionHandle jumpForward(InstructionHandle t,Set handlesForDeletion) {
  1096. InstructionHandle target = t;
  1097. if (handlesForDeletion.contains(target)) {
  1098. do {
  1099. target = target.getNext();
  1100. } while (handlesForDeletion.contains(target));
  1101. }
  1102. return target;
  1103. }
  1104. private void handleBranchInstruction(BranchHandle branchHandle, Set handlesForDeletion) {
  1105. InstructionBranch branchInstruction = (InstructionBranch) branchHandle.getInstruction();
  1106. InstructionHandle target = branchInstruction.getTarget(); // old target
  1107. if (handlesForDeletion.contains(target)) {
  1108. do {
  1109. target = target.getNext();
  1110. } while (handlesForDeletion.contains(target));
  1111. branchInstruction.setTarget(target);
  1112. }
  1113. if (branchInstruction instanceof InstructionSelect) {
  1114. // Either LOOKUPSWITCH or TABLESWITCH
  1115. InstructionHandle[] targets = ((InstructionSelect)branchInstruction).getTargets();
  1116. for (int k = targets.length - 1; k >= 0; k--) {
  1117. InstructionHandle oneTarget = targets[k];
  1118. if (handlesForDeletion.contains(oneTarget)) {
  1119. do {
  1120. oneTarget = oneTarget.getNext();
  1121. } while (handlesForDeletion.contains(oneTarget));
  1122. branchInstruction.setTarget(oneTarget);
  1123. oneTarget.addTargeter(branchInstruction);
  1124. }
  1125. }
  1126. }
  1127. }
  1128. private void handleRangeInstruction(InstructionHandle ih, LinkedList exnList) {
  1129. // we're a range instruction
  1130. Range r = Range.getRange(ih);
  1131. if (r instanceof ExceptionRange) {
  1132. ExceptionRange er = (ExceptionRange) r;
  1133. if (er.getStart() == ih) {
  1134. //System.err.println("er " + er);
  1135. if (!er.isEmpty()){
  1136. // order is important, insert handlers in order of start
  1137. insertHandler(er, exnList);
  1138. }
  1139. }
  1140. } else {
  1141. // we must be a shadow range or something equally useless,
  1142. // so forget about doing anything
  1143. }
  1144. }
  1145. /* Make copies of all instructions, append them to the new list
  1146. * and associate old instruction references with the new ones, i.e.,
  1147. * a 1:1 mapping.
  1148. */
  1149. private Map copyAllInstructionsExceptRangeInstructionsInto(InstructionList intoList) {
  1150. HashMap map = new HashMap();
  1151. for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) {
  1152. if (Range.isRangeHandle(ih)) {
  1153. continue;
  1154. }
  1155. Instruction i = ih.getInstruction();
  1156. Instruction c = Utility.copyInstruction(i);
  1157. if (c instanceof InstructionBranch)
  1158. map.put(ih, intoList.append((InstructionBranch) c));
  1159. else
  1160. map.put(ih, intoList.append(c));
  1161. }
  1162. return map;
  1163. }
  1164. /** This procedure should not currently be used.
  1165. */
  1166. // public void killNops() {
  1167. // InstructionHandle curr = body.getStart();
  1168. // while (true) {
  1169. // if (curr == null) break;
  1170. // InstructionHandle next = curr.getNext();
  1171. // if (curr.getInstruction() instanceof NOP) {
  1172. // InstructionTargeter[] targeters = curr.getTargeters();
  1173. // if (targeters != null) {
  1174. // for (int i = 0, len = targeters.length; i < len; i++) {
  1175. // InstructionTargeter targeter = targeters[i];
  1176. // targeter.updateTarget(curr, next);
  1177. // }
  1178. // }
  1179. // try {
  1180. // body.delete(curr);
  1181. // } catch (TargetLostException e) {
  1182. // }
  1183. // }
  1184. // curr = next;
  1185. // }
  1186. // }
  1187. private static InstructionHandle fNext(InstructionHandle ih) {
  1188. while (true) {
  1189. if (ih.getInstruction()==Range.RANGEINSTRUCTION) ih = ih.getNext();
  1190. else return ih;
  1191. }
  1192. }
  1193. private static InstructionHandle remap(InstructionHandle ih, Map map) {
  1194. while (true) {
  1195. Object ret = map.get(ih);
  1196. if (ret == null) {
  1197. ih = ih.getNext();
  1198. } else {
  1199. return (InstructionHandle) ret;
  1200. }
  1201. }
  1202. }
  1203. // Update to all these comments, ASC 11-01-2005
  1204. // The right thing to do may be to do more with priorities as
  1205. // we create new exception handlers, but that is a relatively
  1206. // complex task. In the meantime, just taking account of the
  1207. // priority here enables a couple of bugs to be fixed to do
  1208. // with using return or break in code that contains a finally
  1209. // block (pr78021,pr79554).
  1210. // exception ordering.
  1211. // What we should be doing is dealing with priority inversions way earlier than we are
  1212. // and counting on the tree structure. In which case, the below code is in fact right.
  1213. // XXX THIS COMMENT BELOW IS CURRENTLY WRONG.
  1214. // An exception A preceeds an exception B in the exception table iff:
  1215. // * A and B were in the original method, and A preceeded B in the original exception table
  1216. // * If A has a higher priority than B, than it preceeds B.
  1217. // * If A and B have the same priority, then the one whose START happens EARLIEST has LEAST priority.
  1218. // in short, the outermost exception has least priority.
  1219. // we implement this with a LinkedList. We could possibly implement this with a java.util.SortedSet,
  1220. // but I don't trust the only implementation, TreeSet, to do the right thing.
  1221. /* private */ static void insertHandler(ExceptionRange fresh, LinkedList l) {
  1222. // Old implementation, simply: l.add(0,fresh);
  1223. for (ListIterator iter = l.listIterator(); iter.hasNext();) {
  1224. ExceptionRange r = (ExceptionRange) iter.next();
  1225. // int freal = fresh.getRealStart().getPosition();
  1226. // int rreal = r.getRealStart().getPosition();
  1227. if (fresh.getPriority() >= r.getPriority()) {
  1228. iter.previous();
  1229. iter.add(fresh);
  1230. return;
  1231. }
  1232. }
  1233. // we have reached the end
  1234. l.add(fresh);
  1235. }
  1236. public boolean isPrivate() {
  1237. return Modifier.isPrivate(getAccessFlags());
  1238. }
  1239. public boolean isProtected() {
  1240. return Modifier.isProtected(getAccessFlags());
  1241. }
  1242. public boolean isDefault() {
  1243. return !(isProtected() || isPrivate() || isPublic());
  1244. }
  1245. public boolean isPublic() {
  1246. return Modifier.isPublic(getAccessFlags());
  1247. }
  1248. // ----
  1249. /** A good body is a body with the following properties:
  1250. *
  1251. * <ul>
  1252. * <li> For each branch instruction S in body, target T of S is in body.
  1253. * <li> For each branch instruction S in body, target T of S has S as a targeter.
  1254. * <li> For each instruction T in body, for each branch instruction S that is a
  1255. * targeter of T, S is in body.
  1256. * <li> For each non-range-handle instruction T in body, for each instruction S
  1257. * that is a targeter of T, S is
  1258. * either a branch instruction, an exception range or a tag
  1259. * <li> For each range-handle instruction T in body, there is exactly one targeter S
  1260. * that is a range.
  1261. * <li> For each range-handle instruction T in body, the range R targeting T is in body.
  1262. * <li> For each instruction T in body, for each exception range R targeting T, R is
  1263. * in body.
  1264. * <li> For each exception range R in body, let T := R.handler. T is in body, and R is one
  1265. * of T's targeters
  1266. * <li> All ranges are properly nested: For all ranges Q and R, if Q.start preceeds
  1267. * R.start, then R.end preceeds Q.end.
  1268. * </ul>
  1269. *
  1270. * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and
  1271. * any InstructionHandle stored in a field of R (such as an exception handle) is in body".
  1272. */
  1273. public void assertGoodBody() {
  1274. if (true) return; // only enable for debugging, consider using cheaper toString()
  1275. assertGoodBody(getBody(), toString()); //definingType.getNameAsIdentifier() + "." + getName()); //toString());
  1276. }
  1277. public static void assertGoodBody(InstructionList il, String from) {
  1278. if (true) return; // only to be enabled for debugging
  1279. if (il == null) return;
  1280. Set body = new HashSet();
  1281. Stack ranges = new Stack();
  1282. for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
  1283. body.add(ih);
  1284. if (ih.getInstruction() instanceof InstructionBranch) {
  1285. body.add(ih.getInstruction());
  1286. }
  1287. }
  1288. for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
  1289. assertGoodHandle(ih, body, ranges, from);
  1290. InstructionTargeter[] ts = ih.getTargeters();
  1291. if (ts != null) {
  1292. for (int i = ts.length - 1; i >= 0; i--) {
  1293. assertGoodTargeter(ts[i], ih, body, from);
  1294. }
  1295. }
  1296. }
  1297. }
  1298. private static void assertGoodHandle(InstructionHandle ih, Set body, Stack ranges, String from) {
  1299. Instruction inst = ih.getInstruction();
  1300. if ((inst instanceof InstructionBranch) ^ (ih instanceof BranchHandle)) {
  1301. throw new BCException("bad instruction/handle pair in " + from);
  1302. }
  1303. if (Range.isRangeHandle(ih)) {
  1304. assertGoodRangeHandle(ih, body, ranges, from);
  1305. } else if (inst instanceof InstructionBranch) {
  1306. assertGoodBranchInstruction((BranchHandle) ih, (InstructionBranch) inst, body, ranges, from);
  1307. }
  1308. }
  1309. private static void assertGoodBranchInstruction(
  1310. BranchHandle ih,
  1311. InstructionBranch inst,
  1312. Set body,
  1313. Stack ranges,
  1314. String from)
  1315. {
  1316. if (ih.getTarget() != inst.getTarget()) {
  1317. throw new BCException("bad branch instruction/handle pair in " + from);
  1318. }
  1319. InstructionHandle target = ih.getTarget();
  1320. assertInBody(target, body, from);
  1321. assertTargetedBy(target, inst, from);
  1322. if (inst instanceof InstructionSelect) {
  1323. InstructionSelect sel = (InstructionSelect) inst;
  1324. InstructionHandle[] itargets = sel.getTargets();
  1325. for (int k = itargets.length - 1; k >= 0; k--) {
  1326. assertInBody(itargets[k], body, from);
  1327. assertTargetedBy(itargets[k], inst, from);
  1328. }
  1329. }
  1330. }
  1331. /** ih is an InstructionHandle or a BranchInstruction */
  1332. private static void assertInBody(Object ih, Set body, String from) {
  1333. if (! body.contains(ih)) throw new BCException("thing not in body in " + from);
  1334. }
  1335. private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) {
  1336. Range r = getRangeAndAssertExactlyOne(ih, from);
  1337. assertGoodRange(r, body, from);
  1338. if (r.getStart() == ih) {
  1339. ranges.push(r);
  1340. } else if (r.getEnd() == ih) {
  1341. if (ranges.peek() != r) throw new BCException("bad range inclusion in " + from);
  1342. ranges.pop();
  1343. }
  1344. }
  1345. private static void assertGoodRange(Range r, Set body, String from) {
  1346. assertInBody(r.getStart(), body, from);
  1347. assertRangeHandle(r.getStart(), from);
  1348. assertTargetedBy(r.getStart(), r, from);
  1349. assertInBody(r.getEnd(), body, from);
  1350. assertRangeHandle(r.getEnd(), from);
  1351. assertTargetedBy(r.getEnd(), r, from);
  1352. if (r instanceof ExceptionRange) {
  1353. ExceptionRange er = (ExceptionRange) r;
  1354. assertInBody(er.getHandler(), body, from);
  1355. assertTargetedBy(er.getHandler(), r, from);
  1356. }
  1357. }
  1358. private static void assertRangeHandle(InstructionHandle ih, String from) {
  1359. if (! Range.isRangeHandle(ih)) throw new BCException("bad range handle " + ih + " in " + from);
  1360. }
  1361. private static void assertTargetedBy(
  1362. InstructionHandle target,
  1363. InstructionTargeter targeter,
  1364. String from)
  1365. {
  1366. InstructionTargeter[] ts = target.getTargeters();
  1367. if (ts == null) throw new BCException("bad targeting relationship in " + from);
  1368. for (int i = ts.length - 1; i >= 0; i--) {
  1369. if (ts[i] == targeter) return;
  1370. }
  1371. throw new RuntimeException("bad targeting relationship in " + from);
  1372. }
  1373. private static void assertTargets(InstructionTargeter targeter, InstructionHandle target, String from) {
  1374. if (targeter instanceof Range) {
  1375. Range r = (Range) targeter;
  1376. if (r.getStart() == target || r.getEnd() == target) return;
  1377. if (r instanceof ExceptionRange) {
  1378. if (((ExceptionRange)r).getHandler() == target) return;
  1379. }
  1380. } else if (targeter instanceof InstructionBranch) {
  1381. InstructionBranch bi = (InstructionBranch) targeter;
  1382. if (bi.getTarget() == target) return;
  1383. if (targeter instanceof InstructionSelect) {
  1384. InstructionSelect sel = (InstructionSelect) targeter;
  1385. InstructionHandle[] itargets = sel.getTargets();
  1386. for (int k = itargets.length - 1; k >= 0; k--) {
  1387. if (itargets[k] == target) return;
  1388. }
  1389. }
  1390. } else if (targeter instanceof Tag) {
  1391. return;
  1392. }
  1393. throw new BCException(targeter + " doesn't target " + target + " in " + from );
  1394. }
  1395. private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) {
  1396. Range ret = null;
  1397. InstructionTargeter[] ts = ih.getTargeters();
  1398. if (ts == null) throw new BCException("range handle with no range in " + from);
  1399. for (int i = ts.length - 1; i >= 0; i--) {
  1400. if (ts[i] instanceof Range) {
  1401. if (ret != null) throw new BCException("range handle with multiple ranges in " + from);
  1402. ret = (Range) ts[i];
  1403. }
  1404. }
  1405. if (ret == null) throw new BCException("range handle with no range in " + from);
  1406. return ret;
  1407. }
  1408. private static void assertGoodTargeter(
  1409. InstructionTargeter t,
  1410. InstructionHandle ih,
  1411. Set body,
  1412. String from)
  1413. {
  1414. assertTargets(t, ih, from);
  1415. if (t instanceof Range) {
  1416. assertGoodRange((Range) t, body, from);
  1417. } else if (t instanceof InstructionBranch) {
  1418. assertInBody(t, body, from);
  1419. }
  1420. }
  1421. // ----
  1422. boolean isAdviceMethod() {
  1423. if (memberView==null) return false;
  1424. return memberView.getAssociatedShadowMunger() != null;
  1425. }
  1426. boolean isAjSynthetic() {
  1427. if (memberView == null) return true;
  1428. return memberView.isAjSynthetic();
  1429. }
  1430. boolean isSynthetic() {
  1431. if (memberView == null) return false;
  1432. return memberView.isSynthetic();
  1433. }
  1434. public ISourceLocation getSourceLocation() {
  1435. if (memberView!=null) return memberView.getSourceLocation();
  1436. return null;
  1437. }
  1438. public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() {
  1439. //if (memberView == null) return null;
  1440. if (effectiveSignature != null) return effectiveSignature;
  1441. return memberView.getEffectiveSignature();
  1442. }
  1443. public void setEffectiveSignature(ResolvedMember member, Shadow.Kind kind, boolean shouldWeave) {
  1444. this.effectiveSignature =
  1445. new AjAttribute.EffectiveSignatureAttribute(member,kind,shouldWeave);
  1446. }
  1447. public String getSignature() {
  1448. if (memberView!=null) return memberView.getSignature();
  1449. return MemberImpl.typesToSignature(BcelWorld.fromBcel(getReturnType()),
  1450. BcelWorld.fromBcel(getArgumentTypes()),false);
  1451. }
  1452. public String getParameterSignature() {
  1453. if (memberView!=null) return memberView.getParameterSignature();
  1454. return MemberImpl.typesToSignature(BcelWorld.fromBcel(getArgumentTypes()));
  1455. }
  1456. public BcelMethod getMemberView() {
  1457. return memberView;
  1458. }
  1459. public void forcePublic() {
  1460. markAsChanged();
  1461. accessFlags = Utility.makePublic(accessFlags);
  1462. }
  1463. public boolean getCanInline() {
  1464. return canInline;
  1465. }
  1466. public void setCanInline(boolean canInline) {
  1467. this.canInline = canInline;
  1468. }
  1469. /**
  1470. * Adds an attribute to the method
  1471. * @param attr
  1472. */
  1473. public void addAttribute(Attribute attr) {
  1474. attributes.add(attr);
  1475. // Attribute[] newAttributes = new Attribute[attributes.length + 1];
  1476. // System.arraycopy(attributes, 0, newAttributes, 0, attributes.length);
  1477. // newAttributes[attributes.length] = attr;
  1478. // attributes = newAttributes;
  1479. }
  1480. public String toTraceString() {
  1481. return toShortString();
  1482. }
  1483. }