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.

BcelClassWeaver.java 68KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778
  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.lang.reflect.Modifier;
  14. import java.util.ArrayList;
  15. import java.util.Collection;
  16. import java.util.Collections;
  17. import java.util.Comparator;
  18. import java.util.HashMap;
  19. import java.util.HashSet;
  20. import java.util.Iterator;
  21. import java.util.List;
  22. import java.util.Map;
  23. import java.util.Set;
  24. import org.aspectj.apache.bcel.Constants;
  25. import org.aspectj.apache.bcel.classfile.Field;
  26. import org.aspectj.apache.bcel.classfile.Method;
  27. import org.aspectj.apache.bcel.classfile.annotation.Annotation;
  28. import org.aspectj.apache.bcel.generic.BranchInstruction;
  29. import org.aspectj.apache.bcel.generic.CPInstruction;
  30. import org.aspectj.apache.bcel.generic.ConstantPoolGen;
  31. import org.aspectj.apache.bcel.generic.FieldGen;
  32. import org.aspectj.apache.bcel.generic.FieldInstruction;
  33. import org.aspectj.apache.bcel.generic.INVOKESPECIAL;
  34. import org.aspectj.apache.bcel.generic.IndexedInstruction;
  35. import org.aspectj.apache.bcel.generic.Instruction;
  36. import org.aspectj.apache.bcel.generic.InstructionConstants;
  37. import org.aspectj.apache.bcel.generic.InstructionFactory;
  38. import org.aspectj.apache.bcel.generic.InstructionHandle;
  39. import org.aspectj.apache.bcel.generic.InstructionList;
  40. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  41. import org.aspectj.apache.bcel.generic.InvokeInstruction;
  42. import org.aspectj.apache.bcel.generic.LocalVariableInstruction;
  43. import org.aspectj.apache.bcel.generic.MethodGen;
  44. import org.aspectj.apache.bcel.generic.NEW;
  45. import org.aspectj.apache.bcel.generic.ObjectType;
  46. import org.aspectj.apache.bcel.generic.PUTFIELD;
  47. import org.aspectj.apache.bcel.generic.PUTSTATIC;
  48. import org.aspectj.apache.bcel.generic.RET;
  49. import org.aspectj.apache.bcel.generic.ReturnInstruction;
  50. import org.aspectj.apache.bcel.generic.Select;
  51. import org.aspectj.apache.bcel.generic.Type;
  52. import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
  53. import org.aspectj.bridge.IMessage;
  54. import org.aspectj.bridge.ISourceLocation;
  55. import org.aspectj.bridge.WeaveMessage;
  56. import org.aspectj.util.PartialOrder;
  57. import org.aspectj.weaver.AjAttribute;
  58. import org.aspectj.weaver.AjcMemberMaker;
  59. import org.aspectj.weaver.AsmRelationshipProvider;
  60. import org.aspectj.weaver.BCException;
  61. import org.aspectj.weaver.ConcreteTypeMunger;
  62. import org.aspectj.weaver.IClassWeaver;
  63. import org.aspectj.weaver.IntMap;
  64. import org.aspectj.weaver.Member;
  65. import org.aspectj.weaver.NameMangler;
  66. import org.aspectj.weaver.NewConstructorTypeMunger;
  67. import org.aspectj.weaver.NewFieldTypeMunger;
  68. import org.aspectj.weaver.NewMethodTypeMunger;
  69. import org.aspectj.weaver.ResolvedMember;
  70. import org.aspectj.weaver.ResolvedType;
  71. import org.aspectj.weaver.ResolvedTypeMunger;
  72. import org.aspectj.weaver.Shadow;
  73. import org.aspectj.weaver.ShadowMunger;
  74. import org.aspectj.weaver.UnresolvedType;
  75. import org.aspectj.weaver.WeaverMessages;
  76. import org.aspectj.weaver.WeaverMetrics;
  77. import org.aspectj.weaver.WeaverStateInfo;
  78. import org.aspectj.weaver.patterns.DeclareAnnotation;
  79. class BcelClassWeaver implements IClassWeaver {
  80. /**
  81. * This is called from {@link BcelWeaver} to perform the per-class weaving process.
  82. */
  83. public static boolean weave(
  84. BcelWorld world,
  85. LazyClassGen clazz,
  86. List shadowMungers,
  87. List typeMungers,
  88. List lateTypeMungers)
  89. {
  90. boolean b = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers).weave();
  91. //System.out.println(clazz.getClassName() + ", " + clazz.getType().getWeaverState());
  92. //clazz.print();
  93. return b;
  94. }
  95. // --------------------------------------------
  96. private final LazyClassGen clazz;
  97. private final List shadowMungers;
  98. private final List typeMungers;
  99. private final List lateTypeMungers;
  100. private final BcelObjectType ty; // alias of clazz.getType()
  101. private final BcelWorld world; // alias of ty.getWorld()
  102. private final ConstantPoolGen cpg; // alias of clazz.getConstantPoolGen()
  103. private final InstructionFactory fact; // alias of clazz.getFactory();
  104. private final List addedLazyMethodGens = new ArrayList();
  105. private final Set addedDispatchTargets = new HashSet();
  106. // Static setting across BcelClassWeavers
  107. private static boolean inReweavableMode = false;
  108. private static boolean compressReweavableAttributes = false;
  109. private List addedSuperInitializersAsList = null; // List<IfaceInitList>
  110. private final Map addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList
  111. private List addedThisInitializers = new ArrayList(); // List<NewFieldMunger>
  112. private List addedClassInitializers = new ArrayList(); // List<NewFieldMunger>
  113. private Map mapToAnnotations = new HashMap();
  114. private BcelShadow clinitShadow = null;
  115. /**
  116. * This holds the initialization and pre-initialization shadows for this class
  117. * that were actually matched by mungers (if no match, then we don't even create the
  118. * shadows really).
  119. */
  120. private final List initializationShadows = new ArrayList(1);
  121. private BcelClassWeaver(
  122. BcelWorld world,
  123. LazyClassGen clazz,
  124. List shadowMungers,
  125. List typeMungers,
  126. List lateTypeMungers)
  127. {
  128. super();
  129. // assert world == clazz.getType().getWorld()
  130. this.world = world;
  131. this.clazz = clazz;
  132. this.shadowMungers = shadowMungers;
  133. this.typeMungers = typeMungers;
  134. this.lateTypeMungers = lateTypeMungers;
  135. this.ty = clazz.getBcelObjectType();
  136. this.cpg = clazz.getConstantPoolGen();
  137. this.fact = clazz.getFactory();
  138. fastMatchShadowMungers(shadowMungers);
  139. initializeSuperInitializerMap(ty.getResolvedTypeX());
  140. }
  141. private List[] perKindShadowMungers;
  142. private boolean canMatchBodyShadows = false;
  143. private boolean canMatchInitialization = false;
  144. private void fastMatchShadowMungers(List shadowMungers) {
  145. // beware the annoying property that SHADOW_KINDS[i].getKey == (i+1) !
  146. perKindShadowMungers = new List[Shadow.MAX_SHADOW_KIND + 1];
  147. for (int i = 0; i < perKindShadowMungers.length; i++) {
  148. perKindShadowMungers[i] = new ArrayList(0);
  149. }
  150. for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
  151. ShadowMunger munger = (ShadowMunger) iter.next();
  152. Set couldMatchKinds = munger.getPointcut().couldMatchKinds();
  153. for (Iterator kindIterator = couldMatchKinds.iterator();
  154. kindIterator.hasNext();) {
  155. Shadow.Kind aKind = (Shadow.Kind) kindIterator.next();
  156. perKindShadowMungers[aKind.getKey()].add(munger);
  157. }
  158. }
  159. if (!perKindShadowMungers[Shadow.Initialization.getKey()].isEmpty())
  160. canMatchInitialization = true;
  161. for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
  162. Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
  163. if (!kind.isEnclosingKind() && !perKindShadowMungers[i+1].isEmpty()) {
  164. canMatchBodyShadows = true;
  165. }
  166. if (perKindShadowMungers[i+1].isEmpty()) {
  167. perKindShadowMungers[i+1] = null;
  168. }
  169. }
  170. }
  171. private boolean canMatch(Shadow.Kind kind) {
  172. return perKindShadowMungers[kind.getKey()] != null;
  173. }
  174. // private void fastMatchShadowMungers(List shadowMungers, ArrayList mungers, Kind kind) {
  175. // FastMatchInfo info = new FastMatchInfo(clazz.getType(), kind);
  176. // for (Iterator i = shadowMungers.iterator(); i.hasNext();) {
  177. // ShadowMunger munger = (ShadowMunger) i.next();
  178. // FuzzyBoolean fb = munger.getPointcut().fastMatch(info);
  179. // WeaverMetrics.recordFastMatchResult(fb);// Could pass: munger.getPointcut().toString()
  180. // if (fb.maybeTrue()) mungers.add(munger);
  181. // }
  182. // }
  183. private void initializeSuperInitializerMap(ResolvedType child) {
  184. ResolvedType[] superInterfaces = child.getDeclaredInterfaces();
  185. for (int i=0, len=superInterfaces.length; i < len; i++) {
  186. if (ty.getResolvedTypeX().isTopmostImplementor(superInterfaces[i])) {
  187. if (addSuperInitializer(superInterfaces[i])) {
  188. initializeSuperInitializerMap(superInterfaces[i]);
  189. }
  190. }
  191. }
  192. }
  193. private boolean addSuperInitializer(ResolvedType onType) {
  194. IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType);
  195. if (l != null) return false;
  196. l = new IfaceInitList(onType);
  197. addedSuperInitializers.put(onType, l);
  198. return true;
  199. }
  200. public void addInitializer(ConcreteTypeMunger cm) {
  201. NewFieldTypeMunger m = (NewFieldTypeMunger) cm.getMunger();
  202. ResolvedType onType = m.getSignature().getDeclaringType().resolve(world);
  203. if (onType.isRawType()) onType = onType.getGenericType();
  204. if (m.getSignature().isStatic()) {
  205. addedClassInitializers.add(cm);
  206. } else {
  207. if (onType == ty.getResolvedTypeX()) {
  208. addedThisInitializers.add(cm);
  209. } else {
  210. IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType);
  211. l.list.add(cm);
  212. }
  213. }
  214. }
  215. private static class IfaceInitList implements PartialOrder.PartialComparable {
  216. final ResolvedType onType;
  217. List list = new ArrayList();
  218. IfaceInitList(ResolvedType onType) {
  219. this.onType = onType;
  220. }
  221. public int compareTo(Object other) {
  222. IfaceInitList o = (IfaceInitList)other;
  223. if (onType.isAssignableFrom(o.onType)) return +1;
  224. else if (o.onType.isAssignableFrom(onType)) return -1;
  225. else return 0;
  226. }
  227. public int fallbackCompareTo(Object other) {
  228. return 0;
  229. }
  230. }
  231. // XXX this is being called, but the result doesn't seem to be being used
  232. public boolean addDispatchTarget(ResolvedMember m) {
  233. return addedDispatchTargets.add(m);
  234. }
  235. public void addLazyMethodGen(LazyMethodGen gen) {
  236. addedLazyMethodGens.add(gen);
  237. }
  238. public void addOrReplaceLazyMethodGen(LazyMethodGen mg) {
  239. if (alreadyDefined(clazz, mg)) return;
  240. for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
  241. LazyMethodGen existing = (LazyMethodGen)i.next();
  242. if (signaturesMatch(mg, existing)) {
  243. if (existing.definingType == null) {
  244. // this means existing was introduced on the class itself
  245. return;
  246. } else if (mg.definingType.isAssignableFrom(existing.definingType)) {
  247. // existing is mg's subtype and dominates mg
  248. return;
  249. } else if (existing.definingType.isAssignableFrom(mg.definingType)) {
  250. // mg is existing's subtype and dominates existing
  251. i.remove();
  252. addedLazyMethodGens.add(mg);
  253. return;
  254. } else {
  255. throw new BCException("conflict between: " + mg + " and " + existing);
  256. }
  257. }
  258. }
  259. addedLazyMethodGens.add(mg);
  260. }
  261. private boolean alreadyDefined(LazyClassGen clazz, LazyMethodGen mg) {
  262. for (Iterator i = clazz.getMethodGens().iterator(); i.hasNext(); ) {
  263. LazyMethodGen existing = (LazyMethodGen)i.next();
  264. if (signaturesMatch(mg, existing)) {
  265. if (!mg.isAbstract() && existing.isAbstract()) {
  266. i.remove();
  267. return false;
  268. }
  269. return true;
  270. }
  271. }
  272. return false;
  273. }
  274. private boolean signaturesMatch(LazyMethodGen mg, LazyMethodGen existing) {
  275. return mg.getName().equals(existing.getName()) &&
  276. mg.getSignature().equals(existing.getSignature());
  277. }
  278. // ----
  279. public boolean weave() {
  280. if (clazz.isWoven() && !clazz.isReweavable()) {
  281. world.showMessage(IMessage.ERROR,
  282. WeaverMessages.format(WeaverMessages.ALREADY_WOVEN,clazz.getType().getName()),
  283. ty.getSourceLocation(), null);
  284. return false;
  285. }
  286. Set aspectsAffectingType = null;
  287. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType = new HashSet();
  288. boolean isChanged = false;
  289. // we want to "touch" all aspects
  290. if (clazz.getType().isAspect()) isChanged = true;
  291. // start by munging all typeMungers
  292. for (Iterator i = typeMungers.iterator(); i.hasNext(); ) {
  293. Object o = i.next();
  294. if ( !(o instanceof BcelTypeMunger) ) {
  295. //???System.err.println("surprising: " + o);
  296. continue;
  297. }
  298. BcelTypeMunger munger = (BcelTypeMunger)o;
  299. boolean typeMungerAffectedType = munger.munge(this);
  300. if (typeMungerAffectedType) {
  301. isChanged = true;
  302. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.add(munger.getAspectType().getName());
  303. }
  304. }
  305. // Weave special half type/half shadow mungers...
  306. isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged;
  307. isChanged = weaveDeclareAtField(clazz) || isChanged;
  308. // XXX do major sort of stuff
  309. // sort according to: Major: type hierarchy
  310. // within each list: dominates
  311. // don't forget to sort addedThisInitialiers according to dominates
  312. addedSuperInitializersAsList = new ArrayList(addedSuperInitializers.values());
  313. addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList);
  314. if (addedSuperInitializersAsList == null) {
  315. throw new BCException("circularity in inter-types");
  316. }
  317. // this will create a static initializer if there isn't one
  318. // this is in just as bad taste as NOPs
  319. LazyMethodGen staticInit = clazz.getStaticInitializer();
  320. staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true));
  321. // now go through each method, and match against each method. This
  322. // sets up each method's {@link LazyMethodGen#matchedShadows} field,
  323. // and it also possibly adds to {@link #initializationShadows}.
  324. List methodGens = new ArrayList(clazz.getMethodGens());
  325. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  326. LazyMethodGen mg = (LazyMethodGen)i.next();
  327. if (! mg.hasBody()) continue;
  328. boolean shadowMungerMatched = match(mg);
  329. if (shadowMungerMatched) {
  330. // For matching mungers, add their declaring aspects to the list that affected this type
  331. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.addAll(findAspectsForMungers(mg));
  332. isChanged = true;
  333. }
  334. }
  335. // now we weave all but the initialization shadows
  336. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  337. LazyMethodGen mg = (LazyMethodGen)i.next();
  338. if (! mg.hasBody()) continue;
  339. implement(mg);
  340. }
  341. // if we matched any initialization shadows, we inline and weave
  342. if (! initializationShadows.isEmpty()) {
  343. // Repeat next step until nothing left to inline...cant go on
  344. // infinetly as compiler will have detected and reported
  345. // "Recursive constructor invocation"
  346. while (inlineSelfConstructors(methodGens));
  347. positionAndImplement(initializationShadows);
  348. }
  349. // now proceed with late type mungers
  350. if (lateTypeMungers != null) {
  351. for (Iterator i = lateTypeMungers.iterator(); i.hasNext(); ) {
  352. BcelTypeMunger munger = (BcelTypeMunger)i.next();
  353. if (munger.matches(clazz.getType())) {
  354. boolean typeMungerAffectedType = munger.munge(this);
  355. if (typeMungerAffectedType) {
  356. isChanged = true;
  357. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.add(munger.getAspectType().getName());
  358. }
  359. }
  360. }
  361. }
  362. //FIXME AV - see #75442, for now this is not enough to fix the bug, comment that out until we really fix it
  363. // // flush to save some memory
  364. // PerObjectInterfaceTypeMunger.unregisterFromAsAdvisedBy(clazz.getType());
  365. // finally, if we changed, we add in the introduced methods.
  366. if (isChanged) {
  367. clazz.getOrCreateWeaverStateInfo();
  368. weaveInAddedMethods(); // FIXME asc are these potentially affected by declare annotation?
  369. }
  370. if (inReweavableMode || clazz.getType().isAspect()) {
  371. WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo();
  372. wsi.addAspectsAffectingType(aspectsAffectingType);
  373. wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes());
  374. wsi.setReweavable(true,compressReweavableAttributes);
  375. } else {
  376. clazz.getOrCreateWeaverStateInfo().setReweavable(false,false);
  377. }
  378. return isChanged;
  379. }
  380. /**
  381. * Weave any declare @method/@ctor statements into the members of the supplied class
  382. */
  383. private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) {
  384. List reportedProblems = new ArrayList();
  385. List allDecams = world.getDeclareAnnotationOnMethods();
  386. if (allDecams.isEmpty()) return false; // nothing to do
  387. boolean isChanged = false;
  388. // deal with ITDs
  389. List itdMethodsCtors = getITDSubset(clazz,ResolvedTypeMunger.Method);
  390. itdMethodsCtors.addAll(getITDSubset(clazz,ResolvedTypeMunger.Constructor));
  391. if (!itdMethodsCtors.isEmpty()) {
  392. // Can't use the subset called 'decaMs' as it won't be right for ITDs...
  393. isChanged = weaveAtMethodOnITDSRepeatedly(allDecams,itdMethodsCtors,reportedProblems);
  394. }
  395. // deal with all the other methods...
  396. List members = clazz.getMethodGens();
  397. List decaMs = getMatchingSubset(allDecams,clazz.getType());
  398. if (decaMs.isEmpty()) return false; // nothing to do
  399. if (!members.isEmpty()) {
  400. for (int memberCounter = 0;memberCounter<members.size();memberCounter++) {
  401. LazyMethodGen mg = (LazyMethodGen)members.get(memberCounter);
  402. if (!mg.getName().startsWith(NameMangler.PREFIX)) {
  403. // Single first pass
  404. List worthRetrying = new ArrayList();
  405. boolean modificationOccured = false;
  406. for (Iterator iter = decaMs.iterator(); iter.hasNext();) {
  407. DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
  408. if (decaM.matches(mg.getMemberView(),world)) {
  409. if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) continue; // skip this one...
  410. Annotation a = decaM.getAnnotationX().getBcelAnnotation();
  411. AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true);
  412. Method oldMethod = mg.getMethod();
  413. MethodGen myGen = new MethodGen(oldMethod,clazz.getClassName(),clazz.getConstantPoolGen());
  414. myGen.addAnnotation(ag);
  415. Method newMethod = myGen.getMethod();
  416. mg.addAnnotation(decaM.getAnnotationX());
  417. members.set(memberCounter,new LazyMethodGen(newMethod,clazz));
  418. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
  419. reportMethodCtorWeavingMessage(clazz, mg, decaM);
  420. isChanged = true;
  421. modificationOccured = true;
  422. } else {
  423. if (!decaM.isStarredAnnotationPattern())
  424. worthRetrying.add(decaM); // an annotation is specified that might be put on by a subsequent decaf
  425. }
  426. }
  427. // Multiple secondary passes
  428. while (!worthRetrying.isEmpty() && modificationOccured) {
  429. modificationOccured = false;
  430. // lets have another go
  431. List forRemoval = new ArrayList();
  432. for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
  433. DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
  434. if (decaM.matches(mg.getMemberView(),world)) {
  435. if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) continue; // skip this one...
  436. mg.addAnnotation(decaM.getAnnotationX());
  437. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
  438. isChanged = true;
  439. modificationOccured = true;
  440. forRemoval.add(decaM);
  441. }
  442. }
  443. worthRetrying.removeAll(forRemoval);
  444. }
  445. }
  446. }
  447. }
  448. return isChanged;
  449. }
  450. // TAG: WeavingMessage
  451. private void reportMethodCtorWeavingMessage(LazyClassGen clazz, LazyMethodGen mg, DeclareAnnotation decaM) {
  452. if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
  453. StringBuffer parmString = new StringBuffer("(");
  454. Type[] args = mg.getMethod().getArgumentTypes();
  455. for (int i = 0; i < args.length; i++) {
  456. Type type2 = args[i];
  457. String s = org.aspectj.apache.bcel.classfile.Utility.signatureToString(type2.getSignature());
  458. if (s.lastIndexOf(".")!=-1) s =s.substring(s.lastIndexOf(".")+1);
  459. parmString.append(s);
  460. if ((i+1)<args.length) parmString.append(",");
  461. }
  462. parmString.append(")");
  463. String methodName = mg.getMethod().getName();
  464. StringBuffer sig = new StringBuffer();
  465. sig.append(org.aspectj.apache.bcel.classfile.Utility.accessToString(mg.getMethod().getAccessFlags()) );
  466. sig.append(" ");
  467. sig.append(mg.getMethod().getReturnType().toString());
  468. sig.append(" ");
  469. sig.append(clazz.getName());
  470. sig.append(".");
  471. sig.append(methodName.equals("<init>")?"new":methodName);
  472. sig.append(parmString);
  473. StringBuffer loc = new StringBuffer();
  474. if (clazz.getFileName()==null) {
  475. loc.append("no debug info available");
  476. } else {
  477. loc.append(clazz.getFileName());
  478. if (mg.getDeclarationLineNumber()!=-1) {
  479. loc.append(":"+mg.getDeclarationLineNumber());
  480. }
  481. }
  482. getWorld().getMessageHandler().handleMessage(
  483. WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
  484. new String[]{
  485. sig.toString(),
  486. loc.toString(),
  487. decaM.getAnnotationString(),
  488. methodName.startsWith("<init>")?"constructor":"method",
  489. decaM.getAspect().toString(),
  490. Utility.beautifyLocation(decaM.getSourceLocation())
  491. }));
  492. }
  493. }
  494. /**
  495. * Looks through a list of declare annotation statements and only returns
  496. * those that could possibly match on a field/method/ctor in type.
  497. */
  498. private List getMatchingSubset(List declareAnnotations, ResolvedType type) {
  499. List subset = new ArrayList();
  500. for (Iterator iter = declareAnnotations.iterator(); iter.hasNext();) {
  501. DeclareAnnotation da = (DeclareAnnotation) iter.next();
  502. if (da.couldEverMatch(type)) {
  503. subset.add(da);
  504. }
  505. }
  506. return subset;
  507. }
  508. /**
  509. * Get a subset of all the type mungers defined on this aspect
  510. */
  511. private List getITDSubset(LazyClassGen clazz,ResolvedTypeMunger.Kind wantedKind) {
  512. List subset = new ArrayList();
  513. Collection c = clazz.getBcelObjectType().getTypeMungers();
  514. for (Iterator iter = c.iterator();iter.hasNext();) {
  515. BcelTypeMunger typeMunger = (BcelTypeMunger)iter.next();
  516. if (typeMunger.getMunger().getKind()==wantedKind)
  517. subset.add(typeMunger);
  518. }
  519. return subset;
  520. }
  521. public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz,BcelTypeMunger fieldMunger) {
  522. NewFieldTypeMunger nftm = (NewFieldTypeMunger)fieldMunger.getMunger();
  523. ResolvedMember lookingFor =AjcMemberMaker.interFieldInitializer(nftm.getSignature(),clazz.getType());
  524. List meths = clazz.getMethodGens();
  525. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  526. LazyMethodGen element = (LazyMethodGen) iter.next();
  527. if (element.getName().equals(lookingFor.getName())) return element;
  528. }
  529. return null;
  530. }
  531. // FIXME asc refactor this to neaten it up
  532. public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz,BcelTypeMunger methodCtorMunger) {
  533. if (methodCtorMunger.getMunger() instanceof NewMethodTypeMunger) {
  534. NewMethodTypeMunger nftm = (NewMethodTypeMunger)methodCtorMunger.getMunger();
  535. ResolvedMember lookingFor = AjcMemberMaker.interMethodDispatcher(nftm.getSignature(),methodCtorMunger.getAspectType());
  536. List meths = clazz.getMethodGens();
  537. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  538. LazyMethodGen element = (LazyMethodGen) iter.next();
  539. if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
  540. }
  541. return null;
  542. } else if (methodCtorMunger.getMunger() instanceof NewConstructorTypeMunger) {
  543. NewConstructorTypeMunger nftm = (NewConstructorTypeMunger)methodCtorMunger.getMunger();
  544. ResolvedMember lookingFor =AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(),nftm.getSignature().getDeclaringType(),nftm.getSignature().getParameterTypes());
  545. List meths = clazz.getMethodGens();
  546. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  547. LazyMethodGen element = (LazyMethodGen) iter.next();
  548. if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
  549. }
  550. return null;
  551. } else {
  552. throw new RuntimeException("Not sure what this is: "+methodCtorMunger);
  553. }
  554. }
  555. /**
  556. * Applies some set of declare @field constructs (List<DeclareAnnotation>) to some bunch
  557. * of ITDfields (List<BcelTypeMunger>. It will iterate over the fields repeatedly until
  558. * everything has been applied.
  559. *
  560. */
  561. private boolean weaveAtFieldRepeatedly(List decaFs, List itdFields,List reportedErrors) {
  562. boolean isChanged = false;
  563. for (Iterator iter = itdFields.iterator(); iter.hasNext();) {
  564. BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next();
  565. ResolvedMember itdIsActually = fieldMunger.getSignature();
  566. List worthRetrying = new ArrayList();
  567. boolean modificationOccured = false;
  568. for (Iterator iter2 = decaFs.iterator(); iter2.hasNext();) {
  569. DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
  570. if (decaF.matches(itdIsActually,world)) {
  571. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
  572. if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
  573. annotationHolder.addAnnotation(decaF.getAnnotationX());
  574. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
  575. isChanged = true;
  576. modificationOccured = true;
  577. } else {
  578. if (!decaF.isStarredAnnotationPattern())
  579. worthRetrying.add(decaF); // an annotation is specified that might be put on by a subsequent decaf
  580. }
  581. }
  582. while (!worthRetrying.isEmpty() && modificationOccured) {
  583. modificationOccured = false;
  584. List forRemoval = new ArrayList();
  585. for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) {
  586. DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
  587. if (decaF.matches(itdIsActually,world)) {
  588. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
  589. if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
  590. annotationHolder.addAnnotation(decaF.getAnnotationX());
  591. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
  592. isChanged = true;
  593. modificationOccured = true;
  594. forRemoval.add(decaF);
  595. }
  596. worthRetrying.removeAll(forRemoval);
  597. }
  598. }
  599. }
  600. return isChanged;
  601. }
  602. /**
  603. * Applies some set of declare @method/@ctor constructs (List<DeclareAnnotation>) to some bunch
  604. * of ITDmembers (List<BcelTypeMunger>. It will iterate over the fields repeatedly until
  605. * everything has been applied.
  606. */
  607. private boolean weaveAtMethodOnITDSRepeatedly(List decaMCs, List itdMethodsCtors,List reportedErrors) {
  608. boolean isChanged = false;
  609. for (Iterator iter = itdMethodsCtors.iterator(); iter.hasNext();) {
  610. BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next();
  611. ResolvedMember unMangledInterMethod = methodctorMunger.getSignature();
  612. List worthRetrying = new ArrayList();
  613. boolean modificationOccured = false;
  614. for (Iterator iter2 = decaMCs.iterator(); iter2.hasNext();) {
  615. DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next();
  616. if (decaMC.matches(unMangledInterMethod,world)) {
  617. LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz,methodctorMunger);
  618. if (annotationHolder == null || doesAlreadyHaveAnnotation(annotationHolder,unMangledInterMethod,decaMC,reportedErrors)){
  619. continue; // skip this one...
  620. }
  621. annotationHolder.addAnnotation(decaMC.getAnnotationX());
  622. isChanged=true;
  623. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
  624. modificationOccured = true;
  625. } else {
  626. if (!decaMC.isStarredAnnotationPattern())
  627. worthRetrying.add(decaMC); // an annotation is specified that might be put on by a subsequent decaf
  628. }
  629. }
  630. while (!worthRetrying.isEmpty() && modificationOccured) {
  631. modificationOccured = false;
  632. List forRemoval = new ArrayList();
  633. for (Iterator iter2 = worthRetrying.iterator(); iter.hasNext();) {
  634. DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next();
  635. if (decaMC.matches(unMangledInterMethod,world)) {
  636. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,methodctorMunger);
  637. if (doesAlreadyHaveAnnotation(annotationHolder,unMangledInterMethod,decaMC,reportedErrors)) continue; // skip this one...
  638. annotationHolder.addAnnotation(decaMC.getAnnotationX());
  639. unMangledInterMethod.addAnnotation(decaMC.getAnnotationX());
  640. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
  641. isChanged = true;
  642. modificationOccured = true;
  643. forRemoval.add(decaMC);
  644. }
  645. worthRetrying.removeAll(forRemoval);
  646. }
  647. }
  648. }
  649. return isChanged;
  650. }
  651. private boolean dontAddTwice(DeclareAnnotation decaF, Annotation [] dontAddMeTwice){
  652. for (int i = 0; i < dontAddMeTwice.length; i++){
  653. Annotation ann = dontAddMeTwice[i];
  654. if (ann != null && decaF.getAnnotationX().getTypeName().equals(ann.getTypeName())){
  655. dontAddMeTwice[i] = null; // incase it really has been added twice!
  656. return true;
  657. }
  658. }
  659. return false;
  660. }
  661. /**
  662. * Weave any declare @field statements into the fields of the supplied class
  663. *
  664. * Interesting case relating to public ITDd fields. The annotations are really stored against
  665. * the interfieldinit method in the aspect, but the public field is placed in the target
  666. * type and then is processed in the 2nd pass over fields that occurs. I think it would be
  667. * more expensive to avoid putting the annotation on that inserted public field than just to
  668. * have it put there as well as on the interfieldinit method.
  669. */
  670. private boolean weaveDeclareAtField(LazyClassGen clazz) {
  671. // BUGWARNING not getting enough warnings out on declare @field ?
  672. // There is a potential problem here with warnings not coming out - this
  673. // will occur if they are created on the second iteration round this loop.
  674. // We currently deactivate error reporting for the second time round.
  675. // A possible solution is to record what annotations were added by what
  676. // decafs and check that to see if an error needs to be reported - this
  677. // would be expensive so lets skip it for now
  678. List reportedProblems = new ArrayList();
  679. List allDecafs = world.getDeclareAnnotationOnFields();
  680. if (allDecafs.isEmpty()) return false; // nothing to do
  681. boolean isChanged = false;
  682. List itdFields = getITDSubset(clazz,ResolvedTypeMunger.Field);
  683. if (itdFields!=null) {
  684. isChanged = weaveAtFieldRepeatedly(allDecafs,itdFields,reportedProblems);
  685. }
  686. List decaFs = getMatchingSubset(allDecafs,clazz.getType());
  687. if (decaFs.isEmpty()) return false; // nothing more to do
  688. Field[] fields = clazz.getFieldGens();
  689. if (fields!=null) {
  690. for (int fieldCounter = 0;fieldCounter<fields.length;fieldCounter++) {
  691. BcelField aBcelField = new BcelField(clazz.getBcelObjectType(),fields[fieldCounter]);
  692. if (!aBcelField.getName().startsWith(NameMangler.PREFIX)) {
  693. // Single first pass
  694. List worthRetrying = new ArrayList();
  695. boolean modificationOccured = false;
  696. Annotation [] dontAddMeTwice = fields[fieldCounter].getAnnotations();
  697. // go through all the declare @field statements
  698. for (Iterator iter = decaFs.iterator(); iter.hasNext();) {
  699. DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
  700. if (decaF.matches(aBcelField,world)) {
  701. if (!dontAddTwice(decaF,dontAddMeTwice)){
  702. if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)){
  703. continue;
  704. }
  705. if(decaF.getAnnotationX().isRuntimeVisible()){ // isAnnotationWithRuntimeRetention(clazz.getJavaClass(world))){
  706. //if(decaF.getAnnotationTypeX().isAnnotationWithRuntimeRetention(world)){
  707. // it should be runtime visible, so put it on the Field
  708. Annotation a = decaF.getAnnotationX().getBcelAnnotation();
  709. AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true);
  710. FieldGen myGen = new FieldGen(fields[fieldCounter],clazz.getConstantPoolGen());
  711. myGen.addAnnotation(ag);
  712. Field newField = myGen.getField();
  713. aBcelField.addAnnotation(decaF.getAnnotationX());
  714. clazz.replaceField(fields[fieldCounter],newField);
  715. fields[fieldCounter]=newField;
  716. } else{
  717. aBcelField.addAnnotation(decaF.getAnnotationX());
  718. }
  719. }
  720. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]);
  721. reportFieldAnnotationWeavingMessage(clazz, fields, fieldCounter, decaF);
  722. isChanged = true;
  723. modificationOccured = true;
  724. } else {
  725. if (!decaF.isStarredAnnotationPattern())
  726. worthRetrying.add(decaF); // an annotation is specified that might be put on by a subsequent decaf
  727. }
  728. }
  729. // Multiple secondary passes
  730. while (!worthRetrying.isEmpty() && modificationOccured) {
  731. modificationOccured = false;
  732. // lets have another go
  733. List forRemoval = new ArrayList();
  734. for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
  735. DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
  736. if (decaF.matches(aBcelField,world)) {
  737. // below code is for recursive things
  738. if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)) continue; // skip this one...
  739. aBcelField.addAnnotation(decaF.getAnnotationX());
  740. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),fields[fieldCounter]);
  741. isChanged = true;
  742. modificationOccured = true;
  743. forRemoval.add(decaF);
  744. }
  745. }
  746. worthRetrying.removeAll(forRemoval);
  747. }
  748. }
  749. }
  750. }
  751. return isChanged;
  752. }
  753. // TAG: WeavingMessage
  754. private void reportFieldAnnotationWeavingMessage(LazyClassGen clazz, Field[] fields, int fieldCounter, DeclareAnnotation decaF) {
  755. if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
  756. Field theField = fields[fieldCounter];
  757. world.getMessageHandler().handleMessage(
  758. WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
  759. new String[]{
  760. theField.toString() + "' of type '" + clazz.getName(),
  761. clazz.getFileName(),
  762. decaF.getAnnotationString(),
  763. "field",
  764. decaF.getAspect().toString(),
  765. Utility.beautifyLocation(decaF.getSourceLocation())}));
  766. }
  767. }
  768. /**
  769. * Check if a resolved member (field/method/ctor) already has an annotation, if it
  770. * does then put out a warning and return true
  771. */
  772. private boolean doesAlreadyHaveAnnotation(ResolvedMember rm,DeclareAnnotation deca,List reportedProblems) {
  773. if (rm.hasAnnotation(deca.getAnnotationTypeX())) {
  774. if (world.getLint().elementAlreadyAnnotated.isEnabled()) {
  775. Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode());
  776. if (!reportedProblems.contains(uniqueID)) {
  777. reportedProblems.add(uniqueID);
  778. world.getLint().elementAlreadyAnnotated.signal(
  779. new String[]{rm.toString(),deca.getAnnotationTypeX().toString()},
  780. rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
  781. }
  782. }
  783. return true;
  784. }
  785. return false;
  786. }
  787. private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm,ResolvedMember itdfieldsig,DeclareAnnotation deca,List reportedProblems) {
  788. if (rm != null && rm.hasAnnotation(deca.getAnnotationTypeX())) {
  789. if (world.getLint().elementAlreadyAnnotated.isEnabled()) {
  790. Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode());
  791. if (!reportedProblems.contains(uniqueID)) {
  792. reportedProblems.add(uniqueID);
  793. reportedProblems.add(new Integer(itdfieldsig.hashCode()*deca.hashCode()));
  794. world.getLint().elementAlreadyAnnotated.signal(
  795. new String[]{rm.toString(),deca.getAnnotationTypeX().toString()},
  796. rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
  797. }
  798. }
  799. return true;
  800. }
  801. return false;
  802. }
  803. private Set findAspectsForMungers(LazyMethodGen mg) {
  804. Set aspectsAffectingType = new HashSet();
  805. for (Iterator iter = mg.matchedShadows.iterator(); iter.hasNext();) {
  806. BcelShadow aShadow = (BcelShadow) iter.next();
  807. // Mungers in effect on that shadow
  808. for (Iterator iter2 = aShadow.getMungers().iterator();iter2.hasNext();) {
  809. ShadowMunger aMunger = (ShadowMunger) iter2.next();
  810. if (aMunger instanceof BcelAdvice) {
  811. BcelAdvice bAdvice = (BcelAdvice)aMunger;
  812. aspectsAffectingType.add(bAdvice.getConcreteAspect().getName());
  813. } else {
  814. // It is a 'Checker' - we don't need to remember aspects that only contributed Checkers...
  815. }
  816. }
  817. }
  818. return aspectsAffectingType;
  819. }
  820. private boolean inlineSelfConstructors(List methodGens) {
  821. boolean inlinedSomething = false;
  822. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  823. LazyMethodGen mg = (LazyMethodGen) i.next();
  824. if (! mg.getName().equals("<init>")) continue;
  825. InstructionHandle ih = findSuperOrThisCall(mg);
  826. if (ih != null && isThisCall(ih)) {
  827. LazyMethodGen donor = getCalledMethod(ih);
  828. inlineMethod(donor, mg, ih);
  829. inlinedSomething = true;
  830. }
  831. }
  832. return inlinedSomething;
  833. }
  834. private void positionAndImplement(List initializationShadows) {
  835. for (Iterator i = initializationShadows.iterator(); i.hasNext(); ) {
  836. BcelShadow s = (BcelShadow) i.next();
  837. positionInitializationShadow(s);
  838. //s.getEnclosingMethod().print();
  839. s.implement();
  840. }
  841. }
  842. private void positionInitializationShadow(BcelShadow s) {
  843. LazyMethodGen mg = s.getEnclosingMethod();
  844. InstructionHandle call = findSuperOrThisCall(mg);
  845. InstructionList body = mg.getBody();
  846. ShadowRange r = new ShadowRange(body);
  847. r.associateWithShadow((BcelShadow) s);
  848. if (s.getKind() == Shadow.PreInitialization) {
  849. // XXX assert first instruction is an ALOAD_0.
  850. // a pre shadow goes from AFTER the first instruction (which we believe to
  851. // be an ALOAD_0) to just before the call to super
  852. r.associateWithTargets(
  853. Range.genStart(body, body.getStart().getNext()),
  854. Range.genEnd(body, call.getPrev()));
  855. } else {
  856. // assert s.getKind() == Shadow.Initialization
  857. r.associateWithTargets(
  858. Range.genStart(body, call.getNext()),
  859. Range.genEnd(body));
  860. }
  861. }
  862. private boolean isThisCall(InstructionHandle ih) {
  863. INVOKESPECIAL inst = (INVOKESPECIAL) ih.getInstruction();
  864. return inst.getClassName(cpg).equals(clazz.getName());
  865. }
  866. /** inline a particular call in bytecode.
  867. *
  868. * @param donor the method we want to inline
  869. * @param recipient the method containing the call we want to inline
  870. * @param call the instructionHandle in recipient's body holding the call we want to
  871. * inline.
  872. */
  873. public static void inlineMethod(
  874. LazyMethodGen donor,
  875. LazyMethodGen recipient,
  876. InstructionHandle call)
  877. {
  878. // assert recipient.contains(call)
  879. /* Implementation notes:
  880. *
  881. * We allocate two slots for every tempvar so we don't screw up
  882. * longs and doubles which may share space. This could be conservatively avoided
  883. * (no reference to a long/double instruction, don't do it) or packed later.
  884. * Right now we don't bother to pack.
  885. *
  886. * Allocate a new var for each formal param of the inlined. Fill with stack
  887. * contents. Then copy the inlined instructions in with the appropriate remap
  888. * table. Any framelocs used by locals in inlined are reallocated to top of
  889. * frame,
  890. */
  891. final InstructionFactory fact = recipient.getEnclosingClass().getFactory();
  892. IntMap frameEnv = new IntMap();
  893. // this also sets up the initial environment
  894. InstructionList argumentStores =
  895. genArgumentStores(donor, recipient, frameEnv, fact);
  896. InstructionList inlineInstructions =
  897. genInlineInstructions(donor, recipient, frameEnv, fact, false);
  898. inlineInstructions.insert(argumentStores);
  899. recipient.getBody().append(call, inlineInstructions);
  900. Utility.deleteInstruction(call, recipient);
  901. }
  902. /** generate the instructions to be inlined.
  903. *
  904. * @param donor the method from which we will copy (and adjust frame and jumps)
  905. * instructions.
  906. * @param recipient the method the instructions will go into. Used to get the frame
  907. * size so we can allocate new frame locations for locals in donor.
  908. * @param frameEnv an environment to map from donor frame to recipient frame,
  909. * initially populated with argument locations.
  910. * @param fact an instruction factory for recipient
  911. */
  912. static InstructionList genInlineInstructions(
  913. LazyMethodGen donor,
  914. LazyMethodGen recipient,
  915. IntMap frameEnv,
  916. InstructionFactory fact,
  917. boolean keepReturns)
  918. {
  919. InstructionList footer = new InstructionList();
  920. InstructionHandle end = footer.append(InstructionConstants.NOP);
  921. InstructionList ret = new InstructionList();
  922. InstructionList sourceList = donor.getBody();
  923. Map srcToDest = new HashMap();
  924. ConstantPoolGen donorCpg = donor.getEnclosingClass().getConstantPoolGen();
  925. ConstantPoolGen recipientCpg = recipient.getEnclosingClass().getConstantPoolGen();
  926. boolean isAcrossClass = donorCpg != recipientCpg;
  927. // first pass: copy the instructions directly, populate the srcToDest map,
  928. // fix frame instructions
  929. for (InstructionHandle src = sourceList.getStart();
  930. src != null;
  931. src = src.getNext())
  932. {
  933. Instruction fresh = Utility.copyInstruction(src.getInstruction());
  934. InstructionHandle dest;
  935. if (fresh instanceof CPInstruction) {
  936. // need to reset index to go to new constant pool. This is totally
  937. // a computation leak... we're testing this LOTS of times. Sigh.
  938. if (isAcrossClass) {
  939. CPInstruction cpi = (CPInstruction) fresh;
  940. cpi.setIndex(
  941. recipientCpg.addConstant(
  942. donorCpg.getConstant(cpi.getIndex()),
  943. donorCpg));
  944. }
  945. }
  946. if (src.getInstruction() == Range.RANGEINSTRUCTION) {
  947. dest = ret.append(Range.RANGEINSTRUCTION);
  948. } else if (fresh instanceof ReturnInstruction) {
  949. if (keepReturns) {
  950. dest = ret.append(fresh);
  951. } else {
  952. dest =
  953. ret.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end));
  954. }
  955. } else if (fresh instanceof BranchInstruction) {
  956. dest = ret.append((BranchInstruction) fresh);
  957. } else if (
  958. fresh instanceof LocalVariableInstruction || fresh instanceof RET) {
  959. IndexedInstruction indexed = (IndexedInstruction) fresh;
  960. int oldIndex = indexed.getIndex();
  961. int freshIndex;
  962. if (!frameEnv.hasKey(oldIndex)) {
  963. freshIndex = recipient.allocateLocal(2);
  964. frameEnv.put(oldIndex, freshIndex);
  965. } else {
  966. freshIndex = frameEnv.get(oldIndex);
  967. }
  968. indexed.setIndex(freshIndex);
  969. dest = ret.append(fresh);
  970. } else {
  971. dest = ret.append(fresh);
  972. }
  973. srcToDest.put(src, dest);
  974. }
  975. // second pass: retarget branch instructions, copy ranges and tags
  976. Map tagMap = new HashMap();
  977. Map shadowMap = new HashMap();
  978. for (InstructionHandle dest = ret.getStart(), src = sourceList.getStart();
  979. dest != null;
  980. dest = dest.getNext(), src = src.getNext()) {
  981. Instruction inst = dest.getInstruction();
  982. // retarget branches
  983. if (inst instanceof BranchInstruction) {
  984. BranchInstruction branch = (BranchInstruction) inst;
  985. InstructionHandle oldTarget = branch.getTarget();
  986. InstructionHandle newTarget =
  987. (InstructionHandle) srcToDest.get(oldTarget);
  988. if (newTarget == null) {
  989. // assert this is a GOTO
  990. // this was a return instruction we previously replaced
  991. } else {
  992. branch.setTarget(newTarget);
  993. if (branch instanceof Select) {
  994. Select select = (Select) branch;
  995. InstructionHandle[] oldTargets = select.getTargets();
  996. for (int k = oldTargets.length - 1; k >= 0; k--) {
  997. select.setTarget(
  998. k,
  999. (InstructionHandle) srcToDest.get(oldTargets[k]));
  1000. }
  1001. }
  1002. }
  1003. }
  1004. //copy over tags and range attributes
  1005. InstructionTargeter[] srcTargeters = src.getTargeters();
  1006. if (srcTargeters != null) {
  1007. for (int j = srcTargeters.length - 1; j >= 0; j--) {
  1008. InstructionTargeter old = srcTargeters[j];
  1009. if (old instanceof Tag) {
  1010. Tag oldTag = (Tag) old;
  1011. Tag fresh = (Tag) tagMap.get(oldTag);
  1012. if (fresh == null) {
  1013. fresh = oldTag.copy();
  1014. tagMap.put(oldTag, fresh);
  1015. }
  1016. dest.addTargeter(fresh);
  1017. } else if (old instanceof ExceptionRange) {
  1018. ExceptionRange er = (ExceptionRange) old;
  1019. if (er.getStart() == src) {
  1020. ExceptionRange freshEr =
  1021. new ExceptionRange(
  1022. recipient.getBody(),
  1023. er.getCatchType(),
  1024. er.getPriority());
  1025. freshEr.associateWithTargets(
  1026. dest,
  1027. (InstructionHandle)srcToDest.get(er.getEnd()),
  1028. (InstructionHandle)srcToDest.get(er.getHandler()));
  1029. }
  1030. } else if (old instanceof ShadowRange) {
  1031. ShadowRange oldRange = (ShadowRange) old;
  1032. if (oldRange.getStart() == src) {
  1033. BcelShadow oldShadow = oldRange.getShadow();
  1034. BcelShadow freshEnclosing =
  1035. oldShadow.getEnclosingShadow() == null
  1036. ? null
  1037. : (BcelShadow) shadowMap.get(oldShadow.getEnclosingShadow());
  1038. BcelShadow freshShadow =
  1039. oldShadow.copyInto(recipient, freshEnclosing);
  1040. ShadowRange freshRange = new ShadowRange(recipient.getBody());
  1041. freshRange.associateWithShadow(freshShadow);
  1042. freshRange.associateWithTargets(
  1043. dest,
  1044. (InstructionHandle) srcToDest.get(oldRange.getEnd()));
  1045. shadowMap.put(oldRange, freshRange);
  1046. //recipient.matchedShadows.add(freshShadow);
  1047. // XXX should go through the NEW copied shadow and update
  1048. // the thisVar, targetVar, and argsVar
  1049. // ??? Might want to also go through at this time and add
  1050. // "extra" vars to the shadow.
  1051. }
  1052. }
  1053. }
  1054. }
  1055. }
  1056. if (!keepReturns) ret.append(footer);
  1057. return ret;
  1058. }
  1059. /** generate the argument stores in preparation for inlining.
  1060. *
  1061. * @param donor the method we will inline from. Used to get the signature.
  1062. * @param recipient the method we will inline into. Used to get the frame size
  1063. * so we can allocate fresh locations.
  1064. * @param frameEnv an empty environment we populate with a map from donor frame to
  1065. * recipient frame.
  1066. * @param fact an instruction factory for recipient
  1067. */
  1068. private static InstructionList genArgumentStores(
  1069. LazyMethodGen donor,
  1070. LazyMethodGen recipient,
  1071. IntMap frameEnv,
  1072. InstructionFactory fact)
  1073. {
  1074. InstructionList ret = new InstructionList();
  1075. int donorFramePos = 0;
  1076. // writing ret back to front because we're popping.
  1077. if (! donor.isStatic()) {
  1078. int targetSlot = recipient.allocateLocal(Type.OBJECT);
  1079. ret.insert(InstructionFactory.createStore(Type.OBJECT, targetSlot));
  1080. frameEnv.put(donorFramePos, targetSlot);
  1081. donorFramePos += 1;
  1082. }
  1083. Type[] argTypes = donor.getArgumentTypes();
  1084. for (int i = 0, len = argTypes.length; i < len; i++) {
  1085. Type argType = argTypes[i];
  1086. int argSlot = recipient.allocateLocal(argType);
  1087. ret.insert(InstructionFactory.createStore(argType, argSlot));
  1088. frameEnv.put(donorFramePos, argSlot);
  1089. donorFramePos += argType.getSize();
  1090. }
  1091. return ret;
  1092. }
  1093. /** get a called method: Assumes the called method is in this class,
  1094. * and the reference to it is exact (a la INVOKESPECIAL).
  1095. *
  1096. * @param ih The InvokeInstruction instructionHandle pointing to the called method.
  1097. */
  1098. private LazyMethodGen getCalledMethod(
  1099. InstructionHandle ih)
  1100. {
  1101. InvokeInstruction inst = (InvokeInstruction) ih.getInstruction();
  1102. String methodName = inst.getName(cpg);
  1103. String signature = inst.getSignature(cpg);
  1104. return clazz.getLazyMethodGen(methodName, signature);
  1105. }
  1106. private void weaveInAddedMethods() {
  1107. Collections.sort(addedLazyMethodGens,
  1108. new Comparator() {
  1109. public int compare(Object a, Object b) {
  1110. LazyMethodGen aa = (LazyMethodGen) a;
  1111. LazyMethodGen bb = (LazyMethodGen) b;
  1112. int i = aa.getName().compareTo(bb.getName());
  1113. if (i != 0) return i;
  1114. return aa.getSignature().compareTo(bb.getSignature());
  1115. }
  1116. }
  1117. );
  1118. for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
  1119. clazz.addMethodGen((LazyMethodGen)i.next());
  1120. }
  1121. }
  1122. void addPerSingletonField(Member field) {
  1123. ObjectType aspectType = (ObjectType) BcelWorld.makeBcelType(field.getReturnType());
  1124. String aspectName = field.getReturnType().getName();
  1125. LazyMethodGen clinit = clazz.getStaticInitializer();
  1126. InstructionList setup = new InstructionList();
  1127. InstructionFactory fact = clazz.getFactory();
  1128. setup.append(fact.createNew(aspectType));
  1129. setup.append(InstructionFactory.createDup(1));
  1130. setup.append(fact.createInvoke(
  1131. aspectName,
  1132. "<init>",
  1133. Type.VOID,
  1134. new Type[0],
  1135. Constants.INVOKESPECIAL));
  1136. setup.append(
  1137. fact.createFieldAccess(
  1138. aspectName,
  1139. field.getName(),
  1140. aspectType,
  1141. Constants.PUTSTATIC));
  1142. clinit.getBody().insert(setup);
  1143. }
  1144. /**
  1145. * Returns null if this is not a Java constructor, and then we won't
  1146. * weave into it at all
  1147. */
  1148. private InstructionHandle findSuperOrThisCall(LazyMethodGen mg) {
  1149. int depth = 1;
  1150. InstructionHandle start = mg.getBody().getStart();
  1151. while (true) {
  1152. if (start == null) return null;
  1153. Instruction inst = start.getInstruction();
  1154. if (inst instanceof INVOKESPECIAL
  1155. && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) {
  1156. depth--;
  1157. if (depth == 0) return start;
  1158. } else if (inst instanceof NEW) {
  1159. depth++;
  1160. }
  1161. start = start.getNext();
  1162. }
  1163. }
  1164. // ----
  1165. private boolean match(LazyMethodGen mg) {
  1166. BcelShadow enclosingShadow;
  1167. List shadowAccumulator = new ArrayList();
  1168. // we want to match ajsynthetic constructors...
  1169. if (mg.getName().equals("<init>")) {
  1170. return matchInit(mg, shadowAccumulator);
  1171. } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) {
  1172. return false;
  1173. } else {
  1174. if (mg.getName().equals("<clinit>")) {
  1175. clinitShadow = enclosingShadow = BcelShadow.makeStaticInitialization(world, mg);
  1176. //System.err.println(enclosingShadow);
  1177. } else if (mg.isAdviceMethod()) {
  1178. enclosingShadow = BcelShadow.makeAdviceExecution(world, mg);
  1179. } else {
  1180. AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature();
  1181. if (effective == null) {
  1182. enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows);
  1183. } else if (effective.isWeaveBody()) {
  1184. ResolvedMember rm = effective.getEffectiveSignature();
  1185. // Annotations for things with effective signatures are never stored in the effective
  1186. // signature itself - we have to hunt for them. Storing them in the effective signature
  1187. // would mean keeping two sets up to date (no way!!)
  1188. fixAnnotationsForResolvedMember(rm,mg.getMemberView());
  1189. enclosingShadow =
  1190. BcelShadow.makeShadowForMethod(world,mg,effective.getShadowKind(),rm);
  1191. } else {
  1192. return false;
  1193. }
  1194. }
  1195. if (canMatchBodyShadows) {
  1196. for (InstructionHandle h = mg.getBody().getStart();
  1197. h != null;
  1198. h = h.getNext()) {
  1199. match(mg, h, enclosingShadow, shadowAccumulator);
  1200. }
  1201. }
  1202. // FIXME asc change from string match if we can, rather brittle. this check actually prevents field-exec jps
  1203. if (canMatch(enclosingShadow.getKind()) && !mg.getName().startsWith("ajc$interFieldInit")) {
  1204. if (match(enclosingShadow, shadowAccumulator)) {
  1205. enclosingShadow.init();
  1206. }
  1207. }
  1208. mg.matchedShadows = shadowAccumulator;
  1209. return !shadowAccumulator.isEmpty();
  1210. }
  1211. }
  1212. private boolean matchInit(LazyMethodGen mg, List shadowAccumulator) {
  1213. BcelShadow enclosingShadow;
  1214. // XXX the enclosing join point is wrong for things before ignoreMe.
  1215. InstructionHandle superOrThisCall = findSuperOrThisCall(mg);
  1216. // we don't walk bodies of things where it's a wrong constructor thingie
  1217. if (superOrThisCall == null) return false;
  1218. enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
  1219. // walk the body
  1220. boolean beforeSuperOrThisCall = true;
  1221. if (shouldWeaveBody(mg)) {
  1222. if (canMatchBodyShadows) {
  1223. for (InstructionHandle h = mg.getBody().getStart();
  1224. h != null;
  1225. h = h.getNext()) {
  1226. if (h == superOrThisCall) {
  1227. beforeSuperOrThisCall = false;
  1228. continue;
  1229. }
  1230. match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
  1231. }
  1232. }
  1233. if (canMatch(Shadow.ConstructorExecution))
  1234. match(enclosingShadow, shadowAccumulator);
  1235. }
  1236. // XXX we don't do pre-inits of interfaces
  1237. // now add interface inits
  1238. if (superOrThisCall != null && ! isThisCall(superOrThisCall)) {
  1239. InstructionHandle curr = enclosingShadow.getRange().getStart();
  1240. for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) {
  1241. IfaceInitList l = (IfaceInitList) i.next();
  1242. Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType);
  1243. BcelShadow initShadow =
  1244. BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig);
  1245. // insert code in place
  1246. InstructionList inits = genInitInstructions(l.list, false);
  1247. if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) {
  1248. initShadow.initIfaceInitializer(curr);
  1249. initShadow.getRange().insert(inits, Range.OutsideBefore);
  1250. }
  1251. }
  1252. // now we add our initialization code
  1253. InstructionList inits = genInitInstructions(addedThisInitializers, false);
  1254. enclosingShadow.getRange().insert(inits, Range.OutsideBefore);
  1255. }
  1256. // actually, you only need to inline the self constructors that are
  1257. // in a particular group (partition the constructors into groups where members
  1258. // call or are called only by those in the group). Then only inline
  1259. // constructors
  1260. // in groups where at least one initialization jp matched. Future work.
  1261. boolean addedInitialization =
  1262. match(
  1263. BcelShadow.makeUnfinishedInitialization(world, mg),
  1264. initializationShadows);
  1265. addedInitialization |=
  1266. match(
  1267. BcelShadow.makeUnfinishedPreinitialization(world, mg),
  1268. initializationShadows);
  1269. mg.matchedShadows = shadowAccumulator;
  1270. return addedInitialization || !shadowAccumulator.isEmpty();
  1271. }
  1272. private boolean shouldWeaveBody(LazyMethodGen mg) {
  1273. if (mg.isBridgeMethod()) return false;
  1274. if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>");
  1275. AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature();
  1276. if (a != null) return a.isWeaveBody();
  1277. return true;
  1278. }
  1279. /**
  1280. * first sorts the mungers, then gens the initializers in the right order
  1281. */
  1282. private InstructionList genInitInstructions(List list, boolean isStatic) {
  1283. list = PartialOrder.sort(list);
  1284. if (list == null) {
  1285. throw new BCException("circularity in inter-types");
  1286. }
  1287. InstructionList ret = new InstructionList();
  1288. for (Iterator i = list.iterator(); i.hasNext();) {
  1289. ConcreteTypeMunger cmunger = (ConcreteTypeMunger) i.next();
  1290. NewFieldTypeMunger munger = (NewFieldTypeMunger) cmunger.getMunger();
  1291. ResolvedMember initMethod = munger.getInitMethod(cmunger.getAspectType());
  1292. if (!isStatic) ret.append(InstructionConstants.ALOAD_0);
  1293. ret.append(Utility.createInvoke(fact, world, initMethod));
  1294. }
  1295. return ret;
  1296. }
  1297. private void match(
  1298. LazyMethodGen mg,
  1299. InstructionHandle ih,
  1300. BcelShadow enclosingShadow,
  1301. List shadowAccumulator)
  1302. {
  1303. Instruction i = ih.getInstruction();
  1304. if ((i instanceof FieldInstruction) &&
  1305. (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))
  1306. ) {
  1307. FieldInstruction fi = (FieldInstruction) i;
  1308. if (fi instanceof PUTFIELD || fi instanceof PUTSTATIC) {
  1309. // check for sets of constant fields. We first check the previous
  1310. // instruction. If the previous instruction is a LD_WHATEVER (push
  1311. // constant on the stack) then we must resolve the field to determine
  1312. // if it's final. If it is final, then we don't generate a shadow.
  1313. InstructionHandle prevHandle = ih.getPrev();
  1314. Instruction prevI = prevHandle.getInstruction();
  1315. if (Utility.isConstantPushInstruction(prevI)) {
  1316. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, (FieldInstruction) i);
  1317. ResolvedMember resolvedField = field.resolve(world);
  1318. if (resolvedField == null) {
  1319. // we can't find the field, so it's not a join point.
  1320. } else if (Modifier.isFinal(resolvedField.getModifiers())) {
  1321. // it's final, so it's the set of a final constant, so it's
  1322. // not a join point according to 1.0.6 and 1.1.
  1323. } else {
  1324. if (canMatch(Shadow.FieldSet))
  1325. matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  1326. }
  1327. } else {
  1328. if (canMatch(Shadow.FieldSet))
  1329. matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  1330. }
  1331. } else {
  1332. if (canMatch(Shadow.FieldGet))
  1333. matchGetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  1334. }
  1335. } else if (i instanceof InvokeInstruction) {
  1336. InvokeInstruction ii = (InvokeInstruction) i;
  1337. if (ii.getMethodName(clazz.getConstantPoolGen()).equals("<init>")) {
  1338. if (canMatch(Shadow.ConstructorCall))
  1339. match(
  1340. BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow),
  1341. shadowAccumulator);
  1342. } else if (ii instanceof INVOKESPECIAL) {
  1343. String onTypeName = ii.getClassName(cpg);
  1344. if (onTypeName.equals(mg.getEnclosingClass().getName())) {
  1345. // we are private
  1346. matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
  1347. } else {
  1348. // we are a super call, and this is not a join point in AspectJ-1.{0,1}
  1349. }
  1350. } else {
  1351. matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
  1352. }
  1353. }
  1354. // performance optimization... we only actually care about ASTORE instructions,
  1355. // since that's what every javac type thing ever uses to start a handler, but for
  1356. // now we'll do this for everybody.
  1357. if (!canMatch(Shadow.ExceptionHandler)) return;
  1358. if (Range.isRangeHandle(ih)) return;
  1359. InstructionTargeter[] targeters = ih.getTargeters();
  1360. if (targeters != null) {
  1361. for (int j = 0; j < targeters.length; j++) {
  1362. InstructionTargeter t = targeters[j];
  1363. if (t instanceof ExceptionRange) {
  1364. // assert t.getHandler() == ih
  1365. ExceptionRange er = (ExceptionRange) t;
  1366. if (er.getCatchType() == null) continue;
  1367. if (isInitFailureHandler(ih)) return;
  1368. match(
  1369. BcelShadow.makeExceptionHandler(
  1370. world,
  1371. er,
  1372. mg, ih, enclosingShadow),
  1373. shadowAccumulator);
  1374. }
  1375. }
  1376. }
  1377. }
  1378. private boolean isInitFailureHandler(InstructionHandle ih) {
  1379. // Skip the astore_0 and aload_0 at the start of the handler and
  1380. // then check if the instruction following these is
  1381. // 'putstatic ajc$initFailureCause'. If it is then we are
  1382. // in the handler we created in AspectClinit.generatePostSyntheticCode()
  1383. InstructionHandle twoInstructionsAway = ih.getNext().getNext();
  1384. if (twoInstructionsAway.getInstruction() instanceof PUTSTATIC) {
  1385. String name = ((PUTSTATIC)twoInstructionsAway.getInstruction()).getFieldName(cpg);
  1386. if (name.equals(NameMangler.INITFAILURECAUSE_FIELD_NAME)) return true;
  1387. }
  1388. return false;
  1389. }
  1390. private void matchSetInstruction(
  1391. LazyMethodGen mg,
  1392. InstructionHandle ih,
  1393. BcelShadow enclosingShadow,
  1394. List shadowAccumulator) {
  1395. FieldInstruction fi = (FieldInstruction) ih.getInstruction();
  1396. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
  1397. // synthetic fields are never join points
  1398. if (field.getName().startsWith(NameMangler.PREFIX)) return;
  1399. ResolvedMember resolvedField = field.resolve(world);
  1400. if (resolvedField == null) {
  1401. // we can't find the field, so it's not a join point.
  1402. return;
  1403. } else if (
  1404. Modifier.isFinal(resolvedField.getModifiers())
  1405. && Utility.isConstantPushInstruction(ih.getPrev().getInstruction())) {
  1406. // it's the set of a final constant, so it's
  1407. // not a join point according to 1.0.6 and 1.1.
  1408. return;
  1409. } else if (resolvedField.isSynthetic()) {
  1410. // sets of synthetics aren't join points in 1.1
  1411. return;
  1412. } else {
  1413. match(
  1414. BcelShadow.makeFieldSet(world, mg, ih, enclosingShadow),
  1415. shadowAccumulator);
  1416. }
  1417. }
  1418. private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List shadowAccumulator) {
  1419. FieldInstruction fi = (FieldInstruction) ih.getInstruction();
  1420. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
  1421. // synthetic fields are never join points
  1422. if (field.getName().startsWith(NameMangler.PREFIX)) return;
  1423. ResolvedMember resolvedField = field.resolve(world);
  1424. if (resolvedField == null) {
  1425. // we can't find the field, so it's not a join point.
  1426. return;
  1427. } else if (resolvedField.isSynthetic()) {
  1428. // sets of synthetics aren't join points in 1.1
  1429. return;
  1430. } else {
  1431. match(BcelShadow.makeFieldGet(world, resolvedField, mg, ih, enclosingShadow), shadowAccumulator);
  1432. }
  1433. }
  1434. /**
  1435. * For a given resolvedmember, this will discover the real annotations for it.
  1436. * <b>Should only be used when the resolvedmember is the contents of an effective signature
  1437. * attribute, as thats the only time when the annotations aren't stored directly in the
  1438. * resolvedMember</b>
  1439. * @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing
  1440. * @param declaredSig the real sig 'blah.ajc$xxx'
  1441. */
  1442. private void fixAnnotationsForResolvedMember(ResolvedMember rm,ResolvedMember declaredSig) {
  1443. try {
  1444. UnresolvedType memberHostType = declaredSig.getDeclaringType();
  1445. ResolvedType[] annotations = (ResolvedType[])mapToAnnotations.get(rm);
  1446. String methodName = declaredSig.getName();
  1447. // FIXME asc shouldnt really rely on string names !
  1448. if (annotations == null) {
  1449. if (rm.getKind()==Member.FIELD) {
  1450. if (methodName.startsWith("ajc$inlineAccessField")) {
  1451. ResolvedMember resolvedDooberry = world.resolve(rm);
  1452. annotations = resolvedDooberry.getAnnotationTypes();
  1453. } else {
  1454. ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm,memberHostType);
  1455. ResolvedMember resolvedDooberry = world.resolve(realthing);
  1456. annotations = resolvedDooberry.getAnnotationTypes();
  1457. }
  1458. } else if (rm.getKind()==Member.METHOD && !rm.isAbstract()) {
  1459. if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) {
  1460. ResolvedMember resolvedDooberry = world.resolve(declaredSig);
  1461. annotations = resolvedDooberry.getAnnotationTypes();
  1462. } else {
  1463. ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm,memberHostType);
  1464. ResolvedMember resolvedDooberry = world.resolve(realthing);
  1465. annotations = resolvedDooberry.getAnnotationTypes();
  1466. }
  1467. } else if (rm.getKind()==Member.CONSTRUCTOR) {
  1468. ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(),rm.getParameterTypes());
  1469. ResolvedMember resolvedDooberry = world.resolve(realThing);
  1470. annotations = resolvedDooberry.getAnnotationTypes();
  1471. }
  1472. if (annotations == null)
  1473. annotations = new ResolvedType[0];
  1474. mapToAnnotations.put(rm,annotations);
  1475. }
  1476. rm.setAnnotationTypes(annotations);
  1477. } catch (Throwable t) {
  1478. //FIXME asc remove this catch after more testing has confirmed the above stuff is OK
  1479. throw new BCException("Unexpectedly went bang when searching for annotations on "+rm,t);
  1480. }
  1481. }
  1482. private void matchInvokeInstruction(LazyMethodGen mg,
  1483. InstructionHandle ih,
  1484. InvokeInstruction invoke,
  1485. BcelShadow enclosingShadow,
  1486. List shadowAccumulator)
  1487. {
  1488. String methodName = invoke.getName(cpg);
  1489. if (methodName.startsWith(NameMangler.PREFIX)) {
  1490. Member jpSig =
  1491. world.makeJoinPointSignatureForMethodInvocation(clazz, invoke);
  1492. ResolvedMember declaredSig = jpSig.resolve(world);
  1493. //System.err.println(method + ", declaredSig: " +declaredSig);
  1494. if (declaredSig == null) return;
  1495. if (declaredSig.getKind() == Member.FIELD) {
  1496. Shadow.Kind kind;
  1497. if (jpSig.getReturnType().equals(ResolvedType.VOID)) {
  1498. kind = Shadow.FieldSet;
  1499. } else {
  1500. kind = Shadow.FieldGet;
  1501. }
  1502. if (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))
  1503. match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow,
  1504. kind, declaredSig),
  1505. shadowAccumulator);
  1506. } else {
  1507. AjAttribute.EffectiveSignatureAttribute effectiveSig =
  1508. declaredSig.getEffectiveSignature();
  1509. if (effectiveSig == null) return;
  1510. //System.err.println("call to inter-type member: " + effectiveSig);
  1511. if (effectiveSig.isWeaveBody()) return;
  1512. ResolvedMember rm = effectiveSig.getEffectiveSignature();
  1513. fixAnnotationsForResolvedMember(rm,declaredSig); // abracadabra
  1514. if (canMatch(effectiveSig.getShadowKind()))
  1515. match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow,
  1516. effectiveSig.getShadowKind(), rm), shadowAccumulator);
  1517. }
  1518. } else {
  1519. if (canMatch(Shadow.MethodCall))
  1520. match(
  1521. BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow),
  1522. shadowAccumulator);
  1523. }
  1524. }
  1525. private boolean match(BcelShadow shadow, List shadowAccumulator) {
  1526. //System.err.println("match: " + shadow);
  1527. boolean isMatched = false;
  1528. for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
  1529. ShadowMunger munger = (ShadowMunger)i.next();
  1530. if (munger.match(shadow, world)) {
  1531. WeaverMetrics.recordMatchResult(true);// Could pass: munger
  1532. shadow.addMunger(munger);
  1533. isMatched = true;
  1534. if (shadow.getKind() == Shadow.StaticInitialization) {
  1535. clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation());
  1536. }
  1537. } else {
  1538. WeaverMetrics.recordMatchResult(false); // Could pass: munger
  1539. }
  1540. }
  1541. if (isMatched) shadowAccumulator.add(shadow);
  1542. return isMatched;
  1543. }
  1544. // ----
  1545. private void implement(LazyMethodGen mg) {
  1546. List shadows = mg.matchedShadows;
  1547. if (shadows == null) return;
  1548. // We depend on a partial order such that inner shadows are earlier on the list
  1549. // than outer shadows. That's fine. This order is preserved if:
  1550. // A preceeds B iff B.getStart() is LATER THAN A.getStart().
  1551. for (Iterator i = shadows.iterator(); i.hasNext(); ) {
  1552. BcelShadow shadow = (BcelShadow)i.next();
  1553. shadow.implement();
  1554. }
  1555. mg.matchedShadows = null;
  1556. }
  1557. // ----
  1558. public LazyClassGen getLazyClassGen() {
  1559. return clazz;
  1560. }
  1561. public List getShadowMungers() {
  1562. return shadowMungers;
  1563. }
  1564. public BcelWorld getWorld() {
  1565. return world;
  1566. }
  1567. // Called by the BcelWeaver to let us know all BcelClassWeavers need to collect reweavable info
  1568. public static void setReweavableMode(boolean mode,boolean compress) {
  1569. inReweavableMode = mode;
  1570. compressReweavableAttributes = compress;
  1571. }
  1572. }