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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858
  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.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.Properties;
  24. import java.util.Set;
  25. import org.aspectj.apache.bcel.Constants;
  26. import org.aspectj.apache.bcel.classfile.Method;
  27. import org.aspectj.apache.bcel.classfile.ConstantPool;
  28. import org.aspectj.apache.bcel.classfile.annotation.AnnotationGen;
  29. import org.aspectj.apache.bcel.generic.FieldGen;
  30. import org.aspectj.apache.bcel.generic.FieldInstruction;
  31. import org.aspectj.apache.bcel.generic.Instruction;
  32. import org.aspectj.apache.bcel.generic.InstructionBranch;
  33. import org.aspectj.apache.bcel.generic.InstructionCP;
  34. import org.aspectj.apache.bcel.generic.InstructionConstants;
  35. import org.aspectj.apache.bcel.generic.InstructionFactory;
  36. import org.aspectj.apache.bcel.generic.InstructionHandle;
  37. import org.aspectj.apache.bcel.generic.InstructionList;
  38. import org.aspectj.apache.bcel.generic.InstructionSelect;
  39. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  40. import org.aspectj.apache.bcel.generic.InvokeInstruction;
  41. import org.aspectj.apache.bcel.generic.LineNumberTag;
  42. import org.aspectj.apache.bcel.generic.LocalVariableTag;
  43. import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
  44. import org.aspectj.apache.bcel.generic.MethodGen;
  45. import org.aspectj.apache.bcel.generic.ObjectType;
  46. import org.aspectj.apache.bcel.generic.RET;
  47. import org.aspectj.apache.bcel.generic.Tag;
  48. import org.aspectj.apache.bcel.generic.Type;
  49. import org.aspectj.bridge.IMessage;
  50. import org.aspectj.bridge.ISourceLocation;
  51. import org.aspectj.bridge.Message;
  52. import org.aspectj.bridge.MessageUtil;
  53. import org.aspectj.bridge.WeaveMessage;
  54. import org.aspectj.bridge.context.CompilationAndWeavingContext;
  55. import org.aspectj.bridge.context.ContextToken;
  56. import org.aspectj.util.PartialOrder;
  57. import org.aspectj.weaver.AjAttribute;
  58. import org.aspectj.weaver.AjcMemberMaker;
  59. import org.aspectj.weaver.AnnotationX;
  60. import org.aspectj.weaver.AsmRelationshipProvider;
  61. import org.aspectj.weaver.BCException;
  62. import org.aspectj.weaver.ConcreteTypeMunger;
  63. import org.aspectj.weaver.IClassWeaver;
  64. import org.aspectj.weaver.IntMap;
  65. import org.aspectj.weaver.Member;
  66. import org.aspectj.weaver.MissingResolvedTypeWithKnownSignature;
  67. import org.aspectj.weaver.NameMangler;
  68. import org.aspectj.weaver.NewConstructorTypeMunger;
  69. import org.aspectj.weaver.NewFieldTypeMunger;
  70. import org.aspectj.weaver.NewMethodTypeMunger;
  71. import org.aspectj.weaver.ResolvedMember;
  72. import org.aspectj.weaver.ResolvedMemberImpl;
  73. import org.aspectj.weaver.ResolvedType;
  74. import org.aspectj.weaver.ResolvedTypeMunger;
  75. import org.aspectj.weaver.Shadow;
  76. import org.aspectj.weaver.ShadowMunger;
  77. import org.aspectj.weaver.UnresolvedType;
  78. import org.aspectj.weaver.WeaverMessages;
  79. import org.aspectj.weaver.WeaverStateInfo;
  80. import org.aspectj.weaver.World;
  81. import org.aspectj.weaver.patterns.DeclareAnnotation;
  82. import org.aspectj.weaver.patterns.ExactTypePattern;
  83. import org.aspectj.weaver.tools.Trace;
  84. import org.aspectj.weaver.tools.TraceFactory;
  85. class BcelClassWeaver implements IClassWeaver {
  86. private static Trace trace = TraceFactory.getTraceFactory().getTrace(BcelClassWeaver.class);
  87. /**
  88. * This is called from {@link BcelWeaver} to perform the per-class weaving process.
  89. */
  90. public static boolean weave(
  91. BcelWorld world,
  92. LazyClassGen clazz,
  93. List shadowMungers,
  94. List typeMungers,
  95. List lateTypeMungers)
  96. {
  97. boolean b = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers, lateTypeMungers).weave();
  98. //System.out.println(clazz.getClassName() + ", " + clazz.getType().getWeaverState());
  99. //clazz.print();
  100. return b;
  101. }
  102. // --------------------------------------------
  103. private final LazyClassGen clazz;
  104. private final List shadowMungers;
  105. private final List typeMungers;
  106. private final List lateTypeMungers;
  107. private final BcelObjectType ty; // alias of clazz.getType()
  108. private final BcelWorld world; // alias of ty.getWorld()
  109. private final ConstantPool cpg; // alias of clazz.getConstantPoolGen()
  110. private final InstructionFactory fact; // alias of clazz.getFactory();
  111. private final List addedLazyMethodGens = new ArrayList();
  112. private final Set addedDispatchTargets = new HashSet();
  113. // Static setting across BcelClassWeavers
  114. private static boolean inReweavableMode = false;
  115. private List addedSuperInitializersAsList = null; // List<IfaceInitList>
  116. private final Map addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList
  117. private List addedThisInitializers = new ArrayList(); // List<NewFieldMunger>
  118. private List addedClassInitializers = new ArrayList(); // List<NewFieldMunger>
  119. private Map mapToAnnotations = new HashMap();
  120. private BcelShadow clinitShadow = null;
  121. /**
  122. * This holds the initialization and pre-initialization shadows for this class
  123. * that were actually matched by mungers (if no match, then we don't even create the
  124. * shadows really).
  125. */
  126. private final List initializationShadows = new ArrayList(1);
  127. private BcelClassWeaver(
  128. BcelWorld world,
  129. LazyClassGen clazz,
  130. List shadowMungers,
  131. List typeMungers,
  132. List lateTypeMungers)
  133. {
  134. super();
  135. // assert world == clazz.getType().getWorld()
  136. this.world = world;
  137. this.clazz = clazz;
  138. this.shadowMungers = shadowMungers;
  139. this.typeMungers = typeMungers;
  140. this.lateTypeMungers = lateTypeMungers;
  141. this.ty = clazz.getBcelObjectType();
  142. this.cpg = clazz.getConstantPool();
  143. this.fact = clazz.getFactory();
  144. fastMatchShadowMungers(shadowMungers);
  145. initializeSuperInitializerMap(ty.getResolvedTypeX());
  146. if (!checkedXsetForLowLevelContextCapturing) {
  147. Properties p = world.getExtraConfiguration();
  148. if (p!=null) {
  149. String s = p.getProperty(World.xsetCAPTURE_ALL_CONTEXT,"false");
  150. captureLowLevelContext = s.equalsIgnoreCase("true");
  151. if (captureLowLevelContext)
  152. world.getMessageHandler().handleMessage(MessageUtil.info("["+World.xsetCAPTURE_ALL_CONTEXT+"=true] Enabling collection of low level context for debug/crash messages"));
  153. }
  154. checkedXsetForLowLevelContextCapturing=true;
  155. }
  156. }
  157. private List[] perKindShadowMungers;
  158. private boolean canMatchBodyShadows = false;
  159. private boolean canMatchInitialization = false;
  160. private void fastMatchShadowMungers(List shadowMungers) {
  161. // beware the annoying property that SHADOW_KINDS[i].getKey == (i+1) !
  162. perKindShadowMungers = new List[Shadow.MAX_SHADOW_KIND + 1];
  163. for (int i = 0; i < perKindShadowMungers.length; i++) {
  164. perKindShadowMungers[i] = new ArrayList(0);
  165. }
  166. for (Iterator iter = shadowMungers.iterator(); iter.hasNext();) {
  167. ShadowMunger munger = (ShadowMunger) iter.next();
  168. int couldMatchKinds = munger.getPointcut().couldMatchKinds();
  169. for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
  170. Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
  171. if (kind.isSet(couldMatchKinds)) perKindShadowMungers[kind.getKey()].add(munger);
  172. }
  173. // Set couldMatchKinds = munger.getPointcut().couldMatchKinds();
  174. // for (Iterator kindIterator = couldMatchKinds.iterator();
  175. // kindIterator.hasNext();) {
  176. // Shadow.Kind aKind = (Shadow.Kind) kindIterator.next();
  177. // perKindShadowMungers[aKind.getKey()].add(munger);
  178. // }
  179. }
  180. if (!perKindShadowMungers[Shadow.Initialization.getKey()].isEmpty())
  181. canMatchInitialization = true;
  182. for (int i = 0; i < Shadow.SHADOW_KINDS.length; i++) {
  183. Shadow.Kind kind = Shadow.SHADOW_KINDS[i];
  184. if (!kind.isEnclosingKind() && !perKindShadowMungers[i+1].isEmpty()) {
  185. canMatchBodyShadows = true;
  186. }
  187. if (perKindShadowMungers[i+1].isEmpty()) {
  188. perKindShadowMungers[i+1] = null;
  189. }
  190. }
  191. }
  192. private boolean canMatch(Shadow.Kind kind) {
  193. return perKindShadowMungers[kind.getKey()] != null;
  194. }
  195. // private void fastMatchShadowMungers(List shadowMungers, ArrayList mungers, Kind kind) {
  196. // FastMatchInfo info = new FastMatchInfo(clazz.getType(), kind);
  197. // for (Iterator i = shadowMungers.iterator(); i.hasNext();) {
  198. // ShadowMunger munger = (ShadowMunger) i.next();
  199. // FuzzyBoolean fb = munger.getPointcut().fastMatch(info);
  200. // WeaverMetrics.recordFastMatchResult(fb);// Could pass: munger.getPointcut().toString()
  201. // if (fb.maybeTrue()) mungers.add(munger);
  202. // }
  203. // }
  204. private void initializeSuperInitializerMap(ResolvedType child) {
  205. ResolvedType[] superInterfaces = child.getDeclaredInterfaces();
  206. for (int i=0, len=superInterfaces.length; i < len; i++) {
  207. if (ty.getResolvedTypeX().isTopmostImplementor(superInterfaces[i])) {
  208. if (addSuperInitializer(superInterfaces[i])) {
  209. initializeSuperInitializerMap(superInterfaces[i]);
  210. }
  211. }
  212. }
  213. }
  214. private boolean addSuperInitializer(ResolvedType onType) {
  215. if (onType.isRawType() || onType.isParameterizedType()) onType = onType.getGenericType();
  216. IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType);
  217. if (l != null) return false;
  218. l = new IfaceInitList(onType);
  219. addedSuperInitializers.put(onType, l);
  220. return true;
  221. }
  222. public void addInitializer(ConcreteTypeMunger cm) {
  223. NewFieldTypeMunger m = (NewFieldTypeMunger) cm.getMunger();
  224. ResolvedType onType = m.getSignature().getDeclaringType().resolve(world);
  225. if (onType.isRawType()) onType = onType.getGenericType();
  226. if (m.getSignature().isStatic()) {
  227. addedClassInitializers.add(cm);
  228. } else {
  229. if (onType == ty.getResolvedTypeX()) {
  230. addedThisInitializers.add(cm);
  231. } else {
  232. IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType);
  233. l.list.add(cm);
  234. }
  235. }
  236. }
  237. private static class IfaceInitList implements PartialOrder.PartialComparable {
  238. final ResolvedType onType;
  239. List list = new ArrayList();
  240. IfaceInitList(ResolvedType onType) {
  241. this.onType = onType;
  242. }
  243. public int compareTo(Object other) {
  244. IfaceInitList o = (IfaceInitList)other;
  245. if (onType.isAssignableFrom(o.onType)) return +1;
  246. else if (o.onType.isAssignableFrom(onType)) return -1;
  247. else return 0;
  248. }
  249. public int fallbackCompareTo(Object other) {
  250. return 0;
  251. }
  252. }
  253. // XXX this is being called, but the result doesn't seem to be being used
  254. public boolean addDispatchTarget(ResolvedMember m) {
  255. return addedDispatchTargets.add(m);
  256. }
  257. public void addLazyMethodGen(LazyMethodGen gen) {
  258. addedLazyMethodGens.add(gen);
  259. }
  260. public void addOrReplaceLazyMethodGen(LazyMethodGen mg) {
  261. if (alreadyDefined(clazz, mg)) return;
  262. for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
  263. LazyMethodGen existing = (LazyMethodGen)i.next();
  264. if (signaturesMatch(mg, existing)) {
  265. if (existing.definingType == null) {
  266. // this means existing was introduced on the class itself
  267. return;
  268. } else if (mg.definingType.isAssignableFrom(existing.definingType)) {
  269. // existing is mg's subtype and dominates mg
  270. return;
  271. } else if (existing.definingType.isAssignableFrom(mg.definingType)) {
  272. // mg is existing's subtype and dominates existing
  273. i.remove();
  274. addedLazyMethodGens.add(mg);
  275. return;
  276. } else {
  277. throw new BCException("conflict between: " + mg + " and " + existing);
  278. }
  279. }
  280. }
  281. addedLazyMethodGens.add(mg);
  282. }
  283. private boolean alreadyDefined(LazyClassGen clazz, LazyMethodGen mg) {
  284. for (Iterator i = clazz.getMethodGens().iterator(); i.hasNext(); ) {
  285. LazyMethodGen existing = (LazyMethodGen)i.next();
  286. if (signaturesMatch(mg, existing)) {
  287. if (!mg.isAbstract() && existing.isAbstract()) {
  288. i.remove();
  289. return false;
  290. }
  291. return true;
  292. }
  293. }
  294. return false;
  295. }
  296. private boolean signaturesMatch(LazyMethodGen mg, LazyMethodGen existing) {
  297. return mg.getName().equals(existing.getName()) &&
  298. mg.getSignature().equals(existing.getSignature());
  299. }
  300. protected static LazyMethodGen makeBridgeMethod(LazyClassGen gen, ResolvedMember member) {
  301. // remove abstract modifier
  302. int mods = member.getModifiers();
  303. if (Modifier.isAbstract(mods)) mods = mods - Modifier.ABSTRACT;
  304. LazyMethodGen ret = new LazyMethodGen(
  305. mods,
  306. BcelWorld.makeBcelType(member.getReturnType()),
  307. member.getName(),
  308. BcelWorld.makeBcelTypes(member.getParameterTypes()),
  309. UnresolvedType.getNames(member.getExceptions()),
  310. gen);
  311. // 43972 : Static crosscutting makes interfaces unusable for javac
  312. // ret.makeSynthetic();
  313. return ret;
  314. }
  315. /**
  316. * Create a single bridge method called 'theBridgeMethod' that bridges to 'whatToBridgeTo'
  317. */
  318. private static void createBridgeMethod(BcelWorld world, LazyMethodGen whatToBridgeToMethodGen, LazyClassGen clazz,ResolvedMember theBridgeMethod) {
  319. InstructionList body;
  320. InstructionFactory fact;
  321. int pos = 0;
  322. ResolvedMember whatToBridgeTo = whatToBridgeToMethodGen.getMemberView();
  323. if (whatToBridgeTo==null) {
  324. whatToBridgeTo =
  325. new ResolvedMemberImpl(Member.METHOD,
  326. whatToBridgeToMethodGen.getEnclosingClass().getType(),
  327. whatToBridgeToMethodGen.getAccessFlags(),
  328. whatToBridgeToMethodGen.getName(),
  329. whatToBridgeToMethodGen.getSignature());
  330. }
  331. LazyMethodGen bridgeMethod = makeBridgeMethod(clazz,theBridgeMethod); // The bridge method in this type will have the same signature as the one in the supertype
  332. bridgeMethod.setAccessFlags(bridgeMethod.getAccessFlags() | 0x00000040 /*BRIDGE = 0x00000040*/ );
  333. Type returnType = BcelWorld.makeBcelType(theBridgeMethod.getReturnType());
  334. Type[] paramTypes = BcelWorld.makeBcelTypes(theBridgeMethod.getParameterTypes());
  335. Type[] newParamTypes=whatToBridgeToMethodGen.getArgumentTypes();
  336. body = bridgeMethod.getBody();
  337. fact = clazz.getFactory();
  338. if (!whatToBridgeToMethodGen.isStatic()) {
  339. body.append(InstructionFactory.createThis());
  340. pos++;
  341. }
  342. for (int i = 0, len = paramTypes.length; i < len; i++) {
  343. Type paramType = paramTypes[i];
  344. body.append(InstructionFactory.createLoad(paramType, pos));
  345. if (!newParamTypes[i].equals(paramTypes[i])) {
  346. if (world.forDEBUG_bridgingCode) System.err.println("Bridging: Cast "+newParamTypes[i]+" from "+paramTypes[i]);
  347. body.append(fact.createCast(paramTypes[i],newParamTypes[i]));
  348. }
  349. pos+=paramType.getSize();
  350. }
  351. body.append(Utility.createInvoke(fact, world,whatToBridgeTo));
  352. body.append(InstructionFactory.createReturn(returnType));
  353. clazz.addMethodGen(bridgeMethod);
  354. }
  355. // ----
  356. public boolean weave() {
  357. if (clazz.isWoven() && !clazz.isReweavable()) {
  358. world.showMessage(IMessage.ERROR,
  359. WeaverMessages.format(WeaverMessages.ALREADY_WOVEN,clazz.getType().getName()),
  360. ty.getSourceLocation(), null);
  361. return false;
  362. }
  363. Set aspectsAffectingType = null;
  364. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType = new HashSet();
  365. boolean isChanged = false;
  366. // we want to "touch" all aspects
  367. if (clazz.getType().isAspect()) isChanged = true;
  368. // start by munging all typeMungers
  369. for (Iterator i = typeMungers.iterator(); i.hasNext(); ) {
  370. Object o = i.next();
  371. if ( !(o instanceof BcelTypeMunger) ) {
  372. //???System.err.println("surprising: " + o);
  373. continue;
  374. }
  375. BcelTypeMunger munger = (BcelTypeMunger)o;
  376. boolean typeMungerAffectedType = munger.munge(this);
  377. if (typeMungerAffectedType) {
  378. isChanged = true;
  379. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.add(munger.getAspectType().getName());
  380. }
  381. }
  382. // Weave special half type/half shadow mungers...
  383. isChanged = weaveDeclareAtMethodCtor(clazz) || isChanged;
  384. isChanged = weaveDeclareAtField(clazz) || isChanged;
  385. // XXX do major sort of stuff
  386. // sort according to: Major: type hierarchy
  387. // within each list: dominates
  388. // don't forget to sort addedThisInitialiers according to dominates
  389. addedSuperInitializersAsList = new ArrayList(addedSuperInitializers.values());
  390. addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList);
  391. if (addedSuperInitializersAsList == null) {
  392. throw new BCException("circularity in inter-types");
  393. }
  394. // this will create a static initializer if there isn't one
  395. // this is in just as bad taste as NOPs
  396. LazyMethodGen staticInit = clazz.getStaticInitializer();
  397. staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true));
  398. // now go through each method, and match against each method. This
  399. // sets up each method's {@link LazyMethodGen#matchedShadows} field,
  400. // and it also possibly adds to {@link #initializationShadows}.
  401. List methodGens = new ArrayList(clazz.getMethodGens());
  402. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  403. LazyMethodGen mg = (LazyMethodGen)i.next();
  404. if (! mg.hasBody()) continue;
  405. if (world.isJoinpointSynchronizationEnabled() &&
  406. world.areSynchronizationPointcutsInUse() &&
  407. mg.getMethod().isSynchronized()) {
  408. transformSynchronizedMethod(mg);
  409. }
  410. boolean shadowMungerMatched = match(mg);
  411. if (shadowMungerMatched) {
  412. // For matching mungers, add their declaring aspects to the list that affected this type
  413. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.addAll(findAspectsForMungers(mg));
  414. isChanged = true;
  415. }
  416. }
  417. // now we weave all but the initialization shadows
  418. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  419. LazyMethodGen mg = (LazyMethodGen)i.next();
  420. if (! mg.hasBody()) continue;
  421. implement(mg);
  422. }
  423. // if we matched any initialization shadows, we inline and weave
  424. if (!initializationShadows.isEmpty()) {
  425. // Repeat next step until nothing left to inline...cant go on
  426. // infinetly as compiler will have detected and reported
  427. // "Recursive constructor invocation"
  428. while (inlineSelfConstructors(methodGens));
  429. positionAndImplement(initializationShadows);
  430. }
  431. // now proceed with late type mungers
  432. if (lateTypeMungers != null) {
  433. for (Iterator i = lateTypeMungers.iterator(); i.hasNext(); ) {
  434. BcelTypeMunger munger = (BcelTypeMunger)i.next();
  435. if (munger.matches(clazz.getType())) {
  436. boolean typeMungerAffectedType = munger.munge(this);
  437. if (typeMungerAffectedType) {
  438. isChanged = true;
  439. if (inReweavableMode || clazz.getType().isAspect()) aspectsAffectingType.add(munger.getAspectType().getName());
  440. }
  441. }
  442. }
  443. }
  444. //FIXME AV - see #75442, for now this is not enough to fix the bug, comment that out until we really fix it
  445. // // flush to save some memory
  446. // PerObjectInterfaceTypeMunger.unregisterFromAsAdvisedBy(clazz.getType());
  447. // finally, if we changed, we add in the introduced methods.
  448. if (isChanged) {
  449. clazz.getOrCreateWeaverStateInfo(inReweavableMode);
  450. weaveInAddedMethods(); // FIXME asc are these potentially affected by declare annotation?
  451. }
  452. if (inReweavableMode) {
  453. WeaverStateInfo wsi = clazz.getOrCreateWeaverStateInfo(true);
  454. wsi.addAspectsAffectingType(aspectsAffectingType);
  455. wsi.setUnwovenClassFileData(ty.getJavaClass().getBytes());
  456. wsi.setReweavable(true);
  457. } else {
  458. clazz.getOrCreateWeaverStateInfo(false).setReweavable(false);
  459. }
  460. return isChanged;
  461. }
  462. // **************************** start of bridge method creation code *****************
  463. // FIXME asc tidy this lot up !!
  464. // FIXME asc refactor into ResolvedType or even ResolvedMember?
  465. /**
  466. * Check if a particular method is overriding another - refactored into this helper so it
  467. * can be used from multiple places.
  468. */
  469. private static ResolvedMember isOverriding(ResolvedType typeToCheck,ResolvedMember methodThatMightBeGettingOverridden,String mname,String mrettype,int mmods,boolean inSamePackage,UnresolvedType[] methodParamsArray) {
  470. // Check if we can be an override...
  471. if (methodThatMightBeGettingOverridden.isStatic()) return null; // we can't be overriding a static method
  472. if (methodThatMightBeGettingOverridden.isPrivate()) return null; // we can't be overriding a private method
  473. if (!methodThatMightBeGettingOverridden.getName().equals(mname)) return null; // names dont match (this will also skip <init> and <clinit> too)
  474. if (methodThatMightBeGettingOverridden.getParameterTypes().length!=methodParamsArray.length) return null; // check same number of parameters
  475. if (!isVisibilityOverride(mmods,methodThatMightBeGettingOverridden,inSamePackage)) return null;
  476. if (typeToCheck.getWorld().forDEBUG_bridgingCode) System.err.println(" Bridging:seriously considering this might be getting overridden '"+methodThatMightBeGettingOverridden+"'");
  477. // Look at erasures of parameters (List<String> erased is List)
  478. boolean sameParams = true;
  479. for (int p = 0;p<methodThatMightBeGettingOverridden.getParameterTypes().length;p++) {
  480. if (!methodThatMightBeGettingOverridden.getParameterTypes()[p].getErasureSignature().equals(methodParamsArray[p].getErasureSignature())) sameParams = false;
  481. }
  482. // If the 'typeToCheck' represents a parameterized type then the method will be the parameterized form of the
  483. // generic method in the generic type. So if the method was 'void m(List<T> lt, T t)' and the parameterized type here
  484. // is I<String> then the method we are looking at will be 'void m(List<String> lt, String t)' which when erased
  485. // is 'void m(List lt,String t)' - so if the parameters *do* match then there is a generic method we are
  486. // overriding
  487. if (sameParams) {
  488. // check for covariance
  489. if (typeToCheck.isParameterizedType()) {
  490. return methodThatMightBeGettingOverridden.getBackingGenericMember();
  491. } else if (!methodThatMightBeGettingOverridden.getReturnType().getErasureSignature().equals(mrettype)) {
  492. // addressing the wierd situation from bug 147801
  493. // just check whether these things are in the right relationship for covariance...
  494. ResolvedType superReturn = typeToCheck.getWorld().resolve(UnresolvedType.forSignature(methodThatMightBeGettingOverridden.getReturnType().getErasureSignature()));
  495. ResolvedType subReturn = typeToCheck.getWorld().resolve(UnresolvedType.forSignature(mrettype));
  496. if (superReturn.isAssignableFrom(subReturn))
  497. return methodThatMightBeGettingOverridden;
  498. }
  499. }
  500. return null;
  501. }
  502. /**
  503. * Looks at the visibility modifiers between two methods, and knows whether they are from classes in
  504. * the same package, and decides whether one overrides the other.
  505. * @return true if there is an overrides rather than a 'hides' relationship
  506. */
  507. static boolean isVisibilityOverride(int methodMods, ResolvedMember inheritedMethod,boolean inSamePackage) {
  508. if (inheritedMethod.isStatic()) return false;
  509. if (methodMods == inheritedMethod.getModifiers()) return true;
  510. if (inheritedMethod.isPrivate()) return false;
  511. boolean isPackageVisible = !inheritedMethod.isPrivate() && !inheritedMethod.isProtected()
  512. && !inheritedMethod.isPublic();
  513. if (isPackageVisible && !inSamePackage) return false;
  514. return true;
  515. }
  516. /**
  517. * This method recurses up a specified type looking for a method that overrides the one passed in.
  518. *
  519. * @return the method being overridden or null if none is found
  520. */
  521. public static ResolvedMember checkForOverride(ResolvedType typeToCheck,String mname,String mparams,String mrettype,int mmods,String mpkg,UnresolvedType[] methodParamsArray) {
  522. if (typeToCheck==null) return null;
  523. if (typeToCheck instanceof MissingResolvedTypeWithKnownSignature) return null; // we just can't tell !
  524. if (typeToCheck.getWorld().forDEBUG_bridgingCode) System.err.println(" Bridging:checking for override of "+mname+" in "+typeToCheck);
  525. String packageName = typeToCheck.getPackageName();
  526. if (packageName==null) packageName="";
  527. boolean inSamePackage = packageName.equals(mpkg); // used when looking at visibility rules
  528. ResolvedMember [] methods = typeToCheck.getDeclaredMethods();
  529. for (int ii=0;ii<methods.length;ii++) {
  530. ResolvedMember methodThatMightBeGettingOverridden = methods[ii]; // the method we are going to check
  531. ResolvedMember isOverriding = isOverriding(typeToCheck,methodThatMightBeGettingOverridden,mname,mrettype,mmods,inSamePackage,methodParamsArray);
  532. if (isOverriding!=null) return isOverriding;
  533. }
  534. List l = typeToCheck.getInterTypeMungers();
  535. for (Iterator iterator = l.iterator(); iterator.hasNext();) {
  536. Object o = iterator.next();
  537. // FIXME asc if its not a BcelTypeMunger then its an EclipseTypeMunger ... do I need to worry about that?
  538. if (o instanceof BcelTypeMunger) {
  539. BcelTypeMunger element = (BcelTypeMunger)o;
  540. if (element.getMunger() instanceof NewMethodTypeMunger) {
  541. if (typeToCheck.getWorld().forDEBUG_bridgingCode) System.err.println("Possible ITD candidate "+element);
  542. ResolvedMember aMethod = element.getSignature();
  543. ResolvedMember isOverriding = isOverriding(typeToCheck,aMethod,mname,mrettype,mmods,inSamePackage,methodParamsArray);
  544. if (isOverriding!=null) return isOverriding;
  545. }
  546. }
  547. }
  548. if (typeToCheck.equals(UnresolvedType.OBJECT)) return null;
  549. ResolvedType superclass = typeToCheck.getSuperclass();
  550. ResolvedMember overriddenMethod = checkForOverride(superclass,mname,mparams,mrettype,mmods,mpkg,methodParamsArray);
  551. if (overriddenMethod!=null) return overriddenMethod;
  552. ResolvedType[] interfaces = typeToCheck.getDeclaredInterfaces();
  553. for (int i = 0; i < interfaces.length; i++) {
  554. ResolvedType anInterface = interfaces[i];
  555. overriddenMethod = checkForOverride(anInterface,mname,mparams,mrettype,mmods,mpkg,methodParamsArray);
  556. if (overriddenMethod!=null) return overriddenMethod;
  557. }
  558. return null;
  559. }
  560. /**
  561. * We need to determine if any methods in this type require bridge methods - this method should only
  562. * be called if necessary to do this calculation, i.e. we are on a 1.5 VM (where covariance/generics exist) and
  563. * the type hierarchy for the specified class has changed (via decp/itd).
  564. *
  565. * See pr108101
  566. */
  567. public static boolean calculateAnyRequiredBridgeMethods(BcelWorld world,LazyClassGen clazz) {
  568. world.ensureAdvancedConfigurationProcessed();
  569. if (!world.isInJava5Mode()) return false; // just double check... the caller should have already verified this
  570. if (clazz.isInterface()) return false; // dont bother if we're an interface
  571. boolean didSomething=false; // set if we build any bridge methods
  572. // So what methods do we have right now in this class?
  573. List /*LazyMethodGen*/ methods = clazz.getMethodGens();
  574. // Keep a set of all methods from this type - it'll help us to check if bridge methods
  575. // have already been created, we don't want to do it twice!
  576. Set methodsSet = new HashSet();
  577. for (int i = 0; i < methods.size(); i++) {
  578. LazyMethodGen aMethod = (LazyMethodGen)methods.get(i);
  579. methodsSet.add(aMethod.getName()+aMethod.getSignature()); // e.g. "foo(Ljava/lang/String;)V"
  580. }
  581. // Now go through all the methods in this type
  582. for (int i = 0; i < methods.size(); i++) {
  583. // This is the local method that we *might* have to bridge to
  584. LazyMethodGen bridgeToCandidate = (LazyMethodGen)methods.get(i);
  585. if (bridgeToCandidate.isBridgeMethod()) continue; // Doh!
  586. String name = bridgeToCandidate.getName();
  587. String psig = bridgeToCandidate.getParameterSignature();
  588. String rsig = bridgeToCandidate.getReturnType().getSignature();
  589. //if (bridgeToCandidate.isAbstract()) continue;
  590. if (bridgeToCandidate.isStatic()) continue; // ignore static methods
  591. if (name.endsWith("init>")) continue; // Skip constructors and static initializers
  592. if (world.forDEBUG_bridgingCode) System.err.println("Bridging: Determining if we have to bridge to "+clazz.getName()+"."+name+""+bridgeToCandidate.getSignature());
  593. // Let's take a look at the superclass
  594. ResolvedType theSuperclass= clazz.getSuperClass();
  595. if (world.forDEBUG_bridgingCode) System.err.println("Bridging: Checking supertype "+theSuperclass);
  596. String pkgName = clazz.getPackageName();
  597. UnresolvedType[] bm = BcelWorld.fromBcel(bridgeToCandidate.getArgumentTypes());
  598. ResolvedMember overriddenMethod = checkForOverride(theSuperclass,name,psig,rsig,bridgeToCandidate.getAccessFlags(),pkgName,bm);
  599. if (overriddenMethod!=null) {
  600. boolean alreadyHaveABridgeMethod = methodsSet.contains(overriddenMethod.getName()+overriddenMethod.getSignature());
  601. if (!alreadyHaveABridgeMethod) {
  602. if (world.forDEBUG_bridgingCode) System.err.println("Bridging:bridging to '"+overriddenMethod+"'");
  603. createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
  604. didSomething = true;
  605. continue; // look at the next method
  606. }
  607. }
  608. // Check superinterfaces
  609. String[] interfaces = clazz.getInterfaceNames();
  610. for (int j = 0; j < interfaces.length; j++) {
  611. if (world.forDEBUG_bridgingCode) System.err.println("Bridging:checking superinterface "+interfaces[j]);
  612. ResolvedType interfaceType = world.resolve(interfaces[j]);
  613. overriddenMethod = checkForOverride(interfaceType,name,psig,rsig,bridgeToCandidate.getAccessFlags(),clazz.getPackageName(),bm);
  614. if (overriddenMethod!=null) {
  615. boolean alreadyHaveABridgeMethod = methodsSet.contains(overriddenMethod.getName()+overriddenMethod.getSignature());
  616. if (!alreadyHaveABridgeMethod) {
  617. createBridgeMethod(world, bridgeToCandidate, clazz, overriddenMethod);
  618. didSomething=true;
  619. if (world.forDEBUG_bridgingCode) System.err.println("Bridging:bridging to "+overriddenMethod);
  620. continue; // look at the next method
  621. }
  622. }
  623. }
  624. }
  625. return didSomething;
  626. }
  627. // **************************** end of bridge method creation code *****************
  628. /**
  629. * Weave any declare @method/@ctor statements into the members of the supplied class
  630. */
  631. private boolean weaveDeclareAtMethodCtor(LazyClassGen clazz) {
  632. List reportedProblems = new ArrayList();
  633. List allDecams = world.getDeclareAnnotationOnMethods();
  634. if (allDecams.isEmpty()) return false; // nothing to do
  635. boolean isChanged = false;
  636. // deal with ITDs
  637. List itdMethodsCtors = getITDSubset(clazz,ResolvedTypeMunger.Method);
  638. itdMethodsCtors.addAll(getITDSubset(clazz,ResolvedTypeMunger.Constructor));
  639. if (!itdMethodsCtors.isEmpty()) {
  640. // Can't use the subset called 'decaMs' as it won't be right for ITDs...
  641. isChanged = weaveAtMethodOnITDSRepeatedly(allDecams,itdMethodsCtors,reportedProblems);
  642. }
  643. // deal with all the other methods...
  644. List members = clazz.getMethodGens();
  645. List decaMs = getMatchingSubset(allDecams,clazz.getType());
  646. if (decaMs.isEmpty()) return false; // nothing to do
  647. if (!members.isEmpty()) {
  648. Set unusedDecams = new HashSet();
  649. unusedDecams.addAll(decaMs);
  650. for (int memberCounter = 0;memberCounter<members.size();memberCounter++) {
  651. LazyMethodGen mg = (LazyMethodGen)members.get(memberCounter);
  652. if (!mg.getName().startsWith(NameMangler.PREFIX)) {
  653. // Single first pass
  654. List worthRetrying = new ArrayList();
  655. boolean modificationOccured = false;
  656. List /*AnnotationGen*/ annotationsToAdd = null;
  657. for (Iterator iter = decaMs.iterator(); iter.hasNext();) {
  658. DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
  659. if (decaM.matches(mg.getMemberView(),world)) {
  660. if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) {
  661. // remove the declare @method since don't want an error when
  662. // the annotation is already there
  663. unusedDecams.remove(decaM);
  664. continue; // skip this one...
  665. }
  666. if (annotationsToAdd==null) annotationsToAdd = new ArrayList();
  667. AnnotationGen a = decaM.getAnnotationX().getBcelAnnotation();
  668. AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPool(),true);
  669. annotationsToAdd.add(ag);
  670. mg.addAnnotation(decaM.getAnnotationX());
  671. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
  672. reportMethodCtorWeavingMessage(clazz, mg.getMemberView(), decaM,mg.getDeclarationLineNumber());
  673. isChanged = true;
  674. modificationOccured = true;
  675. // remove the declare @method since have matched against it
  676. unusedDecams.remove(decaM);
  677. } else {
  678. if (!decaM.isStarredAnnotationPattern())
  679. worthRetrying.add(decaM); // an annotation is specified that might be put on by a subsequent decaf
  680. }
  681. }
  682. // Multiple secondary passes
  683. while (!worthRetrying.isEmpty() && modificationOccured) {
  684. modificationOccured = false;
  685. // lets have another go
  686. List forRemoval = new ArrayList();
  687. for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
  688. DeclareAnnotation decaM = (DeclareAnnotation) iter.next();
  689. if (decaM.matches(mg.getMemberView(),world)) {
  690. if (doesAlreadyHaveAnnotation(mg.getMemberView(),decaM,reportedProblems)) {
  691. // remove the declare @method since don't want an error when
  692. // the annotation is already there
  693. unusedDecams.remove(decaM);
  694. continue; // skip this one...
  695. }
  696. if (annotationsToAdd==null) annotationsToAdd = new ArrayList();
  697. AnnotationGen a = decaM.getAnnotationX().getBcelAnnotation();
  698. //CUSTARD superfluous?
  699. //AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPool(),true);
  700. annotationsToAdd.add(a);
  701. mg.addAnnotation(decaM.getAnnotationX());
  702. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaM.getSourceLocation(),clazz.getName(),mg.getMethod());
  703. isChanged = true;
  704. modificationOccured = true;
  705. forRemoval.add(decaM);
  706. // remove the declare @method since have matched against it
  707. unusedDecams.remove(decaM);
  708. }
  709. }
  710. worthRetrying.removeAll(forRemoval);
  711. }
  712. if (annotationsToAdd!=null) {
  713. Method oldMethod = mg.getMethod();
  714. MethodGen myGen = new MethodGen(oldMethod,clazz.getClassName(),clazz.getConstantPool(),false);// dont use tags, they won't get repaired like for woven methods.
  715. for (Iterator iter = annotationsToAdd.iterator(); iter.hasNext();) {
  716. AnnotationGen a = (AnnotationGen) iter.next();
  717. myGen.addAnnotation(a);
  718. }
  719. Method newMethod = myGen.getMethod();
  720. members.set(memberCounter,new LazyMethodGen(newMethod,clazz));
  721. }
  722. }
  723. }
  724. checkUnusedDeclareAtTypes(unusedDecams, false);
  725. }
  726. return isChanged;
  727. }
  728. // TAG: WeavingMessage
  729. private void reportMethodCtorWeavingMessage(LazyClassGen clazz, ResolvedMember member, DeclareAnnotation decaM,int memberLineNumber) {
  730. if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
  731. StringBuffer parmString = new StringBuffer("(");
  732. UnresolvedType[] paramTypes = member.getParameterTypes();
  733. for (int i = 0; i < paramTypes.length; i++) {
  734. UnresolvedType type = paramTypes[i];
  735. String s = org.aspectj.apache.bcel.classfile.Utility.signatureToString(type.getSignature());
  736. if (s.lastIndexOf(".")!=-1) s =s.substring(s.lastIndexOf(".")+1);
  737. parmString.append(s);
  738. if ((i+1)<paramTypes.length) parmString.append(",");
  739. }
  740. parmString.append(")");
  741. String methodName = member.getName();
  742. StringBuffer sig = new StringBuffer();
  743. sig.append(org.aspectj.apache.bcel.classfile.Utility.accessToString(member.getModifiers()));
  744. sig.append(" ");
  745. sig.append(member.getReturnType().toString());
  746. sig.append(" ");
  747. sig.append(member.getDeclaringType().toString());
  748. sig.append(".");
  749. sig.append(methodName.equals("<init>")?"new":methodName);
  750. sig.append(parmString);
  751. StringBuffer loc = new StringBuffer();
  752. if (clazz.getFileName()==null) {
  753. loc.append("no debug info available");
  754. } else {
  755. loc.append(clazz.getFileName());
  756. if (memberLineNumber!=-1) {
  757. loc.append(":"+memberLineNumber);
  758. }
  759. }
  760. getWorld().getMessageHandler().handleMessage(
  761. WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
  762. new String[]{
  763. sig.toString(),
  764. loc.toString(),
  765. decaM.getAnnotationString(),
  766. methodName.startsWith("<init>")?"constructor":"method",
  767. decaM.getAspect().toString(),
  768. Utility.beautifyLocation(decaM.getSourceLocation())
  769. }));
  770. }
  771. }
  772. /**
  773. * Looks through a list of declare annotation statements and only returns
  774. * those that could possibly match on a field/method/ctor in type.
  775. */
  776. private List getMatchingSubset(List declareAnnotations, ResolvedType type) {
  777. List subset = new ArrayList();
  778. for (Iterator iter = declareAnnotations.iterator(); iter.hasNext();) {
  779. DeclareAnnotation da = (DeclareAnnotation) iter.next();
  780. if (da.couldEverMatch(type)) {
  781. subset.add(da);
  782. }
  783. }
  784. return subset;
  785. }
  786. /**
  787. * Get a subset of all the type mungers defined on this aspect
  788. */
  789. private List getITDSubset(LazyClassGen clazz,ResolvedTypeMunger.Kind wantedKind) {
  790. List subset = new ArrayList();
  791. Collection c = clazz.getBcelObjectType().getTypeMungers();
  792. for (Iterator iter = c.iterator();iter.hasNext();) {
  793. BcelTypeMunger typeMunger = (BcelTypeMunger)iter.next();
  794. if (typeMunger.getMunger().getKind()==wantedKind)
  795. subset.add(typeMunger);
  796. }
  797. return subset;
  798. }
  799. public LazyMethodGen locateAnnotationHolderForFieldMunger(LazyClassGen clazz,BcelTypeMunger fieldMunger) {
  800. NewFieldTypeMunger nftm = (NewFieldTypeMunger)fieldMunger.getMunger();
  801. ResolvedMember lookingFor =AjcMemberMaker.interFieldInitializer(nftm.getSignature(),clazz.getType());
  802. List meths = clazz.getMethodGens();
  803. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  804. LazyMethodGen element = (LazyMethodGen) iter.next();
  805. if (element.getName().equals(lookingFor.getName())) return element;
  806. }
  807. return null;
  808. }
  809. // FIXME asc refactor this to neaten it up
  810. public LazyMethodGen locateAnnotationHolderForMethodCtorMunger(LazyClassGen clazz,BcelTypeMunger methodCtorMunger) {
  811. if (methodCtorMunger.getMunger() instanceof NewMethodTypeMunger) {
  812. NewMethodTypeMunger nftm = (NewMethodTypeMunger)methodCtorMunger.getMunger();
  813. ResolvedMember lookingFor = AjcMemberMaker.interMethodDispatcher(nftm.getSignature(),methodCtorMunger.getAspectType());
  814. List meths = clazz.getMethodGens();
  815. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  816. LazyMethodGen element = (LazyMethodGen) iter.next();
  817. if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
  818. }
  819. return null;
  820. } else if (methodCtorMunger.getMunger() instanceof NewConstructorTypeMunger) {
  821. NewConstructorTypeMunger nftm = (NewConstructorTypeMunger)methodCtorMunger.getMunger();
  822. ResolvedMember lookingFor =AjcMemberMaker.postIntroducedConstructor(methodCtorMunger.getAspectType(),nftm.getSignature().getDeclaringType(),nftm.getSignature().getParameterTypes());
  823. List meths = clazz.getMethodGens();
  824. for (Iterator iter = meths.iterator(); iter.hasNext();) {
  825. LazyMethodGen element = (LazyMethodGen) iter.next();
  826. if (element.getName().equals(lookingFor.getName()) && element.getParameterSignature().equals(lookingFor.getParameterSignature())) return element;
  827. }
  828. return null;
  829. } else {
  830. throw new RuntimeException("Not sure what this is: "+methodCtorMunger);
  831. }
  832. }
  833. /**
  834. * Applies some set of declare @field constructs (List<DeclareAnnotation>) to some bunch
  835. * of ITDfields (List<BcelTypeMunger>. It will iterate over the fields repeatedly until
  836. * everything has been applied.
  837. *
  838. */
  839. private boolean weaveAtFieldRepeatedly(List decaFs, List itdFields,List reportedErrors) {
  840. boolean isChanged = false;
  841. for (Iterator iter = itdFields.iterator(); iter.hasNext();) {
  842. BcelTypeMunger fieldMunger = (BcelTypeMunger) iter.next();
  843. ResolvedMember itdIsActually = fieldMunger.getSignature();
  844. List worthRetrying = new ArrayList();
  845. boolean modificationOccured = false;
  846. for (Iterator iter2 = decaFs.iterator(); iter2.hasNext();) {
  847. DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
  848. if (decaF.matches(itdIsActually,world)) {
  849. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
  850. if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
  851. annotationHolder.addAnnotation(decaF.getAnnotationX());
  852. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
  853. isChanged = true;
  854. modificationOccured = true;
  855. } else {
  856. if (!decaF.isStarredAnnotationPattern())
  857. worthRetrying.add(decaF); // an annotation is specified that might be put on by a subsequent decaf
  858. }
  859. }
  860. while (!worthRetrying.isEmpty() && modificationOccured) {
  861. modificationOccured = false;
  862. List forRemoval = new ArrayList();
  863. for (Iterator iter2 = worthRetrying.iterator(); iter2.hasNext();) {
  864. DeclareAnnotation decaF = (DeclareAnnotation) iter2.next();
  865. if (decaF.matches(itdIsActually,world)) {
  866. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,fieldMunger);
  867. if (doesAlreadyHaveAnnotation(annotationHolder,itdIsActually,decaF,reportedErrors)) continue; // skip this one...
  868. annotationHolder.addAnnotation(decaF.getAnnotationX());
  869. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),itdIsActually.getSourceLocation());
  870. isChanged = true;
  871. modificationOccured = true;
  872. forRemoval.add(decaF);
  873. }
  874. worthRetrying.removeAll(forRemoval);
  875. }
  876. }
  877. }
  878. return isChanged;
  879. }
  880. /**
  881. * Applies some set of declare @method/@ctor constructs (List<DeclareAnnotation>) to some bunch
  882. * of ITDmembers (List<BcelTypeMunger>. It will iterate over the fields repeatedly until
  883. * everything has been applied.
  884. */
  885. private boolean weaveAtMethodOnITDSRepeatedly(List decaMCs, List itdMethodsCtors,List reportedErrors) {
  886. boolean isChanged = false;
  887. for (Iterator iter = itdMethodsCtors.iterator(); iter.hasNext();) {
  888. BcelTypeMunger methodctorMunger = (BcelTypeMunger) iter.next();
  889. ResolvedMember unMangledInterMethod = methodctorMunger.getSignature();
  890. List worthRetrying = new ArrayList();
  891. boolean modificationOccured = false;
  892. for (Iterator iter2 = decaMCs.iterator(); iter2.hasNext();) {
  893. DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next();
  894. if (decaMC.matches(unMangledInterMethod,world)) {
  895. LazyMethodGen annotationHolder = locateAnnotationHolderForMethodCtorMunger(clazz,methodctorMunger);
  896. if (annotationHolder == null || doesAlreadyHaveAnnotation(annotationHolder,unMangledInterMethod,decaMC,reportedErrors)){
  897. continue; // skip this one...
  898. }
  899. annotationHolder.addAnnotation(decaMC.getAnnotationX());
  900. isChanged=true;
  901. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
  902. reportMethodCtorWeavingMessage(clazz, unMangledInterMethod, decaMC,-1);
  903. modificationOccured = true;
  904. } else {
  905. if (!decaMC.isStarredAnnotationPattern())
  906. worthRetrying.add(decaMC); // an annotation is specified that might be put on by a subsequent decaf
  907. }
  908. }
  909. while (!worthRetrying.isEmpty() && modificationOccured) {
  910. modificationOccured = false;
  911. List forRemoval = new ArrayList();
  912. for (Iterator iter2 = worthRetrying.iterator(); iter2.hasNext();) {
  913. DeclareAnnotation decaMC = (DeclareAnnotation) iter2.next();
  914. if (decaMC.matches(unMangledInterMethod,world)) {
  915. LazyMethodGen annotationHolder = locateAnnotationHolderForFieldMunger(clazz,methodctorMunger);
  916. if (doesAlreadyHaveAnnotation(annotationHolder,unMangledInterMethod,decaMC,reportedErrors)) continue; // skip this one...
  917. annotationHolder.addAnnotation(decaMC.getAnnotationX());
  918. unMangledInterMethod.addAnnotation(decaMC.getAnnotationX());
  919. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaMC.getSourceLocation(),unMangledInterMethod.getSourceLocation());
  920. isChanged = true;
  921. modificationOccured = true;
  922. forRemoval.add(decaMC);
  923. }
  924. worthRetrying.removeAll(forRemoval);
  925. }
  926. }
  927. }
  928. return isChanged;
  929. }
  930. private boolean dontAddTwice(DeclareAnnotation decaF, AnnotationX [] dontAddMeTwice){
  931. for (int i = 0; i < dontAddMeTwice.length; i++){
  932. AnnotationX ann = dontAddMeTwice[i];
  933. if (ann != null && decaF.getAnnotationX().getTypeName().equals(ann.getTypeName())){
  934. //dontAddMeTwice[i] = null; // incase it really has been added twice!
  935. return true;
  936. }
  937. }
  938. return false;
  939. }
  940. /**
  941. * Weave any declare @field statements into the fields of the supplied class
  942. *
  943. * Interesting case relating to public ITDd fields. The annotations are really stored against
  944. * the interfieldinit method in the aspect, but the public field is placed in the target
  945. * type and then is processed in the 2nd pass over fields that occurs. I think it would be
  946. * more expensive to avoid putting the annotation on that inserted public field than just to
  947. * have it put there as well as on the interfieldinit method.
  948. */
  949. private boolean weaveDeclareAtField(LazyClassGen clazz) {
  950. // BUGWARNING not getting enough warnings out on declare @field ?
  951. // There is a potential problem here with warnings not coming out - this
  952. // will occur if they are created on the second iteration round this loop.
  953. // We currently deactivate error reporting for the second time round.
  954. // A possible solution is to record what annotations were added by what
  955. // decafs and check that to see if an error needs to be reported - this
  956. // would be expensive so lets skip it for now
  957. List reportedProblems = new ArrayList();
  958. List allDecafs = world.getDeclareAnnotationOnFields();
  959. if (allDecafs.isEmpty()) return false; // nothing to do
  960. boolean isChanged = false;
  961. List itdFields = getITDSubset(clazz,ResolvedTypeMunger.Field);
  962. if (itdFields!=null) {
  963. isChanged = weaveAtFieldRepeatedly(allDecafs,itdFields,reportedProblems);
  964. }
  965. List decaFs = getMatchingSubset(allDecafs,clazz.getType());
  966. if (decaFs.isEmpty()) return false; // nothing more to do
  967. List fields = clazz.getFieldGens();
  968. if (fields!=null) {
  969. Set unusedDecafs = new HashSet();
  970. unusedDecafs.addAll(decaFs);
  971. for (int fieldCounter = 0;fieldCounter<fields.size();fieldCounter++) {
  972. BcelField aBcelField = (BcelField)fields.get(fieldCounter);//new BcelField(clazz.getBcelObjectType(),fields[fieldCounter]);
  973. if (!aBcelField.getName().startsWith(NameMangler.PREFIX)) {
  974. // Single first pass
  975. List worthRetrying = new ArrayList();
  976. boolean modificationOccured = false;
  977. AnnotationX[] dontAddMeTwice = aBcelField.getAnnotations();
  978. // go through all the declare @field statements
  979. for (Iterator iter = decaFs.iterator(); iter.hasNext();) {
  980. DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
  981. if (decaF.matches(aBcelField,world)) {
  982. if (!dontAddTwice(decaF,dontAddMeTwice)){
  983. if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)){
  984. // remove the declare @field since don't want an error when
  985. // the annotation is already there
  986. unusedDecafs.remove(decaF);
  987. continue;
  988. }
  989. if(decaF.getAnnotationX().isRuntimeVisible()){ // isAnnotationWithRuntimeRetention(clazz.getJavaClass(world))){
  990. //if(decaF.getAnnotationTypeX().isAnnotationWithRuntimeRetention(world)){
  991. // it should be runtime visible, so put it on the Field
  992. // Annotation a = decaF.getAnnotationX().getBcelAnnotation();
  993. // AnnotationGen ag = new AnnotationGen(a,clazz.getConstantPoolGen(),true);
  994. // FieldGen myGen = new FieldGen(fields[fieldCounter],clazz.getConstantPoolGen());
  995. // myGen.addAnnotation(ag);
  996. // Field newField = myGen.getField();
  997. aBcelField.addAnnotation(decaF.getAnnotationX());
  998. // clazz.replaceField(fields[fieldCounter],newField);
  999. // fields[fieldCounter]=newField;
  1000. } else{
  1001. aBcelField.addAnnotation(decaF.getAnnotationX());
  1002. }
  1003. }
  1004. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getFieldAsIs());
  1005. reportFieldAnnotationWeavingMessage(clazz, fields, fieldCounter, decaF);
  1006. isChanged = true;
  1007. modificationOccured = true;
  1008. // remove the declare @field since have matched against it
  1009. unusedDecafs.remove(decaF);
  1010. } else {
  1011. if (!decaF.isStarredAnnotationPattern())
  1012. worthRetrying.add(decaF); // an annotation is specified that might be put on by a subsequent decaf
  1013. }
  1014. }
  1015. // Multiple secondary passes
  1016. while (!worthRetrying.isEmpty() && modificationOccured) {
  1017. modificationOccured = false;
  1018. // lets have another go
  1019. List forRemoval = new ArrayList();
  1020. for (Iterator iter = worthRetrying.iterator(); iter.hasNext();) {
  1021. DeclareAnnotation decaF = (DeclareAnnotation) iter.next();
  1022. if (decaF.matches(aBcelField,world)) {
  1023. // below code is for recursive things
  1024. if (doesAlreadyHaveAnnotation(aBcelField,decaF,reportedProblems)) {
  1025. // remove the declare @field since don't want an error when
  1026. // the annotation is already there
  1027. unusedDecafs.remove(decaF);
  1028. continue; // skip this one...
  1029. }
  1030. aBcelField.addAnnotation(decaF.getAnnotationX());
  1031. AsmRelationshipProvider.getDefault().addDeclareAnnotationRelationship(decaF.getSourceLocation(),clazz.getName(),aBcelField.getFieldAsIs());
  1032. isChanged = true;
  1033. modificationOccured = true;
  1034. forRemoval.add(decaF);
  1035. // remove the declare @field since have matched against it
  1036. unusedDecafs.remove(decaF);
  1037. }
  1038. }
  1039. worthRetrying.removeAll(forRemoval);
  1040. }
  1041. }
  1042. }
  1043. checkUnusedDeclareAtTypes(unusedDecafs,true);
  1044. }
  1045. return isChanged;
  1046. }
  1047. // bug 99191 - put out an error message if the type doesn't exist
  1048. /**
  1049. * Report an error if the reason a "declare @method/ctor/field" was not used was because the member
  1050. * specified does not exist. This method is passed some set of declare statements that didn't
  1051. * match and a flag indicating whether the set contains declare @field or declare @method/ctor
  1052. * entries.
  1053. */
  1054. private void checkUnusedDeclareAtTypes(Set unusedDecaTs, boolean isDeclareAtField) {
  1055. for (Iterator iter = unusedDecaTs.iterator(); iter.hasNext();) {
  1056. DeclareAnnotation declA = (DeclareAnnotation) iter.next();
  1057. // Error if an exact type pattern was specified
  1058. if ((declA.isExactPattern() ||
  1059. (declA.getSignaturePattern().getDeclaringType() instanceof ExactTypePattern))
  1060. && (!declA.getSignaturePattern().getName().isAny()
  1061. || (declA.getKind() == DeclareAnnotation.AT_CONSTRUCTOR))) {
  1062. // Quickly check if an ITD meets supplies the 'missing' member
  1063. boolean itdMatch = false;
  1064. List lst = clazz.getType().getInterTypeMungers();
  1065. for (Iterator iterator = lst.iterator(); iterator.hasNext() && !itdMatch;) {
  1066. BcelTypeMunger element = (BcelTypeMunger) iterator.next();
  1067. if (element.getMunger() instanceof NewFieldTypeMunger) {
  1068. NewFieldTypeMunger nftm = (NewFieldTypeMunger)element.getMunger();
  1069. itdMatch = declA.getSignaturePattern().matches(nftm.getSignature(),world,false);
  1070. }else if (element.getMunger() instanceof NewMethodTypeMunger) {
  1071. NewMethodTypeMunger nmtm = (NewMethodTypeMunger)element.getMunger();
  1072. itdMatch = declA.getSignaturePattern().matches(nmtm.getSignature(),world,false);
  1073. } else if (element.getMunger() instanceof NewConstructorTypeMunger) {
  1074. NewConstructorTypeMunger nctm = (NewConstructorTypeMunger)element.getMunger();
  1075. itdMatch = declA.getSignaturePattern().matches(nctm.getSignature(),world,false);
  1076. }
  1077. }
  1078. if (!itdMatch) {
  1079. IMessage message = null;
  1080. if (isDeclareAtField) {
  1081. message = new Message(
  1082. "The field '"+ declA.getSignaturePattern().toString() +
  1083. "' does not exist", declA.getSourceLocation() , true);
  1084. } else {
  1085. message = new Message(
  1086. "The method '"+ declA.getSignaturePattern().toString() +
  1087. "' does not exist", declA.getSourceLocation() , true);
  1088. }
  1089. world.getMessageHandler().handleMessage(message);
  1090. }
  1091. }
  1092. }
  1093. }
  1094. // TAG: WeavingMessage
  1095. private void reportFieldAnnotationWeavingMessage(LazyClassGen clazz, List fields, int fieldCounter, DeclareAnnotation decaF) {
  1096. if (!getWorld().getMessageHandler().isIgnoring(IMessage.WEAVEINFO)){
  1097. BcelField theField = (BcelField)fields.get(fieldCounter);
  1098. world.getMessageHandler().handleMessage(
  1099. WeaveMessage.constructWeavingMessage(WeaveMessage.WEAVEMESSAGE_ANNOTATES,
  1100. new String[]{
  1101. theField.getFieldAsIs().toString() + "' of type '" + clazz.getName(),
  1102. clazz.getFileName(),
  1103. decaF.getAnnotationString(),
  1104. "field",
  1105. decaF.getAspect().toString(),
  1106. Utility.beautifyLocation(decaF.getSourceLocation())}));
  1107. }
  1108. }
  1109. /**
  1110. * Check if a resolved member (field/method/ctor) already has an annotation, if it
  1111. * does then put out a warning and return true
  1112. */
  1113. private boolean doesAlreadyHaveAnnotation(ResolvedMember rm,DeclareAnnotation deca,List reportedProblems) {
  1114. if (rm.hasAnnotation(deca.getAnnotationTypeX())) {
  1115. if (world.getLint().elementAlreadyAnnotated.isEnabled()) {
  1116. Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode());
  1117. if (!reportedProblems.contains(uniqueID)) {
  1118. reportedProblems.add(uniqueID);
  1119. world.getLint().elementAlreadyAnnotated.signal(
  1120. new String[]{rm.toString(),deca.getAnnotationTypeX().toString()},
  1121. rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
  1122. }
  1123. }
  1124. return true;
  1125. }
  1126. return false;
  1127. }
  1128. private boolean doesAlreadyHaveAnnotation(LazyMethodGen rm,ResolvedMember itdfieldsig,DeclareAnnotation deca,List reportedProblems) {
  1129. if (rm != null && rm.hasAnnotation(deca.getAnnotationTypeX())) {
  1130. if (world.getLint().elementAlreadyAnnotated.isEnabled()) {
  1131. Integer uniqueID = new Integer(rm.hashCode()*deca.hashCode());
  1132. if (!reportedProblems.contains(uniqueID)) {
  1133. reportedProblems.add(uniqueID);
  1134. reportedProblems.add(new Integer(itdfieldsig.hashCode()*deca.hashCode()));
  1135. world.getLint().elementAlreadyAnnotated.signal(
  1136. new String[]{itdfieldsig.toString(),deca.getAnnotationTypeX().toString()},
  1137. rm.getSourceLocation(),new ISourceLocation[]{deca.getSourceLocation()});
  1138. }
  1139. }
  1140. return true;
  1141. }
  1142. return false;
  1143. }
  1144. private Set findAspectsForMungers(LazyMethodGen mg) {
  1145. Set aspectsAffectingType = new HashSet();
  1146. for (Iterator iter = mg.matchedShadows.iterator(); iter.hasNext();) {
  1147. BcelShadow aShadow = (BcelShadow) iter.next();
  1148. // Mungers in effect on that shadow
  1149. for (Iterator iter2 = aShadow.getMungers().iterator();iter2.hasNext();) {
  1150. ShadowMunger aMunger = (ShadowMunger) iter2.next();
  1151. if (aMunger instanceof BcelAdvice) {
  1152. BcelAdvice bAdvice = (BcelAdvice)aMunger;
  1153. if(bAdvice.getConcreteAspect() != null){
  1154. aspectsAffectingType.add(bAdvice.getConcreteAspect().getName());
  1155. }
  1156. } else {
  1157. // It is a 'Checker' - we don't need to remember aspects that only contributed Checkers...
  1158. }
  1159. }
  1160. }
  1161. return aspectsAffectingType;
  1162. }
  1163. private boolean inlineSelfConstructors(List methodGens) {
  1164. boolean inlinedSomething = false;
  1165. for (Iterator i = methodGens.iterator(); i.hasNext();) {
  1166. LazyMethodGen mg = (LazyMethodGen) i.next();
  1167. if (! mg.getName().equals("<init>")) continue;
  1168. InstructionHandle ih = findSuperOrThisCall(mg);
  1169. if (ih != null && isThisCall(ih)) {
  1170. LazyMethodGen donor = getCalledMethod(ih);
  1171. inlineMethod(donor, mg, ih);
  1172. inlinedSomething = true;
  1173. }
  1174. }
  1175. return inlinedSomething;
  1176. }
  1177. private void positionAndImplement(List initializationShadows) {
  1178. for (Iterator i = initializationShadows.iterator(); i.hasNext(); ) {
  1179. BcelShadow s = (BcelShadow) i.next();
  1180. positionInitializationShadow(s);
  1181. //s.getEnclosingMethod().print();
  1182. s.implement();
  1183. }
  1184. }
  1185. private void positionInitializationShadow(BcelShadow s) {
  1186. LazyMethodGen mg = s.getEnclosingMethod();
  1187. InstructionHandle call = findSuperOrThisCall(mg);
  1188. InstructionList body = mg.getBody();
  1189. ShadowRange r = new ShadowRange(body);
  1190. r.associateWithShadow((BcelShadow) s);
  1191. if (s.getKind() == Shadow.PreInitialization) {
  1192. // XXX assert first instruction is an ALOAD_0.
  1193. // a pre shadow goes from AFTER the first instruction (which we believe to
  1194. // be an ALOAD_0) to just before the call to super
  1195. r.associateWithTargets(
  1196. Range.genStart(body, body.getStart().getNext()),
  1197. Range.genEnd(body, call.getPrev()));
  1198. } else {
  1199. // assert s.getKind() == Shadow.Initialization
  1200. r.associateWithTargets(
  1201. Range.genStart(body, call.getNext()),
  1202. Range.genEnd(body));
  1203. }
  1204. }
  1205. private boolean isThisCall(InstructionHandle ih) {
  1206. InvokeInstruction inst = (InvokeInstruction) ih.getInstruction();
  1207. return inst.getClassName(cpg).equals(clazz.getName());
  1208. }
  1209. /** inline a particular call in bytecode.
  1210. *
  1211. * @param donor the method we want to inline
  1212. * @param recipient the method containing the call we want to inline
  1213. * @param call the instructionHandle in recipient's body holding the call we want to
  1214. * inline.
  1215. */
  1216. public static void inlineMethod(
  1217. LazyMethodGen donor,
  1218. LazyMethodGen recipient,
  1219. InstructionHandle call)
  1220. {
  1221. // assert recipient.contains(call)
  1222. /* Implementation notes:
  1223. *
  1224. * We allocate two slots for every tempvar so we don't screw up
  1225. * longs and doubles which may share space. This could be conservatively avoided
  1226. * (no reference to a long/double instruction, don't do it) or packed later.
  1227. * Right now we don't bother to pack.
  1228. *
  1229. * Allocate a new var for each formal param of the inlined. Fill with stack
  1230. * contents. Then copy the inlined instructions in with the appropriate remap
  1231. * table. Any framelocs used by locals in inlined are reallocated to top of
  1232. * frame,
  1233. */
  1234. final InstructionFactory fact = recipient.getEnclosingClass().getFactory();
  1235. IntMap frameEnv = new IntMap();
  1236. // this also sets up the initial environment
  1237. InstructionList argumentStores =
  1238. genArgumentStores(donor, recipient, frameEnv, fact);
  1239. InstructionList inlineInstructions =
  1240. genInlineInstructions(donor, recipient, frameEnv, fact, false);
  1241. inlineInstructions.insert(argumentStores);
  1242. recipient.getBody().append(call, inlineInstructions);
  1243. Utility.deleteInstruction(call, recipient);
  1244. }
  1245. // public BcelVar genTempVar(UnresolvedType typeX) {
  1246. // return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize()));
  1247. // }
  1248. //
  1249. // private int genTempVarIndex(int size) {
  1250. // return enclosingMethod.allocateLocal(size);
  1251. // }
  1252. /**
  1253. * Input method is a synchronized method, we remove the bit flag for synchronized and
  1254. * then insert a try..finally block
  1255. *
  1256. * Some jumping through firey hoops required - depending on the input code level (1.5 or not)
  1257. * we may or may not be able to use the LDC instruction that takes a class literal (doesnt on
  1258. * <1.5).
  1259. *
  1260. * FIXME asc Before promoting -Xjoinpoints:synchronization to be a standard option, this needs a bunch of
  1261. * tidying up - there is some duplication that can be removed.
  1262. */
  1263. public static void transformSynchronizedMethod(LazyMethodGen synchronizedMethod) {
  1264. if (trace.isTraceEnabled()) trace.enter("transformSynchronizedMethod",synchronizedMethod);
  1265. // System.err.println("DEBUG: Transforming synchronized method: "+synchronizedMethod.getName());
  1266. final InstructionFactory fact = synchronizedMethod.getEnclosingClass().getFactory();
  1267. InstructionList body = synchronizedMethod.getBody();
  1268. InstructionList prepend = new InstructionList();
  1269. Type enclosingClassType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
  1270. Type javaLangClassType = Type.getType(Class.class);
  1271. // STATIC METHOD TRANSFORMATION
  1272. if (synchronizedMethod.isStatic()) {
  1273. // What to do here depends on the level of the class file!
  1274. // LDC can handle class literals in Java5 and above *sigh*
  1275. if (synchronizedMethod.getEnclosingClass().isAtLeastJava5()) {
  1276. // MONITORENTER logic:
  1277. // 0: ldc #2; //class C
  1278. // 2: dup
  1279. // 3: astore_0
  1280. // 4: monitorenter
  1281. int slotForLockObject = synchronizedMethod.allocateLocal(enclosingClassType);
  1282. prepend.append(fact.createConstant(enclosingClassType));
  1283. prepend.append(InstructionFactory.createDup(1));
  1284. prepend.append(InstructionFactory.createStore(enclosingClassType, slotForLockObject));
  1285. prepend.append(InstructionFactory.MONITORENTER);
  1286. // MONITOREXIT logic:
  1287. // We basically need to wrap the code from the method in a finally block that
  1288. // will ensure monitorexit is called. Content on the finally block seems to
  1289. // be always:
  1290. //
  1291. // E1: ALOAD_1
  1292. // MONITOREXIT
  1293. // ATHROW
  1294. //
  1295. // so lets build that:
  1296. InstructionList finallyBlock = new InstructionList();
  1297. finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class),slotForLockObject));
  1298. finallyBlock.append(InstructionConstants.MONITOREXIT);
  1299. finallyBlock.append(InstructionConstants.ATHROW);
  1300. // finally -> E1
  1301. // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 21)
  1302. // | LDC "hello"
  1303. // | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V
  1304. // | ALOAD_1 (line 20)
  1305. // | MONITOREXIT
  1306. // finally -> E1
  1307. // GOTO L0
  1308. // finally -> E1
  1309. // | E1: ALOAD_1
  1310. // | MONITOREXIT
  1311. // finally -> E1
  1312. // ATHROW
  1313. // L0: RETURN (line 23)
  1314. // search for 'returns' and make them jump to the aload_<n>,monitorexit
  1315. InstructionHandle walker = body.getStart();
  1316. List rets = new ArrayList();
  1317. while (walker!=null) {
  1318. if (walker.getInstruction().isReturnInstruction()) {
  1319. rets.add(walker);
  1320. }
  1321. walker = walker.getNext();
  1322. }
  1323. if (rets.size()>0) {
  1324. // need to ensure targeters for 'return' now instead target the load instruction
  1325. // (so we never jump over the monitorexit logic)
  1326. for (Iterator iter = rets.iterator(); iter.hasNext();) {
  1327. InstructionHandle element = (InstructionHandle) iter.next();
  1328. InstructionList monitorExitBlock = new InstructionList();
  1329. monitorExitBlock.append(InstructionFactory.createLoad(enclosingClassType,slotForLockObject));
  1330. monitorExitBlock.append(InstructionConstants.MONITOREXIT);
  1331. //monitorExitBlock.append(Utility.copyInstruction(element.getInstruction()));
  1332. //element.setInstruction(InstructionFactory.createLoad(classType,slotForThis));
  1333. InstructionHandle monitorExitBlockStart = body.insert(element,monitorExitBlock);
  1334. // now move the targeters from the RET to the start of the monitorexit block
  1335. InstructionTargeter[] targeters = element.getTargeters();
  1336. if (targeters!=null) {
  1337. for (int i = 0; i < targeters.length; i++) {
  1338. InstructionTargeter targeter = targeters[i];
  1339. // what kinds are there?
  1340. if (targeter instanceof LocalVariableTag) {
  1341. // ignore
  1342. } else if (targeter instanceof LineNumberTag) {
  1343. // ignore
  1344. // } else if (targeter instanceof InstructionBranch && ((InstructionBranch)targeter).isGoto()) {
  1345. // // move it...
  1346. // targeter.updateTarget(element, monitorExitBlockStart);
  1347. } else if (targeter instanceof InstructionBranch) {
  1348. // move it
  1349. targeter.updateTarget(element, monitorExitBlockStart);
  1350. } else {
  1351. throw new RuntimeException("Unexpected targeter encountered during transform: "+targeter);
  1352. }
  1353. }
  1354. }
  1355. }
  1356. }
  1357. // now the magic, putting the finally block around the code
  1358. InstructionHandle finallyStart = finallyBlock.getStart();
  1359. InstructionHandle tryPosition = body.getStart();
  1360. InstructionHandle catchPosition = body.getEnd();
  1361. body.insert(body.getStart(),prepend); // now we can put the monitorenter stuff on
  1362. synchronizedMethod.getBody().append(finallyBlock);
  1363. synchronizedMethod.addExceptionHandler(tryPosition, catchPosition,finallyStart,null/*==finally*/,false);
  1364. synchronizedMethod.addExceptionHandler(finallyStart,finallyStart.getNext(),finallyStart,null,false);
  1365. } else {
  1366. // TRANSFORMING STATIC METHOD ON PRE JAVA5
  1367. // Hideous nightmare, class literal references prior to Java5
  1368. // YIKES! this is just the code for MONITORENTER !
  1369. // 0: getstatic #59; //Field class$1:Ljava/lang/Class;
  1370. // 3: dup
  1371. // 4: ifnonnull 32
  1372. // 7: pop
  1373. // try
  1374. // 8: ldc #61; //String java.lang.String
  1375. // 10: invokestatic #44; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
  1376. // 13: dup
  1377. // catch
  1378. // 14: putstatic #59; //Field class$1:Ljava/lang/Class;
  1379. // 17: goto 32
  1380. // 20: new #46; //class java/lang/NoClassDefFoundError
  1381. // 23: dup_x1
  1382. // 24: swap
  1383. // 25: invokevirtual #52; //Method java/lang/Throwable.getMessage:()Ljava/lang/String;
  1384. // 28: invokespecial #54; //Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
  1385. // 31: athrow
  1386. // 32: dup <-- partTwo (branch target)
  1387. // 33: astore_0
  1388. // 34: monitorenter
  1389. //
  1390. // plus exceptiontable entry!
  1391. // 8 13 20 Class java/lang/ClassNotFoundException
  1392. Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
  1393. Type clazzType = Type.getType(Class.class);
  1394. InstructionList parttwo = new InstructionList();
  1395. parttwo.append(InstructionFactory.createDup(1));
  1396. int slotForThis = synchronizedMethod.allocateLocal(classType);
  1397. parttwo.append(InstructionFactory.createStore(clazzType, slotForThis)); // ? should be the real type ? String or something?
  1398. parttwo.append(InstructionFactory.MONITORENTER);
  1399. String fieldname = synchronizedMethod.getEnclosingClass().allocateField("class$");
  1400. FieldGen f = new FieldGen(Modifier.STATIC | Modifier.PRIVATE,
  1401. Type.getType(Class.class),fieldname,synchronizedMethod.getEnclosingClass().getConstantPool());
  1402. synchronizedMethod.getEnclosingClass().addField(f, null);
  1403. // 10: invokestatic #44; //Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
  1404. // 13: dup
  1405. // 14: putstatic #59; //Field class$1:Ljava/lang/Class;
  1406. // 17: goto 32
  1407. // 20: new #46; //class java/lang/NoClassDefFoundError
  1408. // 23: dup_x1
  1409. // 24: swap
  1410. // 25: invokevirtual #52; //Method java/lang/Throwable.getMessage:()Ljava/lang/String;
  1411. // 28: invokespecial #54; //Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
  1412. // 31: athrow
  1413. String name = synchronizedMethod.getEnclosingClass().getName();
  1414. prepend.append(fact.createGetStatic(name, fieldname, Type.getType(Class.class)));
  1415. prepend.append(InstructionFactory.createDup(1));
  1416. prepend.append(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, parttwo.getStart()));
  1417. prepend.append(InstructionFactory.POP);
  1418. prepend.append(fact.createConstant(name));
  1419. InstructionHandle tryInstruction = prepend.getEnd();
  1420. prepend.append(fact.createInvoke("java.lang.Class", "forName", clazzType,new Type[]{ Type.getType(String.class)}, Constants.INVOKESTATIC));
  1421. InstructionHandle catchInstruction = prepend.getEnd();
  1422. prepend.append(InstructionFactory.createDup(1));
  1423. prepend.append(fact.createPutStatic(synchronizedMethod.getEnclosingClass().getType().getName(), fieldname, Type.getType(Class.class)));
  1424. prepend.append(InstructionFactory.createBranchInstruction(Constants.GOTO, parttwo.getStart()));
  1425. // start of catch block
  1426. InstructionList catchBlockForLiteralLoadingFail = new InstructionList();
  1427. catchBlockForLiteralLoadingFail.append(fact.createNew((ObjectType)Type.getType(NoClassDefFoundError.class)));
  1428. catchBlockForLiteralLoadingFail.append(InstructionFactory.createDup_1(1));
  1429. catchBlockForLiteralLoadingFail.append(InstructionFactory.SWAP);
  1430. catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.Throwable", "getMessage", Type.getType(String.class),new Type[]{}, Constants.INVOKEVIRTUAL));
  1431. catchBlockForLiteralLoadingFail.append(fact.createInvoke("java.lang.NoClassDefFoundError", "<init>", Type.VOID,new Type[]{ Type.getType(String.class)}, Constants.INVOKESPECIAL));
  1432. catchBlockForLiteralLoadingFail.append(InstructionFactory.ATHROW);
  1433. InstructionHandle catchBlockStart = catchBlockForLiteralLoadingFail.getStart();
  1434. prepend.append(catchBlockForLiteralLoadingFail);
  1435. prepend.append(parttwo);
  1436. // MONITORENTER
  1437. // pseudocode: load up 'this' (var0), dup it, store it in a new local var (for use with monitorexit) and call monitorenter:
  1438. // ALOAD_0, DUP, ASTORE_<n>, MONITORENTER
  1439. // prepend.append(InstructionFactory.createLoad(classType,0));
  1440. // prepend.append(InstructionFactory.createDup(1));
  1441. // int slotForThis = synchronizedMethod.allocateLocal(classType);
  1442. // prepend.append(InstructionFactory.createStore(classType, slotForThis));
  1443. // prepend.append(InstructionFactory.MONITORENTER);
  1444. // MONITOREXIT
  1445. // here be dragons
  1446. // We basically need to wrap the code from the method in a finally block that
  1447. // will ensure monitorexit is called. Content on the finally block seems to
  1448. // be always:
  1449. //
  1450. // E1: ALOAD_1
  1451. // MONITOREXIT
  1452. // ATHROW
  1453. //
  1454. // so lets build that:
  1455. InstructionList finallyBlock = new InstructionList();
  1456. finallyBlock.append(InstructionFactory.createLoad(Type.getType(java.lang.Class.class),slotForThis));
  1457. finallyBlock.append(InstructionConstants.MONITOREXIT);
  1458. finallyBlock.append(InstructionConstants.ATHROW);
  1459. // finally -> E1
  1460. // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 21)
  1461. // | LDC "hello"
  1462. // | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V
  1463. // | ALOAD_1 (line 20)
  1464. // | MONITOREXIT
  1465. // finally -> E1
  1466. // GOTO L0
  1467. // finally -> E1
  1468. // | E1: ALOAD_1
  1469. // | MONITOREXIT
  1470. // finally -> E1
  1471. // ATHROW
  1472. // L0: RETURN (line 23)
  1473. //frameEnv.put(donorFramePos, thisSlot);
  1474. // search for 'returns' and make them to the aload_<n>,monitorexit
  1475. InstructionHandle walker = body.getStart();
  1476. List rets = new ArrayList();
  1477. while (walker!=null) { //!walker.equals(body.getEnd())) {
  1478. if (walker.getInstruction().isReturnInstruction()) {
  1479. rets.add(walker);
  1480. }
  1481. walker = walker.getNext();
  1482. }
  1483. if (rets.size()>0) {
  1484. // need to ensure targeters for 'return' now instead target the load instruction
  1485. // (so we never jump over the monitorexit logic)
  1486. for (Iterator iter = rets.iterator(); iter.hasNext();) {
  1487. InstructionHandle element = (InstructionHandle) iter.next();
  1488. // System.err.println("Adding monitor exit block at "+element);
  1489. InstructionList monitorExitBlock = new InstructionList();
  1490. monitorExitBlock.append(InstructionFactory.createLoad(classType,slotForThis));
  1491. monitorExitBlock.append(InstructionConstants.MONITOREXIT);
  1492. //monitorExitBlock.append(Utility.copyInstruction(element.getInstruction()));
  1493. //element.setInstruction(InstructionFactory.createLoad(classType,slotForThis));
  1494. InstructionHandle monitorExitBlockStart = body.insert(element,monitorExitBlock);
  1495. // now move the targeters from the RET to the start of the monitorexit block
  1496. InstructionTargeter[] targeters = element.getTargeters();
  1497. if (targeters!=null) {
  1498. for (int i = 0; i < targeters.length; i++) {
  1499. InstructionTargeter targeter = targeters[i];
  1500. // what kinds are there?
  1501. if (targeter instanceof LocalVariableTag) {
  1502. // ignore
  1503. } else if (targeter instanceof LineNumberTag) {
  1504. // ignore
  1505. // } else if (targeter instanceof GOTO || targeter instanceof GOTO_W) {
  1506. // // move it...
  1507. // targeter.updateTarget(element, monitorExitBlockStart);
  1508. } else if (targeter instanceof InstructionBranch) {
  1509. // move it
  1510. targeter.updateTarget(element, monitorExitBlockStart);
  1511. } else {
  1512. throw new RuntimeException("Unexpected targeter encountered during transform: "+targeter);
  1513. }
  1514. }
  1515. }
  1516. }
  1517. }
  1518. // body = rewriteWithMonitorExitCalls(body,fact,true,slotForThis,classType);
  1519. // synchronizedMethod.setBody(body);
  1520. // now the magic, putting the finally block around the code
  1521. InstructionHandle finallyStart = finallyBlock.getStart();
  1522. InstructionHandle tryPosition = body.getStart();
  1523. InstructionHandle catchPosition = body.getEnd();
  1524. body.insert(body.getStart(),prepend); // now we can put the monitorenter stuff on
  1525. synchronizedMethod.getBody().append(finallyBlock);
  1526. synchronizedMethod.addExceptionHandler(tryPosition, catchPosition,finallyStart,null/*==finally*/,false);
  1527. synchronizedMethod.addExceptionHandler(tryInstruction, catchInstruction,catchBlockStart,(ObjectType)Type.getType(ClassNotFoundException.class),true);
  1528. synchronizedMethod.addExceptionHandler(finallyStart,finallyStart.getNext(),finallyStart,null,false);
  1529. }
  1530. } else {
  1531. // TRANSFORMING NON STATIC METHOD
  1532. Type classType = BcelWorld.makeBcelType(synchronizedMethod.getEnclosingClass().getType());
  1533. // MONITORENTER
  1534. // pseudocode: load up 'this' (var0), dup it, store it in a new local var (for use with monitorexit) and call monitorenter:
  1535. // ALOAD_0, DUP, ASTORE_<n>, MONITORENTER
  1536. prepend.append(InstructionFactory.createLoad(classType,0));
  1537. prepend.append(InstructionFactory.createDup(1));
  1538. int slotForThis = synchronizedMethod.allocateLocal(classType);
  1539. prepend.append(InstructionFactory.createStore(classType, slotForThis));
  1540. prepend.append(InstructionFactory.MONITORENTER);
  1541. // body.insert(body.getStart(),prepend);
  1542. // MONITOREXIT
  1543. // We basically need to wrap the code from the method in a finally block that
  1544. // will ensure monitorexit is called. Content on the finally block seems to
  1545. // be always:
  1546. //
  1547. // E1: ALOAD_1
  1548. // MONITOREXIT
  1549. // ATHROW
  1550. //
  1551. // so lets build that:
  1552. InstructionList finallyBlock = new InstructionList();
  1553. finallyBlock.append(InstructionFactory.createLoad(classType,slotForThis));
  1554. finallyBlock.append(InstructionConstants.MONITOREXIT);
  1555. finallyBlock.append(InstructionConstants.ATHROW);
  1556. // finally -> E1
  1557. // | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 21)
  1558. // | LDC "hello"
  1559. // | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V
  1560. // | ALOAD_1 (line 20)
  1561. // | MONITOREXIT
  1562. // finally -> E1
  1563. // GOTO L0
  1564. // finally -> E1
  1565. // | E1: ALOAD_1
  1566. // | MONITOREXIT
  1567. // finally -> E1
  1568. // ATHROW
  1569. // L0: RETURN (line 23)
  1570. //frameEnv.put(donorFramePos, thisSlot);
  1571. // search for 'returns' and make them to the aload_<n>,monitorexit
  1572. InstructionHandle walker = body.getStart();
  1573. List rets = new ArrayList();
  1574. while (walker!=null) { //!walker.equals(body.getEnd())) {
  1575. if (walker.getInstruction().isReturnInstruction()) {
  1576. rets.add(walker);
  1577. }
  1578. walker = walker.getNext();
  1579. }
  1580. if (rets.size()>0) {
  1581. // need to ensure targeters for 'return' now instead target the load instruction
  1582. // (so we never jump over the monitorexit logic)
  1583. for (Iterator iter = rets.iterator(); iter.hasNext();) {
  1584. InstructionHandle element = (InstructionHandle) iter.next();
  1585. // System.err.println("Adding monitor exit block at "+element);
  1586. InstructionList monitorExitBlock = new InstructionList();
  1587. monitorExitBlock.append(InstructionFactory.createLoad(classType,slotForThis));
  1588. monitorExitBlock.append(InstructionConstants.MONITOREXIT);
  1589. //monitorExitBlock.append(Utility.copyInstruction(element.getInstruction()));
  1590. //element.setInstruction(InstructionFactory.createLoad(classType,slotForThis));
  1591. InstructionHandle monitorExitBlockStart = body.insert(element,monitorExitBlock);
  1592. // now move the targeters from the RET to the start of the monitorexit block
  1593. InstructionTargeter[] targeters = element.getTargeters();
  1594. if (targeters!=null) {
  1595. for (int i = 0; i < targeters.length; i++) {
  1596. InstructionTargeter targeter = targeters[i];
  1597. // what kinds are there?
  1598. if (targeter instanceof LocalVariableTag) {
  1599. // ignore
  1600. } else if (targeter instanceof LineNumberTag) {
  1601. // ignore
  1602. // } else if (targeter instanceof GOTO || targeter instanceof GOTO_W) {
  1603. // // move it...
  1604. // targeter.updateTarget(element, monitorExitBlockStart);
  1605. } else if (targeter instanceof InstructionBranch) {
  1606. // move it
  1607. targeter.updateTarget(element, monitorExitBlockStart);
  1608. } else {
  1609. throw new RuntimeException("Unexpected targeter encountered during transform: "+targeter);
  1610. }
  1611. }
  1612. }
  1613. }
  1614. }
  1615. // now the magic, putting the finally block around the code
  1616. InstructionHandle finallyStart = finallyBlock.getStart();
  1617. InstructionHandle tryPosition = body.getStart();
  1618. InstructionHandle catchPosition = body.getEnd();
  1619. body.insert(body.getStart(),prepend); // now we can put the monitorenter stuff on
  1620. synchronizedMethod.getBody().append(finallyBlock);
  1621. synchronizedMethod.addExceptionHandler(tryPosition, catchPosition,finallyStart,null/*==finally*/,false);
  1622. synchronizedMethod.addExceptionHandler(finallyStart,finallyStart.getNext(),finallyStart,null,false);
  1623. // also the exception handling for the finally block jumps to itself
  1624. // max locals will already have been modified in the allocateLocal() call
  1625. // synchronized bit is removed on LazyMethodGen.pack()
  1626. }
  1627. // gonna have to go through and change all aload_0s to load the var from a variable,
  1628. // going to add a new variable for the this var
  1629. if (trace.isTraceEnabled()) trace.exit("transformSynchronizedMethod");
  1630. }
  1631. /** generate the instructions to be inlined.
  1632. *
  1633. * @param donor the method from which we will copy (and adjust frame and jumps)
  1634. * instructions.
  1635. * @param recipient the method the instructions will go into. Used to get the frame
  1636. * size so we can allocate new frame locations for locals in donor.
  1637. * @param frameEnv an environment to map from donor frame to recipient frame,
  1638. * initially populated with argument locations.
  1639. * @param fact an instruction factory for recipient
  1640. */
  1641. static InstructionList genInlineInstructions(
  1642. LazyMethodGen donor,
  1643. LazyMethodGen recipient,
  1644. IntMap frameEnv,
  1645. InstructionFactory fact,
  1646. boolean keepReturns)
  1647. {
  1648. InstructionList footer = new InstructionList();
  1649. InstructionHandle end = footer.append(InstructionConstants.NOP);
  1650. InstructionList ret = new InstructionList();
  1651. InstructionList sourceList = donor.getBody();
  1652. Map srcToDest = new HashMap();
  1653. ConstantPool donorCpg = donor.getEnclosingClass().getConstantPool();
  1654. ConstantPool recipientCpg = recipient.getEnclosingClass().getConstantPool();
  1655. boolean isAcrossClass = donorCpg != recipientCpg;
  1656. // first pass: copy the instructions directly, populate the srcToDest map,
  1657. // fix frame instructions
  1658. for (InstructionHandle src = sourceList.getStart();
  1659. src != null;
  1660. src = src.getNext())
  1661. {
  1662. Instruction fresh = Utility.copyInstruction(src.getInstruction());
  1663. InstructionHandle dest;
  1664. // OPTIMIZE optimize this stuff?
  1665. if (fresh.isConstantPoolInstruction()) {
  1666. // need to reset index to go to new constant pool. This is totally
  1667. // a computation leak... we're testing this LOTS of times. Sigh.
  1668. if (isAcrossClass) {
  1669. InstructionCP cpi = (InstructionCP) fresh;
  1670. cpi.setIndex(
  1671. recipientCpg.addConstant(
  1672. donorCpg.getConstant(cpi.getIndex()),
  1673. donorCpg));
  1674. }
  1675. }
  1676. if (src.getInstruction() == Range.RANGEINSTRUCTION) {
  1677. dest = ret.append(Range.RANGEINSTRUCTION);
  1678. } else if (fresh.isReturnInstruction()) {
  1679. if (keepReturns) {
  1680. dest = ret.append(fresh);
  1681. } else {
  1682. dest =
  1683. ret.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end));
  1684. }
  1685. } else if (fresh instanceof InstructionBranch) {
  1686. dest = ret.append((InstructionBranch) fresh);
  1687. } else if (
  1688. fresh.isLocalVariableInstruction() || fresh instanceof RET) {
  1689. // IndexedInstruction indexed = (IndexedInstruction) fresh;
  1690. int oldIndex = fresh.getIndex();
  1691. int freshIndex;
  1692. if (!frameEnv.hasKey(oldIndex)) {
  1693. freshIndex = recipient.allocateLocal(2);
  1694. frameEnv.put(oldIndex, freshIndex);
  1695. } else {
  1696. freshIndex = frameEnv.get(oldIndex);
  1697. }
  1698. fresh.setIndex(freshIndex);
  1699. dest = ret.append(fresh);
  1700. } else {
  1701. dest = ret.append(fresh);
  1702. }
  1703. srcToDest.put(src, dest);
  1704. }
  1705. // second pass: retarget branch instructions, copy ranges and tags
  1706. Map tagMap = new HashMap();
  1707. Map shadowMap = new HashMap();
  1708. for (InstructionHandle dest = ret.getStart(), src = sourceList.getStart();
  1709. dest != null;
  1710. dest = dest.getNext(), src = src.getNext()) {
  1711. Instruction inst = dest.getInstruction();
  1712. // retarget branches
  1713. if (inst instanceof InstructionBranch) {
  1714. InstructionBranch branch = (InstructionBranch) inst;
  1715. InstructionHandle oldTarget = branch.getTarget();
  1716. InstructionHandle newTarget =
  1717. (InstructionHandle) srcToDest.get(oldTarget);
  1718. if (newTarget == null) {
  1719. // assert this is a GOTO
  1720. // this was a return instruction we previously replaced
  1721. } else {
  1722. branch.setTarget(newTarget);
  1723. if (branch instanceof InstructionSelect) {
  1724. InstructionSelect select = (InstructionSelect) branch;
  1725. InstructionHandle[] oldTargets = select.getTargets();
  1726. for (int k = oldTargets.length - 1; k >= 0; k--) {
  1727. select.setTarget(
  1728. k,
  1729. (InstructionHandle) srcToDest.get(oldTargets[k]));
  1730. }
  1731. }
  1732. }
  1733. }
  1734. //copy over tags and range attributes
  1735. InstructionTargeter[] srcTargeters = src.getTargeters();
  1736. if (srcTargeters != null) {
  1737. for (int j = srcTargeters.length - 1; j >= 0; j--) {
  1738. InstructionTargeter old = srcTargeters[j];
  1739. if (old instanceof Tag) {
  1740. Tag oldTag = (Tag) old;
  1741. Tag fresh = (Tag) tagMap.get(oldTag);
  1742. if (fresh == null) {
  1743. fresh = oldTag.copy();
  1744. tagMap.put(oldTag, fresh);
  1745. }
  1746. dest.addTargeter(fresh);
  1747. } else if (old instanceof ExceptionRange) {
  1748. ExceptionRange er = (ExceptionRange) old;
  1749. if (er.getStart() == src) {
  1750. ExceptionRange freshEr =
  1751. new ExceptionRange(
  1752. recipient.getBody(),
  1753. er.getCatchType(),
  1754. er.getPriority());
  1755. freshEr.associateWithTargets(
  1756. dest,
  1757. (InstructionHandle)srcToDest.get(er.getEnd()),
  1758. (InstructionHandle)srcToDest.get(er.getHandler()));
  1759. }
  1760. } else if (old instanceof ShadowRange) {
  1761. ShadowRange oldRange = (ShadowRange) old;
  1762. if (oldRange.getStart() == src) {
  1763. BcelShadow oldShadow = oldRange.getShadow();
  1764. BcelShadow freshEnclosing =
  1765. oldShadow.getEnclosingShadow() == null
  1766. ? null
  1767. : (BcelShadow) shadowMap.get(oldShadow.getEnclosingShadow());
  1768. BcelShadow freshShadow =
  1769. oldShadow.copyInto(recipient, freshEnclosing);
  1770. ShadowRange freshRange = new ShadowRange(recipient.getBody());
  1771. freshRange.associateWithShadow(freshShadow);
  1772. freshRange.associateWithTargets(
  1773. dest,
  1774. (InstructionHandle) srcToDest.get(oldRange.getEnd()));
  1775. shadowMap.put(oldRange, freshRange);
  1776. //recipient.matchedShadows.add(freshShadow);
  1777. // XXX should go through the NEW copied shadow and update
  1778. // the thisVar, targetVar, and argsVar
  1779. // ??? Might want to also go through at this time and add
  1780. // "extra" vars to the shadow.
  1781. }
  1782. }
  1783. }
  1784. }
  1785. }
  1786. if (!keepReturns) ret.append(footer);
  1787. return ret;
  1788. }
  1789. static InstructionList rewriteWithMonitorExitCalls(InstructionList sourceList,InstructionFactory fact,boolean keepReturns,int monitorVarSlot,Type monitorVarType)
  1790. {
  1791. InstructionList footer = new InstructionList();
  1792. InstructionHandle end = footer.append(InstructionConstants.NOP);
  1793. InstructionList newList = new InstructionList();
  1794. Map srcToDest = new HashMap();
  1795. // first pass: copy the instructions directly, populate the srcToDest map,
  1796. // fix frame instructions
  1797. for (InstructionHandle src = sourceList.getStart(); src != null; src = src.getNext()) {
  1798. Instruction fresh = Utility.copyInstruction(src.getInstruction());
  1799. InstructionHandle dest;
  1800. if (src.getInstruction() == Range.RANGEINSTRUCTION) {
  1801. dest = newList.append(Range.RANGEINSTRUCTION);
  1802. } else if (fresh.isReturnInstruction()) {
  1803. if (keepReturns) {
  1804. newList.append(InstructionFactory.createLoad(monitorVarType,monitorVarSlot));
  1805. newList.append(InstructionConstants.MONITOREXIT);
  1806. dest = newList.append(fresh);
  1807. } else {
  1808. dest =
  1809. newList.append(InstructionFactory.createBranchInstruction(Constants.GOTO, end));
  1810. }
  1811. } else if (fresh instanceof InstructionBranch) {
  1812. dest = newList.append((InstructionBranch) fresh);
  1813. } else if (
  1814. fresh.isLocalVariableInstruction() || fresh instanceof RET) {
  1815. //IndexedInstruction indexed = (IndexedInstruction) fresh;
  1816. int oldIndex = fresh.getIndex();
  1817. int freshIndex;
  1818. // if (!frameEnv.hasKey(oldIndex)) {
  1819. // freshIndex = recipient.allocateLocal(2);
  1820. // frameEnv.put(oldIndex, freshIndex);
  1821. // } else {
  1822. freshIndex = oldIndex;//frameEnv.get(oldIndex);
  1823. // }
  1824. fresh.setIndex(freshIndex);
  1825. dest = newList.append(fresh);
  1826. } else {
  1827. dest = newList.append(fresh);
  1828. }
  1829. srcToDest.put(src, dest);
  1830. }
  1831. // second pass: retarget branch instructions, copy ranges and tags
  1832. Map tagMap = new HashMap();
  1833. Map shadowMap = new HashMap();
  1834. for (InstructionHandle dest = newList.getStart(), src = sourceList.getStart();
  1835. dest != null;
  1836. dest = dest.getNext(), src = src.getNext()) {
  1837. Instruction inst = dest.getInstruction();
  1838. // retarget branches
  1839. if (inst instanceof InstructionBranch) {
  1840. InstructionBranch branch = (InstructionBranch) inst;
  1841. InstructionHandle oldTarget = branch.getTarget();
  1842. InstructionHandle newTarget =
  1843. (InstructionHandle) srcToDest.get(oldTarget);
  1844. if (newTarget == null) {
  1845. // assert this is a GOTO
  1846. // this was a return instruction we previously replaced
  1847. } else {
  1848. branch.setTarget(newTarget);
  1849. if (branch instanceof InstructionSelect) {
  1850. InstructionSelect select = (InstructionSelect) branch;
  1851. InstructionHandle[] oldTargets = select.getTargets();
  1852. for (int k = oldTargets.length - 1; k >= 0; k--) {
  1853. select.setTarget(
  1854. k,
  1855. (InstructionHandle) srcToDest.get(oldTargets[k]));
  1856. }
  1857. }
  1858. }
  1859. }
  1860. //copy over tags and range attributes
  1861. InstructionTargeter[] srcTargeters = src.getTargeters();
  1862. if (srcTargeters != null) {
  1863. for (int j = srcTargeters.length - 1; j >= 0; j--) {
  1864. InstructionTargeter old = srcTargeters[j];
  1865. if (old instanceof Tag) {
  1866. Tag oldTag = (Tag) old;
  1867. Tag fresh = (Tag) tagMap.get(oldTag);
  1868. if (fresh == null) {
  1869. fresh = oldTag.copy();
  1870. tagMap.put(oldTag, fresh);
  1871. }
  1872. dest.addTargeter(fresh);
  1873. } else if (old instanceof ExceptionRange) {
  1874. ExceptionRange er = (ExceptionRange) old;
  1875. if (er.getStart() == src) {
  1876. ExceptionRange freshEr =
  1877. new ExceptionRange(newList/*recipient.getBody()*/,er.getCatchType(),er.getPriority());
  1878. freshEr.associateWithTargets(
  1879. dest,
  1880. (InstructionHandle)srcToDest.get(er.getEnd()),
  1881. (InstructionHandle)srcToDest.get(er.getHandler()));
  1882. }
  1883. }
  1884. /*else if (old instanceof ShadowRange) {
  1885. ShadowRange oldRange = (ShadowRange) old;
  1886. if (oldRange.getStart() == src) {
  1887. BcelShadow oldShadow = oldRange.getShadow();
  1888. BcelShadow freshEnclosing =
  1889. oldShadow.getEnclosingShadow() == null
  1890. ? null
  1891. : (BcelShadow) shadowMap.get(oldShadow.getEnclosingShadow());
  1892. BcelShadow freshShadow =
  1893. oldShadow.copyInto(recipient, freshEnclosing);
  1894. ShadowRange freshRange = new ShadowRange(recipient.getBody());
  1895. freshRange.associateWithShadow(freshShadow);
  1896. freshRange.associateWithTargets(
  1897. dest,
  1898. (InstructionHandle) srcToDest.get(oldRange.getEnd()));
  1899. shadowMap.put(oldRange, freshRange);
  1900. //recipient.matchedShadows.add(freshShadow);
  1901. // XXX should go through the NEW copied shadow and update
  1902. // the thisVar, targetVar, and argsVar
  1903. // ??? Might want to also go through at this time and add
  1904. // "extra" vars to the shadow.
  1905. }
  1906. }*/
  1907. }
  1908. }
  1909. }
  1910. if (!keepReturns) newList.append(footer);
  1911. return newList;
  1912. }
  1913. /** generate the argument stores in preparation for inlining.
  1914. *
  1915. * @param donor the method we will inline from. Used to get the signature.
  1916. * @param recipient the method we will inline into. Used to get the frame size
  1917. * so we can allocate fresh locations.
  1918. * @param frameEnv an empty environment we populate with a map from donor frame to
  1919. * recipient frame.
  1920. * @param fact an instruction factory for recipient
  1921. */
  1922. private static InstructionList genArgumentStores(
  1923. LazyMethodGen donor,
  1924. LazyMethodGen recipient,
  1925. IntMap frameEnv,
  1926. InstructionFactory fact)
  1927. {
  1928. InstructionList ret = new InstructionList();
  1929. int donorFramePos = 0;
  1930. // writing ret back to front because we're popping.
  1931. if (! donor.isStatic()) {
  1932. int targetSlot = recipient.allocateLocal(Type.OBJECT);
  1933. ret.insert(InstructionFactory.createStore(Type.OBJECT, targetSlot));
  1934. frameEnv.put(donorFramePos, targetSlot);
  1935. donorFramePos += 1;
  1936. }
  1937. Type[] argTypes = donor.getArgumentTypes();
  1938. for (int i = 0, len = argTypes.length; i < len; i++) {
  1939. Type argType = argTypes[i];
  1940. int argSlot = recipient.allocateLocal(argType);
  1941. ret.insert(InstructionFactory.createStore(argType, argSlot));
  1942. frameEnv.put(donorFramePos, argSlot);
  1943. donorFramePos += argType.getSize();
  1944. }
  1945. return ret;
  1946. }
  1947. /** get a called method: Assumes the called method is in this class,
  1948. * and the reference to it is exact (a la INVOKESPECIAL).
  1949. *
  1950. * @param ih The InvokeInstruction instructionHandle pointing to the called method.
  1951. */
  1952. private LazyMethodGen getCalledMethod(
  1953. InstructionHandle ih)
  1954. {
  1955. InvokeInstruction inst = (InvokeInstruction) ih.getInstruction();
  1956. String methodName = inst.getName(cpg);
  1957. String signature = inst.getSignature(cpg);
  1958. return clazz.getLazyMethodGen(methodName, signature);
  1959. }
  1960. private void weaveInAddedMethods() {
  1961. Collections.sort(addedLazyMethodGens,
  1962. new Comparator() {
  1963. public int compare(Object a, Object b) {
  1964. LazyMethodGen aa = (LazyMethodGen) a;
  1965. LazyMethodGen bb = (LazyMethodGen) b;
  1966. int i = aa.getName().compareTo(bb.getName());
  1967. if (i != 0) return i;
  1968. return aa.getSignature().compareTo(bb.getSignature());
  1969. }
  1970. }
  1971. );
  1972. for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) {
  1973. clazz.addMethodGen((LazyMethodGen)i.next());
  1974. }
  1975. }
  1976. void addPerSingletonField(Member field) {
  1977. ObjectType aspectType = (ObjectType) BcelWorld.makeBcelType(field.getReturnType());
  1978. String aspectName = field.getReturnType().getName();
  1979. LazyMethodGen clinit = clazz.getStaticInitializer();
  1980. InstructionList setup = new InstructionList();
  1981. InstructionFactory fact = clazz.getFactory();
  1982. setup.append(fact.createNew(aspectType));
  1983. setup.append(InstructionFactory.createDup(1));
  1984. setup.append(fact.createInvoke(
  1985. aspectName,
  1986. "<init>",
  1987. Type.VOID,
  1988. new Type[0],
  1989. Constants.INVOKESPECIAL));
  1990. setup.append(
  1991. fact.createFieldAccess(
  1992. aspectName,
  1993. field.getName(),
  1994. aspectType,
  1995. Constants.PUTSTATIC));
  1996. clinit.getBody().insert(setup);
  1997. }
  1998. /**
  1999. * Returns null if this is not a Java constructor, and then we won't
  2000. * weave into it at all
  2001. */
  2002. private InstructionHandle findSuperOrThisCall(LazyMethodGen mg) {
  2003. int depth = 1;
  2004. InstructionHandle start = mg.getBody().getStart();
  2005. while (true) {
  2006. if (start == null) return null;
  2007. Instruction inst = start.getInstruction();
  2008. if (inst.opcode==Constants.INVOKESPECIAL
  2009. && ((InvokeInstruction) inst).getName(cpg).equals("<init>")) {
  2010. depth--;
  2011. if (depth == 0) return start;
  2012. } else if (inst.opcode==Constants.NEW) {
  2013. depth++;
  2014. }
  2015. start = start.getNext();
  2016. }
  2017. }
  2018. // ----
  2019. private boolean match(LazyMethodGen mg) {
  2020. BcelShadow enclosingShadow;
  2021. List shadowAccumulator = new ArrayList();
  2022. boolean startsAngly = mg.getName().charAt(0)=='<';
  2023. // we want to match ajsynthetic constructors...
  2024. if (startsAngly && mg.getName().equals("<init>")) {
  2025. return matchInit(mg, shadowAccumulator);
  2026. } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) {
  2027. return false;
  2028. } else {
  2029. if (startsAngly && mg.getName().equals("<clinit>")) {
  2030. clinitShadow = enclosingShadow = BcelShadow.makeStaticInitialization(world, mg);
  2031. //System.err.println(enclosingShadow);
  2032. } else if (mg.isAdviceMethod()) {
  2033. enclosingShadow = BcelShadow.makeAdviceExecution(world, mg);
  2034. } else {
  2035. AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature();
  2036. if (effective == null) {
  2037. enclosingShadow = BcelShadow.makeMethodExecution(world, mg, !canMatchBodyShadows);
  2038. } else if (effective.isWeaveBody()) {
  2039. ResolvedMember rm = effective.getEffectiveSignature();
  2040. // Annotations for things with effective signatures are never stored in the effective
  2041. // signature itself - we have to hunt for them. Storing them in the effective signature
  2042. // would mean keeping two sets up to date (no way!!)
  2043. fixAnnotationsForResolvedMember(rm,mg.getMemberView());
  2044. enclosingShadow =
  2045. BcelShadow.makeShadowForMethod(world,mg,effective.getShadowKind(),rm);
  2046. } else {
  2047. return false;
  2048. }
  2049. }
  2050. if (canMatchBodyShadows) {
  2051. for (InstructionHandle h = mg.getBody().getStart();
  2052. h != null;
  2053. h = h.getNext()) {
  2054. match(mg, h, enclosingShadow, shadowAccumulator);
  2055. }
  2056. }
  2057. // FIXME asc change from string match if we can, rather brittle. this check actually prevents field-exec jps
  2058. if (canMatch(enclosingShadow.getKind()) && !(mg.getName().charAt(0)=='a' && mg.getName().startsWith("ajc$interFieldInit"))) {
  2059. if (match(enclosingShadow, shadowAccumulator)) {
  2060. enclosingShadow.init();
  2061. }
  2062. }
  2063. mg.matchedShadows = shadowAccumulator;
  2064. return !shadowAccumulator.isEmpty();
  2065. }
  2066. }
  2067. private boolean matchInit(LazyMethodGen mg, List shadowAccumulator) {
  2068. BcelShadow enclosingShadow;
  2069. // XXX the enclosing join point is wrong for things before ignoreMe.
  2070. InstructionHandle superOrThisCall = findSuperOrThisCall(mg);
  2071. // we don't walk bodies of things where it's a wrong constructor thingie
  2072. if (superOrThisCall == null) return false;
  2073. enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall);
  2074. if (mg.getEffectiveSignature() != null) {
  2075. enclosingShadow.setMatchingSignature(mg.getEffectiveSignature().getEffectiveSignature());
  2076. }
  2077. // walk the body
  2078. boolean beforeSuperOrThisCall = true;
  2079. if (shouldWeaveBody(mg)) {
  2080. if (canMatchBodyShadows) {
  2081. for (InstructionHandle h = mg.getBody().getStart();
  2082. h != null;
  2083. h = h.getNext()) {
  2084. if (h == superOrThisCall) {
  2085. beforeSuperOrThisCall = false;
  2086. continue;
  2087. }
  2088. match(mg, h, beforeSuperOrThisCall ? null : enclosingShadow, shadowAccumulator);
  2089. }
  2090. }
  2091. if (canMatch(Shadow.ConstructorExecution))
  2092. match(enclosingShadow, shadowAccumulator);
  2093. }
  2094. // XXX we don't do pre-inits of interfaces
  2095. // now add interface inits
  2096. if (superOrThisCall != null && ! isThisCall(superOrThisCall)) {
  2097. InstructionHandle curr = enclosingShadow.getRange().getStart();
  2098. for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) {
  2099. IfaceInitList l = (IfaceInitList) i.next();
  2100. Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType);
  2101. BcelShadow initShadow =
  2102. BcelShadow.makeIfaceInitialization(world, mg, ifaceInitSig);
  2103. // insert code in place
  2104. InstructionList inits = genInitInstructions(l.list, false);
  2105. if (match(initShadow, shadowAccumulator) || !inits.isEmpty()) {
  2106. initShadow.initIfaceInitializer(curr);
  2107. initShadow.getRange().insert(inits, Range.OutsideBefore);
  2108. }
  2109. }
  2110. // now we add our initialization code
  2111. InstructionList inits = genInitInstructions(addedThisInitializers, false);
  2112. enclosingShadow.getRange().insert(inits, Range.OutsideBefore);
  2113. }
  2114. // actually, you only need to inline the self constructors that are
  2115. // in a particular group (partition the constructors into groups where members
  2116. // call or are called only by those in the group). Then only inline
  2117. // constructors
  2118. // in groups where at least one initialization jp matched. Future work.
  2119. boolean addedInitialization =
  2120. match(
  2121. BcelShadow.makeUnfinishedInitialization(world, mg),
  2122. initializationShadows);
  2123. addedInitialization |=
  2124. match(
  2125. BcelShadow.makeUnfinishedPreinitialization(world, mg),
  2126. initializationShadows);
  2127. mg.matchedShadows = shadowAccumulator;
  2128. return addedInitialization || !shadowAccumulator.isEmpty();
  2129. }
  2130. private boolean shouldWeaveBody(LazyMethodGen mg) {
  2131. if (mg.isBridgeMethod()) return false;
  2132. if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>");
  2133. AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature();
  2134. if (a != null) return a.isWeaveBody();
  2135. return true;
  2136. }
  2137. /**
  2138. * first sorts the mungers, then gens the initializers in the right order
  2139. */
  2140. private InstructionList genInitInstructions(List list, boolean isStatic) {
  2141. list = PartialOrder.sort(list);
  2142. if (list == null) {
  2143. throw new BCException("circularity in inter-types");
  2144. }
  2145. InstructionList ret = new InstructionList();
  2146. for (Iterator i = list.iterator(); i.hasNext();) {
  2147. ConcreteTypeMunger cmunger = (ConcreteTypeMunger) i.next();
  2148. NewFieldTypeMunger munger = (NewFieldTypeMunger) cmunger.getMunger();
  2149. ResolvedMember initMethod = munger.getInitMethod(cmunger.getAspectType());
  2150. if (!isStatic) ret.append(InstructionConstants.ALOAD_0);
  2151. ret.append(Utility.createInvoke(fact, world, initMethod));
  2152. }
  2153. return ret;
  2154. }
  2155. private void match(
  2156. LazyMethodGen mg,
  2157. InstructionHandle ih,
  2158. BcelShadow enclosingShadow,
  2159. List shadowAccumulator)
  2160. {
  2161. Instruction i = ih.getInstruction();
  2162. if ((i instanceof FieldInstruction) &&
  2163. (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))
  2164. ) {
  2165. FieldInstruction fi = (FieldInstruction) i;
  2166. if (fi.opcode==Constants.PUTFIELD || fi.opcode==Constants.PUTSTATIC) {
  2167. // check for sets of constant fields. We first check the previous
  2168. // instruction. If the previous instruction is a LD_WHATEVER (push
  2169. // constant on the stack) then we must resolve the field to determine
  2170. // if it's final. If it is final, then we don't generate a shadow.
  2171. InstructionHandle prevHandle = ih.getPrev();
  2172. Instruction prevI = prevHandle.getInstruction();
  2173. if (Utility.isConstantPushInstruction(prevI)) {
  2174. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, (FieldInstruction) i);
  2175. ResolvedMember resolvedField = field.resolve(world);
  2176. if (resolvedField == null) {
  2177. // we can't find the field, so it's not a join point.
  2178. } else if (Modifier.isFinal(resolvedField.getModifiers())) {
  2179. // it's final, so it's the set of a final constant, so it's
  2180. // not a join point according to 1.0.6 and 1.1.
  2181. } else {
  2182. if (canMatch(Shadow.FieldSet))
  2183. matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  2184. }
  2185. } else {
  2186. if (canMatch(Shadow.FieldSet))
  2187. matchSetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  2188. }
  2189. } else {
  2190. if (canMatch(Shadow.FieldGet))
  2191. matchGetInstruction(mg, ih, enclosingShadow, shadowAccumulator);
  2192. }
  2193. } else if (i instanceof InvokeInstruction) {
  2194. InvokeInstruction ii = (InvokeInstruction) i;
  2195. if (ii.getMethodName(clazz.getConstantPool()).equals("<init>")) {
  2196. if (canMatch(Shadow.ConstructorCall))
  2197. match(
  2198. BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow),
  2199. shadowAccumulator);
  2200. } else if (ii.opcode==Constants.INVOKESPECIAL) {
  2201. String onTypeName = ii.getClassName(cpg);
  2202. if (onTypeName.equals(mg.getEnclosingClass().getName())) {
  2203. // we are private
  2204. matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
  2205. } else {
  2206. // we are a super call, and this is not a join point in AspectJ-1.{0,1}
  2207. }
  2208. } else {
  2209. matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator);
  2210. }
  2211. } else if (world.isJoinpointArrayConstructionEnabled() && i.isArrayCreationInstruction()) {
  2212. if (canMatch(Shadow.ConstructorCall)) {
  2213. boolean debug = false;
  2214. if (debug) System.err.println("Found new array instruction: "+i);
  2215. if (i.opcode==Constants.ANEWARRAY) {
  2216. // ANEWARRAY arrayInstruction = (ANEWARRAY)i;
  2217. ObjectType arrayType = i.getLoadClassType(clazz.getConstantPool());
  2218. if (debug) System.err.println("Array type is "+arrayType);
  2219. BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world,mg,ih,enclosingShadow);
  2220. match(ctorCallShadow,shadowAccumulator);
  2221. } else if (i.opcode==Constants.NEWARRAY) {
  2222. // NEWARRAY arrayInstruction = (NEWARRAY)i;
  2223. Type arrayType = i.getType();
  2224. if (debug) System.err.println("Array type is "+arrayType);
  2225. BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world,mg,ih,enclosingShadow);
  2226. match(ctorCallShadow,shadowAccumulator);
  2227. } else if (i instanceof MULTIANEWARRAY) {
  2228. MULTIANEWARRAY arrayInstruction = (MULTIANEWARRAY)i;
  2229. ObjectType arrayType = arrayInstruction.getLoadClassType(clazz.getConstantPool());
  2230. if (debug) System.err.println("Array type is "+arrayType);
  2231. BcelShadow ctorCallShadow = BcelShadow.makeArrayConstructorCall(world,mg,ih,enclosingShadow);
  2232. match(ctorCallShadow,shadowAccumulator);
  2233. }
  2234. }
  2235. // see pr77166 if you are thinking about implementing this
  2236. // } else if (i instanceof AALOAD ) {
  2237. // AALOAD arrayLoad = (AALOAD)i;
  2238. // Type arrayType = arrayLoad.getType(clazz.getConstantPoolGen());
  2239. // BcelShadow arrayLoadShadow = BcelShadow.makeArrayLoadCall(world,mg,ih,enclosingShadow);
  2240. // match(arrayLoadShadow,shadowAccumulator);
  2241. // } else if (i instanceof AASTORE) {
  2242. // // ... magic required
  2243. } else if ( world.isJoinpointSynchronizationEnabled() &&
  2244. ((i.getOpcode()==Constants.MONITORENTER) || (i.getOpcode()==Constants.MONITOREXIT))) {
  2245. // if (canMatch(Shadow.Monitoring)) {
  2246. if (i.getOpcode()==Constants.MONITORENTER) {
  2247. BcelShadow monitorEntryShadow = BcelShadow.makeMonitorEnter(world,mg,ih,enclosingShadow);
  2248. match(monitorEntryShadow,shadowAccumulator);
  2249. } else {
  2250. BcelShadow monitorExitShadow = BcelShadow.makeMonitorExit(world,mg,ih,enclosingShadow);
  2251. match(monitorExitShadow,shadowAccumulator);
  2252. }
  2253. // }
  2254. }
  2255. // performance optimization... we only actually care about ASTORE instructions,
  2256. // since that's what every javac type thing ever uses to start a handler, but for
  2257. // now we'll do this for everybody.
  2258. if (!canMatch(Shadow.ExceptionHandler)) return;
  2259. if (Range.isRangeHandle(ih)) return;
  2260. InstructionTargeter[] targeters = ih.getTargeters();
  2261. if (targeters != null) {
  2262. for (int j = 0; j < targeters.length; j++) {
  2263. InstructionTargeter t = targeters[j];
  2264. if (t instanceof ExceptionRange) {
  2265. // assert t.getHandler() == ih
  2266. ExceptionRange er = (ExceptionRange) t;
  2267. if (er.getCatchType() == null) continue;
  2268. if (isInitFailureHandler(ih)) return;
  2269. match(
  2270. BcelShadow.makeExceptionHandler(
  2271. world,
  2272. er,
  2273. mg, ih, enclosingShadow),
  2274. shadowAccumulator);
  2275. }
  2276. }
  2277. }
  2278. }
  2279. private boolean isInitFailureHandler(InstructionHandle ih) {
  2280. // Skip the astore_0 and aload_0 at the start of the handler and
  2281. // then check if the instruction following these is
  2282. // 'putstatic ajc$initFailureCause'. If it is then we are
  2283. // in the handler we created in AspectClinit.generatePostSyntheticCode()
  2284. InstructionHandle twoInstructionsAway = ih.getNext().getNext();
  2285. if (twoInstructionsAway.getInstruction().opcode==Constants.PUTSTATIC) {
  2286. String name = ((FieldInstruction)twoInstructionsAway.getInstruction()).getFieldName(cpg);
  2287. if (name.equals(NameMangler.INITFAILURECAUSE_FIELD_NAME)) return true;
  2288. }
  2289. return false;
  2290. }
  2291. private void matchSetInstruction(
  2292. LazyMethodGen mg,
  2293. InstructionHandle ih,
  2294. BcelShadow enclosingShadow,
  2295. List shadowAccumulator) {
  2296. FieldInstruction fi = (FieldInstruction) ih.getInstruction();
  2297. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
  2298. // synthetic fields are never join points
  2299. if (field.getName().startsWith(NameMangler.PREFIX)) return;
  2300. ResolvedMember resolvedField = field.resolve(world);
  2301. if (resolvedField == null) {
  2302. // we can't find the field, so it's not a join point.
  2303. return;
  2304. } else if (
  2305. Modifier.isFinal(resolvedField.getModifiers())
  2306. && Utility.isConstantPushInstruction(ih.getPrev().getInstruction())) {
  2307. // it's the set of a final constant, so it's
  2308. // not a join point according to 1.0.6 and 1.1.
  2309. return;
  2310. } else if (resolvedField.isSynthetic()) {
  2311. // sets of synthetics aren't join points in 1.1
  2312. return;
  2313. } else {
  2314. // Fix for bug 172107 (similar the "get" fix for bug 109728)
  2315. BcelShadow bs=
  2316. BcelShadow.makeFieldSet(world, resolvedField, mg, ih, enclosingShadow);
  2317. String cname = fi.getClassName(cpg);
  2318. if (!resolvedField.getDeclaringType().getName().equals(cname)) {
  2319. bs.setActualTargetType(cname);
  2320. }
  2321. match(bs, shadowAccumulator);
  2322. }
  2323. }
  2324. private void matchGetInstruction(LazyMethodGen mg, InstructionHandle ih, BcelShadow enclosingShadow, List shadowAccumulator) {
  2325. FieldInstruction fi = (FieldInstruction) ih.getInstruction();
  2326. Member field = BcelWorld.makeFieldJoinPointSignature(clazz, fi);
  2327. // synthetic fields are never join points
  2328. if (field.getName().startsWith(NameMangler.PREFIX)) return;
  2329. ResolvedMember resolvedField = field.resolve(world);
  2330. if (resolvedField == null) {
  2331. // we can't find the field, so it's not a join point.
  2332. return;
  2333. } else if (resolvedField.isSynthetic()) {
  2334. // sets of synthetics aren't join points in 1.1
  2335. return;
  2336. } else {
  2337. BcelShadow bs = BcelShadow.makeFieldGet(world,resolvedField,mg,ih,enclosingShadow);
  2338. String cname = fi.getClassName(cpg);
  2339. if (!resolvedField.getDeclaringType().getName().equals(cname)) {
  2340. bs.setActualTargetType(cname);
  2341. }
  2342. match(bs, shadowAccumulator);
  2343. }
  2344. }
  2345. /**
  2346. * For some named resolved type, this method looks for a member with a particular name -
  2347. * it should only be used when you truly believe there is only one member with that
  2348. * name in the type as it returns the first one it finds.
  2349. */
  2350. private ResolvedMember findResolvedMemberNamed(ResolvedType type,String methodName) {
  2351. ResolvedMember[] allMethods = type.getDeclaredMethods();
  2352. for (int i = 0; i < allMethods.length; i++) {
  2353. ResolvedMember member = allMethods[i];
  2354. if (member.getName().equals(methodName)) return member;
  2355. }
  2356. return null;
  2357. }
  2358. /**
  2359. * For a given resolvedmember, this will discover the real annotations for it.
  2360. * <b>Should only be used when the resolvedmember is the contents of an effective signature
  2361. * attribute, as thats the only time when the annotations aren't stored directly in the
  2362. * resolvedMember</b>
  2363. * @param rm the sig we want it to pretend to be 'int A.m()' or somesuch ITD like thing
  2364. * @param declaredSig the real sig 'blah.ajc$xxx'
  2365. */
  2366. private void fixAnnotationsForResolvedMember(ResolvedMember rm,ResolvedMember declaredSig) {
  2367. try {
  2368. UnresolvedType memberHostType = declaredSig.getDeclaringType();
  2369. ResolvedType[] annotations = (ResolvedType[])mapToAnnotations.get(rm);
  2370. String methodName = declaredSig.getName();
  2371. // FIXME asc shouldnt really rely on string names !
  2372. if (annotations == null) {
  2373. if (rm.getKind()==Member.FIELD) {
  2374. if (methodName.startsWith("ajc$inlineAccessField")) {
  2375. ResolvedMember resolvedDooberry = world.resolve(rm);
  2376. annotations = resolvedDooberry.getAnnotationTypes();
  2377. } else {
  2378. ResolvedMember realthing = AjcMemberMaker.interFieldInitializer(rm,memberHostType);
  2379. ResolvedMember resolvedDooberry = world.resolve(realthing);
  2380. annotations = resolvedDooberry.getAnnotationTypes();
  2381. }
  2382. } else if (rm.getKind()==Member.METHOD && !rm.isAbstract()) {
  2383. if (methodName.startsWith("ajc$inlineAccessMethod") || methodName.startsWith("ajc$superDispatch")) {
  2384. ResolvedMember resolvedDooberry = world.resolve(declaredSig);
  2385. annotations = resolvedDooberry.getAnnotationTypes();
  2386. } else {
  2387. ResolvedMember realthing = AjcMemberMaker.interMethodDispatcher(rm.resolve(world),memberHostType).resolve(world);
  2388. // ResolvedMember resolvedDooberry = world.resolve(realthing);
  2389. ResolvedMember theRealMember = findResolvedMemberNamed(memberHostType.resolve(world),realthing.getName());
  2390. // AMC temp guard for M4
  2391. if (theRealMember == null) {
  2392. throw new UnsupportedOperationException("Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified");
  2393. }
  2394. annotations = theRealMember.getAnnotationTypes();
  2395. }
  2396. } else if (rm.getKind()==Member.CONSTRUCTOR) {
  2397. ResolvedMember realThing = AjcMemberMaker.postIntroducedConstructor(memberHostType.resolve(world),rm.getDeclaringType(),rm.getParameterTypes());
  2398. ResolvedMember resolvedDooberry = world.resolve(realThing);
  2399. // AMC temp guard for M4
  2400. if (resolvedDooberry == null) {
  2401. throw new UnsupportedOperationException("Known limitation in M4 - can't find ITD members when type variable is used as an argument and has upper bound specified");
  2402. }
  2403. annotations = resolvedDooberry.getAnnotationTypes();
  2404. }
  2405. if (annotations == null)
  2406. annotations = new ResolvedType[0];
  2407. mapToAnnotations.put(rm,annotations);
  2408. }
  2409. rm.setAnnotationTypes(annotations);
  2410. }
  2411. catch (UnsupportedOperationException ex) {
  2412. throw ex;
  2413. } catch (Throwable t) {
  2414. //FIXME asc remove this catch after more testing has confirmed the above stuff is OK
  2415. throw new BCException("Unexpectedly went bang when searching for annotations on "+rm,t);
  2416. }
  2417. }
  2418. private void matchInvokeInstruction(LazyMethodGen mg,
  2419. InstructionHandle ih,
  2420. InvokeInstruction invoke,
  2421. BcelShadow enclosingShadow,
  2422. List shadowAccumulator)
  2423. {
  2424. String methodName = invoke.getName(cpg);
  2425. if (methodName.startsWith(NameMangler.PREFIX)) {
  2426. Member jpSig =
  2427. world.makeJoinPointSignatureForMethodInvocation(clazz, invoke);
  2428. ResolvedMember declaredSig = jpSig.resolve(world);
  2429. //System.err.println(method + ", declaredSig: " +declaredSig);
  2430. if (declaredSig == null) return;
  2431. if (declaredSig.getKind() == Member.FIELD) {
  2432. Shadow.Kind kind;
  2433. if (jpSig.getReturnType().equals(ResolvedType.VOID)) {
  2434. kind = Shadow.FieldSet;
  2435. } else {
  2436. kind = Shadow.FieldGet;
  2437. }
  2438. if (canMatch(Shadow.FieldGet) || canMatch(Shadow.FieldSet))
  2439. match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow,
  2440. kind, declaredSig),
  2441. shadowAccumulator);
  2442. } else {
  2443. AjAttribute.EffectiveSignatureAttribute effectiveSig =
  2444. declaredSig.getEffectiveSignature();
  2445. if (effectiveSig == null) return;
  2446. //System.err.println("call to inter-type member: " + effectiveSig);
  2447. if (effectiveSig.isWeaveBody()) return;
  2448. ResolvedMember rm = effectiveSig.getEffectiveSignature();
  2449. fixAnnotationsForResolvedMember(rm,declaredSig); // abracadabra
  2450. if (canMatch(effectiveSig.getShadowKind()))
  2451. match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow,
  2452. effectiveSig.getShadowKind(), rm), shadowAccumulator);
  2453. }
  2454. } else {
  2455. if (canMatch(Shadow.MethodCall))
  2456. match(
  2457. BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow),
  2458. shadowAccumulator);
  2459. }
  2460. }
  2461. // static ... so all worlds will share the config for the first one created...
  2462. private static boolean checkedXsetForLowLevelContextCapturing = false;
  2463. private static boolean captureLowLevelContext = false;
  2464. private boolean match(BcelShadow shadow, List shadowAccumulator) {
  2465. //System.err.println("match: " + shadow);
  2466. if (captureLowLevelContext) { // duplicate blocks - one with context capture, one without, seems faster than multiple 'ifs()'
  2467. ContextToken shadowMatchToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MATCHING_SHADOW, shadow);
  2468. boolean isMatched = false;
  2469. for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
  2470. ShadowMunger munger = (ShadowMunger)i.next();
  2471. ContextToken mungerMatchToken = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.MATCHING_POINTCUT, munger.getPointcut());
  2472. if (munger.match(shadow, world)) {
  2473. shadow.addMunger(munger);
  2474. isMatched = true;
  2475. if (shadow.getKind() == Shadow.StaticInitialization) {
  2476. clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation());
  2477. }
  2478. }
  2479. CompilationAndWeavingContext.leavingPhase(mungerMatchToken);
  2480. }
  2481. if (isMatched) shadowAccumulator.add(shadow);
  2482. CompilationAndWeavingContext.leavingPhase(shadowMatchToken);
  2483. return isMatched;
  2484. } else {
  2485. boolean isMatched = false;
  2486. for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) {
  2487. ShadowMunger munger = (ShadowMunger)i.next();
  2488. if (munger.match(shadow, world)) {
  2489. shadow.addMunger(munger);
  2490. isMatched = true;
  2491. if (shadow.getKind() == Shadow.StaticInitialization) {
  2492. clazz.warnOnAddedStaticInitializer(shadow,munger.getSourceLocation());
  2493. }
  2494. }
  2495. }
  2496. if (isMatched) shadowAccumulator.add(shadow);
  2497. return isMatched;
  2498. }
  2499. }
  2500. // ----
  2501. private void implement(LazyMethodGen mg) {
  2502. List shadows = mg.matchedShadows;
  2503. if (shadows == null) return;
  2504. // We depend on a partial order such that inner shadows are earlier on the list
  2505. // than outer shadows. That's fine. This order is preserved if:
  2506. // A preceeds B iff B.getStart() is LATER THAN A.getStart().
  2507. for (Iterator i = shadows.iterator(); i.hasNext(); ) {
  2508. BcelShadow shadow = (BcelShadow)i.next();
  2509. ContextToken tok = CompilationAndWeavingContext.enteringPhase(CompilationAndWeavingContext.IMPLEMENTING_ON_SHADOW,shadow);
  2510. shadow.implement();
  2511. CompilationAndWeavingContext.leavingPhase(tok);
  2512. }
  2513. int ii = mg.getMaxLocals();
  2514. mg.matchedShadows = null;
  2515. }
  2516. // ----
  2517. public LazyClassGen getLazyClassGen() {
  2518. return clazz;
  2519. }
  2520. public List getShadowMungers() {
  2521. return shadowMungers;
  2522. }
  2523. public BcelWorld getWorld() {
  2524. return world;
  2525. }
  2526. // Called by the BcelWeaver to let us know all BcelClassWeavers need to collect reweavable info
  2527. public static void setReweavableMode(boolean mode) {
  2528. inReweavableMode = mode;
  2529. }
  2530. public static boolean getReweavableMode() {
  2531. return inReweavableMode;
  2532. }
  2533. public String toString() {
  2534. return "BcelClassWeaver instance for : "+clazz;
  2535. }
  2536. }