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

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