Package org.aspectj.weaver.bcel

Source Code of org.aspectj.weaver.bcel.ShadowRange

/* *******************************************************************
* 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()) {
      Iterator<InstructionTargeter> tIter = newIh.getTargeters().iterator();
      while (tIter.hasNext()) {
        InstructionTargeter source = tIter.next();
        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;
  }

}
TOP

Related Classes of org.aspectj.weaver.bcel.ShadowRange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.