123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- /* *******************************************************************
- * 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
- * ******************************************************************/
-
- package org.aspectj.weaver.bcel;
-
- import java.util.Iterator;
-
- import org.aspectj.apache.bcel.generic.Instruction;
- import org.aspectj.apache.bcel.generic.InstructionBranch;
- import org.aspectj.apache.bcel.generic.InstructionFactory;
- import org.aspectj.apache.bcel.generic.InstructionHandle;
- import org.aspectj.apache.bcel.generic.InstructionLV;
- import org.aspectj.apache.bcel.generic.InstructionList;
- import org.aspectj.apache.bcel.generic.InstructionSelect;
- import org.aspectj.apache.bcel.generic.InstructionTargeter;
- import org.aspectj.apache.bcel.generic.LocalVariableTag;
- import org.aspectj.apache.bcel.generic.RET;
- import org.aspectj.apache.bcel.generic.TargetLostException;
- import org.aspectj.weaver.BCException;
- import org.aspectj.weaver.IntMap;
- import org.aspectj.weaver.Shadow;
-
- final class ShadowRange extends Range {
-
- private BcelShadow shadow;
-
- // ---- initialization
-
- /**
- * After this constructor is called, this range is not well situated unless both {@link #associateWithTargets} and
- * {@link #associateWithShadow} are called.
- */
- public ShadowRange(InstructionList body) {
- super(body);
- }
-
- protected void associateWithTargets(InstructionHandle start, InstructionHandle end) {
- // assert body.contains(start) && body.contains(end);
- this.start = start;
- this.end = end;
- start.addTargeter(this);
- end.addTargeter(this);
- }
-
- public void associateWithShadow(BcelShadow shadow) {
- this.shadow = shadow;
- shadow.setRange(this);
- }
-
- // ----
-
- public Shadow.Kind getKind() {
- return shadow.getKind();
- }
-
- @Override
- public String toString() {
- return shadow.toString();
- }
-
- void extractInstructionsInto(LazyMethodGen freshMethod, IntMap remap, boolean addReturn) {
- LazyMethodGen.assertGoodBody(getBody(), toString());
- freshMethod.assertGoodBody();
- InstructionList freshBody = freshMethod.getBody();
-
- for (InstructionHandle oldIh = start.getNext(); oldIh != end; oldIh = oldIh.getNext()) {
- // first we copy the instruction itself.
- Instruction oldI = oldIh.getInstruction();
- Instruction freshI = (oldI == RANGEINSTRUCTION) ? oldI : Utility.copyInstruction(oldI);
-
- // Now we add it to the new instruction list.
- InstructionHandle freshIh;
- if (freshI instanceof InstructionBranch) {
- // If it's a targeting instruction,
- // update the target(s) to point to the new copy instead of the old copy.
- InstructionBranch oldBranch = (InstructionBranch) oldI;
- InstructionBranch freshBranch = (InstructionBranch) freshI;
- InstructionHandle oldTarget = oldBranch.getTarget();
- oldTarget.removeTargeter(oldBranch);
- oldTarget.addTargeter(freshBranch);
- if (freshBranch instanceof InstructionSelect) {
- InstructionSelect oldSelect = (InstructionSelect) oldI;
- InstructionSelect freshSelect = (InstructionSelect) freshI;
- InstructionHandle[] oldTargets = freshSelect.getTargets();
- for (int k = oldTargets.length - 1; k >= 0; k--) {
- oldTargets[k].removeTargeter(oldSelect);
- oldTargets[k].addTargeter(freshSelect);
- }
- }
- freshIh = freshBody.append(freshBranch);
- } else {
- freshIh = freshBody.append(freshI);
- }
-
- // if source comes before target:
- // source <--> target
- // --> [process: target.removeTargeter(source); target.addTargeter(sourcecopy)]
- // source ---------\
- // v
- // sourcecopy <--> target
- // --> [ process: sourcecopy.updateTarget(target, targetcopy) ]
- // source ----> target
- // sourcecopy <--> targetcopy
-
- // if target comes before source
-
- // target <--> source
- // --> [process: source.updateTarget(target, targetcopy) ]
- // target
- // targetcopy <--> source
- // --> [process: targetcopy.removeTargeter(source); targetcopy.addTargeter(sourcecopy)]
- // target source
- // v
- // targetcopy <--> sourcecopy
-
- // now deal with the old instruction's targeters. Update them all to point to us
- // instead of the old instruction. We use updateTarget to do this. One goal is
- // to make sure we remove all targeters from the old guy, so we can successfully
- // delete it.
- for (InstructionTargeter source : oldIh.getTargetersCopy()) {
- if (source instanceof LocalVariableTag) {
- Shadow.Kind kind = getKind();
- if (kind == Shadow.AdviceExecution || kind == Shadow.ConstructorExecution || kind == Shadow.MethodExecution
- || kind == Shadow.PreInitialization || kind == Shadow.Initialization
- || kind == Shadow.StaticInitialization) {
- LocalVariableTag sourceLocalVariableTag = (LocalVariableTag) source;
- if (sourceLocalVariableTag.getSlot() == 0) {
- // might be 'this' so should be renamed if being dumped in a static method 277616
- if (sourceLocalVariableTag.getName().equals("this")) {
- sourceLocalVariableTag.setName("ajc$this");
- }
- }
- // if we're extracting a whole block we can do this...
- source.updateTarget(oldIh, freshIh);
- } else {
- // XXX destroying local variable info
- // but only for a call or get join point, so no big deal
- source.updateTarget(oldIh, null);
- }
- } else if (source instanceof Range) {
- // exceptions and shadows are just moved
- ((Range) source).updateTarget(oldIh, freshIh, freshBody);
- } else {
- // line numbers can be shared,
- // branches will be copied along with us.
- source.updateTarget(oldIh, freshIh);
- }
- }
- // we're now done with the old instruction entirely, and will ignore them through
- // the rest of this loop. The only time we'll see them again is a second pass to
- // delete them.
-
- // now deal with local variable instructions. If this points to a remapped
- // frame location, update the instruction's index. If this doesn't,
- // do compaction/expansion: allocate a new local variable, and modify the remap
- // to handle it. XXX We're doing the safe thing and allocating ALL these local variables
- // as double-wides, in case the location is found to hold a double-wide later.
- if (freshI.isLocalVariableInstruction() || freshI instanceof RET) {
- // IndexedInstruction indexedI = (IndexedInstruction) freshI;
- int oldIndex = freshI.getIndex();
- int freshIndex;
- if (!remap.hasKey(oldIndex)) {
- freshIndex = freshMethod.allocateLocal(2);
- remap.put(oldIndex, freshIndex);
- } else {
- freshIndex = remap.get(oldIndex);
- }
- if (freshI instanceof RET) {
- freshI.setIndex(freshIndex);
- } else {
- freshI = ((InstructionLV) freshI).setIndexAndCopyIfNecessary(freshIndex);
- freshIh.setInstruction(freshI);
- }
- }
- // System.err.println("JUST COPIED: " +
- // oldIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool())
- // + " INTO " +
- // freshIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool()));
- }
-
- // now go through again and update variable slots that have been altered as a result
- // of remapping...
- for (InstructionHandle newIh = freshBody.getStart(); newIh != freshBody.getEnd(); newIh = newIh.getNext()) {
- for (InstructionTargeter source : newIh.getTargeters()) {
- if (source instanceof LocalVariableTag) {
- LocalVariableTag lvt = (LocalVariableTag) source;
- if (!lvt.isRemapped() && remap.hasKey(lvt.getSlot())) {
- lvt.updateSlot(remap.get(lvt.getSlot()));
- }
- }
- }
- }
-
- // we've now copied out all the instructions.
- // now delete the instructions... we've already taken care of the damn
- // targets, but since TargetLostException is checked, we have to do this stuff.
- try {
- for (InstructionHandle oldIh = start.getNext(); oldIh != end;) {
- InstructionHandle next = oldIh.getNext();
- body.delete(oldIh);
- oldIh = next;
- }
- } catch (TargetLostException e) {
- throw new BCException("shouldn't have gotten a target lost");
- }
-
- // now add the return, if one is warranted.
- InstructionHandle ret = null;
- if (addReturn) {
- // we really should pull this out somewhere...
- ret = freshBody.append(InstructionFactory.createReturn(freshMethod.getReturnType()));
- }
- // and remap all the old targeters of the end handle of the range to the return.
- for (InstructionTargeter t : end.getTargetersCopy()) {
- if (t == this) {
- continue;
- }
- if (!addReturn) {
- throw new BCException("range has target, but we aren't adding a return");
- } else {
- t.updateTarget(end, ret);
- }
- }
-
- LazyMethodGen.assertGoodBody(getBody(), toString());
- freshMethod.assertGoodBody();
- }
-
- public BcelShadow getShadow() {
- return shadow;
- }
-
- }
|