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

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