@@ -68,7 +68,7 @@ import org.aspectj.apache.bcel.Constants; | |||
* This attribute has attributes itself, namely <em>LineNumberTable</em> which is used for debugging purposes and | |||
* <em>LocalVariableTable</em> which contains information about the local variables. | |||
* | |||
* @version $Id: Code.java,v 1.8 2009/09/15 19:40:12 aclement Exp $ | |||
* @version $Id: Code.java,v 1.9 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Attribute | |||
* @see CodeException | |||
@@ -109,8 +109,9 @@ public final class Code extends Attribute { | |||
exceptionTable = NO_EXCEPTIONS; | |||
} else { | |||
exceptionTable = new CodeException[len]; | |||
for (int i = 0; i < len; i++) | |||
for (int i = 0; i < len; i++) { | |||
exceptionTable[i] = new CodeException(file); | |||
} | |||
} | |||
// Read all attributes, eg: LineNumberTable, LocalVariableTable | |||
@@ -172,12 +173,14 @@ public final class Code extends Attribute { | |||
file.write(code, 0, code.length); | |||
file.writeShort(exceptionTable.length); | |||
for (int i = 0; i < exceptionTable.length; i++) | |||
for (int i = 0; i < exceptionTable.length; i++) { | |||
exceptionTable[i].dump(file); | |||
} | |||
file.writeShort(attributes.length); | |||
for (int i = 0; i < attributes.length; i++) | |||
for (int i = 0; i < attributes.length; i++) { | |||
attributes[i].dump(file); | |||
} | |||
} | |||
/** | |||
@@ -192,9 +195,11 @@ public final class Code extends Attribute { | |||
* @return LineNumberTable of Code, if it has one | |||
*/ | |||
public LineNumberTable getLineNumberTable() { | |||
for (int i = 0; i < attributes.length; i++) | |||
if (attributes[i].tag == Constants.ATTR_LINE_NUMBER_TABLE) | |||
for (int i = 0; i < attributes.length; i++) { | |||
if (attributes[i].tag == Constants.ATTR_LINE_NUMBER_TABLE) { | |||
return (LineNumberTable) attributes[i]; | |||
} | |||
} | |||
return null; | |||
} | |||
@@ -202,9 +207,11 @@ public final class Code extends Attribute { | |||
* @return LocalVariableTable of Code, if it has one | |||
*/ | |||
public LocalVariableTable getLocalVariableTable() { | |||
for (int i = 0; i < attributes.length; i++) | |||
if (attributes[i].tag == Constants.ATTR_LOCAL_VARIABLE_TABLE) | |||
for (int i = 0; i < attributes.length; i++) { | |||
if (attributes[i].tag == Constants.ATTR_LOCAL_VARIABLE_TABLE) { | |||
return (LocalVariableTable) attributes[i]; | |||
} | |||
} | |||
return null; | |||
} | |||
@@ -255,8 +262,9 @@ public final class Code extends Attribute { | |||
private final int calculateLength() { | |||
int len = 0; | |||
if (attributes != null) { | |||
for (int i = 0; i < attributes.length; i++) | |||
for (int i = 0; i < attributes.length; i++) { | |||
len += attributes[i].length + 6 /* attribute header size */; | |||
} | |||
} | |||
return len + getInternalLength(); | |||
} | |||
@@ -309,15 +317,17 @@ public final class Code extends Attribute { | |||
if (exceptionTable.length > 0) { | |||
buf.append("\nException handler(s) = \n" + "From\tTo\tHandler\tType\n"); | |||
for (int i = 0; i < exceptionTable.length; i++) | |||
for (int i = 0; i < exceptionTable.length; i++) { | |||
buf.append(exceptionTable[i].toString(cpool, verbose) + "\n"); | |||
} | |||
} | |||
if (attributes.length > 0) { | |||
buf.append("\nAttribute(s) = \n"); | |||
for (int i = 0; i < attributes.length; i++) | |||
for (int i = 0; i < attributes.length; i++) { | |||
buf.append(attributes[i].toString() + "\n"); | |||
} | |||
} | |||
return buf.toString(); | |||
@@ -366,8 +376,9 @@ public final class Code extends Attribute { | |||
CodeException exc = exceptionTable[i]; | |||
int type = exc.getCatchType(); | |||
String name = "finally"; | |||
if (type != 0) | |||
if (type != 0) { | |||
name = this.cpool.getConstantString(type, Constants.CONSTANT_Class); | |||
} | |||
codeString.append(name).append("["); | |||
codeString.append(exc.getStartPC()).append(">").append(exc.getEndPC()).append("]\n"); | |||
} |
@@ -55,77 +55,80 @@ package org.aspectj.apache.bcel.generic; | |||
*/ | |||
/** | |||
* BranchHandle is returned by specialized InstructionList.append() whenever a | |||
* BranchInstruction is appended. This is useful when the target of this | |||
* instruction is not known at time of creation and must be set later | |||
* via setTarget(). | |||
* | |||
* BranchHandle is returned by specialized InstructionList.append() whenever a BranchInstruction is appended. This is useful when | |||
* the target of this instruction is not known at time of creation and must be set later via setTarget(). | |||
* | |||
* @see InstructionHandle | |||
* @see Instruction | |||
* @see InstructionList | |||
* @version $Id: BranchHandle.java,v 1.4 2008/05/28 23:52:55 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @version $Id: BranchHandle.java,v 1.5 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public final class BranchHandle extends InstructionHandle { | |||
private InstructionBranch bi; // An alias in fact, but saves lots of casts | |||
private BranchHandle(InstructionBranch i) { | |||
super(i); | |||
bi = i; | |||
} | |||
private InstructionBranch bi; // An alias in fact, but saves lots of casts | |||
static final BranchHandle getBranchHandle(InstructionBranch i) { | |||
return new BranchHandle(i); | |||
} | |||
private BranchHandle(InstructionBranch i) { | |||
super(i); | |||
bi = i; | |||
} | |||
/* Override InstructionHandle methods: delegate to branch instruction. | |||
* Through this overriding all access to the private i_position field should | |||
* be prevented. | |||
*/ | |||
public int getPosition() { return bi.positionOfThisInstruction; } | |||
static final BranchHandle getBranchHandle(InstructionBranch i) { | |||
return new BranchHandle(i); | |||
} | |||
void setPosition(int pos) { | |||
i_position = bi.positionOfThisInstruction = pos; | |||
} | |||
/* | |||
* Override InstructionHandle methods: delegate to branch instruction. Through this overriding all access to the private | |||
* i_position field should be prevented. | |||
*/ | |||
public int getPosition() { | |||
return bi.positionOfThisInstruction; | |||
} | |||
protected int updatePosition(int offset, int max_offset) { | |||
int x = bi.updatePosition(offset, max_offset); | |||
i_position = bi.positionOfThisInstruction; | |||
return x; | |||
} | |||
void setPosition(int pos) { | |||
this.pos = bi.positionOfThisInstruction = pos; | |||
} | |||
/** | |||
* Pass new target to instruction. | |||
*/ | |||
public void setTarget(InstructionHandle ih) { | |||
bi.setTarget(ih); | |||
} | |||
/** | |||
* Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable length | |||
* instructions 'setPositions()' performs multiple passes over the instruction list to calculate the correct (byte) positions | |||
* and offsets by calling this function. | |||
* | |||
* @param offset additional offset caused by preceding (variable length) instructions | |||
* @param max_offset the maximum offset that may be caused by these instructions | |||
* @return additional offset caused by possible change of this instruction's length | |||
*/ | |||
protected int updatePosition(int offset, int max_offset) { | |||
int x = bi.updatePosition(offset, max_offset); | |||
pos = bi.positionOfThisInstruction; | |||
return x; | |||
} | |||
/** | |||
* Update target of instruction. | |||
*/ | |||
public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { | |||
bi.updateTarget(old_ih, new_ih); | |||
} | |||
/** | |||
* Pass new target to instruction. | |||
*/ | |||
public void setTarget(InstructionHandle ih) { | |||
bi.setTarget(ih); | |||
} | |||
/** | |||
* @return target of instruction. | |||
*/ | |||
public InstructionHandle getTarget() { | |||
return bi.getTarget(); | |||
} | |||
/** | |||
* Update target of instruction. | |||
*/ | |||
public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { | |||
bi.updateTarget(old_ih, new_ih); | |||
} | |||
/** | |||
* Set new contents. Old instruction is disposed and may not be used anymore. | |||
*/ | |||
public void setInstruction(Instruction i) { | |||
super.setInstruction(i); | |||
/** | |||
* @return target of instruction. | |||
*/ | |||
public InstructionHandle getTarget() { | |||
return bi.getTarget(); | |||
} | |||
if(!(i instanceof InstructionBranch)) | |||
throw new ClassGenException("Assigning " + i + | |||
" to branch handle which is not a branch instruction"); | |||
bi = (InstructionBranch)i; | |||
} | |||
/** | |||
* Set new contents. Old instruction is disposed and may not be used anymore. | |||
*/ | |||
public void setInstruction(Instruction i) { | |||
super.setInstruction(i); | |||
bi = (InstructionBranch) i; | |||
} | |||
} | |||
@@ -58,50 +58,55 @@ import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
/** | |||
* Super class for the GET/PUTxxx family of instructions. | |||
* | |||
* @version $Id: FieldInstruction.java,v 1.6 2008/05/28 23:52:56 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* @version $Id: FieldInstruction.java,v 1.7 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class FieldInstruction extends FieldOrMethod { | |||
public FieldInstruction(short opcode, int index) { | |||
super(opcode, index); | |||
} | |||
public FieldInstruction(short opcode, int index) { | |||
super(opcode, index); | |||
} | |||
public String toString(ConstantPool cp) { | |||
return org.aspectj.apache.bcel.Constants.OPCODE_NAMES[opcode] + " " + | |||
cp.constantToString(index, org.aspectj.apache.bcel.Constants.CONSTANT_Fieldref); | |||
} | |||
/** @return size of field (1 or 2) | |||
*/ | |||
protected int getFieldSize(ConstantPool cpg) { | |||
return Type.getTypeSize(getSignature(cpg)); | |||
} | |||
public String toString(ConstantPool cp) { | |||
return org.aspectj.apache.bcel.Constants.OPCODE_NAMES[opcode] + " " | |||
+ cp.constantToString(index, org.aspectj.apache.bcel.Constants.CONSTANT_Fieldref); | |||
} | |||
public Type getType(ConstantPool cpg) { | |||
return getFieldType(cpg); | |||
} | |||
/** | |||
* @return size of field (1 or 2) | |||
*/ | |||
protected int getFieldSize(ConstantPool cpg) { | |||
return Type.getTypeSize(getSignature(cpg)); | |||
} | |||
public Type getFieldType(ConstantPool cpg) { | |||
return Type.getType(getSignature(cpg)); | |||
} | |||
public Type getType(ConstantPool cpg) { | |||
return getFieldType(cpg); | |||
} | |||
public Type getFieldType(ConstantPool cpg) { | |||
return Type.getType(getSignature(cpg)); | |||
} | |||
public String getFieldName(ConstantPool cpg) { | |||
return getName(cpg); | |||
} | |||
public int produceStack(ConstantPool cpg) { | |||
if (!isStackProducer()) return 0; | |||
return getFieldSize(cpg); // SAME FOR GETFIELD/GETSTATIC | |||
} | |||
public int consumeStack(ConstantPool cpg) { | |||
if (!isStackConsumer()) return 0; | |||
if (opcode==GETFIELD) return 1; | |||
return getFieldSize(cpg)+(opcode==PUTFIELD?1:0); | |||
} | |||
} | |||
public String getFieldName(ConstantPool cpg) { | |||
return getName(cpg); | |||
} | |||
public int produceStack(ConstantPool cpg) { | |||
if (!isStackProducer()) { | |||
return 0; | |||
} | |||
return getFieldSize(cpg); // SAME FOR GETFIELD/GETSTATIC | |||
} | |||
public int consumeStack(ConstantPool cpg) { | |||
if (!isStackConsumer()) { | |||
return 0; | |||
} | |||
if (opcode == GETFIELD) { | |||
return 1; | |||
} | |||
return getFieldSize(cpg) + (opcode == PUTFIELD ? 1 : 0); | |||
} | |||
} |
@@ -61,23 +61,15 @@ import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
/** | |||
* Super class for InvokeInstruction and FieldInstruction, since they have some methods in common! | |||
* | |||
* @version $Id: FieldOrMethod.java,v 1.7 2009/09/10 15:35:06 aclement Exp $ | |||
* @version $Id: FieldOrMethod.java,v 1.8 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public abstract class FieldOrMethod extends InstructionCP { | |||
// private boolean dontKnowSignature=true; | |||
private String signature; | |||
// private boolean dontKnowName =true; | |||
private String name; | |||
// private boolean dontKnowClassname =true; | |||
private String classname; | |||
/** | |||
* @param index to constant pool | |||
*/ | |||
protected FieldOrMethod(short opcode, int index) { | |||
super(opcode, index); | |||
} | |||
@@ -89,9 +81,7 @@ public abstract class FieldOrMethod extends InstructionCP { | |||
if (signature == null) { | |||
ConstantCP cmr = (ConstantCP) cp.getConstant(index); | |||
ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); | |||
signature = ((ConstantUtf8) cp.getConstant(cnat.getSignatureIndex())).getValue(); | |||
// dontKnowSignature=false; | |||
} | |||
return signature; | |||
} | |||
@@ -104,7 +94,6 @@ public abstract class FieldOrMethod extends InstructionCP { | |||
ConstantCP cmr = (ConstantCP) cp.getConstant(index); | |||
ConstantNameAndType cnat = (ConstantNameAndType) cp.getConstant(cmr.getNameAndTypeIndex()); | |||
name = ((ConstantUtf8) cp.getConstant(cnat.getNameIndex())).getValue(); | |||
// dontKnowName = false; | |||
} | |||
return name; | |||
} | |||
@@ -116,11 +105,11 @@ public abstract class FieldOrMethod extends InstructionCP { | |||
if (classname == null) { | |||
ConstantCP cmr = (ConstantCP) cp.getConstant(index); | |||
String str = cp.getConstantString(cmr.getClassIndex(), CONSTANT_Class); | |||
if (str.charAt(0) == '[') | |||
if (str.charAt(0) == '[') { | |||
classname = str; | |||
else | |||
} else { | |||
classname = str.replace('/', '.'); | |||
// dontKnowClassname = false; | |||
} | |||
} | |||
return classname; | |||
} |
@@ -53,56 +53,69 @@ package org.aspectj.apache.bcel.generic; | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
import java.io.*; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* IINC - Increment local variable by constant | |||
* | |||
* @version $Id: IINC.java,v 1.4 2008/05/28 23:52:57 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* @version $Id: IINC.java,v 1.5 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class IINC extends InstructionLV { | |||
private int c; | |||
private int c; | |||
public IINC(int n, int c, boolean w) { | |||
super(Constants.IINC, n); | |||
this.c = c; | |||
// this.wide = w;//((n > org.aspectj.apache.bcel.Constants.MAX_BYTE) || (Math.abs(c) > Byte.MAX_VALUE)); | |||
} | |||
private boolean wide() { | |||
return ((lvar > org.aspectj.apache.bcel.Constants.MAX_BYTE) || (Math.abs(c) > Byte.MAX_VALUE)); | |||
} | |||
public IINC(int n, int c,boolean w) { | |||
super(Constants.IINC,n); | |||
this.c=c; | |||
// this.wide = w;//((n > org.aspectj.apache.bcel.Constants.MAX_BYTE) || (Math.abs(c) > Byte.MAX_VALUE)); | |||
} | |||
public void dump(DataOutputStream out) throws IOException { | |||
if (wide()) { | |||
out.writeByte(WIDE); | |||
out.writeByte(opcode); | |||
out.writeShort(lvar); | |||
out.writeShort(c); | |||
} else { | |||
out.writeByte(opcode); | |||
out.writeByte(lvar); | |||
out.writeByte(c); | |||
} | |||
} | |||
private boolean wide() { | |||
return ((lvar > org.aspectj.apache.bcel.Constants.MAX_BYTE) || (Math.abs(c) > Byte.MAX_VALUE)); | |||
} | |||
public int getLength() { | |||
if (wide()) { | |||
return 6; | |||
} else { | |||
return 3; // includes wide byte | |||
} | |||
} | |||
public void dump(DataOutputStream out) throws IOException { | |||
if (wide()) { | |||
out.writeByte(WIDE); | |||
out.writeByte(opcode); | |||
out.writeShort(lvar); | |||
out.writeShort(c); | |||
} else { | |||
out.writeByte(opcode); | |||
out.writeByte(lvar); | |||
out.writeByte(c); | |||
} | |||
} | |||
public int getLength() { | |||
if (wide()) return 6; else return 3; // includes wide byte | |||
} | |||
public String toString(boolean verbose) { | |||
return super.toString(verbose) + " " + c; | |||
} | |||
public String toString(boolean verbose) { | |||
return super.toString(verbose) + " " + c; | |||
} | |||
public final int getIncrement() { | |||
return c; | |||
} | |||
public final int getIncrement() { return c; } | |||
public boolean equals(Object other) { | |||
if (!(other instanceof IINC)) { | |||
return false; | |||
} | |||
IINC o = (IINC) other; | |||
return /* o.opcode == opcode && */o.lvar == lvar && o.c == c; | |||
} | |||
// //fixme promote or stick in a table | |||
// public Type getType(ConstantPoolGen cp) { | |||
// return Type.INT; | |||
// } | |||
public int hashCode() { | |||
return opcode * 37 + lvar * (c + 17); | |||
} | |||
} |
@@ -53,58 +53,75 @@ package org.aspectj.apache.bcel.generic; | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import org.aspectj.apache.bcel.Constants; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import java.io.*; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
/** | |||
/** | |||
* INVOKEINTERFACE - Invoke interface method | |||
* <PRE>Stack: ..., objectref, [arg1, [arg2 ...]] -> ...</PRE> | |||
* | |||
* @version $Id: INVOKEINTERFACE.java,v 1.3 2008/05/28 23:52:58 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* <PRE> | |||
* Stack: ..., objectref, [arg1, [arg2 ...]] -> ... | |||
* </PRE> | |||
* | |||
* @version $Id: INVOKEINTERFACE.java,v 1.4 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public final class INVOKEINTERFACE extends InvokeInstruction { | |||
private int nargs; // Number of arguments on stack (number of stack slots), called "count" in vmspec2 | |||
private int nargs; // Number of arguments on stack (number of stack slots), called "count" in vmspec2 | |||
public INVOKEINTERFACE(int index, int nargs, int zerobyte) { | |||
super(Constants.INVOKEINTERFACE, index); | |||
public INVOKEINTERFACE(int index, int nargs,int zerobyte) { | |||
super(Constants.INVOKEINTERFACE, index); | |||
if (nargs < 1) { | |||
throw new ClassGenException("Number of arguments must be > 0 " + nargs); | |||
} | |||
if(nargs < 1) | |||
throw new ClassGenException("Number of arguments must be > 0 " + nargs); | |||
this.nargs = nargs; | |||
} | |||
this.nargs = nargs; | |||
} | |||
/** | |||
* Dump instruction as byte code to stream out. | |||
* | |||
* @param out Output stream | |||
*/ | |||
public void dump(DataOutputStream out) throws IOException { | |||
out.writeByte(opcode); | |||
out.writeShort(index); | |||
out.writeByte(nargs); | |||
out.writeByte(0); | |||
} | |||
/** | |||
* Dump instruction as byte code to stream out. | |||
* @param out Output stream | |||
*/ | |||
public void dump(DataOutputStream out) throws IOException { | |||
out.writeByte(opcode); | |||
out.writeShort(index); | |||
out.writeByte(nargs); | |||
out.writeByte(0); | |||
} | |||
/** | |||
* The <B>count</B> argument according to the Java Language Specification, Second Edition. | |||
*/ | |||
public int getCount() { | |||
return nargs; | |||
} | |||
/** | |||
* The <B>count</B> argument according to the Java Language Specification, | |||
* Second Edition. | |||
*/ | |||
public int getCount() { return nargs; } | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
return super.toString(cp) + " " + nargs; | |||
} | |||
public int consumeStack(ConstantPool cpg) { // nargs is given in byte-code | |||
return nargs; // nargs includes this reference | |||
} | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
return super.toString(cp) + " " + nargs; | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof INVOKEINTERFACE)) { | |||
return false; | |||
} | |||
INVOKEINTERFACE o = (INVOKEINTERFACE) other; | |||
return o.opcode == opcode && o.index == index && o.nargs == nargs; | |||
} | |||
public int consumeStack(ConstantPool cpg) { // nargs is given in byte-code | |||
return nargs; // nargs includes this reference | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + index * (nargs + 17); | |||
} | |||
} |
@@ -67,7 +67,7 @@ import com.sun.org.apache.bcel.internal.generic.BranchInstruction; | |||
/** | |||
* Abstract super class for all Java byte codes. | |||
* | |||
* @version $Id: Instruction.java,v 1.8 2009/09/14 20:29:10 aclement Exp $ | |||
* @version $Id: Instruction.java,v 1.9 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class Instruction implements Cloneable, Serializable, Constants { | |||
@@ -92,7 +92,9 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
* @see BranchInstruction | |||
* @return (shallow) copy of an instruction | |||
*/ | |||
// GET RID OF THIS - make it throw an exception and track the callers | |||
final public Instruction copy() { | |||
// if overridden correctly can just return 'this' here | |||
if (InstructionConstants.INSTRUCTIONS[opcode] != null) { // immutable instructions do not need copying | |||
return this; | |||
} else { | |||
@@ -107,7 +109,7 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
} | |||
/** | |||
* Read an instruction from (byte code) input stream and return the appropiate object. | |||
* Read an instruction bytecode from an input stream and return the appropriate object. | |||
* | |||
* @param file file to read from | |||
* @return instruction object being read | |||
@@ -115,7 +117,6 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
public static final Instruction readInstruction(ByteSequence bytes) throws IOException { | |||
boolean wide = false; | |||
short opcode = (short) bytes.readUnsignedByte(); | |||
Instruction obj = null; | |||
if (opcode == Constants.WIDE) { | |||
wide = true; | |||
@@ -128,6 +129,7 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
return constantInstruction; | |||
} | |||
Instruction obj = null; | |||
try { | |||
switch (opcode) { | |||
case Constants.BIPUSH: | |||
@@ -257,9 +259,10 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
public int getLength() { | |||
// if it is zero, it should have been provided by an overriding implementation of getLength() | |||
int len = Constants.iLen[opcode]; | |||
if (len == 0) { | |||
throw new IllegalStateException("Length not right for " + getName().toUpperCase()); | |||
} | |||
assert len != 0; | |||
// if (len == 0) { | |||
// throw new IllegalStateException("Length not right for " + getName().toUpperCase()); | |||
// } | |||
return len; | |||
} | |||
@@ -268,38 +271,49 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
} | |||
@Override | |||
public boolean equals(Object that) { | |||
if (!(that instanceof Instruction)) { | |||
return false; | |||
public boolean equals(Object other) { | |||
if (this.getClass() != Instruction.class) { | |||
throw new RuntimeException("NO WAY " + this.getClass()); | |||
} | |||
Instruction i1 = this; | |||
Instruction i2 = (Instruction) that; | |||
if (i1.opcode == i2.opcode) { | |||
if (i1.isConstantInstruction()) { | |||
return i1.getValue().equals(i2.getValue()); | |||
} else if (i1.isIndexedInstruction()) { | |||
return i1.getIndex() == i2.getIndex(); | |||
} else if (i1.opcode == Constants.NEWARRAY) { | |||
return ((InstructionByte) i1).getTypecode() == ((InstructionByte) i2).getTypecode(); | |||
} else { | |||
return true; | |||
} | |||
if (!(other instanceof Instruction)) { | |||
return false; | |||
} | |||
return false; | |||
return ((Instruction) other).opcode == opcode; | |||
// IMPLEMENT EQUALS AND HASHCODE IN THE SUBTYPES! | |||
// Instruction i1 = this; | |||
// Instruction i2 = (Instruction) that; | |||
// if (i1.opcode == i2.opcode) { | |||
// if (i1.isConstantInstruction()) { | |||
// return i1.getValue().equals(i2.getValue()); | |||
// } else if (i1.isIndexedInstruction()) { | |||
// return i1.getIndex() == i2.getIndex(); | |||
// } else if (i1.opcode == Constants.NEWARRAY) { | |||
// return ((InstructionByte) i1).getTypecode() == ((InstructionByte) i2).getTypecode(); | |||
// } else { | |||
// return true; | |||
// } | |||
// } | |||
// | |||
// return false; | |||
} | |||
@Override | |||
public int hashCode() { | |||
int result = 17 + opcode * 37; | |||
if (isConstantInstruction()) { | |||
result = 37 * getValue().hashCode() + result; | |||
} else if (isIndexedInstruction()) { | |||
result = 37 * getIndex() + result; | |||
} else if (opcode == Constants.NEWARRAY) { | |||
result = 37 * ((InstructionByte) this).getTypecode() + result; | |||
if (this.getClass() != Instruction.class) { | |||
throw new RuntimeException("NO WAY " + this.getClass()); | |||
} | |||
return result; | |||
return opcode * 37; | |||
// int result = 17 + opcode * 37; | |||
// if (isConstantInstruction()) { | |||
// result = 37 * getValue().hashCode() + result; | |||
// } else if (isIndexedInstruction()) { | |||
// result = 37 * getIndex() + result; | |||
// } else if (opcode == Constants.NEWARRAY) { | |||
// result = 37 * ((InstructionByte) this).getTypecode() + result; | |||
// } | |||
// return result; | |||
} | |||
public Type getType() { | |||
@@ -316,9 +330,10 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
} | |||
public Number getValue() { | |||
if ((instFlags[opcode] & CONSTANT_INST) == 0) { | |||
throw new RuntimeException(getName() + " is not a constant instruction"); | |||
} | |||
assert (instFlags[opcode] & CONSTANT_INST) == 0; | |||
// if ((instFlags[opcode] & CONSTANT_INST) == 0) { | |||
// throw new RuntimeException(getName() + " is not a constant instruction"); | |||
// } | |||
switch (opcode) { | |||
case ICONST_M1: | |||
case ICONST_0: | |||
@@ -349,6 +364,11 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
return (Constants.instFlags[opcode] & LOAD_INST) != 0; | |||
} | |||
// remove these from here, leave them in the InstructionLV | |||
public boolean isASTORE() { | |||
return false; | |||
} | |||
public boolean isALOAD() { | |||
return false; | |||
} | |||
@@ -357,13 +377,9 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
return (Constants.instFlags[opcode] & STORE_INST) != 0; | |||
} | |||
public boolean isASTORE() { | |||
return false; | |||
} | |||
public boolean containsTarget(InstructionHandle ih) { | |||
throw new IllegalStateException("Dont ask!!"); | |||
} | |||
// public boolean containsTarget(InstructionHandle ih) { | |||
// throw new IllegalStateException("Dont ask!!"); | |||
// } | |||
public boolean isJsrInstruction() { | |||
return (Constants.instFlags[opcode] & JSR_INSTRUCTION) != 0; | |||
@@ -394,10 +410,11 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
} | |||
public ObjectType getLoadClassType(ConstantPool cpg) { | |||
if ((Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0) { | |||
throw new IllegalStateException("This opcode " + opcode + " does not have the property " | |||
+ Long.toHexString(Constants.LOADCLASS_INST)); | |||
} | |||
assert (Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0; | |||
// if ((Constants.instFlags[opcode] & Constants.LOADCLASS_INST) == 0) { | |||
// throw new IllegalStateException("This opcode " + opcode + " does not have the property " | |||
// + Long.toHexString(Constants.LOADCLASS_INST)); | |||
// } | |||
Type t = getType(cpg); | |||
if (t instanceof ArrayType) { | |||
t = ((ArrayType) t).getBasicType(); | |||
@@ -409,9 +426,9 @@ public class Instruction implements Cloneable, Serializable, Constants { | |||
return (Constants.instFlags[opcode] & RET_INST) != 0; | |||
} | |||
public boolean isGoto() { | |||
return opcode == GOTO || opcode == GOTO_W; | |||
} | |||
// public boolean isGoto() { | |||
// return opcode == GOTO || opcode == GOTO_W; | |||
// } | |||
public boolean isLocalVariableInstruction() { | |||
return (Constants.instFlags[opcode] & LV_INST) != 0; |
@@ -65,7 +65,7 @@ import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
* about an instruction it doesnt yet know the position if (targetInstruction). targetInstruction (if set) overrides targetIndex | |||
* | |||
* @see InstructionList | |||
* @version $Id: InstructionBranch.java,v 1.5 2008/08/28 00:03:03 aclement Exp $ | |||
* @version $Id: InstructionBranch.java,v 1.6 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class InstructionBranch extends Instruction implements InstructionTargeter { | |||
@@ -171,7 +171,7 @@ public class InstructionBranch extends Instruction implements InstructionTargete | |||
} else { | |||
opcode = GOTO_W; | |||
} | |||
return 2; | |||
return 2; // instruction jump destination grows from a short to a long | |||
} else { | |||
throw new IllegalStateException("Unable to pack method, jump (with opcode=" + opcode + ") is too far: " | |||
+ Math.abs(i)); |
@@ -93,4 +93,16 @@ public class InstructionByte extends Instruction { | |||
public final Type getType() { | |||
return new ArrayType(BasicType.getType(theByte), 1); | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof InstructionByte)) { | |||
return false; | |||
} | |||
InstructionByte o = (InstructionByte) other; | |||
return o.opcode == opcode && o.theByte == theByte; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + theByte; | |||
} | |||
} |
@@ -60,24 +60,22 @@ import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.classfile.Constant; | |||
import org.aspectj.apache.bcel.classfile.ConstantClass; | |||
import org.aspectj.apache.bcel.classfile.ConstantDouble; | |||
import org.aspectj.apache.bcel.classfile.ConstantFloat; | |||
import org.aspectj.apache.bcel.classfile.ConstantInteger; | |||
import org.aspectj.apache.bcel.classfile.ConstantLong; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; | |||
import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; | |||
import com.sun.org.apache.bcel.internal.generic.LDC; | |||
import org.aspectj.apache.bcel.classfile.ConstantString; | |||
import org.aspectj.apache.bcel.classfile.ConstantUtf8; | |||
/** | |||
* Slass for instructions that use an index into the constant pool such as LDC, INVOKEVIRTUAL, etc. | |||
* | |||
* @see ConstantPoolGen | |||
* @see LDC | |||
* @see INVOKEVIRTUAL | |||
* Class for instructions that use an index into the constant pool such as LDC, INVOKEVIRTUAL, etc. | |||
* | |||
* @version $Id: InstructionCP.java,v 1.5 2009/09/14 20:29:10 aclement Exp $ | |||
* @version $Id: InstructionCP.java,v 1.6 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class InstructionCP extends Instruction { | |||
protected int index; // index to constant pool | |||
protected int index; | |||
public InstructionCP(short opcode, int index) { | |||
super(opcode); | |||
@@ -180,36 +178,47 @@ public class InstructionCP extends Instruction { | |||
} else { | |||
return Type.getType(name); | |||
} | |||
default: // Never reached | |||
default: | |||
throw new RuntimeException("Unknown or invalid constant type at " + index); | |||
} | |||
} | |||
@Override | |||
public Object getValue(ConstantPool cpg) { | |||
org.aspectj.apache.bcel.classfile.Constant c = cpg.getConstant(index); | |||
public Object getValue(ConstantPool constantPool) { | |||
Constant constant = constantPool.getConstant(index); | |||
switch (c.getTag()) { | |||
case org.aspectj.apache.bcel.Constants.CONSTANT_String: | |||
int i = ((org.aspectj.apache.bcel.classfile.ConstantString) c).getStringIndex(); | |||
c = cpg.getConstant(i); | |||
return ((org.aspectj.apache.bcel.classfile.ConstantUtf8) c).getValue(); | |||
switch (constant.getTag()) { | |||
case Constants.CONSTANT_String: | |||
int i = ((ConstantString) constant).getStringIndex(); | |||
constant = constantPool.getConstant(i); | |||
return ((ConstantUtf8) constant).getValue(); | |||
case org.aspectj.apache.bcel.Constants.CONSTANT_Float: | |||
return new Float(((org.aspectj.apache.bcel.classfile.ConstantFloat) c).getValue()); | |||
case Constants.CONSTANT_Float: | |||
return ((ConstantFloat) constant).getValue(); | |||
case org.aspectj.apache.bcel.Constants.CONSTANT_Integer: | |||
return new Integer(((org.aspectj.apache.bcel.classfile.ConstantInteger) c).getValue()); | |||
case Constants.CONSTANT_Integer: | |||
return ((ConstantInteger) constant).getValue(); | |||
// from ldc2_w: | |||
case org.aspectj.apache.bcel.Constants.CONSTANT_Long: | |||
return new Long(((org.aspectj.apache.bcel.classfile.ConstantLong) c).getValue()); | |||
case Constants.CONSTANT_Long: | |||
return ((ConstantLong) constant).getValue(); | |||
case org.aspectj.apache.bcel.Constants.CONSTANT_Double: | |||
return new Double(((org.aspectj.apache.bcel.classfile.ConstantDouble) c).getValue()); | |||
default: // Never reached | |||
case Constants.CONSTANT_Double: | |||
return ((ConstantDouble) constant).getValue(); | |||
default: | |||
throw new RuntimeException("Unknown or invalid constant type at " + index); | |||
} | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof InstructionCP)) { | |||
return false; | |||
} | |||
InstructionCP o = (InstructionCP) other; | |||
return o.opcode == opcode && o.index == index; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + index; | |||
} | |||
} |
@@ -68,7 +68,7 @@ import org.aspectj.apache.bcel.classfile.Utility; | |||
* doubly-linked list. From the outside only the next and the previous instruction (handle) are accessible. One can traverse the | |||
* list via an Enumeration returned by InstructionList.elements(). | |||
* | |||
* @version $Id: InstructionHandle.java,v 1.8 2009/09/28 16:39:46 aclement Exp $ | |||
* @version $Id: InstructionHandle.java,v 1.9 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Instruction | |||
* @see BranchHandle | |||
@@ -77,9 +77,17 @@ import org.aspectj.apache.bcel.classfile.Utility; | |||
public class InstructionHandle implements java.io.Serializable { | |||
InstructionHandle next, prev; // Will be set from the outside | |||
Instruction instruction; | |||
protected int i_position = -1; // byte code offset of instruction | |||
protected int pos = -1; // byte code offset of instruction | |||
private Set<InstructionTargeter> targeters = Collections.emptySet(); | |||
protected InstructionHandle(Instruction i) { | |||
setInstruction(i); | |||
} | |||
static final InstructionHandle getInstructionHandle(Instruction i) { | |||
return new InstructionHandle(i); | |||
} | |||
public final InstructionHandle getNext() { | |||
return next; | |||
} | |||
@@ -102,41 +110,19 @@ public class InstructionHandle implements java.io.Serializable { | |||
instruction = i; | |||
} | |||
protected InstructionHandle(Instruction i) { | |||
setInstruction(i); | |||
} | |||
static final InstructionHandle getInstructionHandle(Instruction i) { | |||
return new InstructionHandle(i); | |||
} | |||
/** | |||
* Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable length | |||
* instructions 'setPositions()' performs multiple passes over the instruction list to calculate the correct (byte) positions | |||
* and offsets by calling this function. | |||
* | |||
* @param offset additional offset caused by preceding (variable length) instructions | |||
* @param max_offset the maximum offset that may be caused by these instructions | |||
* @return additional offset caused by possible change of this instruction's length | |||
*/ | |||
protected int updatePosition(int offset, int max_offset) { | |||
i_position += offset; | |||
return 0; | |||
} | |||
/** | |||
* @return the position, i.e., the byte code offset of the contained instruction. This is accurate only after | |||
* InstructionList.setPositions() has been called. | |||
*/ | |||
public int getPosition() { | |||
return i_position; | |||
return pos; | |||
} | |||
/** | |||
* Set the position, i.e., the byte code offset of the contained instruction. | |||
*/ | |||
void setPosition(int pos) { | |||
i_position = pos; | |||
this.pos = pos; | |||
} | |||
/** | |||
@@ -147,7 +133,7 @@ public class InstructionHandle implements java.io.Serializable { | |||
next = prev = null; | |||
instruction.dispose(); | |||
instruction = null; | |||
i_position = -1; | |||
pos = -1; | |||
removeAllTargeters(); | |||
} | |||
@@ -179,7 +165,6 @@ public class InstructionHandle implements java.io.Serializable { | |||
return !targeters.isEmpty(); | |||
} | |||
public Set<InstructionTargeter> getTargeters() { | |||
return targeters; | |||
} | |||
@@ -194,7 +179,7 @@ public class InstructionHandle implements java.io.Serializable { | |||
* @return a (verbose) string representation of the contained instruction. | |||
*/ | |||
public String toString(boolean verbose) { | |||
return Utility.format(i_position, 4, false, ' ') + ": " + instruction.toString(verbose); | |||
return Utility.format(pos, 4, false, ' ') + ": " + instruction.toString(verbose); | |||
} | |||
public String toString() { |
@@ -61,7 +61,7 @@ import org.aspectj.apache.bcel.Constants; | |||
/** | |||
* Abstract super class for instructions dealing with local variables. | |||
* | |||
* @version $Id: InstructionLV.java,v 1.4 2008/08/28 00:05:01 aclement Exp $ | |||
* @version $Id: InstructionLV.java,v 1.5 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class InstructionLV extends Instruction { | |||
@@ -263,4 +263,16 @@ public class InstructionLV extends Instruction { | |||
return lvar > Constants.MAX_BYTE; | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof InstructionLV)) { | |||
return false; | |||
} | |||
InstructionLV o = (InstructionLV) other; | |||
return o.opcode == opcode && o.lvar == lvar; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + lvar; | |||
} | |||
} |
@@ -76,7 +76,7 @@ import org.aspectj.apache.bcel.util.ByteSequence; | |||
* | |||
* A list is finally dumped to a byte code array with <a href="#getByteCode()">getByteCode</a>. | |||
* | |||
* @version $Id: InstructionList.java,v 1.9 2009/09/10 03:59:33 aclement Exp $ | |||
* @version $Id: InstructionList.java,v 1.10 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see Instruction | |||
* @see InstructionHandle | |||
@@ -247,35 +247,34 @@ public class InstructionList implements Serializable { | |||
/** | |||
* Append another list after instruction (handle) ih contained in this list. Consumes argument list, i.e., it becomes empty. | |||
* | |||
* @param ih where to append the instruction list | |||
* @param il Instruction list to append to this one | |||
* @param appendTo where to append the instruction list | |||
* @param appendee Instruction list to append to this one | |||
* @return instruction handle pointing to the <B>first</B> appended instruction | |||
*/ | |||
public InstructionHandle append(InstructionHandle ih, InstructionList il) { | |||
if (il == null) { | |||
throw new ClassGenException("Appending null InstructionList"); | |||
} | |||
public InstructionHandle append(InstructionHandle appendTo, InstructionList appendee) { | |||
assert appendee != null; | |||
if (il.isEmpty()) { | |||
return ih; | |||
if (appendee.isEmpty()) { | |||
return appendTo; | |||
} | |||
InstructionHandle next = ih.next, ret = il.start; | |||
InstructionHandle next = appendTo.next; | |||
InstructionHandle ret = appendee.start; | |||
ih.next = il.start; | |||
il.start.prev = ih; | |||
appendTo.next = appendee.start; | |||
appendee.start.prev = appendTo; | |||
il.end.next = next; | |||
appendee.end.next = next; | |||
if (next != null) { | |||
next.prev = il.end; | |||
next.prev = appendee.end; | |||
} else { | |||
end = il.end; // Update end ... | |||
end = appendee.end; // Update end ... | |||
} | |||
length += il.length; // Update length | |||
length += appendee.length; // Update length | |||
il.clear(); | |||
appendee.clear(); | |||
return ret; | |||
} | |||
@@ -304,9 +303,7 @@ public class InstructionList implements Serializable { | |||
* @return instruction handle of the <B>first</B> appended instruction | |||
*/ | |||
public InstructionHandle append(InstructionList il) { | |||
if (il == null) { | |||
throw new ClassGenException("Appending null InstructionList"); | |||
} | |||
assert il != null; | |||
if (il.isEmpty()) { | |||
return null; | |||
@@ -853,41 +850,13 @@ public class InstructionList implements Serializable { | |||
* @param check Perform sanity checks, e.g. if all targeted instructions really belong to this list | |||
*/ | |||
public void setPositions(boolean check) { | |||
int max_additional_bytes = 0, additional_bytes = 0; | |||
int maxAdditionalBytes = 0; | |||
int index = 0, count = 0; | |||
int[] pos = new int[length]; | |||
// Pass 0: Sanity checks | |||
if (check) { | |||
for (InstructionHandle ih = start; ih != null; ih = ih.next) { | |||
Instruction i = ih.instruction; | |||
if (i instanceof InstructionBranch) { // target instruction within list? | |||
Instruction inst = ((InstructionBranch) i).getTarget().instruction; | |||
if (!contains(inst)) { | |||
throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not in instruction list"); | |||
} | |||
if (i instanceof InstructionSelect) { | |||
InstructionHandle[] targets = ((InstructionSelect) i).getTargets(); | |||
for (int j = 0; j < targets.length; j++) { | |||
inst = targets[j].instruction; | |||
if (!contains(inst)) { | |||
throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not in instruction list"); | |||
} | |||
} | |||
} | |||
if (!(ih instanceof BranchHandle)) { | |||
throw new ClassGenException("Branch instruction " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not contained in BranchHandle."); | |||
} | |||
} | |||
} | |||
checkInstructionList(); | |||
} | |||
// Pass 1: Set position numbers and sum up the maximum number of bytes an | |||
@@ -904,40 +873,81 @@ public class InstructionList implements Serializable { | |||
switch (i.opcode) { | |||
case Constants.JSR: | |||
case Constants.GOTO: | |||
max_additional_bytes += 2; | |||
maxAdditionalBytes += 2; | |||
break; | |||
case Constants.TABLESWITCH: | |||
case Constants.LOOKUPSWITCH: | |||
max_additional_bytes += 3; | |||
maxAdditionalBytes += 3; | |||
break; | |||
} | |||
index += i.getLength(); | |||
} | |||
// OPTIMIZE positions will only move around if there have been expanding instructions | |||
// if (max_additional_bytes==0...) { | |||
// | |||
// } | |||
/* | |||
* Pass 2: Expand the variable-length (Branch)Instructions depending on the target offset (short or int) and ensure that | |||
* branch targets are within this list. | |||
*/ | |||
int offset = 0; | |||
for (InstructionHandle ih = start; ih != null; ih = ih.next) { | |||
additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes); | |||
if (ih instanceof BranchHandle) { | |||
offset += ((BranchHandle) ih).updatePosition(offset, maxAdditionalBytes); | |||
} | |||
} | |||
/* | |||
* Pass 3: Update position numbers (which may have changed due to the preceding expansions), like pass 1. | |||
*/ | |||
index = count = 0; | |||
for (InstructionHandle ih = start; ih != null; ih = ih.next) { | |||
Instruction i = ih.instruction; | |||
ih.setPosition(index); | |||
pos[count++] = index; | |||
index += i.getLength(); | |||
if (offset != 0) { | |||
/* | |||
* Pass 3: Update position numbers (which may have changed due to the preceding expansions), like pass 1. | |||
*/ | |||
index = count = 0; | |||
for (InstructionHandle ih = start; ih != null; ih = ih.next) { | |||
Instruction i = ih.instruction; | |||
ih.setPosition(index); | |||
pos[count++] = index; | |||
index += i.getLength(); | |||
} | |||
} | |||
positions = new int[count]; // Trim to proper size | |||
System.arraycopy(pos, 0, positions, 0, count); | |||
} | |||
private void checkInstructionList() { | |||
for (InstructionHandle ih = start; ih != null; ih = ih.next) { | |||
Instruction i = ih.instruction; | |||
if (i instanceof InstructionBranch) { // target instruction within list? | |||
Instruction inst = ((InstructionBranch) i).getTarget().instruction; | |||
if (!contains(inst)) { | |||
throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not in instruction list"); | |||
} | |||
if (i instanceof InstructionSelect) { | |||
InstructionHandle[] targets = ((InstructionSelect) i).getTargets(); | |||
for (int j = 0; j < targets.length; j++) { | |||
inst = targets[j].instruction; | |||
if (!contains(inst)) { | |||
throw new ClassGenException("Branch target of " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not in instruction list"); | |||
} | |||
} | |||
} | |||
if (!(ih instanceof BranchHandle)) { | |||
throw new ClassGenException("Branch instruction " + Constants.OPCODE_NAMES[i.opcode] + ":" + inst | |||
+ " not contained in BranchHandle."); | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* When everything is finished, use this method to convert the instruction list into an array of bytes. | |||
* |
@@ -61,7 +61,7 @@ import org.aspectj.apache.bcel.util.ByteSequence; | |||
/** | |||
* Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions. | |||
* | |||
* @version $Id: InstructionSelect.java,v 1.3 2008/08/28 00:05:41 aclement Exp $ | |||
* @version $Id: InstructionSelect.java,v 1.4 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @see LOOKUPSWITCH | |||
* @see TABLESWITCH | |||
@@ -78,15 +78,13 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
protected short length; | |||
/** | |||
* (Match, target) pairs for switch. `Match' and `targets' must have the | |||
* same length of course. | |||
* (Match, target) pairs for switch. `Match' and `targets' must have the same length of course. | |||
* | |||
* @param match array of matching values | |||
* @param targets instruction targets | |||
* @param target default instruction target | |||
*/ | |||
InstructionSelect(short opcode, int[] match, InstructionHandle[] targets, | |||
InstructionHandle target) { | |||
InstructionSelect(short opcode, int[] match, InstructionHandle[] targets, InstructionHandle target) { | |||
super(opcode, target); | |||
this.targets = targets; | |||
@@ -97,8 +95,7 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
this.match = match; | |||
if ((matchLength = match.length) != targets.length) { | |||
throw new ClassGenException( | |||
"Match and target array have not the same length"); | |||
throw new ClassGenException("Match and target array have not the same length"); | |||
} | |||
indices = new int[matchLength]; | |||
@@ -106,37 +103,30 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
protected int getTargetOffset(InstructionHandle target) { | |||
if (target == null) { | |||
throw new ClassGenException("Target of " + super.toString(true) | |||
+ " is invalid null handle"); | |||
throw new ClassGenException("Target of " + super.toString(true) + " is invalid null handle"); | |||
} | |||
int t = target.getPosition(); | |||
if (t < 0) { | |||
throw new ClassGenException( | |||
"Invalid branch target position offset for " | |||
+ super.toString(true) + ":" + t + ":" + target); | |||
throw new ClassGenException("Invalid branch target position offset for " + super.toString(true) + ":" + t + ":" | |||
+ target); | |||
} | |||
return t - positionOfThisInstruction; | |||
} | |||
/** | |||
* Since this is a variable length instruction, it may shift the following | |||
* instructions which then need to update their position. | |||
* Since this is a variable length instruction, it may shift the following instructions which then need to update their | |||
* position. | |||
* | |||
* Called by InstructionList.setPositions when setting the position for | |||
* every instruction. In the presence of variable length instructions | |||
* `setPositions' performs multiple passes over the instruction list to | |||
* calculate the correct (byte) positions and offsets by calling this | |||
* function. | |||
* Called by InstructionList.setPositions when setting the position for every instruction. In the presence of variable length | |||
* instructions `setPositions' performs multiple passes over the instruction list to calculate the correct (byte) positions and | |||
* offsets by calling this function. | |||
* | |||
* @param offset additional offset caused by preceding (variable length) | |||
* instructions | |||
* @param max_offset the maximum offset that may be caused by these | |||
* instructions | |||
* @return additional offset caused by possible change of this instruction's | |||
* length | |||
* @param offset additional offset caused by preceding (variable length) instructions | |||
* @param max_offset the maximum offset that may be caused by these instructions | |||
* @return additional offset caused by possible change of this instruction's length | |||
*/ | |||
protected int updatePosition(int offset, int max_offset) { | |||
positionOfThisInstruction += offset; // Additional offset caused by | |||
@@ -170,8 +160,7 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
out.writeInt(targetIndex); | |||
} | |||
public InstructionSelect(short opcode, ByteSequence bytes) | |||
throws IOException { | |||
public InstructionSelect(short opcode, ByteSequence bytes) throws IOException { | |||
super(opcode); | |||
padding = (4 - bytes.getIndex() % 4) % 4; // Compute number of pad bytes | |||
@@ -198,8 +187,7 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
s = targets[i].getInstruction().toString(); | |||
} | |||
buf.append("(" + match[i] + ", " + s + " = {" + indices[i] | |||
+ "})"); | |||
buf.append("(" + match[i] + ", " + s + " = {" + indices[i] + "})"); | |||
} | |||
} else { | |||
buf.append(" ..."); | |||
@@ -268,14 +256,6 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
} | |||
} | |||
public boolean equals(Object other) { | |||
return this == other; | |||
} | |||
public int hashCode() { | |||
return opcode * 37; | |||
} | |||
/** | |||
* @return array of match indices | |||
*/ | |||
@@ -290,6 +270,14 @@ public abstract class InstructionSelect extends InstructionBranch { | |||
return indices; | |||
} | |||
public boolean equals(Object other) { | |||
return this == other; | |||
} | |||
public int hashCode() { | |||
return opcode * 37; | |||
} | |||
/** | |||
* @return array of match targets | |||
*/ |
@@ -61,20 +61,32 @@ import java.io.IOException; | |||
* Instruction that needs one short | |||
*/ | |||
public class InstructionShort extends Instruction { | |||
private final short s; | |||
private final short value; | |||
public InstructionShort(short opcode, short s) { | |||
public InstructionShort(short opcode, short value) { | |||
super(opcode); | |||
this.s = s; | |||
this.value = value; | |||
} | |||
public void dump(DataOutputStream out) throws IOException { | |||
out.writeByte(opcode); | |||
out.writeShort(s); | |||
out.writeShort(value); | |||
} | |||
public String toString(boolean verbose) { | |||
return super.toString(verbose) + " " + s; | |||
return super.toString(verbose) + " " + value; | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof InstructionShort)) { | |||
return false; | |||
} | |||
InstructionShort o = (InstructionShort) other; | |||
return o.opcode == opcode && o.value == value; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + value; | |||
} | |||
} |
@@ -61,72 +61,77 @@ import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
/** | |||
* Super class for the INVOKExxx family of instructions. | |||
* | |||
* @version $Id: InvokeInstruction.java,v 1.5 2008/05/28 23:52:54 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* @version $Id: InvokeInstruction.java,v 1.6 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class InvokeInstruction extends FieldOrMethod { | |||
/** | |||
* @param index to constant pool | |||
*/ | |||
public InvokeInstruction(short opcode, int index) { | |||
super(opcode, index); | |||
} | |||
/** | |||
* @param index to constant pool | |||
*/ | |||
public InvokeInstruction(short opcode, int index) { | |||
super(opcode, index); | |||
} | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
Constant c = cp.getConstant(index); | |||
StringTokenizer tok = new StringTokenizer(cp.constantToString(c)); | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
Constant c = cp.getConstant(index); | |||
StringTokenizer tok = new StringTokenizer(cp.constantToString(c)); | |||
return Constants.OPCODE_NAMES[opcode] + " " + | |||
tok.nextToken().replace('.', '/') + tok.nextToken(); | |||
} | |||
return Constants.OPCODE_NAMES[opcode] + " " + tok.nextToken().replace('.', '/') + tok.nextToken(); | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the | |||
* constant pool entry they reference. | |||
* @return Number of words consumed from stack by this instruction | |||
*/ | |||
public int consumeStack(ConstantPool cpg) { | |||
String signature = getSignature(cpg); | |||
int sum = Type.getArgumentSizes(signature); | |||
if (opcode!=Constants.INVOKESTATIC) sum+=1; | |||
return sum; | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the constant pool entry they reference. | |||
* | |||
* @return Number of words consumed from stack by this instruction | |||
*/ | |||
public int consumeStack(ConstantPool cpg) { | |||
String signature = getSignature(cpg); | |||
int sum = Type.getArgumentSizes(signature); | |||
if (opcode != Constants.INVOKESTATIC) { | |||
sum += 1; | |||
} | |||
return sum; | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the | |||
* constant pool entry they reference. | |||
* @return Number of words produced onto stack by this instruction | |||
*/ | |||
public int produceStack(ConstantPool cpg) { | |||
return getReturnType(cpg).getSize(); | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the constant pool entry they reference. | |||
* | |||
* @return Number of words produced onto stack by this instruction | |||
*/ | |||
public int produceStack(ConstantPool cpg) { | |||
return getReturnType(cpg).getSize(); | |||
} | |||
/** @return return type of referenced method. | |||
*/ | |||
public Type getType(ConstantPool cpg) { | |||
return getReturnType(cpg); | |||
} | |||
/** | |||
* @return return type of referenced method. | |||
*/ | |||
public Type getType(ConstantPool cpg) { | |||
return getReturnType(cpg); | |||
} | |||
/** @return name of referenced method. | |||
*/ | |||
public String getMethodName(ConstantPool cpg) { | |||
return getName(cpg); | |||
} | |||
/** | |||
* @return name of referenced method. | |||
*/ | |||
public String getMethodName(ConstantPool cpg) { | |||
return getName(cpg); | |||
} | |||
/** @return return type of referenced method. | |||
*/ | |||
public Type getReturnType(ConstantPool cpg) { | |||
return Type.getReturnType(getSignature(cpg)); | |||
} | |||
/** | |||
* @return return type of referenced method. | |||
*/ | |||
public Type getReturnType(ConstantPool cpg) { | |||
return Type.getReturnType(getSignature(cpg)); | |||
} | |||
/** @return argument types of referenced method. | |||
*/ | |||
public Type[] getArgumentTypes(ConstantPool cpg) { | |||
return Type.getArgumentTypes(getSignature(cpg)); | |||
} | |||
/** | |||
* @return argument types of referenced method. | |||
*/ | |||
public Type[] getArgumentTypes(ConstantPool cpg) { | |||
return Type.getArgumentTypes(getSignature(cpg)); | |||
} | |||
} |
@@ -14,28 +14,30 @@ | |||
package org.aspectj.apache.bcel.generic; | |||
public final class LocalVariableTag extends Tag { | |||
private Type type; // not always known, in which case signature has to be used | |||
private final String signature; | |||
private String name; | |||
private int slot; | |||
private final int startPos; | |||
boolean remapped = false; | |||
private final int startPosition; | |||
private boolean remapped = false; | |||
private int hashCode = 0; | |||
private Type type; // not always known, in which case signature has to be used | |||
// AMC - pr101047, two local vars with the same name can share the same slot, but must in that case | |||
// have different start positions. | |||
public LocalVariableTag(String sig, String name, int slot, int startPosition) { | |||
this.signature = sig; | |||
public LocalVariableTag(String signature, String name, int slot, int startPosition) { | |||
this.signature = signature; | |||
this.name = name; | |||
this.slot = slot; | |||
this.startPos = startPosition; | |||
this.startPosition = startPosition; | |||
} | |||
public LocalVariableTag(Type t, String sig, String name, int slot, int startPosition) { | |||
this.type = t; | |||
this.signature = sig; | |||
public LocalVariableTag(Type type, String signature, String name, int slot, int startPosition) { | |||
this.type = type; | |||
this.signature = signature; | |||
this.name = name; | |||
this.slot = slot; | |||
this.startPos = startPosition; | |||
this.startPosition = startPosition; | |||
} | |||
public String getName() { | |||
@@ -57,6 +59,12 @@ public final class LocalVariableTag extends Tag { | |||
public void updateSlot(int newSlot) { | |||
this.slot = newSlot; | |||
this.remapped = true; | |||
this.hashCode = 0; | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
this.hashCode = 0; | |||
} | |||
public boolean isRemapped() { | |||
@@ -68,25 +76,19 @@ public final class LocalVariableTag extends Tag { | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof LocalVariableTag)) | |||
if (!(other instanceof LocalVariableTag)) { | |||
return false; | |||
} | |||
LocalVariableTag o = (LocalVariableTag) other; | |||
return o.slot == slot && o.startPos == startPos && o.signature.equals(signature) && o.name.equals(name); | |||
return o.slot == slot && o.startPosition == startPosition && o.signature.equals(signature) && o.name.equals(name); | |||
} | |||
public void setName(String name) { | |||
this.name = name; | |||
} | |||
private int hashCode = 0; | |||
public int hashCode() { | |||
if (hashCode == 0) { | |||
int ret = 17; | |||
ret = 37 * ret + signature.hashCode(); | |||
int ret = signature.hashCode(); | |||
ret = 37 * ret + name.hashCode(); | |||
ret = 37 * ret + slot; | |||
ret = 37 * ret + startPos; | |||
ret = 37 * ret + startPosition; | |||
hashCode = ret; | |||
} | |||
return hashCode; |
@@ -53,109 +53,131 @@ package org.aspectj.apache.bcel.generic; | |||
* information on the Apache Software Foundation, please see | |||
* <http://www.apache.org/>. | |||
*/ | |||
import java.io.*; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
import java.io.DataOutputStream; | |||
import java.io.IOException; | |||
import org.aspectj.apache.bcel.Constants; | |||
import org.aspectj.apache.bcel.ExceptionConstants; | |||
import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
/** | |||
/** | |||
* MULTIANEWARRAY - Create new mutidimensional array of references | |||
* <PRE>Stack: ..., count1, [count2, ...] -> ..., arrayref</PRE> | |||
* | |||
* @version $Id: MULTIANEWARRAY.java,v 1.3 2008/05/28 23:52:59 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* <PRE> | |||
* Stack: ..., count1, [count2, ...] -> ..., arrayref | |||
* </PRE> | |||
* | |||
* @version $Id: MULTIANEWARRAY.java,v 1.4 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class MULTIANEWARRAY extends InstructionCP { | |||
private short dimensions; | |||
public MULTIANEWARRAY(int index, short dimensions) { | |||
super(Constants.MULTIANEWARRAY, index); | |||
this.dimensions = dimensions; | |||
} | |||
/** | |||
* Dump instruction as byte code to stream out. | |||
* @param out Output stream | |||
*/ | |||
public void dump(DataOutputStream out) throws IOException { | |||
out.writeByte(opcode); | |||
out.writeShort(index); | |||
out.writeByte(dimensions); | |||
} | |||
/** | |||
* Read needed data (i.e., no. dimension) from file. | |||
*/ | |||
// protected void initFromFile(ByteSequence bytes, boolean wide) | |||
// throws IOException | |||
// { | |||
// super.initFromFile(bytes, wide); | |||
// dimensions = bytes.readByte(); | |||
//// length = 4; | |||
// } | |||
/** | |||
* @return number of dimensions to be created | |||
*/ | |||
public final short getDimensions() { return dimensions; } | |||
/** | |||
* @return mnemonic for instruction | |||
*/ | |||
public String toString(boolean verbose) { | |||
return super.toString(verbose) + " " + index + " " + dimensions; | |||
} | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
return super.toString(cp) + " " + dimensions; | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the | |||
* constant pool entry they reference. | |||
* @return Number of words consumed from stack by this instruction | |||
*/ | |||
public int consumeStack(ConstantPool cpg) { return dimensions; } | |||
public Class[] getExceptions() { | |||
Class[] cs = new Class[2 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; | |||
System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, | |||
cs, 0, ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); | |||
cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length+1] = ExceptionConstants.NEGATIVE_ARRAY_SIZE_EXCEPTION; | |||
cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.ILLEGAL_ACCESS_ERROR; | |||
return cs; | |||
} | |||
public ObjectType getLoadClassType(ConstantPool cpg) { | |||
Type t = getType(cpg); | |||
if (t instanceof ArrayType){ | |||
t = ((ArrayType) t).getBasicType(); | |||
} | |||
return (t instanceof ObjectType)? (ObjectType) t : null; | |||
} | |||
// /** | |||
// * Call corresponding visitor method(s). The order is: | |||
// * Call visitor methods of implemented interfaces first, then | |||
// * call methods according to the class hierarchy in descending order, | |||
// * i.e., the most specific visitXXX() call comes last. | |||
// * | |||
// * @param v Visitor object | |||
// */ | |||
// public void accept(Visitor v) { | |||
// v.visitLoadClass(this); | |||
// v.visitAllocationInstruction(this); | |||
// v.visitExceptionThrower(this); | |||
// v.visitTypedInstruction(this); | |||
// v.visitCPInstruction(this); | |||
// v.visitMULTIANEWARRAY(this); | |||
// } | |||
private short dimensions; | |||
public MULTIANEWARRAY(int index, short dimensions) { | |||
super(Constants.MULTIANEWARRAY, index); | |||
this.dimensions = dimensions; | |||
} | |||
/** | |||
* Dump instruction as byte code to stream out. | |||
* | |||
* @param out Output stream | |||
*/ | |||
public void dump(DataOutputStream out) throws IOException { | |||
out.writeByte(opcode); | |||
out.writeShort(index); | |||
out.writeByte(dimensions); | |||
} | |||
/** | |||
* Read needed data (i.e., no. dimension) from file. | |||
*/ | |||
// protected void initFromFile(ByteSequence bytes, boolean wide) | |||
// throws IOException | |||
// { | |||
// super.initFromFile(bytes, wide); | |||
// dimensions = bytes.readByte(); | |||
// // length = 4; | |||
// } | |||
/** | |||
* @return number of dimensions to be created | |||
*/ | |||
public final short getDimensions() { | |||
return dimensions; | |||
} | |||
/** | |||
* @return mnemonic for instruction | |||
*/ | |||
public String toString(boolean verbose) { | |||
return super.toString(verbose) + " " + index + " " + dimensions; | |||
} | |||
/** | |||
* @return mnemonic for instruction with symbolic references resolved | |||
*/ | |||
public String toString(ConstantPool cp) { | |||
return super.toString(cp) + " " + dimensions; | |||
} | |||
/** | |||
* Also works for instructions whose stack effect depends on the constant pool entry they reference. | |||
* | |||
* @return Number of words consumed from stack by this instruction | |||
*/ | |||
public int consumeStack(ConstantPool cpg) { | |||
return dimensions; | |||
} | |||
public Class[] getExceptions() { | |||
Class[] cs = new Class[2 + ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length]; | |||
System.arraycopy(ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION, 0, cs, 0, | |||
ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length); | |||
cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length + 1] = ExceptionConstants.NEGATIVE_ARRAY_SIZE_EXCEPTION; | |||
cs[ExceptionConstants.EXCS_CLASS_AND_INTERFACE_RESOLUTION.length] = ExceptionConstants.ILLEGAL_ACCESS_ERROR; | |||
return cs; | |||
} | |||
public ObjectType getLoadClassType(ConstantPool cpg) { | |||
Type t = getType(cpg); | |||
if (t instanceof ArrayType) { | |||
t = ((ArrayType) t).getBasicType(); | |||
} | |||
return (t instanceof ObjectType) ? (ObjectType) t : null; | |||
} | |||
// /** | |||
// * Call corresponding visitor method(s). The order is: | |||
// * Call visitor methods of implemented interfaces first, then | |||
// * call methods according to the class hierarchy in descending order, | |||
// * i.e., the most specific visitXXX() call comes last. | |||
// * | |||
// * @param v Visitor object | |||
// */ | |||
// public void accept(Visitor v) { | |||
// v.visitLoadClass(this); | |||
// v.visitAllocationInstruction(this); | |||
// v.visitExceptionThrower(this); | |||
// v.visitTypedInstruction(this); | |||
// v.visitCPInstruction(this); | |||
// v.visitMULTIANEWARRAY(this); | |||
// } | |||
public boolean equals(Object other) { | |||
if (!(other instanceof MULTIANEWARRAY)) { | |||
return false; | |||
} | |||
MULTIANEWARRAY o = (MULTIANEWARRAY) other; | |||
return o.opcode == opcode && o.index == index && o.dimensions == dimensions; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + index * (dimensions + 17); | |||
} | |||
} |
@@ -84,7 +84,7 @@ import org.aspectj.apache.bcel.classfile.annotation.RuntimeParamAnnos; | |||
* While generating code it may be necessary to insert NOP operations. You can use the `removeNOPs' method to get rid off them. The | |||
* resulting method object can be obtained via the `getMethod()' method. | |||
* | |||
* @version $Id: MethodGen.java,v 1.15 2009/09/15 19:40:14 aclement Exp $ | |||
* @version $Id: MethodGen.java,v 1.16 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* @author <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()] | |||
* @see InstructionList | |||
@@ -264,8 +264,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
for (int k = 0; k < ln.length; k++) { | |||
LineNumber l = ln[k]; | |||
int lnum = l.getLineNumber(); | |||
if (lnum > highestLineNumber) | |||
if (lnum > highestLineNumber) { | |||
highestLineNumber = lnum; | |||
} | |||
LineNumberTag lt = new LineNumberTag(lnum); | |||
il.findHandle(l.getStartPC(), arrayOfInstructions, true).addTargeter(lt); | |||
} | |||
@@ -290,8 +291,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
byte b = t.getType(); | |||
if (b != Constants.T_ADDRESS) { | |||
int increment = t.getSize(); | |||
if (l.getIndex() + increment > maxLocals) | |||
if (l.getIndex() + increment > maxLocals) { | |||
maxLocals = l.getIndex() + increment; | |||
} | |||
} | |||
int end = l.getStartPC() + l.getLength(); | |||
do { | |||
@@ -311,24 +313,29 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength(), arrayOfInstructions); | |||
// AMC, this actually gives us the first instruction AFTER the range, | |||
// so move back one... (findHandle can't cope with mid-instruction indices) | |||
if (end != null) | |||
if (end != null) { | |||
end = end.getPrev(); | |||
} | |||
// Repair malformed handles | |||
if (null == start) | |||
if (null == start) { | |||
start = il.getStart(); | |||
if (null == end) | |||
} | |||
if (null == end) { | |||
end = il.getEnd(); | |||
} | |||
addLocalVariable(l.getName(), Type.getType(l.getSignature()), l.getIndex(), start, end); | |||
} | |||
} | |||
} else | |||
} else { | |||
addCodeAttribute(a); | |||
} | |||
} | |||
} else if (a instanceof ExceptionTable) { | |||
String[] names = ((ExceptionTable) a).getExceptionNames(); | |||
for (int j = 0; j < names.length; j++) | |||
for (int j = 0; j < names.length; j++) { | |||
addException(names[j]); | |||
} | |||
} else if (a instanceof RuntimeAnnos) { | |||
RuntimeAnnos runtimeAnnotations = (RuntimeAnnos) a; | |||
List<AnnotationGen> l = runtimeAnnotations.getAnnotations(); | |||
@@ -395,10 +402,12 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
LocalVariableGen h; | |||
do { | |||
while (vars[i].getIndex() < m) | |||
while (vars[i].getIndex() < m) { | |||
i++; | |||
while (m < vars[j].getIndex()) | |||
} | |||
while (m < vars[j].getIndex()) { | |||
j--; | |||
} | |||
if (i <= j) { | |||
h = vars[i]; | |||
@@ -409,10 +418,12 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
} while (i <= j); | |||
if (l < j) | |||
if (l < j) { | |||
sort(vars, l, j); | |||
if (i < r) | |||
} | |||
if (i < r) { | |||
sort(vars, i, r); | |||
} | |||
} | |||
/* | |||
@@ -427,15 +438,18 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
localVariablesList.toArray(lg); | |||
for (int i = 0; i < size; i++) { | |||
if (lg[i].getStart() == null) | |||
if (lg[i].getStart() == null) { | |||
lg[i].setStart(il.getStart()); | |||
} | |||
if (lg[i].getEnd() == null) | |||
if (lg[i].getEnd() == null) { | |||
lg[i].setEnd(il.getEnd()); | |||
} | |||
} | |||
if (size > 1) | |||
if (size > 1) { | |||
sort(lg, 0, size - 1); | |||
} | |||
return lg; | |||
} | |||
@@ -448,8 +462,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
int size = lg.length; | |||
LocalVariable[] lv = new LocalVariable[size]; | |||
for (int i = 0; i < size; i++) | |||
for (int i = 0; i < size; i++) { | |||
lv[i] = lg[i].getLocalVariable(cp); | |||
} | |||
return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp); | |||
} | |||
@@ -516,8 +531,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
*/ | |||
public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc, InstructionHandle end_pc, InstructionHandle handler_pc, | |||
ObjectType catch_type) { | |||
if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) | |||
if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) { | |||
throw new ClassGenException("Exception handler target is null instruction"); | |||
} | |||
CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type); | |||
exceptionsList.add(c); | |||
@@ -605,8 +621,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
int[] ex = new int[size]; | |||
try { | |||
for (int i = 0; i < size; i++) | |||
for (int i = 0; i < size; i++) { | |||
ex[i] = cp.addClass(exceptionsThrown.get(i)); | |||
} | |||
} catch (ArrayIndexOutOfBoundsException e) { | |||
} | |||
@@ -625,8 +642,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
public void addParameterAnnotationsAsAttribute(ConstantPool cp) { | |||
if (!hasParameterAnnotations) | |||
if (!hasParameterAnnotations) { | |||
return; | |||
} | |||
Attribute[] attrs = Utility.getParameterAnnotationAttributes(cp, param_annotations); | |||
if (attrs != null) { | |||
for (int i = 0; i < attrs.length; i++) { | |||
@@ -674,8 +692,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
*/ | |||
byte[] byte_code = null; | |||
if (il != null) | |||
if (il != null) { | |||
byte_code = il.getByteCode(); | |||
} | |||
LineNumberTable lnt = null; | |||
LocalVariableTable lvt = null; | |||
@@ -684,11 +703,13 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
/* | |||
* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.) | |||
*/ | |||
if ((localVariablesList.size() > 0) && !stripAttributes) | |||
if ((localVariablesList.size() > 0) && !stripAttributes) { | |||
addCodeAttribute(lvt = getLocalVariableTable(cp)); | |||
} | |||
if ((lineNumbersList.size() > 0) && !stripAttributes) | |||
if ((lineNumbersList.size() > 0) && !stripAttributes) { | |||
addCodeAttribute(lnt = getLineNumberTable(cp)); | |||
} | |||
Attribute[] code_attrs = getCodeAttributes(); | |||
@@ -696,8 +717,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
* Each attribute causes 6 additional header bytes | |||
*/ | |||
int attrs_len = 0; | |||
for (int i = 0; i < code_attrs.length; i++) | |||
for (int i = 0; i < code_attrs.length; i++) { | |||
attrs_len += (code_attrs[i].getLength() + 6); | |||
} | |||
CodeException[] c_exc = getCodeExceptions(); | |||
int exc_len = c_exc.length * 8; // Every entry takes 8 bytes | |||
@@ -709,8 +731,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
List<Attribute> attributes = getAttributes(); | |||
for (int i = 0; i < attributes.size(); i++) { | |||
Attribute a = attributes.get(i); | |||
if (a instanceof Code) | |||
if (a instanceof Code) { | |||
removeAttribute(a); | |||
} | |||
} | |||
code = new Code(cp.addUtf8("Code"), 8 + byte_code.length + // prologue byte code | |||
@@ -726,21 +749,26 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
ExceptionTable et = null; | |||
if (exceptionsThrown.size() > 0) | |||
if (exceptionsThrown.size() > 0) { | |||
addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses | |||
} | |||
Method m = new Method(modifiers, name_index, signature_index, getAttributesImmutable(), cp); | |||
// Undo effects of adding attributes | |||
// OPTIMIZE why redo this? is there a better way to clean up? | |||
if (lvt != null) | |||
if (lvt != null) { | |||
removeCodeAttribute(lvt); | |||
if (lnt != null) | |||
} | |||
if (lnt != null) { | |||
removeCodeAttribute(lnt); | |||
if (code != null) | |||
} | |||
if (code != null) { | |||
removeAttribute(code); | |||
if (et != null) | |||
} | |||
if (et != null) { | |||
removeAttribute(et); | |||
} | |||
// J5TODO: Remove the annotation attributes that may have been added | |||
return m; | |||
} | |||
@@ -807,10 +835,11 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
public String[] getArgumentNames() { | |||
if (parameterNames != null) | |||
if (parameterNames != null) { | |||
return parameterNames.clone(); | |||
else | |||
} else { | |||
return new String[0]; | |||
} | |||
} | |||
public void setArgumentName(int i, String name) { | |||
@@ -838,10 +867,11 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
* Computes max. stack size by performing control flow analysis. | |||
*/ | |||
public void setMaxStack() { | |||
if (il != null) | |||
if (il != null) { | |||
maxStack = getMaxStack(cp, il, getExceptionHandlers()); | |||
else | |||
} else { | |||
maxStack = 0; | |||
} | |||
} | |||
/** | |||
@@ -851,9 +881,11 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
if (il != null) { | |||
int max = isStatic() ? 0 : 1; | |||
if (parameterTypes != null) | |||
for (int i = 0; i < parameterTypes.length; i++) | |||
if (parameterTypes != null) { | |||
for (int i = 0; i < parameterTypes.length; i++) { | |||
max += parameterTypes[i].getSize(); | |||
} | |||
} | |||
for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { | |||
Instruction ins = ih.getInstruction(); | |||
@@ -861,14 +893,16 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
if ((ins instanceof InstructionLV) || (ins instanceof RET)) { | |||
int index = ins.getIndex() + ins.getType(cp).getSize(); | |||
if (index > max) | |||
if (index > max) { | |||
max = index; | |||
} | |||
} | |||
} | |||
maxLocals = max; | |||
} else | |||
} else { | |||
maxLocals = 0; | |||
} | |||
} | |||
public void stripAttributes(boolean flag) { | |||
@@ -890,8 +924,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
Hashtable<InstructionHandle, BranchTarget> visitedTargets = new Hashtable<InstructionHandle, BranchTarget>(); | |||
public void push(InstructionHandle target, int stackDepth) { | |||
if (visited(target)) | |||
if (visited(target)) { | |||
return; | |||
} | |||
branchTargets.push(visit(target, stackDepth)); | |||
} | |||
@@ -925,17 +960,19 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
public static int getMaxStack(ConstantPool cp, InstructionList il, CodeExceptionGen[] et) { | |||
BranchStack branchTargets = new BranchStack(); | |||
int stackDepth = 0, maxStackDepth = 0; | |||
int stackDepth = 0; | |||
int maxStackDepth = 0; | |||
/* | |||
* Initially, populate the branch stack with the exception handlers, because these aren't (necessarily) branched to | |||
* explicitly. in each case, the stack will have depth 1, containing the exception object. | |||
* explicitly. In each case, the stack will have depth 1, containing the exception object. | |||
*/ | |||
for (int i = 0; i < et.length; i++) { | |||
InstructionHandle handler_pc = et[i].getHandlerPC(); | |||
if (handler_pc != null) { | |||
for (int i = 0, max = et.length; i < max; i++) { | |||
InstructionHandle handlerPos = et[i].getHandlerPC(); | |||
if (handlerPos != null) { | |||
// it must be at least 1 since there is an exception handler | |||
maxStackDepth = 1; | |||
branchTargets.push(handler_pc, 1); | |||
branchTargets.push(handlerPos, 1); | |||
} | |||
} | |||
@@ -948,8 +985,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
int delta = prod - con; | |||
stackDepth += delta; | |||
if (stackDepth > maxStackDepth) | |||
if (stackDepth > maxStackDepth) { | |||
maxStackDepth = stackDepth; | |||
} | |||
// choose the next instruction based on whether current is a branch. | |||
if (instruction instanceof InstructionBranch) { | |||
@@ -958,15 +996,17 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
// explore all of the select's targets. the default target is handled below. | |||
InstructionSelect select = (InstructionSelect) branch; | |||
InstructionHandle[] targets = select.getTargets(); | |||
for (int i = 0; i < targets.length; i++) | |||
for (int i = 0; i < targets.length; i++) { | |||
branchTargets.push(targets[i], stackDepth); | |||
} | |||
// nothing to fall through to. | |||
ih = null; | |||
} else if (!(branch.isIfInstruction())) { | |||
// if an instruction that comes back to following PC, | |||
// push next instruction, with stack depth reduced by 1. | |||
if (opcode == Constants.JSR || opcode == Constants.JSR_W) | |||
if (opcode == Constants.JSR || opcode == Constants.JSR_W) { | |||
branchTargets.push(ih.getNext(), stackDepth - 1); | |||
} | |||
ih = null; | |||
} | |||
// for all branches, the target of the branch is pushed on the branch stack. | |||
@@ -976,12 +1016,14 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} else { | |||
// check for instructions that terminate the method. | |||
if (opcode == Constants.ATHROW || opcode == Constants.RET | |||
|| (opcode >= Constants.IRETURN && opcode <= Constants.RETURN)) | |||
|| (opcode >= Constants.IRETURN && opcode <= Constants.RETURN)) { | |||
ih = null; | |||
} | |||
} | |||
// normal case, go to the next instruction. | |||
if (ih != null) | |||
if (ih != null) { | |||
ih = ih.getNext(); | |||
} | |||
// if we have no more instructions, see if there are any deferred branches to explore. | |||
if (ih == null) { | |||
BranchTarget bt = branchTargets.pop(); | |||
@@ -1009,8 +1051,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
StringBuffer buf = new StringBuffer(signature); | |||
if (exceptionsThrown.size() > 0) { | |||
for (Iterator<String> e = exceptionsThrown.iterator(); e.hasNext();) | |||
for (Iterator<String> e = exceptionsThrown.iterator(); e.hasNext();) { | |||
buf.append("\n\t\tthrows " + e.next()); | |||
} | |||
} | |||
return buf.toString(); | |||
@@ -1023,8 +1066,9 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
*/ | |||
public List getAnnotationsOnParameter(int i) { | |||
ensureExistingParameterAnnotationsUnpacked(); | |||
if (!hasParameterAnnotations || i > parameterTypes.length) | |||
if (!hasParameterAnnotations || i > parameterTypes.length) { | |||
return null; | |||
} | |||
return param_annotations[i]; | |||
} | |||
@@ -1055,10 +1099,11 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
hasParameterAnnotations = true; | |||
RuntimeParamAnnos rpa = (RuntimeParamAnnos) attribute; | |||
if (rpa.areVisible()) | |||
if (rpa.areVisible()) { | |||
paramAnnVisAttr = rpa; | |||
else | |||
} else { | |||
paramAnnInvisAttr = rpa; | |||
} | |||
for (int j = 0; j < parameterTypes.length; j++) { | |||
// This returns Annotation[] ... | |||
AnnotationGen[] annos = rpa.getAnnotationsOnParameter(j); | |||
@@ -1071,10 +1116,12 @@ public class MethodGen extends FieldGenOrMethodGen { | |||
} | |||
} | |||
} | |||
if (paramAnnVisAttr != null) | |||
if (paramAnnVisAttr != null) { | |||
removeAttribute(paramAnnVisAttr); | |||
if (paramAnnInvisAttr != null) | |||
} | |||
if (paramAnnInvisAttr != null) { | |||
removeAttribute(paramAnnInvisAttr); | |||
} | |||
haveUnpackedParameterAnnotations = true; | |||
} | |||
@@ -66,12 +66,12 @@ import org.aspectj.apache.bcel.classfile.ConstantPool; | |||
* Stack: ..., -> ..., address | |||
* </PRE> | |||
* | |||
* @version $Id: RET.java,v 1.4 2009/10/04 03:21:45 aclement Exp $ | |||
* @version $Id: RET.java,v 1.5 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
*/ | |||
public class RET extends Instruction { | |||
private boolean wide; | |||
private int index; // index to local variable containg the return address | |||
private int index; // index to local variable containing the return address | |||
public RET(int index, boolean wide) { | |||
super(Constants.RET); | |||
@@ -82,7 +82,7 @@ public class RET extends Instruction { | |||
public void dump(DataOutputStream out) throws IOException { | |||
if (wide) { | |||
out.writeByte(org.aspectj.apache.bcel.Constants.WIDE); | |||
out.writeByte(Constants.WIDE); | |||
} | |||
out.writeByte(opcode); | |||
if (wide) { | |||
@@ -106,7 +106,7 @@ public class RET extends Instruction { | |||
public final void setIndex(int index) { | |||
this.index = index; | |||
this.wide = index > org.aspectj.apache.bcel.Constants.MAX_BYTE; | |||
this.wide = index > Constants.MAX_BYTE; | |||
} | |||
public String toString(boolean verbose) { | |||
@@ -117,4 +117,16 @@ public class RET extends Instruction { | |||
return ReturnaddressType.NO_TARGET; | |||
} | |||
public boolean equals(Object other) { | |||
if (!(other instanceof RET)) { | |||
return false; | |||
} | |||
RET o = (RET) other; | |||
return o.opcode == opcode && o.index == index; | |||
} | |||
public int hashCode() { | |||
return opcode * 37 + index; | |||
} | |||
} |
@@ -67,7 +67,7 @@ import org.aspectj.apache.bcel.classfile.Utility; | |||
* Abstract super class for all possible java types, namely basic types such as int, object types like String and array types, e.g. | |||
* int[] | |||
* | |||
* @version $Id: Type.java,v 1.12 2009/09/10 03:59:34 aclement Exp $ | |||
* @version $Id: Type.java,v 1.13 2009/10/05 17:35:36 aclement Exp $ | |||
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> | |||
* | |||
* modified: AndyClement 2-mar-05: Removed unnecessary static and optimized | |||
@@ -177,8 +177,9 @@ public abstract class Type { | |||
public static final Type getType(String signature) { | |||
Type t = commonTypes.get(signature); | |||
if (t != null) | |||
if (t != null) { | |||
return t; | |||
} | |||
byte type = Utility.typeOfSignature(signature); | |||
if (type <= Constants.T_VOID) { | |||
return BasicType.getType(type); | |||
@@ -212,8 +213,9 @@ public abstract class Type { | |||
genericDepth--; | |||
break; | |||
case ';': | |||
if (genericDepth == 0) | |||
if (genericDepth == 0) { | |||
endOfSigReached = true; | |||
} | |||
break; | |||
default: | |||
} | |||
@@ -248,8 +250,9 @@ public abstract class Type { | |||
} else { // type == T_REFERENCE | |||
// Format is 'Lblahblah;' | |||
int index = signature.indexOf(';'); // Look for closing ';' | |||
if (index < 0) | |||
if (index < 0) { | |||
throw new ClassFormatException("Invalid signature: " + signature); | |||
} | |||
// generics awareness | |||
int nextAngly = signature.indexOf('<'); | |||
@@ -269,8 +272,9 @@ public abstract class Type { | |||
genericDepth--; | |||
break; | |||
case ';': | |||
if (genericDepth == 0) | |||
if (genericDepth == 0) { | |||
endOfSigReached = true; | |||
} | |||
break; | |||
default: | |||
} | |||
@@ -312,8 +316,9 @@ public abstract class Type { | |||
Type[] types; | |||
try { // Read all declarations between for `(' and `)' | |||
if (signature.charAt(0) != '(') | |||
if (signature.charAt(0) != '(') { | |||
throw new ClassFormatException("Invalid method signature: " + signature); | |||
} | |||
index = 1; // current string position | |||
@@ -337,8 +342,9 @@ public abstract class Type { | |||
*/ | |||
public static int getArgumentSizes(String signature) { | |||
int size = 0; | |||
if (signature.charAt(0) != '(') | |||
if (signature.charAt(0) != '(') { | |||
throw new ClassFormatException("Invalid method signature: " + signature); | |||
} | |||
int index = 1; // current string position | |||
try { | |||
@@ -375,8 +381,9 @@ public abstract class Type { | |||
genericDepth--; | |||
break; | |||
case ';': | |||
if (genericDepth == 0) | |||
if (genericDepth == 0) { | |||
endOfSigReached = true; | |||
} | |||
break; | |||
default: | |||
} |