org.aspectj.weaver.bcel.Range Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjtools Show documentation
Show all versions of aspectjtools Show documentation
Tools from the AspectJ project
/* *******************************************************************
* 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 v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver.bcel;
import org.aspectj.apache.bcel.generic.Instruction;
import org.aspectj.apache.bcel.generic.InstructionConstants;
import org.aspectj.apache.bcel.generic.InstructionHandle;
import org.aspectj.apache.bcel.generic.InstructionList;
import org.aspectj.apache.bcel.generic.InstructionTargeter;
import org.aspectj.weaver.BCException;
abstract class Range implements InstructionTargeter {
protected InstructionList body;
protected InstructionHandle start;
protected InstructionHandle end;
// ---- initialization
protected Range(InstructionList il) {
this.body = il;
}
// ----
final InstructionList getBody() {
return body;
}
final InstructionHandle getStart() {
return start;
}
final InstructionHandle getEnd() {
return end;
}
// ----
boolean isEmpty() {
InstructionHandle ih = start;
// System.err.println(" looking for " + end);
while (ih != end) {
// System.err.println(" ih " + ih);
if (!Range.isRangeHandle(ih)) {
return false;
}
ih = ih.getNext();
}
return true;
}
static InstructionHandle getRealStart(InstructionHandle ih) {
while (Range.isRangeHandle(ih)) {
ih = ih.getNext();
}
return ih;
}
InstructionHandle getRealStart() {
return getRealStart(start);
}
static InstructionHandle getRealEnd(InstructionHandle ih) {
while (Range.isRangeHandle(ih)) {
ih = ih.getPrev();
}
return ih;
}
InstructionHandle getRealEnd() {
return getRealEnd(end);
}
InstructionHandle getRealNext() {
return getRealStart(end);
}
// ----
InstructionHandle insert(Instruction i, Where where) {
InstructionList il = new InstructionList();
InstructionHandle ret = il.insert(i);
insert(il, where);
return ret;
}
void insert(InstructionList freshIl, Where where) {
InstructionHandle h;
if (where == InsideBefore || where == OutsideBefore) {
h = getStart();
} else {
h = getEnd();
}
if (where == InsideBefore || where == OutsideAfter) {
body.append(h, freshIl);
} else {
InstructionHandle newStart = body.insert(h, freshIl);
if (where == OutsideBefore) {
// XXX this is slow. There's a better design than this. We should
// never have to retarget branches apart from the creation of ranges.
// basically, we should never weave OutsideBefore.
BcelShadow.retargetAllBranches(h, newStart);
}
}
}
InstructionHandle append(Instruction i) {
return insert(i, InsideAfter);
}
void append(InstructionList i) {
insert(i, InsideAfter);
}
private static void setLineNumberFromNext(InstructionHandle ih) {
int lineNumber = Utility.getSourceLine(ih.getNext());
if (lineNumber != -1) {
Utility.setSourceLine(ih, lineNumber);
}
}
static InstructionHandle genStart(InstructionList body) {
InstructionHandle ih = body.insert(Range.RANGEINSTRUCTION);
setLineNumberFromNext(ih);
return ih;
}
static InstructionHandle genEnd(InstructionList body) {
return body.append(Range.RANGEINSTRUCTION);
}
static InstructionHandle genStart(InstructionList body, InstructionHandle ih) {
if (ih == null) {
return genStart(body);
}
InstructionHandle freshIh = body.insert(ih, Range.RANGEINSTRUCTION);
setLineNumberFromNext(freshIh);
return freshIh;
}
static InstructionHandle genEnd(InstructionList body, InstructionHandle ih) {
if (ih == null) {
return genEnd(body);
}
return body.append(ih, Range.RANGEINSTRUCTION);
}
// -----
public boolean containsTarget(InstructionHandle ih) {
return false;
}
public final void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
throw new RuntimeException("Ranges must be updated with an enclosing instructionList");
}
protected void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih, InstructionList new_il) {
old_ih.removeTargeter(this);
if (new_ih != null) {
new_ih.addTargeter(this);
}
body = new_il;
if (old_ih == start) {
start = new_ih;
}
if (old_ih == end) {
end = new_ih;
}
}
public static final boolean isRangeHandle(InstructionHandle ih) {
if (ih == null) {
return false;
}
return ih.getInstruction() == Range.RANGEINSTRUCTION;
}
protected static final Range getRange(InstructionHandle ih) {
// assert isRangeHandle(ih)
Range ret = null;
for (InstructionTargeter targeter : ih.getTargeters()) {
if (targeter instanceof Range) {
Range r = (Range) targeter;
if (r.getStart() != ih && r.getEnd() != ih) {
continue;
}
if (ret != null) {
throw new BCException("multiple ranges on same range handle: " + ret + ", " + targeter);
}
ret = r;
}
}
if (ret == null) {
throw new BCException("shouldn't happen");
}
return ret;
}
// ----
static final Where InsideBefore = new Where("insideBefore");
static final Where InsideAfter = new Where("insideAfter");
static final Where OutsideBefore = new Where("outsideBefore");
static final Where OutsideAfter = new Where("outsideAfter");
// ---- constants
// note that this is STUPIDLY copied by Instruction.copy(), so don't do that.
public static final Instruction RANGEINSTRUCTION = InstructionConstants.IMPDEP1;
// ----
static class Where {
private String name;
public Where(String name) {
this.name = name;
}
public String toString() {
return name;
}
}
}