12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425 |
- /* *******************************************************************
- * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
- * All rights reserved.
- * This program and the accompanying materials are made available
- * under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * PARC initial implementation
- * Alexandre Vasseur support for @AJ aspects
- * ******************************************************************/
-
- package org.aspectj.weaver.bcel;
-
- import java.lang.reflect.Modifier;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
-
- import org.aspectj.apache.bcel.Constants;
- import org.aspectj.apache.bcel.classfile.ConstantPool;
- import org.aspectj.apache.bcel.classfile.Field;
- import org.aspectj.apache.bcel.generic.ArrayType;
- import org.aspectj.apache.bcel.generic.FieldInstruction;
- import org.aspectj.apache.bcel.generic.INVOKEINTERFACE;
- import org.aspectj.apache.bcel.generic.Instruction;
- import org.aspectj.apache.bcel.generic.InstructionBranch;
- import org.aspectj.apache.bcel.generic.InstructionConstants;
- import org.aspectj.apache.bcel.generic.InstructionFactory;
- import org.aspectj.apache.bcel.generic.InstructionHandle;
- import org.aspectj.apache.bcel.generic.InstructionLV;
- import org.aspectj.apache.bcel.generic.InstructionList;
- import org.aspectj.apache.bcel.generic.InstructionTargeter;
- import org.aspectj.apache.bcel.generic.InvokeInstruction;
- import org.aspectj.apache.bcel.generic.LineNumberTag;
- import org.aspectj.apache.bcel.generic.LocalVariableTag;
- import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
- import org.aspectj.apache.bcel.generic.ObjectType;
- import org.aspectj.apache.bcel.generic.TargetLostException;
- import org.aspectj.apache.bcel.generic.Type;
- import org.aspectj.bridge.ISourceLocation;
- import org.aspectj.weaver.Advice;
- import org.aspectj.weaver.AdviceKind;
- import org.aspectj.weaver.AjcMemberMaker;
- import org.aspectj.weaver.BCException;
- import org.aspectj.weaver.ConcreteTypeMunger;
- import org.aspectj.weaver.IntMap;
- import org.aspectj.weaver.Member;
- import org.aspectj.weaver.MemberImpl;
- import org.aspectj.weaver.NameMangler;
- import org.aspectj.weaver.NewConstructorTypeMunger;
- import org.aspectj.weaver.NewFieldTypeMunger;
- import org.aspectj.weaver.NewMethodTypeMunger;
- import org.aspectj.weaver.ResolvedMember;
- import org.aspectj.weaver.ResolvedMemberImpl;
- import org.aspectj.weaver.ResolvedType;
- import org.aspectj.weaver.Shadow;
- import org.aspectj.weaver.ShadowMunger;
- import org.aspectj.weaver.UnresolvedType;
- import org.aspectj.weaver.WeaverMessages;
- import org.aspectj.weaver.World;
- import org.aspectj.weaver.ast.Var;
- import org.aspectj.weaver.patterns.AbstractPatternNodeVisitor;
- import org.aspectj.weaver.patterns.AndPointcut;
- import org.aspectj.weaver.patterns.NotPointcut;
- import org.aspectj.weaver.patterns.OrPointcut;
- import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
-
- /*
- * Some fun implementation stuff:
- *
- * * expressionKind advice is non-execution advice
- * * may have a target.
- * * if the body is extracted, it will be extracted into
- * a static method. The first argument to the static
- * method is the target
- * * advice may expose a this object, but that's the advice's
- * consideration, not ours. This object will NOT be cached in another
- * local, but will always come from frame zero.
- *
- * * non-expressionKind advice is execution advice
- * * may have a this.
- * * target is same as this, and is exposed that way to advice
- * (i.e., target will not be cached, will always come from frame zero)
- * * if the body is extracted, it will be extracted into a method
- * with same static/dynamic modifier as enclosing method. If non-static,
- * target of callback call will be this.
- *
- * * because of these two facts, the setup of the actual arguments (including
- * possible target) callback method is the same for both kinds of advice:
- * push the targetVar, if it exists (it will not exist for advice on static
- * things), then push all the argVars.
- *
- * Protected things:
- *
- * * the above is sufficient for non-expressionKind advice for protected things,
- * since the target will always be this.
- *
- * * For expressionKind things, we have to modify the signature of the callback
- * method slightly. For non-static expressionKind things, we modify
- * the first argument of the callback method NOT to be the type specified
- * by the method/field signature (the owner), but rather we type it to
- * the currentlyEnclosing type. We are guaranteed this will be fine,
- * since the verifier verifies that the target is a subtype of the currently
- * enclosingType.
- *
- * Worries:
- *
- * * ConstructorCalls will be weirder than all of these, since they
- * supposedly don't have a target (according to AspectJ), but they clearly
- * do have a target of sorts, just one that needs to be pushed on the stack,
- * dupped, and not touched otherwise until the constructor runs.
- *
- * @author Jim Hugunin
- * @author Erik Hilsdale
- *
- */
-
- public class BcelShadow extends Shadow {
-
- private static final String[] NoDeclaredExceptions = new String[0];
-
- private ShadowRange range;
- private final BcelWorld world;
- private final LazyMethodGen enclosingMethod;
-
- // TESTING this will tell us if the optimisation succeeded *on the last shadow processed*
- public static boolean appliedLazyTjpOptimization;
-
- // Some instructions have a target type that will vary
- // from the signature (pr109728) (1.4 declaring type issue)
- private String actualInstructionTargetType;
-
- /**
- * This generates an unassociated shadow, rooted in a particular method but not rooted to any particular point in the code. It
- * should be given to a rooted ShadowRange in the {@link ShadowRange#associateWithShadow(BcelShadow)} method.
- */
- public BcelShadow(BcelWorld world, Kind kind, Member signature, LazyMethodGen enclosingMethod, BcelShadow enclosingShadow) {
- super(kind, signature, enclosingShadow);
- this.world = world;
- this.enclosingMethod = enclosingMethod;
- }
-
- // ---- copies all state, including Shadow's mungers...
-
- public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) {
- BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing);
- if (mungers.size() > 0) {
- List<ShadowMunger> src = mungers;
- if (s.mungers == Collections.EMPTY_LIST) {
- s.mungers = new ArrayList<ShadowMunger>();
- }
- List<ShadowMunger> dest = s.mungers;
- for (Iterator<ShadowMunger> i = src.iterator(); i.hasNext();) {
- dest.add(i.next());
- }
- }
- return s;
- }
-
- // ---- overridden behaviour
-
- @Override
- public World getIWorld() {
- return world;
- }
-
- // see comment in deleteNewAndDup
- // } else if (inst.opcode == Constants.DUP_X2) {
- // // This code seen in the wild (by Brad):
- // // 40: new #12; //class java/lang/StringBuffer
- // // STACK: STRINGBUFFER
- // // 43: dup
- // // STACK: STRINGBUFFER/STRINGBUFFER
- // // 44: aload_0
- // // STACK: STRINGBUFFER/STRINGBUFFER/THIS
- // // 45: dup_x2
- // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/THIS
- // // 46: getfield #36; //Field value:Ljava/lang/String;
- // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING<value>
- // // 49: invokestatic #37; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
- // // STACK: THIS/STRINGBUFFER/STRINGBUFFER/STRING
- // // 52: invokespecial #19; //Method java/lang/StringBuffer."<init>":(Ljava/lang/String;)V
- // // STACK: THIS/STRINGBUFFER
- // // 55: aload_1
- // // STACK: THIS/STRINGBUFFER/LOCAL1
- // // 56: invokevirtual #22; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
- // // STACK: THIS/STRINGBUFFER
- // // 59: invokevirtual #34; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
- // // STACK: THIS/STRING
- // // 62: putfield #36; //Field value:Ljava/lang/String;
- // // STACK: <empty>
- // // 65: return
- //
- // // if we attempt to match on the ctor call to StringBuffer.<init> then we get into trouble.
- // // if we simply delete the new/dup pair without fixing up the dup_x2 then the dup_x2 will fail due to there
- // // not being 3 elements on the stack for it to work with. The fix *in this situation* is to change it to
- // // a simple 'dup'
- //
- // // this fix is *not* very clean - but a general purpose decent solution will take much longer and this
- // // bytecode sequence has only been seen once in the wild.
- // ih.setInstruction(InstructionConstants.DUP);
-
- /**
- * The new/dup (or new/dup_x1/swap) are removed and will be readded later (after the advice call) by the caller of this method.
- * The groovy compiler produces unusual code where the new/dup isn't visible (when making a this() call from an existing ctor),
- * an aload_0 is used to load the uninitialized object (as an example see the ctors in grails.util.BuildSettings).
- *
- * @return true if managed to remove them
- */
- private boolean deleteNewAndDup() {
- final ConstantPool cpool = getEnclosingClass().getConstantPool();
- int depth = 1;
- InstructionHandle ih = range.getStart();
-
- // Go back from where we are looking for 'NEW' that takes us to a stack depth of 0. INVOKESPECIAL <init>
- while (ih != null) {
- Instruction inst = ih.getInstruction();
- if (inst.opcode == Constants.INVOKESPECIAL && ((InvokeInstruction) inst).getName(cpool).equals("<init>")) {
- depth++;
- } else if (inst.opcode == Constants.NEW) {
- depth--;
- if (depth == 0) {
- break;
- }
- // need a testcase to show this can really happen in a modern compiler - removed due to 315398 - moved this out to
- // comment proceeding this method:
-
- }
- ih = ih.getPrev();
- }
- if (ih == null) {
- return false;
- }
- // now IH points to the NEW. We're followed by the DUP, and that is followed
- // by the actual instruction we care about.
- InstructionHandle newHandle = ih;
- InstructionHandle endHandle = newHandle.getNext();
- InstructionHandle nextHandle;
- if (endHandle.getInstruction().opcode == Constants.DUP) {
- nextHandle = endHandle.getNext();
- retargetFrom(newHandle, nextHandle);
- retargetFrom(endHandle, nextHandle);
- } else if (endHandle.getInstruction().opcode == Constants.DUP_X1) {
- InstructionHandle dupHandle = endHandle;
- endHandle = endHandle.getNext();
- nextHandle = endHandle.getNext();
- boolean skipEndRepositioning = false;
- if (endHandle.getInstruction().opcode == Constants.SWAP) {
- } else if (endHandle.getInstruction().opcode == Constants.IMPDEP1) {
- skipEndRepositioning = true; // pr186884
- } else {
- // XXX see next XXX comment
- throw new RuntimeException("Unhandled kind of new " + endHandle);
- }
- // Now make any jumps to the 'new', the 'dup' or the 'end' now target the nextHandle
- retargetFrom(newHandle, nextHandle);
- retargetFrom(dupHandle, nextHandle);
- if (!skipEndRepositioning) {
- retargetFrom(endHandle, nextHandle);
- }
- } else {
- endHandle = newHandle;
- nextHandle = endHandle.getNext();
- retargetFrom(newHandle, nextHandle);
- // add a POP here... we found a NEW w/o a dup or anything else, so
- // we must be in statement context.
- getRange().insert(InstructionConstants.POP, Range.OutsideAfter);
- }
- // assert (dupHandle.getInstruction() instanceof DUP);
-
- try {
- range.getBody().delete(newHandle, endHandle);
- } catch (TargetLostException e) {
- throw new BCException("shouldn't happen");
- }
- return true;
- }
-
- private void retargetFrom(InstructionHandle old, InstructionHandle fresh) {
- for (InstructionTargeter targeter : old.getTargetersCopy()) {
- if (targeter instanceof ExceptionRange) {
- ExceptionRange it = (ExceptionRange) targeter;
- it.updateTarget(old, fresh, it.getBody());
- } else {
- targeter.updateTarget(old, fresh);
- }
- }
- }
-
- // records advice that is stopping us doing the lazyTjp optimization
- private List<BcelAdvice> badAdvice = null;
-
- public void addAdvicePreventingLazyTjp(BcelAdvice advice) {
- if (badAdvice == null) {
- badAdvice = new ArrayList<BcelAdvice>();
- }
- badAdvice.add(advice);
- }
-
- @Override
- protected void prepareForMungers() {
- // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap,
- // and store all our arguments on the frame.
-
- // ??? This is a bit of a hack (for the Java langauge). We do this because
- // we sometime add code "outsideBefore" when dealing with weaving join points. We only
- // do this for exposing state that is on the stack. It turns out to just work for
- // everything except for constructor calls and exception handlers. If we were to clean
- // this up, every ShadowRange would have three instructionHandle points, the start of
- // the arg-setup code, the start of the running code, and the end of the running code.
- boolean deletedNewAndDup = true;
- if (getKind() == ConstructorCall) {
- if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) {
- deletedNewAndDup = deleteNewAndDup(); // no new/dup for new array construction
- }
- initializeArgVars();
- } else if (getKind() == PreInitialization) { // pr74952
- ShadowRange range = getRange();
- range.insert(InstructionConstants.NOP, Range.InsideAfter);
- } else if (getKind() == ExceptionHandler) {
-
- ShadowRange range = getRange();
- InstructionList body = range.getBody();
- InstructionHandle start = range.getStart();
-
- // Create a store instruction to put the value from the top of the
- // stack into a local variable slot. This is a trimmed version of
- // what is in initializeArgVars() (since there is only one argument
- // at a handler jp and only before advice is supported) (pr46298)
- argVars = new BcelVar[1];
- // int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0);
- UnresolvedType tx = getArgType(0);
- argVars[0] = genTempVar(tx, "ajc$arg0");
- InstructionHandle insertedInstruction = range.insert(argVars[0].createStore(getFactory()), Range.OutsideBefore);
-
- // Now the exception range starts just after our new instruction.
- // The next bit of code changes the exception range to point at
- // the store instruction
- for (InstructionTargeter t : start.getTargetersCopy()) {
- if (t instanceof ExceptionRange) {
- ExceptionRange er = (ExceptionRange) t;
- er.updateTarget(start, insertedInstruction, body);
- }
- }
- }
-
- // now we ask each munger to request our state
- isThisJoinPointLazy = true;// world.isXlazyTjp(); // lazy is default now
-
- badAdvice = null;
- for (ShadowMunger munger : mungers) {
- munger.specializeOn(this);
- }
-
- initializeThisJoinPoint();
-
- if (thisJoinPointVar != null && !isThisJoinPointLazy && badAdvice != null && badAdvice.size() > 1) {
- // something stopped us making it a lazy tjp
- // can't build tjp lazily, no suitable test...
- int valid = 0;
- for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) {
- BcelAdvice element = iter.next();
- ISourceLocation sLoc = element.getSourceLocation();
- if (sLoc != null && sLoc.getLine() > 0) {
- valid++;
- }
- }
- if (valid != 0) {
- ISourceLocation[] badLocs = new ISourceLocation[valid];
- int i = 0;
- for (Iterator<BcelAdvice> iter = badAdvice.iterator(); iter.hasNext();) {
- BcelAdvice element = iter.next();
- ISourceLocation sLoc = element.getSourceLocation();
- if (sLoc != null) {
- badLocs[i++] = sLoc;
- }
- }
- world.getLint().multipleAdviceStoppingLazyTjp
- .signal(new String[] { this.toString() }, getSourceLocation(), badLocs);
- }
- }
- badAdvice = null;
-
- // If we are an expression kind, we require our target/arguments on the stack
- // before we do our actual thing. However, they may have been removed
- // from the stack as the shadowMungers have requested state.
- // if any of our shadowMungers requested either the arguments or target,
- // the munger will have added code
- // to pop the target/arguments into temporary variables, represented by
- // targetVar and argVars. In such a case, we must make sure to re-push the
- // values.
-
- // If we are nonExpressionKind, we don't expect arguments on the stack
- // so this is moot. If our argVars happen to be null, then we know that
- // no ShadowMunger has squirrelled away our arguments, so they're still
- // on the stack.
- InstructionFactory fact = getFactory();
- if (getKind().argsOnStack() && argVars != null) {
-
- // Special case first (pr46298). If we are an exception handler and the instruction
- // just after the shadow is a POP then we should remove the pop. The code
- // above which generated the store instruction has already cleared the stack.
- // We also don't generate any code for the arguments in this case as it would be
- // an incorrect aload.
- if (getKind() == ExceptionHandler && range.getEnd().getNext().getInstruction().equals(InstructionConstants.POP)) {
- // easier than deleting it ...
- range.getEnd().getNext().setInstruction(InstructionConstants.NOP);
- } else {
- range.insert(BcelRenderer.renderExprs(fact, world, argVars), Range.InsideBefore);
- if (targetVar != null) {
- range.insert(BcelRenderer.renderExpr(fact, world, targetVar), Range.InsideBefore);
- }
- if (getKind() == ConstructorCall) {
- if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray()) {
- if (deletedNewAndDup) { // if didnt delete them, dont insert any!
- range.insert(InstructionFactory.createDup(1), Range.InsideBefore);
- range.insert(fact.createNew((ObjectType) BcelWorld.makeBcelType(getSignature().getDeclaringType())),
- Range.InsideBefore);
- }
- }
- }
- }
- }
- }
-
- // ---- getters
-
- public ShadowRange getRange() {
- return range;
- }
-
- public void setRange(ShadowRange range) {
- this.range = range;
- }
-
- private int sourceline = -1;
-
- public int getSourceLine() {
- // if the kind of join point for which we are a shadow represents
- // a method or constructor execution, then the best source line is
- // the one from the enclosingMethod declarationLineNumber if available.
- if (sourceline != -1) {
- return sourceline;
- }
- Kind kind = getKind();
- if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution)
- || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) {
- if (getEnclosingMethod().hasDeclaredLineNumberInfo()) {
- sourceline = getEnclosingMethod().getDeclarationLineNumber();
- return sourceline;
- }
- }
-
- if (range == null) {
- if (getEnclosingMethod().hasBody()) {
- sourceline = Utility.getSourceLine(getEnclosingMethod().getBody().getStart());
- return sourceline;
- } else {
- sourceline = 0;
- return sourceline;
- }
- }
- sourceline = Utility.getSourceLine(range.getStart());
- if (sourceline < 0) {
- sourceline = 0;
- }
- return sourceline;
- }
-
- @Override
- public ResolvedType getEnclosingType() {
- return getEnclosingClass().getType();
- }
-
- public LazyClassGen getEnclosingClass() {
- return enclosingMethod.getEnclosingClass();
- }
-
- public BcelWorld getWorld() {
- return world;
- }
-
- // ---- factory methods
-
- public static BcelShadow makeConstructorExecution(BcelWorld world, LazyMethodGen enclosingMethod,
- InstructionHandle justBeforeStart) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, ConstructorExecution, world.makeJoinPointSignatureFromMethod(enclosingMethod,
- Member.CONSTRUCTOR), enclosingMethod, null);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, justBeforeStart.getNext()), Range.genEnd(body));
- return s;
- }
-
- public static BcelShadow makeStaticInitialization(BcelWorld world, LazyMethodGen enclosingMethod) {
- InstructionList body = enclosingMethod.getBody();
- // move the start past ajc$preClinit
- InstructionHandle clinitStart = body.getStart();
- if (clinitStart.getInstruction() instanceof InvokeInstruction) {
- InvokeInstruction ii = (InvokeInstruction) clinitStart.getInstruction();
- if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_PRE_CLINIT_NAME)) {
- clinitStart = clinitStart.getNext();
- }
- }
-
- InstructionHandle clinitEnd = body.getEnd();
-
- // XXX should move the end before the postClinit, but the return is then tricky...
- // if (clinitEnd.getInstruction() instanceof InvokeInstruction) {
- // InvokeInstruction ii = (InvokeInstruction)clinitEnd.getInstruction();
- // if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPool()).equals(NameMangler.AJC_POST_CLINIT_NAME)) {
- // clinitEnd = clinitEnd.getPrev();
- // }
- // }
-
- BcelShadow s = new BcelShadow(world, StaticInitialization, world.makeJoinPointSignatureFromMethod(enclosingMethod,
- Member.STATIC_INITIALIZATION), enclosingMethod, null);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, clinitStart), Range.genEnd(body, clinitEnd));
- return s;
- }
-
- /**
- * Make the shadow for an exception handler. Currently makes an empty shadow that only allows before advice to be woven into it.
- */
-
- public static BcelShadow makeExceptionHandler(BcelWorld world, ExceptionRange exceptionRange, LazyMethodGen enclosingMethod,
- InstructionHandle startOfHandler, BcelShadow enclosingShadow) {
- InstructionList body = enclosingMethod.getBody();
- UnresolvedType catchType = exceptionRange.getCatchType();
- UnresolvedType inType = enclosingMethod.getEnclosingClass().getType();
-
- ResolvedMemberImpl sig = MemberImpl.makeExceptionHandlerSignature(inType, catchType);
- sig.setParameterNames(new String[] { findHandlerParamName(startOfHandler) });
-
- BcelShadow s = new BcelShadow(world, ExceptionHandler, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- InstructionHandle start = Range.genStart(body, startOfHandler);
- InstructionHandle end = Range.genEnd(body, start);
-
- r.associateWithTargets(start, end);
- exceptionRange.updateTarget(startOfHandler, start, body);
- return s;
- }
-
- private static String findHandlerParamName(InstructionHandle startOfHandler) {
- if (startOfHandler.getInstruction().isStoreInstruction() && startOfHandler.getNext() != null) {
- int slot = startOfHandler.getInstruction().getIndex();
- // System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index);
- Iterator<InstructionTargeter> tIter = startOfHandler.getNext().getTargeters().iterator();
- while (tIter.hasNext()) {
- InstructionTargeter targeter = tIter.next();
- if (targeter instanceof LocalVariableTag) {
- LocalVariableTag t = (LocalVariableTag) targeter;
- if (t.getSlot() == slot) {
- return t.getName();
- }
- }
- }
- }
-
- return "<missing>";
- }
-
- /** create an init join point associated w/ an interface in the body of a constructor */
-
- public static BcelShadow makeIfaceInitialization(BcelWorld world, LazyMethodGen constructor,
- Member interfaceConstructorSignature) {
- // this call marks the instruction list as changed
- constructor.getBody();
- // UnresolvedType inType = constructor.getEnclosingClass().getType();
- BcelShadow s = new BcelShadow(world, Initialization, interfaceConstructorSignature, constructor, null);
- // s.fallsThrough = true;
- // ShadowRange r = new ShadowRange(body);
- // r.associateWithShadow(s);
- // InstructionHandle start = Range.genStart(body, handle);
- // InstructionHandle end = Range.genEnd(body, handle);
- //
- // r.associateWithTargets(start, end);
- return s;
- }
-
- public void initIfaceInitializer(InstructionHandle end) {
- final InstructionList body = enclosingMethod.getBody();
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(this);
- InstructionHandle nop = body.insert(end, InstructionConstants.NOP);
-
- r.associateWithTargets(Range.genStart(body, nop), Range.genEnd(body, nop));
- }
-
- // public static BcelShadow makeIfaceConstructorExecution(
- // BcelWorld world,
- // LazyMethodGen constructor,
- // InstructionHandle next,
- // Member interfaceConstructorSignature)
- // {
- // // final InstructionFactory fact = constructor.getEnclosingClass().getFactory();
- // InstructionList body = constructor.getBody();
- // // UnresolvedType inType = constructor.getEnclosingClass().getType();
- // BcelShadow s =
- // new BcelShadow(
- // world,
- // ConstructorExecution,
- // interfaceConstructorSignature,
- // constructor,
- // null);
- // s.fallsThrough = true;
- // ShadowRange r = new ShadowRange(body);
- // r.associateWithShadow(s);
- // // ??? this may or may not work
- // InstructionHandle start = Range.genStart(body, next);
- // //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP));
- // InstructionHandle end = Range.genStart(body, next);
- // //body.append(start, fact.NOP);
- //
- // r.associateWithTargets(start, end);
- // return s;
- // }
-
- /**
- * Create an initialization join point associated with a constructor, but not with any body of code yet. If this is actually
- * matched, it's range will be set when we inline self constructors.
- *
- * @param constructor The constructor starting this initialization.
- */
- public static BcelShadow makeUnfinishedInitialization(BcelWorld world, LazyMethodGen constructor) {
- BcelShadow ret = new BcelShadow(world, Initialization, world.makeJoinPointSignatureFromMethod(constructor,
- Member.CONSTRUCTOR), constructor, null);
- if (constructor.getEffectiveSignature() != null) {
- ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature());
- }
- return ret;
- }
-
- public static BcelShadow makeUnfinishedPreinitialization(BcelWorld world, LazyMethodGen constructor) {
- BcelShadow ret = new BcelShadow(world, PreInitialization, world.makeJoinPointSignatureFromMethod(constructor,
- Member.CONSTRUCTOR), constructor, null);
- if (constructor.getEffectiveSignature() != null) {
- ret.setMatchingSignature(constructor.getEffectiveSignature().getEffectiveSignature());
- }
- return ret;
- }
-
- public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod, boolean lazyInit) {
- if (!lazyInit) {
- return makeMethodExecution(world, enclosingMethod);
- }
-
- BcelShadow s = new BcelShadow(world, MethodExecution, enclosingMethod.getMemberView(), enclosingMethod, null);
-
- return s;
- }
-
- public void init() {
- if (range != null) {
- return;
- }
-
- final InstructionList body = enclosingMethod.getBody();
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(this);
- r.associateWithTargets(Range.genStart(body), Range.genEnd(body));
- }
-
- public static BcelShadow makeMethodExecution(BcelWorld world, LazyMethodGen enclosingMethod) {
- return makeShadowForMethod(world, enclosingMethod, MethodExecution, enclosingMethod.getMemberView());
- }
-
- public static BcelShadow makeShadowForMethod(BcelWorld world, LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, null);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(// OPTIMIZE this occurs lots of times for all jp kinds...
- Range.genStart(body), Range.genEnd(body));
- return s;
- }
-
- public static BcelShadow makeAdviceExecution(BcelWorld world, LazyMethodGen enclosingMethod) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, AdviceExecution,
- world.makeJoinPointSignatureFromMethod(enclosingMethod, Member.ADVICE), enclosingMethod, null);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body), Range.genEnd(body));
- return s;
- }
-
- // constructor call shadows are <em>initially</em> just around the
- // call to the constructor. If ANY advice gets put on it, we move
- // the NEW instruction inside the join point, which involves putting
- // all the arguments in temps.
- public static BcelShadow makeConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle,
- BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
-
- Member sig = world.makeJoinPointSignatureForMethodInvocation(enclosingMethod.getEnclosingClass(),
- (InvokeInstruction) callHandle.getInstruction());
-
- BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle));
- retargetAllBranches(callHandle, r.getStart());
- return s;
- }
-
- public static BcelShadow makeArrayConstructorCall(BcelWorld world, LazyMethodGen enclosingMethod,
- InstructionHandle arrayInstruction, BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- Member sig = world.makeJoinPointSignatureForArrayConstruction(enclosingMethod.getEnclosingClass(), arrayInstruction);
- BcelShadow s = new BcelShadow(world, ConstructorCall, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, arrayInstruction), Range.genEnd(body, arrayInstruction));
- retargetAllBranches(arrayInstruction, r.getStart());
- return s;
- }
-
- public static BcelShadow makeMonitorEnter(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction,
- BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- Member sig = world.makeJoinPointSignatureForMonitorEnter(enclosingMethod.getEnclosingClass(), monitorInstruction);
- BcelShadow s = new BcelShadow(world, SynchronizationLock, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction));
- retargetAllBranches(monitorInstruction, r.getStart());
- return s;
- }
-
- public static BcelShadow makeMonitorExit(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle monitorInstruction,
- BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- Member sig = world.makeJoinPointSignatureForMonitorExit(enclosingMethod.getEnclosingClass(), monitorInstruction);
- BcelShadow s = new BcelShadow(world, SynchronizationUnlock, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, monitorInstruction), Range.genEnd(body, monitorInstruction));
- retargetAllBranches(monitorInstruction, r.getStart());
- return s;
- }
-
- // see pr77166
- // public static BcelShadow makeArrayLoadCall(
- // BcelWorld world,
- // LazyMethodGen enclosingMethod,
- // InstructionHandle arrayInstruction,
- // BcelShadow enclosingShadow)
- // {
- // final InstructionList body = enclosingMethod.getBody();
- // Member sig = world.makeJoinPointSignatureForArrayLoad(enclosingMethod.getEnclosingClass(),arrayInstruction);
- // BcelShadow s =
- // new BcelShadow(
- // world,
- // MethodCall,
- // sig,
- // enclosingMethod,
- // enclosingShadow);
- // ShadowRange r = new ShadowRange(body);
- // r.associateWithShadow(s);
- // r.associateWithTargets(
- // Range.genStart(body, arrayInstruction),
- // Range.genEnd(body, arrayInstruction));
- // retargetAllBranches(arrayInstruction, r.getStart());
- // return s;
- // }
-
- public static BcelShadow makeMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle,
- BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, MethodCall, world.makeJoinPointSignatureForMethodInvocation(
- enclosingMethod.getEnclosingClass(), (InvokeInstruction) callHandle.getInstruction()), enclosingMethod,
- enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle));
- retargetAllBranches(callHandle, r.getStart());
- return s;
- }
-
- public static BcelShadow makeShadowForMethodCall(BcelWorld world, LazyMethodGen enclosingMethod, InstructionHandle callHandle,
- BcelShadow enclosingShadow, Kind kind, ResolvedMember sig) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, kind, sig, enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, callHandle), Range.genEnd(body, callHandle));
- retargetAllBranches(callHandle, r.getStart());
- return s;
- }
-
- public static BcelShadow makeFieldGet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod,
- InstructionHandle getHandle, BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, FieldGet, field,
- // BcelWorld.makeFieldSignature(
- // enclosingMethod.getEnclosingClass(),
- // (FieldInstruction) getHandle.getInstruction()),
- enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, getHandle), Range.genEnd(body, getHandle));
- retargetAllBranches(getHandle, r.getStart());
- return s;
- }
-
- public static BcelShadow makeFieldSet(BcelWorld world, ResolvedMember field, LazyMethodGen enclosingMethod,
- InstructionHandle setHandle, BcelShadow enclosingShadow) {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s = new BcelShadow(world, FieldSet, field,
- // BcelWorld.makeFieldJoinPointSignature(
- // enclosingMethod.getEnclosingClass(),
- // (FieldInstruction) setHandle.getInstruction()),
- enclosingMethod, enclosingShadow);
- ShadowRange r = new ShadowRange(body);
- r.associateWithShadow(s);
- r.associateWithTargets(Range.genStart(body, setHandle), Range.genEnd(body, setHandle));
- retargetAllBranches(setHandle, r.getStart());
- return s;
- }
-
- public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) {
- for (InstructionTargeter source : from.getTargetersCopy()) {
- if (source instanceof InstructionBranch) {
- source.updateTarget(from, to);
- }
- }
- }
-
- // // ---- type access methods
- // private ObjectType getTargetBcelType() {
- // return (ObjectType) BcelWorld.makeBcelType(getTargetType());
- // }
- // private Type getArgBcelType(int arg) {
- // return BcelWorld.makeBcelType(getArgType(arg));
- // }
-
- // ---- kinding
-
- /**
- * If the end of my range has no real instructions following then my context needs a return at the end.
- */
- public boolean terminatesWithReturn() {
- return getRange().getRealNext() == null;
- }
-
- /**
- * Is arg0 occupied with the value of this
- */
- public boolean arg0HoldsThis() {
- if (getKind().isEnclosingKind()) {
- return !Modifier.isStatic(getSignature().getModifiers());
- } else if (enclosingShadow == null) {
- // XXX this is mostly right
- // this doesn't do the right thing for calls in the pre part of introduced constructors.
- return !enclosingMethod.isStatic();
- } else {
- return ((BcelShadow) enclosingShadow).arg0HoldsThis();
- }
- }
-
- // ---- argument getting methods
-
- private BcelVar thisVar = null;
- private BcelVar targetVar = null;
- private BcelVar[] argVars = null;
- private Map<ResolvedType, AnnotationAccessVar> kindedAnnotationVars = null;
- private Map<ResolvedType, TypeAnnotationAccessVar> thisAnnotationVars = null;
- private Map<ResolvedType, TypeAnnotationAccessVar> targetAnnotationVars = null;
- // private Map/* <UnresolvedType,BcelVar> */[] argAnnotationVars = null;
- private Map<ResolvedType, AnnotationAccessVar> withinAnnotationVars = null;
- private Map<ResolvedType, AnnotationAccessVar> withincodeAnnotationVars = null;
- private boolean allArgVarsInitialized = false;
-
- @Override
- public Var getThisVar() {
- if (!hasThis()) {
- throw new IllegalStateException("no this");
- }
- initializeThisVar();
- return thisVar;
- }
-
- @Override
- public Var getThisAnnotationVar(UnresolvedType forAnnotationType) {
- if (!hasThis()) {
- throw new IllegalStateException("no this");
- }
- initializeThisAnnotationVars(); // FIXME asc Why bother with this if we always return one?
- // Even if we can't find one, we have to return one as we might have this annotation at runtime
- Var v = thisAnnotationVars.get(forAnnotationType);
- if (v == null) {
- v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getThisVar());
- }
- return v;
- }
-
- @Override
- public Var getTargetVar() {
- if (!hasTarget()) {
- throw new IllegalStateException("no target");
- }
- initializeTargetVar();
- return targetVar;
- }
-
- @Override
- public Var getTargetAnnotationVar(UnresolvedType forAnnotationType) {
- if (!hasTarget()) {
- throw new IllegalStateException("no target");
- }
- initializeTargetAnnotationVars(); // FIXME asc why bother with this if we always return one?
- Var v = targetAnnotationVars.get(forAnnotationType);
- // Even if we can't find one, we have to return one as we might have this annotation at runtime
- if (v == null) {
- v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getTargetVar());
- }
- return v;
- }
-
- @Override
- public Var getArgVar(int i) {
- ensureInitializedArgVar(i);
- return argVars[i];
- }
-
- @Override
- public Var getArgAnnotationVar(int i, UnresolvedType forAnnotationType) {
- return new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getArgVar(i));
- // initializeArgAnnotationVars();
- //
- // Var v = (Var) argAnnotationVars[i].get(forAnnotationType);
- // if (v == null) {
- // v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world), (BcelVar) getArgVar(i));
- // }
- // return v;
- }
-
- @Override
- public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) {
- initializeKindedAnnotationVars();
- return kindedAnnotationVars.get(forAnnotationType);
- }
-
- @Override
- public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
- initializeWithinAnnotationVars();
- return withinAnnotationVars.get(forAnnotationType);
- }
-
- @Override
- public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) {
- initializeWithinCodeAnnotationVars();
- return withincodeAnnotationVars.get(forAnnotationType);
- }
-
- // reflective thisJoinPoint support
- private BcelVar thisJoinPointVar = null;
- private boolean isThisJoinPointLazy;
- private int lazyTjpConsumers = 0;
- private BcelVar thisJoinPointStaticPartVar = null;
-
- // private BcelVar thisEnclosingJoinPointStaticPartVar = null;
-
- @Override
- public final Var getThisJoinPointStaticPartVar() {
- return getThisJoinPointStaticPartBcelVar();
- }
-
- @Override
- public final Var getThisEnclosingJoinPointStaticPartVar() {
- return getThisEnclosingJoinPointStaticPartBcelVar();
- }
-
- public void requireThisJoinPoint(boolean hasGuardTest, boolean isAround) {
- if (!isAround) {
- if (!hasGuardTest) {
- isThisJoinPointLazy = false;
- } else {
- lazyTjpConsumers++;
- }
- }
- // if (!hasGuardTest) {
- // isThisJoinPointLazy = false;
- // } else {
- // lazyTjpConsumers++;
- // }
- if (thisJoinPointVar == null) {
- thisJoinPointVar = genTempVar(UnresolvedType.forName("org.aspectj.lang.JoinPoint"));
- }
- }
-
- @Override
- public Var getThisJoinPointVar() {
- requireThisJoinPoint(false, false);
- return thisJoinPointVar;
- }
-
- void initializeThisJoinPoint() {
- if (thisJoinPointVar == null) {
- return;
- }
-
- if (isThisJoinPointLazy) {
- isThisJoinPointLazy = checkLazyTjp();
- }
-
- if (isThisJoinPointLazy) {
- appliedLazyTjpOptimization = true;
- createThisJoinPoint(); // make sure any state needed is initialized, but throw the instructions out
-
- if (lazyTjpConsumers == 1) {
- return; // special case only one lazyTjpUser
- }
-
- InstructionFactory fact = getFactory();
- InstructionList il = new InstructionList();
- il.append(InstructionConstants.ACONST_NULL);
- il.append(thisJoinPointVar.createStore(fact));
- range.insert(il, Range.OutsideBefore);
- } else {
- appliedLazyTjpOptimization = false;
- InstructionFactory fact = getFactory();
- InstructionList il = createThisJoinPoint();
- il.append(thisJoinPointVar.createStore(fact));
- range.insert(il, Range.OutsideBefore);
- }
- }
-
- private boolean checkLazyTjp() {
- // check for around advice
- for (Iterator<ShadowMunger> i = mungers.iterator(); i.hasNext();) {
- ShadowMunger munger = i.next();
- if (munger instanceof Advice) {
- if (((Advice) munger).getKind() == AdviceKind.Around) {
- if (munger.getSourceLocation() != null) { // do we know enough to bother reporting?
- if (world.getLint().canNotImplementLazyTjp.isEnabled()) {
- world.getLint().canNotImplementLazyTjp.signal(new String[] { toString() }, getSourceLocation(),
- new ISourceLocation[] { munger.getSourceLocation() });
- }
- }
- return false;
- }
- }
- }
-
- return true;
- }
-
- InstructionList loadThisJoinPoint() {
- InstructionFactory fact = getFactory();
- InstructionList il = new InstructionList();
-
- if (isThisJoinPointLazy) {
- // If we're lazy, build the join point right here.
- il.append(createThisJoinPoint());
-
- // Does someone else need it? If so, store it for later retrieval
- if (lazyTjpConsumers > 1) {
- il.append(thisJoinPointVar.createStore(fact));
-
- InstructionHandle end = il.append(thisJoinPointVar.createLoad(fact));
-
- il.insert(InstructionFactory.createBranchInstruction(Constants.IFNONNULL, end));
- il.insert(thisJoinPointVar.createLoad(fact));
- }
- } else {
- // If not lazy, its already been built and stored, just retrieve it
- thisJoinPointVar.appendLoad(il, fact);
- }
-
- return il;
- }
-
- InstructionList createThisJoinPoint() {
- InstructionFactory fact = getFactory();
- InstructionList il = new InstructionList();
-
- BcelVar staticPart = getThisJoinPointStaticPartBcelVar();
- staticPart.appendLoad(il, fact);
- if (hasThis()) {
- ((BcelVar) getThisVar()).appendLoad(il, fact);
- } else {
- il.append(InstructionConstants.ACONST_NULL);
- }
- if (hasTarget()) {
- ((BcelVar) getTargetVar()).appendLoad(il, fact);
- } else {
- il.append(InstructionConstants.ACONST_NULL);
- }
-
- switch (getArgCount()) {
- case 0:
- il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] {
- LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC));
- break;
- case 1:
- ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
- il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] {
- LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC));
- break;
- case 2:
- ((BcelVar) getArgVar(0)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
- ((BcelVar) getArgVar(1)).appendLoadAndConvert(il, fact, world.getCoreType(ResolvedType.OBJECT));
- il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] {
- LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, Type.OBJECT, Type.OBJECT }, Constants.INVOKESTATIC));
- break;
- default:
- il.append(makeArgsObjectArray());
- il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", "makeJP", LazyClassGen.tjpType, new Type[] {
- LazyClassGen.staticTjpType, Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1) }, Constants.INVOKESTATIC));
- break;
- }
-
- return il;
- }
-
- public BcelVar getThisJoinPointStaticPartBcelVar() {
- return getThisJoinPointStaticPartBcelVar(false);
- }
-
- @Override
- public BcelVar getThisAspectInstanceVar(ResolvedType aspectType) {
- return new AspectInstanceVar(aspectType);
- }
-
- /**
- * Get the Var for the xxxxJpStaticPart, xxx = this or enclosing
- *
- * @param isEnclosingJp true to have the enclosingJpStaticPart
- * @return
- */
- public BcelVar getThisJoinPointStaticPartBcelVar(final boolean isEnclosingJp) {
- if (thisJoinPointStaticPartVar == null) {
- Field field = getEnclosingClass().getTjpField(this, isEnclosingJp);
- ResolvedType sjpType = null;
- if (world.isTargettingAspectJRuntime12()) { // TAG:SUPPORTING12: We didn't have different jpsp types in 1.2
- sjpType = world.getCoreType(UnresolvedType.JOINPOINT_STATICPART);
- } else {
- sjpType = isEnclosingJp ? world.getCoreType(UnresolvedType.JOINPOINT_ENCLOSINGSTATICPART) : world
- .getCoreType(UnresolvedType.JOINPOINT_STATICPART);
- }
- thisJoinPointStaticPartVar = new BcelFieldRef(sjpType, getEnclosingClass().getClassName(), field.getName());
- // getEnclosingClass().warnOnAddedStaticInitializer(this,munger.getSourceLocation());
- }
- return thisJoinPointStaticPartVar;
- }
-
- /**
- * Get the Var for the enclosingJpStaticPart
- *
- * @return
- */
- public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() {
- if (enclosingShadow == null) {
- // the enclosing of an execution is itself
- return getThisJoinPointStaticPartBcelVar(true);
- } else {
- return ((BcelShadow) enclosingShadow).getThisJoinPointStaticPartBcelVar(true);
- }
- }
-
- // ??? need to better understand all the enclosing variants
- @Override
- public Member getEnclosingCodeSignature() {
- if (getKind().isEnclosingKind()) {
- return getSignature();
- } else if (getKind() == Shadow.PreInitialization) {
- // PreInit doesn't enclose code but its signature
- // is correctly the signature of the ctor.
- return getSignature();
- } else if (enclosingShadow == null) {
- return getEnclosingMethod().getMemberView();
- } else {
- return enclosingShadow.getSignature();
- }
- }
-
- public Member getRealEnclosingCodeSignature() {
- return enclosingMethod.getMemberView();
- }
-
- // public Member getEnclosingCodeSignatureForModel() {
- // if (getKind().isEnclosingKind()) {
- // return getSignature();
- // } else if (getKind() == Shadow.PreInitialization) {
- // // PreInit doesn't enclose code but its signature
- // // is correctly the signature of the ctor.
- // return getSignature();
- // } else if (enclosingShadow == null) {
- // return getEnclosingMethod().getMemberView();
- // } else {
- // if (enclosingShadow.getKind() == Shadow.MethodExecution && enclosingMethod.getEffectiveSignature() != null) {
- //
- // } else {
- // return enclosingShadow.getSignature();
- // }
- // }
- // }
-
- private InstructionList makeArgsObjectArray() {
- InstructionFactory fact = getFactory();
- BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
- final InstructionList il = new InstructionList();
- int alen = getArgCount();
- il.append(Utility.createConstant(fact, alen));
- il.append(fact.createNewArray(Type.OBJECT, (short) 1));
- arrayVar.appendStore(il, fact);
-
- int stateIndex = 0;
- for (int i = 0, len = getArgCount(); i < len; i++) {
- arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar) getArgVar(i));
- stateIndex++;
- }
- arrayVar.appendLoad(il, fact);
- return il;
- }
-
- // ---- initializing var tables
-
- /*
- * initializing this is doesn't do anything, because this is protected from side-effects, so we don't need to copy its location
- */
-
- private void initializeThisVar() {
- if (thisVar != null) {
- return;
- }
- thisVar = new BcelVar(getThisType().resolve(world), 0);
- thisVar.setPositionInAroundState(0);
- }
-
- public void initializeTargetVar() {
- InstructionFactory fact = getFactory();
- if (targetVar != null) {
- return;
- }
- if (getKind().isTargetSameAsThis()) {
- if (hasThis()) {
- initializeThisVar();
- }
- targetVar = thisVar;
- } else {
- initializeArgVars(); // gotta pop off the args before we find the target
- UnresolvedType type = getTargetType();
- type = ensureTargetTypeIsCorrect(type);
- targetVar = genTempVar(type, "ajc$target");
- range.insert(targetVar.createStore(fact), Range.OutsideBefore);
- targetVar.setPositionInAroundState(hasThis() ? 1 : 0);
- }
- }
-
- /*
- * PR 72528 This method double checks the target type under certain conditions. The Java 1.4 compilers seem to take calls to
- * clone methods on array types and create bytecode that looks like clone is being called on Object. If we advise a clone call
- * with around advice we extract the call into a helper method which we can then refer to. Because the type in the bytecode for
- * the call to clone is Object we create a helper method with an Object parameter - this is not correct as we have lost the fact
- * that the actual type is an array type. If we don't do the check below we will create code that fails java verification. This
- * method checks for the peculiar set of conditions and if they are true, it has a sneak peek at the code before the call to see
- * what is on the stack.
- */
- public UnresolvedType ensureTargetTypeIsCorrect(UnresolvedType tx) {
-
- Member msig = getSignature();
- if (msig.getArity() == 0 && getKind() == MethodCall && msig.getName().charAt(0) == 'c' && tx.equals(ResolvedType.OBJECT)
- && msig.getReturnType().equals(ResolvedType.OBJECT) && msig.getName().equals("clone")) {
-
- // Lets go back through the code from the start of the shadow
- InstructionHandle searchPtr = range.getStart().getPrev();
- while (Range.isRangeHandle(searchPtr) || searchPtr.getInstruction().isStoreInstruction()) { // ignore this instruction -
- // it doesnt give us the
- // info we want
- searchPtr = searchPtr.getPrev();
- }
-
- // A load instruction may tell us the real type of what the clone() call is on
- if (searchPtr.getInstruction().isLoadInstruction()) {
- LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr, searchPtr.getInstruction().getIndex());
- if (lvt != null) {
- return UnresolvedType.forSignature(lvt.getType());
- }
- }
- // A field access instruction may tell us the real type of what the clone() call is on
- if (searchPtr.getInstruction() instanceof FieldInstruction) {
- FieldInstruction si = (FieldInstruction) searchPtr.getInstruction();
- Type t = si.getFieldType(getEnclosingClass().getConstantPool());
- return BcelWorld.fromBcel(t);
- }
- // A new array instruction obviously tells us it is an array type !
- if (searchPtr.getInstruction().opcode == Constants.ANEWARRAY) {
- // ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction();
- // Type t = ana.getType(getEnclosingClass().getConstantPool());
- // Just use a standard java.lang.object array - that will work fine
- return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, 1));
- }
- // A multi new array instruction obviously tells us it is an array type !
- if (searchPtr.getInstruction() instanceof MULTIANEWARRAY) {
- MULTIANEWARRAY ana = (MULTIANEWARRAY) searchPtr.getInstruction();
- // Type t = ana.getType(getEnclosingClass().getConstantPool());
- // t = new ArrayType(t,ana.getDimensions());
- // Just use a standard java.lang.object array - that will work fine
- return BcelWorld.fromBcel(new ArrayType(Type.OBJECT, ana.getDimensions()));
- }
- throw new BCException("Can't determine real target of clone() when processing instruction "
- + searchPtr.getInstruction() + ". Perhaps avoid selecting clone with your pointcut?");
- }
- return tx;
- }
-
- public void ensureInitializedArgVar(int argNumber) {
- if (allArgVarsInitialized || (argVars != null && argVars[argNumber] != null)) {
- return;
- }
- InstructionFactory fact = getFactory();
- int len = getArgCount();
- if (argVars == null) {
- argVars = new BcelVar[len];
- }
-
- // Need to initialize argument i
- int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0);
-
- if (getKind().argsOnStack()) {
- // Let's just do them all now since they are on the stack
- // we move backwards because we're popping off the stack
- for (int i = len - 1; i >= 0; i--) {
- UnresolvedType type = getArgType(i);
- BcelVar tmp = genTempVar(type, "ajc$arg" + i);
- range.insert(tmp.createStore(getFactory()), Range.OutsideBefore);
- int position = i;
- position += positionOffset;
- tmp.setPositionInAroundState(position);
- argVars[i] = tmp;
- }
- allArgVarsInitialized = true;
- } else {
- int index = 0;
- if (arg0HoldsThis()) {
- index++;
- }
- boolean allInited = true;
- for (int i = 0; i < len; i++) {
- UnresolvedType type = getArgType(i);
- if (i == argNumber) {
- argVars[argNumber] = genTempVar(type, "ajc$arg" + argNumber);
- range.insert(argVars[argNumber].createCopyFrom(fact, index), Range.OutsideBefore);
- argVars[argNumber].setPositionInAroundState(argNumber + positionOffset);
- }
- allInited = allInited && argVars[i] != null;
- index += type.getSize();
- }
- if (allInited && (argNumber + 1) == len) {
- allArgVarsInitialized = true;
- }
- }
- }
-
- /**
- * Initialize all the available arguments at the shadow. This means creating a copy of them that we can then use for advice
- * calls (the copy ensures we are not affected by other advice changing the values). This method initializes all arguments
- * whereas the method ensureInitializedArgVar will only ensure a single argument is setup.
- */
- public void initializeArgVars() {
- if (allArgVarsInitialized) {
- return;
- }
- InstructionFactory fact = getFactory();
- int len = getArgCount();
- if (argVars == null) {
- argVars = new BcelVar[len];
- }
- int positionOffset = (hasTarget() ? 1 : 0) + ((hasThis() && !getKind().isTargetSameAsThis()) ? 1 : 0);
-
- if (getKind().argsOnStack()) {
- // we move backwards because we're popping off the stack
- for (int i = len - 1; i >= 0; i--) {
- UnresolvedType type = getArgType(i);
- BcelVar tmp = genTempVar(type, "ajc$arg" + i);
- range.insert(tmp.createStore(getFactory()), Range.OutsideBefore);
- int position = i;
- position += positionOffset;
- tmp.setPositionInAroundState(position);
- argVars[i] = tmp;
- }
- } else {
- int index = 0;
- if (arg0HoldsThis()) {
- index++;
- }
-
- for (int i = 0; i < len; i++) {
- UnresolvedType type = getArgType(i);
- if (argVars[i] == null) {
- BcelVar tmp = genTempVar(type, "ajc$arg" + i);
- range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore);
- argVars[i] = tmp;
- tmp.setPositionInAroundState(i + positionOffset);
- }
- index += type.resolve(world).getSize();
- }
- }
- allArgVarsInitialized = true;
-
- }
-
- public void initializeForAroundClosure() {
- initializeArgVars();
- if (hasTarget()) {
- initializeTargetVar();
- }
- if (hasThis()) {
- initializeThisVar();
- // System.out.println("initialized: " + this + " thisVar = " + thisVar);
- }
- }
-
- public void initializeThisAnnotationVars() {
- if (thisAnnotationVars != null) {
- return;
- }
- thisAnnotationVars = new HashMap<ResolvedType, TypeAnnotationAccessVar>();
- // populate..
- }
-
- public void initializeTargetAnnotationVars() {
- if (targetAnnotationVars != null) {
- return;
- }
- if (getKind().isTargetSameAsThis()) {
- if (hasThis()) {
- initializeThisAnnotationVars();
- }
- targetAnnotationVars = thisAnnotationVars;
- } else {
- targetAnnotationVars = new HashMap<ResolvedType, TypeAnnotationAccessVar>();
- ResolvedType[] rtx = this.getTargetType().resolve(world).getAnnotationTypes(); // what about annotations we havent
- // gotten yet but we will get in
- // subclasses?
- for (int i = 0; i < rtx.length; i++) {
- ResolvedType typeX = rtx[i];
- targetAnnotationVars.put(typeX, new TypeAnnotationAccessVar(typeX, (BcelVar) getTargetVar()));
- }
- // populate.
- }
- }
-
- // public void initializeArgAnnotationVars() {
- // if (argAnnotationVars != null) {
- // return;
- // }
- // int numArgs = getArgCount();
- // argAnnotationVars = new Map[numArgs];
- // for (int i = 0; i < argAnnotationVars.length; i++) {
- // argAnnotationVars[i] = new HashMap();
- // // FIXME asc just delete this logic - we always build the Var on demand, as we don't know at weave time
- // // what the full set of annotations could be (due to static/dynamic type differences...)
- // }
- // }
-
- protected ResolvedMember getRelevantMember(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) {
- if (foundMember != null) {
- return foundMember;
- }
-
- foundMember = getSignature().resolve(world);
- if (foundMember == null && relevantMember != null) {
- foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
- }
-
- // check the ITD'd dooberries
- List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers();
- for (ConcreteTypeMunger typeMunger : mungers) {
- if (typeMunger.getMunger() instanceof NewMethodTypeMunger || typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
- ResolvedMember fakerm = typeMunger.getSignature();
- if (fakerm.getName().equals(getSignature().getName())
- && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) {
- if (foundMember.getKind() == ResolvedMember.CONSTRUCTOR) {
- foundMember = AjcMemberMaker.interConstructor(relevantType, foundMember, typeMunger.getAspectType());
- } else {
- foundMember = AjcMemberMaker.interMethod(foundMember, typeMunger.getAspectType(), false);
- // ResolvedMember o = AjcMemberMaker.interMethodBody(fakerm, typeMunger.getAspectType());
- // // Object os = o.getAnnotations();
- // ResolvedMember foundMember2 = findMethod(typeMunger.getAspectType(), o);
- // Object os2 = foundMember2.getAnnotations();
- // int stop = 1;
- // foundMember = foundMember2;
- // foundMember = AjcMemberMaker.interMethod(foundMember, typeMunger.getAspectType());
- }
- // in the above.. what about if it's on an Interface? Can that happen?
- // then the last arg of the above should be true
- return foundMember;
- }
- }
- }
- return foundMember;
- }
-
- protected ResolvedType[] getAnnotations(ResolvedMember foundMember, Member relevantMember, ResolvedType relevantType) {
- if (foundMember == null) {
- // check the ITD'd dooberries
- List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers();
- for (Iterator<ConcreteTypeMunger> iter = mungers.iterator(); iter.hasNext();) {
- Object munger = iter.next();
- ConcreteTypeMunger typeMunger = (ConcreteTypeMunger) munger;
- if (typeMunger.getMunger() instanceof NewMethodTypeMunger
- || typeMunger.getMunger() instanceof NewConstructorTypeMunger) {
- ResolvedMember fakerm = typeMunger.getSignature();
- // if (fakerm.hasAnnotations())
-
- ResolvedMember ajcMethod = (getSignature().getKind() == ResolvedMember.CONSTRUCTOR ? AjcMemberMaker
- .postIntroducedConstructor(typeMunger.getAspectType(), fakerm.getDeclaringType(),
- fakerm.getParameterTypes()) : AjcMemberMaker.interMethodDispatcher(fakerm,
- typeMunger.getAspectType()));
- // AjcMemberMaker.interMethodBody(fakerm,typeMunger.getAspectType()));
- ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
- if (fakerm.getName().equals(getSignature().getName())
- && fakerm.getParameterSignature().equals(getSignature().getParameterSignature())) {
- relevantType = typeMunger.getAspectType();
- foundMember = rmm;
- return foundMember.getAnnotationTypes();
- }
- }
- }
- // didn't find in ITDs, look in supers
- foundMember = relevantType.lookupMemberWithSupersAndITDs(relevantMember);
- if (foundMember == null) {
- throw new IllegalStateException("Couldn't find member " + relevantMember + " for type " + relevantType);
- }
- }
- return foundMember.getAnnotationTypes();
- }
-
- /**
- * By determining what "kind" of shadow we are, we can find out the annotations on the appropriate element (method, field,
- * constructor, type). Then create one BcelVar entry in the map for each annotation, keyed by annotation type.
- */
- public void initializeKindedAnnotationVars() {
- if (kindedAnnotationVars != null) {
- return;
- }
- kindedAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>();
-
- ResolvedType[] annotations = null;
- Member shadowSignature = getSignature();
- Member annotationHolder = getSignature();
- ResolvedType relevantType = shadowSignature.getDeclaringType().resolve(world);
-
- if (relevantType.isRawType() || relevantType.isParameterizedType()) {
- relevantType = relevantType.getGenericType();
- }
-
- // Determine the annotations that are of interest
- if (getKind() == Shadow.StaticInitialization) {
- annotations = relevantType.resolve(world).getAnnotationTypes();
- } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) {
- ResolvedMember foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(), getSignature());
- annotations = getAnnotations(foundMember, shadowSignature, relevantType);
- annotationHolder = getRelevantMember(foundMember, shadowSignature, relevantType);
- relevantType = annotationHolder.getDeclaringType().resolve(world);
- } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) {
- annotationHolder = findField(relevantType.getDeclaredFields(), getSignature());
-
- if (annotationHolder == null) {
- // check the ITD'd dooberries
- List<ConcreteTypeMunger> mungers = relevantType.resolve(world).getInterTypeMungers();
- for (ConcreteTypeMunger typeMunger : mungers) {
- if (typeMunger.getMunger() instanceof NewFieldTypeMunger) {
- ResolvedMember fakerm = typeMunger.getSignature();
- // if (fakerm.hasAnnotations())
- ResolvedMember ajcMethod = AjcMemberMaker.interFieldInitializer(fakerm, typeMunger.getAspectType());
- ResolvedMember rmm = findMethod(typeMunger.getAspectType(), ajcMethod);
- if (fakerm.equals(getSignature())) {
- relevantType = typeMunger.getAspectType();
- annotationHolder = rmm;
- }
- }
- }
- }
- annotations = ((ResolvedMember) annotationHolder).getAnnotationTypes();
-
- } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution
- || getKind() == Shadow.AdviceExecution) {
-
- ResolvedMember foundMember = findMethod2(relevantType.getDeclaredMethods(), getSignature());
- annotations = getAnnotations(foundMember, shadowSignature, relevantType);
- annotationHolder = getRelevantMember(foundMember, annotationHolder, relevantType);
- UnresolvedType ut = annotationHolder.getDeclaringType();
- relevantType = ut.resolve(world);
-
- } else if (getKind() == Shadow.ExceptionHandler) {
- relevantType = getSignature().getParameterTypes()[0].resolve(world);
- annotations = relevantType.getAnnotationTypes();
-
- } else if (getKind() == Shadow.PreInitialization || getKind() == Shadow.Initialization) {
- ResolvedMember found = findMethod2(relevantType.getDeclaredMethods(), getSignature());
- annotations = found.getAnnotationTypes();
- }
-
- if (annotations == null) {
- // We can't have recognized the shadow - should blow up now to be on the safe side
- throw new BCException("Could not discover annotations for shadow: " + getKind());
- }
-
- for (ResolvedType annotationType : annotations) {
- AnnotationAccessVar accessVar = new AnnotationAccessVar(this, getKind(), annotationType.resolve(world), relevantType,
- annotationHolder, false);
- kindedAnnotationVars.put(annotationType, accessVar);
- }
- }
-
- private ResolvedMember findMethod2(ResolvedMember members[], Member sig) {
- String signatureName = sig.getName();
- String parameterSignature = sig.getParameterSignature();
- for (ResolvedMember member : members) {
- if (member.getName().equals(signatureName) && member.getParameterSignature().equals(parameterSignature)) {
- return member;
- }
- }
- return null;
- }
-
- private ResolvedMember findMethod(ResolvedType aspectType, ResolvedMember ajcMethod) {
- ResolvedMember decMethods[] = aspectType.getDeclaredMethods();
- for (int i = 0; i < decMethods.length; i++) {
- ResolvedMember member = decMethods[i];
- if (member.equals(ajcMethod)) {
- return member;
- }
- }
- return null;
- }
-
- private ResolvedMember findField(ResolvedMember[] members, Member lookingFor) {
- for (int i = 0; i < members.length; i++) {
- ResolvedMember member = members[i];
- if (member.getName().equals(getSignature().getName()) && member.getType().equals(getSignature().getType())) {
- return member;
- }
- }
- return null;
- }
-
- public void initializeWithinAnnotationVars() {
- if (withinAnnotationVars != null) {
- return;
- }
- withinAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>();
-
- ResolvedType[] annotations = getEnclosingType().resolve(world).getAnnotationTypes();
- for (int i = 0; i < annotations.length; i++) {
- ResolvedType ann = annotations[i];
- Kind k = Shadow.StaticInitialization;
- withinAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(), null, true));
- }
- }
-
- public void initializeWithinCodeAnnotationVars() {
- if (withincodeAnnotationVars != null) {
- return;
- }
- withincodeAnnotationVars = new HashMap<ResolvedType, AnnotationAccessVar>();
-
- // For some shadow we are interested in annotations on the method containing that shadow.
- ResolvedType[] annotations = getEnclosingMethod().getMemberView().getAnnotationTypes();
- for (int i = 0; i < annotations.length; i++) {
- ResolvedType ann = annotations[i];
- Kind k = (getEnclosingMethod().getMemberView().getKind() == Member.CONSTRUCTOR ? Shadow.ConstructorExecution
- : Shadow.MethodExecution);
- withincodeAnnotationVars.put(ann, new AnnotationAccessVar(this, k, ann, getEnclosingType(),
- getEnclosingCodeSignature(), true));
- }
- }
-
- // ---- weave methods
-
- void weaveBefore(BcelAdvice munger) {
- range.insert(munger.getAdviceInstructions(this, null, range.getRealStart()), Range.InsideBefore);
- }
-
- public void weaveAfter(BcelAdvice munger) {
- weaveAfterThrowing(munger, UnresolvedType.THROWABLE);
- weaveAfterReturning(munger);
- }
-
- /**
- * The basic strategy here is to add a set of instructions at the end of the shadow range that dispatch the advice, and then
- * return whatever the shadow was going to return anyway.
- *
- * To achieve this, we note all the return statements in the advice, and replace them with code that: 1) stores the return value
- * on top of the stack in a temp var 2) jumps to the start of our advice block 3) restores the return value at the end of the
- * advice block before ultimately returning
- *
- * We also need to bind the return value into a returning parameter, if the advice specified one.
- */
- public void weaveAfterReturning(BcelAdvice munger) {
- List<InstructionHandle> returns = findReturnInstructions();
- boolean hasReturnInstructions = !returns.isEmpty();
-
- // list of instructions that handle the actual return from the join point
- InstructionList retList = new InstructionList();
-
- // variable that holds the return value
- BcelVar returnValueVar = null;
-
- if (hasReturnInstructions) {
- returnValueVar = generateReturnInstructions(returns, retList);
- } else {
- // we need at least one instruction, as the target for jumps
- retList.append(InstructionConstants.NOP);
- }
-
- // list of instructions for dispatching to the advice itself
- InstructionList advice = getAfterReturningAdviceDispatchInstructions(munger, retList.getStart());
-
- if (hasReturnInstructions) {
- InstructionHandle gotoTarget = advice.getStart();
- for (Iterator<InstructionHandle> i = returns.iterator(); i.hasNext();) {
- InstructionHandle ih = i.next();
- retargetReturnInstruction(munger.hasExtraParameter(), returnValueVar, gotoTarget, ih);
- }
- }
-
- range.append(advice);
- range.append(retList);
- }
-
- /**
- * @return a list of all the return instructions in the range of this shadow
- */
- private List<InstructionHandle> findReturnInstructions() {
- List<InstructionHandle> returns = new ArrayList<InstructionHandle>();
- for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
- if (ih.getInstruction().isReturnInstruction()) {
- returns.add(ih);
- }
- }
- return returns;
- }
-
- /**
- * Given a list containing all the return instruction handles for this shadow, finds the last return instruction and copies it,
- * making this the ultimate return. If the shadow has a non-void return type, we also create a temporary variable to hold the
- * return value, and load the value from this var before returning (see pr148007 for why we do this - it works around a JRockit
- * bug, and is also closer to what javac generates)
- *
- * Sometimes the 'last return' isnt the right one - some rogue code can include the real return from the body of a subroutine
- * that exists at the end of the method. In this case the last return is RETURN but that may not be correct for a method with a
- * non-void return type... pr151673
- *
- * @param returns list of all the return instructions in the shadow
- * @param returnInstructions instruction list into which the return instructions should be generated
- * @return the variable holding the return value, if needed
- */
- private BcelVar generateReturnInstructions(List<InstructionHandle> returns, InstructionList returnInstructions) {
- BcelVar returnValueVar = null;
- if (this.hasANonVoidReturnType()) {
- // Find the last *correct* return - this is a method with a non-void return type
- // so ignore RETURN
- Instruction newReturnInstruction = null;
- int i = returns.size() - 1;
- while (newReturnInstruction == null && i >= 0) {
- InstructionHandle ih = returns.get(i);
- if (ih.getInstruction().opcode != Constants.RETURN) {
- newReturnInstruction = Utility.copyInstruction(ih.getInstruction());
- }
- i--;
- }
- returnValueVar = genTempVar(this.getReturnType());
- returnValueVar.appendLoad(returnInstructions, getFactory());
- returnInstructions.append(newReturnInstruction);
- } else {
- InstructionHandle lastReturnHandle = returns.get(returns.size() - 1);
- Instruction newReturnInstruction = Utility.copyInstruction(lastReturnHandle.getInstruction());
- returnInstructions.append(newReturnInstruction);
- }
- return returnValueVar;
- }
-
- /**
- * @return true, iff this shadow returns a value
- */
- private boolean hasANonVoidReturnType() {
- return !this.getReturnType().equals(UnresolvedType.VOID);
- }
-
- /**
- * Get the list of instructions used to dispatch to the after advice
- *
- * @param munger
- * @param firstInstructionInReturnSequence
- * @return
- */
- private InstructionList getAfterReturningAdviceDispatchInstructions(BcelAdvice munger,
- InstructionHandle firstInstructionInReturnSequence) {
- InstructionList advice = new InstructionList();
-
- BcelVar tempVar = null;
- if (munger.hasExtraParameter()) {
- tempVar = insertAdviceInstructionsForBindingReturningParameter(advice);
- }
- advice.append(munger.getAdviceInstructions(this, tempVar, firstInstructionInReturnSequence));
- return advice;
- }
-
- /**
- * If the after() returning(Foo f) form is used, bind the return value to the parameter. If the shadow returns void, bind null.
- *
- * @param advice
- * @return
- */
- private BcelVar insertAdviceInstructionsForBindingReturningParameter(InstructionList advice) {
- BcelVar tempVar;
- UnresolvedType tempVarType = getReturnType();
- if (tempVarType.equals(UnresolvedType.VOID)) {
- tempVar = genTempVar(UnresolvedType.OBJECT);
- advice.append(InstructionConstants.ACONST_NULL);
- tempVar.appendStore(advice, getFactory());
- } else {
- tempVar = genTempVar(tempVarType);
- advice.append(InstructionFactory.createDup(tempVarType.getSize()));
- tempVar.appendStore(advice, getFactory());
- }
- return tempVar;
- }
-
- /**
- * Helper method for weaveAfterReturning
- *
- * Each return instruction in the method body is retargeted by calling this method. The return instruction is replaced by up to
- * three instructions: 1) if the shadow returns a value, and that value is bound to an after returning parameter, then we DUP
- * the return value on the top of the stack 2) if the shadow returns a value, we store it in the returnValueVar (it will be
- * retrieved from here when we ultimately return after the advice dispatch) 3) if the return was the last instruction, we add a
- * NOP (it will fall through to the advice dispatch), otherwise we add a GOTO that branches to the supplied gotoTarget (start of
- * the advice dispatch)
- */
- private void retargetReturnInstruction(boolean hasReturningParameter, BcelVar returnValueVar, InstructionHandle gotoTarget,
- InstructionHandle returnHandle) {
- // pr148007, work around JRockit bug
- // replace ret with store into returnValueVar, followed by goto if not
- // at the end of the instruction list...
- InstructionList newInstructions = new InstructionList();
- if (returnValueVar != null) {
- if (hasReturningParameter) {
- // we have to dup the return val before consuming it...
- newInstructions.append(InstructionFactory.createDup(this.getReturnType().getSize()));
- }
- // store the return value into this var
- returnValueVar.appendStore(newInstructions, getFactory());
- }
- if (!isLastInstructionInRange(returnHandle, range)) {
- newInstructions.append(InstructionFactory.createBranchInstruction(Constants.GOTO, gotoTarget));
- }
- if (newInstructions.isEmpty()) {
- newInstructions.append(InstructionConstants.NOP);
- }
- Utility.replaceInstruction(returnHandle, newInstructions, enclosingMethod);
- }
-
- private boolean isLastInstructionInRange(InstructionHandle ih, ShadowRange aRange) {
- return ih.getNext() == aRange.getEnd();
- }
-
- public void weaveAfterThrowing(BcelAdvice munger, UnresolvedType catchType) {
- // a good optimization would be not to generate anything here
- // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
- // a shadow, inside me).
- if (getRange().getStart().getNext() == getRange().getEnd()) {
- return;
- }
- InstructionFactory fact = getFactory();
- InstructionList handler = new InstructionList();
- BcelVar exceptionVar = genTempVar(catchType);
- exceptionVar.appendStore(handler, fact);
-
- // pr62642
- // I will now jump through some firey BCEL hoops to generate a trivial bit of code:
- // if (exc instanceof ExceptionInInitializerError)
- // throw (ExceptionInInitializerError)exc;
- if (this.getEnclosingMethod().getName().equals("<clinit>")) {
- ResolvedType eiieType = world.resolve("java.lang.ExceptionInInitializerError");
- ObjectType eiieBcelType = (ObjectType) BcelWorld.makeBcelType(eiieType);
- InstructionList ih = new InstructionList(InstructionConstants.NOP);
- handler.append(exceptionVar.createLoad(fact));
- handler.append(fact.createInstanceOf(eiieBcelType));
- InstructionBranch bi = InstructionFactory.createBranchInstruction(Constants.IFEQ, ih.getStart());
- handler.append(bi);
- handler.append(exceptionVar.createLoad(fact));
- handler.append(fact.createCheckCast(eiieBcelType));
- handler.append(InstructionConstants.ATHROW);
- handler.append(ih);
- }
-
- InstructionList endHandler = new InstructionList(exceptionVar.createLoad(fact));
- handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart()));
- handler.append(endHandler);
- handler.append(InstructionConstants.ATHROW);
- InstructionHandle handlerStart = handler.getStart();
-
- if (isFallsThrough()) {
- InstructionHandle jumpTarget = handler.append(InstructionConstants.NOP);
- handler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget));
- }
- InstructionHandle protectedEnd = handler.getStart();
- range.insert(handler, Range.InsideAfter);
-
- enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart,
- (ObjectType) BcelWorld.makeBcelType(catchType), // ???Type.THROWABLE,
- // high priority if our args are on the stack
- getKind().hasHighPriorityExceptions());
- }
-
- // ??? this shares a lot of code with the above weaveAfterThrowing
- // ??? would be nice to abstract that to say things only once
- public void weaveSoftener(BcelAdvice munger, UnresolvedType catchType) {
- // a good optimization would be not to generate anything here
- // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
- // a shadow, inside me).
- if (getRange().getStart().getNext() == getRange().getEnd()) {
- return;
- }
-
- InstructionFactory fact = getFactory();
- InstructionList handler = new InstructionList();
- InstructionList rtExHandler = new InstructionList();
- BcelVar exceptionVar = genTempVar(catchType);
-
- handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE));
- handler.append(InstructionFactory.createDup(1));
- handler.append(exceptionVar.createLoad(fact));
- handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>", Type.VOID, new Type[] { Type.THROWABLE },
- Constants.INVOKESPECIAL)); // ??? special
- handler.append(InstructionConstants.ATHROW);
-
- // ENH 42737
- exceptionVar.appendStore(rtExHandler, fact);
- // aload_1
- rtExHandler.append(exceptionVar.createLoad(fact));
- // instanceof class java/lang/RuntimeException
- rtExHandler.append(fact.createInstanceOf(new ObjectType("java.lang.RuntimeException")));
- // ifeq go to new SOFT_EXCEPTION_TYPE instruction
- rtExHandler.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, handler.getStart()));
- // aload_1
- rtExHandler.append(exceptionVar.createLoad(fact));
- // athrow
- rtExHandler.append(InstructionFactory.ATHROW);
-
- InstructionHandle handlerStart = rtExHandler.getStart();
-
- if (isFallsThrough()) {
- InstructionHandle jumpTarget = range.getEnd();// handler.append(fact.NOP);
- rtExHandler.insert(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget));
- }
-
- rtExHandler.append(handler);
-
- InstructionHandle protectedEnd = rtExHandler.getStart();
- range.insert(rtExHandler, Range.InsideAfter);
-
- enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), handlerStart,
- (ObjectType) BcelWorld.makeBcelType(catchType),
- // high priority if our args are on the stack
- getKind().hasHighPriorityExceptions());
- }
-
- public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) {
- final InstructionFactory fact = getFactory();
-
- InstructionList entryInstructions = new InstructionList();
- InstructionList entrySuccessInstructions = new InstructionList();
- onVar.appendLoad(entrySuccessInstructions, fact);
-
- entrySuccessInstructions
- .append(Utility.createInvoke(fact, world, AjcMemberMaker.perObjectBind(munger.getConcreteAspect())));
-
- InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
- range.getRealStart(), entrySuccessInstructions.getStart());
-
- entryInstructions.append(testInstructions);
- entryInstructions.append(entrySuccessInstructions);
-
- range.insert(entryInstructions, Range.InsideBefore);
- }
-
- // PTWIMPL Create static initializer to call the aspect factory
- /**
- * Causes the aspect instance to be *set* for later retrievable through localAspectof()/aspectOf()
- */
- public void weavePerTypeWithinAspectInitialization(final BcelAdvice munger, UnresolvedType t) {
- ResolvedType tResolved = t.resolve(world);
- if (tResolved.isInterface()) {
- return; // Don't initialize statics in interfaces
- }
- ResolvedType aspectRT = munger.getConcreteAspect();
- BcelWorld.getBcelObjectType(aspectRT);
-
- // Although matched, if the visibility rules prevent the aspect from seeing this type, don't
- // insert any code (easier to do it here than try to affect the matching logic, unfortunately)
- if (!(tResolved.canBeSeenBy(aspectRT) || aspectRT.isPrivilegedAspect())) {
- return;
- }
-
- final InstructionFactory fact = getFactory();
-
- InstructionList entryInstructions = new InstructionList();
- InstructionList entrySuccessInstructions = new InstructionList();
-
- String aspectname = munger.getConcreteAspect().getName();
-
- String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect());
- entrySuccessInstructions.append(InstructionFactory.PUSH(fact.getConstantPool(), t.getName()));
-
- entrySuccessInstructions.append(fact.createInvoke(aspectname, "ajc$createAspectInstance", new ObjectType(aspectname),
- new Type[] { new ObjectType("java.lang.String") }, Constants.INVOKESTATIC));
- entrySuccessInstructions.append(fact.createPutStatic(t.getName(), ptwField, new ObjectType(aspectname)));
-
- entryInstructions.append(entrySuccessInstructions);
-
- range.insert(entryInstructions, Range.InsideBefore);
- }
-
- public void weaveCflowEntry(final BcelAdvice munger, final Member cflowField) {
- final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || munger.getKind() == AdviceKind.PerCflowEntry;
- if (!isPer && getKind() == PreInitialization) {
- return;
- }
- final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
- final InstructionFactory fact = getFactory();
-
- final BcelVar testResult = genTempVar(UnresolvedType.BOOLEAN);
-
- InstructionList entryInstructions = new InstructionList();
- {
- InstructionList entrySuccessInstructions = new InstructionList();
-
- if (munger.hasDynamicTests()) {
- entryInstructions.append(Utility.createConstant(fact, 0));
- testResult.appendStore(entryInstructions, fact);
-
- entrySuccessInstructions.append(Utility.createConstant(fact, 1));
- testResult.appendStore(entrySuccessInstructions, fact);
- }
-
- if (isPer) {
- entrySuccessInstructions.append(fact.createInvoke(munger.getConcreteAspect().getName(),
- NameMangler.PERCFLOW_PUSH_METHOD, Type.VOID, new Type[] {}, Constants.INVOKESTATIC));
- } else {
- BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars(false);
-
- if (cflowStateVars.length == 0) {
- // This should be getting managed by a counter - lets make sure.
- if (!cflowField.getType().getName().endsWith("CFlowCounter")) {
- throw new RuntimeException("Incorrectly attempting counter operation on stacked cflow");
- }
- entrySuccessInstructions.append(Utility.createGet(fact, cflowField));
- // arrayVar.appendLoad(entrySuccessInstructions, fact);
- entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "inc", Type.VOID,
- new Type[] {}, Constants.INVOKEVIRTUAL));
- } else {
- BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
-
- int alen = cflowStateVars.length;
- entrySuccessInstructions.append(Utility.createConstant(fact, alen));
- entrySuccessInstructions.append(fact.createNewArray(Type.OBJECT, (short) 1));
- arrayVar.appendStore(entrySuccessInstructions, fact);
-
- for (int i = 0; i < alen; i++) {
- arrayVar.appendConvertableArrayStore(entrySuccessInstructions, fact, i, cflowStateVars[i]);
- }
-
- entrySuccessInstructions.append(Utility.createGet(fact, cflowField));
- arrayVar.appendLoad(entrySuccessInstructions, fact);
-
- entrySuccessInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID,
- new Type[] { objectArrayType }, Constants.INVOKEVIRTUAL));
- }
- }
-
- InstructionList testInstructions = munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
- range.getRealStart(), entrySuccessInstructions.getStart());
- entryInstructions.append(testInstructions);
- entryInstructions.append(entrySuccessInstructions);
- }
-
- BcelAdvice exitAdvice = new BcelAdvice(null, null, null, 0, 0, 0, null, munger.getConcreteAspect()) {
- @Override
- public InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) {
- InstructionList exitInstructions = new InstructionList();
- if (munger.hasDynamicTests()) {
- testResult.appendLoad(exitInstructions, fact);
- exitInstructions.append(InstructionFactory.createBranchInstruction(Constants.IFEQ, ifNoAdvice));
- }
- exitInstructions.append(Utility.createGet(fact, cflowField));
- if (munger.getKind() != AdviceKind.PerCflowEntry && munger.getKind() != AdviceKind.PerCflowBelowEntry
- && munger.getExposedStateAsBcelVars(false).length == 0) {
- exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_COUNTER_TYPE, "dec", Type.VOID, new Type[] {},
- Constants.INVOKEVIRTUAL));
- } else {
- exitInstructions.append(fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "pop", Type.VOID, new Type[] {},
- Constants.INVOKEVIRTUAL));
- }
- return exitInstructions;
- }
- };
- // if (getKind() == PreInitialization) {
- // weaveAfterReturning(exitAdvice);
- // }
- // else {
- weaveAfter(exitAdvice);
- // }
-
- range.insert(entryInstructions, Range.InsideBefore);
- }
-
- /*
- * Implementation notes:
- *
- * AroundInline still extracts the instructions of the original shadow into an extracted method. This allows inlining of even
- * that advice that doesn't call proceed or calls proceed more than once.
- *
- * It extracts the instructions of the original shadow into a method.
- *
- * Then it extracts the instructions of the advice into a new method defined on this enclosing class. This new method can then
- * be specialized as below.
- *
- * Then it searches in the instructions of the advice for any call to the proceed method.
- *
- * At such a call, there is stuff on the stack representing the arguments to proceed. Pop these into the frame.
- *
- * Now build the stack for the call to the extracted method, taking values either from the join point state or from the new
- * frame locs from proceed. Now call the extracted method. The right return value should be on the stack, so no cast is
- * necessary.
- *
- * If only one call to proceed is made, we can re-inline the original shadow. We are not doing that presently.
- *
- * If the body of the advice can be determined to not alter the stack, or if this shadow doesn't care about the stack, i.e.
- * method-execution, then the new method for the advice can also be re-lined. We are not doing that presently.
- */
- public void weaveAroundInline(BcelAdvice munger, boolean hasDynamicTest) {
- // !!! THIS BLOCK OF CODE SHOULD BE IN A METHOD CALLED weaveAround(...);
- Member mungerSig = munger.getSignature();
- // Member originalSig = mungerSig; // If mungerSig is on a parameterized type, originalSig is the member on the generic type
- if (mungerSig instanceof ResolvedMember) {
- ResolvedMember rm = (ResolvedMember) mungerSig;
- if (rm.hasBackingGenericMember()) {
- mungerSig = rm.getBackingGenericMember();
- }
- }
- ResolvedType declaringAspectType = world.resolve(mungerSig.getDeclaringType(), true);
- if (declaringAspectType.isMissing()) {
- world.getLint().cantFindType.signal(
- new String[] { WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,
- declaringAspectType.getClassName()) }, getSourceLocation(),
- new ISourceLocation[] { munger.getSourceLocation() });
- }
-
- // ??? might want some checks here to give better errors
- ResolvedType rt = (declaringAspectType.isParameterizedType() ? declaringAspectType.getGenericType() : declaringAspectType);
- BcelObjectType ot = BcelWorld.getBcelObjectType(rt);
- LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig);
- if (!adviceMethod.getCanInline()) {
- weaveAroundClosure(munger, hasDynamicTest);
- return;
- }
-
- // specific test for @AJ proceedInInners
- if (isAnnotationStylePassingProceedingJoinPointOutOfAdvice(munger, hasDynamicTest, adviceMethod)) {
- return;
- }
-
- // We can't inline around methods if they have around advice on them, this
- // is because the weaving will extract the body and hence the proceed call.
-
- // TODO should consider optimizations to recognize simple cases that don't require body extraction
-
- enclosingMethod.setCanInline(false);
-
- LazyClassGen shadowClass = getEnclosingClass();
-
- // Extract the shadow into a new method. For example:
- // "private static final void method_aroundBody0(M, M, String, org.aspectj.lang.JoinPoint)"
- // Parameters are: this if there is one, target if there is one and its different to this, then original arguments
- // at the shadow, then tjp
- String extractedShadowMethodName = NameMangler.aroundShadowMethodName(getSignature(), shadowClass.getNewGeneratedNameTag());
- List<String> parameterNames = new ArrayList<String>();
- boolean shadowClassIsInterface = shadowClass.isInterface();
- LazyMethodGen extractedShadowMethod = extractShadowInstructionsIntoNewMethod(extractedShadowMethodName,
- shadowClassIsInterface?Modifier.PUBLIC:Modifier.PRIVATE,
- munger.getSourceLocation(), parameterNames,shadowClassIsInterface);
-
- List<BcelVar> argsToCallLocalAdviceMethodWith = new ArrayList<BcelVar>();
- List<BcelVar> proceedVarList = new ArrayList<BcelVar>();
- int extraParamOffset = 0;
-
- // Create the extra parameters that are needed for passing to proceed
- // This code is very similar to that found in makeCallToCallback and should
- // be rationalized in the future
-
- if (thisVar != null) {
- argsToCallLocalAdviceMethodWith.add(thisVar);
- proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset));
- extraParamOffset += thisVar.getType().getSize();
- }
-
- if (targetVar != null && targetVar != thisVar) {
- argsToCallLocalAdviceMethodWith.add(targetVar);
- proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset));
- extraParamOffset += targetVar.getType().getSize();
- }
- for (int i = 0, len = getArgCount(); i < len; i++) {
- argsToCallLocalAdviceMethodWith.add(argVars[i]);
- proceedVarList.add(new BcelVar(argVars[i].getType(), extraParamOffset));
- extraParamOffset += argVars[i].getType().getSize();
- }
- if (thisJoinPointVar != null) {
- argsToCallLocalAdviceMethodWith.add(thisJoinPointVar);
- proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset));
- extraParamOffset += thisJoinPointVar.getType().getSize();
- }
-
- // We use the munger signature here because it allows for any parameterization of the mungers pointcut that
- // 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
- // then here the munger signature will have 'Foo' as an argument in it whilst the adviceMethod argument type will be
- // 'Object' - since it represents the advice method in the superaspect which uses the erasure of the type variable p(Object
- // t) - see pr174449.
-
- Type[] adviceParameterTypes = BcelWorld.makeBcelTypes(munger.getSignature().getParameterTypes());
-
- // forces initialization ... dont like this but seems to be required for some tests to pass, I think that means there
- // is a LazyMethodGen method that is not correctly setup to call initialize() when it is invoked - but I dont have
- // time right now to discover which
- adviceMethod.getArgumentTypes();
-
- Type[] extractedMethodParameterTypes = extractedShadowMethod.getArgumentTypes();
-
- Type[] parameterTypes = new Type[extractedMethodParameterTypes.length + adviceParameterTypes.length + 1];
- int parameterIndex = 0;
- System.arraycopy(extractedMethodParameterTypes, 0, parameterTypes, parameterIndex, extractedMethodParameterTypes.length);
- parameterIndex += extractedMethodParameterTypes.length;
- parameterTypes[parameterIndex++] = BcelWorld.makeBcelType(adviceMethod.getEnclosingClass().getType());
- System.arraycopy(adviceParameterTypes, 0, parameterTypes, parameterIndex, adviceParameterTypes.length);
-
- // Extract the advice into a new method. This will go in the same type as the shadow
- // name will be something like foo_aroundBody1$advice
- String localAdviceMethodName = NameMangler.aroundAdviceMethodName(getSignature(), shadowClass.getNewGeneratedNameTag());
- int localAdviceMethodModifiers = Modifier.PRIVATE | (world.useFinal() & !shadowClassIsInterface ? Modifier.FINAL : 0) | Modifier.STATIC;
- LazyMethodGen localAdviceMethod = new LazyMethodGen(localAdviceMethodModifiers, BcelWorld.makeBcelType(mungerSig.getReturnType()), localAdviceMethodName, parameterTypes,
- NoDeclaredExceptions, shadowClass);
-
- // Doesnt work properly, so leave it out:
- // String aspectFilename = adviceMethod.getEnclosingClass().getInternalFileName();
- // String shadowFilename = shadowClass.getInternalFileName();
- // if (!aspectFilename.equals(shadowFilename)) {
- // localAdviceMethod.fromFilename = aspectFilename;
- // shadowClass.addInlinedSourceFileInfo(aspectFilename, adviceMethod.highestLineNumber);
- // }
-
- shadowClass.addMethodGen(localAdviceMethod);
-
- // create a map that will move all slots in advice method forward by extraParamOffset
- // in order to make room for the new proceed-required arguments that are added at
- // the beginning of the parameter list
- int nVars = adviceMethod.getMaxLocals() + extraParamOffset;
- IntMap varMap = IntMap.idMap(nVars);
- for (int i = extraParamOffset; i < nVars; i++) {
- varMap.put(i - extraParamOffset, i);
- }
-
- final InstructionFactory fact = getFactory();
-
- localAdviceMethod.getBody().insert(
- BcelClassWeaver.genInlineInstructions(adviceMethod, localAdviceMethod, varMap, fact, true));
-
- localAdviceMethod.setMaxLocals(nVars);
-
- // the shadow is now empty. First, create a correct call
- // to the around advice. This includes both the call (which may involve
- // value conversion of the advice arguments) and the return
- // (which may involve value conversion of the return value). Right now
- // we push a null for the unused closure. It's sad, but there it is.
-
- InstructionList advice = new InstructionList();
- // InstructionHandle adviceMethodInvocation;
- {
- for (Iterator<BcelVar> i = argsToCallLocalAdviceMethodWith.iterator(); i.hasNext();) {
- BcelVar var = i.next();
- var.appendLoad(advice, fact);
- }
- // ??? we don't actually need to push NULL for the closure if we take care
- boolean isAnnoStyleConcreteAspect = munger.getConcreteAspect().isAnnotationStyleAspect();
- boolean isAnnoStyleDeclaringAspect = munger.getDeclaringAspect() != null ? munger.getDeclaringAspect().resolve(world)
- .isAnnotationStyleAspect() : false;
-
- InstructionList iList = null;
- if (isAnnoStyleConcreteAspect && isAnnoStyleDeclaringAspect) {
- iList = this.loadThisJoinPoint();
- iList.append(Utility.createConversion(getFactory(), LazyClassGen.tjpType, LazyClassGen.proceedingTjpType));
- } else {
- iList = new InstructionList(InstructionConstants.ACONST_NULL);
- }
- advice.append(munger.getAdviceArgSetup(this, null, iList));
- // adviceMethodInvocation =
- advice.append(Utility.createInvoke(fact, localAdviceMethod)); // (fact, getWorld(), munger.getSignature()));
- advice.append(Utility.createConversion(getFactory(), BcelWorld.makeBcelType(mungerSig.getReturnType()),
- extractedShadowMethod.getReturnType(), world.isInJava5Mode()));
- if (!isFallsThrough()) {
- advice.append(InstructionFactory.createReturn(extractedShadowMethod.getReturnType()));
- }
- }
-
- // now, situate the call inside the possible dynamic tests,
- // and actually add the whole mess to the shadow
- if (!hasDynamicTest) {
- range.append(advice);
- } else {
- InstructionList afterThingie = new InstructionList(InstructionConstants.NOP);
- InstructionList callback = makeCallToCallback(extractedShadowMethod);
- if (terminatesWithReturn()) {
- callback.append(InstructionFactory.createReturn(extractedShadowMethod.getReturnType()));
- } else {
- // InstructionHandle endNop = range.insert(fact.NOP, Range.InsideAfter);
- advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO, afterThingie.getStart()));
- }
- range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart()));
- range.append(advice);
- range.append(callback);
- range.append(afterThingie);
- }
-
- // now search through the advice, looking for a call to PROCEED.
- // Then we replace the call to proceed with some argument setup, and a
- // call to the extracted method.
-
- // inlining support for code style aspects
- if (!munger.getDeclaringType().isAnnotationStyleAspect()) {
- String proceedName = NameMangler.proceedMethodName(munger.getSignature().getName());
-
- InstructionHandle curr = localAdviceMethod.getBody().getStart();
- InstructionHandle end = localAdviceMethod.getBody().getEnd();
- ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool();
- while (curr != end) {
- InstructionHandle next = curr.getNext();
- Instruction inst = curr.getInstruction();
- if ((inst.opcode == Constants.INVOKESTATIC) && proceedName.equals(((InvokeInstruction) inst).getMethodName(cpg))) {
-
- localAdviceMethod.getBody().append(curr,
- getRedoneProceedCall(fact, extractedShadowMethod, munger, localAdviceMethod, proceedVarList));
- Utility.deleteInstruction(curr, localAdviceMethod);
- }
- curr = next;
- }
- // and that's it.
- } else {
- // ATAJ inlining support for @AJ aspects
- // [TODO document @AJ code rule: don't manipulate 2 jps proceed at the same time.. in an advice body]
- InstructionHandle curr = localAdviceMethod.getBody().getStart();
- InstructionHandle end = localAdviceMethod.getBody().getEnd();
- ConstantPool cpg = localAdviceMethod.getEnclosingClass().getConstantPool();
- while (curr != end) {
- InstructionHandle next = curr.getNext();
- Instruction inst = curr.getInstruction();
- if ((inst instanceof INVOKEINTERFACE) && "proceed".equals(((INVOKEINTERFACE) inst).getMethodName(cpg))) {
- final boolean isProceedWithArgs;
- if (((INVOKEINTERFACE) inst).getArgumentTypes(cpg).length == 1) {
- // proceed with args as a boxed Object[]
- isProceedWithArgs = true;
- } else {
- isProceedWithArgs = false;
- }
- InstructionList insteadProceedIl = getRedoneProceedCallForAnnotationStyle(fact, extractedShadowMethod, munger,
- localAdviceMethod, proceedVarList, isProceedWithArgs);
- localAdviceMethod.getBody().append(curr, insteadProceedIl);
- Utility.deleteInstruction(curr, localAdviceMethod);
- }
- curr = next;
- }
- }
-
- // if (parameterNames.size() == 0) {
- // On return we have inserted the advice body into the local advice method. We have remapped all the local variables
- // that were referenced in the advice as we did the copy, and so the local variable table for localAdviceMethod is
- // now lacking any information about all the initial variables.
- InstructionHandle start = localAdviceMethod.getBody().getStart();
- InstructionHandle end = localAdviceMethod.getBody().getEnd();
-
- // Find the real start and end
- while (start.getInstruction().opcode == Constants.IMPDEP1) {
- start = start.getNext();
- }
- while (end.getInstruction().opcode == Constants.IMPDEP1) {
- end = end.getPrev();
- }
- Type[] args = localAdviceMethod.getArgumentTypes();
- int argNumber = 0;
- for (int slot = 0; slot < extraParamOffset; argNumber++) { // slot will increase by the argument size each time
- String argumentName = null;
- if (argNumber >= args.length || parameterNames.size() == 0 || argNumber >= parameterNames.size()) {
- // this should be unnecessary as I think all known joinpoints and helper methods
- // propagate the parameter names around correctly - but just in case let us do this
- // rather than fail. If a bug is raised reporting unknown as a local variable name
- // then investigate the joinpoint giving rise to the ResolvedMember and why it has
- // no parameter names specified
- argumentName = new StringBuffer("unknown").append(argNumber).toString();
- } else {
- argumentName = parameterNames.get(argNumber);
- }
- String argumentSignature = args[argNumber].getSignature();
- LocalVariableTag lvt = new LocalVariableTag(argumentSignature, argumentName, slot, 0);
- start.addTargeter(lvt);
- end.addTargeter(lvt);
- slot += args[argNumber].getSize();
- }
- }
-
- /**
- * Check if the advice method passes a pjp parameter out via an invoke instruction - if so we can't risk inlining.
- */
- private boolean isAnnotationStylePassingProceedingJoinPointOutOfAdvice(BcelAdvice munger, boolean hasDynamicTest,
- LazyMethodGen adviceMethod) {
- if (munger.getConcreteAspect().isAnnotationStyleAspect()) {
- // if we can't find one proceed() we suspect that the call
- // is happening in an inner class so we don't inline it.
- // Note: for code style, this is done at Aspect compilation time.
- boolean canSeeProceedPassedToOther = false;
- InstructionHandle curr = adviceMethod.getBody().getStart();
- InstructionHandle end = adviceMethod.getBody().getEnd();
- ConstantPool cpg = adviceMethod.getEnclosingClass().getConstantPool();
- while (curr != end) {
- InstructionHandle next = curr.getNext();
- Instruction inst = curr.getInstruction();
- if ((inst instanceof InvokeInstruction)
- && ((InvokeInstruction) inst).getSignature(cpg).indexOf("Lorg/aspectj/lang/ProceedingJoinPoint;") > 0) {
- // we may want to refine to exclude stuff returning jp ?
- // does code style skip inline if i write dump(thisJoinPoint) ?
- canSeeProceedPassedToOther = true;// we see one pjp passed around - dangerous
- break;
- }
- curr = next;
- }
- if (canSeeProceedPassedToOther) {
- // remember this decision to avoid re-analysis
- adviceMethod.setCanInline(false);
- weaveAroundClosure(munger, hasDynamicTest);
- return true;
- }
- }
- return false;
- }
-
- private InstructionList getRedoneProceedCall(InstructionFactory fact, LazyMethodGen callbackMethod, BcelAdvice munger,
- LazyMethodGen localAdviceMethod, List<BcelVar> argVarList) {
- InstructionList ret = new InstructionList();
- // we have on stack all the arguments for the ADVICE call.
- // we have in frame somewhere all the arguments for the non-advice call.
-
- BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true);
- IntMap proceedMap = makeProceedArgumentMap(adviceVars);
-
- // System.out.println(proceedMap + " for " + this);
- // System.out.println(argVarList);
-
- ResolvedType[] proceedParamTypes = world.resolve(munger.getSignature().getParameterTypes());
- // remove this*JoinPoint* as arguments to proceed
- if (munger.getBaseParameterCount() + 1 < proceedParamTypes.length) {
- int len = munger.getBaseParameterCount() + 1;
- ResolvedType[] newTypes = new ResolvedType[len];
- System.arraycopy(proceedParamTypes, 0, newTypes, 0, len);
- proceedParamTypes = newTypes;
- }
-
- // System.out.println("stateTypes: " + Arrays.asList(stateTypes));
- BcelVar[] proceedVars = Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod);
-
- Type[] stateTypes = callbackMethod.getArgumentTypes();
- // System.out.println("stateTypes: " + Arrays.asList(stateTypes));
-
- for (int i = 0, len = stateTypes.length; i < len; i++) {
- Type stateType = stateTypes[i];
- ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
- if (proceedMap.hasKey(i)) {
- // throw new RuntimeException("unimplemented");
- proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
- } else {
- argVarList.get(i).appendLoad(ret, fact);
- }
- }
-
- ret.append(Utility.createInvoke(fact, callbackMethod));
- ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
- BcelWorld.makeBcelType(munger.getSignature().getReturnType()), world.isInJava5Mode()));
- return ret;
- }
-
- // private static boolean bindsThisOrTarget(Pointcut pointcut) {
- // ThisTargetFinder visitor = new ThisTargetFinder();
- // pointcut.accept(visitor, null);
- // return visitor.bindsThisOrTarget;
- // }
-
- // private static class ThisTargetFinder extends IdentityPointcutVisitor {
- // boolean bindsThisOrTarget = false;
- //
- // public Object visit(ThisOrTargetPointcut node, Object data) {
- // if (node.isBinding()) {
- // bindsThisOrTarget = true;
- // }
- // return node;
- // }
- //
- // public Object visit(AndPointcut node, Object data) {
- // if (!bindsThisOrTarget) node.getLeft().accept(this, data);
- // if (!bindsThisOrTarget) node.getRight().accept(this, data);
- // return node;
- // }
- //
- // public Object visit(NotPointcut node, Object data) {
- // if (!bindsThisOrTarget) node.getNegatedPointcut().accept(this, data);
- // return node;
- // }
- //
- // public Object visit(OrPointcut node, Object data) {
- // if (!bindsThisOrTarget) node.getLeft().accept(this, data);
- // if (!bindsThisOrTarget) node.getRight().accept(this, data);
- // return node;
- // }
- // }
-
- /**
- * Annotation style handling for inlining.
- *
- * Note: The proceedingjoinpoint is already on the stack (since the user was calling pjp.proceed(...)
- *
- * The proceed map is ignored (in terms of argument repositioning) since we have a fixed expected format for annotation style.
- * The aim here is to change the proceed() call into a call to the xxx_aroundBody0 method.
- *
- *
- */
- private InstructionList getRedoneProceedCallForAnnotationStyle(InstructionFactory fact, LazyMethodGen callbackMethod,
- BcelAdvice munger, LazyMethodGen localAdviceMethod, List<BcelVar> argVarList, boolean isProceedWithArgs) {
- InstructionList ret = new InstructionList();
-
- // store the Object[] array on stack if proceed with args
- if (isProceedWithArgs) {
-
- // STORE the Object[] into a local variable
- Type objectArrayType = Type.OBJECT_ARRAY;
- int theObjectArrayLocalNumber = localAdviceMethod.allocateLocal(objectArrayType);
- ret.append(InstructionFactory.createStore(objectArrayType, theObjectArrayLocalNumber));
-
- // STORE the ProceedingJoinPoint instance into a local variable
- Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;");
- int pjpLocalNumber = localAdviceMethod.allocateLocal(proceedingJpType);
- ret.append(InstructionFactory.createStore(proceedingJpType, pjpLocalNumber));
-
- // Aim here initially is to determine whether the user will have provided a new
- // this/target in the object array and consume them if they have, leaving us the rest of
- // the arguments to process as regular arguments to the invocation at the original join point
-
- boolean pointcutBindsThis = bindsThis(munger);
- boolean pointcutBindsTarget = bindsTarget(munger);
- boolean targetIsSameAsThis = getKind().isTargetSameAsThis();
-
- int nextArgumentToProvideForCallback = 0;
-
- if (hasThis()) {
- if (!(pointcutBindsTarget && targetIsSameAsThis)) {
- if (pointcutBindsThis) {
- // they have supplied new this as first entry in object array, consume it
- ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber));
- ret.append(Utility.createConstant(fact, 0));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0]));
- } else {
- // use local variable 0
- ret.append(InstructionFactory.createALOAD(0));
- }
- nextArgumentToProvideForCallback++;
- }
- }
-
- if (hasTarget()) {
- if (pointcutBindsTarget) {
- if (getKind().isTargetSameAsThis()) {
- ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber));
- ret.append(Utility.createConstant(fact, pointcutBindsThis ? 1 : 0));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[0]));
- } else {
- int position = (hasThis() && pointcutBindsThis)? 1 : 0;
- ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber));
- ret.append(Utility.createConstant(fact, position));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact, Type.OBJECT, callbackMethod.getArgumentTypes()[nextArgumentToProvideForCallback]));
- }
- nextArgumentToProvideForCallback++;
- } else {
- if (getKind().isTargetSameAsThis()) {
- // ret.append(new ALOAD(0));
- } else {
- ret.append(InstructionFactory.createLoad(localAdviceMethod.getArgumentTypes()[0], hasThis() ? 1 : 0));
- nextArgumentToProvideForCallback++;
- }
- }
- }
-
- // Where to start in the object array in order to pick up arguments
- int indexIntoObjectArrayForArguments = (pointcutBindsThis ? 1 : 0) + (pointcutBindsTarget ? 1 : 0);
-
- int len = callbackMethod.getArgumentTypes().length;
- for (int i = nextArgumentToProvideForCallback; i < len; i++) {
- Type stateType = callbackMethod.getArgumentTypes()[i];
- BcelWorld.fromBcel(stateType).resolve(world);
- if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
- ret.append(new InstructionLV(Constants.ALOAD, pjpLocalNumber));
- } else {
- ret.append(InstructionFactory.createLoad(objectArrayType, theObjectArrayLocalNumber));
- ret.append(Utility
- .createConstant(fact, i - nextArgumentToProvideForCallback + indexIntoObjectArrayForArguments));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact, Type.OBJECT, stateType));
- }
- }
-
- } else {
- Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;");
- int localJp = localAdviceMethod.allocateLocal(proceedingJpType);
- ret.append(InstructionFactory.createStore(proceedingJpType, localJp));
-
- int idx = 0;
- for (int i = 0, len = callbackMethod.getArgumentTypes().length; i < len; i++) {
- Type stateType = callbackMethod.getArgumentTypes()[i];
- /* ResolvedType stateTypeX = */
- BcelWorld.fromBcel(stateType).resolve(world);
- if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
- ret.append(InstructionFactory.createALOAD(localJp));// from localAdvice signature
- // } else if ("Lorg/aspectj/lang/ProceedingJoinPoint;".equals(stateType.getSignature())) {
- // //FIXME ALEX?
- // ret.append(new ALOAD(localJp));// from localAdvice signature
- // // ret.append(fact.createCheckCast(
- // // (ReferenceType) BcelWorld.makeBcelType(stateTypeX)
- // // ));
- // // cast ?
- //
- idx++;
- } else {
- ret.append(InstructionFactory.createLoad(stateType, idx));
- idx += stateType.getSize();
- }
- }
- }
-
- // do the callback invoke
- ret.append(Utility.createInvoke(fact, callbackMethod));
-
- // box it again. Handles cases where around advice does return something else than Object
- if (!UnresolvedType.OBJECT.equals(munger.getSignature().getReturnType())) {
- ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT));
- }
- ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
- BcelWorld.makeBcelType(munger.getSignature().getReturnType()), world.isInJava5Mode()));
-
- return ret;
-
- //
- //
- //
- // if (proceedMap.hasKey(i)) {
- // ret.append(new ALOAD(i));
- // //throw new RuntimeException("unimplemented");
- // //proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
- // } else {
- // //((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
- // //ret.append(new ALOAD(i));
- // if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
- // ret.append(new ALOAD(i));
- // } else {
- // ret.append(new ALOAD(i));
- // }
- // }
- // }
- //
- // ret.append(Utility.createInvoke(fact, callbackMethod));
- // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
- // BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
- //
- // //ret.append(new ACONST_NULL());//will be POPed
- // if (true) return ret;
- //
- //
- //
- // // we have on stack all the arguments for the ADVICE call.
- // // we have in frame somewhere all the arguments for the non-advice call.
- //
- // BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
- // IntMap proceedMap = makeProceedArgumentMap(adviceVars);
- //
- // System.out.println(proceedMap + " for " + this);
- // System.out.println(argVarList);
- //
- // ResolvedType[] proceedParamTypes =
- // world.resolve(munger.getSignature().getParameterTypes());
- // // remove this*JoinPoint* as arguments to proceed
- // if (munger.getBaseParameterCount()+1 < proceedParamTypes.length) {
- // int len = munger.getBaseParameterCount()+1;
- // ResolvedType[] newTypes = new ResolvedType[len];
- // System.arraycopy(proceedParamTypes, 0, newTypes, 0, len);
- // proceedParamTypes = newTypes;
- // }
- //
- // //System.out.println("stateTypes: " + Arrays.asList(stateTypes));
- // BcelVar[] proceedVars =
- // Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, localAdviceMethod);
- //
- // Type[] stateTypes = callbackMethod.getArgumentTypes();
- // // System.out.println("stateTypes: " + Arrays.asList(stateTypes));
- //
- // for (int i=0, len=stateTypes.length; i < len; i++) {
- // Type stateType = stateTypes[i];
- // ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
- // if (proceedMap.hasKey(i)) {
- // //throw new RuntimeException("unimplemented");
- // proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
- // } else {
- // ((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
- // }
- // }
- //
- // ret.append(Utility.createInvoke(fact, callbackMethod));
- // ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
- // BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
- // return ret;
- }
-
- private boolean bindsThis(BcelAdvice munger) {
- UsesThisVisitor utv = new UsesThisVisitor();
- munger.getPointcut().accept(utv, null);
- return utv.usesThis;
- }
-
- private boolean bindsTarget(BcelAdvice munger) {
- UsesTargetVisitor utv = new UsesTargetVisitor();
- munger.getPointcut().accept(utv, null);
- return utv.usesTarget;
- }
-
- private static class UsesThisVisitor extends AbstractPatternNodeVisitor {
- boolean usesThis = false;
-
- @Override
- public Object visit(ThisOrTargetPointcut node, Object data) {
- if (node.isThis() && node.isBinding()) {
- usesThis = true;
- }
- return node;
- }
-
- @Override
- public Object visit(AndPointcut node, Object data) {
- if (!usesThis) {
- node.getLeft().accept(this, data);
- }
- if (!usesThis) {
- node.getRight().accept(this, data);
- }
- return node;
- }
-
- @Override
- public Object visit(NotPointcut node, Object data) {
- if (!usesThis) {
- node.getNegatedPointcut().accept(this, data);
- }
- return node;
- }
-
- @Override
- public Object visit(OrPointcut node, Object data) {
- if (!usesThis) {
- node.getLeft().accept(this, data);
- }
- if (!usesThis) {
- node.getRight().accept(this, data);
- }
- return node;
- }
- }
-
- private static class UsesTargetVisitor extends AbstractPatternNodeVisitor {
- boolean usesTarget = false;
-
- @Override
- public Object visit(ThisOrTargetPointcut node, Object data) {
- if (!node.isThis() && node.isBinding()) {
- usesTarget = true;
- }
- return node;
- }
-
- @Override
- public Object visit(AndPointcut node, Object data) {
- if (!usesTarget) {
- node.getLeft().accept(this, data);
- }
- if (!usesTarget) {
- node.getRight().accept(this, data);
- }
- return node;
- }
-
- @Override
- public Object visit(NotPointcut node, Object data) {
- if (!usesTarget) {
- node.getNegatedPointcut().accept(this, data);
- }
- return node;
- }
-
- @Override
- public Object visit(OrPointcut node, Object data) {
- if (!usesTarget) {
- node.getLeft().accept(this, data);
- }
- if (!usesTarget) {
- node.getRight().accept(this, data);
- }
- return node;
- }
- }
-
- public void weaveAroundClosure(BcelAdvice munger, boolean hasDynamicTest) {
- InstructionFactory fact = getFactory();
-
- enclosingMethod.setCanInline(false);
-
- int linenumber = getSourceLine();
- // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD!
-
- // callbackMethod will be something like: "static final void m_aroundBody0(I)"
- boolean shadowClassIsInterface = getEnclosingClass().isInterface();
- LazyMethodGen callbackMethod = extractShadowInstructionsIntoNewMethod(
- NameMangler.aroundShadowMethodName(getSignature(), getEnclosingClass().getNewGeneratedNameTag()), shadowClassIsInterface?Modifier.PUBLIC:0,
- munger.getSourceLocation(), new ArrayList<String>(),shadowClassIsInterface);
-
- BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(true);
-
- String closureClassName = NameMangler.makeClosureClassName(getEnclosingClass().getType(), getEnclosingClass()
- .getNewGeneratedNameTag());
-
- Member constructorSig = new MemberImpl(Member.CONSTRUCTOR, UnresolvedType.forName(closureClassName), 0, "<init>",
- "([Ljava/lang/Object;)V");
-
- BcelVar closureHolder = null;
-
- // This is not being used currently since getKind() == preinitializaiton
- // cannot happen in around advice
- if (getKind() == PreInitialization) {
- closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE);
- }
-
- InstructionList closureInstantiation = makeClosureInstantiation(constructorSig, closureHolder);
-
- /* LazyMethodGen constructor = */
- makeClosureClassAndReturnConstructor(closureClassName, callbackMethod, makeProceedArgumentMap(adviceVars));
-
- InstructionList returnConversionCode;
- if (getKind() == PreInitialization) {
- returnConversionCode = new InstructionList();
-
- BcelVar stateTempVar = genTempVar(UnresolvedType.OBJECTARRAY);
- closureHolder.appendLoad(returnConversionCode, fact);
-
- returnConversionCode.append(Utility.createInvoke(fact, world, AjcMemberMaker.aroundClosurePreInitializationGetter()));
- stateTempVar.appendStore(returnConversionCode, fact);
-
- Type[] stateTypes = getSuperConstructorParameterTypes();
-
- returnConversionCode.append(InstructionConstants.ALOAD_0); // put "this" back on the stack
- for (int i = 0, len = stateTypes.length; i < len; i++) {
- UnresolvedType bcelTX = BcelWorld.fromBcel(stateTypes[i]);
- ResolvedType stateRTX = world.resolve(bcelTX, true);
- if (stateRTX.isMissing()) {
- world.getLint().cantFindType.signal(
- new String[] { WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,
- bcelTX.getClassName()) }, getSourceLocation(),
- new ISourceLocation[] { munger.getSourceLocation() });
- // IMessage msg = new Message(
- // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE_PREINIT,bcelTX.getClassName()),
- // "",IMessage.ERROR,getSourceLocation(),null,
- // new ISourceLocation[]{ munger.getSourceLocation()});
- // world.getMessageHandler().handleMessage(msg);
- }
- stateTempVar.appendConvertableArrayLoad(returnConversionCode, fact, i, stateRTX);
- }
- } else {
- // pr226201
- Member mungerSignature = munger.getSignature();
- if (munger.getSignature() instanceof ResolvedMember) {
- if (((ResolvedMember) mungerSignature).hasBackingGenericMember()) {
- mungerSignature = ((ResolvedMember) mungerSignature).getBackingGenericMember();
- }
- }
- UnresolvedType returnType = mungerSignature.getReturnType();
- returnConversionCode = Utility.createConversion(getFactory(), BcelWorld.makeBcelType(returnType),
- callbackMethod.getReturnType(), world.isInJava5Mode());
- if (!isFallsThrough()) {
- returnConversionCode.append(InstructionFactory.createReturn(callbackMethod.getReturnType()));
- }
- }
-
- // initialize the bit flags for this shadow
- int bitflags = 0x000000;
- if (getKind().isTargetSameAsThis()) {
- bitflags |= 0x010000;
- }
- if (hasThis()) {
- bitflags |= 0x001000;
- }
- if (bindsThis(munger)) {
- bitflags |= 0x000100;
- }
- if (hasTarget()) {
- bitflags |= 0x000010;
- }
- if (bindsTarget(munger)) {
- bitflags |= 0x000001;
- }
-
- // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance
- if (munger.getConcreteAspect() != null && munger.getConcreteAspect().isAnnotationStyleAspect()
- && munger.getDeclaringAspect() != null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) {
- // stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int
- closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags)));
- closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(),
- new MemberImpl(Member.METHOD, UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
- Modifier.PUBLIC, "linkClosureAndJoinPoint", String.format("%s%s", "(I)", "Lorg/aspectj/lang/ProceedingJoinPoint;"))));
- }
-
- InstructionList advice = new InstructionList();
- advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation));
-
- // invoke the advice
- advice.append(munger.getNonTestAdviceInstructions(this));
- advice.append(returnConversionCode);
- if (getKind() == Shadow.MethodExecution && linenumber > 0) {
- advice.getStart().addTargeter(new LineNumberTag(linenumber));
- }
-
- if (!hasDynamicTest) {
- range.append(advice);
- } else {
- InstructionList callback = makeCallToCallback(callbackMethod);
- InstructionList postCallback = new InstructionList();
- if (terminatesWithReturn()) {
- callback.append(InstructionFactory.createReturn(callbackMethod.getReturnType()));
- } else {
- advice.append(InstructionFactory.createBranchInstruction(Constants.GOTO,
- postCallback.append(InstructionConstants.NOP)));
- }
- range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart()));
- range.append(advice);
- range.append(callback);
- range.append(postCallback);
- }
- }
-
- // exposed for testing
- InstructionList makeCallToCallback(LazyMethodGen callbackMethod) {
- InstructionFactory fact = getFactory();
- InstructionList callback = new InstructionList();
- if (thisVar != null) {
- callback.append(InstructionConstants.ALOAD_0);
- }
- if (targetVar != null && targetVar != thisVar) {
- callback.append(BcelRenderer.renderExpr(fact, world, targetVar));
- }
- callback.append(BcelRenderer.renderExprs(fact, world, argVars));
- // remember to render tjps
- if (thisJoinPointVar != null) {
- callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar));
- }
- callback.append(Utility.createInvoke(fact, callbackMethod));
- return callback;
- }
-
- /** side-effect-free */
- private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) {
-
- // LazyMethodGen constructor) {
- InstructionFactory fact = getFactory();
- BcelVar arrayVar = genTempVar(UnresolvedType.OBJECTARRAY);
- // final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
- final InstructionList il = new InstructionList();
- int alen = getArgCount() + (thisVar == null ? 0 : 1) + ((targetVar != null && targetVar != thisVar) ? 1 : 0)
- + (thisJoinPointVar == null ? 0 : 1);
- il.append(Utility.createConstant(fact, alen));
- il.append(fact.createNewArray(Type.OBJECT, (short) 1));
- arrayVar.appendStore(il, fact);
-
- int stateIndex = 0;
- if (thisVar != null) {
- arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar);
- thisVar.setPositionInAroundState(stateIndex);
- stateIndex++;
- }
- if (targetVar != null && targetVar != thisVar) {
- arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar);
- targetVar.setPositionInAroundState(stateIndex);
- stateIndex++;
- }
- for (int i = 0, len = getArgCount(); i < len; i++) {
- arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]);
- argVars[i].setPositionInAroundState(stateIndex);
- stateIndex++;
- }
- if (thisJoinPointVar != null) {
- arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar);
- thisJoinPointVar.setPositionInAroundState(stateIndex);
- stateIndex++;
- }
- il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName())));
- il.append(InstructionConstants.DUP);
- arrayVar.appendLoad(il, fact);
- il.append(Utility.createInvoke(fact, world, constructor));
- if (getKind() == PreInitialization) {
- il.append(InstructionConstants.DUP);
- holder.appendStore(il, fact);
- }
- return il;
- }
-
- private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) {
- // System.err.println("coming in with " + Arrays.asList(adviceArgs));
-
- IntMap ret = new IntMap();
- for (int i = 0, len = adviceArgs.length; i < len; i++) {
- BcelVar v = adviceArgs[i];
- if (v == null) {
- continue; // XXX we don't know why this is required
- }
- int pos = v.getPositionInAroundState();
- if (pos >= 0) { // need this test to avoid args bound via cflow
- ret.put(pos, i);
- }
- }
- // System.err.println("returning " + ret);
-
- return ret;
- }
-
- /**
- *
- * @param callbackMethod the method we will call back to when our run method gets called.
- * @param proceedMap A map from state position to proceed argument position. May be non covering on state position.
- */
- private LazyMethodGen makeClosureClassAndReturnConstructor(String closureClassName, LazyMethodGen callbackMethod,
- IntMap proceedMap) {
- String superClassName = "org.aspectj.runtime.internal.AroundClosure";
- Type objectArrayType = new ArrayType(Type.OBJECT, 1);
-
- LazyClassGen closureClass = new LazyClassGen(closureClassName, superClassName, getEnclosingClass().getFileName(),
- Modifier.PUBLIC, new String[] {}, getWorld());
- closureClass.setMajorMinor(getEnclosingClass().getMajor(), getEnclosingClass().getMinor());
- InstructionFactory fact = new InstructionFactory(closureClass.getConstantPool());
-
- // constructor
- LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC, Type.VOID, "<init>", new Type[] { objectArrayType },
- new String[] {}, closureClass);
- InstructionList cbody = constructor.getBody();
- cbody.append(InstructionFactory.createLoad(Type.OBJECT, 0));
- cbody.append(InstructionFactory.createLoad(objectArrayType, 1));
- cbody.append(fact
- .createInvoke(superClassName, "<init>", Type.VOID, new Type[] { objectArrayType }, Constants.INVOKESPECIAL));
- cbody.append(InstructionFactory.createReturn(Type.VOID));
-
- closureClass.addMethodGen(constructor);
-
- // Create the 'Object run(Object[])' method
- LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC, Type.OBJECT, "run", new Type[] { objectArrayType },
- new String[] {}, closureClass);
- InstructionList mbody = runMethod.getBody();
- BcelVar proceedVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), 1);
- // int proceedVarIndex = 1;
- BcelVar stateVar = new BcelVar(UnresolvedType.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1));
- // int stateVarIndex = runMethod.allocateLocal(1);
- mbody.append(InstructionFactory.createThis());
- mbody.append(fact.createGetField(superClassName, "state", objectArrayType));
- mbody.append(stateVar.createStore(fact));
- // mbody.append(fact.createStore(objectArrayType, stateVarIndex));
-
- Type[] stateTypes = callbackMethod.getArgumentTypes();
-
- for (int i = 0, len = stateTypes.length; i < len; i++) {
- ResolvedType resolvedStateType = BcelWorld.fromBcel(stateTypes[i]).resolve(world);
- if (proceedMap.hasKey(i)) {
- mbody.append(proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i), resolvedStateType));
- } else {
- mbody.append(stateVar.createConvertableArrayLoad(fact, i, resolvedStateType));
- }
- }
-
- mbody.append(Utility.createInvoke(fact, callbackMethod));
-
- if (getKind() == PreInitialization) {
- mbody.append(Utility.createSet(fact, AjcMemberMaker.aroundClosurePreInitializationField()));
- mbody.append(InstructionConstants.ACONST_NULL);
- } else {
- mbody.append(Utility.createConversion(fact, callbackMethod.getReturnType(), Type.OBJECT));
- }
- mbody.append(InstructionFactory.createReturn(Type.OBJECT));
-
- closureClass.addMethodGen(runMethod);
-
- // class
- getEnclosingClass().addGeneratedInner(closureClass);
-
- return constructor;
- }
-
- // ---- extraction methods
-
- /**
- * Extract the instructions in the shadow to a new method.
- *
- * @param extractedMethodName name for the new method
- * @param extractedMethodVisibilityModifier visibility modifiers for the new method
- * @param adviceSourceLocation source location of the advice affecting the shadow
- * @param beingPlacedInInterface is this new method going into an interface
- */
- LazyMethodGen extractShadowInstructionsIntoNewMethod(String extractedMethodName, int extractedMethodVisibilityModifier,
- ISourceLocation adviceSourceLocation, List<String> parameterNames, boolean beingPlacedInInterface) {
- // LazyMethodGen.assertGoodBody(range.getBody(), extractedMethodName);
- if (!getKind().allowsExtraction()) {
- throw new BCException("Attempt to extract method from a shadow kind (" + getKind()
- + ") that does not support this operation");
- }
- LazyMethodGen newMethod = createShadowMethodGen(extractedMethodName, extractedMethodVisibilityModifier, parameterNames, beingPlacedInInterface);
- IntMap remapper = makeRemap();
- range.extractInstructionsInto(newMethod, remapper, (getKind() != PreInitialization) && isFallsThrough());
- if (getKind() == PreInitialization) {
- addPreInitializationReturnCode(newMethod, getSuperConstructorParameterTypes());
- }
- getEnclosingClass().addMethodGen(newMethod, adviceSourceLocation);
- return newMethod;
- }
-
- private void addPreInitializationReturnCode(LazyMethodGen extractedMethod, Type[] superConstructorTypes) {
- InstructionList body = extractedMethod.getBody();
- final InstructionFactory fact = getFactory();
-
- BcelVar arrayVar = new BcelVar(world.getCoreType(UnresolvedType.OBJECTARRAY), extractedMethod.allocateLocal(1));
-
- int len = superConstructorTypes.length;
-
- body.append(Utility.createConstant(fact, len));
-
- body.append(fact.createNewArray(Type.OBJECT, (short) 1));
- arrayVar.appendStore(body, fact);
-
- for (int i = len - 1; i >= 0; i++) {
- // convert thing on top of stack to object
- body.append(Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT));
- // push object array
- arrayVar.appendLoad(body, fact);
- // swap
- body.append(InstructionConstants.SWAP);
- // do object array store.
- body.append(Utility.createConstant(fact, i));
- body.append(InstructionConstants.SWAP);
- body.append(InstructionFactory.createArrayStore(Type.OBJECT));
- }
- arrayVar.appendLoad(body, fact);
- body.append(InstructionConstants.ARETURN);
- }
-
- private Type[] getSuperConstructorParameterTypes() {
- // assert getKind() == PreInitialization
- InstructionHandle superCallHandle = getRange().getEnd().getNext();
- InvokeInstruction superCallInstruction = (InvokeInstruction) superCallHandle.getInstruction();
- return superCallInstruction.getArgumentTypes(getEnclosingClass().getConstantPool());
- }
-
- /**
- * make a map from old frame location to new frame location. Any unkeyed frame location picks out a copied local
- */
- private IntMap makeRemap() {
- IntMap ret = new IntMap(5);
- int reti = 0;
- if (thisVar != null) {
- ret.put(0, reti++); // thisVar guaranteed to be 0
- }
- if (targetVar != null && targetVar != thisVar) {
- ret.put(targetVar.getSlot(), reti++);
- }
- for (int i = 0, len = argVars.length; i < len; i++) {
- ret.put(argVars[i].getSlot(), reti);
- reti += argVars[i].getType().getSize();
- }
- if (thisJoinPointVar != null) {
- ret.put(thisJoinPointVar.getSlot(), reti++);
- }
- // we not only need to put the arguments, we also need to remap their
- // aliases, which we so helpfully put into temps at the beginning of this join
- // point.
- if (!getKind().argsOnStack()) {
- int oldi = 0;
- int newi = 0;
- // if we're passing in a this and we're not argsOnStack we're always
- // passing in a target too
- if (arg0HoldsThis()) {
- ret.put(0, 0);
- oldi++;
- newi += 1;
- }
- // assert targetVar == thisVar
- for (int i = 0; i < getArgCount(); i++) {
- UnresolvedType type = getArgType(i);
- ret.put(oldi, newi);
- oldi += type.getSize();
- newi += type.getSize();
- }
- }
-
- // System.err.println("making remap for : " + this);
- // if (targetVar != null) System.err.println("target slot : " + targetVar.getSlot());
- // if (thisVar != null) System.err.println(" this slot : " + thisVar.getSlot());
- // System.err.println(ret);
-
- return ret;
- }
-
- /**
- * The new method always static. It may take some extra arguments: this, target. If it's argsOnStack, then it must take both
- * this/target If it's argsOnFrame, it shares this and target. ??? rewrite this to do less array munging, please
- */
- private LazyMethodGen createShadowMethodGen(String newMethodName, int visibilityModifier, List<String> parameterNames, boolean beingPlacedInInterface) {
- Type[] shadowParameterTypes = BcelWorld.makeBcelTypes(getArgTypes());
- int modifiers = (world.useFinal() && !beingPlacedInInterface ? Modifier.FINAL : 0) | Modifier.STATIC | visibilityModifier;
- if (targetVar != null && targetVar != thisVar) {
- UnresolvedType targetType = getTargetType();
- targetType = ensureTargetTypeIsCorrect(targetType);
- // see pr109728,pr229910 - this fixes the case when the declaring class is sometype 'X' but the (gs)etfield
- // in the bytecode refers to a subtype of 'X'. This makes sure we use the type originally
- // mentioned in the fieldget instruction as the method parameter and *not* the type upon which the
- // field is declared because when the instructions are extracted into the new around body,
- // they will still refer to the subtype.
- if ((getKind() == FieldGet || getKind() == FieldSet) && getActualTargetType() != null
- && !getActualTargetType().equals(targetType.getName())) {
- targetType = UnresolvedType.forName(getActualTargetType()).resolve(world);
- }
- ResolvedMember resolvedMember = getSignature().resolve(world);
-
- // pr230075, pr197719
- if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers())
- && !samePackage(resolvedMember.getDeclaringType().getPackageName(), getEnclosingType().getPackageName())
- && !resolvedMember.getName().equals("clone")) {
- if (!hasThis()) { // pr197719 - static accessor has been created to handle the call
- if (Modifier.isStatic(enclosingMethod.getAccessFlags()) && enclosingMethod.getName().startsWith("access$")) {
- targetType = BcelWorld.fromBcel(enclosingMethod.getArgumentTypes()[0]);
- }
- } else {
- if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) {
- throw new BCException("bad bytecode");
- }
- targetType = getThisType();
- }
- }
- parameterNames.add("target");
- // There is a 'target' and it is not the same as 'this', so add it to the parameter list
- shadowParameterTypes = addTypeToFront(BcelWorld.makeBcelType(targetType), shadowParameterTypes);
- }
-
- if (thisVar != null) {
- UnresolvedType thisType = getThisType();
- parameterNames.add(0, "ajc$this");
- shadowParameterTypes = addTypeToFront(BcelWorld.makeBcelType(thisType), shadowParameterTypes);
- }
-
- if (this.getKind() == Shadow.FieldSet || this.getKind() == Shadow.FieldGet) {
- parameterNames.add(getSignature().getName());
- } else {
- String[] pnames = getSignature().getParameterNames(world);
- if (pnames != null) {
- for (int i = 0; i < pnames.length; i++) {
- if (i == 0 && pnames[i].equals("this")) {
- parameterNames.add("ajc$this");
- } else {
- parameterNames.add(pnames[i]);
- }
- }
- }
- }
-
- // We always want to pass down thisJoinPoint in case we have already woven
- // some advice in here. If we only have a single piece of around advice on a
- // join point, it is unnecessary to accept (and pass) tjp.
- if (thisJoinPointVar != null) {
- parameterNames.add("thisJoinPoint");
- shadowParameterTypes = addTypeToEnd(LazyClassGen.tjpType, shadowParameterTypes);
- }
-
- UnresolvedType returnType;
- if (getKind() == PreInitialization) {
- returnType = UnresolvedType.OBJECTARRAY;
- } else {
- if (getKind() == ConstructorCall) {
- returnType = getSignature().getDeclaringType();
- } else if (getKind() == FieldSet) {
- returnType = UnresolvedType.VOID;
- } else {
- returnType = getSignature().getReturnType().resolve(world);
- // returnType = getReturnType(); // for this and above lines, see pr137496
- }
- }
- return new LazyMethodGen(modifiers, BcelWorld.makeBcelType(returnType), newMethodName, shadowParameterTypes,
- NoDeclaredExceptions, getEnclosingClass());
- }
-
- private boolean samePackage(String p1, String p2) {
- if (p1 == null) {
- return p2 == null;
- }
- if (p2 == null) {
- return false;
- }
- return p1.equals(p2);
- }
-
- private Type[] addTypeToFront(Type type, Type[] types) {
- int len = types.length;
- Type[] ret = new Type[len + 1];
- ret[0] = type;
- System.arraycopy(types, 0, ret, 1, len);
- return ret;
- }
-
- private Type[] addTypeToEnd(Type type, Type[] types) {
- int len = types.length;
- Type[] ret = new Type[len + 1];
- ret[len] = type;
- System.arraycopy(types, 0, ret, 0, len);
- return ret;
- }
-
- public BcelVar genTempVar(UnresolvedType utype) {
- ResolvedType rtype = utype.resolve(world);
- return new BcelVar(rtype, genTempVarIndex(rtype.getSize()));
- }
-
- // public static final boolean CREATE_TEMP_NAMES = true;
-
- public BcelVar genTempVar(UnresolvedType typeX, String localName) {
- BcelVar tv = genTempVar(typeX);
-
- // if (CREATE_TEMP_NAMES) {
- // for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
- // if (Range.isRangeHandle(ih)) continue;
- // ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot()));
- // }
- // }
- return tv;
- }
-
- // eh doesn't think we need to garbage collect these (64K is a big number...)
- private int genTempVarIndex(int size) {
- return enclosingMethod.allocateLocal(size);
- }
-
- public InstructionFactory getFactory() {
- return getEnclosingClass().getFactory();
- }
-
- @Override
- public ISourceLocation getSourceLocation() {
- int sourceLine = getSourceLine();
- if (sourceLine == 0 || sourceLine == -1) {
- // Thread.currentThread().dumpStack();
- // System.err.println(this + ": " + range);
- return getEnclosingClass().getType().getSourceLocation();
- } else {
- // For staticinitialization, if we have a nice offset, don't build a new source loc
- if (getKind() == Shadow.StaticInitialization && getEnclosingClass().getType().getSourceLocation().getOffset() != 0) {
- return getEnclosingClass().getType().getSourceLocation();
- } else {
- int offset = 0;
- Kind kind = getKind();
- if ((kind == MethodExecution) || (kind == ConstructorExecution) || (kind == AdviceExecution)
- || (kind == StaticInitialization) || (kind == PreInitialization) || (kind == Initialization)) {
- if (getEnclosingMethod().hasDeclaredLineNumberInfo()) {
- offset = getEnclosingMethod().getDeclarationOffset();
- }
- }
- return getEnclosingClass().getType().getSourceContext().makeSourceLocation(sourceLine, offset);
- }
- }
- }
-
- public Shadow getEnclosingShadow() {
- return enclosingShadow;
- }
-
- public LazyMethodGen getEnclosingMethod() {
- return enclosingMethod;
- }
-
- public boolean isFallsThrough() {
- return !terminatesWithReturn();
- }
-
- public void setActualTargetType(String className) {
- this.actualInstructionTargetType = className;
- }
-
- public String getActualTargetType() {
- return actualInstructionTargetType;
- }
- }
|