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

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