1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556 |
- /* *******************************************************************
- * 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.Field;
- import org.aspectj.apache.bcel.generic.ACONST_NULL;
- import org.aspectj.apache.bcel.generic.ALOAD;
- import org.aspectj.apache.bcel.generic.ANEWARRAY;
- import org.aspectj.apache.bcel.generic.ArrayType;
- import org.aspectj.apache.bcel.generic.BranchInstruction;
- import org.aspectj.apache.bcel.generic.ConstantPoolGen;
- import org.aspectj.apache.bcel.generic.DUP;
- import org.aspectj.apache.bcel.generic.DUP_X1;
- import org.aspectj.apache.bcel.generic.FieldInstruction;
- import org.aspectj.apache.bcel.generic.INVOKEINTERFACE;
- import org.aspectj.apache.bcel.generic.INVOKESPECIAL;
- import org.aspectj.apache.bcel.generic.INVOKESTATIC;
- import org.aspectj.apache.bcel.generic.Instruction;
- 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.InstructionList;
- import org.aspectj.apache.bcel.generic.InstructionTargeter;
- import org.aspectj.apache.bcel.generic.InvokeInstruction;
- import org.aspectj.apache.bcel.generic.LoadInstruction;
- import org.aspectj.apache.bcel.generic.LocalVariableTag;
- import org.aspectj.apache.bcel.generic.MULTIANEWARRAY;
- import org.aspectj.apache.bcel.generic.NEW;
- import org.aspectj.apache.bcel.generic.ObjectType;
- import org.aspectj.apache.bcel.generic.PUSH;
- import org.aspectj.apache.bcel.generic.RETURN;
- import org.aspectj.apache.bcel.generic.ReturnInstruction;
- import org.aspectj.apache.bcel.generic.SWAP;
- import org.aspectj.apache.bcel.generic.StoreInstruction;
- 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.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.AndPointcut;
- import org.aspectj.weaver.patterns.IdentityPointcutVisitor;
- import org.aspectj.weaver.patterns.NotPointcut;
- import org.aspectj.weaver.patterns.OrPointcut;
- import org.aspectj.weaver.patterns.Pointcut;
- 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 ShadowRange range;
- private final BcelWorld world;
- private final LazyMethodGen enclosingMethod;
- // private boolean fallsThrough; //XXX not used anymore
-
- // SECRETAPI - for testing, this will tell us if the optimization 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;
-
- // ---- initialization
-
- /**
- * 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;
- // fallsThrough = kind.argsOnStack();
- }
-
- // ---- 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 src = mungers;
- if (s.mungers==Collections.EMPTY_LIST) s.mungers = new ArrayList();
- List dest = s.mungers;
-
- for (Iterator i = src.iterator(); i.hasNext(); ) {
- dest.add(i.next());
- }
- }
- return s;
- }
-
- // ---- overridden behaviour
-
- public World getIWorld() {
- return world;
- }
-
-
-
- private void deleteNewAndDup() {
- final ConstantPoolGen cpg = getEnclosingClass().getConstantPoolGen();
- int depth = 1;
- InstructionHandle ih = range.getStart();
-
- while (true) {
- Instruction inst = ih.getInstruction();
- if (inst instanceof INVOKESPECIAL
- && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) {
- depth++;
- } else if (inst instanceof NEW) {
- depth--;
- if (depth == 0) break;
- }
- ih = ih.getPrev();
- }
- // 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() instanceof DUP) {
- nextHandle = endHandle.getNext();
- retargetFrom(newHandle, nextHandle);
- retargetFrom(endHandle, nextHandle);
- } else if (endHandle.getInstruction() instanceof DUP_X1) {
- InstructionHandle dupHandle = endHandle;
- endHandle = endHandle.getNext();
- nextHandle = endHandle.getNext();
- if (endHandle.getInstruction() instanceof SWAP) {}
- 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);
- 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");
- }
- }
- private void retargetFrom(InstructionHandle old, InstructionHandle fresh) {
- InstructionTargeter[] sources = old.getTargeters();
- if (sources != null) {
- for (int i = sources.length - 1; i >= 0; i--) {
- if (sources[i] instanceof ExceptionRange) {
- ExceptionRange it = (ExceptionRange)sources[i];
- System.err.println("...");
- it.updateTarget(old,fresh,it.getBody());
- } else {
- sources[i].updateTarget(old, fresh);
- }
- }
- }
- }
-
- // records advice that is stopping us doing the lazyTjp optimization
- private List badAdvice = null;
-
- public void addAdvicePreventingLazyTjp(BcelAdvice advice) {
- if (badAdvice == null) badAdvice = new ArrayList();
- badAdvice.add(advice);
- }
-
- 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.
- if (getKind() == ConstructorCall) {
- if (!world.isJoinpointArrayConstructionEnabled() || !this.getSignature().getDeclaringType().isArray())
- 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
- InstructionTargeter[] targeters = start.getTargeters();
- for (int i = 0; i < targeters.length; i++) {
- InstructionTargeter t = targeters[i];
- 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 (Iterator iter = mungers.iterator(); iter.hasNext();) {
- ShadowMunger munger = (ShadowMunger) iter.next();
- 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 iter = badAdvice.iterator(); iter.hasNext();) {
- BcelAdvice element = (BcelAdvice) 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 iter = badAdvice.iterator(); iter.hasNext();) {
- BcelAdvice element = (BcelAdvice) 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()) {
- range.insert((Instruction) 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;
- }
-
- 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.
- Kind kind = getKind();
- if ( (kind == MethodExecution) ||
- (kind == ConstructorExecution) ||
- (kind == AdviceExecution) ||
- (kind == StaticInitialization) ||
- (kind == PreInitialization) ||
- (kind == Initialization)) {
- if (getEnclosingMethod().hasDeclaredLineNumberInfo()) {
- return getEnclosingMethod().getDeclarationLineNumber();
- }
- }
-
- if (range == null) {
- if (getEnclosingMethod().hasBody()) {
- return Utility.getSourceLine(getEnclosingMethod().getBody().getStart());
- } else {
- return 0;
- }
- }
- int ret = Utility.getSourceLine(range.getStart());
- if (ret < 0) return 0;
- return ret;
- }
-
- // overrides
- public UnresolvedType 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.makeJoinPointSignature(enclosingMethod),
- 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().getConstantPoolGen())
- .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().getConstantPoolGen()).equals(NameMangler.AJC_POST_CLINIT_NAME)) {
- // clinitEnd = clinitEnd.getPrev();
- // }
- // }
-
-
-
- BcelShadow s =
- new BcelShadow(
- world,
- StaticInitialization,
- world.makeJoinPointSignature(enclosingMethod),
- 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() instanceof StoreInstruction &&
- startOfHandler.getNext() != null)
- {
- int slot = ((StoreInstruction)startOfHandler.getInstruction()).getIndex();
- //System.out.println("got store: " + startOfHandler.getInstruction() + ", " + index);
- InstructionTargeter[] targeters = startOfHandler.getNext().getTargeters();
- if (targeters!=null) {
- for (int i=targeters.length-1; i >= 0; i--) {
- if (targeters[i] instanceof LocalVariableTag) {
- LocalVariableTag t = (LocalVariableTag)targeters[i];
- if (t.getSlot() == slot) {
- return t.getName();
- }
- //System.out.println("tag: " + targeters[i]);
- }
- }
- }
- }
-
- 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.makeJoinPointSignature(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.makeJoinPointSignature(constructor),
- constructor,
- null);
- // ret.fallsThrough = true;
- 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()); //world.makeMethodSignature(enclosingMethod));
- }
-
-
- 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(
- 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,
- LazyMethodGen enclosingMethod,
- InstructionHandle setHandle,
- BcelShadow enclosingShadow)
- {
- final InstructionList body = enclosingMethod.getBody();
- BcelShadow s =
- new BcelShadow(
- world,
- FieldSet,
- 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) {
- InstructionTargeter[] sources = from.getTargeters();
- if (sources != null) {
- for (int i = sources.length - 1; i >= 0; i--) {
- InstructionTargeter source = sources[i];
- if (source instanceof BranchInstruction) {
- 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 !getSignature().isStatic();
- } 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/*<UnresolvedType,BcelVar>*/ kindedAnnotationVars = null;
- private Map/*<UnresolvedType,BcelVar>*/ thisAnnotationVars = null;
- private Map/*<UnresolvedType,BcelVar>*/ targetAnnotationVars = null;
- private Map/*<UnresolvedType,BcelVar>*/[] argAnnotationVars = null;
- private Map/*<UnresolvedType,BcelVar>*/ withinAnnotationVars = null;
- private Map/*<UnresolvedType,BcelVar>*/ withincodeAnnotationVars = null;
-
- public Var getThisVar() {
- if (!hasThis()) {
- throw new IllegalStateException("no this");
- }
- initializeThisVar();
- return thisVar;
- }
- 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 = (Var) thisAnnotationVars.get(forAnnotationType);
- if (v==null)
- v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getThisVar());
- return v;
- }
- public Var getTargetVar() {
- if (!hasTarget()) {
- throw new IllegalStateException("no target");
- }
- initializeTargetVar();
- return targetVar;
- }
- 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 =(Var) 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;
- }
- public Var getArgVar(int i) {
- initializeArgVars();
- return argVars[i];
- }
- public Var getArgAnnotationVar(int i,UnresolvedType forAnnotationType) {
- initializeArgAnnotationVars();
-
- Var v= (Var) argAnnotationVars[i].get(forAnnotationType);
- if (v==null)
- v = new TypeAnnotationAccessVar(forAnnotationType.resolve(world),(BcelVar)getArgVar(i));
- return v;
- }
- public Var getKindedAnnotationVar(UnresolvedType forAnnotationType) {
- initializeKindedAnnotationVars();
- return (Var) kindedAnnotationVars.get(forAnnotationType);
- }
- public Var getWithinAnnotationVar(UnresolvedType forAnnotationType) {
- initializeWithinAnnotationVars();
- return (Var) withinAnnotationVars.get(forAnnotationType);
- }
- public Var getWithinCodeAnnotationVar(UnresolvedType forAnnotationType) {
- initializeWithinCodeAnnotationVars();
- return (Var) 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;
-
- public final Var getThisJoinPointStaticPartVar() {
- return getThisJoinPointStaticPartBcelVar();
- }
- 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"));
- }
- }
-
-
- 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 i = mungers.iterator(); i.hasNext();) {
- ShadowMunger munger = (ShadowMunger) 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(new ACONST_NULL());
- }
- if (hasTarget()) {
- ((BcelVar)getTargetVar()).appendLoad(il, fact);
- } else {
- il.append(new 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;
- }
-
- /**
- * Get the Var for the jpStaticPart
- * @return
- */
- public BcelVar getThisJoinPointStaticPartBcelVar() {
- return getThisJoinPointStaticPartBcelVar(false);
- }
-
- /**
- * 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.forName("org.aspectj.lang.JoinPoint$StaticPart"));
- } else {
- sjpType = isEnclosingJp?
- world.getCoreType(UnresolvedType.forName("org.aspectj.lang.JoinPoint$EnclosingStaticPart")):
- world.getCoreType(UnresolvedType.forName("org.aspectj.lang.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
- 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();
- }
- }
-
-
- 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((Instruction)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() instanceof StoreInstruction) { // 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() instanceof LoadInstruction) {
- LoadInstruction li = (LoadInstruction)searchPtr.getInstruction();
- li.getIndex();
- LocalVariableTag lvt = LazyMethodGen.getLocalVariableTag(searchPtr,li.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().getConstantPoolGen());
- return BcelWorld.fromBcel(t);
- }
- // A new array instruction obviously tells us it is an array type !
- if (searchPtr.getInstruction() instanceof ANEWARRAY) {
- //ANEWARRAY ana = (ANEWARRAY)searchPoint.getInstruction();
- //Type t = ana.getType(getEnclosingClass().getConstantPoolGen());
- // 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().getConstantPoolGen());
- // 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 initializeArgVars() {
- if (argVars != null) return;
- InstructionFactory fact = getFactory();
- int len = getArgCount();
- 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);
- BcelVar tmp = genTempVar(type, "ajc$arg" + i);
- range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore);
- argVars[i] = tmp;
- int position = i;
- position += positionOffset;
- // System.out.println("set position: " + tmp + ", " + position + " in " + this);
- // System.out.println(" hasThis: " + hasThis() + ", hasTarget: " + hasTarget());
- tmp.setPositionInAroundState(position);
- index += type.getSize();
- }
- }
- }
- 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();
- // populate..
- }
- public void initializeTargetAnnotationVars() {
- if (targetAnnotationVars != null) return;
- if (getKind().isTargetSameAsThis()) {
- if (hasThis()) initializeThisAnnotationVars();
- targetAnnotationVars = thisAnnotationVars;
- } else {
- targetAnnotationVars = new HashMap();
- 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 Member getRelevantMember(Member 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 mungers = relevantType.resolve(world).getInterTypeMungers();
- for (Iterator iter = mungers.iterator(); iter.hasNext();) {
- BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
- 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,
- (ResolvedMember)foundMember,
- typeMunger.getAspectType());
- } else {
- foundMember = AjcMemberMaker.interMethod((ResolvedMember)foundMember,
- typeMunger.getAspectType(), false);
- }
- // 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(Member foundMember, Member relevantMember, ResolvedType relevantType){
- if (foundMember == null){
- // check the ITD'd dooberries
- List mungers = relevantType.resolve(world).getInterTypeMungers();
- for (Iterator iter = mungers.iterator(); iter.hasNext();) {
- BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
- 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();
- }
-
- public void initializeKindedAnnotationVars() {
- if (kindedAnnotationVars != null) return;
- kindedAnnotationVars = new HashMap();
- // 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 (UnresolvedType).
-
- // FIXME asc Refactor this code, there is duplication
- ResolvedType[] annotations = null;
- Member relevantMember = getSignature();
- ResolvedType relevantType = relevantMember.getDeclaringType().resolve(world);
- if (relevantType.isRawType() || relevantType.isParameterizedType()) relevantType = relevantType.getGenericType();
-
- if (getKind() == Shadow.StaticInitialization) {
- annotations = relevantType.resolve(world).getAnnotationTypes();
-
- } else if (getKind() == Shadow.MethodCall || getKind() == Shadow.ConstructorCall) {
- Member foundMember = findMethod2(relevantType.resolve(world).getDeclaredMethods(),getSignature());
- annotations = getAnnotations(foundMember, relevantMember, relevantType);
- relevantMember = getRelevantMember(foundMember,relevantMember,relevantType);
- relevantType = relevantMember.getDeclaringType().resolve(world);
-
- } else if (getKind() == Shadow.FieldSet || getKind() == Shadow.FieldGet) {
- relevantMember = findField(relevantType.getDeclaredFields(),getSignature());
-
- if (relevantMember==null) {
- // check the ITD'd dooberries
- List mungers = relevantType.resolve(world).getInterTypeMungers();
- for (Iterator iter = mungers.iterator(); iter.hasNext();) {
- BcelTypeMunger typeMunger = (BcelTypeMunger) iter.next();
- 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();
- relevantMember = rmm;
- }
- }
- }
- }
- annotations = relevantMember.getAnnotationTypes();
-
- } else if (getKind() == Shadow.MethodExecution || getKind() == Shadow.ConstructorExecution ||
- getKind() == Shadow.AdviceExecution) {
- //ResolvedMember rm[] = relevantType.getDeclaredMethods();
- Member foundMember = findMethod2(relevantType.getDeclaredMethods(),getSignature());
-
- annotations = getAnnotations(foundMember, relevantMember, relevantType);
- relevantMember = foundMember;
- relevantMember = getRelevantMember(foundMember, relevantMember,relevantType);
-
- } 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("Couldn't discover annotations for shadow: "+getKind());
- }
-
- for (int i = 0; i < annotations.length; i++) {
- ResolvedType aTX = annotations[i];
- KindedAnnotationAccessVar kaav = new KindedAnnotationAccessVar(getKind(),aTX.resolve(world),relevantType,relevantMember);
- kindedAnnotationVars.put(aTX,kaav);
- }
- }
-
- //FIXME asc whats the real diff between this one and the version in findMethod()?
- ResolvedMember findMethod2(ResolvedMember rm[], Member sig) {
- ResolvedMember found = null;
- // String searchString = getSignature().getName()+getSignature().getParameterSignature();
- for (int i = 0; i < rm.length && found==null; i++) {
- ResolvedMember member = rm[i];
- if (member.getName().equals(sig.getName()) && member.getParameterSignature().equals(sig.getParameterSignature()))
- found = member;
- }
- return found;
- }
-
- 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[] 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 KindedAnnotationAccessVar(k,ann,getEnclosingType(),null));
- }
- }
-
- public void initializeWithinCodeAnnotationVars() {
- if (withincodeAnnotationVars != null) return;
- withincodeAnnotationVars = new HashMap();
-
- // 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 KindedAnnotationAccessVar(k,ann,getEnclosingType(),getEnclosingCodeSignature()));
- }
- }
-
-
- // ---- 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 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 i = returns.iterator(); i.hasNext();) {
- InstructionHandle ih = (InstructionHandle) 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 findReturnInstructions() {
- List returns = new ArrayList();
- for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
- if (ih.getInstruction() instanceof ReturnInstruction) {
- 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 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 = (InstructionHandle)returns.get(i);
- if (!(ih.getInstruction() instanceof RETURN)) {
- newReturnInstruction = Utility.copyInstruction(ih.getInstruction());
- }
- i--;
- }
- returnValueVar = genTempVar(this.getReturnType());
- returnValueVar.appendLoad(returnInstructions,getFactory());
- returnInstructions.append(newReturnInstruction);
- } else {
- InstructionHandle lastReturnHandle = (InstructionHandle)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() != ResolvedType.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(ResolvedType.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));
- BranchInstruction 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) {
-
- if (t.resolve(world).isInterface()) return; // Don't initialize statics in
- final InstructionFactory fact = getFactory();
-
- InstructionList entryInstructions = new InstructionList();
- InstructionList entrySuccessInstructions = new InstructionList();
-
- BcelWorld.getBcelObjectType(munger.getConcreteAspect());
- String aspectname = munger.getConcreteAspect().getName();
-
- String ptwField = NameMangler.perTypeWithinFieldForTarget(munger.getConcreteAspect());
- entrySuccessInstructions.append(new 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;
-
- final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
- final InstructionFactory fact = getFactory();
-
- final BcelVar testResult = genTempVar(ResolvedType.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(
- (Instruction) 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);
- }
-
- // this is the same for both per and non-per
- weaveAfter(new BcelAdvice(null, null, null, 0, 0, 0, null, null) {
- 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;
- }
- });
-
-
- 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 declaringType = world.resolve(mungerSig.getDeclaringType(),true);
- if (declaringType.isMissing()) {
- world.getLint().cantFindType.signal(
- new String[] {WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName())},
- getSourceLocation(),
- new ISourceLocation[]{ munger.getSourceLocation()}
- );
- // IMessage msg = new Message(
- // WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE_DURING_AROUND_WEAVE,declaringType.getClassName()),
- // "",IMessage.ERROR,getSourceLocation(),null,
- // new ISourceLocation[]{ munger.getSourceLocation()});
- // world.getMessageHandler().handleMessage(msg);
- }
- //??? might want some checks here to give better errors
- ResolvedType rt = (declaringType.isParameterizedType()?declaringType.getGenericType():declaringType);
- BcelObjectType ot = BcelWorld.getBcelObjectType(rt);
- // if (ot==null) {
- // world.getMessageHandler().handleMessage(
- // MessageUtil.warn("Unable to find modifiable delegate for the aspect '"+rt.getName()+"' containing around advice - cannot implement inlining",munger.getSourceLocation()));
- // weaveAroundClosure(munger, hasDynamicTest);
- // return;
- // }
- LazyMethodGen adviceMethod = ot.getLazyClassGen().getLazyMethodGen(mungerSig);
- if (!adviceMethod.getCanInline()) {
- weaveAroundClosure(munger, hasDynamicTest);
- return;
- }
-
- // specific test for @AJ proceedInInners
- 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();
- ConstantPoolGen cpg = adviceMethod.getEnclosingClass().getConstantPoolGen();
- 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;
- }
- }
-
-
-
- // 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.
- //??? should consider optimizations to recognize simple cases that don't require body extraction
- enclosingMethod.setCanInline(false);
-
- // start by exposing various useful things into the frame
- final InstructionFactory fact = getFactory();
-
- // now generate the aroundBody method
- // eg. "private static final void method_aroundBody0(M, M, String, org.aspectj.lang.JoinPoint)"
- LazyMethodGen extractedMethod =
- extractMethod(
- NameMangler.aroundCallbackMethodName(getSignature(),getEnclosingClass()),
- Modifier.PRIVATE,
- munger);
-
- // now extract the advice into its own method
- String adviceMethodName =
- NameMangler.aroundCallbackMethodName(getSignature(),getEnclosingClass()) + "$advice";
-
- List argVarList = new ArrayList();
- List proceedVarList = new ArrayList();
- 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) {
- argVarList.add(thisVar);
- proceedVarList.add(new BcelVar(thisVar.getType(), extraParamOffset));
- extraParamOffset += thisVar.getType().getSize();
- }
-
- if (targetVar != null && targetVar != thisVar) {
- argVarList.add(targetVar);
- proceedVarList.add(new BcelVar(targetVar.getType(), extraParamOffset));
- extraParamOffset += targetVar.getType().getSize();
- }
- for (int i = 0, len = getArgCount(); i < len; i++) {
- argVarList.add(argVars[i]);
- proceedVarList.add(new BcelVar(argVars[i].getType(), extraParamOffset));
- extraParamOffset += argVars[i].getType().getSize();
- }
- if (thisJoinPointVar != null) {
- argVarList.add(thisJoinPointVar);
- proceedVarList.add(new BcelVar(thisJoinPointVar.getType(), extraParamOffset));
- extraParamOffset += thisJoinPointVar.getType().getSize();
- }
-
- Type[] adviceParameterTypes = adviceMethod.getArgumentTypes();
- Type[] extractedMethodParameterTypes = extractedMethod.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);
-
- LazyMethodGen localAdviceMethod =
- new LazyMethodGen(
- Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC,
- BcelWorld.makeBcelType(mungerSig.getReturnType()),
- adviceMethodName,
- parameterTypes,
- new String[0],
- getEnclosingClass());
-
- String donorFileName = adviceMethod.getEnclosingClass().getInternalFileName();
- String recipientFileName = getEnclosingClass().getInternalFileName();
- // System.err.println("donor " + donorFileName);
- // System.err.println("recip " + recipientFileName);
- if (! donorFileName.equals(recipientFileName)) {
- localAdviceMethod.fromFilename = donorFileName;
- getEnclosingClass().addInlinedSourceFileInfo(
- donorFileName,
- adviceMethod.highestLineNumber);
- }
-
- getEnclosingClass().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);
- }
-
- localAdviceMethod.getBody().insert(
- BcelClassWeaver.genInlineInstructions(adviceMethod,
- localAdviceMethod, varMap, fact, true));
-
-
-
- localAdviceMethod.setMaxLocals(nVars);
-
- //System.err.println(localAdviceMethod);
-
-
- // 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 i = argVarList.iterator(); i.hasNext(); ) {
- BcelVar var = (BcelVar)i.next();
- var.appendLoad(advice, fact);
- }
- // ??? we don't actually need to push NULL for the closure if we take care
- advice.append(
- munger.getAdviceArgSetup(
- this,
- null,
- (munger.getConcreteAspect().isAnnotationStyleAspect() && munger.getDeclaringAspect()!=null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect())?
- this.loadThisJoinPoint():
- new InstructionList(InstructionConstants.ACONST_NULL)));
- // adviceMethodInvocation =
- advice.append(
- Utility.createInvoke(fact, localAdviceMethod)); //(fact, getWorld(), munger.getSignature()));
- advice.append(
- Utility.createConversion(
- getFactory(),
- BcelWorld.makeBcelType(mungerSig.getReturnType()),
- extractedMethod.getReturnType(),world.isInJava5Mode()));
- if (! isFallsThrough()) {
- advice.append(InstructionFactory.createReturn(extractedMethod.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(extractedMethod);
- if (terminatesWithReturn()) {
- callback.append(
- InstructionFactory.createReturn(extractedMethod.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.getConcreteAspect().isAnnotationStyleAspect()) {
- String proceedName =
- NameMangler.proceedMethodName(munger.getSignature().getName());
-
- InstructionHandle curr = localAdviceMethod.getBody().getStart();
- InstructionHandle end = localAdviceMethod.getBody().getEnd();
- ConstantPoolGen cpg = localAdviceMethod.getEnclosingClass().getConstantPoolGen();
- while (curr != end) {
- InstructionHandle next = curr.getNext();
- Instruction inst = curr.getInstruction();
- if ((inst instanceof INVOKESTATIC)
- && proceedName.equals(((INVOKESTATIC) inst).getMethodName(cpg))) {
-
- localAdviceMethod.getBody().append(
- curr,
- getRedoneProceedCall(
- fact,
- extractedMethod,
- 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();
- ConstantPoolGen cpg = localAdviceMethod.getEnclosingClass().getConstantPoolGen();
- 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,
- extractedMethod,
- munger,
- localAdviceMethod,
- proceedVarList,
- isProceedWithArgs
- );
- localAdviceMethod.getBody().append(curr, insteadProceedIl);
- Utility.deleteInstruction(curr, localAdviceMethod);
- }
- curr = next;
- }
- }
- }
-
- private InstructionList getRedoneProceedCall(
- InstructionFactory fact,
- LazyMethodGen callbackMethod,
- BcelAdvice munger,
- LazyMethodGen localAdviceMethod,
- List 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 {
- ((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 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;
- }
- }
-
- /**
- * ATAJ Handle the inlining for @AJ aspects
- *
- */
- private InstructionList getRedoneProceedCallForAnnotationStyle(
- InstructionFactory fact,
- LazyMethodGen callbackMethod,
- BcelAdvice munger,
- LazyMethodGen localAdviceMethod,
- List argVarList,
- boolean isProceedWithArgs)
- {
- // Notes:
- // proceedingjp is on stack (since user was calling pjp.proceed(...)
-
- // new Object[]{new Integer(argAdvice1-1)};// arg of proceed
- // call to proceed(..) is NOT made
- // instead we do
- // itar callback args i
- // get from array i, convert it to the callback arg i
- // if ask for JP, push the one we got on the stack
- // invoke callback, create conversion back to Object/Integer
-
- // rest of method -- (hence all those conversions)
- // intValue() from original code
- // int res = .. from original code
-
- //Note: we just don't care about the proceed map etc
- // (we would need to care if we allow repositioning of arguments in advice signature)
-
- 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.getType("[Ljava/lang/Object;");
- int localProceedArgArray = localAdviceMethod.allocateLocal(objectArrayType);
- ret.append(InstructionFactory.createStore(objectArrayType, localProceedArgArray));
-
- // STORE the ProceedingJoinPoint instance into a local variable
- Type proceedingJpType = Type.getType("Lorg/aspectj/lang/ProceedingJoinPoint;");
- int localJp = localAdviceMethod.allocateLocal(proceedingJpType);
- ret.append(InstructionFactory.createStore(proceedingJpType, localJp));
-
- // push on stack each element of the object array
- // that is assumed to be consistent with the callback argument (ie munger args)
- // TODO do we want to try catch ClassCast and AOOBE exception ?
-
- // special logic when withincode is static or not
-
- // This next bit of code probably makes more sense if you read its implementation for
- // weaveAroundClosure() - see JoinPointImpl.proceed(Object[]). Basically depending
- // on whether the join point has a this/target and whether the pointcut binds this/target
- // then the arguments to the 'new' proceed call need to be reorganized. (pr126167)
- boolean relatedPointcutBindsThis = bindsThis(munger);
- boolean relatedPointcutBindsTarget = bindsTarget(munger);
- boolean targetIsSameAsThis = getKind().isTargetSameAsThis();
-
- // two numbers can differ because a pointcut may bind both this/target and yet at the
- // join point this and target are the same (eg. call)
- int indexIntoObjectArrayForArguments=0;
- int indexIntoCallbackMethodForArguments = 0;
- if (hasThis()) {
- if (relatedPointcutBindsThis) {
- if (!(relatedPointcutBindsTarget && targetIsSameAsThis)) {
- // they have supplied new this as first entry in object array
- ret.append(InstructionFactory.createLoad(objectArrayType, localProceedArgArray));
- ret.append(Utility.createConstant(fact, 0));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[0]));
- indexIntoCallbackMethodForArguments++;
- }
- indexIntoObjectArrayForArguments=1;
- } else {
- // use local variable 0 (which is 'this' for a non-static method)
- ret.append(new ALOAD(0));
- indexIntoCallbackMethodForArguments++;
- }
- }
-
- if (hasTarget()) {
- if (relatedPointcutBindsTarget) {
- if (getKind().isTargetSameAsThis()) {
- ret.append(InstructionFactory.createLoad(objectArrayType, localProceedArgArray));
- ret.append(Utility.createConstant(fact, relatedPointcutBindsThis?1:0));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[0]));
- indexIntoObjectArrayForArguments++;
- indexIntoCallbackMethodForArguments++;
- } else {
- int position =(hasThis()&& relatedPointcutBindsThis?1:0);
- ret.append(InstructionFactory.createLoad(objectArrayType, localProceedArgArray));
- ret.append(Utility.createConstant(fact, position));
- ret.append(InstructionFactory.createArrayLoad(Type.OBJECT));
- ret.append(Utility.createConversion(fact,Type.OBJECT,callbackMethod.getArgumentTypes()[position]));
- indexIntoObjectArrayForArguments=position+1;
- indexIntoCallbackMethodForArguments++;
- }
- } else {
- if (getKind().isTargetSameAsThis()) {
- //ret.append(new ALOAD(0));
- } else {
- ret.append(InstructionFactory.createLoad(localAdviceMethod.getArgumentTypes()[0],hasThis()?1:0));
- indexIntoCallbackMethodForArguments++;
- }
- }
- }
-
-
- for (int i = indexIntoCallbackMethodForArguments, len=callbackMethod.getArgumentTypes().length; i < len; i++) {
- Type stateType = callbackMethod.getArgumentTypes()[i];
- BcelWorld.fromBcel(stateType).resolve(world);
- if ("Lorg/aspectj/lang/JoinPoint;".equals(stateType.getSignature())) {
- ret.append(new ALOAD(localJp));// from localAdvice signature
- } else {
- ret.append(InstructionFactory.createLoad(objectArrayType, localProceedArgArray));
- ret.append(Utility.createConstant(fact, i-indexIntoCallbackMethodForArguments +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));
-
- 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(new ALOAD(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 ?
- //
- } else {
- ret.append(InstructionFactory.createLoad(stateType, i));
- }
- }
- }
-
- // 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())
- ));
-
- 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 IdentityPointcutVisitor {
- boolean usesThis = false;
-
- public Object visit(ThisOrTargetPointcut node, Object data) {
- if (node.isThis() && node.isBinding()) usesThis=true;
- return node;
- }
-
- public Object visit(AndPointcut node, Object data) {
- if (!usesThis) node.getLeft().accept(this, data);
- if (!usesThis) node.getRight().accept(this, data);
- return node;
- }
-
- public Object visit(NotPointcut node, Object data) {
- if (!usesThis) node.getNegatedPointcut().accept(this, data);
- return node;
- }
-
- 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 IdentityPointcutVisitor {
- boolean usesTarget = false;
-
- public Object visit(ThisOrTargetPointcut node, Object data) {
- if (!node.isThis() && node.isBinding()) usesTarget=true;
- return node;
- }
-
- public Object visit(AndPointcut node, Object data) {
- if (!usesTarget) node.getLeft().accept(this, data);
- if (!usesTarget) node.getRight().accept(this, data);
- return node;
- }
-
- public Object visit(NotPointcut node, Object data) {
- if (!usesTarget) node.getNegatedPointcut().accept(this, data);
- return node;
- }
-
- 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);
-
- // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD!
- LazyMethodGen callbackMethod =
- extractMethod(
- NameMangler.aroundCallbackMethodName(
- getSignature(),
- getEnclosingClass()),
- 0,
- munger);
-
- 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 {
- returnConversionCode =
- Utility.createConversion(
- getFactory(),
- BcelWorld.makeBcelType(munger.getSignature().getReturnType()),
- 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(new Integer(bitflags)));
- closureInstantiation.append(Utility.createInvoke(
- getFactory(),
- getWorld(),
- new MemberImpl(
- Member.METHOD,
- UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
- Modifier.PUBLIC,
- "linkClosureAndJoinPoint",
- "(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 (!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((Instruction)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(new 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 = (BcelVar) 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());
- InstructionFactory fact = new InstructionFactory(closureClass.getConstantPoolGen());
-
- // 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);
-
- // 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++) {
- Type stateType = stateTypes[i];
- ResolvedType stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
- if (proceedMap.hasKey(i)) {
- mbody.append(
- proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i),
- stateTypeX));
- } else {
- mbody.append(
- stateVar.createConvertableArrayLoad(fact, i,
- stateTypeX));
- }
- }
-
-
- 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
-
-
- public LazyMethodGen extractMethod(String newMethodName, int visibilityModifier, ShadowMunger munger) {
- LazyMethodGen.assertGoodBody(range.getBody(), newMethodName);
- if (!getKind().allowsExtraction()) throw new BCException("Attempt to extract method from a shadow kind that does not support this operation (" + getKind() + ")");
- LazyMethodGen freshMethod = createMethodGen(newMethodName,visibilityModifier);
-
- // System.err.println("******");
- // System.err.println("ABOUT TO EXTRACT METHOD for" + this);
- // enclosingMethod.print(System.err);
- // System.err.println("INTO");
- // freshMethod.print(System.err);
- // System.err.println("WITH REMAP");
- // System.err.println(makeRemap());
-
- range.extractInstructionsInto(freshMethod, makeRemap(),
- (getKind() != PreInitialization) &&
- isFallsThrough());
- if (getKind() == PreInitialization) {
- addPreInitializationReturnCode(
- freshMethod,
- getSuperConstructorParameterTypes());
- }
- getEnclosingClass().addMethodGen(freshMethod,munger.getSourceLocation());
-
- return freshMethod;
- }
-
- 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((Instruction)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().getConstantPoolGen());
- }
-
-
- /** 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 createMethodGen(String newMethodName, int visibilityModifier) {
- Type[] parameterTypes = BcelWorld.makeBcelTypes(getArgTypes());
- int modifiers = Modifier.FINAL | visibilityModifier;
-
- // XXX some bug
- // if (! isExpressionKind() && getSignature().isStrict(world)) {
- // modifiers |= Modifier.STRICT;
- // }
- modifiers |= Modifier.STATIC;
- if (targetVar != null && targetVar != thisVar) {
- UnresolvedType targetType = getTargetType();
- targetType = ensureTargetTypeIsCorrect(targetType);
- // see pr109728 - this fixes the case when the declaring class is sometype 'X' but the getfield
- // 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 && getActualTargetType()!=null &&
- !getActualTargetType().equals(targetType.getName())) {
- targetType = UnresolvedType.forName(getActualTargetType()).resolve(world);
- }
- ResolvedMember resolvedMember = getSignature().resolve(world);
-
- if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) &&
- !samePackage(targetType.getPackageName(), getEnclosingType().getPackageName()) &&
- !resolvedMember.getName().equals("clone"))
- {
- if (!targetType.resolve(world).isAssignableFrom(getThisType().resolve(world))) {
- throw new BCException("bad bytecode");
- }
- targetType = getThisType();
- }
- parameterTypes = addType(BcelWorld.makeBcelType(targetType), parameterTypes);
- }
- if (thisVar != null) {
- UnresolvedType thisType = getThisType();
- parameterTypes = addType(BcelWorld.makeBcelType(thisType), parameterTypes);
- }
-
- // 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) {
- parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes);
- //FIXME ALEX? which one
- //parameterTypes = addTypeToEnd(LazyClassGen.proceedingTjpType, parameterTypes);
- }
-
- UnresolvedType returnType;
- if (getKind() == PreInitialization) {
- returnType = UnresolvedType.OBJECTARRAY;
- } else {
-
- if (getKind() == ConstructorCall) returnType = getSignature().getDeclaringType();
- else if (getKind() == FieldSet) returnType = ResolvedType.VOID;
- else returnType = getSignature().getReturnType().resolve(world);
- // returnType = getReturnType(); // for this and above lines, see pr137496
- }
- return
- new LazyMethodGen(
- modifiers,
- BcelWorld.makeBcelType(returnType),
- newMethodName,
- parameterTypes,
- new String[0],
- // XXX again, we need to look up methods!
- // UnresolvedType.getNames(getSignature().getExceptions(world)),
- 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[] addType(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 typeX) {
- return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.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();
- }
-
- 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(); //fallsThrough;
- }
-
- public void setActualTargetType(String className) {
- this.actualInstructionTargetType = className;
- }
-
- public String getActualTargetType() {
- return actualInstructionTargetType;
- }
- }
|