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

21 years ago
21 years ago
21 years ago
16 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
15 years ago
15 years ago
21 years ago
21 years ago
15 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
13 years ago
13 years ago
21 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
18 years ago
18 years ago
21 years ago
21 years ago
14 years ago
15 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
13 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
12 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
12 years ago
14 years ago
14 years ago
14 years ago
12 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
13 years ago
14 years ago
21 years ago
21 years ago
13 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
14 years ago
14 years ago
14 years ago
21 years ago
21 years ago
21 years ago
14 years ago
21 years ago
21 years ago
21 years ago
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. }