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.

BcelShadow.java 121KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * Alexandre Vasseur support for @AJ aspects
  12. * ******************************************************************/
  13. package org.aspectj.weaver.bcel;
  14. import java.lang.reflect.Modifier;
  15. import java.util.ArrayList;
  16. import java.util.HashMap;
  17. import java.util.Iterator;
  18. import java.util.List;
  19. import java.util.Map;
  20. import org.aspectj.apache.bcel.Constants;
  21. import org.aspectj.apache.bcel.classfile.Field;
  22. import org.aspectj.apache.bcel.generic.ACONST_NULL;
  23. import org.aspectj.apache.bcel.generic.ALOAD;
  24. import org.aspectj.apache.bcel.generic.ANEWARRAY;
  25. import org.aspectj.apache.bcel.generic.ArrayType;
  26. import org.aspectj.apache.bcel.generic.BranchInstruction;
  27. import org.aspectj.apache.bcel.generic.ConstantPoolGen;
  28. import org.aspectj.apache.bcel.generic.DUP;
  29. import org.aspectj.apache.bcel.generic.DUP_X1;
  30. import org.aspectj.apache.bcel.generic.FieldInstruction;
  31. import org.aspectj.apache.bcel.generic.INVOKEINTERFACE;
  32. import org.aspectj.apache.bcel.generic.INVOKESPECIAL;
  33. import org.aspectj.apache.bcel.generic.INVOKESTATIC;
  34. import org.aspectj.apache.bcel.generic.Instruction;
  35. import org.aspectj.apache.bcel.generic.InstructionConstants;
  36. import org.aspectj.apache.bcel.generic.InstructionFactory;
  37. import org.aspectj.apache.bcel.generic.InstructionHandle;
  38. import org.aspectj.apache.bcel.generic.InstructionList;
  39. import org.aspectj.apache.bcel.generic.InstructionTargeter;
  40. import org.aspectj.apache.bcel.generic.InvokeInstruction;
  41. import org.aspectj.apache.bcel.generic.LoadInstruction;
  42. import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
  43. import org.aspectj.apache.bcel.generic.NEW;
  44. import org.aspectj.apache.bcel.generic.ObjectType;
  45. import org.aspectj.apache.bcel.generic.PUSH;
  46. import org.aspectj.apache.bcel.generic.ReturnInstruction;
  47. import org.aspectj.apache.bcel.generic.SWAP;
  48. import org.aspectj.apache.bcel.generic.StoreInstruction;
  49. import org.aspectj.apache.bcel.generic.TargetLostException;
  50. import org.aspectj.apache.bcel.generic.Type;
  51. import org.aspectj.bridge.IMessage;
  52. import org.aspectj.bridge.ISourceLocation;
  53. import org.aspectj.bridge.Message;
  54. import org.aspectj.weaver.Advice;
  55. import org.aspectj.weaver.AdviceKind;
  56. import org.aspectj.weaver.AjcMemberMaker;
  57. import org.aspectj.weaver.BCException;
  58. import org.aspectj.weaver.IntMap;
  59. import org.aspectj.weaver.Member;
  60. import org.aspectj.weaver.MemberImpl;
  61. import org.aspectj.weaver.NameMangler;
  62. import org.aspectj.weaver.NewConstructorTypeMunger;
  63. import org.aspectj.weaver.NewFieldTypeMunger;
  64. import org.aspectj.weaver.NewMethodTypeMunger;
  65. import org.aspectj.weaver.ResolvedMember;
  66. import org.aspectj.weaver.ResolvedMemberImpl;
  67. import org.aspectj.weaver.ResolvedType;
  68. import org.aspectj.weaver.Shadow;
  69. import org.aspectj.weaver.ShadowMunger;
  70. import org.aspectj.weaver.UnresolvedType;
  71. import org.aspectj.weaver.WeaverMessages;
  72. import org.aspectj.weaver.World;
  73. import org.aspectj.weaver.ast.Var;
  74. /*
  75. * Some fun implementation stuff:
  76. *
  77. * * expressionKind advice is non-execution advice
  78. * * may have a target.
  79. * * if the body is extracted, it will be extracted into
  80. * a static method. The first argument to the static
  81. * method is the target
  82. * * advice may expose a this object, but that's the advice's
  83. * consideration, not ours. This object will NOT be cached in another
  84. * local, but will always come from frame zero.
  85. *
  86. * * non-expressionKind advice is execution advice
  87. * * may have a this.
  88. * * target is same as this, and is exposed that way to advice
  89. * (i.e., target will not be cached, will always come from frame zero)
  90. * * if the body is extracted, it will be extracted into a method
  91. * with same static/dynamic modifier as enclosing method. If non-static,
  92. * target of callback call will be this.
  93. *
  94. * * because of these two facts, the setup of the actual arguments (including
  95. * possible target) callback method is the same for both kinds of advice:
  96. * push the targetVar, if it exists (it will not exist for advice on static
  97. * things), then push all the argVars.
  98. *
  99. * Protected things:
  100. *
  101. * * the above is sufficient for non-expressionKind advice for protected things,
  102. * since the target will always be this.
  103. *
  104. * * For expressionKind things, we have to modify the signature of the callback
  105. * method slightly. For non-static expressionKind things, we modify
  106. * the first argument of the callback method NOT to be the type specified
  107. * by the method/field signature (the owner), but rather we type it to
  108. * the currentlyEnclosing type. We are guaranteed this will be fine,
  109. * since the verifier verifies that the target is a subtype of the currently
  110. * enclosingType.
  111. *
  112. * Worries:
  113. *
  114. * * ConstructorCalls will be weirder than all of these, since they
  115. * supposedly don't have a target (according to AspectJ), but they clearly
  116. * do have a target of sorts, just one that needs to be pushed on the stack,
  117. * dupped, and not touched otherwise until the constructor runs.
  118. *
  119. * @author Jim Hugunin
  120. * @author Erik Hilsdale
  121. *
  122. */
  123. public class BcelShadow extends Shadow {
  124. private ShadowRange range;
  125. private final BcelWorld world;
  126. private final LazyMethodGen enclosingMethod;
  127. private boolean fallsThrough; //XXX not used anymore
  128. // SECRETAPI - for testing, this will tell us if the optimization succeeded *on the last shadow processed*
  129. public static boolean appliedLazyTjpOptimization;
  130. // Some instructions have a target type that will vary
  131. // from the signature (pr109728) (1.4 declaring type issue)
  132. private String actualInstructionTargetType;
  133. // ---- initialization
  134. /**
  135. * This generates an unassociated shadow, rooted in a particular method but not rooted
  136. * to any particular point in the code. It should be given to a rooted ShadowRange
  137. * in the {@link ShadowRange#associateWithShadow(BcelShadow)} method.
  138. */
  139. public BcelShadow(
  140. BcelWorld world,
  141. Kind kind,
  142. Member signature,
  143. LazyMethodGen enclosingMethod,
  144. BcelShadow enclosingShadow)
  145. {
  146. super(kind, signature, enclosingShadow);
  147. this.world = world;
  148. this.enclosingMethod = enclosingMethod;
  149. fallsThrough = kind.argsOnStack();
  150. }
  151. // ---- copies all state, including Shadow's mungers...
  152. public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) {
  153. BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing);
  154. List src = mungers;
  155. List dest = s.mungers;
  156. for (Iterator i = src.iterator(); i.hasNext(); ) {
  157. dest.add(i.next());
  158. }
  159. return s;
  160. }
  161. // ---- overridden behaviour
  162. public World getIWorld() {
  163. return world;
  164. }
  165. private void deleteNewAndDup() {
  166. final ConstantPoolGen cpg = getEnclosingClass().getConstantPoolGen();
  167. int depth = 1;
  168. InstructionHandle ih = range.getStart();
  169. while (true) {
  170. Instruction inst = ih.getInstruction();
  171. if (inst instanceof INVOKESPECIAL
  172. && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) {
  173. depth++;
  174. } else if (inst instanceof NEW) {
  175. depth--;
  176. if (depth == 0) break;
  177. }
  178. ih = ih.getPrev();
  179. }
  180. // now IH points to the NEW. We're followed by the DUP, and that is followed
  181. // by the actual instruciton we care about.
  182. InstructionHandle newHandle = ih;
  183. InstructionHandle endHandle = newHandle.getNext();
  184. InstructionHandle nextHandle;
  185. if (endHandle.getInstruction() instanceof DUP) {
  186. nextHandle = endHandle.getNext();
  187. retargetFrom(newHandle, nextHandle);
  188. retargetFrom(endHandle, nextHandle);
  189. } else if (endHandle.getInstruction() instanceof DUP_X1) {
  190. InstructionHandle dupHandle = endHandle;
  191. endHandle = endHandle.getNext();
  192. nextHandle = endHandle.getNext();
  193. if (endHandle.getInstruction() instanceof SWAP) {}
  194. else {
  195. // XXX see next XXX comment
  196. throw new RuntimeException("Unhandled kind of new " + endHandle);
  197. }
  198. retargetFrom(newHandle, nextHandle);
  199. retargetFrom(dupHandle, nextHandle);
  200. retargetFrom(endHandle, nextHandle);
  201. } else {
  202. endHandle = newHandle;
  203. nextHandle = endHandle.getNext();
  204. retargetFrom(newHandle, nextHandle);
  205. // add a POP here... we found a NEW w/o a dup or anything else, so
  206. // we must be in statement context.
  207. getRange().insert(InstructionConstants.POP, Range.OutsideAfter);
  208. }
  209. // assert (dupHandle.getInstruction() instanceof DUP);
  210. try {
  211. range.getBody().delete(newHandle, endHandle);
  212. } catch (TargetLostException e) {
  213. throw new BCException("shouldn't happen");
  214. }
  215. }
  216. private void retargetFrom(InstructionHandle old, InstructionHandle fresh) {
  217. InstructionTargeter[] sources = old.getTargeters();
  218. if (sources != null) {
  219. for (int i = sources.length - 1; i >= 0; i--) {
  220. sources[i].updateTarget(old, fresh);
  221. }
  222. }
  223. }
  224. // records advice that is stopping us doing the lazyTjp optimization
  225. private List badAdvice = null;
  226. public void addAdvicePreventingLazyTjp(BcelAdvice advice) {
  227. if (badAdvice == null) badAdvice = new ArrayList();
  228. badAdvice.add(advice);
  229. }
  230. protected void prepareForMungers() {
  231. // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap,
  232. // and store all our
  233. // arguments on the frame.
  234. // ??? This is a bit of a hack (for the Java langauge). We do this because
  235. // we sometime add code "outsideBefore" when dealing with weaving join points. We only
  236. // do this for exposing state that is on the stack. It turns out to just work for
  237. // everything except for constructor calls and exception handlers. If we were to clean
  238. // this up, every ShadowRange would have three instructionHandle points, the start of
  239. // the arg-setup code, the start of the running code, and the end of the running code.
  240. if (getKind() == ConstructorCall) {
  241. deleteNewAndDup();
  242. initializeArgVars();
  243. } else if (getKind() == PreInitialization) { // pr74952
  244. ShadowRange range = getRange();
  245. range.insert(InstructionConstants.NOP,Range.InsideAfter);
  246. } else if (getKind() == ExceptionHandler) {
  247. ShadowRange range = getRange();
  248. InstructionList body = range.getBody();
  249. InstructionHandle start = range.getStart();
  250. // Create a store instruction to put the value from the top of the
  251. // stack into a local variable slot. This is a trimmed version of
  252. // what is in initializeArgVars() (since there is only one argument
  253. // at a handler jp and only before advice is supported) (pr46298)
  254. argVars = new BcelVar[1];
  255. int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0);
  256. UnresolvedType tx = getArgType(0);
  257. argVars[0] = genTempVar(tx, "ajc$arg0");
  258. InstructionHandle insertedInstruction =
  259. range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore);
  260. // Now the exception range starts just after our new instruction.
  261. // The next bit of code changes the exception range to point at
  262. // the store instruction
  263. InstructionTargeter[] targeters = start.getTargeters();
  264. for (int i = 0; i < targeters.length; i++) {
  265. InstructionTargeter t = targeters[i];
  266. if (t instanceof ExceptionRange) {
  267. ExceptionRange er = (ExceptionRange) t;
  268. er.updateTarget(start, insertedInstruction, body);
  269. }
  270. }
  271. }
  272. // now we ask each munger to request our state
  273. isThisJoinPointLazy = true;//world.isXlazyTjp(); // lazy is default now
  274. badAdvice = null;
  275. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  276. ShadowMunger munger = (ShadowMunger) iter.next();
  277. munger.specializeOn(this);
  278. }
  279. initializeThisJoinPoint();
  280. if (thisJoinPointVar!=null && !isThisJoinPointLazy && badAdvice!=null && badAdvice.size()>1) {
  281. // something stopped us making it a lazy tjp
  282. // can't build tjp lazily, no suitable test...
  283. int valid = 0;
  284. for (Iterator iter = badAdvice.iterator(); iter.hasNext();) {
  285. BcelAdvice element = (BcelAdvice) iter.next();
  286. ISourceLocation sLoc = element.getSourceLocation();
  287. if (sLoc!=null && sLoc.getLine()>0) valid++;
  288. }
  289. if (valid!=0) {
  290. ISourceLocation[] badLocs = new ISourceLocation[valid];
  291. int i = 0;
  292. for (Iterator iter = badAdvice.iterator(); iter.hasNext();) {
  293. BcelAdvice element = (BcelAdvice) iter.next();
  294. ISourceLocation sLoc = element.getSourceLocation();
  295. if (sLoc!=null) badLocs[i++]=sLoc;
  296. }
  297. world.getLint().multipleAdviceStoppingLazyTjp.signal(
  298. new String[] {this.toString()},
  299. getSourceLocation(),badLocs
  300. );
  301. }
  302. }
  303. badAdvice=null;
  304. // If we are an expression kind, we require our target/arguments on the stack
  305. // before we do our actual thing. However, they may have been removed
  306. // from the stack as the shadowMungers have requested state.
  307. // if any of our shadowMungers requested either the arguments or target,
  308. // the munger will have added code
  309. // to pop the target/arguments into temporary variables, represented by
  310. // targetVar and argVars. In such a case, we must make sure to re-push the
  311. // values.
  312. // If we are nonExpressionKind, we don't expect arguments on the stack
  313. // so this is moot. If our argVars happen to be null, then we know that
  314. // no ShadowMunger has squirrelled away our arguments, so they're still
  315. // on the stack.
  316. InstructionFactory fact = getFactory();
  317. if (getKind().argsOnStack() && argVars != null) {
  318. // Special case first (pr46298). If we are an exception handler and the instruction
  319. // just after the shadow is a POP then we should remove the pop. The code
  320. // above which generated the store instruction has already cleared the stack.
  321. // We also don't generate any code for the arguments in this case as it would be
  322. // an incorrect aload.
  323. if (getKind() == ExceptionHandler
  324. && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) {
  325. // easier than deleting it ...
  326. range.getEnd().getNext().setInstruction(InstructionConstants.NOP);
  327. } else {
  328. range.insert(
  329. BcelRenderer.renderExprs(fact, world, argVars),
  330. Range.InsideBefore);
  331. if (targetVar != null) {
  332. range.insert(
  333. BcelRenderer.renderExpr(fact, world, targetVar),
  334. Range.InsideBefore);
  335. }
  336. if (getKind() == ConstructorCall) {
  337. range.insert((Instruction) InstructionFactory.createDup(1), Range.InsideBefore);
  338. range.insert(
  339. fact.createNew(
  340. (ObjectType) BcelWorld.makeBcelType(
  341. getSignature().getDeclaringType())),
  342. Range.InsideBefore);
  343. }
  344. }
  345. }
  346. }
  347. // ---- getters
  348. public ShadowRange getRange() {
  349. return range;
  350. }
  351. public void setRange(ShadowRange range) {
  352. this.range = range;
  353. }
  354. public int getSourceLine() {
  355. // if the kind of join point for which we are a shadow represents
  356. // a method or constructor execution, then the best source line is
  357. // the one from the enclosingMethod declarationLineNumber if available.
  358. Kind kind = getKind();
  359. if ( (kind == MethodExecution) ||
  360. (kind == ConstructorExecution) ||
  361. (kind == AdviceExecution) ||
  362. (kind == StaticInitialization) ||
  363. (kind == PreInitialization) ||
  364. (kind == Initialization)) {
  365. if (getEnclosingMethod().hasDeclaredLineNumberInfo()) {
  366. return getEnclosingMethod().getDeclarationLineNumber();
  367. }
  368. }
  369. if (range == null) {
  370. if (getEnclosingMethod().hasBody()) {
  371. return Utility.getSourceLine(getEnclosingMethod().getBody().getStart());
  372. } else {
  373. return 0;
  374. }
  375. }
  376. int ret = Utility.getSourceLine(range.getStart());
  377. if (ret < 0) return 0;
  378. return ret;
  379. }
  380. // overrides
  381. public UnresolvedType getEnclosingType() {
  382. return getEnclosingClass().getType();
  383. }
  384. public LazyClassGen getEnclosingClass() {
  385. return enclosingMethod.getEnclosingClass();
  386. }
  387. public BcelWorld getWorld() {
  388. return world;
  389. }
  390. // ---- factory methods
  391. public static BcelShadow makeConstructorExecution(
  392. BcelWorld world,
  393. LazyMethodGen enclosingMethod,
  394. InstructionHandle justBeforeStart)
  395. {
  396. final InstructionList body = enclosingMethod.getBody();
  397. BcelShadow s =
  398. new BcelShadow(
  399. world,
  400. ConstructorExecution,
  401. world.makeJoinPointSignature(enclosingMethod),
  402. enclosingMethod,
  403. null);
  404. ShadowRange r = new ShadowRange(body);
  405. r.associateWithShadow(s);
  406. r.associateWithTargets(
  407. Range.genStart(body, justBeforeStart.getNext()),
  408. Range.genEnd(body));
  409. return s;
  410. }
  411. public static BcelShadow makeStaticInitialization(
  412. BcelWorld world,
  413. LazyMethodGen enclosingMethod)
  414. {
  415. InstructionList body = enclosingMethod.getBody();
  416. // move the start past ajc$preClinit
  417. InstructionHandle clinitStart = body.getStart();
  418. if (clinitStart.getInstruction() instanceof InvokeInstruction) {
  419. InvokeInstruction ii = (InvokeInstruction)clinitStart.getInstruction();
  420. if (ii
  421. .getName(enclosingMethod.getEnclosingClass().getConstantPoolGen())
  422. .equals(NameMangler.AJC_PRE_CLINIT_NAME)) {
  423. clinitStart = clinitStart.getNext();
  424. }
  425. }
  426. InstructionHandle clinitEnd = body.getEnd();
  427. //XXX should move the end before the postClinit, but the return is then tricky...
  428. // if (clinitEnd.getInstruction() instanceof InvokeInstruction) {
  429. // InvokeInstruction ii = (InvokeInstruction)clinitEnd.getInstruction();
  430. // if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPoolGen()).equals(NameMangler.AJC_POST_CLINIT_NAME)) {
  431. // clinitEnd = clinitEnd.getPrev();
  432. // }
  433. // }
  434. BcelShadow s =
  435. new BcelShadow(
  436. world,
  437. StaticInitialization,
  438. world.makeJoinPointSignature(enclosingMethod),
  439. enclosingMethod,
  440. null);
  441. ShadowRange r = new ShadowRange(body);
  442. r.associateWithShadow(s);
  443. r.associateWithTargets(
  444. Range.genStart(body, clinitStart),
  445. Range.genEnd(body, clinitEnd));
  446. return s;
  447. }
  448. /** Make the shadow for an exception handler. Currently makes an empty shadow that
  449. * only allows before advice to be woven into it.
  450. */
  451. public static BcelShadow makeExceptionHandler(
  452. BcelWorld world,
  453. ExceptionRange exceptionRange,
  454. LazyMethodGen enclosingMethod,
  455. InstructionHandle startOfHandler,
  456. BcelShadow enclosingShadow)
  457. {
  458. InstructionList body = enclosingMethod.getBody();
  459. UnresolvedType catchType = exceptionRange.getCatchType();
  460. UnresolvedType inType = enclosingMethod.getEnclosingClass().getType();
  461. ResolvedMemberImpl sig = MemberImpl.makeExceptionHandlerSignature(inType, catchType);
  462. sig.parameterNames = new String[] {findHandlerParamName(startOfHandler)};
  463. BcelShadow s =
  464. new BcelShadow(
  465. world,
  466. ExceptionHandler,
  467. sig,
  468. enclosingMethod,
  469. enclosingShadow);
  470. ShadowRange r = new ShadowRange(body);
  471. r.associateWithShadow(s);
  472. InstructionHandle start = Range.genStart(body, startOfHandler);
  473. InstructionHandle end = Range.genEnd(body, start);
  474. r.associateWithTargets(start, end);
  475. exceptionRange.updateTarget(startOfHandler, start, body);
  476. return s;
  477. }
  478. private static String findHandlerParamName(InstructionHandle startOfHandler) {
  479. if (startOfHandler.getInstruction() instanceof StoreInstruction &&
  480. startOfHandler.getNext() != null)
  481. {
  482. int slot = ((StoreInstruction)startOfHandler.getInstruction()).getIndex();
  483. //System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index);
  484. InstructionTargeter[] targeters = startOfHandler.getNext().getTargeters();
  485. if (targeters!=null) {
  486. for (int i=targeters.length-1; i >= 0; i--) {
  487. if (targeters[i] instanceof LocalVariableTag) {
  488. LocalVariableTag t = (LocalVariableTag)targeters[i];
  489. if (t.getSlot() == slot) {
  490. return t.getName();
  491. }
  492. //System.out.println("tag: " + targeters[i]);
  493. }
  494. }
  495. }
  496. }
  497. return "<missing>";
  498. }
  499. /** create an init join point associated w/ an interface in the body of a constructor */
  500. public static BcelShadow makeIfaceInitialization(
  501. BcelWorld world,
  502. LazyMethodGen constructor,
  503. Member interfaceConstructorSignature)
  504. {
  505. InstructionList body = constructor.getBody();
  506. // UnresolvedType inType = constructor.getEnclosingClass().getType();
  507. BcelShadow s =
  508. new BcelShadow(
  509. world,
  510. Initialization,
  511. interfaceConstructorSignature,
  512. constructor,
  513. null);
  514. s.fallsThrough = true;
  515. // ShadowRange r = new ShadowRange(body);
  516. // r.associateWithShadow(s);
  517. // InstructionHandle start = Range.genStart(body, handle);
  518. // InstructionHandle end = Range.genEnd(body, handle);
  519. //
  520. // r.associateWithTargets(start, end);
  521. return s;
  522. }
  523. public void initIfaceInitializer(InstructionHandle end) {
  524. final InstructionList body = enclosingMethod.getBody();
  525. ShadowRange r = new ShadowRange(body);
  526. r.associateWithShadow(this);
  527. InstructionHandle nop = body.insert(end, InstructionConstants.NOP);
  528. r.associateWithTargets(
  529. Range.genStart(body, nop),
  530. Range.genEnd(body, nop));
  531. }
  532. // public static BcelShadow makeIfaceConstructorExecution(
  533. // BcelWorld world,
  534. // LazyMethodGen constructor,
  535. // InstructionHandle next,
  536. // Member interfaceConstructorSignature)
  537. // {
  538. // // final InstructionFactory fact = constructor.getEnclosingClass().getFactory();
  539. // InstructionList body = constructor.getBody();
  540. // // UnresolvedType inType = constructor.getEnclosingClass().getType();
  541. // BcelShadow s =
  542. // new BcelShadow(
  543. // world,
  544. // ConstructorExecution,
  545. // interfaceConstructorSignature,
  546. // constructor,
  547. // null);
  548. // s.fallsThrough = true;
  549. // ShadowRange r = new ShadowRange(body);
  550. // r.associateWithShadow(s);
  551. // // ??? this may or may not work
  552. // InstructionHandle start = Range.genStart(body, next);
  553. // //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP));
  554. // InstructionHandle end = Range.genStart(body, next);
  555. // //body.append(start, fact.NOP);
  556. //
  557. // r.associateWithTargets(start, end);
  558. // return s;
  559. // }
  560. /** Create an initialization join point associated with a constructor, but not
  561. * with any body of code yet. If this is actually matched, it's range will be set
  562. * when we inline self constructors.
  563. *
  564. * @param constructor The constructor starting this initialization.
  565. */
  566. public static BcelShadow makeUnfinishedInitialization(
  567. BcelWorld world,
  568. LazyMethodGen constructor)
  569. {
  570. BcelShadow ret = new BcelShadow(
  571. world,
  572. Initialization,
  573. world.makeJoinPointSignature(constructor),
  574. constructor,
  575. null);
  576. if (constructor.getEffectiveSignature() != null) {
  577. ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature());
  578. }
  579. return ret;
  580. }
  581. public static BcelShadow makeUnfinishedPreinitialization(
  582. BcelWorld world,
  583. LazyMethodGen constructor)
  584. {
  585. BcelShadow ret = new BcelShadow(
  586. world,
  587. PreInitialization,
  588. world.makeJoinPointSignature(constructor),
  589. constructor,
  590. null);
  591. ret.fallsThrough = true;
  592. if (constructor.getEffectiveSignature() != null) {
  593. ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature());
  594. }
  595. return ret;
  596. }
  597. public static BcelShadow makeMethodExecution(
  598. BcelWorld world,
  599. LazyMethodGen enclosingMethod,
  600. boolean lazyInit)
  601. {
  602. if (!lazyInit) return makeMethodExecution(world, enclosingMethod);
  603. BcelShadow s =
  604. new BcelShadow(
  605. world,
  606. MethodExecution,
  607. enclosingMethod.getMemberView(),
  608. enclosingMethod,
  609. null);
  610. return s;
  611. }
  612. public void init() {
  613. if (range != null) return;
  614. final InstructionList body = enclosingMethod.getBody();
  615. ShadowRange r = new ShadowRange(body);
  616. r.associateWithShadow(this);
  617. r.associateWithTargets(
  618. Range.genStart(body),
  619. Range.genEnd(body));
  620. }
  621. public static BcelShadow makeMethodExecution(
  622. BcelWorld world,
  623. LazyMethodGen enclosingMethod)
  624. {
  625. return makeShadowForMethod(world, enclosingMethod, MethodExecution,
  626. enclosingMethod.getMemberView()); //world.makeMethodSignature(enclosingMethod));
  627. }
  628. public static BcelShadow makeShadowForMethod(BcelWorld world,
  629. LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig)
  630. {
  631. final InstructionList body = enclosingMethod.getBody();
  632. BcelShadow s =
  633. new BcelShadow(
  634. world,
  635. kind,
  636. sig,
  637. enclosingMethod,
  638. null);
  639. ShadowRange r = new ShadowRange(body);
  640. r.associateWithShadow(s);
  641. r.associateWithTargets(
  642. Range.genStart(body),
  643. Range.genEnd(body));
  644. return s;
  645. }
  646. public static BcelShadow makeAdviceExecution(
  647. BcelWorld world,
  648. LazyMethodGen enclosingMethod)
  649. {
  650. final InstructionList body = enclosingMethod.getBody();
  651. BcelShadow s =
  652. new BcelShadow(
  653. world,
  654. AdviceExecution,
  655. world.makeJoinPointSignatureFromMethod(enclosingMethod, Member.ADVICE),
  656. enclosingMethod,
  657. null);
  658. ShadowRange r = new ShadowRange(body);
  659. r.associateWithShadow(s);
  660. r.associateWithTargets(Range.genStart(body), Range.genEnd(body));
  661. return s;
  662. }
  663. // constructor call shadows are <em>initially</em> just around the
  664. // call to the constructor. If ANY advice gets put on it, we move
  665. // the NEW instruction inside the join point, which involves putting
  666. // all the arguments in temps.
  667. public static BcelShadow makeConstructorCall(
  668. BcelWorld world,
  669. LazyMethodGen enclosingMethod,
  670. InstructionHandle callHandle,
  671. BcelShadow enclosingShadow)
  672. {
  673. final InstructionList body = enclosingMethod.getBody();
  674. Member sig = world.makeJoinPointSignatureForMethodInvocation(
  675. enclosingMethod.getEnclosingClass(),
  676. (InvokeInstruction) callHandle.getInstruction());
  677. BcelShadow s =
  678. new BcelShadow(
  679. world,
  680. ConstructorCall,
  681. sig,
  682. enclosingMethod,
  683. enclosingShadow);
  684. ShadowRange r = new ShadowRange(body);
  685. r.associateWithShadow(s);
  686. r.associateWithTargets(
  687. Range.genStart(body, callHandle),
  688. Range.genEnd(body, callHandle));
  689. retargetAllBranches(callHandle, r.getStart());
  690. return s;
  691. }
  692. public static BcelShadow makeMethodCall(
  693. BcelWorld world,
  694. LazyMethodGen enclosingMethod,
  695. InstructionHandle callHandle,
  696. BcelShadow enclosingShadow)
  697. {
  698. final InstructionList body = enclosingMethod.getBody();
  699. BcelShadow s =
  700. new BcelShadow(
  701. world,
  702. MethodCall,
  703. world.makeJoinPointSignatureForMethodInvocation(
  704. enclosingMethod.getEnclosingClass(),
  705. (InvokeInstruction) callHandle.getInstruction()),
  706. enclosingMethod,
  707. enclosingShadow);
  708. ShadowRange r = new ShadowRange(body);
  709. r.associateWithShadow(s);
  710. r.associateWithTargets(
  711. Range.genStart(body, callHandle),
  712. Range.genEnd(body, callHandle));
  713. retargetAllBranches(callHandle, r.getStart());
  714. return s;
  715. }
  716. public static BcelShadow makeShadowForMethodCall(
  717. BcelWorld world,
  718. LazyMethodGen enclosingMethod,
  719. InstructionHandle callHandle,
  720. BcelShadow enclosingShadow,
  721. Kind kind,
  722. ResolvedMember sig)
  723. {
  724. final InstructionList body = enclosingMethod.getBody();
  725. BcelShadow s =
  726. new BcelShadow(
  727. world,
  728. kind,
  729. sig,
  730. enclosingMethod,
  731. enclosingShadow);
  732. ShadowRange r = new ShadowRange(body);
  733. r.associateWithShadow(s);
  734. r.associateWithTargets(
  735. Range.genStart(body, callHandle),
  736. Range.genEnd(body, callHandle));
  737. retargetAllBranches(callHandle, r.getStart());
  738. return s;
  739. }
  740. public static BcelShadow makeFieldGet(
  741. BcelWorld world,
  742. ResolvedMember field,
  743. LazyMethodGen enclosingMethod,
  744. InstructionHandle getHandle,
  745. BcelShadow enclosingShadow)
  746. {
  747. final InstructionList body = enclosingMethod.getBody();
  748. BcelShadow s =
  749. new BcelShadow(
  750. world,
  751. FieldGet,
  752. field,
  753. // BcelWorld.makeFieldSignature(
  754. // enclosingMethod.getEnclosingClass(),
  755. // (FieldInstruction) getHandle.getInstruction()),
  756. enclosingMethod,
  757. enclosingShadow);
  758. ShadowRange r = new ShadowRange(body);
  759. r.associateWithShadow(s);
  760. r.associateWithTargets(
  761. Range.genStart(body, getHandle),
  762. Range.genEnd(body, getHandle));
  763. retargetAllBranches(getHandle, r.getStart());
  764. return s;
  765. }
  766. public static BcelShadow makeFieldSet(
  767. BcelWorld world,
  768. LazyMethodGen enclosingMethod,
  769. InstructionHandle setHandle,
  770. BcelShadow enclosingShadow)
  771. {
  772. final InstructionList body = enclosingMethod.getBody();
  773. BcelShadow s =
  774. new BcelShadow(
  775. world,
  776. FieldSet,
  777. BcelWorld.makeFieldJoinPointSignature(
  778. enclosingMethod.getEnclosingClass(),
  779. (FieldInstruction) setHandle.getInstruction()),
  780. enclosingMethod,
  781. enclosingShadow);
  782. ShadowRange r = new ShadowRange(body);
  783. r.associateWithShadow(s);
  784. r.associateWithTargets(
  785. Range.genStart(body, setHandle),
  786. Range.genEnd(body, setHandle));
  787. retargetAllBranches(setHandle, r.getStart());
  788. return s;
  789. }
  790. public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) {
  791. InstructionTargeter[] sources = from.getTargeters();
  792. if (sources != null) {
  793. for (int i = sources.length - 1; i >= 0; i--) {
  794. InstructionTargeter source = sources[i];
  795. if (source instanceof BranchInstruction) {
  796. source.updateTarget(from, to);
  797. }
  798. }
  799. }
  800. }
  801. // // ---- type access methods
  802. // private ObjectType getTargetBcelType() {
  803. // return (ObjectType) BcelWorld.makeBcelType(getTargetType());
  804. // }
  805. // private Type getArgBcelType(int arg) {
  806. // return BcelWorld.makeBcelType(getArgType(arg));
  807. // }
  808. // ---- kinding
  809. /**
  810. * If the end of my range has no real instructions following then
  811. * my context needs a return at the end.
  812. */
  813. public boolean terminatesWithReturn() {
  814. return getRange().getRealNext() == null;
  815. }
  816. /**
  817. * Is arg0 occupied with the value of this
  818. */
  819. public boolean arg0HoldsThis() {
  820. if (getKind().isEnclosingKind()) {
  821. return !getSignature().isStatic();
  822. } else if (enclosingShadow == null) {
  823. //XXX this is mostly right
  824. // this doesn't do the right thing for calls in the pre part of introduced constructors.
  825. return !enclosingMethod.isStatic();
  826. } else {
  827. return ((BcelShadow)enclosingShadow).arg0HoldsThis();
  828. }
  829. }
  830. // ---- argument getting methods
  831. private BcelVar thisVar = null;
  832. private BcelVar targetVar = null;
  833. private BcelVar[] argVars = null;
  834. private Map/*<UnresolvedType,BcelVar>*/ kindedAnnotationVars = null;
  835. private Map/*<UnresolvedType,BcelVar>*/ thisAnnotationVars = null;
  836. private Map/*<UnresolvedType,BcelVar>*/ targetAnnotationVars = null;
  837. private Map/*<UnresolvedType,BcelVar>*/[] argAnnotationVars = null;
  838. private Map/*<UnresolvedType,BcelVar>*/ withinAnnotationVars = null;
  839. private Map/*<UnresolvedType,BcelVar>*/ withincodeAnnotationVars = null;
  840. public Var getThisVar() {
  841. if (!hasThis()) {
  842. throw new IllegalStateException("no this");
  843. }
  844. initializeThisVar();
  845. return thisVar;
  846. }
  847. public Var getThisAnnotationVar(UnresolvedType forAnnotationType) {
  848. if (!hasThis()) {
  849. throw new IllegalStateException("no this");
  850. }
  851. initializeThisAnnotationVars(); // FIXME asc Why bother with this if we always return one?
  852. // Even if we can't find one, we have to return one as we might have this annotation at runtime
  853. Var v = (Var) thisAnnotationVars.get(forAnnotationType);
  854. if (v==null)
  855. v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getThisVar());
  856. return v;
  857. }
  858. public Var getTargetVar() {
  859. if (!hasTarget()) {
  860. throw new IllegalStateException("no target");
  861. }
  862. initializeTargetVar();
  863. return targetVar;
  864. }
  865. public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) {
  866. if (!hasTarget()) {
  867. throw new IllegalStateException("no target");
  868. }
  869. initializeTargetAnnotationVars(); // FIXME asc why bother with this if we always return one?
  870. Var v =(Var) targetAnnotationVars.get(forAnnotationType);
  871. // Even if we can't find one, we have to return one as we might have this annotation at runtime
  872. if (v==null)
  873. v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getTargetVar());
  874. return v;
  875. }
  876. public Var getArgVar(int i) {
  877. initializeArgVars();
  878. return argVars[i];
  879. }
  880. public Var getArgAnnotationVar(int i,UnresolvedType forAnnotationType) {
  881. initializeArgAnnotationVars();
  882. Var v= (Var) argAnnotationVars[i].get(forAnnotationType);
  883. if (v==null)
  884. v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getArgVar(i));
  885. return v;
  886. }
  887. public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) {
  888. initializeKindedAnnotationVars();
  889. return (Var) kindedAnnotationVars.get(forAnnotationType);
  890. }
  891. public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
  892. initializeWithinAnnotationVars();
  893. return (Var) withinAnnotationVars.get(forAnnotationType);
  894. }
  895. public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) {
  896. initializeWithinCodeAnnotationVars();
  897. return (Var) withincodeAnnotationVars.get(forAnnotationType);
  898. }
  899. // reflective thisJoinPoint support
  900. private BcelVar thisJoinPointVar = null;
  901. private boolean isThisJoinPointLazy;
  902. private int lazyTjpConsumers = 0;
  903. private BcelVar thisJoinPointStaticPartVar = null;
  904. // private BcelVar thisEnclosingJoinPointStaticPartVar = null;
  905. public final Var getThisJoinPointStaticPartVar() {
  906. return getThisJoinPointStaticPartBcelVar();
  907. }
  908. public final Var getThisEnclosingJoinPointStaticPartVar() {
  909. return getThisEnclosingJoinPointStaticPartBcelVar();
  910. }
  911. public void requireThisJoinPoint(boolean hasGuardTest, boolean isAround) {
  912. if (!isAround){
  913. if (!hasGuardTest) {
  914. isThisJoinPointLazy = false;
  915. } else {
  916. lazyTjpConsumers++;
  917. }
  918. }
  919. // if (!hasGuardTest) {
  920. // isThisJoinPointLazy = false;
  921. // } else {
  922. // lazyTjpConsumers++;
  923. // }
  924. if (thisJoinPointVar == null) {
  925. thisJoinPointVar = genTempVar(UnresolvedType.forName("org.aspectj.lang.JoinPoint"));
  926. }
  927. }
  928. public Var getThisJoinPointVar() {
  929. requireThisJoinPoint(false,false);
  930. return thisJoinPointVar;
  931. }
  932. void initializeThisJoinPoint() {
  933. if (thisJoinPointVar == null) return;
  934. if (isThisJoinPointLazy) {
  935. isThisJoinPointLazy = checkLazyTjp();
  936. }
  937. if (isThisJoinPointLazy) {
  938. appliedLazyTjpOptimization = true;
  939. createThisJoinPoint(); // make sure any state needed is initialized, but throw the instructions out
  940. if (lazyTjpConsumers == 1) return; // special case only one lazyTjpUser
  941. InstructionFactory fact = getFactory();
  942. InstructionList il = new InstructionList();
  943. il.append(InstructionConstants.ACONST_NULL);
  944. il.append(thisJoinPointVar.createStore(fact));
  945. range.insert(il, Range.OutsideBefore);
  946. } else {
  947. appliedLazyTjpOptimization = false;
  948. InstructionFactory fact = getFactory();
  949. InstructionList il = createThisJoinPoint();
  950. il.append(thisJoinPointVar.createStore(fact));
  951. range.insert(il, Range.OutsideBefore);
  952. }
  953. }
  954. private boolean checkLazyTjp() {
  955. // check for around advice
  956. for (Iterator i = mungers.iterator(); i.hasNext();) {
  957. ShadowMunger munger = (ShadowMunger) i.next();
  958. if (munger instanceof Advice) {
  959. if ( ((Advice)munger).getKind() == AdviceKind.Around) {
  960. if (munger.getSourceLocation()!=null) { // do we know enough to bother reporting?
  961. world.getLint().canNotImplementLazyTjp.signal(
  962. new String[] {toString()},
  963. getSourceLocation(),
  964. new ISourceLocation[] { munger.getSourceLocation() }
  965. );
  966. }
  967. return false;
  968. }
  969. }
  970. }
  971. return true;
  972. }
  973. InstructionList loadThisJoinPoint() {
  974. InstructionFactory fact = getFactory();
  975. InstructionList il = new InstructionList();
  976. if (isThisJoinPointLazy) {
  977. // If we're lazy, build the join point right here.
  978. il.append(createThisJoinPoint());
  979. // Does someone else need it? If so, store it for later retrieval
  980. if (lazyTjpConsumers > 1) {
  981. il.append(thisJoinPointVar.createStore(fact));
  982. InstructionHandle end = il.append(thisJoinPointVar.createLoad(fact));
  983. il.insert(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, end));
  984. il.insert(thisJoinPointVar.createLoad(fact));
  985. }
  986. } else {
  987. // If not lazy, its already been built and stored, just retrieve it
  988. thisJoinPointVar.appendLoad(il, fact);
  989. }
  990. return il;
  991. }
  992. InstructionList createThisJoinPoint() {
  993. InstructionFactory fact = getFactory();
  994. InstructionList il = new InstructionList();
  995. BcelVar staticPart = getThisJoinPointStaticPartBcelVar();
  996. staticPart.appendLoad(il, fact);
  997. if (hasThis()) {
  998. ((BcelVar)getThisVar()).appendLoad(il, fact);
  999. } else {
  1000. il.append(new ACONST_NULL());
  1001. }
  1002. if (hasTarget()) {
  1003. ((BcelVar)getTargetVar()).appendLoad(il, fact);
  1004. } else {
  1005. il.append(new ACONST_NULL());
  1006. }
  1007. switch(getArgCount()) {
  1008. case 0:
  1009. il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory",
  1010. "makeJP", LazyClassGen.tjpType,
  1011. new Type[] { LazyClassGen.staticTjpType,
  1012. Type.OBJECT, Type.OBJECT},
  1013. Constants.INVOKESTATIC));
  1014. break;
  1015. case 1:
  1016. ((BcelVar)getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
  1017. il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory",
  1018. "makeJP", LazyClassGen.tjpType,
  1019. new Type[] { LazyClassGen.staticTjpType,
  1020. Type.OBJECT, Type.OBJECT, Type.OBJECT},
  1021. Constants.INVOKESTATIC));
  1022. break;
  1023. case 2:
  1024. ((BcelVar)getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
  1025. ((BcelVar)getArgVar(1)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
  1026. il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory",
  1027. "makeJP", LazyClassGen.tjpType,
  1028. new Type[] { LazyClassGen.staticTjpType,
  1029. Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT},
  1030. Constants.INVOKESTATIC));
  1031. break;
  1032. default:
  1033. il.append(makeArgsObjectArray());
  1034. il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory",
  1035. "makeJP", LazyClassGen.tjpType,
  1036. new Type[] { LazyClassGen.staticTjpType,
  1037. Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1)},
  1038. Constants.INVOKESTATIC));
  1039. break;
  1040. }
  1041. return il;
  1042. }
  1043. /**
  1044. * Get the Var for the jpStaticPart
  1045. * @return
  1046. */
  1047. public BcelVar getThisJoinPointStaticPartBcelVar() {
  1048. return getThisJoinPointStaticPartBcelVar(false);
  1049. }
  1050. /**
  1051. * Get the Var for the xxxxJpStaticPart, xxx = this or enclosing
  1052. * @param isEnclosingJp true to have the enclosingJpStaticPart
  1053. * @return
  1054. */
  1055. public BcelVar getThisJoinPointStaticPartBcelVar(final boolean isEnclosingJp) {
  1056. if (thisJoinPointStaticPartVar == null) {
  1057. Field field = getEnclosingClass().getTjpField(this, isEnclosingJp);
  1058. thisJoinPointStaticPartVar =
  1059. new BcelFieldRef(
  1060. isEnclosingJp?
  1061. world.getCoreType(UnresolvedType.forName("org.aspectj.lang.JoinPoint$EnclosingStaticPart")):
  1062. world.getCoreType(UnresolvedType.forName("org.aspectj.lang.JoinPoint$StaticPart")),
  1063. getEnclosingClass().getClassName(),
  1064. field.getName());
  1065. // getEnclosingClass().warnOnAddedStaticInitializer(this,munger.getSourceLocation());
  1066. }
  1067. return thisJoinPointStaticPartVar;
  1068. }
  1069. /**
  1070. * Get the Var for the enclosingJpStaticPart
  1071. * @return
  1072. */
  1073. public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() {
  1074. if (enclosingShadow == null) {
  1075. // the enclosing of an execution is itself
  1076. return getThisJoinPointStaticPartBcelVar(true);
  1077. } else {
  1078. return ((BcelShadow)enclosingShadow).getThisJoinPointStaticPartBcelVar(true);
  1079. }
  1080. }
  1081. //??? need to better understand all the enclosing variants
  1082. public Member getEnclosingCodeSignature() {
  1083. if (getKind().isEnclosingKind()) {
  1084. return getSignature();
  1085. } else if (getKind() == Shadow.PreInitialization) {
  1086. // PreInit doesn't enclose code but its signature
  1087. // is correctly the signature of the ctor.
  1088. return getSignature();
  1089. } else if (enclosingShadow == null) {
  1090. return getEnclosingMethod().getMemberView();
  1091. } else {
  1092. return enclosingShadow.getSignature();
  1093. }
  1094. }
  1095. private InstructionList makeArgsObjectArray() {
  1096. InstructionFactory fact = getFactory();
  1097. BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
  1098. final InstructionList il = new InstructionList();
  1099. int alen = getArgCount() ;
  1100. il.append(Utility.createConstant(fact, alen));
  1101. il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  1102. arrayVar.appendStore(il, fact);
  1103. int stateIndex = 0;
  1104. for (int i = 0, len = getArgCount(); i<len; i++) {
  1105. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar)getArgVar(i));
  1106. stateIndex++;
  1107. }
  1108. arrayVar.appendLoad(il, fact);
  1109. return il;
  1110. }
  1111. // ---- initializing var tables
  1112. /* initializing this is doesn't do anything, because this
  1113. * is protected from side-effects, so we don't need to copy its location
  1114. */
  1115. private void initializeThisVar() {
  1116. if (thisVar != null) return;
  1117. thisVar = new BcelVar(getThisType().resolve(world), 0);
  1118. thisVar.setPositionInAroundState(0);
  1119. }
  1120. public void initializeTargetVar() {
  1121. InstructionFactory fact = getFactory();
  1122. if (targetVar != null) return;
  1123. if (getKind().isTargetSameAsThis()) {
  1124. if (hasThis()) initializeThisVar();
  1125. targetVar = thisVar;
  1126. } else {
  1127. initializeArgVars(); // gotta pop off the args before we find the target
  1128. UnresolvedType type = getTargetType();
  1129. type = ensureTargetTypeIsCorrect(type);
  1130. targetVar = genTempVar(type, "ajc$target");
  1131. range.insert(targetVar.createStore(fact), Range.OutsideBefore);
  1132. targetVar.setPositionInAroundState(hasThis() ? 1 : 0);
  1133. }
  1134. }
  1135. /* PR 72528
  1136. * This method double checks the target type under certain conditions. The Java 1.4
  1137. * compilers seem to take calls to clone methods on array types and create bytecode that
  1138. * looks like clone is being called on Object. If we advise a clone call with around
  1139. * advice we extract the call into a helper method which we can then refer to. Because the
  1140. * type in the bytecode for the call to clone is Object we create a helper method with
  1141. * an Object parameter - this is not correct as we have lost the fact that the actual
  1142. * type is an array type. If we don't do the check below we will create code that fails
  1143. * java verification. This method checks for the peculiar set of conditions and if they
  1144. * are true, it has a sneak peek at the code before the call to see what is on the stack.
  1145. */
  1146. public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) {
  1147. if (tx.equals(ResolvedType.OBJECT) && getKind() == MethodCall &&
  1148. getSignature().getReturnType().equals(ResolvedType.OBJECT) &&
  1149. getSignature().getArity()==0 &&
  1150. getSignature().getName().charAt(0) == 'c' &&
  1151. getSignature().getName().equals("clone")) {
  1152. // Lets go back through the code from the start of the shadow
  1153. InstructionHandle searchPtr = range.getStart().getPrev();
  1154. while (Range.isRangeHandle(searchPtr) ||
  1155. searchPtr.getInstruction() instanceof StoreInstruction) { // ignore this instruction - it doesnt give us the info we want
  1156. searchPtr = searchPtr.getPrev();
  1157. }
  1158. // A load instruction may tell us the real type of what the clone() call is on
  1159. if (searchPtr.getInstruction() instanceof LoadInstruction) {
  1160. LoadInstruction li = (LoadInstruction)searchPtr.getInstruction();
  1161. li.getIndex();
  1162. LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr,li.getIndex());
  1163. return lvt.getType();
  1164. }
  1165. // A field access instruction may tell us the real type of what the clone() call is on
  1166. if (searchPtr.getInstruction() instanceof FieldInstruction) {
  1167. FieldInstruction si = (FieldInstruction)searchPtr.getInstruction();
  1168. Type t = si.getFieldType(getEnclosingClass().getConstantPoolGen());
  1169. return BcelWorld.fromBcel(t);
  1170. }
  1171. // A new array instruction obviously tells us it is an array type !
  1172. if (searchPtr.getInstruction() instanceof ANEWARRAY) {
  1173. //ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction();
  1174. //Type t = ana.getType(getEnclosingClass().getConstantPoolGen());
  1175. // Just use a standard java.lang.object array - that will work fine
  1176. return BcelWorld.fromBcel(new ArrayType(Type.OBJECT,1));
  1177. }
  1178. // A multi new array instruction obviously tells us it is an array type !
  1179. if (searchPtr.getInstruction() instanceof MULTIANEWARRAY) {
  1180. MULTIANEWARRAY ana = (MULTIANEWARRAY)searchPtr.getInstruction();
  1181. // Type t = ana.getType(getEnclosingClass().getConstantPoolGen());
  1182. // t = new ArrayType(t,ana.getDimensions());
  1183. // Just use a standard java.lang.object array - that will work fine
  1184. return BcelWorld.fromBcel(new ArrayType(Type.OBJECT,ana.getDimensions()));
  1185. }
  1186. throw new BCException("Can't determine real target of clone() when processing instruction "+
  1187. searchPtr.getInstruction());
  1188. }
  1189. return tx;
  1190. }
  1191. public void initializeArgVars() {
  1192. if (argVars != null) return;
  1193. InstructionFactory fact = getFactory();
  1194. int len = getArgCount();
  1195. argVars = new BcelVar[len];
  1196. int positionOffset = (hasTarget() ? 1 : 0) +
  1197. ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0);
  1198. if (getKind().argsOnStack()) {
  1199. // we move backwards because we're popping off the stack
  1200. for (int i = len - 1; i >= 0; i--) {
  1201. UnresolvedType type = getArgType(i);
  1202. BcelVar tmp = genTempVar(type, "ajc$arg" + i);
  1203. range.insert(tmp.createStore(getFactory()), Range.OutsideBefore);
  1204. int position = i;
  1205. position += positionOffset;
  1206. tmp.setPositionInAroundState(position);
  1207. argVars[i] = tmp;
  1208. }
  1209. } else {
  1210. int index = 0;
  1211. if (arg0HoldsThis()) index++;
  1212. for (int i = 0; i < len; i++) {
  1213. UnresolvedType type = getArgType(i);
  1214. BcelVar tmp = genTempVar(type, "ajc$arg" + i);
  1215. range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore);
  1216. argVars[i] = tmp;
  1217. int position = i;
  1218. position += positionOffset;
  1219. // System.out.println("set position: " + tmp + ", " + position + " in " + this);
  1220. // System.out.println(" hasThis: " + hasThis() + ", hasTarget: " + hasTarget());
  1221. tmp.setPositionInAroundState(position);
  1222. index += type.getSize();
  1223. }
  1224. }
  1225. }
  1226. public void initializeForAroundClosure() {
  1227. initializeArgVars();
  1228. if (hasTarget()) initializeTargetVar();
  1229. if (hasThis()) initializeThisVar();
  1230. // System.out.println("initialized: " + this + " thisVar = " + thisVar);
  1231. }
  1232. public void initializeThisAnnotationVars() {
  1233. if (thisAnnotationVars != null) return;
  1234. thisAnnotationVars = new HashMap();
  1235. // populate..
  1236. }
  1237. public void initializeTargetAnnotationVars() {
  1238. if (targetAnnotationVars != null) return;
  1239. if (getKind().isTargetSameAsThis()) {
  1240. if (hasThis()) initializeThisAnnotationVars();
  1241. targetAnnotationVars = thisAnnotationVars;
  1242. } else {
  1243. targetAnnotationVars = new HashMap();
  1244. ResolvedType[] rtx = this.getTargetType().resolve(world).getAnnotationTypes(); // what about annotations we havent gotten yet but we will get in subclasses?
  1245. for (int i = 0; i < rtx.length; i++) {
  1246. ResolvedType typeX = rtx[i];
  1247. targetAnnotationVars.put(typeX,new TypeAnnotationAccessVar(typeX,(BcelVar)getTargetVar()));
  1248. }
  1249. // populate.
  1250. }
  1251. }
  1252. public void initializeArgAnnotationVars() {
  1253. if (argAnnotationVars != null) return;
  1254. int numArgs = getArgCount();
  1255. argAnnotationVars = new Map[numArgs];
  1256. for (int i = 0; i < argAnnotationVars.length; i++) {
  1257. argAnnotationVars[i] = new HashMap();
  1258. //FIXME asc just delete this logic - we always build the Var on demand, as we don't know at weave time
  1259. // what the full set of annotations could be (due to static/dynamic type differences...)
  1260. }
  1261. }
  1262. protected Member getRelevantMember(Member foundMember, Member relevantMember, ResolvedType relevantType){
  1263. if (foundMember != null){
  1264. return foundMember;
  1265. }
  1266. foundMember = getSignature().resolve(world);
  1267. if (foundMember == null && relevantMember != null) {
  1268. foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
  1269. }
  1270. // check the ITD'd dooberries
  1271. List mungers = relevantType.resolve(world).getInterTypeMungers();
  1272. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  1273. BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
  1274. if (typeMunger.getMunger() instanceof NewMethodTypeMunger ||
  1275. typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
  1276. ResolvedMember fakerm = typeMunger.getSignature();
  1277. if (fakerm.getName().equals(getSignature().getName()) &&
  1278. fakerm.getParameterSignature().equals(getSignature().getParameterSignature())){
  1279. if (foundMember.getKind()==ResolvedMember.CONSTRUCTOR){
  1280. foundMember = AjcMemberMaker.interConstructor(
  1281. relevantType,
  1282. (ResolvedMember)foundMember,
  1283. typeMunger.getAspectType());
  1284. } else {
  1285. foundMember = AjcMemberMaker.interMethod((ResolvedMember)foundMember,
  1286. typeMunger.getAspectType(), false);
  1287. }
  1288. // in the above.. what about if it's on an Interface? Can that happen?
  1289. // then the last arg of the above should be true
  1290. return foundMember;
  1291. }
  1292. }
  1293. }
  1294. return foundMember;
  1295. }
  1296. protected ResolvedType [] getAnnotations(Member foundMember, Member relevantMember, ResolvedType relevantType){
  1297. if (foundMember == null){
  1298. // check the ITD'd dooberries
  1299. List mungers = relevantType.resolve(world).getInterTypeMungers();
  1300. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  1301. BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
  1302. if (typeMunger.getMunger() instanceof NewMethodTypeMunger ||
  1303. typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
  1304. ResolvedMember fakerm = typeMunger.getSignature();
  1305. //if (fakerm.hasAnnotations())
  1306. ResolvedMember ajcMethod = (getSignature().getKind()==ResolvedMember.CONSTRUCTOR?
  1307. AjcMemberMaker.postIntroducedConstructor(typeMunger.getAspectType(),fakerm.getDeclaringType(),fakerm.getParameterTypes()):
  1308. AjcMemberMaker.interMethodDispatcher(fakerm,typeMunger.getAspectType()));
  1309. //AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType()));
  1310. ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod);
  1311. if (fakerm.getName().equals(getSignature().getName()) &&
  1312. fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) {
  1313. relevantType = typeMunger.getAspectType();
  1314. foundMember = rmm;
  1315. return foundMember.getAnnotationTypes();
  1316. }
  1317. }
  1318. }
  1319. // didn't find in ITDs, look in supers
  1320. foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
  1321. if (foundMember == null) {
  1322. throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType);
  1323. }
  1324. }
  1325. return foundMember.getAnnotationTypes();
  1326. }
  1327. public void initializeKindedAnnotationVars() {
  1328. if (kindedAnnotationVars != null) return;
  1329. kindedAnnotationVars = new HashMap();
  1330. // by determining what "kind" of shadow we are, we can find out the
  1331. // annotations on the appropriate element (method, field, constructor, type).
  1332. // Then create one BcelVar entry in the map for each annotation, keyed by
  1333. // annotation type (UnresolvedType).
  1334. // FIXME asc Refactor this code, there is duplication
  1335. ResolvedType[] annotations = null;
  1336. Member relevantMember = getSignature();
  1337. ResolvedType relevantType = relevantMember.getDeclaringType().resolve(world);
  1338. if (getKind() == Shadow.StaticInitialization) {
  1339. annotations = relevantType.resolve(world).getAnnotationTypes();
  1340. } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) {
  1341. Member foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(),getSignature());
  1342. annotations = getAnnotations(foundMember, relevantMember, relevantType);
  1343. relevantMember = getRelevantMember(foundMember,relevantMember,relevantType);
  1344. relevantType = relevantMember.getDeclaringType().resolve(world);
  1345. } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) {
  1346. relevantMember = findField(relevantType.getDeclaredFields(),getSignature());
  1347. if (relevantMember==null) {
  1348. // check the ITD'd dooberries
  1349. List mungers = relevantType.resolve(world).getInterTypeMungers();
  1350. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  1351. BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
  1352. if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
  1353. ResolvedMember fakerm = typeMunger.getSignature();
  1354. //if (fakerm.hasAnnotations())
  1355. ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm,typeMunger.getAspectType());
  1356. ResolvedMember rmm = findMethod(typeMunger.getAspectType(),ajcMethod);
  1357. if (fakerm.equals(getSignature())) {
  1358. relevantType = typeMunger.getAspectType();
  1359. relevantMember = rmm;
  1360. }
  1361. }
  1362. }
  1363. }
  1364. annotations = relevantMember.getAnnotationTypes();
  1365. } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution ||
  1366. getKind() == Shadow.AdviceExecution) {
  1367. ResolvedMember rm[] = relevantType.getDeclaredMethods();
  1368. Member foundMember = findMethod2(relevantType.getDeclaredMethods(),getSignature());
  1369. annotations = getAnnotations(foundMember, relevantMember,relevantType);
  1370. relevantMember = foundMember;
  1371. relevantMember = getRelevantMember(foundMember, relevantMember,relevantType);
  1372. } else if (getKind() == Shadow.ExceptionHandler) {
  1373. relevantType = getSignature().getParameterTypes()[0].resolve(world);
  1374. annotations = relevantType.getAnnotationTypes();
  1375. } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) {
  1376. ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(),getSignature());
  1377. annotations = found.getAnnotationTypes();
  1378. }
  1379. if (annotations == null) {
  1380. // We can't have recognized the shadow - should blow up now to be on the safe side
  1381. throw new BCException("Couldn't discover annotations for shadow: "+getKind());
  1382. }
  1383. for (int i = 0; i < annotations.length; i++) {
  1384. ResolvedType aTX = annotations[i];
  1385. KindedAnnotationAccessVar kaav = new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,relevantMember);
  1386. kindedAnnotationVars.put(aTX,kaav);
  1387. }
  1388. }
  1389. //FIXME asc whats the real diff between this one and the version in findMethod()?
  1390. ResolvedMember findMethod2(ResolvedMember rm[], Member sig) {
  1391. ResolvedMember found = null;
  1392. // String searchString = getSignature().getName()+getSignature().getParameterSignature();
  1393. for (int i = 0; i < rm.length && found==null; i++) {
  1394. ResolvedMember member = rm[i];
  1395. if (member.getName().equals(sig.getName()) && member.getParameterSignature().equals(sig.getParameterSignature()))
  1396. found = member;
  1397. }
  1398. return found;
  1399. }
  1400. private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
  1401. ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
  1402. for (int i = 0; i < decMethods.length; i++) {
  1403. ResolvedMember member = decMethods[i];
  1404. if (member.equals(ajcMethod)) return member;
  1405. }
  1406. return null;
  1407. }
  1408. private ResolvedMember findField(ResolvedMember[] members,Member lookingFor) {
  1409. for (int i = 0; i < members.length; i++) {
  1410. ResolvedMember member = members[i];
  1411. if ( member.getName().equals(getSignature().getName()) &&
  1412. member.getType().equals(getSignature().getType())) {
  1413. return member;
  1414. }
  1415. }
  1416. return null;
  1417. }
  1418. public void initializeWithinAnnotationVars() {
  1419. if (withinAnnotationVars != null) return;
  1420. withinAnnotationVars = new HashMap();
  1421. ResolvedType[] annotations = getEnclosingType().resolve(world).getAnnotationTypes();
  1422. for (int i = 0; i < annotations.length; i++) {
  1423. ResolvedType ann = annotations[i];
  1424. Kind k = Shadow.StaticInitialization;
  1425. withinAnnotationVars.put(ann,new KindedAnnotationAccessVar(k,ann,getEnclosingType(),null));
  1426. }
  1427. }
  1428. public void initializeWithinCodeAnnotationVars() {
  1429. if (withincodeAnnotationVars != null) return;
  1430. withincodeAnnotationVars = new HashMap();
  1431. // For some shadow we are interested in annotations on the method containing that shadow.
  1432. ResolvedType[] annotations = getEnclosingMethod().getMemberView().getAnnotationTypes();
  1433. for (int i = 0; i < annotations.length; i++) {
  1434. ResolvedType ann = annotations[i];
  1435. Kind k = (getEnclosingMethod().getMemberView().getKind()==Member.CONSTRUCTOR?
  1436. Shadow.ConstructorExecution:Shadow.MethodExecution);
  1437. withincodeAnnotationVars.put(ann,
  1438. new KindedAnnotationAccessVar(k,ann,getEnclosingType(),getEnclosingCodeSignature()));
  1439. }
  1440. }
  1441. // ---- weave methods
  1442. void weaveBefore(BcelAdvice munger) {
  1443. range.insert(
  1444. munger.getAdviceInstructions(this, null, range.getRealStart()),
  1445. Range.InsideBefore);
  1446. }
  1447. public void weaveAfter(BcelAdvice munger) {
  1448. weaveAfterThrowing(munger, UnresolvedType.THROWABLE);
  1449. weaveAfterReturning(munger);
  1450. }
  1451. /**
  1452. * We guarantee that the return value is on the top of the stack when
  1453. * munger.getAdviceInstructions() will be run
  1454. * (Unless we have a void return type in which case there's nothing)
  1455. */
  1456. public void weaveAfterReturning(BcelAdvice munger) {
  1457. // InstructionFactory fact = getFactory();
  1458. List returns = new ArrayList();
  1459. Instruction ret = null;
  1460. for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
  1461. if (ih.getInstruction() instanceof ReturnInstruction) {
  1462. returns.add(ih);
  1463. ret = Utility.copyInstruction(ih.getInstruction());
  1464. }
  1465. }
  1466. InstructionList retList;
  1467. InstructionHandle afterAdvice;
  1468. if (ret != null) {
  1469. retList = new InstructionList(ret);
  1470. afterAdvice = retList.getStart();
  1471. } else /* if (munger.hasDynamicTests()) */ {
  1472. /*
  1473. *
  1474. 27: getstatic #72; //Field ajc$cflowCounter$0:Lorg/aspectj/runtime/internal/CFlowCounter;
  1475. 30: invokevirtual #87; //Method org/aspectj/runtime/internal/CFlowCounter.dec:()V
  1476. 33: aload 6
  1477. 35: athrow
  1478. 36: nop
  1479. 37: getstatic #72; //Field ajc$cflowCounter$0:Lorg/aspectj/runtime/internal/CFlowCounter;
  1480. 40: invokevirtual #87; //Method org/aspectj/runtime/internal/CFlowCounter.dec:()V
  1481. 43: d2i
  1482. 44: invokespecial #23; //Method java/lang/Object."<init>":()V
  1483. */
  1484. retList = new InstructionList(InstructionConstants.NOP);
  1485. afterAdvice = retList.getStart();
  1486. // } else {
  1487. // retList = new InstructionList();
  1488. // afterAdvice = null;
  1489. }
  1490. InstructionList advice = new InstructionList();
  1491. BcelVar tempVar = null;
  1492. if (munger.hasExtraParameter()) {
  1493. UnresolvedType tempVarType = getReturnType();
  1494. if (tempVarType.equals(ResolvedType.VOID)) {
  1495. tempVar = genTempVar(UnresolvedType.OBJECT);
  1496. advice.append(InstructionConstants.ACONST_NULL);
  1497. tempVar.appendStore(advice, getFactory());
  1498. } else {
  1499. tempVar = genTempVar(tempVarType);
  1500. advice.append(InstructionFactory.createDup(tempVarType.getSize()));
  1501. tempVar.appendStore(advice, getFactory());
  1502. }
  1503. }
  1504. advice.append(munger.getAdviceInstructions(this, tempVar, afterAdvice));
  1505. if (ret != null) {
  1506. InstructionHandle gotoTarget = advice.getStart();
  1507. for (Iterator i = returns.iterator(); i.hasNext();) {
  1508. InstructionHandle ih = (InstructionHandle) i.next();
  1509. Utility.replaceInstruction(
  1510. ih,
  1511. InstructionFactory.createBranchInstruction(
  1512. Constants.GOTO,
  1513. gotoTarget),
  1514. enclosingMethod);
  1515. }
  1516. range.append(advice);
  1517. range.append(retList);
  1518. } else {
  1519. range.append(advice);
  1520. range.append(retList);
  1521. }
  1522. }
  1523. public void weaveAfterThrowing(BcelAdvice munger, UnresolvedType catchType) {
  1524. // a good optimization would be not to generate anything here
  1525. // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
  1526. // a shadow, inside me).
  1527. if (getRange().getStart().getNext() == getRange().getEnd()) return;
  1528. InstructionFactory fact = getFactory();
  1529. InstructionList handler = new InstructionList();
  1530. BcelVar exceptionVar = genTempVar(catchType);
  1531. exceptionVar.appendStore(handler, fact);
  1532. // pr62642
  1533. // I will now jump through some firey BCEL hoops to generate a trivial bit of code:
  1534. // if (exc instanceof ExceptionInInitializerError)
  1535. // throw (ExceptionInInitializerError)exc;
  1536. if (this.getEnclosingMethod().getName().equals("<clinit>")) {
  1537. ResolvedType eiieType = world.resolve("java.lang.ExceptionInInitializerError");
  1538. ObjectType eiieBcelType = (ObjectType)BcelWorld.makeBcelType(eiieType);
  1539. InstructionList ih = new InstructionList(InstructionConstants.NOP);
  1540. handler.append(exceptionVar.createLoad(fact));
  1541. handler.append(fact.createInstanceOf(eiieBcelType));
  1542. BranchInstruction bi =
  1543. InstructionFactory.createBranchInstruction(Constants.IFEQ,ih.getStart());
  1544. handler.append(bi);
  1545. handler.append(exceptionVar.createLoad(fact));
  1546. handler.append(fact.createCheckCast(eiieBcelType));
  1547. handler.append(InstructionConstants.ATHROW);
  1548. handler.append(ih);
  1549. }
  1550. InstructionList endHandler = new InstructionList(
  1551. exceptionVar.createLoad(fact));
  1552. handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart()));
  1553. handler.append(endHandler);
  1554. handler.append(InstructionConstants.ATHROW);
  1555. InstructionHandle handlerStart = handler.getStart();
  1556. if (isFallsThrough()) {
  1557. InstructionHandle jumpTarget = handler.append(InstructionConstants.NOP);
  1558. handler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget));
  1559. }
  1560. InstructionHandle protectedEnd = handler.getStart();
  1561. range.insert(handler, Range.InsideAfter);
  1562. enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
  1563. handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), //???Type.THROWABLE,
  1564. // high priority if our args are on the stack
  1565. getKind().hasHighPriorityExceptions());
  1566. }
  1567. //??? this shares a lot of code with the above weaveAfterThrowing
  1568. //??? would be nice to abstract that to say things only once
  1569. public void weaveSoftener(BcelAdvice munger, UnresolvedType catchType) {
  1570. // a good optimization would be not to generate anything here
  1571. // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
  1572. // a shadow, inside me).
  1573. if (getRange().getStart().getNext() == getRange().getEnd()) return;
  1574. InstructionFactory fact = getFactory();
  1575. InstructionList handler = new InstructionList();
  1576. InstructionList rtExHandler = new InstructionList();
  1577. BcelVar exceptionVar = genTempVar(catchType);
  1578. handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE));
  1579. handler.append(InstructionFactory.createDup(1));
  1580. handler.append(exceptionVar.createLoad(fact));
  1581. handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>",
  1582. Type.VOID, new Type[] { Type.THROWABLE }, Constants.INVOKESPECIAL)); //??? special
  1583. handler.append(InstructionConstants.ATHROW);
  1584. // ENH 42737
  1585. exceptionVar.appendStore(rtExHandler, fact);
  1586. // aload_1
  1587. rtExHandler.append(exceptionVar.createLoad(fact));
  1588. // instanceof class java/lang/RuntimeException
  1589. rtExHandler.append(fact.createInstanceOf(new ObjectType("java.lang.RuntimeException")));
  1590. // ifeq go to new SOFT_EXCEPTION_TYPE instruction
  1591. rtExHandler.append(InstructionFactory.createBranchInstruction(Constants.IFEQ,handler.getStart()));
  1592. // aload_1
  1593. rtExHandler.append(exceptionVar.createLoad(fact));
  1594. // athrow
  1595. rtExHandler.append(InstructionFactory.ATHROW);
  1596. InstructionHandle handlerStart = rtExHandler.getStart();
  1597. if (isFallsThrough()) {
  1598. InstructionHandle jumpTarget = range.getEnd();//handler.append(fact.NOP);
  1599. rtExHandler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget));
  1600. }
  1601. rtExHandler.append(handler);
  1602. InstructionHandle protectedEnd = rtExHandler.getStart();
  1603. range.insert(rtExHandler, Range.InsideAfter);
  1604. enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
  1605. handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType),
  1606. // high priority if our args are on the stack
  1607. getKind().hasHighPriorityExceptions());
  1608. }
  1609. public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) {
  1610. final InstructionFactory fact = getFactory();
  1611. InstructionList entryInstructions = new InstructionList();
  1612. InstructionList entrySuccessInstructions = new InstructionList();
  1613. onVar.appendLoad(entrySuccessInstructions, fact);
  1614. entrySuccessInstructions.append(
  1615. Utility.createInvoke(fact, world,
  1616. AjcMemberMaker.perObjectBind(munger.getConcreteAspect())));
  1617. InstructionList testInstructions =
  1618. munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
  1619. range.getRealStart(),
  1620. entrySuccessInstructions.getStart());
  1621. entryInstructions.append(testInstructions);
  1622. entryInstructions.append(entrySuccessInstructions);
  1623. range.insert(entryInstructions, Range.InsideBefore);
  1624. }
  1625. // PTWIMPL Create static initializer to call the aspect factory
  1626. /**
  1627. * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf()
  1628. */
  1629. public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger,UnresolvedType t) {
  1630. if (t.resolve(world).isInterface()) return; // Don't initialize statics in
  1631. final InstructionFactory fact = getFactory();
  1632. InstructionList entryInstructions = new InstructionList();
  1633. InstructionList entrySuccessInstructions = new InstructionList();
  1634. BcelObjectType aspectType = BcelWorld.getBcelObjectType(munger.getConcreteAspect());
  1635. String aspectname = munger.getConcreteAspect().getName();
  1636. String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect());
  1637. entrySuccessInstructions.append(new PUSH(fact.getConstantPool(),t.getName()));
  1638. entrySuccessInstructions.append(fact.createInvoke(aspectname,"ajc$createAspectInstance",new ObjectType(aspectname),
  1639. new Type[]{new ObjectType("java.lang.String")},Constants.INVOKESTATIC));
  1640. entrySuccessInstructions.append(fact.createPutStatic(t.getName(),ptwField,
  1641. new ObjectType(aspectname)));
  1642. entryInstructions.append(entrySuccessInstructions);
  1643. range.insert(entryInstructions, Range.InsideBefore);
  1644. }
  1645. public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) {
  1646. final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry ||
  1647. munger.getKind() == AdviceKind.PerCflowEntry;
  1648. final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  1649. final InstructionFactory fact = getFactory();
  1650. final BcelVar testResult = genTempVar(ResolvedType.BOOLEAN);
  1651. InstructionList entryInstructions = new InstructionList();
  1652. {
  1653. InstructionList entrySuccessInstructions = new InstructionList();
  1654. if (munger.hasDynamicTests()) {
  1655. entryInstructions.append(Utility.createConstant(fact, 0));
  1656. testResult.appendStore(entryInstructions, fact);
  1657. entrySuccessInstructions.append(Utility.createConstant(fact, 1));
  1658. testResult.appendStore(entrySuccessInstructions, fact);
  1659. }
  1660. if (isPer) {
  1661. entrySuccessInstructions.append(
  1662. fact.createInvoke(munger.getConcreteAspect().getName(),
  1663. NameMangler.PERCFLOW_PUSH_METHOD,
  1664. Type.VOID,
  1665. new Type[] { },
  1666. Constants.INVOKESTATIC));
  1667. } else {
  1668. BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars();
  1669. if (cflowStateVars.length == 0) {
  1670. // This should be getting managed by a counter - lets make sure.
  1671. if (!cflowField.getType().getName().endsWith("CFlowCounter"))
  1672. throw new RuntimeException("Incorrectly attempting counter operation on stacked cflow");
  1673. entrySuccessInstructions.append(
  1674. Utility.createGet(fact, cflowField));
  1675. //arrayVar.appendLoad(entrySuccessInstructions, fact);
  1676. entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE,"inc",Type.VOID,new Type[] { },Constants.INVOKEVIRTUAL));
  1677. } else {
  1678. BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
  1679. int alen = cflowStateVars.length;
  1680. entrySuccessInstructions.append(Utility.createConstant(fact, alen));
  1681. entrySuccessInstructions.append(
  1682. (Instruction) fact.createNewArray(Type.OBJECT, (short) 1));
  1683. arrayVar.appendStore(entrySuccessInstructions, fact);
  1684. for (int i = 0; i < alen; i++) {
  1685. arrayVar.appendConvertableArrayStore(
  1686. entrySuccessInstructions,
  1687. fact,
  1688. i,
  1689. cflowStateVars[i]);
  1690. }
  1691. entrySuccessInstructions.append(
  1692. Utility.createGet(fact, cflowField));
  1693. arrayVar.appendLoad(entrySuccessInstructions, fact);
  1694. entrySuccessInstructions.append(
  1695. fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID,
  1696. new Type[] { objectArrayType },
  1697. Constants.INVOKEVIRTUAL));
  1698. }
  1699. }
  1700. InstructionList testInstructions =
  1701. munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
  1702. range.getRealStart(),
  1703. entrySuccessInstructions.getStart());
  1704. entryInstructions.append(testInstructions);
  1705. entryInstructions.append(entrySuccessInstructions);
  1706. }
  1707. // this is the same for both per and non-per
  1708. weaveAfter(new BcelAdvice(null, null, null, 0, 0, 0, null, null) {
  1709. public InstructionList getAdviceInstructions(
  1710. BcelShadow s,
  1711. BcelVar extraArgVar,
  1712. InstructionHandle ifNoAdvice) {
  1713. InstructionList exitInstructions = new InstructionList();
  1714. if (munger.hasDynamicTests()) {
  1715. testResult.appendLoad(exitInstructions, fact);
  1716. exitInstructions.append(
  1717. InstructionFactory.createBranchInstruction(
  1718. Constants.IFEQ,
  1719. ifNoAdvice));
  1720. }
  1721. exitInstructions.append(Utility.createGet(fact, cflowField));
  1722. if (munger.getKind() != AdviceKind.PerCflowEntry &&
  1723. munger.getKind() != AdviceKind.PerCflowBelowEntry &&
  1724. munger.getExposedStateAsBcelVars().length==0) {
  1725. exitInstructions
  1726. .append(
  1727. fact
  1728. .createInvoke(
  1729. NameMangler.CFLOW_COUNTER_TYPE,
  1730. "dec",
  1731. Type.VOID,
  1732. new Type[] {
  1733. }, Constants.INVOKEVIRTUAL));
  1734. } else {
  1735. exitInstructions
  1736. .append(
  1737. fact
  1738. .createInvoke(
  1739. NameMangler.CFLOW_STACK_TYPE,
  1740. "pop",
  1741. Type.VOID,
  1742. new Type[] {
  1743. }, Constants.INVOKEVIRTUAL));
  1744. }
  1745. return exitInstructions;
  1746. }
  1747. });
  1748. range.insert(entryInstructions, Range.InsideBefore);
  1749. }
  1750. public void weaveAroundInline(
  1751. BcelAdvice munger,
  1752. boolean hasDynamicTest)
  1753. {
  1754. /* Implementation notes:
  1755. *
  1756. * AroundInline still extracts the instructions of the original shadow into
  1757. * an extracted method. This allows inlining of even that advice that doesn't
  1758. * call proceed or calls proceed more than once.
  1759. *
  1760. * It extracts the instructions of the original shadow into a method.
  1761. *
  1762. * Then it extracts the instructions of the advice into a new method defined on
  1763. * this enclosing class. This new method can then be specialized as below.
  1764. *
  1765. * Then it searches in the instructions of the advice for any call to the
  1766. * proceed method.
  1767. *
  1768. * At such a call, there is stuff on the stack representing the arguments to
  1769. * proceed. Pop these into the frame.
  1770. *
  1771. * Now build the stack for the call to the extracted method, taking values
  1772. * either from the join point state or from the new frame locs from proceed.
  1773. * Now call the extracted method. The right return value should be on the
  1774. * stack, so no cast is necessary.
  1775. *
  1776. * If only one call to proceed is made, we can re-inline the original shadow.
  1777. * We are not doing that presently.
  1778. *
  1779. * If the body of the advice can be determined to not alter the stack, or if
  1780. * this shadow doesn't care about the stack, i.e. method-execution, then the
  1781. * new method for the advice can also be re-lined. We are not doing that
  1782. * presently.
  1783. */
  1784. // !!! THIS BLOCK OF CODE SHOULD BE IN A METHOD CALLED weaveAround(...);
  1785. Member mungerSig = munger.getSignature();
  1786. ResolvedType declaringType = world.resolve(mungerSig.getDeclaringType(),true);
  1787. if (declaringType == ResolvedType.MISSING) {
  1788. IMessage msg = new Message(
  1789. WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName()),
  1790. "",IMessage.ERROR,getSourceLocation(),null,
  1791. new ISourceLocation[]{ munger.getSourceLocation()});
  1792. world.getMessageHandler().handleMessage(msg);
  1793. }
  1794. //??? might want some checks here to give better errors
  1795. BcelObjectType ot = BcelWorld.getBcelObjectType(declaringType);
  1796. LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig);
  1797. if (!adviceMethod.getCanInline()) {
  1798. weaveAroundClosure(munger, hasDynamicTest);
  1799. return;
  1800. }
  1801. // specific test for @AJ proceedInInners
  1802. if (munger.getConcreteAspect().isAnnotationStyleAspect()) {
  1803. // if we can't find one proceed()
  1804. // we suspect that the call is happening in an inner class
  1805. // so we don't inline it.
  1806. // Note: for code style, this is done at Aspect compilation time.
  1807. boolean canSeeProceedPassedToOther = false;
  1808. InstructionHandle curr = adviceMethod.getBody().getStart();
  1809. InstructionHandle end = adviceMethod.getBody().getEnd();
  1810. ConstantPoolGen cpg = adviceMethod.getEnclosingClass().getConstantPoolGen();
  1811. while (curr != end) {
  1812. InstructionHandle next = curr.getNext();
  1813. Instruction inst = curr.getInstruction();
  1814. if ((inst instanceof InvokeInstruction)
  1815. && ((InvokeInstruction)inst).getSignature(cpg).indexOf("Lorg/aspectj/lang/ProceedingJoinPoint;") > 0) {
  1816. // we may want to refine to exclude stuff returning jp ?
  1817. // does code style skip inline if i write dump(thisJoinPoint) ?
  1818. canSeeProceedPassedToOther = true;// we see one pjp passed around - dangerous
  1819. break;
  1820. }
  1821. curr = next;
  1822. }
  1823. if (canSeeProceedPassedToOther) {
  1824. // remember this decision to avoid re-analysis
  1825. adviceMethod.setCanInline(false);
  1826. weaveAroundClosure(munger, hasDynamicTest);
  1827. return;
  1828. }
  1829. }
  1830. // We can't inline around methods if they have around advice on them, this
  1831. // is because the weaving will extract the body and hence the proceed call.
  1832. //??? should consider optimizations to recognize simple cases that don't require body extraction
  1833. enclosingMethod.setCanInline(false);
  1834. // start by exposing various useful things into the frame
  1835. final InstructionFactory fact = getFactory();
  1836. // now generate the aroundBody method
  1837. LazyMethodGen extractedMethod =
  1838. extractMethod(
  1839. NameMangler.aroundCallbackMethodName(
  1840. getSignature(),
  1841. getEnclosingClass()),
  1842. Modifier.PRIVATE,
  1843. munger
  1844. );
  1845. // now extract the advice into its own method
  1846. String adviceMethodName =
  1847. NameMangler.aroundCallbackMethodName(
  1848. getSignature(),
  1849. getEnclosingClass()) + "$advice";
  1850. List argVarList = new ArrayList();
  1851. List proceedVarList = new ArrayList();
  1852. int extraParamOffset = 0;
  1853. // Create the extra parameters that are needed for passing to proceed
  1854. // This code is very similar to that found in makeCallToCallback and should
  1855. // be rationalized in the future
  1856. if (thisVar != null) {
  1857. argVarList.add(thisVar);
  1858. proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset));
  1859. extraParamOffset += thisVar.getType().getSize();
  1860. }
  1861. if (targetVar != null && targetVar != thisVar) {
  1862. argVarList.add(targetVar);
  1863. proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset));
  1864. extraParamOffset += targetVar.getType().getSize();
  1865. }
  1866. for (int i = 0, len = getArgCount(); i < len; i++) {
  1867. argVarList.add(argVars[i]);
  1868. proceedVarList.add(new BcelVar(argVars[i].getType(), extraParamOffset));
  1869. extraParamOffset += argVars[i].getType().getSize();
  1870. }
  1871. if (thisJoinPointVar != null) {
  1872. argVarList.add(thisJoinPointVar);
  1873. proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset));
  1874. extraParamOffset += thisJoinPointVar.getType().getSize();
  1875. }
  1876. Type[] adviceParameterTypes = adviceMethod.getArgumentTypes();
  1877. Type[] extractedMethodParameterTypes = extractedMethod.getArgumentTypes();
  1878. Type[] parameterTypes =
  1879. new Type[extractedMethodParameterTypes.length
  1880. + adviceParameterTypes.length
  1881. + 1];
  1882. int parameterIndex = 0;
  1883. System.arraycopy(
  1884. extractedMethodParameterTypes,
  1885. 0,
  1886. parameterTypes,
  1887. parameterIndex,
  1888. extractedMethodParameterTypes.length);
  1889. parameterIndex += extractedMethodParameterTypes.length;
  1890. parameterTypes[parameterIndex++] =
  1891. BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType());
  1892. System.arraycopy(
  1893. adviceParameterTypes,
  1894. 0,
  1895. parameterTypes,
  1896. parameterIndex,
  1897. adviceParameterTypes.length);
  1898. LazyMethodGen localAdviceMethod =
  1899. new LazyMethodGen(
  1900. Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
  1901. adviceMethod.getReturnType(),
  1902. adviceMethodName,
  1903. parameterTypes,
  1904. new String[0],
  1905. getEnclosingClass());
  1906. String donorFileName = adviceMethod.getEnclosingClass().getInternalFileName();
  1907. String recipientFileName = getEnclosingClass().getInternalFileName();
  1908. // System.err.println("donor " + donorFileName);
  1909. // System.err.println("recip " + recipientFileName);
  1910. if (! donorFileName.equals(recipientFileName)) {
  1911. localAdviceMethod.fromFilename = donorFileName;
  1912. getEnclosingClass().addInlinedSourceFileInfo(
  1913. donorFileName,
  1914. adviceMethod.highestLineNumber);
  1915. }
  1916. getEnclosingClass().addMethodGen(localAdviceMethod);
  1917. // create a map that will move all slots in advice method forward by extraParamOffset
  1918. // in order to make room for the new proceed-required arguments that are added at
  1919. // the beginning of the parameter list
  1920. int nVars = adviceMethod.getMaxLocals() + extraParamOffset;
  1921. IntMap varMap = IntMap.idMap(nVars);
  1922. for (int i=extraParamOffset; i < nVars; i++) {
  1923. varMap.put(i-extraParamOffset, i);
  1924. }
  1925. localAdviceMethod.getBody().insert(
  1926. BcelClassWeaver.genInlineInstructions(adviceMethod,
  1927. localAdviceMethod, varMap, fact, true));
  1928. localAdviceMethod.setMaxLocals(nVars);
  1929. //System.err.println(localAdviceMethod);
  1930. // the shadow is now empty. First, create a correct call
  1931. // to the around advice. This includes both the call (which may involve
  1932. // value conversion of the advice arguments) and the return
  1933. // (which may involve value conversion of the return value). Right now
  1934. // we push a null for the unused closure. It's sad, but there it is.
  1935. InstructionList advice = new InstructionList();
  1936. // InstructionHandle adviceMethodInvocation;
  1937. {
  1938. for (Iterator i = argVarList.iterator(); i.hasNext(); ) {
  1939. BcelVar var = (BcelVar)i.next();
  1940. var.appendLoad(advice, fact);
  1941. }
  1942. // ??? we don't actually need to push NULL for the closure if we take care
  1943. advice.append(
  1944. munger.getAdviceArgSetup(
  1945. this,
  1946. null,
  1947. (munger.getConcreteAspect().isAnnotationStyleAspect())?
  1948. this.loadThisJoinPoint():
  1949. new InstructionList(InstructionConstants.ACONST_NULL)));
  1950. // adviceMethodInvocation =
  1951. advice.append(
  1952. Utility.createInvoke(fact, localAdviceMethod)); //(fact, getWorld(), munger.getSignature()));
  1953. advice.append(
  1954. Utility.createConversion(
  1955. getFactory(),
  1956. BcelWorld.makeBcelType(munger.getSignature().getReturnType()),
  1957. extractedMethod.getReturnType()));
  1958. if (! isFallsThrough()) {
  1959. advice.append(InstructionFactory.createReturn(extractedMethod.getReturnType()));
  1960. }
  1961. }
  1962. // now, situate the call inside the possible dynamic tests,
  1963. // and actually add the whole mess to the shadow
  1964. if (! hasDynamicTest) {
  1965. range.append(advice);
  1966. } else {
  1967. InstructionList afterThingie = new InstructionList(InstructionConstants.NOP);
  1968. InstructionList callback = makeCallToCallback(extractedMethod);
  1969. if (terminatesWithReturn()) {
  1970. callback.append(
  1971. InstructionFactory.createReturn(extractedMethod.getReturnType()));
  1972. } else {
  1973. //InstructionHandle endNop = range.insert(fact.NOP, Range.InsideAfter);
  1974. advice.append(
  1975. InstructionFactory.createBranchInstruction(
  1976. Constants.GOTO,
  1977. afterThingie.getStart()));
  1978. }
  1979. range.append(
  1980. munger.getTestInstructions(
  1981. this,
  1982. advice.getStart(),
  1983. callback.getStart(),
  1984. advice.getStart()));
  1985. range.append(advice);
  1986. range.append(callback);
  1987. range.append(afterThingie);
  1988. }
  1989. // now search through the advice, looking for a call to PROCEED.
  1990. // Then we replace the call to proceed with some argument setup, and a
  1991. // call to the extracted method.
  1992. // inlining support for code style aspects
  1993. if (!munger.getConcreteAspect().isAnnotationStyleAspect()) {
  1994. String proceedName =
  1995. NameMangler.proceedMethodName(munger.getSignature().getName());
  1996. InstructionHandle curr = localAdviceMethod.getBody().getStart();
  1997. InstructionHandle end = localAdviceMethod.getBody().getEnd();
  1998. ConstantPoolGen cpg = localAdviceMethod.getEnclosingClass().getConstantPoolGen();
  1999. while (curr != end) {
  2000. InstructionHandle next = curr.getNext();
  2001. Instruction inst = curr.getInstruction();
  2002. if ((inst instanceof INVOKESTATIC)
  2003. && proceedName.equals(((INVOKESTATIC) inst).getMethodName(cpg))) {
  2004. localAdviceMethod.getBody().append(
  2005. curr,
  2006. getRedoneProceedCall(
  2007. fact,
  2008. extractedMethod,
  2009. munger,
  2010. localAdviceMethod,
  2011. proceedVarList));
  2012. Utility.deleteInstruction(curr, localAdviceMethod);
  2013. }
  2014. curr = next;
  2015. }
  2016. // and that's it.
  2017. } else {
  2018. //ATAJ inlining support for @AJ aspects
  2019. // [TODO document @AJ code rule: don't manipulate 2 jps proceed at the same time.. in an advice body]
  2020. InstructionHandle curr = localAdviceMethod.getBody().getStart();
  2021. InstructionHandle end = localAdviceMethod.getBody().getEnd();
  2022. ConstantPoolGen cpg = localAdviceMethod.getEnclosingClass().getConstantPoolGen();
  2023. while (curr != end) {
  2024. InstructionHandle next = curr.getNext();
  2025. Instruction inst = curr.getInstruction();
  2026. if ((inst instanceof INVOKEINTERFACE)
  2027. && "proceed".equals(((INVOKEINTERFACE) inst).getMethodName(cpg))) {
  2028. final boolean isProceedWithArgs;
  2029. if (((INVOKEINTERFACE) inst).getArgumentTypes(cpg).length == 1) {
  2030. // proceed with args as a boxed Object[]
  2031. isProceedWithArgs = true;
  2032. } else {
  2033. isProceedWithArgs = false;
  2034. }
  2035. InstructionList insteadProceedIl = getRedoneProceedCallForAnnotationStyle(
  2036. fact,
  2037. extractedMethod,
  2038. munger,
  2039. localAdviceMethod,
  2040. proceedVarList,
  2041. isProceedWithArgs
  2042. );
  2043. localAdviceMethod.getBody().append(curr, insteadProceedIl);
  2044. Utility.deleteInstruction(curr, localAdviceMethod);
  2045. }
  2046. curr = next;
  2047. }
  2048. }
  2049. }
  2050. private InstructionList getRedoneProceedCall(
  2051. InstructionFactory fact,
  2052. LazyMethodGen callbackMethod,
  2053. BcelAdvice munger,
  2054. LazyMethodGen localAdviceMethod,
  2055. List argVarList)
  2056. {
  2057. InstructionList ret = new InstructionList();
  2058. // we have on stack all the arguments for the ADVICE call.
  2059. // we have in frame somewhere all the arguments for the non-advice call.
  2060. BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
  2061. IntMap proceedMap = makeProceedArgumentMap(adviceVars);
  2062. // System.out.println(proceedMap + " for " + this);
  2063. // System.out.println(argVarList);
  2064. ResolvedType[] proceedParamTypes =
  2065. world.resolve(munger.getSignature().getParameterTypes());
  2066. // remove this*JoinPoint* as arguments to proceed
  2067. if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) {
  2068. int len = munger.getBaseParameterCount()+1;
  2069. ResolvedType[] newTypes = new ResolvedType[len];
  2070. System.arraycopy(proceedParamTypes, 0, newTypes, 0, len);
  2071. proceedParamTypes = newTypes;
  2072. }
  2073. //System.out.println("stateTypes: " + Arrays.asList(stateTypes));
  2074. BcelVar[] proceedVars =
  2075. Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod);
  2076. Type[] stateTypes = callbackMethod.getArgumentTypes();
  2077. // System.out.println("stateTypes: " + Arrays.asList(stateTypes));
  2078. for (int i=0, len=stateTypes.length; i < len; i++) {
  2079. Type stateType = stateTypes[i];
  2080. ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  2081. if (proceedMap.hasKey(i)) {
  2082. //throw new RuntimeException("unimplemented");
  2083. proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
  2084. } else {
  2085. ((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
  2086. }
  2087. }
  2088. ret.append(Utility.createInvoke(fact, callbackMethod));
  2089. ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
  2090. BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
  2091. return ret;
  2092. }
  2093. /**
  2094. * ATAJ Handle the inlining for @AJ aspects
  2095. *
  2096. * @param fact
  2097. * @param callbackMethod
  2098. * @param munger
  2099. * @param localAdviceMethod
  2100. * @param argVarList
  2101. * @param isProceedWithArgs
  2102. * @return
  2103. */
  2104. private InstructionList getRedoneProceedCallForAnnotationStyle(
  2105. InstructionFactory fact,
  2106. LazyMethodGen callbackMethod,
  2107. BcelAdvice munger,
  2108. LazyMethodGen localAdviceMethod,
  2109. List argVarList,
  2110. boolean isProceedWithArgs)
  2111. {
  2112. // Notes:
  2113. // proceedingjp is on stack (since user was calling pjp.proceed(...)
  2114. // the boxed args to proceed() are on stack as well (Object[]) unless
  2115. // the call is to pjp.proceed(<noarg>)
  2116. // new Object[]{new Integer(argAdvice1-1)};// arg of proceed
  2117. // call to proceed(..) is NOT made
  2118. // instead we do
  2119. // itar callback args i
  2120. // get from array i, convert it to the callback arg i
  2121. // if ask for JP, push the one we got on the stack
  2122. // invoke callback, create conversion back to Object/Integer
  2123. // rest of method -- (hence all those conversions)
  2124. // intValue() from original code
  2125. // int res = .. from original code
  2126. //Note: we just don't care about the proceed map etc
  2127. InstructionList ret = new InstructionList();
  2128. // store the Object[] array on stack if proceed with args
  2129. if (isProceedWithArgs) {
  2130. Type objectArrayType = Type.getType("[Ljava/lang/Object;");
  2131. int localProceedArgArray = localAdviceMethod.allocateLocal(objectArrayType);
  2132. ret.append(InstructionFactory.createStore(objectArrayType, localProceedArgArray));
  2133. Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;");
  2134. int localJp = localAdviceMethod.allocateLocal(proceedingJpType);
  2135. ret.append(InstructionFactory.createStore(proceedingJpType, localJp));
  2136. // push on stack each element of the object array
  2137. // that is assumed to be consistent with the callback argument (ie munger args)
  2138. // TODO do we want to try catch ClassCast and AOOBE exception ?
  2139. // special logic when withincode is static or not
  2140. int startIndex = 0;
  2141. if (thisVar != null) {
  2142. startIndex = 1;
  2143. //TODO this logic is actually depending on target as well - test me
  2144. ret.append(new ALOAD(0));//thisVar
  2145. }
  2146. for (int i = startIndex, len=callbackMethod.getArgumentTypes().length; i < len; i++) {
  2147. Type stateType = callbackMethod.getArgumentTypes()[i];
  2148. ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  2149. if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
  2150. ret.append(new ALOAD(localJp));// from localAdvice signature
  2151. } else {
  2152. ret.append(InstructionFactory.createLoad(objectArrayType, localProceedArgArray));
  2153. ret.append(Utility.createConstant(fact, i-startIndex));
  2154. ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
  2155. ret.append(Utility.createConversion(
  2156. fact,
  2157. Type.OBJECT,
  2158. stateType
  2159. ));
  2160. }
  2161. }
  2162. } else {
  2163. Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;");
  2164. int localJp = localAdviceMethod.allocateLocal(proceedingJpType);
  2165. ret.append(InstructionFactory.createStore(proceedingJpType, localJp));
  2166. for (int i = 0, len=callbackMethod.getArgumentTypes().length; i < len; i++) {
  2167. Type stateType = callbackMethod.getArgumentTypes()[i];
  2168. ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  2169. if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
  2170. ret.append(new ALOAD(localJp));// from localAdvice signature
  2171. // } else if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(stateType.getSignature())) {
  2172. // //FIXME ALEX?
  2173. // ret.append(new ALOAD(localJp));// from localAdvice signature
  2174. //// ret.append(fact.createCheckCast(
  2175. //// (ReferenceType) BcelWorld.makeBcelType(stateTypeX)
  2176. //// ));
  2177. // // cast ?
  2178. //
  2179. } else {
  2180. ret.append(InstructionFactory.createLoad(stateType, i));
  2181. }
  2182. }
  2183. }
  2184. // do the callback invoke
  2185. ret.append(Utility.createInvoke(fact, callbackMethod));
  2186. // box it again. Handles cases where around advice does return something else than Object
  2187. if (!UnresolvedType.OBJECT.equals(munger.getSignature().getReturnType())) {
  2188. ret.append(Utility.createConversion(
  2189. fact,
  2190. callbackMethod.getReturnType(),
  2191. Type.OBJECT
  2192. ));
  2193. }
  2194. ret.append(Utility.createConversion(
  2195. fact,
  2196. callbackMethod.getReturnType(),
  2197. BcelWorld.makeBcelType(munger.getSignature().getReturnType())
  2198. ));
  2199. return ret;
  2200. //
  2201. //
  2202. //
  2203. // if (proceedMap.hasKey(i)) {
  2204. // ret.append(new ALOAD(i));
  2205. // //throw new RuntimeException("unimplemented");
  2206. // //proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
  2207. // } else {
  2208. // //((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
  2209. // //ret.append(new ALOAD(i));
  2210. // if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
  2211. // ret.append(new ALOAD(i));
  2212. // } else {
  2213. // ret.append(new ALOAD(i));
  2214. // }
  2215. // }
  2216. // }
  2217. //
  2218. // ret.append(Utility.createInvoke(fact, callbackMethod));
  2219. // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
  2220. // BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
  2221. //
  2222. // //ret.append(new ACONST_NULL());//will be POPed
  2223. // if (true) return ret;
  2224. //
  2225. //
  2226. //
  2227. // // we have on stack all the arguments for the ADVICE call.
  2228. // // we have in frame somewhere all the arguments for the non-advice call.
  2229. //
  2230. // BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
  2231. // IntMap proceedMap = makeProceedArgumentMap(adviceVars);
  2232. //
  2233. // System.out.println(proceedMap + " for " + this);
  2234. // System.out.println(argVarList);
  2235. //
  2236. // ResolvedType[] proceedParamTypes =
  2237. // world.resolve(munger.getSignature().getParameterTypes());
  2238. // // remove this*JoinPoint* as arguments to proceed
  2239. // if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) {
  2240. // int len = munger.getBaseParameterCount()+1;
  2241. // ResolvedType[] newTypes = new ResolvedType[len];
  2242. // System.arraycopy(proceedParamTypes, 0, newTypes, 0, len);
  2243. // proceedParamTypes = newTypes;
  2244. // }
  2245. //
  2246. // //System.out.println("stateTypes: " + Arrays.asList(stateTypes));
  2247. // BcelVar[] proceedVars =
  2248. // Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod);
  2249. //
  2250. // Type[] stateTypes = callbackMethod.getArgumentTypes();
  2251. //// System.out.println("stateTypes: " + Arrays.asList(stateTypes));
  2252. //
  2253. // for (int i=0, len=stateTypes.length; i < len; i++) {
  2254. // Type stateType = stateTypes[i];
  2255. // ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  2256. // if (proceedMap.hasKey(i)) {
  2257. // //throw new RuntimeException("unimplemented");
  2258. // proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
  2259. // } else {
  2260. // ((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
  2261. // }
  2262. // }
  2263. //
  2264. // ret.append(Utility.createInvoke(fact, callbackMethod));
  2265. // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
  2266. // BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
  2267. // return ret;
  2268. }
  2269. public void weaveAroundClosure(BcelAdvice munger, boolean hasDynamicTest) {
  2270. InstructionFactory fact = getFactory();
  2271. enclosingMethod.setCanInline(false);
  2272. // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD!
  2273. LazyMethodGen callbackMethod =
  2274. extractMethod(
  2275. NameMangler.aroundCallbackMethodName(
  2276. getSignature(),
  2277. getEnclosingClass()),
  2278. 0,
  2279. munger);
  2280. BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
  2281. String closureClassName =
  2282. NameMangler.makeClosureClassName(
  2283. getEnclosingClass().getType(),
  2284. getEnclosingClass().getNewGeneratedNameTag());
  2285. Member constructorSig = new MemberImpl(Member.CONSTRUCTOR,
  2286. UnresolvedType.forName(closureClassName), 0, "<init>",
  2287. "([Ljava/lang/Object;)V");
  2288. BcelVar closureHolder = null;
  2289. // This is not being used currently since getKind() == preinitializaiton
  2290. // cannot happen in around advice
  2291. if (getKind() == PreInitialization) {
  2292. closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE);
  2293. }
  2294. InstructionList closureInstantiation =
  2295. makeClosureInstantiation(constructorSig, closureHolder);
  2296. /*LazyMethodGen constructor = */
  2297. makeClosureClassAndReturnConstructor(
  2298. closureClassName,
  2299. callbackMethod,
  2300. makeProceedArgumentMap(adviceVars)
  2301. );
  2302. InstructionList returnConversionCode;
  2303. if (getKind() == PreInitialization) {
  2304. returnConversionCode = new InstructionList();
  2305. BcelVar stateTempVar = genTempVar(UnresolvedType.OBJECTARRAY);
  2306. closureHolder.appendLoad(returnConversionCode, fact);
  2307. returnConversionCode.append(
  2308. Utility.createInvoke(
  2309. fact,
  2310. world,
  2311. AjcMemberMaker.aroundClosurePreInitializationGetter()));
  2312. stateTempVar.appendStore(returnConversionCode, fact);
  2313. Type[] stateTypes = getSuperConstructorParameterTypes();
  2314. returnConversionCode.append(InstructionConstants.ALOAD_0); // put "this" back on the stack
  2315. for (int i = 0, len = stateTypes.length; i < len; i++) {
  2316. UnresolvedType bcelTX = BcelWorld.fromBcel(stateTypes[i]);
  2317. ResolvedType stateRTX = world.resolve(bcelTX,true);
  2318. if (stateRTX == ResolvedType.MISSING) {
  2319. IMessage msg = new Message(
  2320. WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName()),
  2321. "",IMessage.ERROR,getSourceLocation(),null,
  2322. new ISourceLocation[]{ munger.getSourceLocation()});
  2323. world.getMessageHandler().handleMessage(msg);
  2324. }
  2325. stateTempVar.appendConvertableArrayLoad(
  2326. returnConversionCode,
  2327. fact,
  2328. i,
  2329. stateRTX);
  2330. }
  2331. } else {
  2332. returnConversionCode =
  2333. Utility.createConversion(
  2334. getFactory(),
  2335. BcelWorld.makeBcelType(munger.getSignature().getReturnType()),
  2336. callbackMethod.getReturnType());
  2337. if (!isFallsThrough()) {
  2338. returnConversionCode.append(
  2339. InstructionFactory.createReturn(callbackMethod.getReturnType()));
  2340. }
  2341. }
  2342. // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance
  2343. if (munger.getConcreteAspect()!=null && munger.getConcreteAspect().isAnnotationStyleAspect()) {
  2344. closureInstantiation.append(Utility.createInvoke(
  2345. getFactory(),
  2346. getWorld(),
  2347. new MemberImpl(
  2348. Member.METHOD,
  2349. UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
  2350. Modifier.PUBLIC,
  2351. "linkClosureAndJoinPoint",
  2352. "()Lorg/aspectj/lang/ProceedingJoinPoint;"
  2353. )
  2354. ));
  2355. }
  2356. InstructionList advice = new InstructionList();
  2357. advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation));
  2358. // invoke the advice
  2359. advice.append(munger.getNonTestAdviceInstructions(this));
  2360. advice.append(returnConversionCode);
  2361. if (!hasDynamicTest) {
  2362. range.append(advice);
  2363. } else {
  2364. InstructionList callback = makeCallToCallback(callbackMethod);
  2365. InstructionList postCallback = new InstructionList();
  2366. if (terminatesWithReturn()) {
  2367. callback.append(
  2368. InstructionFactory.createReturn(callbackMethod.getReturnType()));
  2369. } else {
  2370. advice.append(
  2371. InstructionFactory.createBranchInstruction(
  2372. Constants.GOTO,
  2373. postCallback.append(InstructionConstants.NOP)));
  2374. }
  2375. range.append(
  2376. munger.getTestInstructions(
  2377. this,
  2378. advice.getStart(),
  2379. callback.getStart(),
  2380. advice.getStart()));
  2381. range.append(advice);
  2382. range.append(callback);
  2383. range.append(postCallback);
  2384. }
  2385. }
  2386. // exposed for testing
  2387. InstructionList makeCallToCallback(LazyMethodGen callbackMethod) {
  2388. InstructionFactory fact = getFactory();
  2389. InstructionList callback = new InstructionList();
  2390. if (thisVar != null) {
  2391. callback.append(InstructionConstants.ALOAD_0);
  2392. }
  2393. if (targetVar != null && targetVar != thisVar) {
  2394. callback.append(BcelRenderer.renderExpr(fact, world, targetVar));
  2395. }
  2396. callback.append(BcelRenderer.renderExprs(fact, world, argVars));
  2397. // remember to render tjps
  2398. if (thisJoinPointVar != null) {
  2399. callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar));
  2400. }
  2401. callback.append(Utility.createInvoke(fact, callbackMethod));
  2402. return callback;
  2403. }
  2404. /** side-effect-free */
  2405. private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) {
  2406. // LazyMethodGen constructor) {
  2407. InstructionFactory fact = getFactory();
  2408. BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
  2409. //final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  2410. final InstructionList il = new InstructionList();
  2411. int alen = getArgCount() + (thisVar == null ? 0 : 1) +
  2412. ((targetVar != null && targetVar != thisVar) ? 1 : 0) +
  2413. (thisJoinPointVar == null ? 0 : 1);
  2414. il.append(Utility.createConstant(fact, alen));
  2415. il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  2416. arrayVar.appendStore(il, fact);
  2417. int stateIndex = 0;
  2418. if (thisVar != null) {
  2419. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar);
  2420. thisVar.setPositionInAroundState(stateIndex);
  2421. stateIndex++;
  2422. }
  2423. if (targetVar != null && targetVar != thisVar) {
  2424. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar);
  2425. targetVar.setPositionInAroundState(stateIndex);
  2426. stateIndex++;
  2427. }
  2428. for (int i = 0, len = getArgCount(); i<len; i++) {
  2429. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]);
  2430. argVars[i].setPositionInAroundState(stateIndex);
  2431. stateIndex++;
  2432. }
  2433. if (thisJoinPointVar != null) {
  2434. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar);
  2435. thisJoinPointVar.setPositionInAroundState(stateIndex);
  2436. stateIndex++;
  2437. }
  2438. il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName())));
  2439. il.append(new DUP());
  2440. arrayVar.appendLoad(il, fact);
  2441. il.append(Utility.createInvoke(fact, world, constructor));
  2442. if (getKind() == PreInitialization) {
  2443. il.append(InstructionConstants.DUP);
  2444. holder.appendStore(il, fact);
  2445. }
  2446. return il;
  2447. }
  2448. private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) {
  2449. //System.err.println("coming in with " + Arrays.asList(adviceArgs));
  2450. IntMap ret = new IntMap();
  2451. for(int i = 0, len = adviceArgs.length; i < len; i++) {
  2452. BcelVar v = (BcelVar) adviceArgs[i];
  2453. if (v == null) continue; // XXX we don't know why this is required
  2454. int pos = v.getPositionInAroundState();
  2455. if (pos >= 0) { // need this test to avoid args bound via cflow
  2456. ret.put(pos, i);
  2457. }
  2458. }
  2459. //System.err.println("returning " + ret);
  2460. return ret;
  2461. }
  2462. /**
  2463. *
  2464. *
  2465. * @param callbackMethod the method we will call back to when our run method gets called.
  2466. *
  2467. * @param proceedMap A map from state position to proceed argument position. May be
  2468. * non covering on state position.
  2469. */
  2470. private LazyMethodGen makeClosureClassAndReturnConstructor(
  2471. String closureClassName,
  2472. LazyMethodGen callbackMethod,
  2473. IntMap proceedMap)
  2474. {
  2475. String superClassName = "org.aspectj.runtime.internal.AroundClosure";
  2476. Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  2477. LazyClassGen closureClass = new LazyClassGen(closureClassName,
  2478. superClassName,
  2479. getEnclosingClass().getFileName(),
  2480. Modifier.PUBLIC,
  2481. new String[] {},
  2482. getWorld());
  2483. InstructionFactory fact = new InstructionFactory(closureClass.getConstantPoolGen());
  2484. // constructor
  2485. LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC,
  2486. Type.VOID,
  2487. "<init>",
  2488. new Type[] {objectArrayType},
  2489. new String[] {},
  2490. closureClass);
  2491. InstructionList cbody = constructor.getBody();
  2492. cbody.append(InstructionFactory.createLoad(Type.OBJECT, 0));
  2493. cbody.append(InstructionFactory.createLoad(objectArrayType, 1));
  2494. cbody.append(fact.createInvoke(superClassName, "<init>", Type.VOID,
  2495. new Type[] {objectArrayType}, Constants.INVOKESPECIAL));
  2496. cbody.append(InstructionFactory.createReturn(Type.VOID));
  2497. closureClass.addMethodGen(constructor);
  2498. // method
  2499. LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC,
  2500. Type.OBJECT,
  2501. "run",
  2502. new Type[] {objectArrayType},
  2503. new String[] {},
  2504. closureClass);
  2505. InstructionList mbody = runMethod.getBody();
  2506. BcelVar proceedVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), 1);
  2507. // int proceedVarIndex = 1;
  2508. BcelVar stateVar =
  2509. new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1));
  2510. // int stateVarIndex = runMethod.allocateLocal(1);
  2511. mbody.append(InstructionFactory.createThis());
  2512. mbody.append(fact.createGetField(superClassName, "state", objectArrayType));
  2513. mbody.append(stateVar.createStore(fact));
  2514. // mbody.append(fact.createStore(objectArrayType, stateVarIndex));
  2515. Type[] stateTypes = callbackMethod.getArgumentTypes();
  2516. for (int i=0, len=stateTypes.length; i < len; i++) {
  2517. Type stateType = stateTypes[i];
  2518. ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  2519. if (proceedMap.hasKey(i)) {
  2520. mbody.append(
  2521. proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i),
  2522. stateTypeX));
  2523. } else {
  2524. mbody.append(
  2525. stateVar.createConvertableArrayLoad(fact, i,
  2526. stateTypeX));
  2527. }
  2528. }
  2529. mbody.append(Utility.createInvoke(fact, callbackMethod));
  2530. if (getKind() == PreInitialization) {
  2531. mbody.append(Utility.createSet(
  2532. fact,
  2533. AjcMemberMaker.aroundClosurePreInitializationField()));
  2534. mbody.append(InstructionConstants.ACONST_NULL);
  2535. } else {
  2536. mbody.append(
  2537. Utility.createConversion(
  2538. fact,
  2539. callbackMethod.getReturnType(),
  2540. Type.OBJECT));
  2541. }
  2542. mbody.append(InstructionFactory.createReturn(Type.OBJECT));
  2543. closureClass.addMethodGen(runMethod);
  2544. // class
  2545. getEnclosingClass().addGeneratedInner(closureClass);
  2546. return constructor;
  2547. }
  2548. // ---- extraction methods
  2549. public LazyMethodGen extractMethod(String newMethodName, int visibilityModifier, ShadowMunger munger) {
  2550. LazyMethodGen.assertGoodBody(range.getBody(), newMethodName);
  2551. if (!getKind().allowsExtraction()) throw new BCException("Attempt to extract method from a shadow kind that does not support this operation (" + getKind() + ")");
  2552. LazyMethodGen freshMethod = createMethodGen(newMethodName,visibilityModifier);
  2553. // System.err.println("******");
  2554. // System.err.println("ABOUT TO EXTRACT METHOD for" + this);
  2555. // enclosingMethod.print(System.err);
  2556. // System.err.println("INTO");
  2557. // freshMethod.print(System.err);
  2558. // System.err.println("WITH REMAP");
  2559. // System.err.println(makeRemap());
  2560. range.extractInstructionsInto(freshMethod, makeRemap(),
  2561. (getKind() != PreInitialization) &&
  2562. isFallsThrough());
  2563. if (getKind() == PreInitialization) {
  2564. addPreInitializationReturnCode(
  2565. freshMethod,
  2566. getSuperConstructorParameterTypes());
  2567. }
  2568. getEnclosingClass().addMethodGen(freshMethod,munger.getSourceLocation());
  2569. return freshMethod;
  2570. }
  2571. private void addPreInitializationReturnCode(
  2572. LazyMethodGen extractedMethod,
  2573. Type[] superConstructorTypes)
  2574. {
  2575. InstructionList body = extractedMethod.getBody();
  2576. final InstructionFactory fact = getFactory();
  2577. BcelVar arrayVar = new BcelVar(
  2578. world.getCoreType(UnresolvedType.OBJECTARRAY),
  2579. extractedMethod.allocateLocal(1));
  2580. int len = superConstructorTypes.length;
  2581. body.append(Utility.createConstant(fact, len));
  2582. body.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  2583. arrayVar.appendStore(body, fact);
  2584. for (int i = len - 1; i >= 0; i++) {
  2585. // convert thing on top of stack to object
  2586. body.append(
  2587. Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT));
  2588. // push object array
  2589. arrayVar.appendLoad(body, fact);
  2590. // swap
  2591. body.append(InstructionConstants.SWAP);
  2592. // do object array store.
  2593. body.append(Utility.createConstant(fact, i));
  2594. body.append(InstructionConstants.SWAP);
  2595. body.append(InstructionFactory.createArrayStore(Type.OBJECT));
  2596. }
  2597. arrayVar.appendLoad(body, fact);
  2598. body.append(InstructionConstants.ARETURN);
  2599. }
  2600. private Type[] getSuperConstructorParameterTypes() {
  2601. // assert getKind() == PreInitialization
  2602. InstructionHandle superCallHandle = getRange().getEnd().getNext();
  2603. InvokeInstruction superCallInstruction =
  2604. (InvokeInstruction) superCallHandle.getInstruction();
  2605. return superCallInstruction.getArgumentTypes(
  2606. getEnclosingClass().getConstantPoolGen());
  2607. }
  2608. /** make a map from old frame location to new frame location. Any unkeyed frame
  2609. * location picks out a copied local */
  2610. private IntMap makeRemap() {
  2611. IntMap ret = new IntMap(5);
  2612. int reti = 0;
  2613. if (thisVar != null) {
  2614. ret.put(0, reti++); // thisVar guaranteed to be 0
  2615. }
  2616. if (targetVar != null && targetVar != thisVar) {
  2617. ret.put(targetVar.getSlot(), reti++);
  2618. }
  2619. for (int i = 0, len = argVars.length; i < len; i++) {
  2620. ret.put(argVars[i].getSlot(), reti);
  2621. reti += argVars[i].getType().getSize();
  2622. }
  2623. if (thisJoinPointVar != null) {
  2624. ret.put(thisJoinPointVar.getSlot(), reti++);
  2625. }
  2626. // we not only need to put the arguments, we also need to remap their
  2627. // aliases, which we so helpfully put into temps at the beginning of this join
  2628. // point.
  2629. if (! getKind().argsOnStack()) {
  2630. int oldi = 0;
  2631. int newi = 0;
  2632. // if we're passing in a this and we're not argsOnStack we're always
  2633. // passing in a target too
  2634. if (arg0HoldsThis()) { ret.put(0, 0); oldi++; newi+=1; }
  2635. //assert targetVar == thisVar
  2636. for (int i = 0; i < getArgCount(); i++) {
  2637. UnresolvedType type = getArgType(i);
  2638. ret.put(oldi, newi);
  2639. oldi += type.getSize();
  2640. newi += type.getSize();
  2641. }
  2642. }
  2643. // System.err.println("making remap for : " + this);
  2644. // if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot());
  2645. // if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot());
  2646. // System.err.println(ret);
  2647. return ret;
  2648. }
  2649. /**
  2650. * The new method always static.
  2651. * It may take some extra arguments: this, target.
  2652. * If it's argsOnStack, then it must take both this/target
  2653. * If it's argsOnFrame, it shares this and target.
  2654. * ??? rewrite this to do less array munging, please
  2655. */
  2656. private LazyMethodGen createMethodGen(String newMethodName, int visibilityModifier) {
  2657. Type[] parameterTypes = BcelWorld.makeBcelTypes(getArgTypes());
  2658. int modifiers = Modifier.FINAL | visibilityModifier;
  2659. // XXX some bug
  2660. // if (! isExpressionKind() && getSignature().isStrict(world)) {
  2661. // modifiers |= Modifier.STRICT;
  2662. // }
  2663. modifiers |= Modifier.STATIC;
  2664. if (targetVar != null && targetVar != thisVar) {
  2665. UnresolvedType targetType = getTargetType();
  2666. targetType = ensureTargetTypeIsCorrect(targetType);
  2667. // see pr109728 - this fixes the case when the declaring class is sometype 'X' but the getfield
  2668. // in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally
  2669. // mentioned in the fieldget instruction as the method parameter and *not* the type upon which the
  2670. // field is declared because when the instructions are extracted into the new around body,
  2671. // they will still refer to the subtype.
  2672. if (getKind()==FieldGet && getActualTargetType()!=null &&
  2673. !getActualTargetType().equals(targetType.getName())) {
  2674. targetType = UnresolvedType.forName(getActualTargetType()).resolve(world);
  2675. }
  2676. ResolvedMember resolvedMember = getSignature().resolve(world);
  2677. if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) &&
  2678. !samePackage(targetType.getPackageName(), getEnclosingType().getPackageName()) &&
  2679. !resolvedMember.getName().equals("clone"))
  2680. {
  2681. if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) {
  2682. throw new BCException("bad bytecode");
  2683. }
  2684. targetType = getThisType();
  2685. }
  2686. parameterTypes = addType(BcelWorld.makeBcelType(targetType), parameterTypes);
  2687. }
  2688. if (thisVar != null) {
  2689. UnresolvedType thisType = getThisType();
  2690. parameterTypes = addType(BcelWorld.makeBcelType(thisType), parameterTypes);
  2691. }
  2692. // We always want to pass down thisJoinPoint in case we have already woven
  2693. // some advice in here. If we only have a single piece of around advice on a
  2694. // join point, it is unnecessary to accept (and pass) tjp.
  2695. if (thisJoinPointVar != null) {
  2696. parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes);
  2697. //FIXME ALEX? which one
  2698. //parameterTypes = addTypeToEnd(LazyClassGen.proceedingTjpType, parameterTypes);
  2699. }
  2700. UnresolvedType returnType;
  2701. if (getKind() == PreInitialization) {
  2702. returnType = UnresolvedType.OBJECTARRAY;
  2703. } else {
  2704. returnType = getReturnType();
  2705. }
  2706. return
  2707. new LazyMethodGen(
  2708. modifiers,
  2709. BcelWorld.makeBcelType(returnType),
  2710. newMethodName,
  2711. parameterTypes,
  2712. new String[0],
  2713. // XXX again, we need to look up methods!
  2714. // UnresolvedType.getNames(getSignature().getExceptions(world)),
  2715. getEnclosingClass());
  2716. }
  2717. private boolean samePackage(String p1, String p2) {
  2718. if (p1 == null) return p2 == null;
  2719. if (p2 == null) return false;
  2720. return p1.equals(p2);
  2721. }
  2722. private Type[] addType(Type type, Type[] types) {
  2723. int len = types.length;
  2724. Type[] ret = new Type[len+1];
  2725. ret[0] = type;
  2726. System.arraycopy(types, 0, ret, 1, len);
  2727. return ret;
  2728. }
  2729. private Type[] addTypeToEnd(Type type, Type[] types) {
  2730. int len = types.length;
  2731. Type[] ret = new Type[len+1];
  2732. ret[len] = type;
  2733. System.arraycopy(types, 0, ret, 0, len);
  2734. return ret;
  2735. }
  2736. public BcelVar genTempVar(UnresolvedType typeX) {
  2737. return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize()));
  2738. }
  2739. // public static final boolean CREATE_TEMP_NAMES = true;
  2740. public BcelVar genTempVar(UnresolvedType typeX, String localName) {
  2741. BcelVar tv = genTempVar(typeX);
  2742. // if (CREATE_TEMP_NAMES) {
  2743. // for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
  2744. // if (Range.isRangeHandle(ih)) continue;
  2745. // ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot()));
  2746. // }
  2747. // }
  2748. return tv;
  2749. }
  2750. // eh doesn't think we need to garbage collect these (64K is a big number...)
  2751. private int genTempVarIndex(int size) {
  2752. return enclosingMethod.allocateLocal(size);
  2753. }
  2754. public InstructionFactory getFactory() {
  2755. return getEnclosingClass().getFactory();
  2756. }
  2757. public ISourceLocation getSourceLocation() {
  2758. int sourceLine = getSourceLine();
  2759. if (sourceLine == 0 || sourceLine == -1) {
  2760. // Thread.currentThread().dumpStack();
  2761. // System.err.println(this + ": " + range);
  2762. return getEnclosingClass().getType().getSourceLocation();
  2763. } else {
  2764. // For staticinitialization, if we have a nice offset, don't build a new source loc
  2765. if (getKind()==Shadow.StaticInitialization && getEnclosingClass().getType().getSourceLocation().getOffset()!=0) {
  2766. return getEnclosingClass().getType().getSourceLocation();
  2767. } else {
  2768. int offset = 0;
  2769. Kind kind = getKind();
  2770. if ( (kind == MethodExecution) ||
  2771. (kind == ConstructorExecution) ||
  2772. (kind == AdviceExecution) ||
  2773. (kind == StaticInitialization) ||
  2774. (kind == PreInitialization) ||
  2775. (kind == Initialization)) {
  2776. if (getEnclosingMethod().hasDeclaredLineNumberInfo()) {
  2777. offset = getEnclosingMethod().getDeclarationOffset();
  2778. }
  2779. }
  2780. return getEnclosingClass().getType().getSourceContext().makeSourceLocation(sourceLine, offset);
  2781. }
  2782. }
  2783. }
  2784. public Shadow getEnclosingShadow() {
  2785. return enclosingShadow;
  2786. }
  2787. public LazyMethodGen getEnclosingMethod() {
  2788. return enclosingMethod;
  2789. }
  2790. public boolean isFallsThrough() {
  2791. return !terminatesWithReturn(); //fallsThrough;
  2792. }
  2793. public void setActualTargetType(String className) {
  2794. this.actualInstructionTargetType = className;
  2795. }
  2796. public String getActualTargetType() {
  2797. return actualInstructionTargetType;
  2798. }
  2799. }